aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/cpuidle-psci-domain.c10
-rw-r--r--drivers/cpuidle/cpuidle-psci.c26
-rw-r--r--drivers/pmdomain/amlogic/Kconfig11
-rw-r--r--drivers/pmdomain/amlogic/Makefile1
-rw-r--r--drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c380
-rw-r--r--drivers/pmdomain/bcm/raspberrypi-power.c43
-rw-r--r--drivers/pmdomain/core.c75
-rw-r--r--include/linux/pm_domain.h5
8 files changed, 105 insertions, 446 deletions
diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c
index fae958794339..ea28b73ef3fb 100644
--- a/drivers/cpuidle/cpuidle-psci-domain.c
+++ b/drivers/cpuidle/cpuidle-psci-domain.c
@@ -67,12 +67,16 @@ static int psci_pd_init(struct device_node *np, bool use_osi)
/*
* Allow power off when OSI has been successfully enabled.
- * PREEMPT_RT is not yet ready to enter domain idle states.
+ * On a PREEMPT_RT based configuration the domain idle states are
+ * supported, but only during system-wide suspend.
*/
- if (use_osi && !IS_ENABLED(CONFIG_PREEMPT_RT))
+ if (use_osi) {
pd->power_off = psci_pd_power_off;
- else
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
+ pd->flags |= GENPD_FLAG_RPM_ALWAYS_ON;
+ } else {
pd->flags |= GENPD_FLAG_ALWAYS_ON;
+ }
/* Use governor for CPU PM domains if it has some states to manage. */
pd_gov = pd->states ? &pm_domain_cpu_gov : NULL;
diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c
index 782030a27703..2562dc001fc1 100644
--- a/drivers/cpuidle/cpuidle-psci.c
+++ b/drivers/cpuidle/cpuidle-psci.c
@@ -37,6 +37,7 @@ struct psci_cpuidle_data {
static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data);
static DEFINE_PER_CPU(u32, domain_state);
+static bool psci_cpuidle_use_syscore;
static bool psci_cpuidle_use_cpuhp;
void psci_set_domain_state(u32 state)
@@ -166,6 +167,12 @@ static struct syscore_ops psci_idle_syscore_ops = {
.resume = psci_idle_syscore_resume,
};
+static void psci_idle_init_syscore(void)
+{
+ if (psci_cpuidle_use_syscore)
+ register_syscore_ops(&psci_idle_syscore_ops);
+}
+
static void psci_idle_init_cpuhp(void)
{
int err;
@@ -173,8 +180,6 @@ static void psci_idle_init_cpuhp(void)
if (!psci_cpuidle_use_cpuhp)
return;
- register_syscore_ops(&psci_idle_syscore_ops);
-
err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING,
"cpuidle/psci:online",
psci_idle_cpuhp_up,
@@ -222,22 +227,23 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv,
if (!psci_has_osi_support())
return 0;
- if (IS_ENABLED(CONFIG_PREEMPT_RT))
- return 0;
-
data->dev = dt_idle_attach_cpu(cpu, "psci");
if (IS_ERR_OR_NULL(data->dev))
return PTR_ERR_OR_ZERO(data->dev);
+ psci_cpuidle_use_syscore = true;
+
/*
* Using the deepest state for the CPU to trigger a potential selection
* of a shared state for the domain, assumes the domain states are all
- * deeper states.
+ * deeper states. On PREEMPT_RT the hierarchical topology is limited to
+ * s2ram and s2idle.
*/
- drv->states[state_count - 1].flags |= CPUIDLE_FLAG_RCU_IDLE;
- drv->states[state_count - 1].enter = psci_enter_domain_idle_state;
drv->states[state_count - 1].enter_s2idle = psci_enter_s2idle_domain_idle_state;
- psci_cpuidle_use_cpuhp = true;
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
+ drv->states[state_count - 1].enter = psci_enter_domain_idle_state;
+ psci_cpuidle_use_cpuhp = true;
+ }
return 0;
}
@@ -313,6 +319,7 @@ static void psci_cpu_deinit_idle(int cpu)
struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu);
dt_idle_detach_cpu(data->dev);
+ psci_cpuidle_use_syscore = false;
psci_cpuidle_use_cpuhp = false;
}
@@ -409,6 +416,7 @@ static int psci_cpuidle_probe(struct platform_device *pdev)
goto out_fail;
}
+ psci_idle_init_syscore();
psci_idle_init_cpuhp();
return 0;
diff --git a/drivers/pmdomain/amlogic/Kconfig b/drivers/pmdomain/amlogic/Kconfig
index 2108729909b5..e72b664174af 100644
--- a/drivers/pmdomain/amlogic/Kconfig
+++ b/drivers/pmdomain/amlogic/Kconfig
@@ -1,17 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "Amlogic PM Domains"
-config MESON_GX_PM_DOMAINS
- tristate "Amlogic Meson GX Power Domains driver"
- depends on ARCH_MESON || COMPILE_TEST
- depends on PM && OF
- default ARCH_MESON
- select PM_GENERIC_DOMAINS
- select PM_GENERIC_DOMAINS_OF
- help
- Say yes to expose Amlogic Meson GX Power Domains as
- Generic Power Domains.
-
config MESON_EE_PM_DOMAINS
tristate "Amlogic Meson Everything-Else Power Domains driver"
depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/pmdomain/amlogic/Makefile b/drivers/pmdomain/amlogic/Makefile
index 3d58abd574f9..99f195f09957 100644
--- a/drivers/pmdomain/amlogic/Makefile
+++ b/drivers/pmdomain/amlogic/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o
obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o
diff --git a/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c b/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c
deleted file mode 100644
index 6028e91664a4..000000000000
--- a/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (c) 2017 BayLibre, SAS
- * Author: Neil Armstrong <[email protected]>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/bitfield.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of.h>
-#include <linux/reset.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-
-/* AO Offsets */
-
-#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
-
-#define GEN_PWR_VPU_HDMI BIT(8)
-#define GEN_PWR_VPU_HDMI_ISO BIT(9)
-
-/* HHI Offsets */
-
-#define HHI_MEM_PD_REG0 (0x40 << 2)
-#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
-#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
-#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
-
-struct meson_gx_pwrc_vpu {
- struct generic_pm_domain genpd;
- struct regmap *regmap_ao;
- struct regmap *regmap_hhi;
- struct reset_control *rstc;
- struct clk *vpu_clk;
- struct clk *vapb_clk;
-};
-
-static inline
-struct meson_gx_pwrc_vpu *genpd_to_pd(struct generic_pm_domain *d)
-{
- return container_of(d, struct meson_gx_pwrc_vpu, genpd);
-}
-
-static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
- udelay(20);
-
- /* Power Down Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), BIT(i));
- udelay(5);
- }
- udelay(20);
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
-
- msleep(20);
-
- clk_disable_unprepare(pd->vpu_clk);
- clk_disable_unprepare(pd->vapb_clk);
-
- return 0;
-}
-
-static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
- udelay(20);
-
- /* Power Down Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), BIT(i));
- udelay(5);
- }
- udelay(20);
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
-
- msleep(20);
-
- clk_disable_unprepare(pd->vpu_clk);
- clk_disable_unprepare(pd->vapb_clk);
-
- return 0;
-}
-
-static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd)
-{
- int ret;
-
- ret = clk_prepare_enable(pd->vpu_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(pd->vapb_clk);
- if (ret)
- clk_disable_unprepare(pd->vpu_clk);
-
- return ret;
-}
-
-static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int ret;
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, 0);
- udelay(20);
-
- /* Power Up Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), 0);
- udelay(5);
- }
- udelay(20);
-
- ret = reset_control_assert(pd->rstc);
- if (ret)
- return ret;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, 0);
-
- ret = reset_control_deassert(pd->rstc);
- if (ret)
- return ret;
-
- ret = meson_gx_pwrc_vpu_setup_clk(pd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int ret;
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, 0);
- udelay(20);
-
- /* Power Up Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), 0);
- udelay(5);
- }
- udelay(20);
-
- ret = reset_control_assert(pd->rstc);
- if (ret)
- return ret;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, 0);
-
- ret = reset_control_deassert(pd->rstc);
- if (ret)
- return ret;
-
- ret = meson_gx_pwrc_vpu_setup_clk(pd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd)
-{
- u32 reg;
-
- regmap_read(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, &reg);
-
- return (reg & GEN_PWR_VPU_HDMI);
-}
-
-static struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
- .genpd = {
- .name = "vpu_hdmi",
- .power_off = meson_gx_pwrc_vpu_power_off,
- .power_on = meson_gx_pwrc_vpu_power_on,
- },
-};
-
-static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = {
- .genpd = {
- .name = "vpu_hdmi",
- .power_off = meson_g12a_pwrc_vpu_power_off,
- .power_on = meson_g12a_pwrc_vpu_power_on,
- },
-};
-
-static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
-{
- const struct meson_gx_pwrc_vpu *vpu_pd_match;
- struct regmap *regmap_ao, *regmap_hhi;
- struct meson_gx_pwrc_vpu *vpu_pd;
- struct device_node *parent_np;
- struct reset_control *rstc;
- struct clk *vpu_clk;
- struct clk *vapb_clk;
- bool powered_off;
- int ret;
-
- vpu_pd_match = of_device_get_match_data(&pdev->dev);
- if (!vpu_pd_match) {
- dev_err(&pdev->dev, "failed to get match data\n");
- return -ENODEV;
- }
-
- vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL);
- if (!vpu_pd)
- return -ENOMEM;
-
- memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
-
- parent_np = of_get_parent(pdev->dev.of_node);
- regmap_ao = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap_ao)) {
- dev_err(&pdev->dev, "failed to get regmap\n");
- return PTR_ERR(regmap_ao);
- }
-
- regmap_hhi = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "amlogic,hhi-sysctrl");
- if (IS_ERR(regmap_hhi)) {
- dev_err(&pdev->dev, "failed to get HHI regmap\n");
- return PTR_ERR(regmap_hhi);
- }
-
- rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
- if (IS_ERR(rstc))
- return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
- "failed to get reset lines\n");
-
- vpu_clk = devm_clk_get(&pdev->dev, "vpu");
- if (IS_ERR(vpu_clk)) {
- dev_err(&pdev->dev, "vpu clock request failed\n");
- return PTR_ERR(vpu_clk);
- }
-
- vapb_clk = devm_clk_get(&pdev->dev, "vapb");
- if (IS_ERR(vapb_clk)) {
- dev_err(&pdev->dev, "vapb clock request failed\n");
- return PTR_ERR(vapb_clk);
- }
-
- vpu_pd->regmap_ao = regmap_ao;
- vpu_pd->regmap_hhi = regmap_hhi;
- vpu_pd->rstc = rstc;
- vpu_pd->vpu_clk = vpu_clk;
- vpu_pd->vapb_clk = vapb_clk;
-
- platform_set_drvdata(pdev, vpu_pd);
-
- powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
-
- /* If already powered, sync the clock states */
- if (!powered_off) {
- ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd);
- if (ret)
- return ret;
- }
-
- vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
- pm_genpd_init(&vpu_pd->genpd, NULL, powered_off);
-
- return of_genpd_add_provider_simple(pdev->dev.of_node,
- &vpu_pd->genpd);
-}
-
-static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
-{
- struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
- bool powered_off;
-
- powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
- if (!powered_off)
- vpu_pd->genpd.power_off(&vpu_pd->genpd);
-}
-
-static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
- { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd },
- {
- .compatible = "amlogic,meson-g12a-pwrc-vpu",
- .data = &vpu_hdmi_pd_g12a
- },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, meson_gx_pwrc_vpu_match_table);
-
-static struct platform_driver meson_gx_pwrc_vpu_driver = {
- .probe = meson_gx_pwrc_vpu_probe,
- .shutdown = meson_gx_pwrc_vpu_shutdown,
- .driver = {
- .name = "meson_gx_pwrc_vpu",
- .of_match_table = meson_gx_pwrc_vpu_match_table,
- },
-};
-module_platform_driver(meson_gx_pwrc_vpu_driver);
-MODULE_DESCRIPTION("Amlogic Meson GX Power Domains driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pmdomain/bcm/raspberrypi-power.c b/drivers/pmdomain/bcm/raspberrypi-power.c
index 06196ebfe03b..b87ea7adb7be 100644
--- a/drivers/pmdomain/bcm/raspberrypi-power.c
+++ b/drivers/pmdomain/bcm/raspberrypi-power.c
@@ -41,40 +41,46 @@ struct rpi_power_domains {
*/
struct rpi_power_domain_packet {
u32 domain;
- u32 on;
+ u32 state;
};
/*
* Asks the firmware to enable or disable power on a specific power
* domain.
*/
-static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on)
+static int rpi_firmware_set_power(struct generic_pm_domain *domain, bool on)
{
+ struct rpi_power_domain *rpi_domain =
+ container_of(domain, struct rpi_power_domain, base);
+ bool old_interface = rpi_domain->old_interface;
struct rpi_power_domain_packet packet;
+ int ret;
packet.domain = rpi_domain->domain;
- packet.on = on;
- return rpi_firmware_property(rpi_domain->fw,
- rpi_domain->old_interface ?
- RPI_FIRMWARE_SET_POWER_STATE :
- RPI_FIRMWARE_SET_DOMAIN_STATE,
- &packet, sizeof(packet));
+ packet.state = on;
+
+ ret = rpi_firmware_property(rpi_domain->fw, old_interface ?
+ RPI_FIRMWARE_SET_POWER_STATE :
+ RPI_FIRMWARE_SET_DOMAIN_STATE,
+ &packet, sizeof(packet));
+ if (ret)
+ dev_err(&domain->dev, "Failed to set %s to %u (%d)\n",
+ old_interface ? "power" : "domain", on, ret);
+ else
+ dev_dbg(&domain->dev, "Set %s to %u\n",
+ old_interface ? "power" : "domain", on);
+
+ return ret;
}
static int rpi_domain_off(struct generic_pm_domain *domain)
{
- struct rpi_power_domain *rpi_domain =
- container_of(domain, struct rpi_power_domain, base);
-
- return rpi_firmware_set_power(rpi_domain, false);
+ return rpi_firmware_set_power(domain, false);
}
static int rpi_domain_on(struct generic_pm_domain *domain)
{
- struct rpi_power_domain *rpi_domain =
- container_of(domain, struct rpi_power_domain, base);
-
- return rpi_firmware_set_power(rpi_domain, true);
+ return rpi_firmware_set_power(domain, true);
}
static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
@@ -85,6 +91,7 @@ static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
dom->fw = rpi_domains->fw;
dom->base.name = name;
+ dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP;
dom->base.power_on = rpi_domain_on;
dom->base.power_off = rpi_domain_off;
@@ -142,13 +149,13 @@ rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains)
int ret;
packet.domain = RPI_POWER_DOMAIN_ARM;
- packet.on = ~0;
+ packet.state = ~0;
ret = rpi_firmware_property(rpi_domains->fw,
RPI_FIRMWARE_GET_DOMAIN_STATE,
&packet, sizeof(packet));
- return ret == 0 && packet.on != ~0;
+ return ret == 0 && packet.state != ~0;
}
static int rpi_power_probe(struct platform_device *pdev)
diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
index 7a61aa88c061..2731b285e017 100644
--- a/drivers/pmdomain/core.c
+++ b/drivers/pmdomain/core.c
@@ -117,6 +117,48 @@ static const struct genpd_lock_ops genpd_spin_ops = {
.unlock = genpd_unlock_spin,
};
+static void genpd_lock_raw_spin(struct generic_pm_domain *genpd)
+ __acquires(&genpd->raw_slock)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&genpd->raw_slock, flags);
+ genpd->raw_lock_flags = flags;
+}
+
+static void genpd_lock_nested_raw_spin(struct generic_pm_domain *genpd,
+ int depth)
+ __acquires(&genpd->raw_slock)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave_nested(&genpd->raw_slock, flags, depth);
+ genpd->raw_lock_flags = flags;
+}
+
+static int genpd_lock_interruptible_raw_spin(struct generic_pm_domain *genpd)
+ __acquires(&genpd->raw_slock)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&genpd->raw_slock, flags);
+ genpd->raw_lock_flags = flags;
+ return 0;
+}
+
+static void genpd_unlock_raw_spin(struct generic_pm_domain *genpd)
+ __releases(&genpd->raw_slock)
+{
+ raw_spin_unlock_irqrestore(&genpd->raw_slock, genpd->raw_lock_flags);
+}
+
+static const struct genpd_lock_ops genpd_raw_spin_ops = {
+ .lock = genpd_lock_raw_spin,
+ .lock_nested = genpd_lock_nested_raw_spin,
+ .lock_interruptible = genpd_lock_interruptible_raw_spin,
+ .unlock = genpd_unlock_raw_spin,
+};
+
#define genpd_lock(p) p->lock_ops->lock(p)
#define genpd_lock_nested(p, d) p->lock_ops->lock_nested(p, d)
#define genpd_lock_interruptible(p) p->lock_ops->lock_interruptible(p)
@@ -1758,7 +1800,6 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
genpd_lock(genpd);
genpd_set_cpumask(genpd, gpd_data->cpu);
- dev_pm_domain_set(dev, &genpd->domain);
genpd->device_count++;
if (gd)
@@ -1767,6 +1808,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
genpd_unlock(genpd);
+ dev_pm_domain_set(dev, &genpd->domain);
out:
if (ret)
genpd_free_dev_data(dev, gpd_data);
@@ -1823,12 +1865,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
genpd->gd->max_off_time_changed = true;
genpd_clear_cpumask(genpd, gpd_data->cpu);
- dev_pm_domain_set(dev, NULL);
list_del_init(&pdd->list_node);
genpd_unlock(genpd);
+ dev_pm_domain_set(dev, NULL);
+
if (genpd->detach_dev)
genpd->detach_dev(genpd, dev);
@@ -2143,7 +2186,10 @@ static void genpd_free_data(struct generic_pm_domain *genpd)
static void genpd_lock_init(struct generic_pm_domain *genpd)
{
- if (genpd_is_irq_safe(genpd)) {
+ if (genpd_is_cpu_domain(genpd)) {
+ raw_spin_lock_init(&genpd->raw_slock);
+ genpd->lock_ops = &genpd_raw_spin_ops;
+ } else if (genpd_is_irq_safe(genpd)) {
spin_lock_init(&genpd->slock);
genpd->lock_ops = &genpd_spin_ops;
} else {
@@ -3209,7 +3255,6 @@ static int genpd_summary_one(struct seq_file *s,
[GENPD_STATE_OFF] = "off"
};
struct pm_domain_data *pm_data;
- const char *kobj_path;
struct gpd_link *link;
char state[16];
int ret;
@@ -3242,17 +3287,10 @@ static int genpd_summary_one(struct seq_file *s,
}
list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
- kobj_path = kobject_get_path(&pm_data->dev->kobj,
- genpd_is_irq_safe(genpd) ?
- GFP_ATOMIC : GFP_KERNEL);
- if (kobj_path == NULL)
- continue;
-
- seq_printf(s, "\n %-50s ", kobj_path);
+ seq_printf(s, "\n %-50s ", dev_name(pm_data->dev));
rtpm_status_str(s, pm_data->dev);
perf_status_str(s, pm_data->dev);
mode_status_str(s, pm_data->dev);
- kfree(kobj_path);
}
seq_puts(s, "\n");
@@ -3421,23 +3459,14 @@ static int devices_show(struct seq_file *s, void *data)
{
struct generic_pm_domain *genpd = s->private;
struct pm_domain_data *pm_data;
- const char *kobj_path;
int ret = 0;
ret = genpd_lock_interruptible(genpd);
if (ret)
return -ERESTARTSYS;
- list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
- kobj_path = kobject_get_path(&pm_data->dev->kobj,
- genpd_is_irq_safe(genpd) ?
- GFP_ATOMIC : GFP_KERNEL);
- if (kobj_path == NULL)
- continue;
-
- seq_printf(s, "%s\n", kobj_path);
- kfree(kobj_path);
- }
+ list_for_each_entry(pm_data, &genpd->dev_list, list_node)
+ seq_printf(s, "%s\n", dev_name(pm_data->dev));
genpd_unlock(genpd);
return ret;
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 858c8e7851fb..b86bb52858ac 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -198,8 +198,11 @@ struct generic_pm_domain {
spinlock_t slock;
unsigned long lock_flags;
};
+ struct {
+ raw_spinlock_t raw_slock;
+ unsigned long raw_lock_flags;
+ };
};
-
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)