diff options
| author | Zhen Han <zhen.han@intel.com> | 2018-01-09 19:38:23 -0500 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-01-09 19:33:10 -0500 |
| commit | 52b3672c135416d8ccc3c92f475b983a201fc6f5 (patch) | |
| tree | 4c23511d7435077b119b9dcec9ef37aed6cda8a9 /drivers/powercap | |
| parent | 7f6344896d3e5be3ccfef1c5c98ef24940e5f229 (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.c | 97 |
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 | ||
| 160 | static const char pl1_name[] = "long_term"; | 162 | static const char pl1_name[] = "long_term"; |
| @@ -1533,6 +1535,92 @@ static int rapl_cpu_down_prep(unsigned int cpu) | |||
| 1533 | 1535 | ||
| 1534 | static enum cpuhp_state pcap_rapl_online; | 1536 | static enum cpuhp_state pcap_rapl_online; |
| 1535 | 1537 | ||
| 1538 | static 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 | |||
| 1574 | static 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 | |||
| 1606 | static 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 | |||
| 1620 | static struct notifier_block rapl_pm_notifier = { | ||
| 1621 | .notifier_call = rapl_pm_callback, | ||
| 1622 | }; | ||
| 1623 | |||
| 1536 | static int __init rapl_init(void) | 1624 | static 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 | ||
| 1658 | err_unreg_all: | ||
| 1659 | cpuhp_remove_state(pcap_rapl_online); | ||
| 1660 | |||
| 1565 | err_unreg: | 1661 | err_unreg: |
| 1566 | rapl_unregister_powercap(); | 1662 | rapl_unregister_powercap(); |
| 1567 | return ret; | 1663 | return ret; |
| @@ -1569,6 +1665,7 @@ err_unreg: | |||
| 1569 | 1665 | ||
| 1570 | static void __exit rapl_exit(void) | 1666 | static 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 | } |
