diff options
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/fair_share.c | 12 | ||||
-rw-r--r-- | drivers/thermal/gov_bang_bang.c | 11 | ||||
-rw-r--r-- | drivers/thermal/intel/int340x_thermal/Kconfig | 6 | ||||
-rw-r--r-- | drivers/thermal/intel/int340x_thermal/processor_thermal_device.c | 195 | ||||
-rw-r--r-- | drivers/thermal/power_allocator.c | 11 | ||||
-rw-r--r-- | drivers/thermal/step_wise.c | 11 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.c | 52 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.h | 55 | ||||
-rw-r--r-- | drivers/thermal/user_space.c | 12 |
9 files changed, 244 insertions, 121 deletions
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c index 8ff109fb77e1..afd99f668c65 100644 --- a/drivers/thermal/fair_share.c +++ b/drivers/thermal/fair_share.c @@ -117,14 +117,4 @@ static struct thermal_governor thermal_gov_fair_share = { .name = "fair_share", .throttle = fair_share_throttle, }; - -int thermal_gov_fair_share_register(void) -{ - return thermal_register_governor(&thermal_gov_fair_share); -} - -void thermal_gov_fair_share_unregister(void) -{ - thermal_unregister_governor(&thermal_gov_fair_share); -} - +THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share); diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index 632fb925e975..e0575d29023a 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -116,13 +116,4 @@ static struct thermal_governor thermal_gov_bang_bang = { .name = "bang_bang", .throttle = bang_bang_control, }; - -int thermal_gov_bang_bang_register(void) -{ - return thermal_register_governor(&thermal_gov_bang_bang); -} - -void thermal_gov_bang_bang_unregister(void) -{ - thermal_unregister_governor(&thermal_gov_bang_bang); -} +THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang); diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig index 5333e018c88c..797907542e43 100644 --- a/drivers/thermal/intel/int340x_thermal/Kconfig +++ b/drivers/thermal/intel/int340x_thermal/Kconfig @@ -40,4 +40,10 @@ config INT3406_THERMAL brightness in order to address a thermal condition or to reduce power consumed by display device. +config PROC_THERMAL_MMIO_RAPL + bool + depends on 64BIT + depends on POWERCAP + select INTEL_RAPL_CORE + default y endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 53c84fa498ce..d3446acf9bbd 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -11,6 +11,8 @@ #include <linux/platform_device.h> #include <linux/acpi.h> #include <linux/thermal.h> +#include <linux/cpuhotplug.h> +#include <linux/intel_rapl.h> #include "int340x_thermal_zone.h" #include "../intel_soc_dts_iosf.h" @@ -37,6 +39,8 @@ /* GeminiLake thermal reporting device */ #define PCI_DEVICE_ID_PROC_GLK_THERMAL 0x318C +#define DRV_NAME "proc_thermal" + struct power_config { u32 index; u32 min_uw; @@ -52,6 +56,7 @@ struct proc_thermal_device { struct power_config power_limits[2]; struct int34x_thermal_zone *int340x_zone; struct intel_soc_dts_sensors *soc_dts; + void __iomem *mmio_base; }; enum proc_thermal_emum_mode_type { @@ -60,6 +65,12 @@ enum proc_thermal_emum_mode_type { PROC_THERMAL_PLATFORM_DEV }; +struct rapl_mmio_regs { + u64 reg_unit; + u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX]; + int limits[RAPL_DOMAIN_MAX]; +}; + /* * We can have only one type of enumeration, PCI or Platform, * not both. So we don't need instance specific data. @@ -367,8 +378,155 @@ static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid) return IRQ_HANDLED; } +#ifdef CONFIG_PROC_THERMAL_MMIO_RAPL + +#define MCHBAR 0 + +/* RAPL Support via MMIO interface */ +static struct rapl_if_priv rapl_mmio_priv; + +static int rapl_mmio_cpu_online(unsigned int cpu) +{ + struct rapl_package *rp; + + /* mmio rapl supports package 0 only for now */ + if (topology_physical_package_id(cpu)) + return 0; + + rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); + if (!rp) { + rp = rapl_add_package(cpu, &rapl_mmio_priv); + if (IS_ERR(rp)) + return PTR_ERR(rp); + } + cpumask_set_cpu(cpu, &rp->cpumask); + return 0; +} + +static int rapl_mmio_cpu_down_prep(unsigned int cpu) +{ + struct rapl_package *rp; + int lead_cpu; + + rp = rapl_find_package_domain(cpu, &rapl_mmio_priv); + if (!rp) + return 0; + + cpumask_clear_cpu(cpu, &rp->cpumask); + lead_cpu = cpumask_first(&rp->cpumask); + if (lead_cpu >= nr_cpu_ids) + rapl_remove_package(rp); + else if (rp->lead_cpu == cpu) + rp->lead_cpu = lead_cpu; + return 0; +} + +static int rapl_mmio_read_raw(int cpu, struct reg_action *ra) +{ + if (!ra->reg) + return -EINVAL; + + ra->value = readq((void __iomem *)ra->reg); + ra->value &= ra->mask; + return 0; +} + +static int rapl_mmio_write_raw(int cpu, struct reg_action *ra) +{ + u64 val; + + if (!ra->reg) + return -EINVAL; + + val = readq((void __iomem *)ra->reg); + val &= ~ra->mask; + val |= ra->value; + writeq(val, (void __iomem *)ra->reg); + return 0; +} + +static int proc_thermal_rapl_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv, + struct rapl_mmio_regs *rapl_regs) +{ + enum rapl_domain_reg_id reg; + enum rapl_domain_type domain; + int ret; + + if (!rapl_regs) + return 0; + + ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); + return -ENOMEM; + } + + proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR]; + + for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) { + for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++) + if (rapl_regs->regs[domain][reg]) + rapl_mmio_priv.regs[domain][reg] = + (u64)proc_priv->mmio_base + + rapl_regs->regs[domain][reg]; + rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain]; + } + rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit; + + rapl_mmio_priv.read_raw = rapl_mmio_read_raw; + rapl_mmio_priv.write_raw = rapl_mmio_write_raw; + + rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL); + if (IS_ERR(rapl_mmio_priv.control_type)) { + pr_debug("failed to register powercap control_type.\n"); + return PTR_ERR(rapl_mmio_priv.control_type); + } + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online", + rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep); + if (ret < 0) { + powercap_unregister_control_type(rapl_mmio_priv.control_type); + rapl_mmio_priv.control_type = NULL; + return ret; + } + rapl_mmio_priv.pcap_rapl_online = ret; + + return 0; +} + +static void proc_thermal_rapl_remove(void) +{ + if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type)) + return; + + cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online); + powercap_unregister_control_type(rapl_mmio_priv.control_type); +} + +static const struct rapl_mmio_regs rapl_mmio_hsw = { + .reg_unit = 0x5938, + .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930}, + .regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0}, + .limits[RAPL_DOMAIN_PACKAGE] = 2, + .limits[RAPL_DOMAIN_DRAM] = 2, +}; + +#else + +static int proc_thermal_rapl_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv, + struct rapl_mmio_regs *rapl_regs) +{ + return 0; +} +static void proc_thermal_rapl_remove(void) {} +static const struct rapl_mmio_regs rapl_mmio_hsw; + +#endif /* CONFIG_MMIO_RAPL */ + static int proc_thermal_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *unused) + const struct pci_device_id *id) { struct proc_thermal_device *proc_priv; int ret; @@ -378,15 +536,21 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, return -ENODEV; } - ret = pci_enable_device(pdev); + ret = pcim_enable_device(pdev); if (ret < 0) { dev_err(&pdev->dev, "error: could not enable device\n"); return ret; } ret = proc_thermal_add(&pdev->dev, &proc_priv); + if (ret) + return ret; + + ret = proc_thermal_rapl_add(pdev, proc_priv, + (struct rapl_mmio_regs *)id->driver_data); if (ret) { - pci_disable_device(pdev); + dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n"); + proc_thermal_remove(proc_priv); return ret; } @@ -439,14 +603,31 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev) pci_disable_msi(pdev); } } + proc_thermal_rapl_remove(); proc_thermal_remove(proc_priv); - pci_disable_device(pdev); } +#ifdef CONFIG_PM_SLEEP +static int proc_thermal_resume(struct device *dev) +{ + struct proc_thermal_device *proc_dev; + + proc_dev = dev_get_drvdata(dev); + proc_thermal_read_ppcc(proc_dev); + + return 0; +} +#else +#define proc_thermal_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume); + static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)}, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL)}, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL), + .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT0_THERMAL)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)}, @@ -461,10 +642,11 @@ static const struct pci_device_id proc_thermal_pci_ids[] = { MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); static struct pci_driver proc_thermal_pci_driver = { - .name = "proc_thermal", + .name = DRV_NAME, .probe = proc_thermal_pci_probe, .remove = proc_thermal_pci_remove, .id_table = proc_thermal_pci_ids, + .driver.pm = &proc_thermal_pm, }; static const struct acpi_device_id int3401_device_ids[] = { @@ -479,6 +661,7 @@ static struct platform_driver int3401_driver = { .driver = { .name = "int3401 thermal", .acpi_match_table = int3401_device_ids, + .pm = &proc_thermal_pm, }, }; diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index 3055f9a12a17..44636475b2a3 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -651,13 +651,4 @@ static struct thermal_governor thermal_gov_power_allocator = { .unbind_from_tz = power_allocator_unbind, .throttle = power_allocator_throttle, }; - -int thermal_gov_power_allocator_register(void) -{ - return thermal_register_governor(&thermal_gov_power_allocator); -} - -void thermal_gov_power_allocator_unregister(void) -{ - thermal_unregister_governor(&thermal_gov_power_allocator); -} +THERMAL_GOVERNOR_DECLARE(thermal_gov_power_allocator); diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index 81a183befd48..6e051cbd824f 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -206,13 +206,4 @@ static struct thermal_governor thermal_gov_step_wise = { .name = "step_wise", .throttle = step_wise_throttle, }; - -int thermal_gov_step_wise_register(void) -{ - return thermal_register_governor(&thermal_gov_step_wise); -} - -void thermal_gov_step_wise_unregister(void) -{ - thermal_unregister_governor(&thermal_gov_step_wise); -} +THERMAL_GOVERNOR_DECLARE(thermal_gov_step_wise); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 46cfb7de4eb2..6bab66e84eb5 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -243,36 +243,42 @@ int thermal_build_list_of_policies(char *buf) return count; } -static int __init thermal_register_governors(void) +static void __init thermal_unregister_governors(void) { - int result; + struct thermal_governor **governor; - result = thermal_gov_step_wise_register(); - if (result) - return result; + for_each_governor_table(governor) + thermal_unregister_governor(*governor); +} - result = thermal_gov_fair_share_register(); - if (result) - return result; +static int __init thermal_register_governors(void) +{ + int ret = 0; + struct thermal_governor **governor; - result = thermal_gov_bang_bang_register(); - if (result) - return result; + for_each_governor_table(governor) { + ret = thermal_register_governor(*governor); + if (ret) { + pr_err("Failed to register governor: '%s'", + (*governor)->name); + break; + } - result = thermal_gov_user_space_register(); - if (result) - return result; + pr_info("Registered thermal governor '%s'", + (*governor)->name); + } - return thermal_gov_power_allocator_register(); -} + if (ret) { + struct thermal_governor **gov; -static void __init thermal_unregister_governors(void) -{ - thermal_gov_step_wise_unregister(); - thermal_gov_fair_share_unregister(); - thermal_gov_bang_bang_unregister(); - thermal_gov_user_space_unregister(); - thermal_gov_power_allocator_unregister(); + for_each_governor_table(gov) { + if (gov == governor) + break; + thermal_unregister_governor(*gov); + } + } + + return ret; } /* diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 0df190ed82a7..207b0cda70da 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -15,6 +15,21 @@ /* Initial state of a cooling device during binding */ #define THERMAL_NO_TARGET -1UL +/* Init section thermal table */ +extern struct thermal_governor *__governor_thermal_table[]; +extern struct thermal_governor *__governor_thermal_table_end[]; + +#define THERMAL_TABLE_ENTRY(table, name) \ + static typeof(name) *__thermal_table_entry_##name \ + __used __section(__##table##_thermal_table) = &name + +#define THERMAL_GOVERNOR_DECLARE(name) THERMAL_TABLE_ENTRY(governor, name) + +#define for_each_governor_table(__governor) \ + for (__governor = __governor_thermal_table; \ + __governor < __governor_thermal_table_end; \ + __governor++) + /* * This structure is used to describe the behavior of * a certain cooling device on a certain trip point @@ -74,46 +89,6 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, unsigned long new_state) {} #endif /* CONFIG_THERMAL_STATISTICS */ -#ifdef CONFIG_THERMAL_GOV_STEP_WISE -int thermal_gov_step_wise_register(void); -void thermal_gov_step_wise_unregister(void); -#else -static inline int thermal_gov_step_wise_register(void) { return 0; } -static inline void thermal_gov_step_wise_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_STEP_WISE */ - -#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE -int thermal_gov_fair_share_register(void); -void thermal_gov_fair_share_unregister(void); -#else -static inline int thermal_gov_fair_share_register(void) { return 0; } -static inline void thermal_gov_fair_share_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */ - -#ifdef CONFIG_THERMAL_GOV_BANG_BANG -int thermal_gov_bang_bang_register(void); -void thermal_gov_bang_bang_unregister(void); -#else -static inline int thermal_gov_bang_bang_register(void) { return 0; } -static inline void thermal_gov_bang_bang_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_BANG_BANG */ - -#ifdef CONFIG_THERMAL_GOV_USER_SPACE -int thermal_gov_user_space_register(void); -void thermal_gov_user_space_unregister(void); -#else -static inline int thermal_gov_user_space_register(void) { return 0; } -static inline void thermal_gov_user_space_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_USER_SPACE */ - -#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR -int thermal_gov_power_allocator_register(void); -void thermal_gov_power_allocator_unregister(void); -#else -static inline int thermal_gov_power_allocator_register(void) { return 0; } -static inline void thermal_gov_power_allocator_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */ - /* device tree support */ #ifdef CONFIG_THERMAL_OF int of_parse_thermal_zones(void); diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c index d62a99fc60a6..962873fd9242 100644 --- a/drivers/thermal/user_space.c +++ b/drivers/thermal/user_space.c @@ -44,14 +44,4 @@ static struct thermal_governor thermal_gov_user_space = { .name = "user_space", .throttle = notify_user_space, }; - -int thermal_gov_user_space_register(void) -{ - return thermal_register_governor(&thermal_gov_user_space); -} - -void thermal_gov_user_space_unregister(void) -{ - thermal_unregister_governor(&thermal_gov_user_space); -} - +THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space); |