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);
 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 */
 
 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 */
 
 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 */
 
 
        cpu_detect_mhz_feature();
         cpu_init();
        numa_setup();
+       smp_detect_cpus();
 
        /*
         * Create kernel page tables and switch to virtual addressing.
 
 #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>
        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);
                }
                info->combined = info->configured;
        }
-       return info;
 }
 
 static int smp_add_present_cpu(int cpu);
        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();
        get_online_cpus();
        __smp_rescan_cpus(info, 0);
        put_online_cpus();
-       kfree(info);
+       memblock_free_early((unsigned long)info, sizeof(*info));
 }
 
 /*
        /* 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)
        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);
 
 
 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
        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)
 
  * 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;
 
        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);
        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