diff options
Diffstat (limited to 'arch/s390/kernel/smp.c')
| -rw-r--r-- | arch/s390/kernel/smp.c | 159 | 
1 files changed, 85 insertions, 74 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index efd2c1968000..6f54c175f5c9 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -31,6 +31,7 @@  #include <linux/cpu.h>  #include <linux/slab.h>  #include <linux/crash_dump.h> +#include <linux/memblock.h>  #include <asm/asm-offsets.h>  #include <asm/switch_to.h>  #include <asm/facility.h> @@ -69,7 +70,7 @@ struct pcpu {  	u16 address;			/* physical cpu address */  }; -static u8 boot_cpu_type; +static u8 boot_core_type;  static struct pcpu pcpu_devices[NR_CPUS];  unsigned int smp_cpu_mt_shift; @@ -531,15 +532,12 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);  #ifdef CONFIG_CRASH_DUMP -static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu) +static void __smp_store_cpu_state(struct save_area_ext *sa_ext, u16 address, +				  int is_boot_cpu)  { -	void *lc = pcpu_devices[0].lowcore; -	struct save_area_ext *sa_ext; +	void *lc = (void *)(unsigned long) store_prefix();  	unsigned long vx_sa; -	sa_ext = dump_save_area_create(cpu); -	if (!sa_ext) -		panic("could not allocate memory for save area\n");  	if (is_boot_cpu) {  		/* Copy the registers of the boot CPU. */  		copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa), @@ -554,14 +552,33 @@ static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu)  	if (!MACHINE_HAS_VX)  		return;  	/* Get the VX registers */ -	vx_sa = __get_free_page(GFP_KERNEL); +	vx_sa = memblock_alloc(PAGE_SIZE, PAGE_SIZE);  	if (!vx_sa)  		panic("could not allocate memory for VX save area\n");  	__pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL);  	memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs)); -	free_page(vx_sa); +	memblock_free(vx_sa, PAGE_SIZE);  } +int smp_store_status(int cpu) +{ +	unsigned long vx_sa; +	struct pcpu *pcpu; + +	pcpu = pcpu_devices + cpu; +	if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS, +			      0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED) +		return -EIO; +	if (!MACHINE_HAS_VX) +		return 0; +	vx_sa = __pa(pcpu->lowcore->vector_save_area_addr); +	__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, +			  vx_sa, NULL); +	return 0; +} + +#endif /* CONFIG_CRASH_DUMP */ +  /*   * Collect CPU state of the previous, crashed system.   * There are four cases: @@ -589,10 +606,12 @@ static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu)   *    old system. The ELF sections are picked up by the crash_dump code   *    via elfcorehdr_addr.   */ -static void __init smp_store_cpu_states(struct sclp_cpu_info *info) +void __init smp_save_dump_cpus(void)  { -	unsigned int cpu, address, i, j; -	int is_boot_cpu; +#ifdef CONFIG_CRASH_DUMP +	int addr, cpu, boot_cpu_addr, max_cpu_addr; +	struct save_area_ext *sa_ext; +	bool is_boot_cpu;  	if (is_kdump_kernel())  		/* Previous system stored the CPU states. Nothing to do. */ @@ -601,43 +620,37 @@ static void __init smp_store_cpu_states(struct sclp_cpu_info *info)  		/* No previous system present, normal boot. */  		return;  	/* Set multi-threading state to the previous system. */ -	pcpu_set_smt(sclp_get_mtid_prev()); -	/* Collect CPU states. */ -	cpu = 0; -	for (i = 0; i < info->configured; i++) { -		/* Skip CPUs with different CPU type. */ -		if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type) +	pcpu_set_smt(sclp.mtid_prev); +	max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev; +	for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { +		if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) == +		    SIGP_CC_NOT_OPERATIONAL)  			continue; -		for (j = 0; j <= smp_cpu_mtid; j++, cpu++) { -			address = (info->cpu[i].core_id << smp_cpu_mt_shift) + j; -			is_boot_cpu = (address == pcpu_devices[0].address); -			if (is_boot_cpu && !OLDMEM_BASE) -				/* Skip boot CPU for standard zfcp dump. */ -				continue; -			/* Get state for this CPu. */ -			__smp_store_cpu_state(cpu, address, is_boot_cpu); -		} +		cpu += 1;  	} -} - -int smp_store_status(int cpu) -{ -	unsigned long vx_sa; -	struct pcpu *pcpu; - -	pcpu = pcpu_devices + cpu; -	if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS, -			      0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED) -		return -EIO; -	if (!MACHINE_HAS_VX) -		return 0; -	vx_sa = __pa(pcpu->lowcore->vector_save_area_addr); -	__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, -			  vx_sa, NULL); -	return 0; -} - +	dump_save_areas.areas = (void *)memblock_alloc(sizeof(void *) * cpu, 8); +	dump_save_areas.count = cpu; +	boot_cpu_addr = stap(); +	for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { +		if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) == +		    SIGP_CC_NOT_OPERATIONAL) +			continue; +		sa_ext = (void *) memblock_alloc(sizeof(*sa_ext), 8); +		dump_save_areas.areas[cpu] = sa_ext; +		if (!sa_ext) +			panic("could not allocate memory for save area\n"); +		is_boot_cpu = (addr == boot_cpu_addr); +		cpu += 1; +		if (is_boot_cpu && !OLDMEM_BASE) +			/* Skip boot CPU for standard zfcp dump. */ +			continue; +		/* Get state for this CPU. */ +		__smp_store_cpu_state(sa_ext, addr, is_boot_cpu); +	} +	diag308_reset(); +	pcpu_set_smt(0);  #endif /* CONFIG_CRASH_DUMP */ +}  void smp_cpu_set_polarization(int cpu, int val)  { @@ -649,21 +662,22 @@ int smp_cpu_get_polarization(int cpu)  	return pcpu_devices[cpu].polarization;  } -static struct sclp_cpu_info *smp_get_cpu_info(void) +static struct sclp_core_info *smp_get_core_info(void)  {  	static int use_sigp_detection; -	struct sclp_cpu_info *info; +	struct sclp_core_info *info;  	int address;  	info = kzalloc(sizeof(*info), GFP_KERNEL); -	if (info && (use_sigp_detection || sclp_get_cpu_info(info))) { +	if (info && (use_sigp_detection || sclp_get_core_info(info))) {  		use_sigp_detection = 1; -		for (address = 0; address <= MAX_CPU_ADDRESS; +		for (address = 0; +		     address < (SCLP_MAX_CORES << smp_cpu_mt_shift);  		     address += (1U << smp_cpu_mt_shift)) {  			if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) ==  			    SIGP_CC_NOT_OPERATIONAL)  				continue; -			info->cpu[info->configured].core_id = +			info->core[info->configured].core_id =  				address >> smp_cpu_mt_shift;  			info->configured++;  		} @@ -674,7 +688,7 @@ static struct sclp_cpu_info *smp_get_cpu_info(void)  static int smp_add_present_cpu(int cpu); -static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add) +static int __smp_rescan_cpus(struct sclp_core_info *info, int sysfs_add)  {  	struct pcpu *pcpu;  	cpumask_t avail; @@ -685,9 +699,9 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add)  	cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);  	cpu = cpumask_first(&avail);  	for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) { -		if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type) +		if (sclp.has_core_type && info->core[i].type != boot_core_type)  			continue; -		address = info->cpu[i].core_id << smp_cpu_mt_shift; +		address = info->core[i].core_id << smp_cpu_mt_shift;  		for (j = 0; j <= smp_cpu_mtid; j++) {  			if (pcpu_find_address(cpu_present_mask, address + j))  				continue; @@ -713,41 +727,37 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add)  static void __init smp_detect_cpus(void)  {  	unsigned int cpu, mtid, c_cpus, s_cpus; -	struct sclp_cpu_info *info; +	struct sclp_core_info *info;  	u16 address;  	/* Get CPU information */ -	info = smp_get_cpu_info(); +	info = smp_get_core_info();  	if (!info)  		panic("smp_detect_cpus failed to allocate memory\n");  	/* Find boot CPU type */ -	if (info->has_cpu_type) { +	if (sclp.has_core_type) {  		address = stap();  		for (cpu = 0; cpu < info->combined; cpu++) -			if (info->cpu[cpu].core_id == address) { +			if (info->core[cpu].core_id == address) {  				/* The boot cpu dictates the cpu type. */ -				boot_cpu_type = info->cpu[cpu].type; +				boot_core_type = info->core[cpu].type;  				break;  			}  		if (cpu >= info->combined)  			panic("Could not find boot CPU type");  	} -#ifdef CONFIG_CRASH_DUMP -	/* Collect CPU state of previous system */ -	smp_store_cpu_states(info); -#endif -  	/* Set multi-threading state for the current system */ -	mtid = sclp_get_mtid(boot_cpu_type); +	mtid = boot_core_type ? sclp.mtid : sclp.mtid_cp;  	mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1;  	pcpu_set_smt(mtid);  	/* Print number of CPUs */  	c_cpus = s_cpus = 0;  	for (cpu = 0; cpu < info->combined; cpu++) { -		if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type) +		if (sclp.has_core_type && +		    info->core[cpu].type != boot_core_type)  			continue;  		if (cpu < info->configured)  			c_cpus += smp_cpu_mtid + 1; @@ -880,12 +890,13 @@ void __noreturn cpu_die(void)  void __init smp_fill_possible_mask(void)  { -	unsigned int possible, sclp, cpu; +	unsigned int possible, sclp_max, cpu; -	sclp = min(smp_max_threads, sclp_get_mtid_max() + 1); -	sclp = sclp_get_max_cpu()*sclp ?: nr_cpu_ids; +	sclp_max = max(sclp.mtid, sclp.mtid_cp) + 1; +	sclp_max = min(smp_max_threads, sclp_max); +	sclp_max = sclp.max_cores * sclp_max ?: nr_cpu_ids;  	possible = setup_possible_cpus ?: nr_cpu_ids; -	possible = min(possible, sclp); +	possible = min(possible, sclp_max);  	for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)  		set_cpu_possible(cpu, true);  } @@ -976,7 +987,7 @@ static ssize_t cpu_configure_store(struct device *dev,  	case 0:  		if (pcpu->state != CPU_STATE_CONFIGURED)  			break; -		rc = sclp_cpu_deconfigure(pcpu->address >> smp_cpu_mt_shift); +		rc = sclp_core_deconfigure(pcpu->address >> smp_cpu_mt_shift);  		if (rc)  			break;  		for (i = 0; i <= smp_cpu_mtid; i++) { @@ -991,7 +1002,7 @@ static ssize_t cpu_configure_store(struct device *dev,  	case 1:  		if (pcpu->state != CPU_STATE_STANDBY)  			break; -		rc = sclp_cpu_configure(pcpu->address >> smp_cpu_mt_shift); +		rc = sclp_core_configure(pcpu->address >> smp_cpu_mt_shift);  		if (rc)  			break;  		for (i = 0; i <= smp_cpu_mtid; i++) { @@ -1106,10 +1117,10 @@ out:  int __ref smp_rescan_cpus(void)  { -	struct sclp_cpu_info *info; +	struct sclp_core_info *info;  	int nr; -	info = smp_get_cpu_info(); +	info = smp_get_core_info();  	if (!info)  		return -ENOMEM;  	get_online_cpus();  |