aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/powercap
diff options
context:
space:
mode:
authorZhen Han <zhen.han@intel.com>2018-01-09 19:38:23 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-01-09 19:33:10 -0500
commit52b3672c135416d8ccc3c92f475b983a201fc6f5 (patch)
tree4c23511d7435077b119b9dcec9ef37aed6cda8a9 /drivers/powercap
parent7f6344896d3e5be3ccfef1c5c98ef24940e5f229 (diff)
powercap: add suspend and resume mechanism for SOC power limit
PL1 and PL2 could be throlled or de-throttled by Thermal management to control SOC temperature. However, currently, their value will be reset to default value after once system suspend and resume. Add pm_notifier to save PL1, PL2 before system suspect and restore PL1, PL2 after system resume. Signed-off-by: Zhen Han <zhen.han@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/powercap')
-rw-r--r--drivers/powercap/intel_rapl.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index d1694f1def72..0188cff98cdd 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -29,6 +29,7 @@
29#include <linux/sysfs.h> 29#include <linux/sysfs.h>
30#include <linux/cpu.h> 30#include <linux/cpu.h>
31#include <linux/powercap.h> 31#include <linux/powercap.h>
32#include <linux/suspend.h>
32#include <asm/iosf_mbi.h> 33#include <asm/iosf_mbi.h>
33 34
34#include <asm/processor.h> 35#include <asm/processor.h>
@@ -155,6 +156,7 @@ struct rapl_power_limit {
155 int prim_id; /* primitive ID used to enable */ 156 int prim_id; /* primitive ID used to enable */
156 struct rapl_domain *domain; 157 struct rapl_domain *domain;
157 const char *name; 158 const char *name;
159 u64 last_power_limit;
158}; 160};
159 161
160static const char pl1_name[] = "long_term"; 162static const char pl1_name[] = "long_term";
@@ -1533,6 +1535,92 @@ static int rapl_cpu_down_prep(unsigned int cpu)
1533 1535
1534static enum cpuhp_state pcap_rapl_online; 1536static enum cpuhp_state pcap_rapl_online;
1535 1537
1538static void power_limit_state_save(void)
1539{
1540 struct rapl_package *rp;
1541 struct rapl_domain *rd;
1542 int nr_pl, ret, i;
1543
1544 get_online_cpus();
1545 list_for_each_entry(rp, &rapl_packages, plist) {
1546 if (!rp->power_zone)
1547 continue;
1548 rd = power_zone_to_rapl_domain(rp->power_zone);
1549 nr_pl = find_nr_power_limit(rd);
1550 for (i = 0; i < nr_pl; i++) {
1551 switch (rd->rpl[i].prim_id) {
1552 case PL1_ENABLE:
1553 ret = rapl_read_data_raw(rd,
1554 POWER_LIMIT1,
1555 true,
1556 &rd->rpl[i].last_power_limit);
1557 if (ret)
1558 rd->rpl[i].last_power_limit = 0;
1559 break;
1560 case PL2_ENABLE:
1561 ret = rapl_read_data_raw(rd,
1562 POWER_LIMIT2,
1563 true,
1564 &rd->rpl[i].last_power_limit);
1565 if (ret)
1566 rd->rpl[i].last_power_limit = 0;
1567 break;
1568 }
1569 }
1570 }
1571 put_online_cpus();
1572}
1573
1574static void power_limit_state_restore(void)
1575{
1576 struct rapl_package *rp;
1577 struct rapl_domain *rd;
1578 int nr_pl, i;
1579
1580 get_online_cpus();
1581 list_for_each_entry(rp, &rapl_packages, plist) {
1582 if (!rp->power_zone)
1583 continue;
1584 rd = power_zone_to_rapl_domain(rp->power_zone);
1585 nr_pl = find_nr_power_limit(rd);
1586 for (i = 0; i < nr_pl; i++) {
1587 switch (rd->rpl[i].prim_id) {
1588 case PL1_ENABLE:
1589 if (rd->rpl[i].last_power_limit)
1590 rapl_write_data_raw(rd,
1591 POWER_LIMIT1,
1592 rd->rpl[i].last_power_limit);
1593 break;
1594 case PL2_ENABLE:
1595 if (rd->rpl[i].last_power_limit)
1596 rapl_write_data_raw(rd,
1597 POWER_LIMIT2,
1598 rd->rpl[i].last_power_limit);
1599 break;
1600 }
1601 }
1602 }
1603 put_online_cpus();
1604}
1605
1606static int rapl_pm_callback(struct notifier_block *nb,
1607 unsigned long mode, void *_unused)
1608{
1609 switch (mode) {
1610 case PM_SUSPEND_PREPARE:
1611 power_limit_state_save();
1612 break;
1613 case PM_POST_SUSPEND:
1614 power_limit_state_restore();
1615 break;
1616 }
1617 return NOTIFY_OK;
1618}
1619
1620static struct notifier_block rapl_pm_notifier = {
1621 .notifier_call = rapl_pm_callback,
1622};
1623
1536static int __init rapl_init(void) 1624static int __init rapl_init(void)
1537{ 1625{
1538 const struct x86_cpu_id *id; 1626 const struct x86_cpu_id *id;
@@ -1560,8 +1648,16 @@ static int __init rapl_init(void)
1560 1648
1561 /* Don't bail out if PSys is not supported */ 1649 /* Don't bail out if PSys is not supported */
1562 rapl_register_psys(); 1650 rapl_register_psys();
1651
1652 ret = register_pm_notifier(&rapl_pm_notifier);
1653 if (ret)
1654 goto err_unreg_all;
1655
1563 return 0; 1656 return 0;
1564 1657
1658err_unreg_all:
1659 cpuhp_remove_state(pcap_rapl_online);
1660
1565err_unreg: 1661err_unreg:
1566 rapl_unregister_powercap(); 1662 rapl_unregister_powercap();
1567 return ret; 1663 return ret;
@@ -1569,6 +1665,7 @@ err_unreg:
1569 1665
1570static void __exit rapl_exit(void) 1666static void __exit rapl_exit(void)
1571{ 1667{
1668 unregister_pm_notifier(&rapl_pm_notifier);
1572 cpuhp_remove_state(pcap_rapl_online); 1669 cpuhp_remove_state(pcap_rapl_online);
1573 rapl_unregister_powercap(); 1670 rapl_unregister_powercap();
1574} 1671}