2022-12-21 17:26:52

by Akhil P Oommen

[permalink] [raw]
Subject: [PATCH v4 0/5] Improve GPU reset sequence for Adreno GPU


This is a rework of [1] using genpd instead of 'reset' framework.

As per the recommended reset sequence of Adreno gpu, we should ensure that
gpucc-cx-gdsc has collapsed at hardware to reset gpu's internal hardware states.
Because this gdsc is implemented as 'votable', gdsc driver doesn't poll and
wait until its hw status says OFF.

So use the newly introduced genpd api (dev_pm_genpd_synced_poweroff()) to
provide a hint to the gdsc driver to poll for the hw status and use genpd
notifier to wait from adreno gpu driver until gdsc is turned OFF.

This series is rebased on top of linux-next (20221215) since the changes span
multiple drivers.

[1] https://patchwork.freedesktop.org/series/107507/

Changes in v4:
- Update genpd function documentation (Ulf)

Changes in v3:
- Rename the var 'force_sync' to 'wait (Stephen)

Changes in v2:
- Minor formatting fix
- Select PM_GENERIC_DOMAINS from Kconfig

Akhil P Oommen (4):
clk: qcom: gdsc: Support 'synced_poweroff' genpd flag
drm/msm/a6xx: Vote for cx gdsc from gpu driver
drm/msm/a6xx: Remove cx gdsc polling using 'reset'
drm/msm/a6xx: Use genpd notifier to ensure cx-gdsc collapse

Ulf Hansson (1):
PM: domains: Allow a genpd consumer to require a synced power off

drivers/base/power/domain.c | 26 ++++++++++++++++++++
drivers/clk/qcom/gdsc.c | 11 +++++----
drivers/gpu/drm/msm/Kconfig | 1 +
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 46 ++++++++++++++++++++++++++++++++---
drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 7 ++++++
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 13 +++++++---
drivers/gpu/drm/msm/msm_gpu.c | 4 ---
drivers/gpu/drm/msm/msm_gpu.h | 4 ---
include/linux/pm_domain.h | 5 ++++
9 files changed, 97 insertions(+), 20 deletions(-)

--
2.7.4


2022-12-21 17:29:01

by Akhil P Oommen

[permalink] [raw]
Subject: [PATCH v4 4/5] drm/msm/a6xx: Remove cx gdsc polling using 'reset'

Remove the unused 'reset' interface which was supposed to help to ensure
that cx gdsc has collapsed during gpu recovery. This is was not enabled
so far due to missing gpucc driver support. Similar functionality using
genpd framework will be implemented in the upcoming patch.

This effectively reverts commit 1f6cca404918
("drm/msm/a6xx: Ensure CX collapse during gpu recovery").

Signed-off-by: Akhil P Oommen <[email protected]>
---

(no changes since v3)

Changes in v3:
- Updated commit msg (Philipp)

drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 4 ----
drivers/gpu/drm/msm/msm_gpu.c | 4 ----
drivers/gpu/drm/msm/msm_gpu.h | 4 ----
3 files changed, 12 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 36c8fb699b56..4b16e75dfa50 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -10,7 +10,6 @@

#include <linux/bitfield.h>
#include <linux/devfreq.h>
-#include <linux/reset.h>
#include <linux/soc/qcom/llcc-qcom.h>

#define GPU_PAS_ID 13
@@ -1298,9 +1297,6 @@ static void a6xx_recover(struct msm_gpu *gpu)
/* And the final one from recover worker */
pm_runtime_put_sync(&gpu->pdev->dev);

- /* Call into gpucc driver to poll for cx gdsc collapse */
- reset_control_reset(gpu->cx_collapse);
-
pm_runtime_use_autosuspend(&gpu->pdev->dev);

if (active_submits)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 30ed45af76ad..97e1319d4577 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -16,7 +16,6 @@
#include <generated/utsrelease.h>
#include <linux/string_helpers.h>
#include <linux/devcoredump.h>
-#include <linux/reset.h>
#include <linux/sched/task.h>

/*
@@ -933,9 +932,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
if (IS_ERR(gpu->gpu_cx))
gpu->gpu_cx = NULL;

- gpu->cx_collapse = devm_reset_control_get_optional_exclusive(&pdev->dev,
- "cx_collapse");
-
gpu->pdev = pdev;
platform_set_drvdata(pdev, &gpu->adreno_smmu);

diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 651786bc55e5..fa9e34d02c91 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -13,7 +13,6 @@
#include <linux/interconnect.h>
#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
-#include <linux/reset.h>

#include "msm_drv.h"
#include "msm_fence.h"
@@ -282,9 +281,6 @@ struct msm_gpu {
bool hw_apriv;

struct thermal_cooling_device *cooling;
-
- /* To poll for cx gdsc collapse during gpu recovery */
- struct reset_control *cx_collapse;
};

static inline struct msm_gpu *dev_to_gpu(struct device *dev)
--
2.7.4

2022-12-21 17:29:53

by Akhil P Oommen

[permalink] [raw]
Subject: [PATCH v4 5/5] drm/msm/a6xx: Use genpd notifier to ensure cx-gdsc collapse

As per the recommended recovery sequence of adreno gpu, cx gdsc should
collapse at hardware before it is turned back ON. This helps to clear
out the stale states in hardware before it is reinitialized. Use the
genpd notifier along with the newly introduced
dev_pm_genpd_synced_poweroff() api to ensure that cx gdsc has collapsed
before we turn it back ON.

Signed-off-by: Akhil P Oommen <[email protected]>
---

(no changes since v2)

Changes in v2:
- Select PM_GENERIC_DOMAINS from Kconfig

drivers/gpu/drm/msm/Kconfig | 1 +
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 15 +++++++++++++++
drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 6 ++++++
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 11 +++++++++++
4 files changed, 33 insertions(+)

diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 3c9dfdb0b328..74f5916f5ca5 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -28,6 +28,7 @@ config DRM_MSM
select SYNC_FILE
select PM_OPP
select NVMEM
+ select PM_GENERIC_DOMAINS
help
DRM/KMS driver for MSM/snapdragon.

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 1580d0090f35..c03830957c26 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -1507,6 +1507,17 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
gmu->initialized = false;
}

+static int cxpd_notifier_cb(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct a6xx_gmu *gmu = container_of(nb, struct a6xx_gmu, pd_nb);
+
+ if (action == GENPD_NOTIFY_OFF)
+ complete_all(&gmu->pd_gate);
+
+ return 0;
+}
+
int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
@@ -1640,6 +1651,10 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
goto detach_cxpd;
}

+ init_completion(&gmu->pd_gate);
+ complete_all(&gmu->pd_gate);
+ gmu->pd_nb.notifier_call = cxpd_notifier_cb;
+
/*
* Get a link to the GX power domain to reset the GPU in case of GMU
* crash
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index 5a42dd4dd31f..0bc3eb443fec 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -4,8 +4,10 @@
#ifndef _A6XX_GMU_H_
#define _A6XX_GMU_H_

+#include <linux/completion.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
+#include <linux/notifier.h>
#include "msm_drv.h"
#include "a6xx_hfi.h"

@@ -90,6 +92,10 @@ struct a6xx_gmu {
bool initialized;
bool hung;
bool legacy; /* a618 or a630 */
+
+ /* For power domain callback */
+ struct notifier_block pd_nb;
+ struct completion pd_gate;
};

static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 4b16e75dfa50..dd618b099110 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -10,6 +10,7 @@

#include <linux/bitfield.h>
#include <linux/devfreq.h>
+#include <linux/pm_domain.h>
#include <linux/soc/qcom/llcc-qcom.h>

#define GPU_PAS_ID 13
@@ -1258,6 +1259,7 @@ static void a6xx_recover(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+ struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
int i, active_submits;

adreno_dump_info(gpu);
@@ -1290,6 +1292,10 @@ static void a6xx_recover(struct msm_gpu *gpu)
*/
gpu->active_submits = 0;

+ reinit_completion(&gmu->pd_gate);
+ dev_pm_genpd_add_notifier(gmu->cxpd, &gmu->pd_nb);
+ dev_pm_genpd_synced_poweroff(gmu->cxpd);
+
/* Drop the rpm refcount from active submits */
if (active_submits)
pm_runtime_put(&gpu->pdev->dev);
@@ -1297,6 +1303,11 @@ static void a6xx_recover(struct msm_gpu *gpu)
/* And the final one from recover worker */
pm_runtime_put_sync(&gpu->pdev->dev);

+ if (!wait_for_completion_timeout(&gmu->pd_gate, msecs_to_jiffies(1000)))
+ DRM_DEV_ERROR(&gpu->pdev->dev, "cx gdsc didn't collapse\n");
+
+ dev_pm_genpd_remove_notifier(gmu->cxpd);
+
pm_runtime_use_autosuspend(&gpu->pdev->dev);

if (active_submits)
--
2.7.4

2022-12-21 17:42:53

by Akhil P Oommen

[permalink] [raw]
Subject: [PATCH v4 1/5] PM: domains: Allow a genpd consumer to require a synced power off

From: Ulf Hansson <[email protected]>

Some genpd providers doesn't ensure that it has turned off at hardware.
This is fine until the consumer really requires during some special
scenarios that the power domain collapse at hardware before it is
turned ON again.

An example is the reset sequence of Adreno GPU which requires that the
'gpucc cx gdsc' power domain should move to OFF state in hardware at
least once before turning in ON again to clear the internal state.

Signed-off-by: Ulf Hansson <[email protected]>
Signed-off-by: Akhil P Oommen <[email protected]>
---

Changes in v4:
- Update genpd function documentation (Ulf)

Changes in v2:
- Minor formatting fix

drivers/base/power/domain.c | 26 ++++++++++++++++++++++++++
include/linux/pm_domain.h | 5 +++++
2 files changed, 31 insertions(+)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 967bcf9d415e..84662d338188 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -519,6 +519,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer);

+/*
+ * dev_pm_genpd_synced_poweroff - Next power off should be synchronous
+ *
+ * @dev: A device that is attached to the genpd.
+ *
+ * Allows a consumer of the genpd to notify the provider that the next power off
+ * should be synchronous.
+ *
+ * It is assumed that the users guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ */
+void dev_pm_genpd_synced_poweroff(struct device *dev)
+{
+ struct generic_pm_domain *genpd;
+
+ genpd = dev_to_genpd_safe(dev);
+ if (!genpd)
+ return;
+
+ genpd_lock(genpd);
+ genpd->synced_poweroff = true;
+ genpd_unlock(genpd);
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff);
+
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
unsigned int state_idx = genpd->state_idx;
@@ -562,6 +587,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)

out:
raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL);
+ genpd->synced_poweroff = false;
return 0;
err:
raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF,
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 1cd41bdf73cf..f776fb93eaa0 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -136,6 +136,7 @@ struct generic_pm_domain {
unsigned int prepared_count; /* Suspend counter of prepared devices */
unsigned int performance_state; /* Aggregated max performance state */
cpumask_var_t cpus; /* A cpumask of the attached CPUs */
+ bool synced_poweroff; /* A consumer needs a synced poweroff */
int (*power_off)(struct generic_pm_domain *domain);
int (*power_on)(struct generic_pm_domain *domain);
struct raw_notifier_head power_notifiers; /* Power on/off notifiers */
@@ -235,6 +236,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
int dev_pm_genpd_remove_notifier(struct device *dev);
void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next);
ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
+void dev_pm_genpd_synced_poweroff(struct device *dev);

extern struct dev_power_governor simple_qos_governor;
extern struct dev_power_governor pm_domain_always_on_gov;
@@ -300,6 +302,9 @@ static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
{
return KTIME_MAX;
}
+static inline void dev_pm_genpd_synced_poweroff(struct device *dev)
+{ }
+
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
#endif
--
2.7.4

2022-12-21 17:45:40

by Akhil P Oommen

[permalink] [raw]
Subject: [PATCH v4 2/5] clk: qcom: gdsc: Support 'synced_poweroff' genpd flag

Add support for the newly added 'synced_poweroff' genpd flag. This allows
some clients (like adreno gpu driver) to request gdsc driver to ensure
a votable gdsc (like gpucc cx gdsc) has collapsed at hardware.

Signed-off-by: Akhil P Oommen <[email protected]>
---

(no changes since v3)

Changes in v3:
- Rename the var 'force_sync' to 'wait (Stephen)

drivers/clk/qcom/gdsc.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 9e4d6ce891aa..5358e28122ab 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -136,7 +136,8 @@ static int gdsc_update_collapse_bit(struct gdsc *sc, bool val)
return 0;
}

-static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
+static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status,
+ bool wait)
{
int ret;

@@ -149,7 +150,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
ret = gdsc_update_collapse_bit(sc, status == GDSC_OFF);

/* If disabling votable gdscs, don't poll on status */
- if ((sc->flags & VOTABLE) && status == GDSC_OFF) {
+ if ((sc->flags & VOTABLE) && status == GDSC_OFF && !wait) {
/*
* Add a short delay here to ensure that an enable
* right after it was disabled does not put it in an
@@ -275,7 +276,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
gdsc_deassert_clamp_io(sc);
}

- ret = gdsc_toggle_logic(sc, GDSC_ON);
+ ret = gdsc_toggle_logic(sc, GDSC_ON, false);
if (ret)
return ret;

@@ -352,7 +353,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
if (sc->pwrsts == PWRSTS_RET_ON)
return 0;

- ret = gdsc_toggle_logic(sc, GDSC_OFF);
+ ret = gdsc_toggle_logic(sc, GDSC_OFF, domain->synced_poweroff);
if (ret)
return ret;

@@ -392,7 +393,7 @@ static int gdsc_init(struct gdsc *sc)

/* Force gdsc ON if only ON state is supported */
if (sc->pwrsts == PWRSTS_ON) {
- ret = gdsc_toggle_logic(sc, GDSC_ON);
+ ret = gdsc_toggle_logic(sc, GDSC_ON, false);
if (ret)
return ret;
}
--
2.7.4

2022-12-21 17:50:39

by Akhil P Oommen

[permalink] [raw]
Subject: [PATCH v4 3/5] drm/msm/a6xx: Vote for cx gdsc from gpu driver

When a device has multiple power domains, dev->power_domain is left
empty during probe. That didn't cause any issue so far because we are
freeloading on smmu driver's vote on cx gdsc. Instead of that, create
a device_link between cx genpd device and gmu device to keep a vote from
gpu driver.

Before this patch:
localhost ~ # cat /sys/kernel/debug/pm_genpd/pm_genpd_summary
gx_gdsc on 0
/devices/genpd:1:3d6a000.gmu active 0
cx_gdsc on 0
/devices/platform/soc@0/3da0000.iommu active 0

After this patch:
localhost ~ # cat /sys/kernel/debug/pm_genpd/pm_genpd_summary
gx_gdsc on 0
/devices/genpd:1:3d6a000.gmu active 0
cx_gdsc on 0
/devices/platform/soc@0/3da0000.iommu active 0
/devices/genpd:0:3d6a000.gmu active 0

Signed-off-by: Akhil P Oommen <[email protected]>
---

(no changes since v1)

drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 31 +++++++++++++++++++++++++++----
drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 1 +
2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 6484b97c5344..1580d0090f35 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -1479,6 +1479,12 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)

pm_runtime_force_suspend(gmu->dev);

+ /*
+ * Since cxpd is a virt device, the devlink with gmu-dev will be removed
+ * automatically when we do detach
+ */
+ dev_pm_domain_detach(gmu->cxpd, false);
+
if (!IS_ERR_OR_NULL(gmu->gxpd)) {
pm_runtime_disable(gmu->gxpd);
dev_pm_domain_detach(gmu->gxpd, false);
@@ -1605,8 +1611,10 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)

if (adreno_is_a650_family(adreno_gpu)) {
gmu->rscc = a6xx_gmu_get_mmio(pdev, "rscc");
- if (IS_ERR(gmu->rscc))
+ if (IS_ERR(gmu->rscc)) {
+ ret = -ENODEV;
goto err_mmio;
+ }
} else {
gmu->rscc = gmu->mmio + 0x23000;
}
@@ -1615,8 +1623,22 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
gmu->hfi_irq = a6xx_gmu_get_irq(gmu, pdev, "hfi", a6xx_hfi_irq);
gmu->gmu_irq = a6xx_gmu_get_irq(gmu, pdev, "gmu", a6xx_gmu_irq);

- if (gmu->hfi_irq < 0 || gmu->gmu_irq < 0)
+ if (gmu->hfi_irq < 0 || gmu->gmu_irq < 0) {
+ ret = -ENODEV;
+ goto err_mmio;
+ }
+
+ gmu->cxpd = dev_pm_domain_attach_by_name(gmu->dev, "cx");
+ if (IS_ERR(gmu->cxpd)) {
+ ret = PTR_ERR(gmu->cxpd);
goto err_mmio;
+ }
+
+ if (!device_link_add(gmu->dev, gmu->cxpd,
+ DL_FLAG_PM_RUNTIME)) {
+ ret = -ENODEV;
+ goto detach_cxpd;
+ }

/*
* Get a link to the GX power domain to reset the GPU in case of GMU
@@ -1634,6 +1656,9 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)

return 0;

+detach_cxpd:
+ dev_pm_domain_detach(gmu->cxpd, false);
+
err_mmio:
iounmap(gmu->mmio);
if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc"))
@@ -1641,8 +1666,6 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
free_irq(gmu->gmu_irq, gmu);
free_irq(gmu->hfi_irq, gmu);

- ret = -ENODEV;
-
err_memory:
a6xx_gmu_memory_free(gmu);
err_put_device:
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index e034935b3986..5a42dd4dd31f 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -56,6 +56,7 @@ struct a6xx_gmu {
int gmu_irq;

struct device *gxpd;
+ struct device *cxpd;

int idle_level;

--
2.7.4

2022-12-22 16:13:19

by Ulf Hansson

[permalink] [raw]
Subject: Re: [PATCH v4 4/5] drm/msm/a6xx: Remove cx gdsc polling using 'reset'

On Wed, 21 Dec 2022 at 18:14, Akhil P Oommen <[email protected]> wrote:
>
> Remove the unused 'reset' interface which was supposed to help to ensure
> that cx gdsc has collapsed during gpu recovery. This is was not enabled
> so far due to missing gpucc driver support. Similar functionality using
> genpd framework will be implemented in the upcoming patch.
>
> This effectively reverts commit 1f6cca404918
> ("drm/msm/a6xx: Ensure CX collapse during gpu recovery").
>
> Signed-off-by: Akhil P Oommen <[email protected]>

Reviewed-by: Ulf Hansson <[email protected]>

Kind regards
Uffe


> ---
>
> (no changes since v3)
>
> Changes in v3:
> - Updated commit msg (Philipp)
>
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 4 ----
> drivers/gpu/drm/msm/msm_gpu.c | 4 ----
> drivers/gpu/drm/msm/msm_gpu.h | 4 ----
> 3 files changed, 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index 36c8fb699b56..4b16e75dfa50 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -10,7 +10,6 @@
>
> #include <linux/bitfield.h>
> #include <linux/devfreq.h>
> -#include <linux/reset.h>
> #include <linux/soc/qcom/llcc-qcom.h>
>
> #define GPU_PAS_ID 13
> @@ -1298,9 +1297,6 @@ static void a6xx_recover(struct msm_gpu *gpu)
> /* And the final one from recover worker */
> pm_runtime_put_sync(&gpu->pdev->dev);
>
> - /* Call into gpucc driver to poll for cx gdsc collapse */
> - reset_control_reset(gpu->cx_collapse);
> -
> pm_runtime_use_autosuspend(&gpu->pdev->dev);
>
> if (active_submits)
> diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
> index 30ed45af76ad..97e1319d4577 100644
> --- a/drivers/gpu/drm/msm/msm_gpu.c
> +++ b/drivers/gpu/drm/msm/msm_gpu.c
> @@ -16,7 +16,6 @@
> #include <generated/utsrelease.h>
> #include <linux/string_helpers.h>
> #include <linux/devcoredump.h>
> -#include <linux/reset.h>
> #include <linux/sched/task.h>
>
> /*
> @@ -933,9 +932,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
> if (IS_ERR(gpu->gpu_cx))
> gpu->gpu_cx = NULL;
>
> - gpu->cx_collapse = devm_reset_control_get_optional_exclusive(&pdev->dev,
> - "cx_collapse");
> -
> gpu->pdev = pdev;
> platform_set_drvdata(pdev, &gpu->adreno_smmu);
>
> diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
> index 651786bc55e5..fa9e34d02c91 100644
> --- a/drivers/gpu/drm/msm/msm_gpu.h
> +++ b/drivers/gpu/drm/msm/msm_gpu.h
> @@ -13,7 +13,6 @@
> #include <linux/interconnect.h>
> #include <linux/pm_opp.h>
> #include <linux/regulator/consumer.h>
> -#include <linux/reset.h>
>
> #include "msm_drv.h"
> #include "msm_fence.h"
> @@ -282,9 +281,6 @@ struct msm_gpu {
> bool hw_apriv;
>
> struct thermal_cooling_device *cooling;
> -
> - /* To poll for cx gdsc collapse during gpu recovery */
> - struct reset_control *cx_collapse;
> };
>
> static inline struct msm_gpu *dev_to_gpu(struct device *dev)
> --
> 2.7.4
>

2022-12-22 16:27:15

by Ulf Hansson

[permalink] [raw]
Subject: Re: [PATCH v4 3/5] drm/msm/a6xx: Vote for cx gdsc from gpu driver

On Wed, 21 Dec 2022 at 18:14, Akhil P Oommen <[email protected]> wrote:
>
> When a device has multiple power domains, dev->power_domain is left
> empty during probe. That didn't cause any issue so far because we are
> freeloading on smmu driver's vote on cx gdsc. Instead of that, create
> a device_link between cx genpd device and gmu device to keep a vote from
> gpu driver.
>
> Before this patch:
> localhost ~ # cat /sys/kernel/debug/pm_genpd/pm_genpd_summary
> gx_gdsc on 0
> /devices/genpd:1:3d6a000.gmu active 0
> cx_gdsc on 0
> /devices/platform/soc@0/3da0000.iommu active 0
>
> After this patch:
> localhost ~ # cat /sys/kernel/debug/pm_genpd/pm_genpd_summary
> gx_gdsc on 0
> /devices/genpd:1:3d6a000.gmu active 0
> cx_gdsc on 0
> /devices/platform/soc@0/3da0000.iommu active 0
> /devices/genpd:0:3d6a000.gmu active 0
>
> Signed-off-by: Akhil P Oommen <[email protected]>

Reviewed-by: Ulf Hansson <[email protected]>

Kind regards
Uffe

> ---
>
> (no changes since v1)
>
> drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 31 +++++++++++++++++++++++++++----
> drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 1 +
> 2 files changed, 28 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> index 6484b97c5344..1580d0090f35 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> @@ -1479,6 +1479,12 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
>
> pm_runtime_force_suspend(gmu->dev);
>
> + /*
> + * Since cxpd is a virt device, the devlink with gmu-dev will be removed
> + * automatically when we do detach
> + */
> + dev_pm_domain_detach(gmu->cxpd, false);
> +
> if (!IS_ERR_OR_NULL(gmu->gxpd)) {
> pm_runtime_disable(gmu->gxpd);
> dev_pm_domain_detach(gmu->gxpd, false);
> @@ -1605,8 +1611,10 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
>
> if (adreno_is_a650_family(adreno_gpu)) {
> gmu->rscc = a6xx_gmu_get_mmio(pdev, "rscc");
> - if (IS_ERR(gmu->rscc))
> + if (IS_ERR(gmu->rscc)) {
> + ret = -ENODEV;
> goto err_mmio;
> + }
> } else {
> gmu->rscc = gmu->mmio + 0x23000;
> }
> @@ -1615,8 +1623,22 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
> gmu->hfi_irq = a6xx_gmu_get_irq(gmu, pdev, "hfi", a6xx_hfi_irq);
> gmu->gmu_irq = a6xx_gmu_get_irq(gmu, pdev, "gmu", a6xx_gmu_irq);
>
> - if (gmu->hfi_irq < 0 || gmu->gmu_irq < 0)
> + if (gmu->hfi_irq < 0 || gmu->gmu_irq < 0) {
> + ret = -ENODEV;
> + goto err_mmio;
> + }
> +
> + gmu->cxpd = dev_pm_domain_attach_by_name(gmu->dev, "cx");
> + if (IS_ERR(gmu->cxpd)) {
> + ret = PTR_ERR(gmu->cxpd);
> goto err_mmio;
> + }
> +
> + if (!device_link_add(gmu->dev, gmu->cxpd,
> + DL_FLAG_PM_RUNTIME)) {
> + ret = -ENODEV;
> + goto detach_cxpd;
> + }
>
> /*
> * Get a link to the GX power domain to reset the GPU in case of GMU
> @@ -1634,6 +1656,9 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
>
> return 0;
>
> +detach_cxpd:
> + dev_pm_domain_detach(gmu->cxpd, false);
> +
> err_mmio:
> iounmap(gmu->mmio);
> if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc"))
> @@ -1641,8 +1666,6 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
> free_irq(gmu->gmu_irq, gmu);
> free_irq(gmu->hfi_irq, gmu);
>
> - ret = -ENODEV;
> -
> err_memory:
> a6xx_gmu_memory_free(gmu);
> err_put_device:
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
> index e034935b3986..5a42dd4dd31f 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
> @@ -56,6 +56,7 @@ struct a6xx_gmu {
> int gmu_irq;
>
> struct device *gxpd;
> + struct device *cxpd;
>
> int idle_level;
>
> --
> 2.7.4
>

2022-12-22 16:37:00

by Ulf Hansson

[permalink] [raw]
Subject: Re: [PATCH v4 5/5] drm/msm/a6xx: Use genpd notifier to ensure cx-gdsc collapse

On Wed, 21 Dec 2022 at 18:14, Akhil P Oommen <[email protected]> wrote:
>
> As per the recommended recovery sequence of adreno gpu, cx gdsc should
> collapse at hardware before it is turned back ON. This helps to clear
> out the stale states in hardware before it is reinitialized. Use the
> genpd notifier along with the newly introduced
> dev_pm_genpd_synced_poweroff() api to ensure that cx gdsc has collapsed
> before we turn it back ON.
>
> Signed-off-by: Akhil P Oommen <[email protected]>

Reviewed-by: Ulf Hansson <[email protected]>

Kind regards
Uffe

> ---
>
> (no changes since v2)
>
> Changes in v2:
> - Select PM_GENERIC_DOMAINS from Kconfig
>
> drivers/gpu/drm/msm/Kconfig | 1 +
> drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 15 +++++++++++++++
> drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 6 ++++++
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 11 +++++++++++
> 4 files changed, 33 insertions(+)
>
> diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
> index 3c9dfdb0b328..74f5916f5ca5 100644
> --- a/drivers/gpu/drm/msm/Kconfig
> +++ b/drivers/gpu/drm/msm/Kconfig
> @@ -28,6 +28,7 @@ config DRM_MSM
> select SYNC_FILE
> select PM_OPP
> select NVMEM
> + select PM_GENERIC_DOMAINS
> help
> DRM/KMS driver for MSM/snapdragon.
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> index 1580d0090f35..c03830957c26 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> @@ -1507,6 +1507,17 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
> gmu->initialized = false;
> }
>
> +static int cxpd_notifier_cb(struct notifier_block *nb,
> + unsigned long action, void *data)
> +{
> + struct a6xx_gmu *gmu = container_of(nb, struct a6xx_gmu, pd_nb);
> +
> + if (action == GENPD_NOTIFY_OFF)
> + complete_all(&gmu->pd_gate);
> +
> + return 0;
> +}
> +
> int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
> {
> struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
> @@ -1640,6 +1651,10 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
> goto detach_cxpd;
> }
>
> + init_completion(&gmu->pd_gate);
> + complete_all(&gmu->pd_gate);
> + gmu->pd_nb.notifier_call = cxpd_notifier_cb;
> +
> /*
> * Get a link to the GX power domain to reset the GPU in case of GMU
> * crash
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
> index 5a42dd4dd31f..0bc3eb443fec 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
> @@ -4,8 +4,10 @@
> #ifndef _A6XX_GMU_H_
> #define _A6XX_GMU_H_
>
> +#include <linux/completion.h>
> #include <linux/iopoll.h>
> #include <linux/interrupt.h>
> +#include <linux/notifier.h>
> #include "msm_drv.h"
> #include "a6xx_hfi.h"
>
> @@ -90,6 +92,10 @@ struct a6xx_gmu {
> bool initialized;
> bool hung;
> bool legacy; /* a618 or a630 */
> +
> + /* For power domain callback */
> + struct notifier_block pd_nb;
> + struct completion pd_gate;
> };
>
> static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset)
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index 4b16e75dfa50..dd618b099110 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -10,6 +10,7 @@
>
> #include <linux/bitfield.h>
> #include <linux/devfreq.h>
> +#include <linux/pm_domain.h>
> #include <linux/soc/qcom/llcc-qcom.h>
>
> #define GPU_PAS_ID 13
> @@ -1258,6 +1259,7 @@ static void a6xx_recover(struct msm_gpu *gpu)
> {
> struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
> + struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
> int i, active_submits;
>
> adreno_dump_info(gpu);
> @@ -1290,6 +1292,10 @@ static void a6xx_recover(struct msm_gpu *gpu)
> */
> gpu->active_submits = 0;
>
> + reinit_completion(&gmu->pd_gate);
> + dev_pm_genpd_add_notifier(gmu->cxpd, &gmu->pd_nb);
> + dev_pm_genpd_synced_poweroff(gmu->cxpd);
> +
> /* Drop the rpm refcount from active submits */
> if (active_submits)
> pm_runtime_put(&gpu->pdev->dev);
> @@ -1297,6 +1303,11 @@ static void a6xx_recover(struct msm_gpu *gpu)
> /* And the final one from recover worker */
> pm_runtime_put_sync(&gpu->pdev->dev);
>
> + if (!wait_for_completion_timeout(&gmu->pd_gate, msecs_to_jiffies(1000)))
> + DRM_DEV_ERROR(&gpu->pdev->dev, "cx gdsc didn't collapse\n");
> +
> + dev_pm_genpd_remove_notifier(gmu->cxpd);
> +
> pm_runtime_use_autosuspend(&gpu->pdev->dev);
>
> if (active_submits)
> --
> 2.7.4
>

2022-12-22 16:42:06

by Ulf Hansson

[permalink] [raw]
Subject: Re: [PATCH v4 2/5] clk: qcom: gdsc: Support 'synced_poweroff' genpd flag

On Wed, 21 Dec 2022 at 18:14, Akhil P Oommen <[email protected]> wrote:
>
> Add support for the newly added 'synced_poweroff' genpd flag. This allows
> some clients (like adreno gpu driver) to request gdsc driver to ensure
> a votable gdsc (like gpucc cx gdsc) has collapsed at hardware.
>
> Signed-off-by: Akhil P Oommen <[email protected]>

Reviewed-by: Ulf Hansson <[email protected]>

Kind regards
Uffe

> ---
>
> (no changes since v3)
>
> Changes in v3:
> - Rename the var 'force_sync' to 'wait (Stephen)
>
> drivers/clk/qcom/gdsc.c | 11 ++++++-----
> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
> index 9e4d6ce891aa..5358e28122ab 100644
> --- a/drivers/clk/qcom/gdsc.c
> +++ b/drivers/clk/qcom/gdsc.c
> @@ -136,7 +136,8 @@ static int gdsc_update_collapse_bit(struct gdsc *sc, bool val)
> return 0;
> }
>
> -static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
> +static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status,
> + bool wait)
> {
> int ret;
>
> @@ -149,7 +150,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
> ret = gdsc_update_collapse_bit(sc, status == GDSC_OFF);
>
> /* If disabling votable gdscs, don't poll on status */
> - if ((sc->flags & VOTABLE) && status == GDSC_OFF) {
> + if ((sc->flags & VOTABLE) && status == GDSC_OFF && !wait) {
> /*
> * Add a short delay here to ensure that an enable
> * right after it was disabled does not put it in an
> @@ -275,7 +276,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
> gdsc_deassert_clamp_io(sc);
> }
>
> - ret = gdsc_toggle_logic(sc, GDSC_ON);
> + ret = gdsc_toggle_logic(sc, GDSC_ON, false);
> if (ret)
> return ret;
>
> @@ -352,7 +353,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
> if (sc->pwrsts == PWRSTS_RET_ON)
> return 0;
>
> - ret = gdsc_toggle_logic(sc, GDSC_OFF);
> + ret = gdsc_toggle_logic(sc, GDSC_OFF, domain->synced_poweroff);
> if (ret)
> return ret;
>
> @@ -392,7 +393,7 @@ static int gdsc_init(struct gdsc *sc)
>
> /* Force gdsc ON if only ON state is supported */
> if (sc->pwrsts == PWRSTS_ON) {
> - ret = gdsc_toggle_logic(sc, GDSC_ON);
> + ret = gdsc_toggle_logic(sc, GDSC_ON, false);
> if (ret)
> return ret;
> }
> --
> 2.7.4
>

2022-12-28 18:53:34

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v4 1/5] PM: domains: Allow a genpd consumer to require a synced power off

On Wed, Dec 21, 2022 at 10:43:59PM +0530, Akhil P Oommen wrote:
> From: Ulf Hansson <[email protected]>
>
> Some genpd providers doesn't ensure that it has turned off at hardware.
> This is fine until the consumer really requires during some special
> scenarios that the power domain collapse at hardware before it is
> turned ON again.
>
> An example is the reset sequence of Adreno GPU which requires that the
> 'gpucc cx gdsc' power domain should move to OFF state in hardware at
> least once before turning in ON again to clear the internal state.
>
> Signed-off-by: Ulf Hansson <[email protected]>
> Signed-off-by: Akhil P Oommen <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

@Rafael, would you be willing to share an immutable branch with this
change? Or would you be okay with me doing so from the qcom clock tree?

Regards,
Bjorn

> ---
>
> Changes in v4:
> - Update genpd function documentation (Ulf)
>
> Changes in v2:
> - Minor formatting fix
>
> drivers/base/power/domain.c | 26 ++++++++++++++++++++++++++
> include/linux/pm_domain.h | 5 +++++
> 2 files changed, 31 insertions(+)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 967bcf9d415e..84662d338188 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -519,6 +519,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
> }
> EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer);
>
> +/*
> + * dev_pm_genpd_synced_poweroff - Next power off should be synchronous
> + *
> + * @dev: A device that is attached to the genpd.
> + *
> + * Allows a consumer of the genpd to notify the provider that the next power off
> + * should be synchronous.
> + *
> + * It is assumed that the users guarantee that the genpd wouldn't be detached
> + * while this routine is getting called.
> + */
> +void dev_pm_genpd_synced_poweroff(struct device *dev)
> +{
> + struct generic_pm_domain *genpd;
> +
> + genpd = dev_to_genpd_safe(dev);
> + if (!genpd)
> + return;
> +
> + genpd_lock(genpd);
> + genpd->synced_poweroff = true;
> + genpd_unlock(genpd);
> +}
> +EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff);
> +
> static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
> {
> unsigned int state_idx = genpd->state_idx;
> @@ -562,6 +587,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>
> out:
> raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL);
> + genpd->synced_poweroff = false;
> return 0;
> err:
> raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF,
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 1cd41bdf73cf..f776fb93eaa0 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -136,6 +136,7 @@ struct generic_pm_domain {
> unsigned int prepared_count; /* Suspend counter of prepared devices */
> unsigned int performance_state; /* Aggregated max performance state */
> cpumask_var_t cpus; /* A cpumask of the attached CPUs */
> + bool synced_poweroff; /* A consumer needs a synced poweroff */
> int (*power_off)(struct generic_pm_domain *domain);
> int (*power_on)(struct generic_pm_domain *domain);
> struct raw_notifier_head power_notifiers; /* Power on/off notifiers */
> @@ -235,6 +236,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
> int dev_pm_genpd_remove_notifier(struct device *dev);
> void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next);
> ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
> +void dev_pm_genpd_synced_poweroff(struct device *dev);
>
> extern struct dev_power_governor simple_qos_governor;
> extern struct dev_power_governor pm_domain_always_on_gov;
> @@ -300,6 +302,9 @@ static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
> {
> return KTIME_MAX;
> }
> +static inline void dev_pm_genpd_synced_poweroff(struct device *dev)
> +{ }
> +
> #define simple_qos_governor (*(struct dev_power_governor *)(NULL))
> #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
> #endif
> --
> 2.7.4
>

2023-01-02 10:11:01

by Akhil P Oommen

[permalink] [raw]
Subject: Re: [PATCH v4 1/5] PM: domains: Allow a genpd consumer to require a synced power off

On 12/29/2022 12:13 AM, Bjorn Andersson wrote:
> On Wed, Dec 21, 2022 at 10:43:59PM +0530, Akhil P Oommen wrote:
>> From: Ulf Hansson <[email protected]>
>>
>> Some genpd providers doesn't ensure that it has turned off at hardware.
>> This is fine until the consumer really requires during some special
>> scenarios that the power domain collapse at hardware before it is
>> turned ON again.
>>
>> An example is the reset sequence of Adreno GPU which requires that the
>> 'gpucc cx gdsc' power domain should move to OFF state in hardware at
>> least once before turning in ON again to clear the internal state.
>>
>> Signed-off-by: Ulf Hansson <[email protected]>
>> Signed-off-by: Akhil P Oommen <[email protected]>
> Reviewed-by: Bjorn Andersson <[email protected]>
>
> @Rafael, would you be willing to share an immutable branch with this
> change? Or would you be okay with me doing so from the qcom clock tree?
>
> Regards,
> Bjorn
Rafael, gentle ping. Could you please check Bjorn's question here?

-Akhil.
>
>> ---
>>
>> Changes in v4:
>> - Update genpd function documentation (Ulf)
>>
>> Changes in v2:
>> - Minor formatting fix
>>
>> drivers/base/power/domain.c | 26 ++++++++++++++++++++++++++
>> include/linux/pm_domain.h | 5 +++++
>> 2 files changed, 31 insertions(+)
>>
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index 967bcf9d415e..84662d338188 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -519,6 +519,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
>> }
>> EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer);
>>
>> +/*
>> + * dev_pm_genpd_synced_poweroff - Next power off should be synchronous
>> + *
>> + * @dev: A device that is attached to the genpd.
>> + *
>> + * Allows a consumer of the genpd to notify the provider that the next power off
>> + * should be synchronous.
>> + *
>> + * It is assumed that the users guarantee that the genpd wouldn't be detached
>> + * while this routine is getting called.
>> + */
>> +void dev_pm_genpd_synced_poweroff(struct device *dev)
>> +{
>> + struct generic_pm_domain *genpd;
>> +
>> + genpd = dev_to_genpd_safe(dev);
>> + if (!genpd)
>> + return;
>> +
>> + genpd_lock(genpd);
>> + genpd->synced_poweroff = true;
>> + genpd_unlock(genpd);
>> +}
>> +EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff);
>> +
>> static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>> {
>> unsigned int state_idx = genpd->state_idx;
>> @@ -562,6 +587,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>>
>> out:
>> raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL);
>> + genpd->synced_poweroff = false;
>> return 0;
>> err:
>> raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF,
>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>> index 1cd41bdf73cf..f776fb93eaa0 100644
>> --- a/include/linux/pm_domain.h
>> +++ b/include/linux/pm_domain.h
>> @@ -136,6 +136,7 @@ struct generic_pm_domain {
>> unsigned int prepared_count; /* Suspend counter of prepared devices */
>> unsigned int performance_state; /* Aggregated max performance state */
>> cpumask_var_t cpus; /* A cpumask of the attached CPUs */
>> + bool synced_poweroff; /* A consumer needs a synced poweroff */
>> int (*power_off)(struct generic_pm_domain *domain);
>> int (*power_on)(struct generic_pm_domain *domain);
>> struct raw_notifier_head power_notifiers; /* Power on/off notifiers */
>> @@ -235,6 +236,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
>> int dev_pm_genpd_remove_notifier(struct device *dev);
>> void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next);
>> ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
>> +void dev_pm_genpd_synced_poweroff(struct device *dev);
>>
>> extern struct dev_power_governor simple_qos_governor;
>> extern struct dev_power_governor pm_domain_always_on_gov;
>> @@ -300,6 +302,9 @@ static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
>> {
>> return KTIME_MAX;
>> }
>> +static inline void dev_pm_genpd_synced_poweroff(struct device *dev)
>> +{ }
>> +
>> #define simple_qos_governor (*(struct dev_power_governor *)(NULL))
>> #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
>> #endif
>> --
>> 2.7.4
>>