Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4005e92 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Rafael J. Wysocki
Browse files

powercap/intel_rapl: Track active CPUs internally



The ability of the CPU hotplug code to stop online/offline at each step
makes it necessary to track the activated CPUs in a package directly,
because outerwise a CPU offline callback can find CPUs which have already
executed the offline callback, but are not yet marked offline in the
topology mask. That could make such a CPU the package leader and in case
that CPU goes fully offline leave the package lead orphaned.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatarJacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 58705069
Loading
Loading
Loading
Loading
+24 −35
Original line number Original line Diff line number Diff line
@@ -189,14 +189,13 @@ struct rapl_package {
	unsigned int time_unit;
	unsigned int time_unit;
	struct rapl_domain *domains; /* array of domains, sized at runtime */
	struct rapl_domain *domains; /* array of domains, sized at runtime */
	struct powercap_zone *power_zone; /* keep track of parent zone */
	struct powercap_zone *power_zone; /* keep track of parent zone */
	int nr_cpus; /* active cpus on the package, topology info is lost during
		      * cpu hotplug. so we have to track ourselves.
		      */
	unsigned long power_limit_irq; /* keep track of package power limit
	unsigned long power_limit_irq; /* keep track of package power limit
					* notify interrupt enable status.
					* notify interrupt enable status.
					*/
					*/
	struct list_head plist;
	struct list_head plist;
	int lead_cpu; /* one active cpu per package for access */
	int lead_cpu; /* one active cpu per package for access */
	/* Track active cpus */
	struct cpumask cpumask;
};
};


struct rapl_defaults {
struct rapl_defaults {
@@ -1432,19 +1431,17 @@ static void rapl_remove_package(struct rapl_package *rp)
}
}


/* called from CPU hotplug notifier, hotplug lock held */
/* called from CPU hotplug notifier, hotplug lock held */
static int rapl_add_package(int cpu)
static struct rapl_package *rapl_add_package(int cpu, int pkgid)
{
{
	struct rapl_package *rp;
	struct rapl_package *rp;
	int ret, phy_package_id;
	int ret;


	phy_package_id = topology_physical_package_id(cpu);
	rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
	rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
	if (!rp)
	if (!rp)
		return -ENOMEM;
		return ERR_PTR(-ENOMEM);


	/* add the new package to the list */
	/* add the new package to the list */
	rp->id = phy_package_id;
	rp->id = pkgid;
	rp->nr_cpus = 1;
	rp->lead_cpu = cpu;
	rp->lead_cpu = cpu;


	/* check if the package contains valid domains */
	/* check if the package contains valid domains */
@@ -1457,14 +1454,13 @@ static int rapl_add_package(int cpu)
	if (!ret) {
	if (!ret) {
		INIT_LIST_HEAD(&rp->plist);
		INIT_LIST_HEAD(&rp->plist);
		list_add(&rp->plist, &rapl_packages);
		list_add(&rp->plist, &rapl_packages);
		return 0;
		return rp;
	}
	}


err_free_package:
err_free_package:
	kfree(rp->domains);
	kfree(rp->domains);
	kfree(rp);
	kfree(rp);

	return ERR_PTR(ret);
	return ret;
}
}


/* Handles CPU hotplug on multi-socket systems.
/* Handles CPU hotplug on multi-socket systems.
@@ -1476,42 +1472,35 @@ static int rapl_add_package(int cpu)
 */
 */
static int rapl_cpu_online(unsigned int cpu)
static int rapl_cpu_online(unsigned int cpu)
{
{
	int pkgid = topology_physical_package_id(cpu);
	struct rapl_package *rp;
	struct rapl_package *rp;
	int phy_package_id;


	phy_package_id = topology_physical_package_id(cpu);
	rp = find_package_by_id(pkgid);

	if (!rp) {
	rp = find_package_by_id(phy_package_id);
		rp = rapl_add_package(cpu, pkgid);
	if (rp) {
		if (IS_ERR(rp))
		rp->nr_cpus++;
			return PTR_ERR(rp);
		return 0;
	}
	}
	return rapl_add_package(cpu);
	cpumask_set_cpu(cpu, &rp->cpumask);
	return 0;
}
}


static int rapl_cpu_down_prep(unsigned int cpu)
static int rapl_cpu_down_prep(unsigned int cpu)
{
{
	int phy_package_id;
	int pkgid = topology_physical_package_id(cpu);
	struct rapl_package *rp;
	struct rapl_package *rp;
	int lead_cpu;
	int lead_cpu;


	phy_package_id = topology_physical_package_id(cpu);
	rp = find_package_by_id(pkgid);
	rp = find_package_by_id(phy_package_id);
	if (!rp)
	if (!rp)
		return 0;
		return 0;
	if (--rp->nr_cpus == 0) {

	cpumask_clear_cpu(cpu, &rp->cpumask);
	lead_cpu = cpumask_first(&rp->cpumask);
	if (lead_cpu >= nr_cpu_ids)
		rapl_remove_package(rp);
		rapl_remove_package(rp);
	} else if (cpu == rp->lead_cpu) {
	else if (rp->lead_cpu == cpu)
		/* choose another active cpu in the package */
		lead_cpu = cpumask_any_but(topology_core_cpumask(cpu), cpu);
		if (lead_cpu < nr_cpu_ids) {
		rp->lead_cpu = lead_cpu;
		rp->lead_cpu = lead_cpu;
		} else {
			/* should never go here */
			pr_err("no active cpu available for package %d\n",
			       phy_package_id);
		}
	}
	return 0;
	return 0;
}
}