mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	powerpc/pseries: Add CPU dlpar add functionality
Add the ability to hotplug add cpus via rtas hotplug events by either specifying the drc index of the CPU to add, or providing a count of the number of CPUs to add. Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
		
							parent
							
								
									ac71380071
								
							
						
					
					
						commit
						90edf184b9
					
				| @ -405,6 +405,27 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index) | |||||||
| 	return found; | 	return found; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index) | ||||||
|  | { | ||||||
|  | 	bool found = false; | ||||||
|  | 	int rc, index; | ||||||
|  | 
 | ||||||
|  | 	index = 0; | ||||||
|  | 	while (!found) { | ||||||
|  | 		u32 drc; | ||||||
|  | 
 | ||||||
|  | 		rc = of_property_read_u32_index(parent, "ibm,drc-indexes", | ||||||
|  | 						index++, &drc); | ||||||
|  | 		if (rc) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		if (drc == drc_index) | ||||||
|  | 			found = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return found; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static ssize_t dlpar_cpu_add(u32 drc_index) | static ssize_t dlpar_cpu_add(u32 drc_index) | ||||||
| { | { | ||||||
| 	struct device_node *dn, *parent; | 	struct device_node *dn, *parent; | ||||||
| @ -424,6 +445,12 @@ static ssize_t dlpar_cpu_add(u32 drc_index) | |||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (!valid_cpu_drc_index(parent, drc_index)) { | ||||||
|  | 		of_node_put(parent); | ||||||
|  | 		pr_warn("Cannot find CPU (drc index %x) to add.\n", drc_index); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	rc = dlpar_acquire_drc(drc_index); | 	rc = dlpar_acquire_drc(drc_index); | ||||||
| 	if (rc) { | 	if (rc) { | ||||||
| 		pr_warn("Failed to acquire DRC, rc: %d, drc index: %x\n", | 		pr_warn("Failed to acquire DRC, rc: %d, drc index: %x\n", | ||||||
| @ -683,6 +710,87 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove) | |||||||
| 	return rc; | 	return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add) | ||||||
|  | { | ||||||
|  | 	struct device_node *parent; | ||||||
|  | 	int cpus_found = 0; | ||||||
|  | 	int index, rc; | ||||||
|  | 
 | ||||||
|  | 	parent = of_find_node_by_path("/cpus"); | ||||||
|  | 	if (!parent) { | ||||||
|  | 		pr_warn("Could not find CPU root node in device tree\n"); | ||||||
|  | 		kfree(cpu_drcs); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Search the ibm,drc-indexes array for possible CPU drcs to
 | ||||||
|  | 	 * add. Note that the format of the ibm,drc-indexes array is | ||||||
|  | 	 * the number of entries in the array followed by the array | ||||||
|  | 	 * of drc values so we start looking at index = 1. | ||||||
|  | 	 */ | ||||||
|  | 	index = 1; | ||||||
|  | 	while (cpus_found < cpus_to_add) { | ||||||
|  | 		u32 drc; | ||||||
|  | 
 | ||||||
|  | 		rc = of_property_read_u32_index(parent, "ibm,drc-indexes", | ||||||
|  | 						index++, &drc); | ||||||
|  | 		if (rc) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		if (dlpar_cpu_exists(parent, drc)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		cpu_drcs[cpus_found++] = drc; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	of_node_put(parent); | ||||||
|  | 	return cpus_found; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int dlpar_cpu_add_by_count(u32 cpus_to_add) | ||||||
|  | { | ||||||
|  | 	u32 *cpu_drcs; | ||||||
|  | 	int cpus_added = 0; | ||||||
|  | 	int cpus_found; | ||||||
|  | 	int i, rc; | ||||||
|  | 
 | ||||||
|  | 	pr_debug("Attempting to hot-add %d CPUs\n", cpus_to_add); | ||||||
|  | 
 | ||||||
|  | 	cpu_drcs = kcalloc(cpus_to_add, sizeof(*cpu_drcs), GFP_KERNEL); | ||||||
|  | 	if (!cpu_drcs) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	cpus_found = find_dlpar_cpus_to_add(cpu_drcs, cpus_to_add); | ||||||
|  | 	if (cpus_found < cpus_to_add) { | ||||||
|  | 		pr_warn("Failed to find enough CPUs (%d of %d) to add\n", | ||||||
|  | 			cpus_found, cpus_to_add); | ||||||
|  | 		kfree(cpu_drcs); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < cpus_to_add; i++) { | ||||||
|  | 		rc = dlpar_cpu_add(cpu_drcs[i]); | ||||||
|  | 		if (rc) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		cpus_added++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (cpus_added < cpus_to_add) { | ||||||
|  | 		pr_warn("CPU hot-add failed, removing any added CPUs\n"); | ||||||
|  | 
 | ||||||
|  | 		for (i = 0; i < cpus_added; i++) | ||||||
|  | 			dlpar_cpu_remove_by_index(cpu_drcs[i]); | ||||||
|  | 
 | ||||||
|  | 		rc = -EINVAL; | ||||||
|  | 	} else { | ||||||
|  | 		rc = 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	kfree(cpu_drcs); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int dlpar_cpu(struct pseries_hp_errorlog *hp_elog) | int dlpar_cpu(struct pseries_hp_errorlog *hp_elog) | ||||||
| { | { | ||||||
| 	u32 count, drc_index; | 	u32 count, drc_index; | ||||||
| @ -702,6 +810,14 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog) | |||||||
| 		else | 		else | ||||||
| 			rc = -EINVAL; | 			rc = -EINVAL; | ||||||
| 		break; | 		break; | ||||||
|  | 	case PSERIES_HP_ELOG_ACTION_ADD: | ||||||
|  | 		if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) | ||||||
|  | 			rc = dlpar_cpu_add_by_count(count); | ||||||
|  | 		else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) | ||||||
|  | 			rc = dlpar_cpu_add(drc_index); | ||||||
|  | 		else | ||||||
|  | 			rc = -EINVAL; | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		pr_err("Invalid action (%d) specified\n", hp_elog->action); | 		pr_err("Invalid action (%d) specified\n", hp_elog->action); | ||||||
| 		rc = -EINVAL; | 		rc = -EINVAL; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Nathan Fontenot
						Nathan Fontenot