diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c index 07db08cabc12..13f37d212164 100644 --- a/drivers/thermal/x86_pkg_temp_thermal.c +++ b/drivers/thermal/x86_pkg_temp_thermal.c @@ -54,13 +54,9 @@ MODULE_PARM_DESC(notify_delay_ms, * is some wrong values returned by cpuid for number of thresholds. */ #define MAX_NUMBER_OF_TRIPS 2 -/* Limit number of package temp zones */ -#define MAX_PKG_TEMP_ZONE_IDS 256 struct pkg_device { - struct list_head list; - u16 phys_proc_id; - u16 cpu; + int cpu; bool work_scheduled; u32 tj_max; u32 msr_pkg_therm_low; @@ -74,8 +70,10 @@ static struct thermal_zone_params pkg_temp_tz_params = { .no_hwmon = true, }; -/* List maintaining number of package instances */ -static LIST_HEAD(phy_dev_list); +/* Keep track of how many package pointers we allocated in init() */ +static int max_packages __read_mostly; +/* Array of package pointers */ +static struct pkg_device **packages; /* Serializes interrupt notification, work and hotplug */ static DEFINE_SPINLOCK(pkg_temp_lock); /* Protects zone operation in the work function against hotplug removal */ @@ -121,13 +119,10 @@ static int pkg_temp_debugfs_init(void) */ static struct pkg_device *pkg_temp_thermal_get_dev(unsigned int cpu) { - u16 phys_proc_id = topology_physical_package_id(cpu); - struct pkg_device *pkgdev; + int pkgid = topology_logical_package_id(cpu); - list_for_each_entry(pkgdev, &phy_dev_list, list) { - if (pkgdev->phys_proc_id == phys_proc_id) - return pkgdev; - } + if (pkgid >= 0 && pkgid < max_packages) + return packages[pkgid]; return NULL; } @@ -355,18 +350,19 @@ static int pkg_thermal_notify(u64 msr_val) static int pkg_temp_thermal_device_add(unsigned int cpu) { + int pkgid = topology_logical_package_id(cpu); u32 tj_max, eax, ebx, ecx, edx; struct pkg_device *pkgdev; int thres_count, err; + if (pkgid >= max_packages) + return -ENOMEM; + cpuid(6, &eax, &ebx, &ecx, &edx); thres_count = ebx & 0x07; if (!thres_count) return -ENODEV; - if (topology_physical_package_id(cpu) > MAX_PKG_TEMP_ZONE_IDS) - return -ENODEV; - thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS); err = get_tj_max(cpu, &tj_max); @@ -378,7 +374,6 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) return -ENOMEM; INIT_DELAYED_WORK(&pkgdev->work, pkg_temp_thermal_threshold_work_fn); - pkgdev->phys_proc_id = topology_physical_package_id(cpu); pkgdev->cpu = cpu; pkgdev->tj_max = tj_max; pkgdev->tzone = thermal_zone_device_register("x86_pkg_temp", @@ -397,7 +392,7 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) cpumask_set_cpu(cpu, &pkgdev->cpumask); spin_lock_irq(&pkg_temp_lock); - list_add_tail(&pkgdev->list, &phy_dev_list); + packages[pkgid] = pkgdev; spin_unlock_irq(&pkg_temp_lock); return 0; } @@ -447,12 +442,12 @@ static void put_core_offline(unsigned int cpu) /* * If this is the last CPU in the package remove the package - * reference from the list and restore the interrupt MSR. When we + * reference from the array and restore the interrupt MSR. When we * drop the lock neither the interrupt notify function nor the * worker will see the package anymore. */ if (lastcpu) { - list_del(&pkgdev->list); + packages[topology_logical_package_id(cpu)] = NULL; /* * After this point nothing touches the MSR anymore. We * must drop the lock to make the cross cpu call. This goes @@ -545,6 +540,11 @@ static int __init pkg_temp_thermal_init(void) if (!x86_match_cpu(pkg_temp_thermal_ids)) return -ENODEV; + max_packages = topology_max_packages(); + packages = kzalloc(max_packages * sizeof(struct pkg_device *), GFP_KERNEL); + if (!packages) + return -ENOMEM; + cpu_notifier_register_begin(); for_each_online_cpu(i) if (get_core_online(i)) @@ -563,6 +563,7 @@ static int __init pkg_temp_thermal_init(void) for_each_online_cpu(i) put_core_offline(i); cpu_notifier_register_done(); + kfree(packages); return -ENODEV; } module_init(pkg_temp_thermal_init) @@ -581,6 +582,7 @@ static void __exit pkg_temp_thermal_exit(void) cpu_notifier_register_done(); debugfs_remove_recursive(debugfs); + kfree(packages); } module_exit(pkg_temp_thermal_exit)