s390/smp: initialize cpu_present_mask in setup_arch
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Sat, 3 Dec 2016 08:48:01 +0000 (09:48 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 7 Dec 2016 06:23:07 +0000 (07:23 +0100)
In order to be able to setup the cpu to node mappings early it is a
prerequisite to know which cpus are present. Therefore cpus must be
detected much earlier than before.

For sclp based cpu detection this requires yet another early sclp
call, since the system is not ready to use the regular interrupt and
memory allocations.

Reviewed-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/sclp.h
arch/s390/include/asm/smp.h
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_cmd.c
drivers/s390/char/sclp_early.c

index 2ad9c204b1a2fccc142a787ccb85f3262298cd92..8db92a5b3bf13ecf206b09bcc40fd4d3bd6a617c 100644 (file)
@@ -101,7 +101,8 @@ struct zpci_report_error_header {
        u8 data[0];     /* Subsequent Data passed verbatim to SCLP ET 24 */
 } __packed;
 
-int sclp_get_core_info(struct sclp_core_info *info);
+int _sclp_get_core_info_early(struct sclp_core_info *info);
+int _sclp_get_core_info(struct sclp_core_info *info);
 int sclp_core_configure(u8 core);
 int sclp_core_deconfigure(u8 core);
 int sclp_sdias_blk_count(void);
@@ -119,4 +120,11 @@ void sclp_early_detect(void);
 void _sclp_print_early(const char *);
 void sclp_ocf_cpc_name_copy(char *dst);
 
+static inline int sclp_get_core_info(struct sclp_core_info *info, int early)
+{
+       if (early)
+               return _sclp_get_core_info_early(info);
+       return _sclp_get_core_info(info);
+}
+
 #endif /* _ASM_S390_SCLP_H */
index 8116b7b63af3180067ec2eefe27c3957ccf19aeb..3deb134587b744f41164c58255d9f2bba3c92dc0 100644 (file)
@@ -36,6 +36,7 @@ extern void smp_yield_cpu(int cpu);
 extern void smp_cpu_set_polarization(int cpu, int val);
 extern int smp_cpu_get_polarization(int cpu);
 extern void smp_fill_possible_mask(void);
+extern void smp_detect_cpus(void);
 
 #else /* CONFIG_SMP */
 
@@ -56,6 +57,7 @@ static inline int smp_store_status(int cpu) { return 0; }
 static inline int smp_vcpu_scheduled(int cpu) { return 1; }
 static inline void smp_yield_cpu(int cpu) { }
 static inline void smp_fill_possible_mask(void) { }
+static inline void smp_detect_cpus(void) { }
 
 #endif /* CONFIG_SMP */
 
index b57e28f1edc253aca1d1b0babf3aa77cba95c551..aba3c5ce1559534a97f3641e7f500b45f16dc5f3 100644 (file)
@@ -923,6 +923,7 @@ void __init setup_arch(char **cmdline_p)
        cpu_detect_mhz_feature();
         cpu_init();
        numa_setup();
+       smp_detect_cpus();
 
        /*
         * Create kernel page tables and switch to virtual addressing.
index 66ffc2350f2417c9947d4e7965bda2531d969cb6..5d53ab646b3f19f0f38a5568ae7d0e0db7cd2d81 100644 (file)
@@ -19,6 +19,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/workqueue.h>
+#include <linux/bootmem.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -655,14 +656,12 @@ int smp_cpu_get_polarization(int cpu)
        return pcpu_devices[cpu].polarization;
 }
 
-static struct sclp_core_info *smp_get_core_info(void)
+static void __ref smp_get_core_info(struct sclp_core_info *info, int early)
 {
        static int use_sigp_detection;
-       struct sclp_core_info *info;
        int address;
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (info && (use_sigp_detection || sclp_get_core_info(info))) {
+       if (use_sigp_detection || sclp_get_core_info(info, early)) {
                use_sigp_detection = 1;
                for (address = 0;
                     address < (SCLP_MAX_CORES << smp_cpu_mt_shift);
@@ -676,7 +675,6 @@ static struct sclp_core_info *smp_get_core_info(void)
                }
                info->combined = info->configured;
        }
-       return info;
 }
 
 static int smp_add_present_cpu(int cpu);
@@ -717,17 +715,15 @@ static int __smp_rescan_cpus(struct sclp_core_info *info, int sysfs_add)
        return nr;
 }
 
-static void __init smp_detect_cpus(void)
+void __init smp_detect_cpus(void)
 {
        unsigned int cpu, mtid, c_cpus, s_cpus;
        struct sclp_core_info *info;
        u16 address;
 
        /* Get CPU information */
-       info = smp_get_core_info();
-       if (!info)
-               panic("smp_detect_cpus failed to allocate memory\n");
-
+       info = memblock_virt_alloc(sizeof(*info), 8);
+       smp_get_core_info(info, 1);
        /* Find boot CPU type */
        if (sclp.has_core_type) {
                address = stap();
@@ -763,7 +759,7 @@ static void __init smp_detect_cpus(void)
        get_online_cpus();
        __smp_rescan_cpus(info, 0);
        put_online_cpus();
-       kfree(info);
+       memblock_free_early((unsigned long)info, sizeof(*info));
 }
 
 /*
@@ -900,7 +896,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        /* request the 0x1202 external call external interrupt */
        if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
                panic("Couldn't request external interrupt 0x1202");
-       smp_detect_cpus();
 }
 
 void __init smp_prepare_boot_cpu(void)
@@ -1111,9 +1106,10 @@ int __ref smp_rescan_cpus(void)
        struct sclp_core_info *info;
        int nr;
 
-       info = smp_get_core_info();
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
+       smp_get_core_info(info, 0);
        get_online_cpus();
        mutex_lock(&smp_cpu_state_mutex);
        nr = __smp_rescan_cpus(info, 1);
index 7a10c56334bbec3e0948565073df426381b05dd6..e1fc7eb043d67dbb62403e1744d204be6bc01406 100644 (file)
@@ -59,6 +59,7 @@
 
 typedef unsigned int sclp_cmdw_t;
 
+#define SCLP_CMDW_READ_CPU_INFO                0x00010001
 #define SCLP_CMDW_READ_EVENT_DATA      0x00770005
 #define SCLP_CMDW_WRITE_EVENT_DATA     0x00760005
 #define SCLP_CMDW_WRITE_EVENT_MASK     0x00780005
@@ -102,6 +103,28 @@ struct init_sccb {
        sccb_mask_t sclp_send_mask;
 } __attribute__((packed));
 
+struct read_cpu_info_sccb {
+       struct  sccb_header header;
+       u16     nr_configured;
+       u16     offset_configured;
+       u16     nr_standby;
+       u16     offset_standby;
+       u8      reserved[4096 - 16];
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static inline void sclp_fill_core_info(struct sclp_core_info *info,
+                                      struct read_cpu_info_sccb *sccb)
+{
+       char *page = (char *) sccb;
+
+       memset(info, 0, sizeof(*info));
+       info->configured = sccb->nr_configured;
+       info->standby = sccb->nr_standby;
+       info->combined = sccb->nr_configured + sccb->nr_standby;
+       memcpy(&info->core, page + sccb->offset_configured,
+              info->combined * sizeof(struct sclp_core_entry));
+}
+
 #define SCLP_HAS_CHP_INFO      (sclp.facilities & 0x8000000000000000ULL)
 #define SCLP_HAS_CHP_RECONFIG  (sclp.facilities & 0x2000000000000000ULL)
 #define SCLP_HAS_CPU_INFO      (sclp.facilities & 0x0800000000000000ULL)
index e3fc7539116b4f2c6ba43c0d1938cf407ebaac9e..b9c5522b8a680c0a7a49a2c3196d8b7215803b40 100644 (file)
@@ -80,33 +80,10 @@ out:
  * CPU configuration related functions.
  */
 
-#define SCLP_CMDW_READ_CPU_INFO                0x00010001
 #define SCLP_CMDW_CONFIGURE_CPU                0x00110001
 #define SCLP_CMDW_DECONFIGURE_CPU      0x00100001
 
-struct read_cpu_info_sccb {
-       struct  sccb_header header;
-       u16     nr_configured;
-       u16     offset_configured;
-       u16     nr_standby;
-       u16     offset_standby;
-       u8      reserved[4096 - 16];
-} __attribute__((packed, aligned(PAGE_SIZE)));
-
-static void sclp_fill_core_info(struct sclp_core_info *info,
-                               struct read_cpu_info_sccb *sccb)
-{
-       char *page = (char *) sccb;
-
-       memset(info, 0, sizeof(*info));
-       info->configured = sccb->nr_configured;
-       info->standby = sccb->nr_standby;
-       info->combined = sccb->nr_configured + sccb->nr_standby;
-       memcpy(&info->core, page + sccb->offset_configured,
-              info->combined * sizeof(struct sclp_core_entry));
-}
-
-int sclp_get_core_info(struct sclp_core_info *info)
+int _sclp_get_core_info(struct sclp_core_info *info)
 {
        int rc;
        struct read_cpu_info_sccb *sccb;
index c71df0c7dedc1c75c7b17b0f9038bee188c42939..f8e46c22e641501d5c8e26d1c2c2de52dd97c91a 100644 (file)
@@ -221,6 +221,36 @@ static int __init sclp_set_event_mask(struct init_sccb *sccb,
        return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
 }
 
+static struct sclp_core_info sclp_core_info_early __initdata;
+static int sclp_core_info_early_valid __initdata;
+
+static void __init sclp_init_core_info_early(struct read_cpu_info_sccb *sccb)
+{
+       int rc;
+
+       if (!SCLP_HAS_CPU_INFO)
+               return;
+       memset(sccb, 0, sizeof(*sccb));
+       sccb->header.length = sizeof(*sccb);
+       do {
+               rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb);
+       } while (rc == -EBUSY);
+       if (rc)
+               return;
+       if (sccb->header.response_code != 0x0010)
+               return;
+       sclp_fill_core_info(&sclp_core_info_early, sccb);
+       sclp_core_info_early_valid = 1;
+}
+
+int __init _sclp_get_core_info_early(struct sclp_core_info *info)
+{
+       if (!sclp_core_info_early_valid)
+               return -EIO;
+       *info = sclp_core_info_early;
+       return 0;
+}
+
 static long __init sclp_hsa_size_init(struct sdias_sccb *sccb)
 {
        sccb_init_eq_size(sccb);
@@ -293,6 +323,7 @@ void __init sclp_early_detect(void)
        void *sccb = &sccb_early;
 
        sclp_facilities_detect(sccb);
+       sclp_init_core_info_early(sccb);
        sclp_hsa_size_detect(sccb);
 
        /* Turn off SCLP event notifications.  Also save remote masks in the