Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/smp: initialize cpu_present_mask in setup_arch

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>

authored by

Heiko Carstens and committed by
Martin Schwidefsky
af51160e ebb299a5

+76 -38
+9 -1
arch/s390/include/asm/sclp.h
··· 101 101 u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ 102 102 } __packed; 103 103 104 - int sclp_get_core_info(struct sclp_core_info *info); 104 + int _sclp_get_core_info_early(struct sclp_core_info *info); 105 + int _sclp_get_core_info(struct sclp_core_info *info); 105 106 int sclp_core_configure(u8 core); 106 107 int sclp_core_deconfigure(u8 core); 107 108 int sclp_sdias_blk_count(void); ··· 119 118 void sclp_early_detect(void); 120 119 void _sclp_print_early(const char *); 121 120 void sclp_ocf_cpc_name_copy(char *dst); 121 + 122 + static inline int sclp_get_core_info(struct sclp_core_info *info, int early) 123 + { 124 + if (early) 125 + return _sclp_get_core_info_early(info); 126 + return _sclp_get_core_info(info); 127 + } 122 128 123 129 #endif /* _ASM_S390_SCLP_H */
+2
arch/s390/include/asm/smp.h
··· 36 36 extern void smp_cpu_set_polarization(int cpu, int val); 37 37 extern int smp_cpu_get_polarization(int cpu); 38 38 extern void smp_fill_possible_mask(void); 39 + extern void smp_detect_cpus(void); 39 40 40 41 #else /* CONFIG_SMP */ 41 42 ··· 57 56 static inline int smp_vcpu_scheduled(int cpu) { return 1; } 58 57 static inline void smp_yield_cpu(int cpu) { } 59 58 static inline void smp_fill_possible_mask(void) { } 59 + static inline void smp_detect_cpus(void) { } 60 60 61 61 #endif /* CONFIG_SMP */ 62 62
+1
arch/s390/kernel/setup.c
··· 923 923 cpu_detect_mhz_feature(); 924 924 cpu_init(); 925 925 numa_setup(); 926 + smp_detect_cpus(); 926 927 927 928 /* 928 929 * Create kernel page tables and switch to virtual addressing.
+9 -13
arch/s390/kernel/smp.c
··· 19 19 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 20 20 21 21 #include <linux/workqueue.h> 22 + #include <linux/bootmem.h> 22 23 #include <linux/module.h> 23 24 #include <linux/init.h> 24 25 #include <linux/mm.h> ··· 656 655 return pcpu_devices[cpu].polarization; 657 656 } 658 657 659 - static struct sclp_core_info *smp_get_core_info(void) 658 + static void __ref smp_get_core_info(struct sclp_core_info *info, int early) 660 659 { 661 660 static int use_sigp_detection; 662 - struct sclp_core_info *info; 663 661 int address; 664 662 665 - info = kzalloc(sizeof(*info), GFP_KERNEL); 666 - if (info && (use_sigp_detection || sclp_get_core_info(info))) { 663 + if (use_sigp_detection || sclp_get_core_info(info, early)) { 667 664 use_sigp_detection = 1; 668 665 for (address = 0; 669 666 address < (SCLP_MAX_CORES << smp_cpu_mt_shift); ··· 675 676 } 676 677 info->combined = info->configured; 677 678 } 678 - return info; 679 679 } 680 680 681 681 static int smp_add_present_cpu(int cpu); ··· 715 717 return nr; 716 718 } 717 719 718 - static void __init smp_detect_cpus(void) 720 + void __init smp_detect_cpus(void) 719 721 { 720 722 unsigned int cpu, mtid, c_cpus, s_cpus; 721 723 struct sclp_core_info *info; 722 724 u16 address; 723 725 724 726 /* Get CPU information */ 725 - info = smp_get_core_info(); 726 - if (!info) 727 - panic("smp_detect_cpus failed to allocate memory\n"); 728 - 727 + info = memblock_virt_alloc(sizeof(*info), 8); 728 + smp_get_core_info(info, 1); 729 729 /* Find boot CPU type */ 730 730 if (sclp.has_core_type) { 731 731 address = stap(); ··· 759 763 get_online_cpus(); 760 764 __smp_rescan_cpus(info, 0); 761 765 put_online_cpus(); 762 - kfree(info); 766 + memblock_free_early((unsigned long)info, sizeof(*info)); 763 767 } 764 768 765 769 /* ··· 896 900 /* request the 0x1202 external call external interrupt */ 897 901 if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt)) 898 902 panic("Couldn't request external interrupt 0x1202"); 899 - smp_detect_cpus(); 900 903 } 901 904 902 905 void __init smp_prepare_boot_cpu(void) ··· 1106 1111 struct sclp_core_info *info; 1107 1112 int nr; 1108 1113 1109 - info = smp_get_core_info(); 1114 + info = kzalloc(sizeof(*info), GFP_KERNEL); 1110 1115 if (!info) 1111 1116 return -ENOMEM; 1117 + smp_get_core_info(info, 0); 1112 1118 get_online_cpus(); 1113 1119 mutex_lock(&smp_cpu_state_mutex); 1114 1120 nr = __smp_rescan_cpus(info, 1);
+23
drivers/s390/char/sclp.h
··· 59 59 60 60 typedef unsigned int sclp_cmdw_t; 61 61 62 + #define SCLP_CMDW_READ_CPU_INFO 0x00010001 62 63 #define SCLP_CMDW_READ_EVENT_DATA 0x00770005 63 64 #define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005 64 65 #define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005 ··· 102 101 sccb_mask_t sclp_receive_mask; 103 102 sccb_mask_t sclp_send_mask; 104 103 } __attribute__((packed)); 104 + 105 + struct read_cpu_info_sccb { 106 + struct sccb_header header; 107 + u16 nr_configured; 108 + u16 offset_configured; 109 + u16 nr_standby; 110 + u16 offset_standby; 111 + u8 reserved[4096 - 16]; 112 + } __attribute__((packed, aligned(PAGE_SIZE))); 113 + 114 + static inline void sclp_fill_core_info(struct sclp_core_info *info, 115 + struct read_cpu_info_sccb *sccb) 116 + { 117 + char *page = (char *) sccb; 118 + 119 + memset(info, 0, sizeof(*info)); 120 + info->configured = sccb->nr_configured; 121 + info->standby = sccb->nr_standby; 122 + info->combined = sccb->nr_configured + sccb->nr_standby; 123 + memcpy(&info->core, page + sccb->offset_configured, 124 + info->combined * sizeof(struct sclp_core_entry)); 125 + } 105 126 106 127 #define SCLP_HAS_CHP_INFO (sclp.facilities & 0x8000000000000000ULL) 107 128 #define SCLP_HAS_CHP_RECONFIG (sclp.facilities & 0x2000000000000000ULL)
+1 -24
drivers/s390/char/sclp_cmd.c
··· 80 80 * CPU configuration related functions. 81 81 */ 82 82 83 - #define SCLP_CMDW_READ_CPU_INFO 0x00010001 84 83 #define SCLP_CMDW_CONFIGURE_CPU 0x00110001 85 84 #define SCLP_CMDW_DECONFIGURE_CPU 0x00100001 86 85 87 - struct read_cpu_info_sccb { 88 - struct sccb_header header; 89 - u16 nr_configured; 90 - u16 offset_configured; 91 - u16 nr_standby; 92 - u16 offset_standby; 93 - u8 reserved[4096 - 16]; 94 - } __attribute__((packed, aligned(PAGE_SIZE))); 95 - 96 - static void sclp_fill_core_info(struct sclp_core_info *info, 97 - struct read_cpu_info_sccb *sccb) 98 - { 99 - char *page = (char *) sccb; 100 - 101 - memset(info, 0, sizeof(*info)); 102 - info->configured = sccb->nr_configured; 103 - info->standby = sccb->nr_standby; 104 - info->combined = sccb->nr_configured + sccb->nr_standby; 105 - memcpy(&info->core, page + sccb->offset_configured, 106 - info->combined * sizeof(struct sclp_core_entry)); 107 - } 108 - 109 - int sclp_get_core_info(struct sclp_core_info *info) 86 + int _sclp_get_core_info(struct sclp_core_info *info) 110 87 { 111 88 int rc; 112 89 struct read_cpu_info_sccb *sccb;
+31
drivers/s390/char/sclp_early.c
··· 221 221 return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb); 222 222 } 223 223 224 + static struct sclp_core_info sclp_core_info_early __initdata; 225 + static int sclp_core_info_early_valid __initdata; 226 + 227 + static void __init sclp_init_core_info_early(struct read_cpu_info_sccb *sccb) 228 + { 229 + int rc; 230 + 231 + if (!SCLP_HAS_CPU_INFO) 232 + return; 233 + memset(sccb, 0, sizeof(*sccb)); 234 + sccb->header.length = sizeof(*sccb); 235 + do { 236 + rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb); 237 + } while (rc == -EBUSY); 238 + if (rc) 239 + return; 240 + if (sccb->header.response_code != 0x0010) 241 + return; 242 + sclp_fill_core_info(&sclp_core_info_early, sccb); 243 + sclp_core_info_early_valid = 1; 244 + } 245 + 246 + int __init _sclp_get_core_info_early(struct sclp_core_info *info) 247 + { 248 + if (!sclp_core_info_early_valid) 249 + return -EIO; 250 + *info = sclp_core_info_early; 251 + return 0; 252 + } 253 + 224 254 static long __init sclp_hsa_size_init(struct sdias_sccb *sccb) 225 255 { 226 256 sccb_init_eq_size(sccb); ··· 323 293 void *sccb = &sccb_early; 324 294 325 295 sclp_facilities_detect(sccb); 296 + sclp_init_core_info_early(sccb); 326 297 sclp_hsa_size_detect(sccb); 327 298 328 299 /* Turn off SCLP event notifications. Also save remote masks in the