Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powercap/rapl: track lead cpu per package

RAPL driver operates on MSRs that are under package/socket
scope instead of core scope. However, the current code does not
keep track of which CPUs are available on each package for MSR
access. Therefore it has to search for an active CPU on a given
package each time.

This patch optimizes the package level operations by tracking a
per package lead CPU during initialization and CPU hotplug. The
runtime search for active CPU is avoided.

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Jacob Pan and committed by
Rafael J. Wysocki
323ee64a 309557f5

+20 -39
+20 -39
drivers/powercap/intel_rapl.c
··· 191 191 * notify interrupt enable status. 192 192 */ 193 193 struct list_head plist; 194 + int lead_cpu; /* one active cpu per package for access */ 194 195 }; 195 196 196 197 struct rapl_defaults { ··· 266 265 } 267 266 268 267 return NULL; 269 - } 270 - 271 - /* caller to ensure CPU hotplug lock is held */ 272 - static int find_active_cpu_on_package(int package_id) 273 - { 274 - int i; 275 - 276 - for_each_online_cpu(i) { 277 - if (topology_physical_package_id(i) == package_id) 278 - return i; 279 - } 280 - /* all CPUs on this package are offline */ 281 - 282 - return -ENODEV; 283 268 } 284 269 285 270 /* caller must hold cpu hotplug lock */ ··· 748 761 msr = rd->msrs[rp->id]; 749 762 if (!msr) 750 763 return -EINVAL; 751 - /* use physical package id to look up active cpus */ 752 - cpu = find_active_cpu_on_package(rd->rp->id); 753 - if (cpu < 0) 754 - return cpu; 764 + 765 + cpu = rd->rp->lead_cpu; 755 766 756 767 /* special-case package domain, which uses a different bit*/ 757 768 if (prim == FW_LOCK && rd->id == RAPL_DOMAIN_PACKAGE) { ··· 814 829 struct msrl_action ma; 815 830 int ret; 816 831 817 - cpu = find_active_cpu_on_package(rd->rp->id); 818 - if (cpu < 0) 819 - return cpu; 820 - 832 + cpu = rd->rp->lead_cpu; 821 833 bits = rapl_unit_xlate(rd, rp->unit, value, 1); 822 834 bits |= bits << rp->shift; 823 835 memset(&ma, 0, sizeof(ma)); ··· 922 940 923 941 static void package_power_limit_irq_save(struct rapl_package *rp) 924 942 { 925 - int cpu; 926 - 927 943 if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN)) 928 944 return; 929 945 930 - cpu = find_active_cpu_on_package(rp->id); 931 - if (cpu < 0) 932 - return; 933 - if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN)) 934 - return; 935 - 936 - smp_call_function_single(cpu, power_limit_irq_save_cpu, rp, 1); 946 + smp_call_function_single(rp->lead_cpu, power_limit_irq_save_cpu, rp, 1); 937 947 } 938 948 939 949 static void power_limit_irq_restore_cpu(void *info) ··· 946 972 /* restore per package power limit interrupt enable state */ 947 973 static void package_power_limit_irq_restore(struct rapl_package *rp) 948 974 { 949 - int cpu; 950 - 951 975 if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN)) 952 - return; 953 - 954 - cpu = find_active_cpu_on_package(rp->id); 955 - if (cpu < 0) 956 976 return; 957 977 958 978 /* irq enable state not saved, nothing to restore */ 959 979 if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) 960 980 return; 961 981 962 - smp_call_function_single(cpu, power_limit_irq_restore_cpu, rp, 1); 982 + smp_call_function_single(rp->lead_cpu, power_limit_irq_restore_cpu, rp, 1); 963 983 } 964 984 965 985 static void set_floor_freq_default(struct rapl_domain *rd, bool mode) ··· 1387 1419 /* add the new package to the list */ 1388 1420 new_package->id = phy_package_id; 1389 1421 new_package->nr_cpus = 1; 1390 - 1422 + /* use the first active cpu of the package to access */ 1423 + new_package->lead_cpu = i; 1391 1424 /* check if the package contains valid domains */ 1392 1425 if (rapl_detect_domains(new_package, i) || 1393 1426 rapl_defaults->check_unit(new_package, i)) { ··· 1444 1475 /* add the new package to the list */ 1445 1476 rp->id = phy_package_id; 1446 1477 rp->nr_cpus = 1; 1478 + rp->lead_cpu = cpu; 1479 + 1447 1480 /* check if the package contains valid domains */ 1448 1481 if (rapl_detect_domains(rp, cpu) || 1449 1482 rapl_defaults->check_unit(rp, cpu)) { ··· 1478 1507 unsigned long cpu = (unsigned long)hcpu; 1479 1508 int phy_package_id; 1480 1509 struct rapl_package *rp; 1510 + int lead_cpu; 1481 1511 1482 1512 phy_package_id = topology_physical_package_id(cpu); 1483 1513 switch (action) { ··· 1499 1527 break; 1500 1528 if (--rp->nr_cpus == 0) 1501 1529 rapl_remove_package(rp); 1530 + else if (cpu == rp->lead_cpu) { 1531 + /* choose another active cpu in the package */ 1532 + lead_cpu = cpumask_any_but(topology_core_cpumask(cpu), cpu); 1533 + if (lead_cpu < nr_cpu_ids) 1534 + rp->lead_cpu = lead_cpu; 1535 + else /* should never go here */ 1536 + pr_err("no active cpu available for package %d\n", 1537 + phy_package_id); 1538 + } 1502 1539 } 1503 1540 1504 1541 return NOTIFY_OK;