[PATCH] powerpc/pseries: Split CPU readd for single CPU systems

Michael Ellerman mpe at ellerman.id.au
Tue Jan 15 17:38:59 AEDT 2019


Michael Bringmann <mwb at linux.vnet.ibm.com> writes:
> [FYI: Please post to linuxppc-dev mailing list when you are ready.
>       Good luck.]

???

I guess I'll ignore this and look at the other version you posted? :)

cheers

> We have encountered cases where DLPAR CPU 'readd' fails on single
> CPU platforms, because the system needs a minimum amount of resources
> to keep operating.  The current implementation attempts to add, and
> remove all of the threads of a specified core at once, and will fail
> if there is a problem removing any of the thread cpus.  In single CPU
> platforms, the system must hold onto at least some resources to keep
> operating i.e. at least one thread of a CPU.  So in such environments,
> attempting to remove and add the single core and all of its CPU threads
> in order to reset and flush system structures and/or caches fails.
>
> This problem has been observed on PowerVM and qemu environments.
>
> This change attempts to resolve such situations by breaking up the
> DLPAR CPU 'readd' operation into multiple steps, performing the
> remove+readd of the CPU threads until an error occurs, and then
> continuing the 'readd' operation for the threads that could not be
> removed during the first phase of the operation.
>
> Requires: ("powerpc/pseries: Perform full re-add of CPU for topology update post-migration")
> Signed-off-by: Michael W. Bringmann <mwb at linux.vnet.ibm.com>
> ---
>  arch/powerpc/platforms/pseries/hotplug-cpu.c |  187 ++++++++++++++++----------
>  1 file changed, 117 insertions(+), 70 deletions(-)
>
> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> index 97feb6e..b33e066 100644
> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> @@ -342,7 +342,8 @@ static void pseries_remove_processor(struct device_node *np)
>  	cpu_maps_update_done();
>  }
>  
> -static int dlpar_online_cpu(struct device_node *dn)
> +static int dlpar_online_cpu(struct device_node *dn, cpumask_t *whichcpus,
> +				int partial)
>  {
>  	int rc = 0;
>  	unsigned int cpu;
> @@ -359,6 +360,8 @@ static int dlpar_online_cpu(struct device_node *dn)
>  	cpu_maps_update_begin();
>  	for (i = 0; i < nthreads; i++) {
>  		thread = be32_to_cpu(intserv[i]);
> +		if (partial && !cpumask_test_cpu(thread, whichcpus))
> +			continue;
>  		for_each_present_cpu(cpu) {
>  			if (get_hard_smp_processor_id(cpu) != thread)
>  				continue;
> @@ -371,7 +374,6 @@ static int dlpar_online_cpu(struct device_node *dn)
>  			if (rc)
>  				goto out;
>  			cpu_maps_update_begin();
> -
>  			break;
>  		}
>  		if (cpu == num_possible_cpus())
> @@ -432,7 +434,10 @@ static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
>  	return found;
>  }
>  
> -static ssize_t dlpar_cpu_add(u32 drc_index)
> +static struct device_node *cpu_drc_index_to_dn(u32 drc_index);
> +
> +static ssize_t dlpar_cpu_add(u32 drc_index, cpumask_t *whichcpus,
> +				bool partial)
>  {
>  	struct device_node *dn, *parent;
>  	int rc, saved_rc;
> @@ -445,10 +450,12 @@ static ssize_t dlpar_cpu_add(u32 drc_index)
>  		return -ENODEV;
>  	}
>  
> -	if (dlpar_cpu_exists(parent, drc_index)) {
> -		of_node_put(parent);
> -		pr_warn("CPU with drc index %x already exists\n", drc_index);
> -		return -EINVAL;
> +	if (!parent) {
> +		if (dlpar_cpu_exists(parent, drc_index)) {
> +			of_node_put(parent);
> +			pr_warn("CPU with drc index %x already exists\n", drc_index);
> +			return -EINVAL;
> +		}
>  	}
>  
>  	if (!valid_cpu_drc_index(parent, drc_index)) {
> @@ -457,49 +464,59 @@ static ssize_t dlpar_cpu_add(u32 drc_index)
>  		return -EINVAL;
>  	}
>  
> -	rc = dlpar_acquire_drc(drc_index);
> -	if (rc) {
> -		pr_warn("Failed to acquire DRC, rc: %d, drc index: %x\n",
> -			rc, drc_index);
> -		of_node_put(parent);
> -		return -EINVAL;
> -	}
> +	if (!partial) {
> +		rc = dlpar_acquire_drc(drc_index);
> +		if (rc) {
> +			pr_warn("Failed to acquire DRC, rc: %d, drc index: %x\n",
> +				rc, drc_index);
> +			of_node_put(parent);
> +			return -EINVAL;
> +		}
>  
> -	dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
> -	if (!dn) {
> -		pr_warn("Failed call to configure-connector, drc index: %x\n",
> -			drc_index);
> -		dlpar_release_drc(drc_index);
> -		of_node_put(parent);
> -		return -EINVAL;
> -	}
> +		dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
> +		if (!dn) {
> +			pr_warn("Failed call to configure-connector, drc index: %x\n",
> +				drc_index);
> +			dlpar_release_drc(drc_index);
> +			of_node_put(parent);
> +			return -EINVAL;
> +		}
>  
> -	rc = dlpar_attach_node(dn, parent);
> +		rc = dlpar_attach_node(dn, parent);
>  
> -	/* Regardless we are done with parent now */
> -	of_node_put(parent);
> +		/* Regardless we are done with parent now */
> +		of_node_put(parent);
>  
> -	if (rc) {
> -		saved_rc = rc;
> -		pr_warn("Failed to attach node %pOFn, rc: %d, drc index: %x\n",
> -			dn, rc, drc_index);
> +		if (rc) {
> +			saved_rc = rc;
> +			pr_warn("Failed to attach node %pOFn, rc: %d, drc index: %x\n",
> +				dn, rc, drc_index);
>  
> -		rc = dlpar_release_drc(drc_index);
> -		if (!rc)
> -			dlpar_free_cc_nodes(dn);
> +			rc = dlpar_release_drc(drc_index);
> +			if (!rc)
> +				dlpar_free_cc_nodes(dn);
>  
> -		return saved_rc;
> +			return saved_rc;
> +		}
> +	} else {
> +		dn = cpu_drc_index_to_dn(drc_index);
> +		if (!dn) {
> +			pr_warn("Cannot find CPU (drc index %x) to add.\n", drc_index);
> +			return -EINVAL;
> +		}
>  	}
>  
> -	rc = dlpar_online_cpu(dn);
> +	rc = dlpar_online_cpu(dn, whichcpus, partial);
>  	if (rc) {
>  		saved_rc = rc;
>  		pr_warn("Failed to online cpu %pOFn, rc: %d, drc index: %x\n",
>  			dn, rc, drc_index);
>  
> -		rc = dlpar_detach_node(dn);
> -		if (!rc)
> -			dlpar_release_drc(drc_index);
> +		if (!partial || (cpumask_weight(whichcpus) == 0)) {
> +			rc = dlpar_detach_node(dn);
> +			if (!rc)
> +				dlpar_release_drc(drc_index);
> +		}
>  
>  		return saved_rc;
>  	}
> @@ -509,7 +526,8 @@ static ssize_t dlpar_cpu_add(u32 drc_index)
>  	return rc;
>  }
>  
> -static int dlpar_offline_cpu(struct device_node *dn)
> +static int dlpar_offline_cpu(struct device_node *dn, cpumask_t *whichcpus,
> +				int partial)
>  {
>  	int rc = 0;
>  	unsigned int cpu;
> @@ -526,6 +544,8 @@ static int dlpar_offline_cpu(struct device_node *dn)
>  	cpu_maps_update_begin();
>  	for (i = 0; i < nthreads; i++) {
>  		thread = be32_to_cpu(intserv[i]);
> +		if (partial && cpumask_test_cpu(thread, whichcpus))
> +			continue;
>  		for_each_present_cpu(cpu) {
>  			if (get_hard_smp_processor_id(cpu) != thread)
>  				continue;
> @@ -542,8 +562,9 @@ static int dlpar_offline_cpu(struct device_node *dn)
>  				if (rc)
>  					goto out;
>  				cpu_maps_update_begin();
> +				if (whichcpus)
> +					cpumask_set_cpu(cpu, whichcpus);
>  				break;
> -
>  			}
>  
>  			/*
> @@ -566,41 +587,45 @@ static int dlpar_offline_cpu(struct device_node *dn)
>  
>  }
>  
> -static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index)
> +static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index,
> +				cpumask_t *whichcpus, bool partial)
>  {
>  	int rc;
>  
>  	pr_debug("Attempting to remove CPU %pOFn, drc index: %x\n",
>  		 dn, drc_index);
>  
> -	rc = dlpar_offline_cpu(dn);
> +	rc = dlpar_offline_cpu(dn, whichcpus, partial);
>  	if (rc) {
>  		pr_warn("Failed to offline CPU %pOFn, rc: %d\n", dn, rc);
>  		return -EINVAL;
>  	}
>  
> -	rc = dlpar_release_drc(drc_index);
> -	if (rc) {
> -		pr_warn("Failed to release drc (%x) for CPU %pOFn, rc: %d\n",
> -			drc_index, dn, rc);
> -		dlpar_online_cpu(dn);
> -		return rc;
> -	}
> +	if (!partial) {
> +		rc = dlpar_release_drc(drc_index);
> +		if (rc) {
> +			pr_warn("Failed to release drc (%x) for CPU %pOFn, rc: %d\n",
> +				drc_index, dn, rc);
> +			dlpar_online_cpu(dn, whichcpus, partial);
> +			return rc;
> +		}
>  
> -	rc = dlpar_detach_node(dn);
> -	if (rc) {
> -		int saved_rc = rc;
> +		rc = dlpar_detach_node(dn);
> +		if (rc) {
> +			int saved_rc = rc;
>  
> -		pr_warn("Failed to detach CPU %pOFn, rc: %d", dn, rc);
> +			pr_warn("Failed to detach CPU %pOFn, rc: %d", dn, rc);
>  
> -		rc = dlpar_acquire_drc(drc_index);
> -		if (!rc)
> -			dlpar_online_cpu(dn);
> +			rc = dlpar_acquire_drc(drc_index);
> +			if (!rc)
> +				dlpar_online_cpu(dn, whichcpus, partial);
>  
> -		return saved_rc;
> +			return saved_rc;
> +		}
> +
> +		pr_debug("Successfully removed CPU, drc index: %x\n", drc_index);
>  	}
>  
> -	pr_debug("Successfully removed CPU, drc index: %x\n", drc_index);
>  	return 0;
>  }
>  
> @@ -622,7 +647,8 @@ static struct device_node *cpu_drc_index_to_dn(u32 drc_index)
>  	return dn;
>  }
>  
> -static int dlpar_cpu_remove_by_index(u32 drc_index)
> +static int dlpar_cpu_remove_by_index(u32 drc_index, cpumask_t *whichcpus,
> +					bool partial)
>  {
>  	struct device_node *dn;
>  	int rc;
> @@ -634,7 +660,7 @@ static int dlpar_cpu_remove_by_index(u32 drc_index)
>  		return -ENODEV;
>  	}
>  
> -	rc = dlpar_cpu_remove(dn, drc_index);
> +	rc = dlpar_cpu_remove(dn, drc_index, whichcpus, partial);
>  	of_node_put(dn);
>  	return rc;
>  }
> @@ -699,7 +725,7 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
>  	}
>  
>  	for (i = 0; i < cpus_to_remove; i++) {
> -		rc = dlpar_cpu_remove_by_index(cpu_drcs[i]);
> +		rc = dlpar_cpu_remove_by_index(cpu_drcs[i], NULL, false);
>  		if (rc)
>  			break;
>  
> @@ -710,7 +736,7 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
>  		pr_warn("CPU hot-remove failed, adding back removed CPUs\n");
>  
>  		for (i = 0; i < cpus_removed; i++)
> -			dlpar_cpu_add(cpu_drcs[i]);
> +			dlpar_cpu_add(cpu_drcs[i], NULL, false);
>  
>  		rc = -EINVAL;
>  	} else {
> @@ -780,7 +806,7 @@ static int dlpar_cpu_add_by_count(u32 cpus_to_add)
>  	}
>  
>  	for (i = 0; i < cpus_to_add; i++) {
> -		rc = dlpar_cpu_add(cpu_drcs[i]);
> +		rc = dlpar_cpu_add(cpu_drcs[i], NULL, false);
>  		if (rc)
>  			break;
>  
> @@ -791,7 +817,7 @@ static int dlpar_cpu_add_by_count(u32 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]);
> +			dlpar_cpu_remove_by_index(cpu_drcs[i], NULL, false);
>  
>  		rc = -EINVAL;
>  	} else {
> @@ -807,16 +833,36 @@ int dlpar_cpu_readd(int cpu)
>  	struct device_node *dn;
>  	struct device *dev;
>  	u32 drc_index;
> -	int rc;
> +	const __be32 *intserv;
> +	cpumask_t whichcpus;
> +	int rc, len, nthreads;
>  
>  	dev = get_cpu_device(cpu);
>  	dn = dev->of_node;
>  
> +	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
> +	if (!intserv)
> +		return -EINVAL;
> +	nthreads = len / sizeof(u32);
> +	cpumask_clear(&whichcpus);
> +
>  	rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
>  
> -	rc = dlpar_cpu_remove_by_index(drc_index);
> +	rc = dlpar_cpu_remove_by_index(drc_index, &whichcpus, false);
>  	if (!rc)
> -		rc = dlpar_cpu_add(drc_index);
> +		rc = dlpar_cpu_add(drc_index, &whichcpus, false);
> +
> +	if (cpumask_weight(&whichcpus) < nthreads) {
> +		cpumask_t whichcpus2;
> +
> +		rc = dlpar_cpu_add(drc_index, &whichcpus, false);
> +
> +		cpumask_copy(&whichcpus2, &whichcpus);
> +		dlpar_cpu_remove_by_index(drc_index, &whichcpus2, true);
> +
> +		cpumask_andnot(&whichcpus2, &whichcpus2, &whichcpus);
> +		dlpar_cpu_add(drc_index, &whichcpus2, true);
> +	}
>  
>  	return rc;
>  }
> @@ -836,7 +882,8 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
>  		if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT)
>  			rc = dlpar_cpu_remove_by_count(count);
>  		else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX)
> -			rc = dlpar_cpu_remove_by_index(drc_index);
> +			rc = dlpar_cpu_remove_by_index(drc_index,
> +					NULL, false);
>  		else
>  			rc = -EINVAL;
>  		break;
> @@ -844,7 +891,7 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
>  		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);
> +			rc = dlpar_cpu_add(drc_index, NULL, false);
>  		else
>  			rc = -EINVAL;
>  		break;
> @@ -869,7 +916,7 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
>  	if (rc)
>  		return -EINVAL;
>  
> -	rc = dlpar_cpu_add(drc_index);
> +	rc = dlpar_cpu_add(drc_index, NULL, false);
>  
>  	return rc ? rc : count;
>  }
> @@ -890,7 +937,7 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
>  		return -EINVAL;
>  	}
>  
> -	rc = dlpar_cpu_remove(dn, drc_index);
> +	rc = dlpar_cpu_remove(dn, drc_index, NULL, false);
>  	of_node_put(dn);
>  
>  	return rc ? rc : count;


More information about the Linuxppc-dev mailing list