Re: [PATCH -next] regulator: qcom-rpmh: fix build after QCOM_COMMAND_DB is tristate

2020-12-27 Thread Lina Iyer

On Fri, Dec 25 2020 at 11:50 -0700, Randy Dunlap wrote:

Restrict REGULATOR_QCOM_RPMH to QCOM_COMMAND_DB it the latter is enabled.

Fixes this build error:
 microblaze-linux-ld: drivers/regulator/qcom-rpmh-regulator.o: in function 
`rpmh_regulator_probe':
 (.text+0x354): undefined reference to `cmd_db_read_addr'

Fixes: 778279f4f5e4 ("soc: qcom: cmd-db: allow loading as a module")
Reported-by: kernel test robot 
Signed-off-by: Randy Dunlap 
Cc: Lina Iyer 
Cc: Liam Girdwood 
Cc: Mark Brown 

Reviewed-by: Lina Iyer 


---
drivers/regulator/Kconfig |1 +
1 file changed, 1 insertion(+)

--- linux-next-20201223.orig/drivers/regulator/Kconfig
+++ linux-next-20201223/drivers/regulator/Kconfig
@@ -881,6 +881,7 @@ config REGULATOR_QCOM_RPM
config REGULATOR_QCOM_RPMH
tristate "Qualcomm Technologies, Inc. RPMh regulator driver"
depends on QCOM_RPMH || (QCOM_RPMH=n && COMPILE_TEST)
+   depends on QCOM_COMMAND_DB || !QCOM_COMMAND_DB
help
  This driver supports control of PMIC regulators via the RPMh hardware
  block found on Qualcomm Technologies Inc. SoCs.  RPMh regulator


Re: [PATCH] soc: qcom: QCOM_RPMH fix build with modular QCOM_RPMH

2020-10-28 Thread Lina Iyer

On Wed, Oct 28 2020 at 03:43 -0600, Anders Roxell wrote:

On Tue, 27 Oct 2020 at 22:15, Lina Iyer  wrote:


Hi Anders,

On Tue, Oct 27 2020 at 05:14 -0600, Anders Roxell wrote:
>When building allmodconfig leading to the following link error with
>CONFIG_QCOM_RPMH=y and CONFIG_QCOM_COMMAND_DB=m:
>
>aarch64-linux-gnu-ld: drivers/clk/qcom/clk-rpmh.o: in function 
`clk_rpmh_probe':
>  drivers/clk/qcom/clk-rpmh.c:474: undefined reference to `cmd_db_read_addr'
>  drivers/clk/qcom/clk-rpmh.c:474:(.text+0x254): relocation truncated to fit: 
R_AARCH64_CALL26 against undefined symbol `cmd_db_read_addr'
>
>Fix this by adding a Kconfig depenency and forcing QCOM_RPMH to be a
>module when QCOM_COMMAND_DB is a module. Also removing the dependency on
>'ARCH_QCOM || COMPILE_TEST' since that is already a dependency for
>QCOM_COMMAND_DB.
>
>Fixes: 778279f4f5e4 ("soc: qcom: cmd-db: allow loading as a module")
>Signed-off-by: Anders Roxell 
>---
> drivers/soc/qcom/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
>diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
>index 9b4ae9c16ba7..3bdd1604f78f 100644
>--- a/drivers/soc/qcom/Kconfig
>+++ b/drivers/soc/qcom/Kconfig
>@@ -109,7 +109,7 @@ config QCOM_RMTFS_MEM
>
> config QCOM_RPMH
>   tristate "Qualcomm RPM-Hardened (RPMH) Communication"
>-  depends on ARCH_QCOM || COMPILE_TEST
>+  depends on QCOM_COMMAND_DB
A solution was posted in the mailing list alredy -
https://lore.kernel.org/linux-arm-msm/20201008040907.7036-1-il...@codeaurora.org/


I missed that one, thanks.



If you get a chance, please give that a shot to see if that works for
you.


That will work too, but the "depends on ARCH_QCOM || COMPILE_TEST"
isn't needed since that is already the dependency for QCOM_COMMAND_DB.
So that should be met here too or am I missing something?


Sure, if you want to post an update to the patch, that would be fine
too.
Bjorn: Have you picked up this patch yet? If he hasn't please feel free
to update the patch. Or, I can do that as well.

--Lina


Cheers,
Anders



Thanks,
Lina

>   help
> Support for communication with the hardened-RPM blocks in
> Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
>--
>2.28.0
>


Re: [PATCH] soc: qcom: QCOM_RPMH fix build with modular QCOM_RPMH

2020-10-27 Thread Lina Iyer

Hi Anders,

On Tue, Oct 27 2020 at 05:14 -0600, Anders Roxell wrote:

When building allmodconfig leading to the following link error with
CONFIG_QCOM_RPMH=y and CONFIG_QCOM_COMMAND_DB=m:

aarch64-linux-gnu-ld: drivers/clk/qcom/clk-rpmh.o: in function `clk_rpmh_probe':
 drivers/clk/qcom/clk-rpmh.c:474: undefined reference to `cmd_db_read_addr'
 drivers/clk/qcom/clk-rpmh.c:474:(.text+0x254): relocation truncated to fit: 
R_AARCH64_CALL26 against undefined symbol `cmd_db_read_addr'

Fix this by adding a Kconfig depenency and forcing QCOM_RPMH to be a
module when QCOM_COMMAND_DB is a module. Also removing the dependency on
'ARCH_QCOM || COMPILE_TEST' since that is already a dependency for
QCOM_COMMAND_DB.

Fixes: 778279f4f5e4 ("soc: qcom: cmd-db: allow loading as a module")
Signed-off-by: Anders Roxell 
---
drivers/soc/qcom/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 9b4ae9c16ba7..3bdd1604f78f 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -109,7 +109,7 @@ config QCOM_RMTFS_MEM

config QCOM_RPMH
tristate "Qualcomm RPM-Hardened (RPMH) Communication"
-   depends on ARCH_QCOM || COMPILE_TEST
+   depends on QCOM_COMMAND_DB

A solution was posted in the mailing list alredy -
https://lore.kernel.org/linux-arm-msm/20201008040907.7036-1-il...@codeaurora.org/

If you get a chance, please give that a shot to see if that works for
you.

Thanks,
Lina


help
  Support for communication with the hardened-RPM blocks in
  Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
--
2.28.0



Re: [PATCH v3] PM: domains: Add support for PM domain on/off notifiers for genpd

2020-10-19 Thread Lina Iyer

On Tue, Oct 13 2020 at 06:23 -0600, Ulf Hansson wrote:

A device may have specific HW constraints that must be obeyed to, before
its corresponding PM domain (genpd) can be powered off - and vice verse at
power on. These constraints can't be managed through the regular runtime PM
based deployment for a device, because the access pattern for it, isn't
always request based. In other words, using the runtime PM callbacks to
deal with the constraints doesn't work for these cases.

For these reasons, let's instead add a PM domain power on/off notification
mechanism to genpd. To add/remove a notifier for a device, the device must
already have been attached to the genpd, which also means that it needs to
be a part of the PM domain topology.

To add/remove a notifier, let's introduce two genpd specific functions:
- dev_pm_genpd_add|remove_notifier()

Note that, to further clarify when genpd power on/off notifiers may be
used, one can compare with the existing CPU_CLUSTER_PM_ENTER|EXIT
notifiers. In the long run, the genpd power on/off notifiers should be able
to replace them, but that requires additional genpd based platform support
for the current users.

Signed-off-by: Ulf Hansson 
---

Changes in v3:
- Adopted suggestions from Peng Fan to allow more fine grained levels of
notifications, which is needed on some NXP platforms.
- Move the code that fires the notifications into _genpd_power_on|off(),
as it simply fits better in there.

Note that, I understand that some of us may be occupied with dealing with the
merge window, but I still wanted to get this submitted to allow those that have
some time to review and test.

Kind regards
Ulf Hansson

---
drivers/base/power/domain.c | 161 +---
include/linux/pm_domain.h   |  22 +
2 files changed, 171 insertions(+), 12 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 05bb4d4401b2..c2a8821bdb26 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -413,28 +413,47 @@ static int _genpd_power_on(struct generic_pm_domain 
*genpd, bool timed)
unsigned int state_idx = genpd->state_idx;
ktime_t time_start;
s64 elapsed_ns;
-   int ret;
+   int ret, nr_calls = 0;
+
+   /* Notify consumers that we are about to power on. */
+   ret = __raw_notifier_call_chain(>power_notifiers,
+   GENPD_NOTIFY_PRE_ON, NULL, -1,
+   _calls);

Rafael's bleeding-edge fails to compile because this call is removed
now -
https://lore.kernel.org/lkml/20200818135804.325626...@infradead.org/
which also handles the failure case (_robust) variant.

--Lina


+   ret = notifier_to_errno(ret);
+   if (ret)
+   goto err;

if (!genpd->power_on)
-   return 0;
+   goto out;

-   if (!timed)
-   return genpd->power_on(genpd);
+   if (!timed) {
+   ret = genpd->power_on(genpd);
+   if (ret)
+   goto err;
+
+   goto out;
+   }

time_start = ktime_get();
ret = genpd->power_on(genpd);
if (ret)
-   return ret;
+   goto err;

elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
-   return ret;
+   goto out;

genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
genpd->max_off_time_changed = true;
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 genpd->name, "on", elapsed_ns);

+out:
+   raw_notifier_call_chain(>power_notifiers, GENPD_NOTIFY_ON, NULL);
+   return 0;
+err:
+   raw_notifier_call_chain(>power_notifiers, GENPD_NOTIFY_OFF,
+   NULL);
return ret;
}

@@ -443,29 +462,51 @@ static int _genpd_power_off(struct generic_pm_domain 
*genpd, bool timed)
unsigned int state_idx = genpd->state_idx;
ktime_t time_start;
s64 elapsed_ns;
-   int ret;
+   int ret, nr_calls = 0;
+
+   /* Notify consumers that we are about to power off. */
+   ret = __raw_notifier_call_chain(>power_notifiers,
+   GENPD_NOTIFY_PRE_OFF, NULL, -1,
+   _calls);
+   ret = notifier_to_errno(ret);
+   if (ret)
+   goto busy;

if (!genpd->power_off)
-   return 0;
+   goto out;
+
+   if (!timed) {
+   ret = genpd->power_off(genpd);
+   if (ret)
+   goto busy;

-   if (!timed)
-   return genpd->power_off(genpd);
+   goto out;
+   }

time_start = ktime_get();
ret = genpd->power_off(genpd);
if (ret)
-   return ret;
+   goto busy;


Re: [PATCH v3] PM: domains: Add support for PM domain on/off notifiers for genpd

2020-10-16 Thread Lina Iyer

On Tue, Oct 13 2020 at 06:23 -0600, Ulf Hansson wrote:

A device may have specific HW constraints that must be obeyed to, before
its corresponding PM domain (genpd) can be powered off - and vice verse at
power on. These constraints can't be managed through the regular runtime PM
based deployment for a device, because the access pattern for it, isn't
always request based. In other words, using the runtime PM callbacks to
deal with the constraints doesn't work for these cases.

For these reasons, let's instead add a PM domain power on/off notification
mechanism to genpd. To add/remove a notifier for a device, the device must
already have been attached to the genpd, which also means that it needs to
be a part of the PM domain topology.

To add/remove a notifier, let's introduce two genpd specific functions:
- dev_pm_genpd_add|remove_notifier()

Note that, to further clarify when genpd power on/off notifiers may be
used, one can compare with the existing CPU_CLUSTER_PM_ENTER|EXIT
notifiers. In the long run, the genpd power on/off notifiers should be able
to replace them, but that requires additional genpd based platform support
for the current users.

Signed-off-by: Ulf Hansson 
---

Changes in v3:
- Adopted suggestions from Peng Fan to allow more fine grained levels of
notifications, which is needed on some NXP platforms.
- Move the code that fires the notifications into _genpd_power_on|off(),
as it simply fits better in there.

Note that, I understand that some of us may be occupied with dealing with the
merge window, but I still wanted to get this submitted to allow those that have
some time to review and test.

Kind regards
Ulf Hansson

---
drivers/base/power/domain.c | 161 +---
include/linux/pm_domain.h   |  22 +
2 files changed, 171 insertions(+), 12 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 05bb4d4401b2..c2a8821bdb26 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -413,28 +413,47 @@ static int _genpd_power_on(struct generic_pm_domain 
*genpd, bool timed)
unsigned int state_idx = genpd->state_idx;
ktime_t time_start;
s64 elapsed_ns;
-   int ret;
+   int ret, nr_calls = 0;
+
+   /* Notify consumers that we are about to power on. */
+   ret = __raw_notifier_call_chain(>power_notifiers,
+   GENPD_NOTIFY_PRE_ON, NULL, -1,
+   _calls);
+   ret = notifier_to_errno(ret);
+   if (ret)
+   goto err;

if (!genpd->power_on)
-   return 0;
+   goto out;

-   if (!timed)
-   return genpd->power_on(genpd);
+   if (!timed) {
+   ret = genpd->power_on(genpd);
+   if (ret)
+   goto err;
+
+   goto out;
+   }

time_start = ktime_get();
ret = genpd->power_on(genpd);
if (ret)
-   return ret;
+   goto err;

elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
-   return ret;
+   goto out;

genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
genpd->max_off_time_changed = true;
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 genpd->name, "on", elapsed_ns);

+out:
+   raw_notifier_call_chain(>power_notifiers, GENPD_NOTIFY_ON, NULL);
+   return 0;
+err:
+   raw_notifier_call_chain(>power_notifiers, GENPD_NOTIFY_OFF,
+   NULL);
return ret;
}

@@ -443,29 +462,51 @@ static int _genpd_power_off(struct generic_pm_domain 
*genpd, bool timed)
unsigned int state_idx = genpd->state_idx;
ktime_t time_start;
s64 elapsed_ns;
-   int ret;
+   int ret, nr_calls = 0;
+
+   /* Notify consumers that we are about to power off. */
+   ret = __raw_notifier_call_chain(>power_notifiers,
+   GENPD_NOTIFY_PRE_OFF, NULL, -1,
+   _calls);
+   ret = notifier_to_errno(ret);
+   if (ret)
+   goto busy;

Nit: You could enclose this in a function call to keep these functions
clean.

Otherwise,

Tested-by: Lina Iyer 


if (!genpd->power_off)
-   return 0;
+   goto out;
+
+   if (!timed) {
+   ret = genpd->power_off(genpd);
+   if (ret)
+   goto busy;

-   if (!timed)
-   return genpd->power_off(genpd);
+   goto out;
+   }

time_start = ktime_get();
ret = genpd->power_off(genpd);
if (ret)
-   return ret;
+   goto busy;

elapsed_ns = kti

Re: [PATCH 3/3] PM / Domains: Add support for PM domain on/off notifiers for genpd

2020-09-09 Thread Lina Iyer
-Original Message-
Date: Wed, 19 Aug 2020 12:40:57 +0200
From: Ulf Hansson 
To: "Rafael J . Wysocki" , Kevin Hilman
 , linux...@vger.kernel.org
Cc: Sudeep Holla , Lorenzo Pieralisi
 , Daniel Lezcano ,
 Lina Iyer , Lukasz Luba , Vincent
 Guittot , Stephen Boyd , Bjorn
 Andersson , Benjamin Gaignard
 , Ulf Hansson ,
 linux-arm-ker...@lists.infradead.org, linux-kernel@vger.kernel.org
Subject: [PATCH 3/3] PM / Domains: Add support for PM domain on/off notifiers
 for genpd

A device may have specific HW constraints that must be obeyed to, before
its corresponding PM domain (genpd) can be powered off - and vice verse at
power on. These constraints can't be managed through the regular runtime PM
based deployment for a device, because the access pattern for it, isn't
always request based. In other words, using the runtime PM callbacks to
deal with the constraints doesn't work for these cases.

For these reasons, let's instead add a PM domain power on/off notification
mechanism to genpd. To add/remove a notifier for a device, the device must
already have been attached to the genpd, which also means that it needs to
be a part of the PM domain topology.

To add/remove a notifier, let's introduce two genpd specific functions:
 - dev_pm_genpd_add|remove_notifier()

Note that, to further clarify when genpd power on/off notifiers may be
used, one can compare with the existing CPU_CLUSTER_PM_ENTER|EXIT
notifiers. In the long run, the genpd power on/off notifiers should be able
to replace them, but that requires additional genpd based platform support
for the current users.

Signed-off-by: Ulf Hansson 
---
 drivers/base/power/domain.c | 130 ++--
 include/linux/pm_domain.h   |  15 +
 2 files changed, 141 insertions(+), 4 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 4b787e1ff188..9cb85a5e8342 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -545,13 +545,21 @@ static int genpd_power_off(struct generic_pm_domain 
*genpd, bool one_dev_on,
if (!genpd->gov)
genpd->state_idx = 0;
 
+   /* Notify consumers that we are about to power off. */
+   ret = raw_notifier_call_chain(>power_notifiers, GENPD_STATE_OFF,
+ NULL);
+   if (ret)
+   return ret;
+
/* Don't power off, if a child domain is waiting to power on. */
-   if (atomic_read(>sd_count) > 0)
-   return -EBUSY;
+   if (atomic_read(>sd_count) > 0) {
+   ret = -EBUSY;
+   goto busy;
+   }
 
ret = _genpd_power_off(genpd, true);
if (ret)
-   return ret;
+   goto busy;
 
genpd->status = GENPD_STATE_OFF;
genpd_update_accounting(genpd);
@@ -564,6 +572,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd, 
bool one_dev_on,
}
 
return 0;
+busy:
+   raw_notifier_call_chain(>power_notifiers, GENPD_STATE_ON, NULL);
+   return ret;
 }
 
 /**
@@ -606,6 +617,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd, 
unsigned int depth)
if (ret)
goto err;
 
+   /* Inform consumers that we have powered on. */
+   raw_notifier_call_chain(>power_notifiers, GENPD_STATE_ON, NULL);
+
genpd->status = GENPD_STATE_ON;
genpd_update_accounting(genpd);
 
@@ -948,9 +962,18 @@ static void genpd_sync_power_off(struct generic_pm_domain 
*genpd, bool use_lock,
 
/* Choose the deepest state when suspending */
genpd->state_idx = genpd->state_count - 1;
-   if (_genpd_power_off(genpd, false))
+
+   /* Notify consumers that we are about to power off. */
+   if (raw_notifier_call_chain(>power_notifiers,
+   GENPD_STATE_OFF, NULL))
return;
If any of the notified returns an error, we probably should inform that
the genpd failed as well. 

-- Lina

+   if (_genpd_power_off(genpd, false)) {
+   raw_notifier_call_chain(>power_notifiers,
+   GENPD_STATE_ON, NULL);
+   return;
+   }
+
genpd->status = GENPD_STATE_OFF;
 
list_for_each_entry(link, >child_links, child_node) {
@@ -998,6 +1021,9 @@ static void genpd_sync_power_on(struct generic_pm_domain 
*genpd, bool use_lock,
 
_genpd_power_on(genpd, false);
 
+   /* Inform consumers that we have powered on. */
+   raw_notifier_call_chain(>power_notifiers, GENPD_STATE_ON, NULL);
+
genpd->status = GENPD_STATE_ON;
 }
 
@@ -1593,6 +1619,101 @@ int pm_genpd_remove_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(pm_genpd_remove_device);
 
+/**
+ * dev_pm_genpd_add_notifier - Add a genpd power on/off notifier for @dev
+ *
+ * @dev: Device that should be associated with the notifier
+ * @nb: The notifier block to register
+ *
+ 

Re: WARNING: suspicious RCU usage - sdhci-pltfm: SDHCI platform and OF driver helper

2020-09-01 Thread Lina Iyer

Hi Ulf,

On Tue, Sep 01 2020 at 06:41 -0600, Ulf Hansson wrote:

On Tue, 1 Sep 2020 at 14:35, Ulf Hansson  wrote:


On Tue, 1 Sep 2020 at 12:42,  wrote:
>
> On Tue, Sep 01, 2020 at 08:50:57AM +0200, Ulf Hansson wrote:
> > On Tue, 1 Sep 2020 at 08:46, Ulf Hansson  wrote:
> > > On Mon, 31 Aug 2020 at 21:44, Paul E. McKenney  wrote:
>
> > > > > [5.308588] =
> > > > > [5.308593] WARNING: suspicious RCU usage
> > > > > [5.316628] sdhci-pltfm: SDHCI platform and OF driver helper
> > > > > [5.320052] 5.9.0-rc3 #1 Not tainted
> > > > > [5.320057] -
> > > > > [5.320063] /usr/src/kernel/include/trace/events/lock.h:37 
suspicious rcu_dereference_check() usage!
> > > > > [5.320068]
> > > > > [5.320068] other info that might help us debug this:
> > > > > [5.320068]
> > > > > [5.320074]
> > > > > [5.320074] rcu_scheduler_active = 2, debug_locks = 1
> > > > > [5.320078] RCU used illegally from extended quiescent state!
> > > > > [5.320084] no locks held by swapper/0/0.
> > > > > [5.320089]
> > > > > [5.320089] stack backtrace:
> > > > > [5.320098] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.9.0-rc3 #1
> > > > > [5.346354] sdhci_msm 7864900.sdhci: Got CD GPIO
> > > > > [5.346446] Hardware name: Qualcomm Technologies, Inc. APQ 8016 
SBC (DT)
> > > > > [5.346452] Call trace:
> > > > > [5.346463]  dump_backtrace+0x0/0x1f8
> > > > > [5.346471]  show_stack+0x2c/0x38
> > > > > [5.346480]  dump_stack+0xec/0x15c
> > > > > [5.346490]  lockdep_rcu_suspicious+0xd4/0xf8
> > > > > [5.346499]  lock_acquire+0x3d0/0x440
> > > > > [5.346510]  _raw_spin_lock_irqsave+0x80/0xb0
> > > > > [5.413118]  __pm_runtime_suspend+0x34/0x1d0
> > > > > [5.417457]  psci_enter_domain_idle_state+0x4c/0xb0
> > > > > [5.421795]  cpuidle_enter_state+0xc8/0x610
> > > > > [5.426392]  cpuidle_enter+0x3c/0x50
> > > > > [5.430561]  call_cpuidle+0x44/0x80
> > > > > [5.434378]  do_idle+0x240/0x2a0
>
> > > > Note also that Peter Zijlstra (CCed) is working to shrink the portion
> > > > of the idle loop that RCU ignores.  Not sure that it covers your
> > > > case, but it is worth checking.
>
> Right, so I think I 'caused' this by making the lock tracepoints
> visible. That is, the error always existed, now we actually warn about
> it.
>
> > > Thanks for letting me know. Let's see what Peter thinks about this then.
> > >
> > > Apologize for my ignorance, but from a cpuidle point of view, what
> > > does it mean using RCU_NONIDLE()? I guess we should avoid RCU_NONIDLE
> > > on bigger code paths?
> > >
> > > I could add RCU_NONIDLE for the calls to pm_runtime_put_sync_suspend()
> > > and pm_runtime_get_sync() in psci_enter_domain_idle_state(). Perhaps
> > > that's the easiest approach, at least to start with.
> > >

I think this would be nice. This should also cover the case, where PM domain
power off notification callbacks call trace function internally. Right?

--Lina


> > > Or do you have any other ideas?
>
> So IMO trace_*_rcuidle() and RCU_NONIDLE() are bugs, they just mean we
> got the ordering wrong and are papering over it. That said, that's been
> the modus operandi for a while now, just make it shut up and don't think
> about it :-/
>
> That said; I pushed the rcu_idle_enter() about as deep as it goes into
> generic code in commit 1098582a0f6c ("sched,idle,rcu: Push rcu_idle
> deeper into the idle path")

Aha, that commit should fix this problem, I think. Looks like that
commit was sent as a fix and included in the recent v5.9-rc3.

Naresh, can you try with the above commit?


Ah, just realized that I misread the patch. It doesn't fix it.

We would still need a RCU_NONIDLE() in psci_enter_domain_idle_state()
- or something along the lines of what you suggest below.

Apologies for the noise.

Kind regards
Uffe


[1]. https://lkml.org/lkml/2020/8/26/81


>
> I suppose the next step is pushing it into individual driver when
> needed, something like the below perhaps. I realize the coupled idle
> state stuff is more complicated that most, but it's also not an area
> I've looked at in detail, so perhaps I've just made a bigger mess, but
> it ought to give you enough to get going I think.

These aren't coupled states. Instead, in cpuidle-psci, we are using PM
domains through genpd and runtime PM to manage "shared idle states"
between CPUs.

Kind regards
Uffe

>
> Rafael?
>
> ---
> diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c
> index 74463841805f..617bbef316e6 100644
> --- a/drivers/cpuidle/cpuidle-psci.c
> +++ b/drivers/cpuidle/cpuidle-psci.c
> @@ -49,6 +49,9 @@ static inline u32 psci_get_domain_state(void)
>
>  static inline int psci_enter_state(int idx, u32 state)
>  {
> +   /*
> +* XXX push rcu_idle_enter into the coupled code
> +*/
> return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter, idx, 
state);
>  }
>
> @@ -72,7 

Re: [PATCH 3/3] PM / Domains: Add support for PM domain on/off notifiers for genpd

2020-08-25 Thread Lina Iyer

On Wed, Aug 19 2020 at 04:41 -0600, Ulf Hansson wrote:

A device may have specific HW constraints that must be obeyed to, before
its corresponding PM domain (genpd) can be powered off - and vice verse at
power on. These constraints can't be managed through the regular runtime PM
based deployment for a device, because the access pattern for it, isn't
always request based. In other words, using the runtime PM callbacks to
deal with the constraints doesn't work for these cases.

For these reasons, let's instead add a PM domain power on/off notification
mechanism to genpd. To add/remove a notifier for a device, the device must
already have been attached to the genpd, which also means that it needs to
be a part of the PM domain topology.

To add/remove a notifier, let's introduce two genpd specific functions:
- dev_pm_genpd_add|remove_notifier()

Note that, to further clarify when genpd power on/off notifiers may be
used, one can compare with the existing CPU_CLUSTER_PM_ENTER|EXIT
notifiers. In the long run, the genpd power on/off notifiers should be able
to replace them, but that requires additional genpd based platform support
for the current users.

Signed-off-by: Ulf Hansson 
---
drivers/base/power/domain.c | 130 ++--
include/linux/pm_domain.h   |  15 +
2 files changed, 141 insertions(+), 4 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 4b787e1ff188..9cb85a5e8342 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -545,13 +545,21 @@ static int genpd_power_off(struct generic_pm_domain 
*genpd, bool one_dev_on,
if (!genpd->gov)
genpd->state_idx = 0;

+   /* Notify consumers that we are about to power off. */
+   ret = raw_notifier_call_chain(>power_notifiers, GENPD_STATE_OFF,
+ NULL);
+   if (ret)
+   return ret;
+
/* Don't power off, if a child domain is waiting to power on. */
-   if (atomic_read(>sd_count) > 0)
-   return -EBUSY;
+   if (atomic_read(>sd_count) > 0) {
+   ret = -EBUSY;
+   goto busy;
+   }

ret = _genpd_power_off(genpd, true);
if (ret)
-   return ret;
+   goto busy;

genpd->status = GENPD_STATE_OFF;
genpd_update_accounting(genpd);
@@ -564,6 +572,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd, 
bool one_dev_on,
}

return 0;
+busy:
+   raw_notifier_call_chain(>power_notifiers, GENPD_STATE_ON, NULL);

It would be helpful to abstract these notification related calls into
functions of their own. So, for CPU PM domains, it would help to add
RCU_NONIDLE() around the notifiers, allowing the callbacks to add trace
functions.

--Lina


+   return ret;
}

/**
@@ -606,6 +617,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd, 
unsigned int depth)
if (ret)
goto err;

+   /* Inform consumers that we have powered on. */
+   raw_notifier_call_chain(>power_notifiers, GENPD_STATE_ON, NULL);
+
genpd->status = GENPD_STATE_ON;
genpd_update_accounting(genpd);

@@ -948,9 +962,18 @@ static void genpd_sync_power_off(struct generic_pm_domain 
*genpd, bool use_lock,

/* Choose the deepest state when suspending */
genpd->state_idx = genpd->state_count - 1;
-   if (_genpd_power_off(genpd, false))
+
+   /* Notify consumers that we are about to power off. */
+   if (raw_notifier_call_chain(>power_notifiers,
+   GENPD_STATE_OFF, NULL))
return;

+   if (_genpd_power_off(genpd, false)) {
+   raw_notifier_call_chain(>power_notifiers,
+   GENPD_STATE_ON, NULL);
+   return;
+   }
+
genpd->status = GENPD_STATE_OFF;

list_for_each_entry(link, >child_links, child_node) {
@@ -998,6 +1021,9 @@ static void genpd_sync_power_on(struct generic_pm_domain 
*genpd, bool use_lock,

_genpd_power_on(genpd, false);

+   /* Inform consumers that we have powered on. */
+   raw_notifier_call_chain(>power_notifiers, GENPD_STATE_ON, NULL);
+
genpd->status = GENPD_STATE_ON;
}

@@ -1593,6 +1619,101 @@ int pm_genpd_remove_device(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_genpd_remove_device);

+/**
+ * dev_pm_genpd_add_notifier - Add a genpd power on/off notifier for @dev
+ *
+ * @dev: Device that should be associated with the notifier
+ * @nb: The notifier block to register
+ *
+ * Users may call this function to add a genpd power on/off notifier for an
+ * attached @dev. Only one notifier per device is allowed. The notifier is
+ * sent when genpd is powering on/off the PM domain.
+ *
+ * It is assumed that the user guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ *
+ * Returns 0 on success and negative error values on failures.
+ 

Re: [PATCH v4 4/5] arm64: dts: sdm845: Add OPP tables and power-domains for venus

2020-07-28 Thread Lina Iyer

On Tue, Jul 28 2020 at 13:51 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2020-07-28 09:52:12)

On Mon, Jul 27 2020 at 18:45 -0600, Stephen Boyd wrote:
>Quoting Lina Iyer (2020-07-24 09:28:25)
>> On Fri, Jul 24 2020 at 03:03 -0600, Rajendra Nayak wrote:
>> >Hi Maulik/Lina,
>> >
>> >On 7/23/2020 11:36 PM, Stanimir Varbanov wrote:
>> >>Hi Rajendra,
>> >>
>> >>After applying 2,3 and 4/5 patches on linaro-integration v5.8-rc2 I see
>> >>below messages on db845:
>> >>
>> >>qcom-venus aa0.video-codec: dev_pm_opp_set_rate: failed to find
>> >>current OPP for freq 53397 (-34)
>> >>
>> >>^^^ This one is new.
>> >>
>> >>qcom_rpmh TCS Busy, retrying RPMH message send: addr=0x3
>> >>
>> >>^^^ and this message is annoying, can we make it pr_debug in rpmh?
>> >
>> How annoyingly often do you see this message?
>> Usually, this is an indication of bad system state either on remote
>> processors in the SoC or in Linux itself. On a smooth sailing build you
>> should not see this 'warning'.
>>
>> >Would you be fine with moving this message to a pr_debug? Its currently
>> >a pr_info_ratelimited()
>> I would rather not, moving this out of sight will mask a lot serious
>> issues that otherwise bring attention to the developers.
>>
>
>I removed this warning message in my patch posted to the list[1]. If
>it's a serious problem then I suppose a timeout is more appropriate, on
>the order of several seconds or so and then a pr_warn() and bail out of
>the async call with an error.
>
The warning used to capture issues that happen within a second and it
helps capture system related issues. Timing out after many seconds
overlooks the system issues that generally tend to resolve itself, but
nevertheless need to be investigated.



Is it correct to read "system related issues" as performance problems
where the thread is spinning forever trying to send a message and it
can't? So the problem is mostly that it's an unbounded amount of time
before the message is sent to rpmh and this printk helps identify those
situations where that is happening?


Yes, but mostly a short period of time like when other processors are in
the middle of a restart or resource states changes have taken unusual
amounts of time. The system will generally recover from this without
crashing in this case. User action is investigation of the situation
leading to these messages.


Otherwise as you say above it's a bad system state where the rpmh
processor has gotten into a bad state like a crash? Can we recover from
that? Or is the only recovery a reboot of the system? Does the rpmh
processor reboot the system if it crashes?

We cannot recover from such a state. The remote processor will reboot if
it detects a failure at it's end. If the system entered a bad state, it
is possible that RPMH requests start timing out in Linux and remote
processor may not detect it. Hence, the timeout in rpmh_write() API. The
advised course of action is a restart as there is no way to recover from
this state.

--Lina




Re: [PATCH v4 4/5] arm64: dts: sdm845: Add OPP tables and power-domains for venus

2020-07-28 Thread Lina Iyer

On Mon, Jul 27 2020 at 18:45 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2020-07-24 09:28:25)

On Fri, Jul 24 2020 at 03:03 -0600, Rajendra Nayak wrote:
>Hi Maulik/Lina,
>
>On 7/23/2020 11:36 PM, Stanimir Varbanov wrote:
>>Hi Rajendra,
>>
>>After applying 2,3 and 4/5 patches on linaro-integration v5.8-rc2 I see
>>below messages on db845:
>>
>>qcom-venus aa0.video-codec: dev_pm_opp_set_rate: failed to find
>>current OPP for freq 53397 (-34)
>>
>>^^^ This one is new.
>>
>>qcom_rpmh TCS Busy, retrying RPMH message send: addr=0x3
>>
>>^^^ and this message is annoying, can we make it pr_debug in rpmh?
>
How annoyingly often do you see this message?
Usually, this is an indication of bad system state either on remote
processors in the SoC or in Linux itself. On a smooth sailing build you
should not see this 'warning'.

>Would you be fine with moving this message to a pr_debug? Its currently
>a pr_info_ratelimited()
I would rather not, moving this out of sight will mask a lot serious
issues that otherwise bring attention to the developers.



I removed this warning message in my patch posted to the list[1]. If
it's a serious problem then I suppose a timeout is more appropriate, on
the order of several seconds or so and then a pr_warn() and bail out of
the async call with an error.


The warning used to capture issues that happen within a second and it
helps capture system related issues. Timing out after many seconds
overlooks the system issues that generally tend to resolve itself, but
nevertheless need to be investigated.

--Lina


[1] https://lore.kernel.org/r/20200724211711.810009-1-sb...@kernel.org


Re: [PATCH] soc: qcom: rpmh-rsc: Sleep waiting for tcs slots to be free

2020-07-24 Thread Lina Iyer

On Fri, Jul 24 2020 at 14:11 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2020-07-24 13:08:41)

On Fri, Jul 24 2020 at 14:01 -0600, Stephen Boyd wrote:
>Quoting Doug Anderson (2020-07-24 12:49:56)
>> Hi,
>>
>> On Fri, Jul 24, 2020 at 12:44 PM Stephen Boyd  wrote:
>I think Lina was alluding to this earlier in this
>thread.
I was thinking more of threaded irq handler than a kthread to post the
requests. We went away from post-thread approach a few years ago.



Ok, got it. Why was the kthread approach abandoned?


Simplification mostly, I think. Also, somebody requested that when the
async call returns they would atleast be guaranteed that the request has
been posted not necessarily processed at the remote end.



Re: [PATCH] soc: qcom: rpmh-rsc: Sleep waiting for tcs slots to be free

2020-07-24 Thread Lina Iyer

On Fri, Jul 24 2020 at 14:01 -0600, Stephen Boyd wrote:

Quoting Doug Anderson (2020-07-24 12:49:56)

Hi,

On Fri, Jul 24, 2020 at 12:44 PM Stephen Boyd  wrote:

I think Lina was alluding to this earlier in this
thread.

I was thinking more of threaded irq handler than a kthread to post the
requests. We went away from post-thread approach a few years ago.



Re: [PATCH v4 4/5] arm64: dts: sdm845: Add OPP tables and power-domains for venus

2020-07-24 Thread Lina Iyer

On Fri, Jul 24 2020 at 03:03 -0600, Rajendra Nayak wrote:

Hi Maulik/Lina,

On 7/23/2020 11:36 PM, Stanimir Varbanov wrote:

Hi Rajendra,

After applying 2,3 and 4/5 patches on linaro-integration v5.8-rc2 I see
below messages on db845:

qcom-venus aa0.video-codec: dev_pm_opp_set_rate: failed to find
current OPP for freq 53397 (-34)

^^^ This one is new.

qcom_rpmh TCS Busy, retrying RPMH message send: addr=0x3

^^^ and this message is annoying, can we make it pr_debug in rpmh?



How annoyingly often do you see this message?
Usually, this is an indication of bad system state either on remote
processors in the SoC or in Linux itself. On a smooth sailing build you
should not see this 'warning'.


Would you be fine with moving this message to a pr_debug? Its currently
a pr_info_ratelimited()

I would rather not, moving this out of sight will mask a lot serious
issues that otherwise bring attention to the developers.

--Lina


Re: [PATCH] soc: qcom: rpmh-rsc: Sleep waiting for tcs slots to be free

2020-07-23 Thread Lina Iyer

On Wed, Jul 22 2020 at 19:01 -0600, Stephen Boyd wrote:

The busy loop in rpmh_rsc_send_data() is written with the assumption
that the udelay will be preempted by the tcs_tx_done() irq handler when
the TCS slots are all full. This doesn't hold true when the calling
thread is an irqthread and the tcs_tx_done() irq is also an irqthread.
That's because kernel irqthreads are SCHED_FIFO and thus need to
voluntarily give up priority by calling into the scheduler so that other
threads can run.

I see RCU stalls when I boot with irqthreads on the kernel commandline
because the modem remoteproc driver is trying to send an rpmh async
message from an irqthread that needs to give up the CPU for the rpmh
irqthread to run and clear out tcs slots.


Would this be not better, if we we use a threaded IRQ handler or offload
tx_done to another waitqueue instead of handling it in IRQ handler?

-- Lina


rcu: INFO: rcu_preempt self-detected stall on CPU
rcu: 0-: (1 GPs behind) idle=402/1/0x4002 softirq=2108/2109 
fqs=4920
 (t=21016 jiffies g=2933 q=590)
Task dump for CPU 0:
irq/11-smp2pR  running task0   148  2 0x0028
Call trace:
 dump_backtrace+0x0/0x154
 show_stack+0x20/0x2c
 sched_show_task+0xfc/0x108
 dump_cpu_task+0x44/0x50
 rcu_dump_cpu_stacks+0xa4/0xf8
 rcu_sched_clock_irq+0x7dc/0xaa8
 update_process_times+0x30/0x54
 tick_sched_handle+0x50/0x64
 tick_sched_timer+0x4c/0x8c
 __hrtimer_run_queues+0x21c/0x36c
 hrtimer_interrupt+0xf0/0x22c
 arch_timer_handler_phys+0x40/0x50
 handle_percpu_devid_irq+0x114/0x25c
 __handle_domain_irq+0x84/0xc4
 gic_handle_irq+0xd0/0x178
 el1_irq+0xbc/0x180
 save_return_addr+0x18/0x28
 return_address+0x54/0x88
 preempt_count_sub+0x40/0x88
 _raw_spin_unlock_irqrestore+0x4c/0x6c
 ___ratelimit+0xd0/0x128
 rpmh_rsc_send_data+0x24c/0x378
 __rpmh_write+0x1b0/0x208
 rpmh_write_async+0x90/0xbc
 rpmhpd_send_corner+0x60/0x8c
 rpmhpd_aggregate_corner+0x8c/0x124
 rpmhpd_set_performance_state+0x8c/0xbc
 _genpd_set_performance_state+0xdc/0x1b8
 dev_pm_genpd_set_performance_state+0xb8/0xf8
 q6v5_pds_disable+0x34/0x60 [qcom_q6v5_mss]
 qcom_msa_handover+0x38/0x44 [qcom_q6v5_mss]
 q6v5_handover_interrupt+0x24/0x3c [qcom_q6v5]
 handle_nested_irq+0xd0/0x138
 qcom_smp2p_intr+0x188/0x200
 irq_thread_fn+0x2c/0x70
 irq_thread+0xfc/0x14c
 kthread+0x11c/0x12c
 ret_from_fork+0x10/0x18

This busy loop naturally lends itself to using a wait queue so that each
thread that tries to send a message will sleep waiting on the waitqueue
and only be woken up when a free slot is available. This should make
things more predictable too because the scheduler will be able to sleep
tasks that are waiting on a free tcs instead of the busy loop we
currently have today.

Cc: Douglas Anderson 
Cc: Maulik Shah 
Cc: Lina Iyer 
Signed-off-by: Stephen Boyd 
---
drivers/soc/qcom/rpmh-internal.h |   2 +
drivers/soc/qcom/rpmh-rsc.c  | 101 ---
2 files changed, 41 insertions(+), 62 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index ef60e790a750..9a325bac58fe 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -8,6 +8,7 @@
#define __RPM_INTERNAL_H__

#include 
+#include 
#include 

#define TCS_TYPE_NR 4
@@ -118,6 +119,7 @@ struct rsc_drv {
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
+   wait_queue_head_t tcs_wait;
struct rpmh_ctrlr client;
};

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 076fd27f3081..6c758b052c95 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -19,6 +19,7 @@
#include 
#include 
#include 
+#include 

#include 
#include 
@@ -444,6 +445,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
 */
if (!drv->tcs[ACTIVE_TCS].num_tcs)
enable_tcs_irq(drv, i, false);
+   wake_up(>tcs_wait);
spin_unlock(>lock);
if (req)
rpmh_tx_done(req, err);
@@ -562,44 +564,59 @@ static int find_free_tcs(struct tcs_group *tcs)
return -EBUSY;
}

+static int claim_tcs_for_req(struct rsc_drv *drv, struct tcs_group *tcs,
+const struct tcs_request *msg)
+{
+   int ret;
+
+   /*
+* The h/w does not like if we send a request to the same address,
+* when one is already in-flight or being processed.
+*/
+   ret = check_for_req_inflight(drv, tcs, msg);
+   if (ret)
+   return ret;
+
+   return find_free_tcs(tcs);
+}
+
/**
- * tcs_write() - Store messages into a TCS right now, or return -EBUSY.
+ * rpmh_rsc_send_data() - Write / trigger active-only message.
 * @drv: The controller.
 * @msg: The data to be sent.
 *
- * Grabs a TCS for ACTIVE_ONLY transfers and writes the messages to it.
- *
- * If there are no free TCSes for AC

Re: [PATCH] soc: qcom: rpmh: Update rpmh_invalidate function to return void

2020-06-18 Thread Lina Iyer

On Thu, Jun 18 2020 at 07:06 -0600, Maulik Shah wrote:

Currently rpmh_invalidate() always returns success. Update its
return type to void.

Suggested-by: Stephen Boyd 
Signed-off-by: Maulik Shah 

Reviewed-by: Lina Iyer 


---
drivers/interconnect/qcom/bcm-voter.c | 6 +-
drivers/soc/qcom/rpmh.c   | 4 +---
include/soc/qcom/rpmh.h   | 7 ---
3 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/interconnect/qcom/bcm-voter.c 
b/drivers/interconnect/qcom/bcm-voter.c
index 2a11a63..a3d2ef1 100644
--- a/drivers/interconnect/qcom/bcm-voter.c
+++ b/drivers/interconnect/qcom/bcm-voter.c
@@ -266,11 +266,7 @@ int qcom_icc_bcm_voter_commit(struct bcm_voter *voter)
if (!commit_idx[0])
goto out;

-   ret = rpmh_invalidate(voter->dev);
-   if (ret) {
-   pr_err("Error invalidating RPMH client (%d)\n", ret);
-   goto out;
-   }
+   rpmh_invalidate(voter->dev);

ret = rpmh_write_batch(voter->dev, RPMH_ACTIVE_ONLY_STATE,
   cmds, commit_idx);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index f2b5b46c..b61e183 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -497,7 +497,7 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
 *
 * Invalidate the sleep and wake values in batch_cache.
 */
-int rpmh_invalidate(const struct device *dev)
+void rpmh_invalidate(const struct device *dev)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
struct batch_cache_req *req, *tmp;
@@ -509,7 +509,5 @@ int rpmh_invalidate(const struct device *dev)
INIT_LIST_HEAD(>batch_cache);
ctrlr->dirty = true;
spin_unlock_irqrestore(>cache_lock, flags);
-
-   return 0;
}
EXPORT_SYMBOL(rpmh_invalidate);
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
index f9ec353..bdbee1a 100644
--- a/include/soc/qcom/rpmh.h
+++ b/include/soc/qcom/rpmh.h
@@ -20,7 +20,7 @@ int rpmh_write_async(const struct device *dev, enum 
rpmh_state state,
int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
 const struct tcs_cmd *cmd, u32 *n);

-int rpmh_invalidate(const struct device *dev);
+void rpmh_invalidate(const struct device *dev);

#else

@@ -38,8 +38,9 @@ static inline int rpmh_write_batch(const struct device *dev,
   const struct tcs_cmd *cmd, u32 *n)
{ return -ENODEV; }

-static inline int rpmh_invalidate(const struct device *dev)
-{ return -ENODEV; }
+static inline void rpmh_invalidate(const struct device *dev)
+{
+}

#endif /* CONFIG_QCOM_RPMH */

--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation



Re: [RFC][PATCH 3/5] irqchip: Allow QCOM_PDC to be loadable as a perment module

2020-06-16 Thread Lina Iyer

On Tue, Jun 16 2020 at 05:30 -0600, Maulik Shah wrote:

Hi,

On 6/16/2020 11:43 AM, John Stultz wrote:

Allows qcom-pdc driver to be loaded as a permenent module


typo: permanent


Also, due to the fact that IRQCHIP_DECLARE becomes a no-op when
building as a module, we have to add the platform driver hooks
explicitly.

Thanks to Saravana for his help on pointing out the
IRQCHIP_DECLARE issue and guidance on a solution.

Cc: Andy Gross 
Cc: Bjorn Andersson 
Cc: Joerg Roedel 
Cc: Thomas Gleixner 
Cc: Jason Cooper 
Cc: Marc Zyngier 
Cc: Linus Walleij 
Cc: Lina Iyer 
Cc: Saravana Kannan 
Cc: Todd Kjos 
Cc: Greg Kroah-Hartman 
Cc: linux-arm-...@vger.kernel.org
Cc: io...@lists.linux-foundation.org
Cc: linux-g...@vger.kernel.org
Signed-off-by: John Stultz 
---
 drivers/irqchip/Kconfig|  2 +-
 drivers/irqchip/qcom-pdc.c | 30 ++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 29fead208cad..12765bed08f9 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -425,7 +425,7 @@ config GOLDFISH_PIC
  for Goldfish based virtual platforms.
 config QCOM_PDC
-   bool "QCOM PDC"
+   tristate "QCOM PDC"
depends on ARCH_QCOM
select IRQ_DOMAIN_HIERARCHY
help
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index 6ae9e1f0819d..98d74160afcd 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -11,7 +11,9 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 

please move this include in order after of_device.h

 #include 
 #include 
 #include 
@@ -430,4 +432,32 @@ static int qcom_pdc_init(struct device_node *node, struct 
device_node *parent)
return ret;
 }
+#ifdef MODULE
+static int qcom_pdc_probe(struct platform_device *pdev)
+{
+   struct device_node *np = pdev->dev.of_node;
+   struct device_node *parent = of_irq_find_parent(np);
+
+   return qcom_pdc_init(np, parent);
+}
+
+static const struct of_device_id qcom_pdc_match_table[] = {
+   { .compatible = "qcom,pdc" },
+   {}
+};
+MODULE_DEVICE_TABLE(of, qcom_pdc_match_table);
+
+static struct platform_driver qcom_pdc_driver = {
+   .probe = qcom_pdc_probe,
+   .driver = {
+   .name = "qcom-pdc",
+   .of_match_table = qcom_pdc_match_table,


can you please set .suppress_bind_attrs = true,

This is to prevent bind/unbind using sysfs. Once irqchip driver module 
is loaded, it shouldn't get unbind at runtime.



That is a good point. We probably should do that to RPMH RSC driver as well.


Thanks,
Maulik

+   },
+};
+module_platform_driver(qcom_pdc_driver);
+#else
 IRQCHIP_DECLARE(qcom_pdc, "qcom,pdc", qcom_pdc_init);
+#endif
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
+MODULE_LICENSE("GPL v2");


--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of 
Code Aurora Forum, hosted by The Linux Foundation



Re: [PATCH RFC 02/14] drivers: irqchip: pdc: Do not toggle IRQ_ENABLE during mask/unmask

2019-09-20 Thread Lina Iyer

On Fri, Sep 20 2019 at 16:22 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-09-11 09:15:57)

On Thu, Sep 05 2019 at 18:39 -0600, Stephen Boyd wrote:
>Quoting Lina Iyer (2019-08-29 11:11:51)
>> When an interrupt is to be serviced, the convention is to mask the
>> interrupt at the chip and unmask after servicing the interrupt. Enabling
>> and disabling the interrupt at the PDC irqchip causes an interrupt storm
>> due to the way dual edge interrupts are handled in hardware.
>>
>> Skip configuring the PDC when the IRQ is masked and unmasked, instead
>> use the irq_enable/irq_disable callbacks to toggle the IRQ_ENABLE
>> register at the PDC. The PDC's IRQ_ENABLE register is only used during
>> the monitoring mode when the system is asleep and is not needed for
>> active mode detection.
>
>I think this is saying that we want to always let the line be sent
>through the PDC to the parent irqchip, in this case GIC, so that we
>don't get an interrupt storm for dual edge interrupts? Why does dual
>edge interrupts cause a problem?
>
I am not sure about the hardware details, but the PDC designers did not
expect enable and disable to be called whenever the interrupt is
handled. This specially becomes a problem for dual edge interrupts which
seems to generate a interrupt storm when enabled/disabled while handling
the interrupt.



Ok. I just wanted to confirm that masking "doesn't matter" to the PDC
because it assumes the irqchip closer to the CPU will be able to mask it
anyway. Is that right?


That is correct.


Re: [PATCH RFC 05/14] dt-bindings/interrupt-controller: pdc: add SPI config register

2019-09-17 Thread Lina Iyer

Adding Sibi

On Fri, Sep 13 2019 at 13:53 -0600, Lina Iyer wrote:

Sorry, I couldn't get to this earlier.

On Thu, Sep 05 2019 at 18:03 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-09-03 10:07:22)

On Mon, Sep 02 2019 at 07:58 -0600, Marc Zyngier wrote:

On 02/09/2019 14:38, Rob Herring wrote:

On Thu, Aug 29, 2019 at 12:11:54PM -0600, Lina Iyer wrote:

These are not GIC registers but located on the PDC interface to the GIC.
They may or may not be secure access controlled, depending on the SoC.



It looks like it falls under this "mailbox" device which is really the
catch all bucket for bits with no home besides they're related to the
apps CPUs/subsystem.


Thanks for pointing to this.

apss_shared: mailbox@1799 {
compatible = "qcom,sdm845-apss-shared";
reg = <0 0x1799 0 0x1000>;

But this doesn't seem correct. The registers in this page are all not
mailbox door bell registers. We should restrict the space allocated to
the mbox to 0xC or something, definitely, not the whole page. They all
cannot be treated as a mailbox registers.

#mbox-cells = <1>;
};

Can you point to this node with a phandle and then parse the reg
property out of it to use in the scm readl/writel APIs? Maybe it can be
a two cell property with <_shared 0xf0> to indicate the offset to
the registers to read/write? In non-secure mode presumably we need to
also write these registers? Good news is that there's a regmap for this
driver already, so maybe that can be acquired from the pdc driver.


The register space collection seems to be mix of different types of
application processor registers that should probably not be grouped up
under one subsystem. A single regmap doesn't seem correct either.

-- Lina


[PATCH RFC v2 12/14] arm64: dts: qcom: add PDC interrupt controller for SDM845

2019-09-13 Thread Lina Iyer
Add PDC interrupt controller device bindings for SDM845.

Signed-off-by: Lina Iyer 
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index be0022e..41455b8 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -2375,6 +2375,16 @@
#power-domain-cells = <1>;
};
 
+   pdc_intc: interrupt-controller@b22 {
+   compatible = "qcom,sdm845-pdc";
+   reg = <0 0x0b22 0 0x3>, <0 0x179900f0 0 0x60>;
+   qcom,pdc-ranges = <0 480 94>, <94 609 15>, <115 630 7>;
+   #interrupt-cells = <2>;
+   interrupt-parent = <>;
+   interrupt-controller;
+   qcom,scm-spi-cfg;
+   };
+
pdc_reset: reset-controller@b2e {
compatible = "qcom,sdm845-pdc-global";
reg = <0 0x0b2e 0 0x2>;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 05/14] of: irq: document properties for wakeup interrupt parent

2019-09-13 Thread Lina Iyer
Some interrupt controllers in a SoC, are always powered on and have a
select interrupts routed to them, so that they can wakeup the SoC from
suspend. Add wakeup-parent DT property to refer to these interrupt
controllers.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
Reviewed-by: Rob Herring 
---
 .../devicetree/bindings/interrupt-controller/interrupts.txt | 13 +
 1 file changed, 13 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt 
b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
index 8a3c408..c10e310 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
@@ -108,3 +108,16 @@ commonly used:
sensitivity = <7>;
};
};
+
+3) Interrupt wakeup parent
+--
+
+Some interrupt controllers in a SoC, are always powered on and have a select
+interrupts routed to them, so that they can wakeup the SoC from suspend. These
+interrupt controllers do not fall into the category of a parent interrupt
+controller and can be specified by the "wakeup-parent" property and contain a
+single phandle referring to the wakeup capable interrupt controller.
+
+   Example:
+   wakeup-parent = <_intc>;
+
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 04/14] drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs

2019-09-13 Thread Lina Iyer
Introduce a new domain for wakeup capable GPIOs. The domain can be
requested using the bus token DOMAIN_BUS_WAKEUP. In the following
patches, we will specify PDC as the wakeup-parent for the TLMM GPIO
irqchip. Requesting a wakeup GPIO will setup the GPIO and the
corresponding PDC interrupt as its parent.

Co-developed-by: Stephen Boyd 
Signed-off-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
Changes in RFC v2:
- Move irq_domain_qcom_handle_wakeup to the patch where it is
used
- Replace #define definitons
- Add Signed-off-by and other minor changes
---
 drivers/irqchip/qcom-pdc.c   | 104 +++
 include/linux/soc/qcom/irq.h |  19 
 2 files changed, 114 insertions(+), 9 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index 5eef5ea..4abd775 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -13,12 +13,13 @@
 #include 
 #include 
 #include 
+#include 
 #include 
-#include 
 #include 
 #include 
 
 #define PDC_MAX_IRQS   168
+#define PDC_MAX_GPIO_IRQS  256
 
 #define CLEAR_INTR(reg, intr)  (reg & ~(1 << intr))
 #define ENABLE_INTR(reg, intr) (reg | (1 << intr))
@@ -26,6 +27,8 @@
 #define IRQ_ENABLE_BANK0x10
 #define IRQ_i_CFG  0x110
 
+#define PDC_NO_PARENT_IRQ  ~0UL
+
 struct pdc_pin_region {
u32 pin_base;
u32 parent_base;
@@ -65,23 +68,35 @@ static void pdc_enable_intr(struct irq_data *d, bool on)
 
 static void qcom_pdc_gic_disable(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, false);
irq_chip_disable_parent(d);
 }
 
 static void qcom_pdc_gic_enable(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, true);
irq_chip_enable_parent(d);
 }
 
 static void qcom_pdc_gic_mask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
irq_chip_mask_parent(d);
 }
 
 static void qcom_pdc_gic_unmask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
irq_chip_unmask_parent(d);
 }
 
@@ -124,6 +139,9 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, 
unsigned int type)
int pin_out = d->hwirq;
enum pdc_irq_config_bits pdc_type;
 
+   if (pin_out == GPIO_NO_WAKE_IRQ)
+   return 0;
+
switch (type) {
case IRQ_TYPE_EDGE_RISING:
pdc_type = PDC_EDGE_RISING;
@@ -181,8 +199,7 @@ static irq_hw_number_t get_parent_hwirq(int pin)
return (region->parent_base + pin - region->pin_base);
}
 
-   WARN_ON(1);
-   return ~0UL;
+   return PDC_NO_PARENT_IRQ;
 }
 
 static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
@@ -211,17 +228,17 @@ static int qcom_pdc_alloc(struct irq_domain *domain, 
unsigned int virq,
 
ret = qcom_pdc_translate(domain, fwspec, , );
if (ret)
-   return -EINVAL;
-
-   parent_hwirq = get_parent_hwirq(hwirq);
-   if (parent_hwirq == ~0UL)
-   return -EINVAL;
+   return ret;
 
ret  = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
 _pdc_gic_chip, NULL);
if (ret)
return ret;
 
+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
if (type & IRQ_TYPE_EDGE_BOTH)
type = IRQ_TYPE_EDGE_RISING;
 
@@ -244,6 +261,60 @@ static const struct irq_domain_ops qcom_pdc_ops = {
.free   = irq_domain_free_irqs_common,
 };
 
+static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,
+  unsigned int nr_irqs, void *data)
+{
+   struct irq_fwspec *fwspec = data;
+   struct irq_fwspec parent_fwspec;
+   irq_hw_number_t hwirq, parent_hwirq;
+   unsigned int type;
+   int ret;
+
+   ret = qcom_pdc_translate(domain, fwspec, , );
+   if (ret)
+   return ret;
+
+   ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+   _pdc_gic_chip, NULL);
+   if (ret)
+   return ret;
+
+   if (hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
+   if (type & IRQ_TYPE_EDGE_BOTH)
+   type = IRQ_TYPE_EDGE_RISING;
+
+   if (type & IRQ_TYPE_LEVEL_MASK)
+   type = IRQ_TYPE_LEVEL_HIGH;
+
+   parent_fwspec.fwnode  = domain->parent->fwnode;
+   parent_fwspec.param_count = 3;
+   parent_fwspec.param[0]= 0;
+   parent_fwspec.pa

[PATCH RFC v2 09/14] drivers: irqchip: pdc: Add irqchip set/get state calls

2019-09-13 Thread Lina Iyer
From: Maulik Shah 

Add irqchip calls to set/get interrupt state from the parent interrupt
controller. When GPIOs are renabled as interrupt lines, it is desirable
to clear the interrupt state at the GIC. This avoids any unwanted
interrupt as a result of stale pending state recorded when the line was
used as a GPIO.

Signed-off-by: Maulik Shah 
[updated commit text]
Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index affb0bfa..2b49e70 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -5,6 +5,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -87,6 +88,24 @@ static void qcom_pdc_gic_disable(struct irq_data *d)
irq_chip_disable_parent(d);
 }
 
+static int qcom_pdc_gic_get_irqchip_state(struct irq_data *d,
+   enum irqchip_irq_state which, bool *state)
+{
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   return irq_chip_get_parent_state(d, which, state);
+}
+
+static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d,
+   enum irqchip_irq_state which, bool value)
+{
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   return irq_chip_set_parent_state(d, which, value);
+}
+
 static void qcom_pdc_gic_enable(struct irq_data *d)
 {
if (d->hwirq == GPIO_NO_WAKE_IRQ)
@@ -248,6 +267,8 @@ static struct irq_chip qcom_pdc_gic_chip = {
.irq_unmask = qcom_pdc_gic_unmask,
.irq_disable= qcom_pdc_gic_disable,
.irq_enable = qcom_pdc_gic_enable,
+   .irq_get_irqchip_state  = qcom_pdc_gic_get_irqchip_state,
+   .irq_set_irqchip_state  = qcom_pdc_gic_set_irqchip_state,
.irq_retrigger  = irq_chip_retrigger_hierarchy,
.irq_set_type   = qcom_pdc_gic_set_type,
.flags  = IRQCHIP_MASK_ON_SUSPEND |
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 14/14] arm64: defconfig: enable PDC interrupt controller for Qualcomm SDM845

2019-09-13 Thread Lina Iyer
Enable PDC interrupt controller for SDM845 devices. The interrupt
controller can detect wakeup capable interrupts when the SoC is in a low
power state.

Signed-off-by: Lina Iyer 
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 0e58ef0..310b604 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -729,6 +729,7 @@ CONFIG_ARCH_R8A77970=y
 CONFIG_ARCH_R8A77980=y
 CONFIG_ARCH_R8A77990=y
 CONFIG_ARCH_R8A77995=y
+CONFIG_QCOM_PDC=y
 CONFIG_ROCKCHIP_PM_DOMAINS=y
 CONFIG_ARCH_TEGRA_132_SOC=y
 CONFIG_ARCH_TEGRA_210_SOC=y
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 13/14] arm64: dts: qcom: setup PDC as the wakeup parent for TLMM on SDM845

2019-09-13 Thread Lina Iyer
PDC always-on interrupt controller can detect certain GPIOs even when
the TLMM interrupt controller is powered off. Link the PDC as TLMM's
wakeup parent.

Signed-off-by: Lina Iyer 
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 41455b8..1b70254 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1358,6 +1358,7 @@
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = < 0 0 150>;
+   wakeup-parent = <_intc>;
 
qspi_clk: qspi-clk {
pinmux {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 10/14] drivers: pinctrl: msm: setup GPIO chip in hierarchy

2019-09-13 Thread Lina Iyer
Some GPIOs are marked as wakeup capable and are routed to another
interrupt controller that is an always-domain and can detect interrupts
even most of the SoC is powered off. The wakeup interrupt controller
wakes up the GIC and replays the interrupt at the GIC.

Setup the TLMM irqchip in hierarchy with the wakeup interrupt controller
and ensure the wakeup GPIOs are handled correctly.

Signed-off-by: Maulik Shah 
Signed-off-by: Lina Iyer 

Changes in RFC v2:
- Define irq_domain_qcom_handle_wakeup()
- Rebase on top of GPIO hierarchy support in linux-next
- Set the chained irq handler for summary line
---
 drivers/pinctrl/qcom/pinctrl-msm.c | 119 +
 drivers/pinctrl/qcom/pinctrl-msm.h |  16 +
 include/linux/soc/qcom/irq.h   |  13 
 3 files changed, 148 insertions(+)

diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c 
b/drivers/pinctrl/qcom/pinctrl-msm.c
index f355ddd..c5ba389 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -23,6 +23,8 @@
 #include 
 #include 
 
+#include 
+
 #include "../core.h"
 #include "../pinconf.h"
 #include "pinctrl-msm.h"
@@ -44,6 +46,7 @@
  * @enabled_irqs:   Bitmap of currently enabled irqs.
  * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
  *  detection.
+ * @skip_wake_irqs: Skip IRQs that are handled by wakeup interrupt contrroller
  * @soc;Reference to soc_data of platform specific data.
  * @regs:   Base addresses for the TLMM tiles.
  */
@@ -61,6 +64,7 @@ struct msm_pinctrl {
 
DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
+   DECLARE_BITMAP(skip_wake_irqs, MAX_NR_GPIO);
 
const struct msm_pinctrl_soc_data *soc;
void __iomem *regs[MAX_NR_TILES];
@@ -709,6 +713,12 @@ static void msm_gpio_irq_mask(struct irq_data *d)
unsigned long flags;
u32 val;
 
+   if (d->parent_data)
+   irq_chip_mask_parent(d);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -753,6 +763,12 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, 
bool status_clear)
unsigned long flags;
u32 val;
 
+   if (d->parent_data)
+   irq_chip_unmask_parent(d);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -780,10 +796,37 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, 
bool status_clear)
 
 static void msm_gpio_irq_enable(struct irq_data *d)
 {
+   /*
+* Clear the interrupt that may be pending before we enable
+* the line.
+* This is especially a problem with the GPIOs routed to the
+* PDC. These GPIOs are direct-connect interrupts to the GIC.
+* Disabling the interrupt line at the PDC does not prevent
+* the interrupt from being latched at the GIC. The state at
+* GIC needs to be cleared before enabling.
+*/
+   if (d->parent_data) {
+   irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, 0);
+   irq_chip_enable_parent(d);
+   }
 
msm_gpio_irq_clear_unmask(d, true);
 }
 
+static void msm_gpio_irq_disable(struct irq_data *d)
+{
+   struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+   struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+
+   if (d->parent_data)
+   irq_chip_disable_parent(d);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
+   msm_gpio_irq_mask(d);
+}
+
 static void msm_gpio_irq_unmask(struct irq_data *d)
 {
msm_gpio_irq_clear_unmask(d, false);
@@ -797,6 +840,9 @@ static void msm_gpio_irq_ack(struct irq_data *d)
unsigned long flags;
u32 val;
 
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -822,6 +868,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, 
unsigned int type)
unsigned long flags;
u32 val;
 
+   if (d->parent_data)
+   irq_chip_set_type_parent(d, type);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return 0;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -914,6 +966,15 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, 
unsigned int on)
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned long flags;
 
+   if (d->parent_data)
+   irq_chip_set_wake_parent(d, on);
+
+   /*
+* While they may not wake up when the TLMM is powered off

[PATCH RFC v2 08/14] genirq: Introduce irq_chip_get/set_parent_state calls

2019-09-13 Thread Lina Iyer
From: Maulik Shah 

On certain QTI chipsets some GPIOs are direct-connect interrupts to the
GIC to be used as regular interrupt lines. When the GPIOs are not used
for interrupt generation the interrupt line is disabled. But disabling
the interrupt at GIC does not prevent the interrupt to be reported as
pending at GIC_ISPEND. Later, when drivers call enable_irq() on the
interrupt, an unwanted interrupt occurs.

Introduce get and set methods for irqchip's parent to clear it's pending
irq state. This then can be invoked by the GPIO interrupt controller on
the parents in it hierarchy to clear the interrupt before enabling the
interrupt.

Signed-off-by: Maulik Shah 
[updated commit text and minor code fixes]
Signed-off-by: Lina Iyer 
---
Changes in RFC v2 -
- Rephrase commit text
- Address code review comments
---
 include/linux/irq.h |  6 ++
 kernel/irq/chip.c   | 44 
 2 files changed, 50 insertions(+)

diff --git a/include/linux/irq.h b/include/linux/irq.h
index fb301cf..7853eb9 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -610,6 +610,12 @@ extern int irq_chip_pm_put(struct irq_data *data);
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
 extern void handle_fasteoi_ack_irq(struct irq_desc *desc);
 extern void handle_fasteoi_mask_irq(struct irq_desc *desc);
+extern int irq_chip_set_parent_state(struct irq_data *data,
+enum irqchip_irq_state which,
+bool val);
+extern int irq_chip_get_parent_state(struct irq_data *data,
+enum irqchip_irq_state which,
+bool *state);
 extern void irq_chip_enable_parent(struct irq_data *data);
 extern void irq_chip_disable_parent(struct irq_data *data);
 extern void irq_chip_ack_parent(struct irq_data *data);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index b76703b..b3fa2d8 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -1298,6 +1298,50 @@ EXPORT_SYMBOL_GPL(handle_fasteoi_mask_irq);
 #endif /* CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS */
 
 /**
+ * irq_chip_set_parent_state - set the state of a parent interrupt.
+ *
+ * @data: Pointer to interrupt specific data
+ * @which: State to be restored (one of IRQCHIP_STATE_*)
+ * @val: Value corresponding to @which
+ *
+ * Conditional success, if the underlying irqchip does not implement it.
+ */
+int irq_chip_set_parent_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool val)
+{
+   data = data->parent_data;
+
+   if (!data || !data->chip->irq_set_irqchip_state)
+   return 0;
+
+   return data->chip->irq_set_irqchip_state(data, which, val);
+}
+EXPORT_SYMBOL_GPL(irq_chip_set_parent_state);
+
+/**
+ * irq_chip_get_parent_state - get the state of a parent interrupt.
+ *
+ * @data: Pointer to interrupt specific data
+ * @which: one of IRQCHIP_STATE_* the caller wants to know
+ * @state: a pointer to a boolean where the state is to be stored
+ *
+ * Conditional success, if the underlying irqchip does not implement it.
+ */
+int irq_chip_get_parent_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool *state)
+{
+   data = data->parent_data;
+
+   if (!data || !data->chip->irq_get_irqchip_state)
+   return 0;
+
+   return data->chip->irq_get_irqchip_state(data, which, state);
+}
+EXPORT_SYMBOL_GPL(irq_chip_get_parent_state);
+
+/**
  * irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if
  * NULL)
  * @data:  Pointer to interrupt specific data
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 11/14] drivers: pinctrl: sdm845: add PDC wakeup interrupt map for GPIOs

2019-09-13 Thread Lina Iyer
Add interrupt parents for wakeup capable GPIOs for Qualcomm SDM845 SoC.

Signed-off-by: Lina Iyer 
---
Changes in RFC v2:
- Rearranged GPIO wakeup parent map
---
 drivers/pinctrl/qcom/pinctrl-sdm845.c | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c 
b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 39f498c..9cff3a4 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
  */
 
 #include 
@@ -1282,6 +1282,24 @@ static const int sdm845_acpi_reserved_gpios[] = {
0, 1, 2, 3, 81, 82, 83, 84, -1
 };
 
+static const struct msm_gpio_wakeirq_map sdm845_pdc_map[] = {
+   { 1, 30 }, { 3, 31 }, { 5, 32 }, { 10, 33 }, { 11, 34 },
+   { 20, 35 }, { 22, 36 }, { 24, 37 }, { 26, 38 }, { 30, 39 },
+   { 31, 117 }, { 32, 41 }, { 34, 42 }, { 36, 43 }, { 37, 44 },
+   { 38, 45 }, { 39, 46 }, { 40, 47 }, { 41, 115 }, { 43, 49 },
+   { 44, 50 }, { 46, 51 }, { 48, 52 }, { 49, 118 }, { 52, 54 },
+   { 53, 55 }, { 54, 56 }, { 56, 57 }, { 57, 58 }, { 58, 59 },
+   { 59, 60 }, { 60, 61 }, { 61, 62 }, { 62, 63 }, { 63, 64 },
+   { 64, 65 }, { 66, 66 }, { 68, 67 }, { 71, 68 }, { 73, 69 },
+   { 77, 70 }, { 78, 71 }, { 79, 72 }, { 80, 73 }, { 84, 74 },
+   { 85, 75 }, { 86, 76 }, { 88, 77 }, { 89, 116 }, { 91, 79 },
+   { 92, 80 }, { 95, 81 }, { 96, 82 }, { 97, 83 }, { 101, 84 },
+   { 103, 85 }, { 104, 86 }, { 115, 90 }, { 116, 91 }, { 117, 92 },
+   { 118, 93 }, { 119, 94 }, { 120, 95 }, { 121, 96 }, { 122, 97 },
+   { 123, 98 }, { 124, 99 }, { 125, 100 }, { 127, 102 }, { 128, 103 },
+   { 129, 104 }, { 130, 105 }, { 132, 106 }, { 133, 107 }, { 145, 108 },
+};
+
 static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
.pins = sdm845_pins,
.npins = ARRAY_SIZE(sdm845_pins),
@@ -1290,6 +1308,9 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = 
{
.groups = sdm845_groups,
.ngroups = ARRAY_SIZE(sdm845_groups),
.ngpios = 151,
+   .wakeirq_map = sdm845_pdc_map,
+   .nwakeirq_map = ARRAY_SIZE(sdm845_pdc_map),
+
 };
 
 static const struct msm_pinctrl_soc_data sdm845_acpi_pinctrl = {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 07/14] drivers: irqchip: pdc: additionally set type in SPI config registers

2019-09-13 Thread Lina Iyer
GPIOs that can be configured as wakeup are routed to the PDC wakeup
interrupt controller and from there to the GIC interrupt controller. On
some QCOM SoCs, the interface to the GIC for wakeup capable GPIOs have
additional hardware registers that need to be configured as well to
match the trigger type of the GPIO. This register interfaces the PDC to
the GIC and therefore updated from the PDC driver.

Typically, the firmware intializes the interface registers for the
wakeup capable GPIOs with commonly used GPIO trigger type, but it is
possible that a platform may want to use the GPIO differently. So, in
addition to configuring the PDC, configure the interface registers as
well.

Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c | 93 ++
 1 file changed, 93 insertions(+)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index 4abd775..affb0bfa 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -18,6 +18,8 @@
 #include 
 #include 
 
+#include 
+
 #define PDC_MAX_IRQS   168
 #define PDC_MAX_GPIO_IRQS  256
 
@@ -35,10 +37,20 @@ struct pdc_pin_region {
u32 cnt;
 };
 
+struct spi_cfg_regs {
+   union {
+   u64 start;
+   void __iomem *base;
+   };
+   resource_size_t size;
+   bool scm_io;
+};
+
 static DEFINE_RAW_SPINLOCK(pdc_lock);
 static void __iomem *pdc_base;
 static struct pdc_pin_region *pdc_region;
 static int pdc_region_cnt;
+static struct spi_cfg_regs *spi_cfg;
 
 static void pdc_reg_write(int reg, u32 i, u32 val)
 {
@@ -100,6 +112,57 @@ static void qcom_pdc_gic_unmask(struct irq_data *d)
irq_chip_unmask_parent(d);
 }
 
+static u32 __spi_pin_read(unsigned int pin)
+{
+   void __iomem *cfg_reg = spi_cfg->base + pin * 4;
+   u64 scm_cfg_reg = spi_cfg->start + pin * 4;
+
+   if (spi_cfg->scm_io) {
+   unsigned int val;
+
+   qcom_scm_io_readl(scm_cfg_reg, );
+   return val;
+   } else {
+   return readl(cfg_reg);
+   }
+}
+
+static void __spi_pin_write(unsigned int pin, unsigned int val)
+{
+   void __iomem *cfg_reg = spi_cfg->base + pin * 4;
+   u64 scm_cfg_reg = spi_cfg->start + pin * 4;
+
+   if (spi_cfg->scm_io)
+   qcom_scm_io_writel(scm_cfg_reg, val);
+   else
+   writel(val, cfg_reg);
+}
+
+static int spi_configure_type(irq_hw_number_t hwirq, unsigned int type)
+{
+   int spi = hwirq - 32;
+   u32 pin = spi / 32;
+   u32 mask = BIT(spi % 32);
+   u32 val;
+   unsigned long flags;
+
+   if (!spi_cfg)
+   return 0;
+
+   if (pin * 4 > spi_cfg->size)
+   return -EFAULT;
+
+   raw_spin_lock_irqsave(_lock, flags);
+   val = __spi_pin_read(pin);
+   val &= ~mask;
+   if (type & IRQ_TYPE_LEVEL_MASK)
+   val |= mask;
+   __spi_pin_write(pin, val);
+   raw_spin_unlock_irqrestore(_lock, flags);
+
+   return 0;
+}
+
 /*
  * GIC does not handle falling edge or active low. To allow falling edge and
  * active low interrupts to be handled at GIC, PDC has an inverter that inverts
@@ -137,7 +200,9 @@ enum pdc_irq_config_bits {
 static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
 {
int pin_out = d->hwirq;
+   int parent_hwirq = d->parent_data->hwirq;
enum pdc_irq_config_bits pdc_type;
+   int ret;
 
if (pin_out == GPIO_NO_WAKE_IRQ)
return 0;
@@ -168,6 +233,11 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, 
unsigned int type)
 
pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type);
 
+   /* Additionally, configure (only) the GPIO in the f/w */
+   ret = spi_configure_type(parent_hwirq, type);
+   if (ret)
+   return ret;
+
return irq_chip_set_type_parent(d, type);
 }
 
@@ -354,6 +424,7 @@ static int pdc_setup_pin_mapping(struct device_node *np)
 static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
 {
struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain;
+   struct resource res;
int ret;
 
pdc_base = of_iomap(node, 0);
@@ -384,6 +455,27 @@ static int qcom_pdc_init(struct device_node *node, struct 
device_node *parent)
goto fail;
}
 
+   ret = of_address_to_resource(node, 1, );
+   if (!ret) {
+   spi_cfg = kcalloc(1, sizeof(*spi_cfg), GFP_KERNEL);
+   if (!spi_cfg) {
+   ret = -ENOMEM;
+   goto remove;
+   }
+   spi_cfg->scm_io = of_find_property(node,
+  "qcom,scm-spi-cfg", NULL);
+   spi_cfg->size = resource_size();
+   if (spi_cfg->scm_io) {
+   spi_cfg->start = res.start;
+   } else {
+

[PATCH RFC v2 02/14] drivers: irqchip: qcom-pdc: update max PDC interrupts

2019-09-13 Thread Lina Iyer
Newer SoCs have increased the number of interrupts routed to the PDC
interrupt controller. Update the definition of max PDC interrupts.

Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index faa7d61..b230794 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  */
 
 #include 
@@ -18,7 +18,7 @@
 #include 
 #include 
 
-#define PDC_MAX_IRQS   126
+#define PDC_MAX_IRQS   168
 
 #define CLEAR_INTR(reg, intr)  (reg & ~(1 << intr))
 #define ENABLE_INTR(reg, intr) (reg | (1 << intr))
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 00/14] Support wakeup capable GPIOs

2019-09-13 Thread Lina Iyer
Thanks for all the helpful reviews. Here is the next revision addressing the
comments.

Changes in RFC v2:
- Address review comments #3, #4, #6, #7, #8, #9, #10
- Rebased on top of linux-next GPIO latest patches [1],[3],[4]
- Increase PDC max irqs in #2 (avoid merge conflicts with downstream)
- Add Reviewed-by #5

Note: This revision does not update writing the config registers that are
written from the PDC. There needs more discussion in that area. #6, #7

---

This series is another attempt on adding wakeup capable GPIOs for QCOM
SoC. This patchset is based on Linus's support for hierarchical GPIOs
merged into linux-next [1]. The essense of the idea remains the same as
the previous submission [2]. GPIO irqchip TLMM is setup in hierarchy wit
the PDC as the wakeup-parent. PDC's interrupt parent is the GIC. GPIOs
in QCOM SoC that are wakeup capable (when TLMM is powered off) are
routed to the PDC as well and can be detected at the always-on interrupt
controller (PDC). The idea is setup the irqchips in hierarchy and if the
interrupt is handled at the PDC, then TLMM relinquishes control and
configuration of the interrupt to the PDC.

There are few new additions in this submission. The first is the
additional SPI configuration that needs to be done to setup the GPIO
type in a register interface between the PDC and the GIC. This is needed
only for GPIOs. This registers in some QCOM SoCs is access restricted
and has to be written from the TZ. The DT bindings are also updated for
this new requirement. The second change is that with the new
hierarchical support in gpiolib, we could remove the .alloc and
.translate functions from the pinctrl driver. But to distinguish the
case where a wakeup interrupt controller needs the TLMM to configure the
GPIO interrupts (in the case of MPM interrupt controller), irqdomain
flags have been added. The third change is ensure the interrupt
controllers' interrupt pending bits are cleared when the GPIO is enabled
as an interrupt.

Please consider reviewing these patches.

Thanks,
Lina

[1]. 
https://lore.kernel.org/linux-gpio/20190808123242.5359-1-linus.wall...@linaro.org/
[2]. https://lkml.org/lkml/2019/5/7/1173
[3]. https://lore.kernel.org/r/20190819084904.30027-1-linus.wall...@linaro.org
[4]. https://lore.kernel.org/r/20190724083828.7496-1-linus.wall...@linaro.org


Lina Iyer (12):
  irqdomain: add bus token DOMAIN_BUS_WAKEUP
  drivers: irqchip: qcom-pdc: update max PDC interrupts
  drivers: irqchip: pdc: Do not toggle IRQ_ENABLE during mask/unmask
  drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs
  of: irq: document properties for wakeup interrupt parent
  dt-bindings/interrupt-controller: pdc: add SPI config register
  drivers: irqchip: pdc: additionally set type in SPI config registers
  drivers: pinctrl: msm: setup GPIO chip in hierarchy
  drivers: pinctrl: sdm845: add PDC wakeup interrupt map for GPIOs
  arm64: dts: qcom: add PDC interrupt controller for SDM845
  arm64: dts: qcom: setup PDC as the wakeup parent for TLMM on SDM845
  arm64: defconfig: enable PDC interrupt controller for Qualcomm SDM845

Maulik Shah (2):
  genirq: Introduce irq_chip_get/set_parent_state calls
  drivers: irqchip: pdc: Add irqchip set/get state calls

 .../bindings/interrupt-controller/interrupts.txt   |  13 ++
 .../bindings/interrupt-controller/qcom,pdc.txt |  13 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi   |  11 +
 arch/arm64/configs/defconfig   |   1 +
 drivers/irqchip/qcom-pdc.c | 238 +++--
 drivers/pinctrl/qcom/pinctrl-msm.c | 119 +++
 drivers/pinctrl/qcom/pinctrl-msm.h |  16 ++
 drivers/pinctrl/qcom/pinctrl-sdm845.c  |  23 +-
 include/linux/irq.h|   6 +
 include/linux/irqdomain.h  |   1 +
 include/linux/soc/qcom/irq.h   |  32 +++
 kernel/irq/chip.c  |  44 
 12 files changed, 502 insertions(+), 15 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 01/14] irqdomain: add bus token DOMAIN_BUS_WAKEUP

2019-09-13 Thread Lina Iyer
A single controller can handle normal interrupts and wake-up interrupts
independently, with a different numbering space. It is thus crucial to
allow the driver for such a controller discriminate between the two.

A simple way to do so is to tag the wake-up irqdomain with a "bus token"
that indicates the wake-up domain. This slightly abuses the notion of
bus, but also radically simplifies the design of such a driver. Between
two evils, we choose the least damaging.

Suggested-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
 include/linux/irqdomain.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 07ec8b3..cc846ab 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -83,6 +83,7 @@ enum irq_domain_bus_token {
DOMAIN_BUS_IPI,
DOMAIN_BUS_FSL_MC_MSI,
DOMAIN_BUS_TI_SCI_INTA_MSI,
+   DOMAIN_BUS_WAKEUP,
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 03/14] drivers: irqchip: pdc: Do not toggle IRQ_ENABLE during mask/unmask

2019-09-13 Thread Lina Iyer
When an interrupt is to be serviced, the convention is to mask the
interrupt at the chip and unmask after servicing the interrupt. Enabling
and disabling the interrupt at the PDC irqchip causes an interrupt storm
due to the way dual edge interrupts are handled in hardware.

Skip configuring the PDC when the IRQ is masked and unmasked, instead
use the irq_enable/irq_disable callbacks to toggle the IRQ_ENABLE
register at the PDC. The PDC's IRQ_ENABLE register is only used during
the monitoring mode when the system is asleep and is not needed for
active mode detection.

Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index b230794..5eef5ea 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -63,15 +63,25 @@ static void pdc_enable_intr(struct irq_data *d, bool on)
raw_spin_unlock(_lock);
 }
 
-static void qcom_pdc_gic_mask(struct irq_data *d)
+static void qcom_pdc_gic_disable(struct irq_data *d)
 {
pdc_enable_intr(d, false);
+   irq_chip_disable_parent(d);
+}
+
+static void qcom_pdc_gic_enable(struct irq_data *d)
+{
+   pdc_enable_intr(d, true);
+   irq_chip_enable_parent(d);
+}
+
+static void qcom_pdc_gic_mask(struct irq_data *d)
+{
irq_chip_mask_parent(d);
 }
 
 static void qcom_pdc_gic_unmask(struct irq_data *d)
 {
-   pdc_enable_intr(d, true);
irq_chip_unmask_parent(d);
 }
 
@@ -148,6 +158,8 @@ static struct irq_chip qcom_pdc_gic_chip = {
.irq_eoi= irq_chip_eoi_parent,
.irq_mask   = qcom_pdc_gic_mask,
.irq_unmask = qcom_pdc_gic_unmask,
+   .irq_disable= qcom_pdc_gic_disable,
+   .irq_enable = qcom_pdc_gic_enable,
.irq_retrigger  = irq_chip_retrigger_hierarchy,
.irq_set_type   = qcom_pdc_gic_set_type,
.flags  = IRQCHIP_MASK_ON_SUSPEND |
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC v2 06/14] dt-bindings/interrupt-controller: pdc: add SPI config register

2019-09-13 Thread Lina Iyer
In addition to configuring the PDC, additional registers that interface
the GIC have to be configured to match the GPIO type. The registers on
some QCOM SoCs are access restricted, while on other SoCs are not. They
SoCs with access restriction to these SPI registers need to be written
from the firmware using the SCM interface. Add a flag to indicate if the
register is to be written using SCM interface.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
---
 .../devicetree/bindings/interrupt-controller/qcom,pdc.txt   | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt 
b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
index 8e0797c..e329f8d 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
@@ -24,6 +24,9 @@ Properties:
Usage: required
Value type: 
Definition: Specifies the base physical address for PDC hardware.
+   Optionally, specify the PDC's GIC interface registers that
+   need to be configured for wakeup capable GPIOs routed to
+   the PDC.
 
 - interrupt-cells:
Usage: required
@@ -50,15 +53,23 @@ Properties:
The second element is the GIC hwirq number for the PDC port.
The third element is the number of interrupts in sequence.
 
+- qcom,scm-spi-cfg:
+   Usage: optional
+   Value type: 
+   Definition: Specifies if the SPI configuration registers have to be
+   written from the firmware. Sometimes the PDC interface
+   register to the GIC can only be written from the firmware.
+
 Example:
 
pdc: interrupt-controller@b22 {
compatible = "qcom,sdm845-pdc";
-   reg = <0xb22 0x3>;
+   reg = <0 0x0b22 0 0x3>, <0 0x179900f0 0 0x60>;
qcom,pdc-ranges = <0 512 94>, <94 641 15>, <115 662 7>;
#interrupt-cells = <2>;
interrupt-parent = <>;
interrupt-controller;
+   qcom,scm-spi-cfg;
};
 
 DT binding of a device that wants to use the GIC SPI 514 as a wakeup
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH RFC 05/14] dt-bindings/interrupt-controller: pdc: add SPI config register

2019-09-13 Thread Lina Iyer

Sorry, I couldn't get to this earlier.

On Thu, Sep 05 2019 at 18:03 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-09-03 10:07:22)

On Mon, Sep 02 2019 at 07:58 -0600, Marc Zyngier wrote:
>On 02/09/2019 14:38, Rob Herring wrote:
>> On Thu, Aug 29, 2019 at 12:11:54PM -0600, Lina Iyer wrote:
These are not GIC registers but located on the PDC interface to the GIC.
They may or may not be secure access controlled, depending on the SoC.



It looks like it falls under this "mailbox" device which is really the
catch all bucket for bits with no home besides they're related to the
apps CPUs/subsystem.


Thanks for pointing to this.

apss_shared: mailbox@1799 {
compatible = "qcom,sdm845-apss-shared";
reg = <0 0x1799 0 0x1000>;

But this doesn't seem correct. The registers in this page are all not
mailbox door bell registers. We should restrict the space allocated to
the mbox to 0xC or something, definitely, not the whole page. They all
cannot be treated as a mailbox registers.

#mbox-cells = <1>;
};

Can you point to this node with a phandle and then parse the reg
property out of it to use in the scm readl/writel APIs? Maybe it can be
a two cell property with <_shared 0xf0> to indicate the offset to
the registers to read/write? In non-secure mode presumably we need to
also write these registers? Good news is that there's a regmap for this
driver already, so maybe that can be acquired from the pdc driver.


The register space collection seems to be mix of different types of
application processor registers that should probably not be grouped up
under one subsystem. A single regmap doesn't seem correct either.

-- Lina


Re: [PATCH RFC 09/14] drivers: pinctrl: msm: fix use of deprecated gpiolib APIs

2019-09-11 Thread Lina Iyer

On Wed, Sep 11 2019 at 04:19 -0600, Linus Walleij wrote:

On Thu, Aug 29, 2019 at 7:35 PM Lina Iyer  wrote:


Replace gpiochip_irqchip_add() and gpiochip_set_chained_irqchip() calls
by populating the gpio_irq_chip data structures instead.

Signed-off-by: Lina Iyer 


This is mostly fixed upstream I think, but:


+   chip->irq.fwnode = pctrl->dev->fwnode;


This fwnode assignment is missing though.

Sorry for the constant churn and required rebasing...


Not a problem. Will rebase.


Re: [PATCH RFC 02/14] drivers: irqchip: pdc: Do not toggle IRQ_ENABLE during mask/unmask

2019-09-11 Thread Lina Iyer

On Thu, Sep 05 2019 at 18:39 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-08-29 11:11:51)

When an interrupt is to be serviced, the convention is to mask the
interrupt at the chip and unmask after servicing the interrupt. Enabling
and disabling the interrupt at the PDC irqchip causes an interrupt storm
due to the way dual edge interrupts are handled in hardware.

Skip configuring the PDC when the IRQ is masked and unmasked, instead
use the irq_enable/irq_disable callbacks to toggle the IRQ_ENABLE
register at the PDC. The PDC's IRQ_ENABLE register is only used during
the monitoring mode when the system is asleep and is not needed for
active mode detection.


I think this is saying that we want to always let the line be sent
through the PDC to the parent irqchip, in this case GIC, so that we
don't get an interrupt storm for dual edge interrupts? Why does dual
edge interrupts cause a problem?


I am not sure about the hardware details, but the PDC designers did not
expect enable and disable to be called whenever the interrupt is
handled. This specially becomes a problem for dual edge interrupts which
seems to generate a interrupt storm when enabled/disabled while handling
the interrupt.

--Lina



Re: [PATCH RFC 05/14] dt-bindings/interrupt-controller: pdc: add SPI config register

2019-09-11 Thread Lina Iyer

On Wed, Sep 11 2019 at 04:05 -0600, Linus Walleij wrote:

On Thu, Aug 29, 2019 at 8:47 PM Lina Iyer  wrote:


+- qcom,scm-spi-cfg:
+   Usage: optional
+   Value type: 
+   Definition: Specifies if the SPI configuration registers have to be
+   written from the firmware.
+
 Example:

pdc: interrupt-controller@b22 {
compatible = "qcom,sdm845-pdc";
-   reg = <0xb22 0x3>;
+   reg = <0xb22 0x3>, <0x179900f0 0x60>;
qcom,pdc-ranges = <0 512 94>, <94 641 15>, <115 662 7>;
#interrupt-cells = <2>;
interrupt-parent = <>;
interrupt-controller;
+   qcom,scm-spi-cfg;


You can probably drop this bool if you just give names to the registers.

Like
reg = <0xb22 0x3>, <0x179900f0 0x60>;
reg-names = "gic", "pdc";

Then jus check explicitly for a "pdc" register and in that case
initialize the PDC.


Well the address remains the same. The bool defines how to access that
register address - from linux or from the firmware using SCM calls. But
I get your point, I could have different register namess - pdc-linux or
pdc-scm and request by name. I can then use that to determine the mode
for accessing the register.

Thanks,
Lina



Re: [PATCH RFC 05/14] dt-bindings/interrupt-controller: pdc: add SPI config register

2019-09-03 Thread Lina Iyer

On Mon, Sep 02 2019 at 07:58 -0600, Marc Zyngier wrote:

On 02/09/2019 14:38, Rob Herring wrote:

On Thu, Aug 29, 2019 at 12:11:54PM -0600, Lina Iyer wrote:

In addition to configuring the PDC, additional registers that interface
the GIC have to be configured to match the GPIO type. The registers on
some QCOM SoCs are access restricted, while on other SoCs are not. They
SoCs with access restriction to these SPI registers need to be written


Took me a minute to figure out this is GIC SPI interrupts, not SPI bus.


from the firmware using the SCM interface. Add a flag to indicate if the
register is to be written using SCM interface.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
---
 .../bindings/interrupt-controller/qcom,pdc.txt   | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt 
b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
index 8e0797cb1487..852fcba98ea6 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
@@ -50,15 +50,22 @@ Properties:
The second element is the GIC hwirq number for the PDC port.
The third element is the number of interrupts in sequence.

+- qcom,scm-spi-cfg:
+   Usage: optional
+   Value type: 
+   Definition: Specifies if the SPI configuration registers have to be
+   written from the firmware.
+
 Example:

pdc: interrupt-controller@b22 {
compatible = "qcom,sdm845-pdc";
-   reg = <0xb22 0x3>;
+   reg = <0xb22 0x3>, <0x179900f0 0x60>;


There needs to be a description for reg updated. These aren't GIC
registers are they? Because those go in the GIC node.



They are not GIC registers. I will update this documentation.


This is completely insane. Why are the GIC registers configured as
secure the first place, if they are expected to be in control of the
non-secure?

These are not GIC registers but located on the PDC interface to the GIC.
They may or may not be secure access controlled, depending on the SoC.

Thanks,
Lina


Re: [PATCH RFC 03/14] drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs

2019-08-30 Thread Lina Iyer

On Fri, Aug 30 2019 at 08:50 -0600, Marc Zyngier wrote:

[Please use my kernel.org address in the future. The days of this
arm.com address are numbered...]


Sure, will update and repost.


On 29/08/2019 19:11, Lina Iyer wrote:

Introduce a new domain for wakeup capable GPIOs. The domain can be
requested using the bus token DOMAIN_BUS_WAKEUP. In the following
patches, we will specify PDC as the wakeup-parent for the TLMM GPIO
irqchip. Requesting a wakeup GPIO will setup the GPIO and the
corresponding PDC interrupt as its parent.

Co-developed-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c   | 104 ---
 include/linux/soc/qcom/irq.h |  34 
 2 files changed, 129 insertions(+), 9 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index 338fae604af5..ad1faf634bcf 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -13,12 +13,13 @@
 #include 
 #include 
 #include 
+#include 
 #include 
-#include 
 #include 
 #include 

 #define PDC_MAX_IRQS   126
+#define PDC_MAX_GPIO_IRQS  256

 #define CLEAR_INTR(reg, intr)  (reg & ~(1 << intr))
 #define ENABLE_INTR(reg, intr) (reg | (1 << intr))
@@ -26,6 +27,8 @@
 #define IRQ_ENABLE_BANK0x10
 #define IRQ_i_CFG  0x110

+#define PDC_NO_PARENT_IRQ  ~0UL
+
 struct pdc_pin_region {
u32 pin_base;
u32 parent_base;
@@ -65,23 +68,35 @@ static void pdc_enable_intr(struct irq_data *d, bool on)

 static void qcom_pdc_gic_disable(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, false);
irq_chip_disable_parent(d);
 }

 static void qcom_pdc_gic_enable(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, true);
irq_chip_enable_parent(d);
 }

 static void qcom_pdc_gic_mask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
irq_chip_mask_parent(d);
 }

 static void qcom_pdc_gic_unmask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
irq_chip_unmask_parent(d);
 }

@@ -124,6 +139,9 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, 
unsigned int type)
int pin_out = d->hwirq;
enum pdc_irq_config_bits pdc_type;

+   if (pin_out == GPIO_NO_WAKE_IRQ)
+   return 0;
+
switch (type) {
case IRQ_TYPE_EDGE_RISING:
pdc_type = PDC_EDGE_RISING;
@@ -181,8 +199,7 @@ static irq_hw_number_t get_parent_hwirq(int pin)
return (region->parent_base + pin - region->pin_base);
}

-   WARN_ON(1);
-   return ~0UL;
+   return PDC_NO_PARENT_IRQ;
 }

 static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
@@ -211,17 +228,17 @@ static int qcom_pdc_alloc(struct irq_domain *domain, 
unsigned int virq,

ret = qcom_pdc_translate(domain, fwspec, , );
if (ret)
-   return -EINVAL;
-
-   parent_hwirq = get_parent_hwirq(hwirq);
-   if (parent_hwirq == ~0UL)
-   return -EINVAL;
+   return ret;

ret  = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
 _pdc_gic_chip, NULL);
if (ret)
return ret;

+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
if (type & IRQ_TYPE_EDGE_BOTH)
type = IRQ_TYPE_EDGE_RISING;

@@ -244,6 +261,60 @@ static const struct irq_domain_ops qcom_pdc_ops = {
.free   = irq_domain_free_irqs_common,
 };

+static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,
+  unsigned int nr_irqs, void *data)
+{
+   struct irq_fwspec *fwspec = data;
+   struct irq_fwspec parent_fwspec;
+   irq_hw_number_t hwirq, parent_hwirq;
+   unsigned int type;
+   int ret;
+
+   ret = qcom_pdc_translate(domain, fwspec, , );
+   if (ret)
+   return ret;
+
+   ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+   _pdc_gic_chip, NULL);
+   if (ret)
+   return ret;
+
+   if (hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
+   if (type & IRQ_TYPE_EDGE_BOTH)
+   type = IRQ_TYPE_EDGE_RISING;
+
+   if (type & IRQ_TYPE_LEVEL_MASK)
+   type = IRQ_TYPE_LEVEL_HIGH;
+
+   parent_fwspec.fwnode  = domain->parent->fwnode;
+   parent_fwspec.param_count = 3;
+   parent_fwspec.param[0]= 0;
+   parent_fwspec.pa

[PATCH RFC 01/14] irqdomain: add bus token DOMAIN_BUS_WAKEUP

2019-08-29 Thread Lina Iyer
A single controller can handle normal interrupts and wake-up interrupts
independently, with a different numbering space. It is thus crucial to
allow the driver for such a controller discriminate between the two.

A simple way to do so is to tag the wake-up irqdomain with a "bus token"
that indicates the wake-up domain. This slightly abuses the notion of
bus, but also radically simplifies the design of such a driver. Between
two evils, we choose the least damaging.

Suggested-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
 include/linux/irqdomain.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 07ec8b390161..cc846abeff28 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -83,6 +83,7 @@ enum irq_domain_bus_token {
DOMAIN_BUS_IPI,
DOMAIN_BUS_FSL_MC_MSI,
DOMAIN_BUS_TI_SCI_INTA_MSI,
+   DOMAIN_BUS_WAKEUP,
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 05/14] dt-bindings/interrupt-controller: pdc: add SPI config register

2019-08-29 Thread Lina Iyer
In addition to configuring the PDC, additional registers that interface
the GIC have to be configured to match the GPIO type. The registers on
some QCOM SoCs are access restricted, while on other SoCs are not. They
SoCs with access restriction to these SPI registers need to be written
from the firmware using the SCM interface. Add a flag to indicate if the
register is to be written using SCM interface.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
---
 .../bindings/interrupt-controller/qcom,pdc.txt   | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt 
b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
index 8e0797cb1487..852fcba98ea6 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
@@ -50,15 +50,22 @@ Properties:
The second element is the GIC hwirq number for the PDC port.
The third element is the number of interrupts in sequence.
 
+- qcom,scm-spi-cfg:
+   Usage: optional
+   Value type: 
+   Definition: Specifies if the SPI configuration registers have to be
+   written from the firmware.
+
 Example:
 
pdc: interrupt-controller@b22 {
compatible = "qcom,sdm845-pdc";
-   reg = <0xb22 0x3>;
+   reg = <0xb22 0x3>, <0x179900f0 0x60>;
qcom,pdc-ranges = <0 512 94>, <94 641 15>, <115 662 7>;
#interrupt-cells = <2>;
interrupt-parent = <>;
interrupt-controller;
+   qcom,scm-spi-cfg;
};
 
 DT binding of a device that wants to use the GIC SPI 514 as a wakeup
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 10/14] drivers: pinctrl: msm: setup GPIO chip in hierarchy

2019-08-29 Thread Lina Iyer
Some GPIOs are marked as wakeup capable and are routed to another
interrupt controller that is an always-domain and can detect interrupts
even most of the SoC is powered off. The wakeup interrupt controller
wakes up the GIC and replays the interrupt at the GIC.

Setup the TLMM irqchip in hierarchy with the wakeup interrupt controller
and ensure the wakeup GPIOs are handled correctly.

Signed-off-by: Maulik Shah 
Signed-off-by: Lina Iyer 
---
 drivers/pinctrl/qcom/pinctrl-msm.c | 114 +
 drivers/pinctrl/qcom/pinctrl-msm.h |  16 
 2 files changed, 130 insertions(+)

diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c 
b/drivers/pinctrl/qcom/pinctrl-msm.c
index 76e8528e4d0a..d626264fe678 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -23,6 +23,8 @@
 #include 
 #include 
 
+#include 
+
 #include "../core.h"
 #include "../pinconf.h"
 #include "pinctrl-msm.h"
@@ -44,6 +46,7 @@
  * @enabled_irqs:   Bitmap of currently enabled irqs.
  * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
  *  detection.
+ * @skip_wake_irqs: Skip IRQs that are handled by wakeup interrupt contrroller
  * @soc;Reference to soc_data of platform specific data.
  * @regs:   Base addresses for the TLMM tiles.
  */
@@ -61,6 +64,7 @@ struct msm_pinctrl {
 
DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
+   DECLARE_BITMAP(skip_wake_irqs, MAX_NR_GPIO);
 
const struct msm_pinctrl_soc_data *soc;
void __iomem *regs[MAX_NR_TILES];
@@ -708,6 +712,12 @@ static void msm_gpio_irq_mask(struct irq_data *d)
unsigned long flags;
u32 val;
 
+   if (d->parent_data)
+   irq_chip_mask_parent(d);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -752,6 +762,12 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, 
bool status_clear)
unsigned long flags;
u32 val;
 
+   if (d->parent_data)
+   irq_chip_unmask_parent(d);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -779,10 +795,43 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, 
bool status_clear)
 
 static void msm_gpio_irq_enable(struct irq_data *d)
 {
+   struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+   struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+
+   /*
+* Clear the interrupt that may be pending before we enable
+* the line.
+* This is especially a problem with the GPIOs routed to the
+* PDC. These GPIOs are direct-connect interrupts to the GIC.
+* Disabling the interrupt line at the PDC does not prevent
+* the interrupt from being latched at the GIC. The state at
+* GIC needs to be cleared before enabling.
+*/
+   if (d->parent_data) {
+   irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, 0);
+   irq_chip_enable_parent(d);
+   }
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
 
msm_gpio_irq_clear_unmask(d, true);
 }
 
+static void msm_gpio_irq_disable(struct irq_data *d)
+{
+   struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+   struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+
+   if (d->parent_data)
+   irq_chip_disable_parent(d);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
+   msm_gpio_irq_mask(d);
+}
+
 static void msm_gpio_irq_unmask(struct irq_data *d)
 {
msm_gpio_irq_clear_unmask(d, false);
@@ -796,6 +845,9 @@ static void msm_gpio_irq_ack(struct irq_data *d)
unsigned long flags;
u32 val;
 
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -821,6 +873,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, 
unsigned int type)
unsigned long flags;
u32 val;
 
+   if (d->parent_data)
+   irq_chip_set_type_parent(d, type);
+
+   if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
+   return 0;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -913,6 +971,15 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, 
unsigned int on)
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned long flags;
 
+   if (d->parent_data)
+   irq_chip_set_wake_parent(d, on);
+
+   /*
+* While they may not wake up when the TLMM is powered off,
+* some GPIOs wou

[PATCH RFC 06/14] drivers: irqchip: pdc: additionally set type in SPI config registers

2019-08-29 Thread Lina Iyer
GPIOs that can be configured as wakeup are routed to the PDC wakeup
interrupt controller and from there to the GIC interrupt controller. On
some QCOM SoCs, the interface to the GIC for wakeup capable GPIOs have
additional hardware registers that need to be configured as well to
match the trigger type of the GPIO. This register interfaces the PDC to
the GIC and therefore updated from the PDC driver.

Typically, the firmware intializes the interface registers for the
wakeup capable GPIOs with commonly used GPIO trigger type, but it is
possible that a platform may want to use the GPIO differently. So, in
addition to configuring the PDC, configure the interface registers as
well.

Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c | 93 ++
 1 file changed, 93 insertions(+)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index ad1faf634bcf..bf5f98bb4d2b 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -18,6 +18,8 @@
 #include 
 #include 
 
+#include 
+
 #define PDC_MAX_IRQS   126
 #define PDC_MAX_GPIO_IRQS  256
 
@@ -35,10 +37,20 @@ struct pdc_pin_region {
u32 cnt;
 };
 
+struct spi_cfg_regs {
+   union {
+   u64 start;
+   void __iomem *base;
+   };
+   resource_size_t size;
+   bool scm_io;
+};
+
 static DEFINE_RAW_SPINLOCK(pdc_lock);
 static void __iomem *pdc_base;
 static struct pdc_pin_region *pdc_region;
 static int pdc_region_cnt;
+static struct spi_cfg_regs *spi_cfg;
 
 static void pdc_reg_write(int reg, u32 i, u32 val)
 {
@@ -100,6 +112,57 @@ static void qcom_pdc_gic_unmask(struct irq_data *d)
irq_chip_unmask_parent(d);
 }
 
+static u32 __spi_pin_read(unsigned int pin)
+{
+   void __iomem *cfg_reg = spi_cfg->base + pin * 4;
+   u64 scm_cfg_reg = spi_cfg->start + pin * 4;
+
+   if (spi_cfg->scm_io) {
+   unsigned int val;
+
+   qcom_scm_io_readl(scm_cfg_reg, );
+   return val;
+   } else {
+   return readl(cfg_reg);
+   }
+}
+
+static void __spi_pin_write(unsigned int pin, unsigned int val)
+{
+   void __iomem *cfg_reg = spi_cfg->base + pin * 4;
+   u64 scm_cfg_reg = spi_cfg->start + pin * 4;
+
+   if (spi_cfg->scm_io)
+   qcom_scm_io_writel(scm_cfg_reg, val);
+   else
+   writel(val, cfg_reg);
+}
+
+static int spi_configure_type(irq_hw_number_t hwirq, unsigned int type)
+{
+   int spi = hwirq - 32;
+   u32 pin = spi / 32;
+   u32 mask = BIT(spi % 32);
+   u32 val;
+   unsigned long flags;
+
+   if (!spi_cfg)
+   return 0;
+
+   if (pin * 4 > spi_cfg->size)
+   return -EFAULT;
+
+   raw_spin_lock_irqsave(_lock, flags);
+   val = __spi_pin_read(pin);
+   val &= ~mask;
+   if (type & IRQ_TYPE_LEVEL_MASK)
+   val |= mask;
+   __spi_pin_write(pin, val);
+   raw_spin_unlock_irqrestore(_lock, flags);
+
+   return 0;
+}
+
 /*
  * GIC does not handle falling edge or active low. To allow falling edge and
  * active low interrupts to be handled at GIC, PDC has an inverter that inverts
@@ -137,7 +200,9 @@ enum pdc_irq_config_bits {
 static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
 {
int pin_out = d->hwirq;
+   int parent_hwirq = d->parent_data->hwirq;
enum pdc_irq_config_bits pdc_type;
+   int ret;
 
if (pin_out == GPIO_NO_WAKE_IRQ)
return 0;
@@ -168,6 +233,11 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, 
unsigned int type)
 
pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type);
 
+   /* Additionally, configure (only) the GPIO in the f/w */
+   ret = spi_configure_type(parent_hwirq, type);
+   if (ret)
+   return ret;
+
return irq_chip_set_type_parent(d, type);
 }
 
@@ -354,6 +424,7 @@ static int pdc_setup_pin_mapping(struct device_node *np)
 static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
 {
struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain;
+   struct resource res;
int ret;
 
pdc_base = of_iomap(node, 0);
@@ -384,6 +455,27 @@ static int qcom_pdc_init(struct device_node *node, struct 
device_node *parent)
goto fail;
}
 
+   ret = of_address_to_resource(node, 1, );
+   if (!ret) {
+   spi_cfg = kcalloc(1, sizeof(*spi_cfg), GFP_KERNEL);
+   if (!spi_cfg) {
+   ret = -ENOMEM;
+   goto remove;
+   }
+   spi_cfg->scm_io = of_find_property(node,
+  "qcom,scm-spi-cfg", NULL);
+   spi_cfg->size = resource_size();
+   if (spi_cfg->scm_io) {
+   spi_cfg->start = res.start;
+   } else {
+

[PATCH RFC 00/14] qcom: support wakeup capable GPIOs

2019-08-29 Thread Lina Iyer
This series is another attempt on adding wakeup capable GPIOs for QCOM
SoC. This patchset is based on Linus's support for hierarchical GPIOs
merged into linux-next [1]. The essense of the idea remains the same as
the previous submission [2]. GPIO irqchip TLMM is setup in hierarchy with
the PDC as the wakeup-parent. PDC's interrupt parent is the GIC. GPIOs
in QCOM SoC that are wakeup capable (when TLMM is powered off) are
routed to the PDC as well and can be detected at the always-on interrupt
controller (PDC). The idea is setup the irqchips in hierarchy and if the
interrupt is handled at the PDC, then TLMM relinquishes control and
configuration of the interrupt to the PDC.

There are few new additions in this submission. The first is the
additional SPI configuration that needs to be done to setup the GPIO
type in a register interface between the PDC and the GIC. This is needed
only for GPIOs. This registers in some QCOM SoCs is access restricted
and has to be written from the TZ. The DT bindings are also updated for
this new requirement. The second change is that with the new
hierarchical support in gpiolib, we could remove the .alloc and
.translate functions from the pinctrl driver. But to distinguish the
case where a wakeup interrupt controller needs the TLMM to configure the
GPIO interrupts (in the case of MPM interrupt controller), irqdomain
flags have been added. The third change is ensure the interrupt
controllers' interrupt pending bits are cleared when the GPIO is enabled
as an interrupt.

Please consider reviewing these patches.

Thanks,
Lina

Lina Iyer (12):
  irqdomain: add bus token DOMAIN_BUS_WAKEUP
  drivers: irqchip: pdc: Do not toggle IRQ_ENABLE during mask/unmask
  drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs
  of: irq: document properties for wakeup interrupt parent
  dt-bindings/interrupt-controller: pdc: add SPI config register
  drivers: irqchip: pdc: additionally set type in SPI config registers
  drivers: pinctrl: msm: fix use of deprecated gpiolib APIs
  drivers: pinctrl: msm: setup GPIO chip in hierarchy
  drivers: pinctrl: sdm845: add PDC wakeup interrupt map for GPIOs
  arm64: dts: qcom: add PDC interrupt controller for SDM845
  arm64: dts: qcom: setup PDC as the wakeup parent for TLMM on SDM845
  arm64: defconfig: enable PDC interrupt controller for Qualcomm SDM845

Maulik Shah (2):
  genirq: Introduce irq_chip_get/set_parent_state calls
  drivers: irqchip: pdc: Add irqchip set/get state calls

 .../interrupt-controller/interrupts.txt   |  13 +
 .../interrupt-controller/qcom,pdc.txt |   9 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi  |  11 +
 arch/arm64/configs/defconfig  |   1 +
 drivers/irqchip/qcom-pdc.c| 234 +-
 drivers/pinctrl/qcom/pinctrl-msm.c| 142 +--
 drivers/pinctrl/qcom/pinctrl-msm.h|  16 ++
 drivers/pinctrl/qcom/pinctrl-sdm845.c |  83 ++-
 include/linux/irq.h   |   6 +
 include/linux/irqdomain.h |   1 +
 include/linux/soc/qcom/irq.h  |  34 +++
 kernel/irq/chip.c |  44 
 12 files changed, 566 insertions(+), 28 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 13/14] arm64: dts: qcom: setup PDC as the wakeup parent for TLMM on SDM845

2019-08-29 Thread Lina Iyer
PDC always-on interrupt controller can detect certain GPIOs even when
the TLMM interrupt controller is powered off. Link the PDC as TLMM's
wakeup parent.

Signed-off-by: Lina Iyer 
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index ffe28b3e41d8..3002793ee688 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1358,6 +1358,7 @@
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = < 0 0 150>;
+   wakeup-parent = <_intc>;
 
qspi_clk: qspi-clk {
pinmux {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 04/14] of: irq: document properties for wakeup interrupt parent

2019-08-29 Thread Lina Iyer
Some interrupt controllers in a SoC, are always powered on and have a
select interrupts routed to them, so that they can wakeup the SoC from
suspend. Add wakeup-parent DT property to refer to these interrupt
controllers.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
---
 .../bindings/interrupt-controller/interrupts.txt| 13 +
 1 file changed, 13 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt 
b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
index 8a3c40829899..c10e31050dd2 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
@@ -108,3 +108,16 @@ commonly used:
sensitivity = <7>;
};
};
+
+3) Interrupt wakeup parent
+--
+
+Some interrupt controllers in a SoC, are always powered on and have a select
+interrupts routed to them, so that they can wakeup the SoC from suspend. These
+interrupt controllers do not fall into the category of a parent interrupt
+controller and can be specified by the "wakeup-parent" property and contain a
+single phandle referring to the wakeup capable interrupt controller.
+
+   Example:
+   wakeup-parent = <_intc>;
+
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 08/14] drivers: irqchip: pdc: Add irqchip set/get state calls

2019-08-29 Thread Lina Iyer
From: Maulik Shah 

Add irqchip calls to set/get interrupt status from the parent interrupt
controller.

Signed-off-by: Maulik Shah 
---
 drivers/irqchip/qcom-pdc.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index bf5f98bb4d2b..ffd5f83d1023 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -5,6 +5,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -87,6 +88,24 @@ static void qcom_pdc_gic_disable(struct irq_data *d)
irq_chip_disable_parent(d);
 }
 
+static int qcom_pdc_gic_get_irqchip_state(struct irq_data *d,
+   enum irqchip_irq_state which, bool *state)
+{
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   return irq_chip_get_parent_state(d, which, state);
+}
+
+static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d,
+   enum irqchip_irq_state which, bool value)
+{
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   return irq_chip_set_parent_state(d, which, value);
+}
+
 static void qcom_pdc_gic_enable(struct irq_data *d)
 {
if (d->hwirq == GPIO_NO_WAKE_IRQ)
@@ -248,6 +267,8 @@ static struct irq_chip qcom_pdc_gic_chip = {
.irq_unmask = qcom_pdc_gic_unmask,
.irq_disable= qcom_pdc_gic_disable,
.irq_enable = qcom_pdc_gic_enable,
+   .irq_get_irqchip_state  = qcom_pdc_gic_get_irqchip_state,
+   .irq_set_irqchip_state  = qcom_pdc_gic_set_irqchip_state,
.irq_retrigger  = irq_chip_retrigger_hierarchy,
.irq_set_type   = qcom_pdc_gic_set_type,
.flags  = IRQCHIP_MASK_ON_SUSPEND |
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 07/14] genirq: Introduce irq_chip_get/set_parent_state calls

2019-08-29 Thread Lina Iyer
From: Maulik Shah 

On certain QTI chipsets some GPIOs are direct-connect interrupts
to the GIC.

Even when GPIOs are not used for interrupt generation and interrupt
line is disabled, it does not prevent interrupt to get pending at
GIC_ISPEND. When drivers call enable_irq unwanted interrupt occures.

Introduce irq_chip_get/set_parent_state calls to clear pending irq
which can get called within irq_enable of child irq chip to clear
any pending irq before enabling.

Signed-off-by: Maulik Shah 
---
 include/linux/irq.h |  6 ++
 kernel/irq/chip.c   | 44 
 2 files changed, 50 insertions(+)

diff --git a/include/linux/irq.h b/include/linux/irq.h
index fb301cf29148..7853eb9301f2 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -610,6 +610,12 @@ extern int irq_chip_pm_put(struct irq_data *data);
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
 extern void handle_fasteoi_ack_irq(struct irq_desc *desc);
 extern void handle_fasteoi_mask_irq(struct irq_desc *desc);
+extern int irq_chip_set_parent_state(struct irq_data *data,
+enum irqchip_irq_state which,
+bool val);
+extern int irq_chip_get_parent_state(struct irq_data *data,
+enum irqchip_irq_state which,
+bool *state);
 extern void irq_chip_enable_parent(struct irq_data *data);
 extern void irq_chip_disable_parent(struct irq_data *data);
 extern void irq_chip_ack_parent(struct irq_data *data);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index b76703b2c0af..6bb5b22bb0a7 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -1297,6 +1297,50 @@ EXPORT_SYMBOL_GPL(handle_fasteoi_mask_irq);
 
 #endif /* CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS */
 
+/**
+ * irq_chip_set_parent_state - set the state of a parent interrupt.
+ * @data: Pointer to interrupt specific data
+ * @which: State to be restored (one of IRQCHIP_STATE_*)
+ * @val: Value corresponding to @which
+ *
+ */
+int irq_chip_set_parent_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool val)
+{
+   data = data->parent_data;
+   if (!data)
+   return 0;
+
+   if (data->chip->irq_set_irqchip_state)
+   return data->chip->irq_set_irqchip_state(data, which, val);
+
+   return 0;
+}
+EXPORT_SYMBOL(irq_chip_set_parent_state);
+
+/**
+ * irq_chip_get_parent_state - get the state of a parent interrupt.
+ * @data: Pointer to interrupt specific data
+ * @which: one of IRQCHIP_STATE_* the caller wants to know
+ * @state: a pointer to a boolean where the state is to be stored
+ *
+ */
+int irq_chip_get_parent_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool *state)
+{
+   data = data->parent_data;
+   if (!data)
+   return 0;
+
+   if (data->chip->irq_get_irqchip_state)
+   return data->chip->irq_get_irqchip_state(data, which, state);
+
+   return 0;
+}
+EXPORT_SYMBOL(irq_chip_get_parent_state);
+
 /**
  * irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if
  * NULL)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 09/14] drivers: pinctrl: msm: fix use of deprecated gpiolib APIs

2019-08-29 Thread Lina Iyer
Replace gpiochip_irqchip_add() and gpiochip_set_chained_irqchip() calls
by populating the gpio_irq_chip data structures instead.

Signed-off-by: Lina Iyer 
---
 drivers/pinctrl/qcom/pinctrl-msm.c | 28 +---
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c 
b/drivers/pinctrl/qcom/pinctrl-msm.c
index 7f35c196bb3e..76e8528e4d0a 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -1027,7 +1027,19 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
 
-   ret = gpiochip_add_data(>chip, pctrl);
+   chip->irq.chip = >irq_chip;
+   chip->irq.default_type = IRQ_TYPE_NONE;
+   chip->irq.handler = handle_bad_irq;
+   chip->irq.fwnode = pctrl->dev->fwnode;
+   chip->irq.parent_handler = msm_gpio_irq_handler;
+   chip->irq.num_parents = 1;
+   chip->irq.parents = devm_kcalloc(pctrl->dev, 1,
+sizeof(*chip->irq.parents),
+GFP_KERNEL);
+   if (!chip->irq.parents)
+   return -ENOMEM;
+
+   ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "Failed register gpiochip\n");
return ret;
@@ -1053,20 +1065,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
}
}
 
-   ret = gpiochip_irqchip_add(chip,
-  >irq_chip,
-  0,
-  handle_edge_irq,
-  IRQ_TYPE_NONE);
-   if (ret) {
-   dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
-   gpiochip_remove(>chip);
-   return -ENOSYS;
-   }
-
-   gpiochip_set_chained_irqchip(chip, >irq_chip, pctrl->irq,
-msm_gpio_irq_handler);
-
return 0;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 14/14] arm64: defconfig: enable PDC interrupt controller for Qualcomm SDM845

2019-08-29 Thread Lina Iyer
Enable PDC interrupt controller for SDM845 devices. The interrupt
controller can detect wakeup capable interrupts when the SoC is in a low
power state.

Signed-off-by: Lina Iyer 
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 0e58ef02880c..310b6048054a 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -729,6 +729,7 @@ CONFIG_ARCH_R8A77970=y
 CONFIG_ARCH_R8A77980=y
 CONFIG_ARCH_R8A77990=y
 CONFIG_ARCH_R8A77995=y
+CONFIG_QCOM_PDC=y
 CONFIG_ROCKCHIP_PM_DOMAINS=y
 CONFIG_ARCH_TEGRA_132_SOC=y
 CONFIG_ARCH_TEGRA_210_SOC=y
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 03/14] drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs

2019-08-29 Thread Lina Iyer
Introduce a new domain for wakeup capable GPIOs. The domain can be
requested using the bus token DOMAIN_BUS_WAKEUP. In the following
patches, we will specify PDC as the wakeup-parent for the TLMM GPIO
irqchip. Requesting a wakeup GPIO will setup the GPIO and the
corresponding PDC interrupt as its parent.

Co-developed-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c   | 104 ---
 include/linux/soc/qcom/irq.h |  34 
 2 files changed, 129 insertions(+), 9 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index 338fae604af5..ad1faf634bcf 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -13,12 +13,13 @@
 #include 
 #include 
 #include 
+#include 
 #include 
-#include 
 #include 
 #include 
 
 #define PDC_MAX_IRQS   126
+#define PDC_MAX_GPIO_IRQS  256
 
 #define CLEAR_INTR(reg, intr)  (reg & ~(1 << intr))
 #define ENABLE_INTR(reg, intr) (reg | (1 << intr))
@@ -26,6 +27,8 @@
 #define IRQ_ENABLE_BANK0x10
 #define IRQ_i_CFG  0x110
 
+#define PDC_NO_PARENT_IRQ  ~0UL
+
 struct pdc_pin_region {
u32 pin_base;
u32 parent_base;
@@ -65,23 +68,35 @@ static void pdc_enable_intr(struct irq_data *d, bool on)
 
 static void qcom_pdc_gic_disable(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, false);
irq_chip_disable_parent(d);
 }
 
 static void qcom_pdc_gic_enable(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, true);
irq_chip_enable_parent(d);
 }
 
 static void qcom_pdc_gic_mask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
irq_chip_mask_parent(d);
 }
 
 static void qcom_pdc_gic_unmask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
irq_chip_unmask_parent(d);
 }
 
@@ -124,6 +139,9 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, 
unsigned int type)
int pin_out = d->hwirq;
enum pdc_irq_config_bits pdc_type;
 
+   if (pin_out == GPIO_NO_WAKE_IRQ)
+   return 0;
+
switch (type) {
case IRQ_TYPE_EDGE_RISING:
pdc_type = PDC_EDGE_RISING;
@@ -181,8 +199,7 @@ static irq_hw_number_t get_parent_hwirq(int pin)
return (region->parent_base + pin - region->pin_base);
}
 
-   WARN_ON(1);
-   return ~0UL;
+   return PDC_NO_PARENT_IRQ;
 }
 
 static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
@@ -211,17 +228,17 @@ static int qcom_pdc_alloc(struct irq_domain *domain, 
unsigned int virq,
 
ret = qcom_pdc_translate(domain, fwspec, , );
if (ret)
-   return -EINVAL;
-
-   parent_hwirq = get_parent_hwirq(hwirq);
-   if (parent_hwirq == ~0UL)
-   return -EINVAL;
+   return ret;
 
ret  = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
 _pdc_gic_chip, NULL);
if (ret)
return ret;
 
+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
if (type & IRQ_TYPE_EDGE_BOTH)
type = IRQ_TYPE_EDGE_RISING;
 
@@ -244,6 +261,60 @@ static const struct irq_domain_ops qcom_pdc_ops = {
.free   = irq_domain_free_irqs_common,
 };
 
+static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,
+  unsigned int nr_irqs, void *data)
+{
+   struct irq_fwspec *fwspec = data;
+   struct irq_fwspec parent_fwspec;
+   irq_hw_number_t hwirq, parent_hwirq;
+   unsigned int type;
+   int ret;
+
+   ret = qcom_pdc_translate(domain, fwspec, , );
+   if (ret)
+   return ret;
+
+   ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+   _pdc_gic_chip, NULL);
+   if (ret)
+   return ret;
+
+   if (hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
+   if (type & IRQ_TYPE_EDGE_BOTH)
+   type = IRQ_TYPE_EDGE_RISING;
+
+   if (type & IRQ_TYPE_LEVEL_MASK)
+   type = IRQ_TYPE_LEVEL_HIGH;
+
+   parent_fwspec.fwnode  = domain->parent->fwnode;
+   parent_fwspec.param_count = 3;
+   parent_fwspec.param[0]= 0;
+   parent_fwspec.param[1]= parent_hwirq;
+   parent_fwspec.param[2]= type;
+
+   return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+   _fwspec);
+}
+
+stat

[PATCH RFC 11/14] drivers: pinctrl: sdm845: add PDC wakeup interrupt map for GPIOs

2019-08-29 Thread Lina Iyer
Add interrupt parents for wakeup capable GPIOs for Qualcomm SDM845 SoC.

Signed-off-by: Lina Iyer 
---
 drivers/pinctrl/qcom/pinctrl-sdm845.c | 83 ++-
 1 file changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c 
b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 39f498c09906..5f43dabcd8eb 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
  */
 
 #include 
@@ -1282,6 +1282,84 @@ static const int sdm845_acpi_reserved_gpios[] = {
0, 1, 2, 3, 81, 82, 83, 84, -1
 };
 
+static const struct msm_gpio_wakeirq_map sdm845_pdc_map[] = {
+   {1, 30},
+   {3, 31},
+   {5, 32},
+   {10, 33},
+   {11, 34},
+   {20, 35},
+   {22, 36},
+   {24, 37},
+   {26, 38},
+   {30, 39},
+   {31, 117},
+   {32, 41},
+   {34, 42},
+   {36, 43},
+   {37, 44},
+   {38, 45},
+   {39, 46},
+   {40, 47},
+   {41, 115},
+   {43, 49},
+   {44, 50},
+   {46, 51},
+   {48, 52},
+   {49, 118},
+   {52, 54},
+   {53, 55},
+   {54, 56},
+   {56, 57},
+   {57, 58},
+   {58, 59},
+   {59, 60},
+   {60, 61},
+   {61, 62},
+   {62, 63},
+   {63, 64},
+   {64, 65},
+   {66, 66},
+   {68, 67},
+   {71, 68},
+   {73, 69},
+   {77, 70},
+   {78, 71},
+   {79, 72},
+   {80, 73},
+   {84, 74},
+   {85, 75},
+   {86, 76},
+   {88, 77},
+   {89, 116},
+   {91, 79},
+   {92, 80},
+   {95, 81},
+   {96, 82},
+   {97, 83},
+   {101, 84},
+   {103, 85},
+   {104, 86},
+   {115, 90},
+   {116, 91},
+   {117, 92},
+   {118, 93},
+   {119, 94},
+   {120, 95},
+   {121, 96},
+   {122, 97},
+   {123, 98},
+   {124, 99},
+   {125, 100},
+   {127, 102},
+   {128, 103},
+   {129, 104},
+   {130, 105},
+   {132, 106},
+   {133, 107},
+   {145, 108},
+};
+
 static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
.pins = sdm845_pins,
.npins = ARRAY_SIZE(sdm845_pins),
@@ -1290,6 +1368,9 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = 
{
.groups = sdm845_groups,
.ngroups = ARRAY_SIZE(sdm845_groups),
.ngpios = 151,
+   .wakeirq_map = sdm845_pdc_map,
+   .nwakeirq_map = ARRAY_SIZE(sdm845_pdc_map),
+
 };
 
 static const struct msm_pinctrl_soc_data sdm845_acpi_pinctrl = {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 12/14] arm64: dts: qcom: add PDC interrupt controller for SDM845

2019-08-29 Thread Lina Iyer
Add PDC interrupt controller device bindings for SDM845.

Signed-off-by: Lina Iyer 
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index be0022e09465..ffe28b3e41d8 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -2375,6 +2375,16 @@
#power-domain-cells = <1>;
};
 
+   pdc_intc: interrupt-controller@b22 {
+   compatible = "qcom,sdm845-pdc";
+   reg = <0 0x0b22 0 0x3>, <0x179900f0 0x60>;
+   qcom,pdc-ranges = <0 480 94>, <94 609 15>, <115 630 7>;
+   #interrupt-cells = <2>;
+   interrupt-parent = <>;
+   interrupt-controller;
+   qcom,scm-spi-cfg;
+   };
+
pdc_reset: reset-controller@b2e {
compatible = "qcom,sdm845-pdc-global";
reg = <0 0x0b2e 0 0x2>;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH RFC 02/14] drivers: irqchip: pdc: Do not toggle IRQ_ENABLE during mask/unmask

2019-08-29 Thread Lina Iyer
When an interrupt is to be serviced, the convention is to mask the
interrupt at the chip and unmask after servicing the interrupt. Enabling
and disabling the interrupt at the PDC irqchip causes an interrupt storm
due to the way dual edge interrupts are handled in hardware.

Skip configuring the PDC when the IRQ is masked and unmasked, instead
use the irq_enable/irq_disable callbacks to toggle the IRQ_ENABLE
register at the PDC. The PDC's IRQ_ENABLE register is only used during
the monitoring mode when the system is asleep and is not needed for
active mode detection.

Signed-off-by: Lina Iyer 
---
 drivers/irqchip/qcom-pdc.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index faa7d61b9d6c..338fae604af5 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -63,15 +63,25 @@ static void pdc_enable_intr(struct irq_data *d, bool on)
raw_spin_unlock(_lock);
 }
 
-static void qcom_pdc_gic_mask(struct irq_data *d)
+static void qcom_pdc_gic_disable(struct irq_data *d)
 {
pdc_enable_intr(d, false);
+   irq_chip_disable_parent(d);
+}
+
+static void qcom_pdc_gic_enable(struct irq_data *d)
+{
+   pdc_enable_intr(d, true);
+   irq_chip_enable_parent(d);
+}
+
+static void qcom_pdc_gic_mask(struct irq_data *d)
+{
irq_chip_mask_parent(d);
 }
 
 static void qcom_pdc_gic_unmask(struct irq_data *d)
 {
-   pdc_enable_intr(d, true);
irq_chip_unmask_parent(d);
 }
 
@@ -148,6 +158,8 @@ static struct irq_chip qcom_pdc_gic_chip = {
.irq_eoi= irq_chip_eoi_parent,
.irq_mask   = qcom_pdc_gic_mask,
.irq_unmask = qcom_pdc_gic_unmask,
+   .irq_disable= qcom_pdc_gic_disable,
+   .irq_enable = qcom_pdc_gic_enable,
.irq_retrigger  = irq_chip_retrigger_hierarchy,
.irq_set_type   = qcom_pdc_gic_set_type,
.flags  = IRQCHIP_MASK_ON_SUSPEND |
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH V2 2/4] drivers: qcom: rpmh-rsc: avoid locking in the interrupt handler

2019-07-30 Thread Lina Iyer

On Mon, Jul 29 2019 at 14:56 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-29 12:01:39)

On Thu, Jul 25 2019 at 09:44 -0600, Doug Anderson wrote:
>On Thu, Jul 25, 2019 at 8:18 AM Lina Iyer  wrote:
>>
>> On Wed, Jul 24 2019 at 17:28 -0600, Doug Anderson wrote:
>> >
>> >Jumping in without reading all the context, but I saw this fly by and
>> >it seemed odd.  If I'm way off base then please ignore...
>> >
>> >Can you give more details?  Why are these drivers in atomic contexts?
>> >If they are in atomic contexts because they are running in the context
>> >of an interrupt then your next patch in the series isn't so correct.
>> >
>> >Also: when people submit requests in atomic context are they always
>> >submitting an asynchronous request?  In that case we could
>> >(presumably) just use a spinlock to protect the queue of async
>> >requests and a mutex for everything else?
>> Yes, drivers only make async requests in interrupt contexts.
>
>So correct me if I'm off base, but you're saying that drivers make
>requests in interrupt contexts even after your whole series and that's
>why you're using spinlocks instead of mutexes.  ...but then in patch
>#3 in your series you say:
>
>> Switch over from using _irqsave/_irqrestore variants since we no longer
>> race with a lock from the interrupt handler.
>
>Those seem like contradictions.  What happens if someone is holding
>the lock, then an interrupt fires, then the interrupt routine wants to
>do an async request.  Boom, right?
>
The interrupt routine is handled by the driver and only completes the
waiting object (for sync requests). No other requests can be made from
our interrupt handler.


The question is more if an interrupt handler for some consumer driver
can call into this code and make an async request. Is that possible? If
so, the concern is that the driver's interrupt handler can run and try
to grab the lock on a CPU that already holds the lock in a non-irq
disabled context. This would lead to a deadlock while the CPU servicing
the interrupt waits for the lock held by another task that's been
interrupted.


Hmm.. this patch will cause that issue, since we remove the irqsave
aspects of the locking. Let me give that a thought.


>> They cannot
>> use the sync variants. The async and sync variants are streamlined into
>> the same code path. Hence the use of spinlocks instead of mutexes
>> through the critical path.
>
>I will perhaps defer to Stephen who was the one thinking that a mutex
>would be a big win here.  ...but if a mutex truly is a big win then it
>doesn't seem like it'd be that hard to have a linked list (protected
>by a spinlock) and then some type of async worker that:
>
>1. Grab the spinlock, pops one element off the linked list, release the 
spinlock
>2. Grab the mutex, send the one element, release the mutex
This would be a problem when the request is made from an irq handler. We
want to keep things simple and quick.



Is the problem that you want to use RPMh code from deep within the idle
thread? As part of some sort of CPU idle driver for qcom platforms? The
way this discussion is going it sounds like nothing is standing in the
way of a design that use a kthread to pump messages off a queue of
messages that is protected by a spinlock. The kthread would be woken up
by the sync or async write to continue to pump messages out until the
queue is empty.


While it is true that we want to use RPMH in cpuidle driver. Its just
that we had threads and all in our downstream 845 and it complicated the
whole setup a bit too much to our liking and did not help debug either.
I would rather not get all that back in the driver.

--Lina


Re: [PATCH V2 2/4] drivers: qcom: rpmh-rsc: avoid locking in the interrupt handler

2019-07-29 Thread Lina Iyer

On Thu, Jul 25 2019 at 09:44 -0600, Doug Anderson wrote:

Hi,

On Thu, Jul 25, 2019 at 8:18 AM Lina Iyer  wrote:


On Wed, Jul 24 2019 at 17:28 -0600, Doug Anderson wrote:
>Hi,
>
>On Wed, Jul 24, 2019 at 1:36 PM Lina Iyer  wrote:
>>
>> On Wed, Jul 24 2019 at 13:38 -0600, Stephen Boyd wrote:
>> >Quoting Lina Iyer (2019-07-24 07:52:51)
>> >> On Tue, Jul 23 2019 at 14:11 -0600, Stephen Boyd wrote:
>> >> >Quoting Lina Iyer (2019-07-22 14:53:38)
>> >> >> Avoid locking in the interrupt context to improve latency. Since we
>> >> >> don't lock in the interrupt context, it is possible that we now could
>> >> >> race with the DRV_CONTROL register that writes the enable register and
>> >> >> cleared by the interrupt handler. For fire-n-forget requests, the
>> >> >> interrupt may be raised as soon as the TCS is triggered and the IRQ
>> >> >> handler may clear the enable bit before the DRV_CONTROL is read back.
>> >> >>
>> >> >> Use the non-sync variant when enabling the TCS register to avoid 
reading
>> >> >> back a value that may been cleared because the interrupt handler ran
>> >> >> immediately after triggering the TCS.
>> >> >>
>> >> >> Signed-off-by: Lina Iyer 
>> >> >> ---
>> >> >
>> >> >I have to read this patch carefully. The commit text isn't convincing me
>> >> >that it is actually safe to make this change. It mostly talks about the
>> >> >performance improvements and how we need to fix __tcs_trigger(), which
>> >> >is good, but I was hoping to be convinced that not grabbing the lock
>> >> >here is safe.
>> >> >
>> >> >How do we ensure that drv->tcs_in_use is cleared before we call
>> >> >tcs_write() and try to look for a free bit? Isn't it possible that we'll
>> >> >get into a situation where the bitmap is all used up but the hardware
>> >> >has just received an interrupt and is going to clear out a bit and then
>> >> >an rpmh write fails with -EBUSY?
>> >> >
>> >> If we have a situation where there are no available free bits, we retry
>> >> and that is part of the function. Since we have only 2 TCSes avaialble
>> >> to write to the hardware and there could be multiple requests coming in,
>> >> it is a very common situation. We try and acquire the drv->lock and if
>> >> there are free TCS available and if available mark them busy and send
>> >> our requests. If there are none available, we keep retrying.
>> >>
>> >
>> >Ok. I wonder if we need some sort of barriers here too, like an
>> >smp_mb__after_atomic()? That way we can make sure that the write to
>> >clear the bit is seen by another CPU that could be spinning forever
>> >waiting for that bit to be cleared? Before this change the spinlock
>> >would be guaranteed to make these barriers for us, but now that doesn't
>> >seem to be the case. I really hope that this whole thing can be changed
>> >to be a mutex though, in which case we can use the bit_wait() API, etc.
>> >to put tasks to sleep while RPMh is processing things.
>> >
>> We have drivers that want to send requests in atomic contexts and
>> therefore mutex locks would not work.
>
>Jumping in without reading all the context, but I saw this fly by and
>it seemed odd.  If I'm way off base then please ignore...
>
>Can you give more details?  Why are these drivers in atomic contexts?
>If they are in atomic contexts because they are running in the context
>of an interrupt then your next patch in the series isn't so correct.
>
>Also: when people submit requests in atomic context are they always
>submitting an asynchronous request?  In that case we could
>(presumably) just use a spinlock to protect the queue of async
>requests and a mutex for everything else?
Yes, drivers only make async requests in interrupt contexts.


So correct me if I'm off base, but you're saying that drivers make
requests in interrupt contexts even after your whole series and that's
why you're using spinlocks instead of mutexes.  ...but then in patch
#3 in your series you say:


Switch over from using _irqsave/_irqrestore variants since we no longer
race with a lock from the interrupt handler.


Those seem like contradictions.  What happens if someone is holding
the lock, then an interrupt fires, then the interrupt routine wants to
do an async request.  Boom, right?


The interrupt routine is handled by the driver and only comple

Re: [PATCH V2 2/4] drivers: qcom: rpmh-rsc: avoid locking in the interrupt handler

2019-07-25 Thread Lina Iyer

On Wed, Jul 24 2019 at 17:28 -0600, Doug Anderson wrote:

Hi,

On Wed, Jul 24, 2019 at 1:36 PM Lina Iyer  wrote:


On Wed, Jul 24 2019 at 13:38 -0600, Stephen Boyd wrote:
>Quoting Lina Iyer (2019-07-24 07:52:51)
>> On Tue, Jul 23 2019 at 14:11 -0600, Stephen Boyd wrote:
>> >Quoting Lina Iyer (2019-07-22 14:53:38)
>> >> Avoid locking in the interrupt context to improve latency. Since we
>> >> don't lock in the interrupt context, it is possible that we now could
>> >> race with the DRV_CONTROL register that writes the enable register and
>> >> cleared by the interrupt handler. For fire-n-forget requests, the
>> >> interrupt may be raised as soon as the TCS is triggered and the IRQ
>> >> handler may clear the enable bit before the DRV_CONTROL is read back.
>> >>
>> >> Use the non-sync variant when enabling the TCS register to avoid reading
>> >> back a value that may been cleared because the interrupt handler ran
>> >> immediately after triggering the TCS.
>> >>
>> >> Signed-off-by: Lina Iyer 
>> >> ---
>> >
>> >I have to read this patch carefully. The commit text isn't convincing me
>> >that it is actually safe to make this change. It mostly talks about the
>> >performance improvements and how we need to fix __tcs_trigger(), which
>> >is good, but I was hoping to be convinced that not grabbing the lock
>> >here is safe.
>> >
>> >How do we ensure that drv->tcs_in_use is cleared before we call
>> >tcs_write() and try to look for a free bit? Isn't it possible that we'll
>> >get into a situation where the bitmap is all used up but the hardware
>> >has just received an interrupt and is going to clear out a bit and then
>> >an rpmh write fails with -EBUSY?
>> >
>> If we have a situation where there are no available free bits, we retry
>> and that is part of the function. Since we have only 2 TCSes avaialble
>> to write to the hardware and there could be multiple requests coming in,
>> it is a very common situation. We try and acquire the drv->lock and if
>> there are free TCS available and if available mark them busy and send
>> our requests. If there are none available, we keep retrying.
>>
>
>Ok. I wonder if we need some sort of barriers here too, like an
>smp_mb__after_atomic()? That way we can make sure that the write to
>clear the bit is seen by another CPU that could be spinning forever
>waiting for that bit to be cleared? Before this change the spinlock
>would be guaranteed to make these barriers for us, but now that doesn't
>seem to be the case. I really hope that this whole thing can be changed
>to be a mutex though, in which case we can use the bit_wait() API, etc.
>to put tasks to sleep while RPMh is processing things.
>
We have drivers that want to send requests in atomic contexts and
therefore mutex locks would not work.


Jumping in without reading all the context, but I saw this fly by and
it seemed odd.  If I'm way off base then please ignore...

Can you give more details?  Why are these drivers in atomic contexts?
If they are in atomic contexts because they are running in the context
of an interrupt then your next patch in the series isn't so correct.

Also: when people submit requests in atomic context are they always
submitting an asynchronous request?  In that case we could
(presumably) just use a spinlock to protect the queue of async
requests and a mutex for everything else?

Yes, drivers only make async requests in interrupt contexts. They cannot
use the sync variants. The async and sync variants are streamlined into
the same code path. Hence the use of spinlocks instead of mutexes
through the critical path.

--Lina



Re: [PATCH V2 2/4] drivers: qcom: rpmh-rsc: avoid locking in the interrupt handler

2019-07-24 Thread Lina Iyer

On Wed, Jul 24 2019 at 13:38 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-24 07:52:51)

On Tue, Jul 23 2019 at 14:11 -0600, Stephen Boyd wrote:
>Quoting Lina Iyer (2019-07-22 14:53:38)
>> Avoid locking in the interrupt context to improve latency. Since we
>> don't lock in the interrupt context, it is possible that we now could
>> race with the DRV_CONTROL register that writes the enable register and
>> cleared by the interrupt handler. For fire-n-forget requests, the
>> interrupt may be raised as soon as the TCS is triggered and the IRQ
>> handler may clear the enable bit before the DRV_CONTROL is read back.
>>
>> Use the non-sync variant when enabling the TCS register to avoid reading
>> back a value that may been cleared because the interrupt handler ran
>> immediately after triggering the TCS.
>>
>> Signed-off-by: Lina Iyer 
>> ---
>
>I have to read this patch carefully. The commit text isn't convincing me
>that it is actually safe to make this change. It mostly talks about the
>performance improvements and how we need to fix __tcs_trigger(), which
>is good, but I was hoping to be convinced that not grabbing the lock
>here is safe.
>
>How do we ensure that drv->tcs_in_use is cleared before we call
>tcs_write() and try to look for a free bit? Isn't it possible that we'll
>get into a situation where the bitmap is all used up but the hardware
>has just received an interrupt and is going to clear out a bit and then
>an rpmh write fails with -EBUSY?
>
If we have a situation where there are no available free bits, we retry
and that is part of the function. Since we have only 2 TCSes avaialble
to write to the hardware and there could be multiple requests coming in,
it is a very common situation. We try and acquire the drv->lock and if
there are free TCS available and if available mark them busy and send
our requests. If there are none available, we keep retrying.



Ok. I wonder if we need some sort of barriers here too, like an
smp_mb__after_atomic()? That way we can make sure that the write to
clear the bit is seen by another CPU that could be spinning forever
waiting for that bit to be cleared? Before this change the spinlock
would be guaranteed to make these barriers for us, but now that doesn't
seem to be the case. I really hope that this whole thing can be changed
to be a mutex though, in which case we can use the bit_wait() API, etc.
to put tasks to sleep while RPMh is processing things.


We have drivers that want to send requests in atomic contexts and
therefore mutex locks would not work.

--Lina



Re: [PATCH V2 1/4] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-24 Thread Lina Iyer

On Wed, Jul 24 2019 at 12:32 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-24 07:54:52)

On Tue, Jul 23 2019 at 14:19 -0600, Stephen Boyd wrote:
>Quoting Lina Iyer (2019-07-23 12:21:59)
>> On Tue, Jul 23 2019 at 12:22 -0600, Stephen Boyd wrote:
>> >Can you keep irq saving and restoring in this patch and then remove that
>> >in the next patch with reasoning? It probably isn't safe if the lock is
>> >taken in interrupt context anyway.
>> >
>> Yes, the drv->lock should have been irqsave/irqrestore, but it hasn't
>> been changed by this patch.
>
>It needs to be changed to maintain the irqsaving/restoring of the code.
>
May be I should club this with the following patch. Instead of adding
irqsave and restore to drv->lock and then remvoing them again in the
following patch.



I suspect that gets us back to v1 of this patch series? I'd prefer you
just keep the save/restore of irqs in this patch and then remove them
later. Or if the order can be the other way, where we remove grabbing
the lock in irq context comes first and then consolidate the locks into
one it might work.


Patches 1 and 3 need not be bundled. We can keep them separate to help
understand the change better.
This patch order - #2, #1, #3, #4 would work.

--Lina



Re: [PATCH V2 1/4] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-24 Thread Lina Iyer

On Tue, Jul 23 2019 at 14:19 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-23 12:21:59)

On Tue, Jul 23 2019 at 12:22 -0600, Stephen Boyd wrote:
>Quoting Lina Iyer (2019-07-22 14:53:37)
>> From: "Raju P.L.S.S.S.N" 
>>
>> The tcs->lock was introduced to serialize access with in TCS group. But,
>> drv->lock is still needed to synchronize core aspects of the
>> communication. This puts the drv->lock in the critical and high latency
>> path of sending a request. drv->lock provides the all necessary
>> synchronization. So remove locking around TCS group and simply use the
>> drv->lock instead.
>
>This doesn't talk about removing the irq saving and restoring though.
You mean for drv->lock? It was not an _irqsave/_irqrestore anyways and
we were only removing the tcs->lock.


Yes drv->lock wasn't an irqsave/restore variant because it was a
spinlock inside of an obviously already irqsaved region of code because
the tcs->lock was outside the drv->lock and that was saving the irq
flags.


Oh, right.


>Can you keep irq saving and restoring in this patch and then remove that
>in the next patch with reasoning? It probably isn't safe if the lock is
>taken in interrupt context anyway.
>
Yes, the drv->lock should have been irqsave/irqrestore, but it hasn't
been changed by this patch.


It needs to be changed to maintain the irqsaving/restoring of the code.


May be I should club this with the following patch. Instead of adding
irqsave and restore to drv->lock and then remvoing them again in the
following patch.


>> @@ -349,41 +349,35 @@ static int tcs_write(struct rsc_drv *drv, const struct 
tcs_request *msg)
>>  {
>> struct tcs_group *tcs;
>> int tcs_id;
>> -   unsigned long flags;
>> int ret;
>>
>> tcs = get_tcs_for_msg(drv, msg);
>> if (IS_ERR(tcs))
>> return PTR_ERR(tcs);
>>
>> -   spin_lock_irqsave(>lock, flags);
>> spin_lock(>lock);
>> /*
>>  * The h/w does not like if we send a request to the same address,
>>  * when one is already in-flight or being processed.
>>  */
>> ret = check_for_req_inflight(drv, tcs, msg);
>> -   if (ret) {
>> -   spin_unlock(>lock);
>> +   if (ret)
>> goto done_write;
>> -   }
>>
>> tcs_id = find_free_tcs(tcs);
>> if (tcs_id < 0) {
>> ret = tcs_id;
>> -   spin_unlock(>lock);
>> goto done_write;
>> }
>>
>> tcs->req[tcs_id - tcs->offset] = msg;
>> set_bit(tcs_id, drv->tcs_in_use);
>> -   spin_unlock(>lock);
>>
>> __tcs_buffer_write(drv, tcs_id, 0, msg);
>> __tcs_trigger(drv, tcs_id);
>>
>>  done_write:
>> -   spin_unlock_irqrestore(>lock, flags);
>> +   spin_unlock(>lock);
>> return ret;
>>  }
>>
>> @@ -481,19 +475,18 @@ static int tcs_ctrl_write(struct rsc_drv *drv, const 
struct tcs_request *msg)
>>  {
>> struct tcs_group *tcs;
>> int tcs_id = 0, cmd_id = 0;
>> -   unsigned long flags;
>> int ret;
>>
>> tcs = get_tcs_for_msg(drv, msg);
>> if (IS_ERR(tcs))
>> return PTR_ERR(tcs);
>>
>> -   spin_lock_irqsave(>lock, flags);
>> +   spin_lock(>lock);
>> /* find the TCS id and the command in the TCS to write to */
>> ret = find_slots(tcs, msg, _id, _id);
>> if (!ret)
>> __tcs_buffer_write(drv, tcs_id, cmd_id, msg);
>> -   spin_unlock_irqrestore(>lock, flags);
>> +   spin_unlock(>lock);
>>
>
>These ones, just leave them doing the irq save restore for now?
>
drv->lock ??



Yes, it should have irq save/restore still.



Re: [PATCH V2 2/4] drivers: qcom: rpmh-rsc: avoid locking in the interrupt handler

2019-07-24 Thread Lina Iyer

On Tue, Jul 23 2019 at 14:11 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-22 14:53:38)

Avoid locking in the interrupt context to improve latency. Since we
don't lock in the interrupt context, it is possible that we now could
race with the DRV_CONTROL register that writes the enable register and
cleared by the interrupt handler. For fire-n-forget requests, the
interrupt may be raised as soon as the TCS is triggered and the IRQ
handler may clear the enable bit before the DRV_CONTROL is read back.

Use the non-sync variant when enabling the TCS register to avoid reading
back a value that may been cleared because the interrupt handler ran
immediately after triggering the TCS.

Signed-off-by: Lina Iyer 
---


I have to read this patch carefully. The commit text isn't convincing me
that it is actually safe to make this change. It mostly talks about the
performance improvements and how we need to fix __tcs_trigger(), which
is good, but I was hoping to be convinced that not grabbing the lock
here is safe.

How do we ensure that drv->tcs_in_use is cleared before we call
tcs_write() and try to look for a free bit? Isn't it possible that we'll
get into a situation where the bitmap is all used up but the hardware
has just received an interrupt and is going to clear out a bit and then
an rpmh write fails with -EBUSY?


If we have a situation where there are no available free bits, we retry
and that is part of the function. Since we have only 2 TCSes avaialble
to write to the hardware and there could be multiple requests coming in,
it is a very common situation. We try and acquire the drv->lock and if
there are free TCS available and if available mark them busy and send
our requests. If there are none available, we keep retrying.


 drivers/soc/qcom/rpmh-rsc.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 5ede8d6de3ad..694ba881624e 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -242,9 +242,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
-   spin_lock(>lock);
clear_bit(i, drv->tcs_in_use);
-   spin_unlock(>lock);
if (req)
rpmh_tx_done(req, err);
}
@@ -304,7 +302,7 @@ static void __tcs_trigger(struct rsc_drv *drv, int tcs_id)
enable = TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
-   write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+   write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
 }

 static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,


Re: [PATCH V2 1/4] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-23 Thread Lina Iyer

On Tue, Jul 23 2019 at 12:22 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-22 14:53:37)

From: "Raju P.L.S.S.S.N" 

The tcs->lock was introduced to serialize access with in TCS group. But,
drv->lock is still needed to synchronize core aspects of the
communication. This puts the drv->lock in the critical and high latency
path of sending a request. drv->lock provides the all necessary
synchronization. So remove locking around TCS group and simply use the
drv->lock instead.


This doesn't talk about removing the irq saving and restoring though.

You mean for drv->lock? It was not an _irqsave/_irqrestore anyways and
we were only removing the tcs->lock.


Can you keep irq saving and restoring in this patch and then remove that
in the next patch with reasoning? It probably isn't safe if the lock is
taken in interrupt context anyway.


Yes, the drv->lock should have been irqsave/irqrestore, but it hasn't
been changed by this patch.



Signed-off-by: Raju P.L.S.S.S.N 
[ilina: split patch into multiple files, update commit text]
Signed-off-by: Lina Iyer 



diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index a767991c..969d5030860e 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index e278fc11fe5c..5ede8d6de3ad 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -106,26 +106,26 @@ static int tcs_invalidate(struct rsc_drv *drv, int type)
 {
int m;
struct tcs_group *tcs;
+   int ret = 0;

tcs = get_tcs_of_type(drv, type);

-   spin_lock(>lock);
-   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) {
-   spin_unlock(>lock);
-   return 0;
-   }
+   spin_lock(>lock);
+   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS))
+   goto done_invalidate;

for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
if (!tcs_is_free(drv, m)) {
-   spin_unlock(>lock);
-   return -EAGAIN;
+   ret = -EAGAIN;
+   goto done_invalidate;
}
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
}
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
-   spin_unlock(>lock);

+done_invalidate:
+   spin_unlock(>lock);
return 0;


return ret now?


Yes, will do.

 }

@@ -349,41 +349,35 @@ static int tcs_write(struct rsc_drv *drv, const struct 
tcs_request *msg)
 {
struct tcs_group *tcs;
int tcs_id;
-   unsigned long flags;
int ret;

tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);

-   spin_lock_irqsave(>lock, flags);
spin_lock(>lock);
/*
 * The h/w does not like if we send a request to the same address,
 * when one is already in-flight or being processed.
 */
ret = check_for_req_inflight(drv, tcs, msg);
-   if (ret) {
-   spin_unlock(>lock);
+   if (ret)
goto done_write;
-   }

tcs_id = find_free_tcs(tcs);
if (tcs_id < 0) {
ret = tcs_id;
-   spin_unlock(>lock);
goto done_write;
}

tcs->req[tcs_id - tcs->offset] = msg;
set_bit(tcs_id, drv->tcs_in_use);
-   spin_unlock(>lock);

__tcs_buffer_write(drv, tcs_id, 0, msg);
__tcs_trigger(drv, tcs_id);

 done_write:
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock(>lock);
return ret;
 }

@@ -481,19 +475,18 @@ static int tcs_ctrl_write(struct rsc_drv *drv, const 
struct tcs_request *msg)
 {
struct tcs_group *tcs;
int tcs_id = 0, cmd_id = 0;
-   unsigned long flags;
int ret;

tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);

-   spin_lock_irqsave(>lock, flags);
+   spin_lock(>lock);
/* find the TCS id and the command in the TCS to write to */
ret = find_slots(tcs, msg, _id, _id);
if (!ret)
__tcs_buffer_write(drv, tcs_id, cmd_id, msg);
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock(>lock);



These ones, just leave them doing the irq save restore for now?


drv->lock ??

--Lina



[PATCH V2 3/4] drivers: qcom: rpmh: switch over from spinlock irq variants

2019-07-22 Thread Lina Iyer
From: "Raju P.L.S.S.S.N" 

Switch over from using _irqsave/_irqrestore variants since we no longer
race with a lock from the interrupt handler. While we are at it, rename
the cache_lock to just lock to allow use of the lock to synchronize
controller access.

Signed-off-by: Raju P.L.S.S.S.N 
Signed-off-by: Lina Iyer 
---
 drivers/soc/qcom/rpmh-internal.h |  4 ++--
 drivers/soc/qcom/rpmh-rsc.c  |  2 +-
 drivers/soc/qcom/rpmh.c  | 21 -
 3 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index 969d5030860e..93d59db435bb 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -67,13 +67,13 @@ struct rpmh_request {
  * struct rpmh_ctrlr: our representation of the controller
  *
  * @cache: the list of cached requests
- * @cache_lock: synchronize access to the cache data
+ * @lock: synchronize access to the controller data
  * @dirty: was the cache updated since flush
  * @batch_cache: Cache sleep and wake requests sent as batch
  */
 struct rpmh_ctrlr {
struct list_head cache;
-   spinlock_t cache_lock;
+   spinlock_t lock;
bool dirty;
struct list_head batch_cache;
 };
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 694ba881624e..add5e84751c9 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -656,7 +656,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
/* Enable the active TCS to send requests immediately */
write_tcs_reg(drv, RSC_DRV_IRQ_ENABLE, 0, drv->tcs[ACTIVE_TCS].mask);
 
-   spin_lock_init(>client.cache_lock);
+   spin_lock_init(>client.lock);
INIT_LIST_HEAD(>client.cache);
INIT_LIST_HEAD(>client.batch_cache);
 
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 035091fd44b8..d6fb254a4b57 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -118,9 +118,8 @@ static struct cache_req *cache_rpm_request(struct 
rpmh_ctrlr *ctrlr,
   struct tcs_cmd *cmd)
 {
struct cache_req *req;
-   unsigned long flags;
 
-   spin_lock_irqsave(>cache_lock, flags);
+   spin_lock(>lock);
req = __find_req(ctrlr, cmd->addr);
if (req)
goto existing;
@@ -154,7 +153,7 @@ static struct cache_req *cache_rpm_request(struct 
rpmh_ctrlr *ctrlr,
 
ctrlr->dirty = true;
 unlock:
-   spin_unlock_irqrestore(>cache_lock, flags);
+   spin_unlock(>lock);
 
return req;
 }
@@ -283,23 +282,20 @@ EXPORT_SYMBOL(rpmh_write);
 
 static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
 {
-   unsigned long flags;
-
-   spin_lock_irqsave(>cache_lock, flags);
+   spin_lock(>lock);
list_add_tail(>list, >batch_cache);
-   spin_unlock_irqrestore(>cache_lock, flags);
+   spin_unlock(>lock);
 }
 
 static int flush_batch(struct rpmh_ctrlr *ctrlr)
 {
struct batch_cache_req *req;
const struct rpmh_request *rpm_msg;
-   unsigned long flags;
int ret = 0;
int i;
 
/* Send Sleep/Wake requests to the controller, expect no response */
-   spin_lock_irqsave(>cache_lock, flags);
+   spin_lock(>lock);
list_for_each_entry(req, >batch_cache, list) {
for (i = 0; i < req->count; i++) {
rpm_msg = req->rpm_msgs + i;
@@ -309,7 +305,7 @@ static int flush_batch(struct rpmh_ctrlr *ctrlr)
break;
}
}
-   spin_unlock_irqrestore(>cache_lock, flags);
+   spin_unlock(>lock);
 
return ret;
 }
@@ -317,13 +313,12 @@ static int flush_batch(struct rpmh_ctrlr *ctrlr)
 static void invalidate_batch(struct rpmh_ctrlr *ctrlr)
 {
struct batch_cache_req *req, *tmp;
-   unsigned long flags;
 
-   spin_lock_irqsave(>cache_lock, flags);
+   spin_lock(>lock);
list_for_each_entry_safe(req, tmp, >batch_cache, list)
kfree(req);
INIT_LIST_HEAD(>batch_cache);
-   spin_unlock_irqrestore(>cache_lock, flags);
+   spin_unlock(>lock);
 }
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH V2 1/4] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-22 Thread Lina Iyer
From: "Raju P.L.S.S.S.N" 

The tcs->lock was introduced to serialize access with in TCS group. But,
drv->lock is still needed to synchronize core aspects of the
communication. This puts the drv->lock in the critical and high latency
path of sending a request. drv->lock provides the all necessary
synchronization. So remove locking around TCS group and simply use the
drv->lock instead.

Signed-off-by: Raju P.L.S.S.S.N 
[ilina: split patch into multiple files, update commit text]
Signed-off-by: Lina Iyer 
---
Changes in v2:
- Split the patches into multiple
- Optimzation to remove reundant TCS access
- Split the rpmh library changes into its own patch
- Remove locks in IRQ handler
- Update commit text
- Remove fixes in commit text
---
 drivers/soc/qcom/rpmh-internal.h |  2 --
 drivers/soc/qcom/rpmh-rsc.c  | 32 
 2 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index a767991c..969d5030860e 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -28,7 +28,6 @@ struct rsc_drv;
  * @offset:start of the TCS group relative to the TCSes in the RSC
  * @num_tcs:   number of TCSes in this type
  * @ncpt:  number of commands in each TCS
- * @lock:  lock for synchronizing this TCS writes
  * @req:   requests that are sent from the TCS
  * @cmd_cache: flattened cache of cmds in sleep/wake TCS
  * @slots: indicates which of @cmd_addr are occupied
@@ -40,7 +39,6 @@ struct tcs_group {
u32 offset;
int num_tcs;
int ncpt;
-   spinlock_t lock;
const struct tcs_request *req[MAX_TCS_PER_TYPE];
u32 *cmd_cache;
DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index e278fc11fe5c..5ede8d6de3ad 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -106,26 +106,26 @@ static int tcs_invalidate(struct rsc_drv *drv, int type)
 {
int m;
struct tcs_group *tcs;
+   int ret = 0;
 
tcs = get_tcs_of_type(drv, type);
 
-   spin_lock(>lock);
-   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) {
-   spin_unlock(>lock);
-   return 0;
-   }
+   spin_lock(>lock);
+   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS))
+   goto done_invalidate;
 
for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
if (!tcs_is_free(drv, m)) {
-   spin_unlock(>lock);
-   return -EAGAIN;
+   ret = -EAGAIN;
+   goto done_invalidate;
}
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
}
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
-   spin_unlock(>lock);
 
+done_invalidate:
+   spin_unlock(>lock);
return 0;
 }
 
@@ -349,41 +349,35 @@ static int tcs_write(struct rsc_drv *drv, const struct 
tcs_request *msg)
 {
struct tcs_group *tcs;
int tcs_id;
-   unsigned long flags;
int ret;
 
tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
 
-   spin_lock_irqsave(>lock, flags);
spin_lock(>lock);
/*
 * The h/w does not like if we send a request to the same address,
 * when one is already in-flight or being processed.
 */
ret = check_for_req_inflight(drv, tcs, msg);
-   if (ret) {
-   spin_unlock(>lock);
+   if (ret)
goto done_write;
-   }
 
tcs_id = find_free_tcs(tcs);
if (tcs_id < 0) {
ret = tcs_id;
-   spin_unlock(>lock);
goto done_write;
}
 
tcs->req[tcs_id - tcs->offset] = msg;
set_bit(tcs_id, drv->tcs_in_use);
-   spin_unlock(>lock);
 
__tcs_buffer_write(drv, tcs_id, 0, msg);
__tcs_trigger(drv, tcs_id);
 
 done_write:
-   spin_unlock_irqrestore(>lock, flags);
+   spin_unlock(>lock);
return ret;
 }
 
@@ -481,19 +475,18 @@ static int tcs_ctrl_write(struct rsc_drv *drv, const 
struct tcs_request *msg)
 {
struct tcs_group *tcs;
int tcs_id = 0, cmd_id = 0;
-   unsigned long flags;
int ret;
 
tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
 
-   spin_lock_irqsave(>lock, flags);
+   spin_lock(>lock);
/* find the TCS id and the command in the TCS to write to */
ret = find_slots(tcs, msg, _id, _id);
if (!ret)
__tcs_buffer_write(drv, tcs_id, cmd_id, msg);
-   spin_unlock_irqrestore(>lock, flags);
+ 

[PATCH V2 4/4] drivers: qcom: rpmh-rsc: remove redundant register access

2019-07-22 Thread Lina Iyer
Since drv->tcs_in_use is updated when the DRV_STATUS is updated, we
could simply use the former to determine if the TCS is idle or not.
Therefore, remove redundant TCS register read.

Signed-off-by: Lina Iyer 
---
 drivers/soc/qcom/rpmh-rsc.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index add5e84751c9..b04cd2d2910c 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -93,8 +93,7 @@ static void write_tcs_reg_sync(struct rsc_drv *drv, int reg, 
int tcs_id,
 
 static bool tcs_is_free(struct rsc_drv *drv, int tcs_id)
 {
-   return !test_bit(tcs_id, drv->tcs_in_use) &&
-  read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id, 0);
+   return !test_bit(tcs_id, drv->tcs_in_use);
 }
 
 static struct tcs_group *get_tcs_of_type(struct rsc_drv *drv, int type)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH V2 2/4] drivers: qcom: rpmh-rsc: avoid locking in the interrupt handler

2019-07-22 Thread Lina Iyer
Avoid locking in the interrupt context to improve latency. Since we
don't lock in the interrupt context, it is possible that we now could
race with the DRV_CONTROL register that writes the enable register and
cleared by the interrupt handler. For fire-n-forget requests, the
interrupt may be raised as soon as the TCS is triggered and the IRQ
handler may clear the enable bit before the DRV_CONTROL is read back.

Use the non-sync variant when enabling the TCS register to avoid reading
back a value that may been cleared because the interrupt handler ran
immediately after triggering the TCS.

Signed-off-by: Lina Iyer 
---
 drivers/soc/qcom/rpmh-rsc.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 5ede8d6de3ad..694ba881624e 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -242,9 +242,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
-   spin_lock(>lock);
clear_bit(i, drv->tcs_in_use);
-   spin_unlock(>lock);
if (req)
rpmh_tx_done(req, err);
}
@@ -304,7 +302,7 @@ static void __tcs_trigger(struct rsc_drv *drv, int tcs_id)
enable = TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
-   write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+   write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
 }
 
 static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH 1/2] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-22 Thread Lina Iyer

On Mon, Jul 22 2019 at 12:18 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-22 09:20:03)

On Fri, Jul 19 2019 at 12:20 -0600, Stephen Boyd wrote:
>Quoting Lina Iyer (2019-07-01 08:29:06)
>> From: "Raju P.L.S.S.S.N" 
>>
>> tcs->lock was introduced to serialize access with in TCS group. But
>> even without tcs->lock, drv->lock is serving the same purpose. So
>> use a single drv->lock.
>
>Isn't the downside now that we're going to be serializing access to the
>different TCSes when two are being written in parallel or waited on? I
>thought that was the whole point of splitting the lock into a TCS lock
>and a general "driver" lock that protects the global driver state vs.
>the specific TCS state.
>
Yes but we were holding the drv->lock as well as tcs->lock for the most
critical of the path anyways (writing to TCS). The added complexity
doesn't seem to help reduce the latency that it expected to reduce.


Ok. That sort of information should be in the commit text to explain why
it's not helping with reducing the latency or throughput of the API.


Will add.

--Lina


Re: [PATCH 1/2] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-22 Thread Lina Iyer

On Fri, Jul 19 2019 at 12:20 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-01 08:29:06)

From: "Raju P.L.S.S.S.N" 

tcs->lock was introduced to serialize access with in TCS group. But
even without tcs->lock, drv->lock is serving the same purpose. So
use a single drv->lock.


Isn't the downside now that we're going to be serializing access to the
different TCSes when two are being written in parallel or waited on? I
thought that was the whole point of splitting the lock into a TCS lock
and a general "driver" lock that protects the global driver state vs.
the specific TCS state.


Yes but we were holding the drv->lock as well as tcs->lock for the most
critical of the path anyways (writing to TCS). The added complexity
doesn't seem to help reduce the latency that it expected to reduce.


Other optimizations include -
 - Remove locking around clear_bit() in IRQ handler. clear_bit() is
   atomic.
 - Remove redundant read of TCS registers.
 - Use spin_lock instead of _irq variants as the locks are not held
   in interrupt context.


Can you please split this patch up into 3 or 4 different patches? I'm
not sure why any of these patches are marked with Fixes either. It's an
optimization patch, not a fix patch, unless the optimization is really
large somehow?


Okay. I will try that.


Fixes: 658628 ("drivers: qcom: rpmh-rsc: add RPMH controller for QCOM
SoCs")
Signed-off-by: Raju P.L.S.S.S.N 
Signed-off-by: Lina Iyer 
---
 drivers/soc/qcom/rpmh-internal.h |  2 --
 drivers/soc/qcom/rpmh-rsc.c  | 37 +++-
 drivers/soc/qcom/rpmh.c  | 20 +++--
 3 files changed, 21 insertions(+), 38 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index a767991c..969d5030860e 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index e278fc11fe5c..92461311aef3 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -93,8 +93,7 @@ static void write_tcs_reg_sync(struct rsc_drv *drv, int reg, 
int tcs_id,

 static bool tcs_is_free(struct rsc_drv *drv, int tcs_id)
 {
-   return !test_bit(tcs_id, drv->tcs_in_use) &&
-  read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id, 0);
+   return !test_bit(tcs_id, drv->tcs_in_use);


This can be a diffedjusted rent patch. Why is reading the tcs register
redundant? Please put that information in the commit text.


The tcs_in_use, is adjusted along with the DRV_STS and reading the
tcs_in_use should be enough.

Thanks for your review Stephen.

--Lina


Re: [PATCH 2/2] drivers: qcom: rpmh-rsc: fix read back of trigger register

2019-07-22 Thread Lina Iyer

On Fri, Jul 19 2019 at 12:22 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-07-01 08:29:07)

When triggering a TCS to send its contents, reading back the trigger
value may return an incorrect value. That is because, writing the
trigger may raise an interrupt which could be handled immediately and
the trigger value could be reset in the interrupt handler. By doing a
read back we may end up spinning waiting for the value we wrote.


Doesn't this need to be squashed into the patch that gets rid of the
irqs disabled state of this code? It sounds an awful lot like this
problem only happens now because the previous patch removed the
irqsave/irqrestore code around this function.



True. Could be rolled into that fix.

--Lina


Re: [PATCH 09/18] drivers: firmware: psci: Add support for PM domains using genpd

2019-07-18 Thread Lina Iyer

On Thu, Jul 18 2019 at 07:19 -0600, Sudeep Holla wrote:

On Thu, Jul 18, 2019 at 01:04:03PM +0200, Ulf Hansson wrote:

On Tue, 16 Jul 2019 at 17:05, Sudeep Holla  wrote:
>
> On Mon, May 13, 2019 at 09:22:51PM +0200, Ulf Hansson wrote:
> > When the hierarchical CPU topology layout is used in DT, we need to setup
> > the corresponding PM domain data structures, as to allow a CPU and a group
> > of CPUs to be power managed accordingly. Let's enable this by deploying
> > support through the genpd interface.
> >
> > Additionally, when the OS initiated mode is supported by the PSCI FW, let's
> > also parse the domain idle states DT bindings as to make genpd responsible
> > for the state selection, when the states are compatible with
> > "domain-idle-state". Otherwise, when only Platform Coordinated mode is
> > supported, we rely solely on the state selection to be managed through the
> > regular cpuidle framework.
> >
> > If the initialization of the PM domain data structures succeeds and the OS
> > initiated mode is supported, we try to switch to it. In case it fails,
> > let's fall back into a degraded mode, rather than bailing out and returning
> > an error code.
> >
> > Due to that the OS initiated mode may become enabled, we need to adjust to
> > maintain backwards compatibility for a kernel started through a kexec call.
> > Do this by explicitly switch to Platform Coordinated mode during boot.
> >
> > Finally, the actual initialization of the PM domain data structures, is
> > done via calling the new shared function, psci_dt_init_pm_domains().
> > However, this is implemented by subsequent changes.
> >
> > Co-developed-by: Lina Iyer 
> > Signed-off-by: Lina Iyer 
> > Signed-off-by: Ulf Hansson 
> > ---
> >
> > Changes:
> >   - Simplify code setting domain_state at power off.
> >   - Use the genpd ->free_state() callback to manage freeing of states.
> >   - Fixup a bogus while loop.
> >
> > ---
> >  drivers/firmware/psci/Makefile |   2 +-
> >  drivers/firmware/psci/psci.c   |   7 +-
> >  drivers/firmware/psci/psci.h   |   5 +
> >  drivers/firmware/psci/psci_pm_domain.c | 268 +
> >  4 files changed, 280 insertions(+), 2 deletions(-)
> >  create mode 100644 drivers/firmware/psci/psci_pm_domain.c
> >
>
> [...]
>
> >  #endif /* __PSCI_H */
> > diff --git a/drivers/firmware/psci/psci_pm_domain.c 
b/drivers/firmware/psci/psci_pm_domain.c
> > new file mode 100644
> > index ..3c6ca846caf4
> > --- /dev/null
> > +++ b/drivers/firmware/psci/psci_pm_domain.c
> > @@ -0,0 +1,268 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * PM domains for CPUs via genpd - managed by PSCI.
> > + *
> > + * Copyright (C) 2019 Linaro Ltd.
> > + * Author: Ulf Hansson 
> > + *
> > + */
> > +
>
> [...]
>
> > +static int psci_pd_power_off(struct generic_pm_domain *pd)
> > +{
> > + struct genpd_power_state *state = >states[pd->state_idx];
> > + u32 *pd_state;
> > +
> > + /* If we have failed to enable OSI mode, then abort power off. */
> > + if (psci_has_osi_support() && !osi_mode_enabled)
> > + return -EBUSY;
> > +
> > + if (!state->data)
> > + return 0;
> > +
> > + /* When OSI mode is enabled, set the corresponding domain state. */
> > + pd_state = state->data;
> > + psci_set_domain_state(*pd_state);
>
> I trying to understand how would this scale to level 2(cluster of
> clusters or for simply system). The current code for psci_set_domain_state
> just stores the value @pd_state into per-cpu domain_state. E.g.: Now if
> the system level pd is getting called after cluster PD, it will set the
> domain state to system level PD state. It won't work with original
> format and it may work with extended format if it's carefully crafted.
> In short, the point is just over-writing domain_state is asking for
> troubles IMO.

Thanks for spotting this!

While walking upwards in the PM domain topology, I thought I was ORing
the domain states, but clearly the code isn't doing that.

In principle we need to do the below instead.

pd_state = state->data;
composite_pd_state = *pd_state | psci_get_domain_state();
psci_set_domain_state(composite_pd_state);



Yes 2 different issues here:
1. The direct assignment overwriting the value is problem which you agree.
2. The OR logic on it's own is bit not so clear from the specification.
  Since firmware authors need to be aware of this to make all the

Re: [PATCH 14/18] drivers: firmware: psci: Manage runtime PM in the idle path for CPUs

2019-07-18 Thread Lina Iyer

On Thu, Jul 18 2019 at 10:55 -0600, Ulf Hansson wrote:

On Thu, 18 Jul 2019 at 15:31, Lorenzo Pieralisi
 wrote:


On Thu, Jul 18, 2019 at 12:35:07PM +0200, Ulf Hansson wrote:
> On Tue, 16 Jul 2019 at 17:53, Lorenzo Pieralisi
>  wrote:
> >
> > On Mon, May 13, 2019 at 09:22:56PM +0200, Ulf Hansson wrote:
> > > When the hierarchical CPU topology layout is used in DT, let's allow the
> > > CPU to be power managed through its PM domain, via deploying runtime PM
> > > support.
> > >
> > > To know for which idle states runtime PM reference counting is needed,
> > > let's store the index of deepest idle state for the CPU, in a per CPU
> > > variable. This allows psci_cpu_suspend_enter() to compare this index with
> > > the requested idle state index and then act accordingly.
> >
> > I do not see why a system with two CPU CPUidle states, say CPU retention
> > and CPU shutdown, should not be calling runtime PM on CPU retention
> > entry.
>
> If the CPU idle governor did select the CPU retention for the CPU, it
> was probably because the target residency for the CPU shutdown state
> could not be met.

The kernel does not know what those cpu states represent, so, this is an
assumption you are making and it must be made clear that this code works
as long as your assumption is valid.

If eg a "cluster" retention state has lower target_residency than
the deepest CPU idle state this assumption is wrong.


Good point, you are right. I try to find a place to document this assumption.



And CPUidle and genPD governor decisions are not synced anyway so,
again, this is an assumption, not a certainty.

> In this case, there is no point in allowing any other deeper idle
> states for cluster/package/system, since those have even greater
> residencies, hence calling runtime PM doesn't make sense.

On the systems you are testing on.


So what you are saying typically means, that if all CPUs in the same
cluster have entered the CPU retention state, on some system the
cluster may also put into a cluster retention state (assuming the
target residency is met)?

Do you know of any systems that has these characteristics?


Many QCOM SoCs can do that. But with the hardware improving, the
power-performance benefits skew the results in favor of powering off
the cluster than keeping the CPU and cluster in retention.

Kevin H and I thought of this problem earlier on. But that is a second
level problem to solve and definitely to be thought of after we have the
support for the deepest states in the kernel. We left that out for a
later date. The idea would have been to setup the allowable state(s) in
the DT for CPU and cluster state definitions and have the genpd take
that into consideration when deciding the idle state for the domain.

Thanks,
Lina



Re: [PATCH 17/18] arm64: dts: Convert to the hierarchical CPU topology layout for MSM8916

2019-07-16 Thread Lina Iyer

On Tue, Jul 16 2019 at 08:47 -0600, Sudeep Holla wrote:

On Mon, May 13, 2019 at 09:22:59PM +0200, Ulf Hansson wrote:

From: Lina Iyer 

In the hierarchical layout, we are creating power domains around each CPU
and describes the idle states for them inside the power domain provider
node. Note that, the CPU's idle states still needs to be compatible with
"arm,idle-state".

Furthermore, represent the CPU cluster as a separate master power domain,
powering the CPU's power domains. The cluster node, contains the idle
states for the cluster and each idle state needs to be compatible with the
"domain-idle-state".

If the running platform is using a PSCI FW that supports the OS initiated
CPU suspend mode, which likely should be the case unless the PSCI FW is
very old, this change triggers the PSCI driver to enable it.

Cc: Andy Gross 
Cc: David Brown 
Signed-off-by: Lina Iyer 
Co-developed-by: Ulf Hansson 
Signed-off-by: Ulf Hansson 
---


[...]


@@ -166,12 +170,57 @@
min-residency-us = <2000>;
local-timer-stop;
};
+
+   CLUSTER_RET: cluster-retention {
+   compatible = "domain-idle-state";
+   arm,psci-suspend-param = <0x110>;
+   entry-latency-us = <500>;
+   exit-latency-us = <500>;
+   min-residency-us = <2000>;
+   };
+
+   CLUSTER_PWRDN: cluster-gdhs {
+   compatible = "domain-idle-state";
+   arm,psci-suspend-param = <0x130>;
+   entry-latency-us = <2000>;
+   exit-latency-us = <2000>;
+   min-residency-us = <6000>;
+   };
};
};


I was trying to understand the composition of composite state parameters
in this series and that made me look at these DT examples.


This was meant to depict a hierarchical state format for OSI.


What format does the above platform use ? I tried matching them to
both original as well as extended format and I fail to understand.
Assuming original format:
State power_state PowerLevel  StateType StateID
SPC   0x4002   0(core)0(Retention)  0x2 (Res0 b[29]=1?)
CLUSTER_RET   0x110   1(clusters) 0(Retention)  0x10
CLUSTER_PWRDN 0x130   1(clusters) 0(Retention?) 0x30
Now extended format:
State power_state StateType StateID
SPC   0x4002  0(Retention)  0x4002 (Res0 b[29]=1?)
CLUSTER_RET   0x110   0(Retention)  0x110

The composite state would comprise of CPU state and  Cluster state.
So for the last CPU entering idle -
(CLUSTER_RET | SPC)
0x4112

CLUSTER_PWRDN 0x130   0(Retention?) 0x130


(CLUSTER_PWRDN | SPC)
0x4132

Hope this helps.

Lina


Re: [PATCH 2/2] drivers: qcom: rpmh-rsc: fix read back of trigger register

2019-07-01 Thread Lina Iyer

Switching Andy's email address.

On Mon, Jul 01 2019 at 09:32 -0600, Lina Iyer wrote:

When triggering a TCS to send its contents, reading back the trigger
value may return an incorrect value. That is because, writing the
trigger may raise an interrupt which could be handled immediately and
the trigger value could be reset in the interrupt handler. By doing a
read back we may end up spinning waiting for the value we wrote.

Fixes: 658628 ("drivers: qcom: rpmh-rsc: add RPMH controller for QCOM
SoCs")
Signed-off-by: Lina Iyer 
---
drivers/soc/qcom/rpmh-rsc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 92461311aef3..2fc2fa879480 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -300,7 +300,7 @@ static void __tcs_trigger(struct rsc_drv *drv, int tcs_id)
enable = TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
-   write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+   write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
}

static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH 1/2] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-01 Thread Lina Iyer

Switching Andy's email address.

On Mon, Jul 01 2019 at 09:32 -0600, Lina Iyer wrote:

From: "Raju P.L.S.S.S.N" 

tcs->lock was introduced to serialize access with in TCS group. But
even without tcs->lock, drv->lock is serving the same purpose. So
use a single drv->lock.

Other optimizations include -
- Remove locking around clear_bit() in IRQ handler. clear_bit() is
  atomic.
- Remove redundant read of TCS registers.
- Use spin_lock instead of _irq variants as the locks are not held
  in interrupt context.

Fixes: 658628 ("drivers: qcom: rpmh-rsc: add RPMH controller for QCOM
SoCs")
Signed-off-by: Raju P.L.S.S.S.N 
Signed-off-by: Lina Iyer 
---
drivers/soc/qcom/rpmh-internal.h |  2 --
drivers/soc/qcom/rpmh-rsc.c  | 37 +++-
drivers/soc/qcom/rpmh.c  | 20 +++--
3 files changed, 21 insertions(+), 38 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index a767991c..969d5030860e 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -28,7 +28,6 @@ struct rsc_drv;
 * @offset:start of the TCS group relative to the TCSes in the RSC
 * @num_tcs:   number of TCSes in this type
 * @ncpt:  number of commands in each TCS
- * @lock:  lock for synchronizing this TCS writes
 * @req:   requests that are sent from the TCS
 * @cmd_cache: flattened cache of cmds in sleep/wake TCS
 * @slots: indicates which of @cmd_addr are occupied
@@ -40,7 +39,6 @@ struct tcs_group {
u32 offset;
int num_tcs;
int ncpt;
-   spinlock_t lock;
const struct tcs_request *req[MAX_TCS_PER_TYPE];
u32 *cmd_cache;
DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index e278fc11fe5c..92461311aef3 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -93,8 +93,7 @@ static void write_tcs_reg_sync(struct rsc_drv *drv, int reg, 
int tcs_id,

static bool tcs_is_free(struct rsc_drv *drv, int tcs_id)
{
-   return !test_bit(tcs_id, drv->tcs_in_use) &&
-  read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id, 0);
+   return !test_bit(tcs_id, drv->tcs_in_use);
}

static struct tcs_group *get_tcs_of_type(struct rsc_drv *drv, int type)
@@ -104,29 +103,28 @@ static struct tcs_group *get_tcs_of_type(struct rsc_drv 
*drv, int type)

static int tcs_invalidate(struct rsc_drv *drv, int type)
{
-   int m;
+   int m, ret = 0;
struct tcs_group *tcs;

tcs = get_tcs_of_type(drv, type);

-   spin_lock(>lock);
-   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) {
-   spin_unlock(>lock);
-   return 0;
-   }
+   spin_lock(>lock);
+   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS))
+   goto done;

for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
if (!tcs_is_free(drv, m)) {
-   spin_unlock(>lock);
-   return -EAGAIN;
+   ret = -EAGAIN;
+   goto done;
}
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
}
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
-   spin_unlock(>lock);

-   return 0;
+done:
+   spin_unlock(>lock);
+   return ret;
}

/**
@@ -242,9 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
-   spin_lock(>lock);
clear_bit(i, drv->tcs_in_use);
-   spin_unlock(>lock);
if (req)
rpmh_tx_done(req, err);
}
@@ -349,14 +345,12 @@ static int tcs_write(struct rsc_drv *drv, const struct 
tcs_request *msg)
{
struct tcs_group *tcs;
int tcs_id;
-   unsigned long flags;
int ret;

tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);

-   spin_lock_irqsave(>lock, flags);
spin_lock(>lock);
/*
 * The h/w does not like if we send a request to the same address,
@@ -364,26 +358,23 @@ static int tcs_write(struct rsc_drv *drv, const struct 
tcs_request *msg)
 */
ret = check_for_req_inflight(drv, tcs, msg);
if (ret) {
-   spin_unlock(>lock);
goto done_write;
}

tcs_id = find_free_tcs(tcs);
if (tcs_id < 0) {
ret = tcs_id;
-   spin_unlock(>lock);
goto done_write;
}

tcs->req[tcs_id - tcs->offset] = msg;
set_bit(tcs_id, drv->tcs_in

[PATCH 1/2] drivers: qcom: rpmh-rsc: simplify TCS locking

2019-07-01 Thread Lina Iyer
From: "Raju P.L.S.S.S.N" 

tcs->lock was introduced to serialize access with in TCS group. But
even without tcs->lock, drv->lock is serving the same purpose. So
use a single drv->lock.

Other optimizations include -
 - Remove locking around clear_bit() in IRQ handler. clear_bit() is
   atomic.
 - Remove redundant read of TCS registers.
 - Use spin_lock instead of _irq variants as the locks are not held
   in interrupt context.

Fixes: 658628 ("drivers: qcom: rpmh-rsc: add RPMH controller for QCOM
SoCs")
Signed-off-by: Raju P.L.S.S.S.N 
Signed-off-by: Lina Iyer 
---
 drivers/soc/qcom/rpmh-internal.h |  2 --
 drivers/soc/qcom/rpmh-rsc.c  | 37 +++-
 drivers/soc/qcom/rpmh.c  | 20 +++--
 3 files changed, 21 insertions(+), 38 deletions(-)

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index a767991c..969d5030860e 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -28,7 +28,6 @@ struct rsc_drv;
  * @offset:start of the TCS group relative to the TCSes in the RSC
  * @num_tcs:   number of TCSes in this type
  * @ncpt:  number of commands in each TCS
- * @lock:  lock for synchronizing this TCS writes
  * @req:   requests that are sent from the TCS
  * @cmd_cache: flattened cache of cmds in sleep/wake TCS
  * @slots: indicates which of @cmd_addr are occupied
@@ -40,7 +39,6 @@ struct tcs_group {
u32 offset;
int num_tcs;
int ncpt;
-   spinlock_t lock;
const struct tcs_request *req[MAX_TCS_PER_TYPE];
u32 *cmd_cache;
DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index e278fc11fe5c..92461311aef3 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -93,8 +93,7 @@ static void write_tcs_reg_sync(struct rsc_drv *drv, int reg, 
int tcs_id,
 
 static bool tcs_is_free(struct rsc_drv *drv, int tcs_id)
 {
-   return !test_bit(tcs_id, drv->tcs_in_use) &&
-  read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id, 0);
+   return !test_bit(tcs_id, drv->tcs_in_use);
 }
 
 static struct tcs_group *get_tcs_of_type(struct rsc_drv *drv, int type)
@@ -104,29 +103,28 @@ static struct tcs_group *get_tcs_of_type(struct rsc_drv 
*drv, int type)
 
 static int tcs_invalidate(struct rsc_drv *drv, int type)
 {
-   int m;
+   int m, ret = 0;
struct tcs_group *tcs;
 
tcs = get_tcs_of_type(drv, type);
 
-   spin_lock(>lock);
-   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) {
-   spin_unlock(>lock);
-   return 0;
-   }
+   spin_lock(>lock);
+   if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS))
+   goto done;
 
for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
if (!tcs_is_free(drv, m)) {
-   spin_unlock(>lock);
-   return -EAGAIN;
+   ret = -EAGAIN;
+   goto done;
}
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
}
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
-   spin_unlock(>lock);
 
-   return 0;
+done:
+   spin_unlock(>lock);
+   return ret;
 }
 
 /**
@@ -242,9 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
-   spin_lock(>lock);
clear_bit(i, drv->tcs_in_use);
-   spin_unlock(>lock);
if (req)
rpmh_tx_done(req, err);
}
@@ -349,14 +345,12 @@ static int tcs_write(struct rsc_drv *drv, const struct 
tcs_request *msg)
 {
struct tcs_group *tcs;
int tcs_id;
-   unsigned long flags;
int ret;
 
tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
 
-   spin_lock_irqsave(>lock, flags);
spin_lock(>lock);
/*
 * The h/w does not like if we send a request to the same address,
@@ -364,26 +358,23 @@ static int tcs_write(struct rsc_drv *drv, const struct 
tcs_request *msg)
 */
ret = check_for_req_inflight(drv, tcs, msg);
if (ret) {
-   spin_unlock(>lock);
goto done_write;
}
 
tcs_id = find_free_tcs(tcs);
if (tcs_id < 0) {
ret = tcs_id;
-   spin_unlock(>lock);
goto done_write;
}
 
tcs->req[tcs_id - tcs->offset] = msg;
set_bit(tcs_id, drv->tcs_in_use);
-   spin_unlock(>lock);
 
__tcs_buffer_w

[PATCH 2/2] drivers: qcom: rpmh-rsc: fix read back of trigger register

2019-07-01 Thread Lina Iyer
When triggering a TCS to send its contents, reading back the trigger
value may return an incorrect value. That is because, writing the
trigger may raise an interrupt which could be handled immediately and
the trigger value could be reset in the interrupt handler. By doing a
read back we may end up spinning waiting for the value we wrote.

Fixes: 658628 ("drivers: qcom: rpmh-rsc: add RPMH controller for QCOM
SoCs")
Signed-off-by: Lina Iyer 
---
 drivers/soc/qcom/rpmh-rsc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 92461311aef3..2fc2fa879480 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -300,7 +300,7 @@ static void __tcs_trigger(struct rsc_drv *drv, int tcs_id)
enable = TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
-   write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+   write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
 }
 
 static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 11/11] arm64: dts: qcom: setup PDC as wakeup parent for GPIOs for SDM845

2019-05-07 Thread Lina Iyer
Setup PDC wakeup parent for TLMM for SDM845 SoC.

Signed-off-by: Lina Iyer 
---
Changes in v3:
- Provide irqdomain-map for GPIOs that map to PDC
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 79 
 1 file changed, 79 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 7d4b11c9314e..59da6944b106 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1105,6 +1105,85 @@
#interrupt-cells = <2>;
gpio-ranges = < 0 0 150>;
 
+   wakeup-parent = <_intc>;
+   irqdomain-map = <1 0 _intc 30 0>,
+   <3 0 _intc 31 0>,
+   <5 0 _intc 32 0>,
+   <10 0 _intc 33 0>,
+   <11 0 _intc 34 0>,
+   <20 0 _intc 35 0>,
+   <22 0 _intc 36 0>,
+   <24 0 _intc 37 0>,
+   <26 0 _intc 38 0>,
+   <30 0 _intc 39 0>,
+   <31 0 _intc 117 0>,
+   <32 0 _intc 41 0>,
+   <34 0 _intc 42 0>,
+   <36 0 _intc 43 0>,
+   <37 0 _intc 44 0>,
+   <38 0 _intc 45 0>,
+   <39 0 _intc 46 0>,
+   <40 0 _intc 47 0>,
+   <41 0 _intc 115 0>,
+   <43 0 _intc 49 0>,
+   <44 0 _intc 50 0>,
+   <46 0 _intc 51 0>,
+   <48 0 _intc 52 0>,
+   <49 0 _intc 118 0>,
+   <52 0 _intc 54 0>,
+   <53 0 _intc 55 0>,
+   <54 0 _intc 56 0>,
+   <56 0 _intc 57 0>,
+   <57 0 _intc 58 0>,
+   <58 0 _intc 59 0>,
+   <59 0 _intc 60 0>,
+   <60 0 _intc 61 0>,
+   <61 0 _intc 62 0>,
+   <62 0 _intc 63 0>,
+   <63 0 _intc 64 0>,
+   <64 0 _intc 65 0>,
+   <66 0 _intc 66 0>,
+   <68 0 _intc 67 0>,
+   <71 0 _intc 68 0>,
+   <73 0 _intc 69 0>,
+   <77 0 _intc 70 0>,
+   <78 0 _intc 71 0>,
+   <79 0 _intc 72 0>,
+   <80 0 _intc 73 0>,
+   <84 0 _intc 74 0>,
+   <85 0 _intc 75 0>,
+   <86 0 _intc 76 0>,
+   <88 0 _intc 77 0>,
+   <89 0 _intc 116 0>,
+   <91 0 _intc 79 0>,
+   <92 0 _intc 80 0>,
+   <95 0 _intc 81 0>,
+   <96 0 _intc 82 0>,
+   <97 0 _intc 83 0>,
+   <101 0 _intc 84 0>,
+   <103 0 _intc 85 0>,
+   <104 0 _intc 86 0>,
+   <115 0 _intc 90 0>,
+   <116 0 _intc 91 0>,
+   <117 0 _intc 92 0>,
+   <118 0 _intc 93 0>,
+   <119 0 _intc 94 0>,
+   <120 0 _intc 95 0>,
+   <121 0 _intc 96 0>,
+   <122 0 _intc 97 0>,
+   <123 0 _intc 98 0>,
+

[PATCH v5 00/11] Support wakeup capable GPIOs

2019-05-07 Thread Lina Iyer
Hi all,

This is a re-spin of the wakeup capable GPIO support for QCOM SoCs.
The earlier version of the patch revision 4, was published [1] and had
some good discussions. The comments from the review have also been
addressed and the code rebased on top of 5.1 in this spin. There a few
changes in this spin:
- Review comments from Stephen, Marc
- Bug fixes in irqdomain-map
- Fix invalid interrupt case
- Update documentation
- Attempt generalizing gpiochip_to_irq() for hierarchical domain

In patch v4, we were discussing about the IRQ type of GPIO defaulting to
IRQ_TYPE_NONE (as is was the custom for older implementation). In the
SDM845 SoC select GPIOs are routed to an always-on interrupt controller
called the PDC and then to the GIC.

Wakeup capabable:
GPIO  --->  PDC  -->  GIC

Requesting a GPIO as an interrupt through the gpio_to_irq() call would
setup an interrupt hierarchy as above and return the linux interrupt
number. However, since the trigger type of the GPIO is unknown at this
time, gpiolib defaults to IRQ_TYPE_NONE. This triggers a warning at the
GIC, which expects a valid trigger type be set correctly in the fwspec.
The solution to this problem is still at large and I would like to
solicit feedback on this.

Appreciate your time.

Thanks,
Lina

[1]. https://patchwork.kernel.org/cover/10851807/

Lina Iyer (9):
  gpio: allow gpio_to_irq to use OF variants for gpiochips
  irqdomain: add bus token DOMAIN_BUS_WAKEUP
  of: irq: document properties for wakeup interrupt parent
  drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs
  dt-bindings: sdm845-pinctrl: add wakeup interrupt parent for GPIO
  drivers: pinctrl: msm: setup GPIO irqchip hierarchy
  arm64: dts: qcom: add PDC interrupt controller for SDM845
  arm64: defconfig: enable PDC interrupt controller for Qualcomm SDM845
  arm64: dts: qcom: setup PDC as wakeup parent for GPIOs for SDM845

Stephen Boyd (1):
  of: irq: add helper to remap interrupts to another irqdomain

Thierry Reding (1):
  gpio: Add support for hierarchical IRQ domains

 .../interrupt-controller/interrupts.txt   |  54 +++
 .../bindings/pinctrl/qcom,sdm845-pinctrl.txt  |  79 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi  |  88 +++
 arch/arm64/configs/defconfig  |   1 +
 drivers/gpio/gpiolib.c|  28 +++-
 drivers/irqchip/qcom-pdc.c|  98 +++--
 drivers/of/irq.c  | 129 +
 drivers/pinctrl/qcom/pinctrl-msm.c| 137 +++---
 include/linux/gpio/driver.h   |   6 +
 include/linux/irqdomain.h |   1 +
 include/linux/of_irq.h|   1 +
 include/linux/soc/qcom/irq.h  |  25 
 12 files changed, 610 insertions(+), 37 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 10/11] arm64: defconfig: enable PDC interrupt controller for Qualcomm SDM845

2019-05-07 Thread Lina Iyer
Enable PDC interrupt controller for SDM845 devices. The interrupt
controller can detect wakeup capable interrupts when the SoC is in a low
power state.

Signed-off-by: Lina Iyer 
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 2d9c39033c1a..4e5e681c4b11 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -685,6 +685,7 @@ CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD_RPM=y
 CONFIG_QCOM_SMP2P=y
 CONFIG_QCOM_SMSM=y
+CONFIG_QCOM_PDC=y
 CONFIG_ROCKCHIP_PM_DOMAINS=y
 CONFIG_ARCH_TEGRA_132_SOC=y
 CONFIG_ARCH_TEGRA_210_SOC=y
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 07/11] dt-bindings: sdm845-pinctrl: add wakeup interrupt parent for GPIO

2019-05-07 Thread Lina Iyer
SDM845 SoC has an always-on interrupt controller (PDC) with select GPIO
routed to the PDC as interrupts that can be used to wake the system up
from deep low power modes and suspend.

Update the sdm845 pinctrl device bindings to reference the PDC wakeup
interrupt controller and the GPIO PDC interrupt map.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
---
 .../bindings/pinctrl/qcom,sdm845-pinctrl.txt  | 79 ++-
 1 file changed, 78 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt 
b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
index 665aadb5ea28..895832127193 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
@@ -53,7 +53,6 @@ pin, a group, or a list of pins or groups. This configuration 
can include the
 mux function to select on those pin(s)/group(s), and various pin configuration
 parameters, such as pull-up, drive strength, etc.
 
-
 PIN CONFIGURATION NODES:
 
 The name of each subnode is not important; all subnodes should be enumerated
@@ -160,6 +159,84 @@ Example:
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+   wakeup-parent = <_intc>;
+   irqdomain-map = <1 0 _intc 30 0>,
+   <3 0 _intc 31 0>,
+   <5 0 _intc 32 0>,
+   <10 0 _intc 33 0>,
+   <11 0 _intc 34 0>,
+   <20 0 _intc 35 0>,
+   <22 0 _intc 36 0>,
+   <24 0 _intc 37 0>,
+   <26 0 _intc 38 0>,
+   <30 0 _intc 39 0>,
+   <31 0 _intc 117 0>,
+   <32 0 _intc 41 0>,
+   <34 0 _intc 42 0>,
+   <36 0 _intc 43 0>,
+   <37 0 _intc 44 0>,
+   <38 0 _intc 45 0>,
+   <39 0 _intc 46 0>,
+   <40 0 _intc 47 0>,
+   <41 0 _intc 115 0>,
+   <43 0 _intc 49 0>,
+   <44 0 _intc 50 0>,
+   <46 0 _intc 51 0>,
+   <48 0 _intc 52 0>,
+   <49 0 _intc 118 0>,
+   <52 0 _intc 54 0>,
+   <53 0 _intc 55 0>,
+   <54 0 _intc 56 0>,
+   <56 0 _intc 57 0>,
+   <57 0 _intc 58 0>,
+   <58 0 _intc 59 0>,
+   <59 0 _intc 60 0>,
+   <60 0 _intc 61 0>,
+   <61 0 _intc 62 0>,
+   <62 0 _intc 63 0>,
+   <63 0 _intc 64 0>,
+   <64 0 _intc 65 0>,
+   <66 0 _intc 66 0>,
+   <68 0 _intc 67 0>,
+   <71 0 _intc 68 0>,
+   <73 0 _intc 69 0>,
+   <77 0 _intc 70 0>,
+   <78 0 _intc 71 0>,
+   <79 0 _intc 72 0>,
+   <80 0 _intc 73 0>,
+   <84 0 _intc 74 0>,
+   <85 0 _intc 75 0>,
+   <86 0 _intc 76 0>,
+   <88 0 _intc 77 0>,
+   <89 0 _intc 116 0>,
+   <91 0 _intc 79 0>,
+   <92 0 _intc 80 0>,
+   <95 0 _intc 81 0>,
+   <96 0 _intc 82 0>,
+   <97 0 _intc 83 0>,
+   <101 0 _intc 84 0>,
+   <103 0 _intc 85 0>,
+   <104 0 _intc 86 0>,
+   <115 0 _intc 90 0>,
+   <116 0 _intc 91 0>,
+   <117 0 _intc 92 0>,
+   <118 0 _intc 93 0>,
+   <119 0 _intc 94 0>,
+   <120 0 _intc 95 0>,
+

[PATCH v5 04/11] of: irq: document properties for wakeup interrupt parent

2019-05-07 Thread Lina Iyer
Some interrupt controllers in a SoC, are always powered on and have a
select interrupts routed to them, so that they can wakeup the SoC from
suspend. Add wakeup-parent DT property to refer to these interrupt
controllers.

If the interrupts routed to the wakeup parent are not sequential, than a
map needs to exist to associate the same interrupt line on multiple
interrupt controllers. Providing this map in every driver is cumbersome.
Let's add this in the device tree and document the properties to map the
interrupt specifiers

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
---
Changes in v5:
- Update documentation to describe masks in the example
Changes in v4:
- Added this documentation
---
 .../interrupt-controller/interrupts.txt   | 54 +++
 1 file changed, 54 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt 
b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
index 8a3c40829899..e3e43f5d5566 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
@@ -108,3 +108,57 @@ commonly used:
sensitivity = <7>;
};
};
+
+3) Interrupt wakeup parent
+--
+
+Some interrupt controllers in a SoC, are always powered on and have a select
+interrupts routed to them, so that they can wakeup the SoC from suspend. These
+interrupt controllers do not fall into the category of a parent interrupt
+controller and can be specified by the "wakeup-parent" property and contain a
+single phandle referring to the wakeup capable interrupt controller.
+
+   Example:
+   wakeup-parent = <_intc>;
+
+
+4) Interrupt mapping
+
+
+Sometimes interrupts may be detected by more than one interrupt controller
+(depending on which controller is active). The interrupt controllers may not
+be in hierarchy and therefore the interrupt controller driver is required to
+establish the relationship between the same interrupt at different interrupt
+controllers. If these interrupts are not sequential then a map needs to be
+specified to help identify these interrupts.
+
+Mapping the interrupt specifiers in the device tree can be done using the
+"irqdomain-map" property. The property contains interrupt specifier at the
+current interrupt controller followed by the interrupt specifier at the mapped
+interrupt controller.
+
+   irqdomain-map = 
+
+The optional properties "irqdomain-map-mask" and "irqdomain-map-pass-thru" may
+be provided to help interpret the valid bits of the incoming and mapped
+interrupt specifiers respectively.
+
+   Example:
+   intc: interrupt-controller@17a0 {
+   #interrupt-cells = <3>;
+   };
+
+   pinctrl@340 {
+   #interrupt-cells = <2>;
+   irqdomain-map = <22 0  36 0>, <24 0  37 0>;
+   irqdomain-map-mask = <0xff 0>;
+   irqdomain-map-pass-thru = <0 0xff>;
+   };
+
+In the above example, the input interrupt specifier map-mask <0xff 0> applied
+on the incoming interrupt specifier of the map <22 0>, <24 0>, returns the
+input interrupt 22, 24 etc. The second argument being irq type is immaterial
+from the map and is used from the incoming request instead. The pass-thru
+specifier parses the output interrupt specifier from the rest of the unparsed
+argments from the map < 36 0>, < 37 0> etc to return the output
+interrupt 36, 37 etc.
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 02/11] gpio: allow gpio_to_irq to use OF variants for gpiochips

2019-05-07 Thread Lina Iyer
The chip may define additional information in the DT that may be useful
for translating and allocting a linux interrupt for the GPIO. When
drivers do not specify a .to_irq function, the gpiolib defaults to
gpiochip_to_irq() function. The defalt function uses creates an IRQ
without referencing the OF definition of the gpiochip. Let's add this
OF support to the default gpiochip_to_irq function.

When requesting an interrupt for the GPIO, let's stick to IRQ_TYPE_NONE
for the trigger type, for we don't have the information what trigger
type the driver may set when requesting the IRQ.

Signed-off-by: Lina Iyer 
---
 drivers/gpio/gpiolib.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4a9a6d4afe6e..77317435e2b2 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1825,6 +1825,19 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
+#ifdef CONFIG_OF_GPIO
+   struct irq_fwspec fwspec;
+
+   if (chip->of_node) {
+   fwspec.fwnode = of_node_to_fwnode(chip->of_node);
+   fwspec.param[0] = offset;
+   fwspec.param[1] = IRQ_TYPE_NONE;
+   fwspec.param_count = 2;
+
+   return irq_create_fwspec_mapping();
+   }
+#endif
+
if (!gpiochip_irqchip_irq_valid(chip, offset))
return -ENXIO;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 03/11] irqdomain: add bus token DOMAIN_BUS_WAKEUP

2019-05-07 Thread Lina Iyer
A single controller can handle normal interrupts and wake-up interrupts
independently, with a different numbering space. It is thus crucial to
allow the driver for such a controller discriminate between the two.

A simple way to do so is to tag the wake-up irqdomain with a "bus token"
that indicates the wake-up domain. This slightly abuses the notion of
bus, but also radically simplifies the design of such a driver. Between
two evils, we choose the least damaging.

Suggested-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
Changes in v4:
- Update commit text
---
 include/linux/irqdomain.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 61706b430907..4eaf17dfd2f8 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -82,6 +82,7 @@ enum irq_domain_bus_token {
DOMAIN_BUS_NEXUS,
DOMAIN_BUS_IPI,
DOMAIN_BUS_FSL_MC_MSI,
+   DOMAIN_BUS_WAKEUP,
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 06/11] drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs

2019-05-07 Thread Lina Iyer
Introduce a new domain for wakeup capable GPIOs. The domain can be
requested using the bus token DOMAIN_BUS_WAKEUP. In the following
patches, we will specify PDC as the wakeup-parent for the TLMM GPIO
irqchip. Requesting a wakeup GPIO will setup the GPIO and the
corresponding PDC interrupt as its parent.

Co-developed-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
Changes in v5:
- Define invalid wakeup interrupt
Changes in v4:
- Remove vestigial changes from v2
Changes in v3:
- Remove PDC GPIO map data (moved to DT)
- hwirq passed in .alloc() is a PDC pin now
Changes in v2:
- Remove separate file for PDC GPIO map data
- Error checks and return
- Whitespace fixes
---
 drivers/irqchip/qcom-pdc.c   | 98 
 include/linux/soc/qcom/irq.h | 25 +
 2 files changed, 114 insertions(+), 9 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index faa7d61b9d6c..ef0135fbc41a 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -13,12 +13,13 @@
 #include 
 #include 
 #include 
+#include 
 #include 
-#include 
 #include 
 #include 
 
 #define PDC_MAX_IRQS   126
+#define PDC_MAX_GPIO_IRQS  256
 
 #define CLEAR_INTR(reg, intr)  (reg & ~(1 << intr))
 #define ENABLE_INTR(reg, intr) (reg | (1 << intr))
@@ -26,6 +27,8 @@
 #define IRQ_ENABLE_BANK0x10
 #define IRQ_i_CFG  0x110
 
+#define PDC_NO_PARENT_IRQ  ~0UL
+
 struct pdc_pin_region {
u32 pin_base;
u32 parent_base;
@@ -65,12 +68,18 @@ static void pdc_enable_intr(struct irq_data *d, bool on)
 
 static void qcom_pdc_gic_mask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, false);
irq_chip_mask_parent(d);
 }
 
 static void qcom_pdc_gic_unmask(struct irq_data *d)
 {
+   if (d->hwirq == GPIO_NO_WAKE_IRQ)
+   return;
+
pdc_enable_intr(d, true);
irq_chip_unmask_parent(d);
 }
@@ -114,6 +123,9 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, 
unsigned int type)
int pin_out = d->hwirq;
enum pdc_irq_config_bits pdc_type;
 
+   if (pin_out == GPIO_NO_WAKE_IRQ)
+   return 0;
+
switch (type) {
case IRQ_TYPE_EDGE_RISING:
pdc_type = PDC_EDGE_RISING;
@@ -169,8 +181,7 @@ static irq_hw_number_t get_parent_hwirq(int pin)
return (region->parent_base + pin - region->pin_base);
}
 
-   WARN_ON(1);
-   return ~0UL;
+   return PDC_NO_PARENT_IRQ;
 }
 
 static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
@@ -199,17 +210,17 @@ static int qcom_pdc_alloc(struct irq_domain *domain, 
unsigned int virq,
 
ret = qcom_pdc_translate(domain, fwspec, , );
if (ret)
-   return -EINVAL;
-
-   parent_hwirq = get_parent_hwirq(hwirq);
-   if (parent_hwirq == ~0UL)
-   return -EINVAL;
+   return ret;
 
ret  = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
 _pdc_gic_chip, NULL);
if (ret)
return ret;
 
+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
if (type & IRQ_TYPE_EDGE_BOTH)
type = IRQ_TYPE_EDGE_RISING;
 
@@ -232,6 +243,63 @@ static const struct irq_domain_ops qcom_pdc_ops = {
.free   = irq_domain_free_irqs_common,
 };
 
+static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,
+  unsigned int nr_irqs, void *data)
+{
+   struct qcom_irq_fwspec *qcom_fwspec = data;
+   struct irq_fwspec *fwspec = _fwspec->fwspec;
+   struct irq_fwspec parent_fwspec;
+   irq_hw_number_t hwirq, parent_hwirq;
+   unsigned int type;
+   int ret;
+
+   ret = qcom_pdc_translate(domain, fwspec, , );
+   if (ret)
+   return ret;
+
+   ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+   _pdc_gic_chip, NULL);
+   if (ret)
+   return ret;
+
+   if (hwirq == GPIO_NO_WAKE_IRQ)
+   return 0;
+
+   parent_hwirq = get_parent_hwirq(hwirq);
+   if (parent_hwirq == PDC_NO_PARENT_IRQ)
+   return 0;
+
+   qcom_fwspec->mask = true;
+
+   if (type & IRQ_TYPE_EDGE_BOTH)
+   type = IRQ_TYPE_EDGE_RISING;
+
+   if (type & IRQ_TYPE_LEVEL_MASK)
+   type = IRQ_TYPE_LEVEL_HIGH;
+
+   parent_fwspec.fwnode  = domain->parent->fwnode;
+   parent_fwspec.param_count = 3;
+   parent_fwspec.param[0]= 0;
+   parent_fwspec.param[1]= parent_hwirq;
+   parent_fwspec.param[2]= type;
+
+   re

[PATCH v5 09/11] arm64: dts: qcom: add PDC interrupt controller for SDM845

2019-05-07 Thread Lina Iyer
Add PDC interrupt controller device bindings for SDM845.

Signed-off-by: Lina Iyer 
---
Changes in v1:
- Use updated address specification in reg
- Rename to pdc_intc
- Sort per address in DT
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 9 +
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi 
b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 5308f1671824..7d4b11c9314e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1934,6 +1934,15 @@
#power-domain-cells = <1>;
};
 
+   pdc_intc: interrupt-controller@b22 {
+   compatible = "qcom,sdm845-pdc";
+   reg = <0 0x0b22 0 0x3>;
+   qcom,pdc-ranges = <0 480 94>, <94 609 15>, <115 630 7>;
+   #interrupt-cells = <2>;
+   interrupt-parent = <>;
+   interrupt-controller;
+   };
+
pdc_reset: reset-controller@b2e {
compatible = "qcom,sdm845-pdc-global";
reg = <0 0x0b2e 0 0x2>;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 08/11] drivers: pinctrl: msm: setup GPIO irqchip hierarchy

2019-05-07 Thread Lina Iyer
To allow GPIOs to wakeup the system from suspend or deep idle, the
wakeup capable GPIOs are setup in hierarchy with interrupts from the
wakeup-parent irqchip.

In older SoC's, the TLMM will handover detection to the parent irqchip
and in newer SoC's, the parent irqchip may also be active as well as the
TLMM and therefore the GPIOs need to be masked at TLMM to avoid
duplicate interrupts. To enable both these configurations to exist,
allow the parent irqchip to dictate the TLMM irqchip's behavior when
masking/unmasking the interrupt.

Co-developed-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
Changes in v5:
- Fix when GPIO does not have a wakeup interrupt parent
Changes in v4:
- Remove irq_set_wake() on summary IRQ interrupt
Changes in v3:
- Use of_irq_domain_map() and pass PDC pin to parent irqdomain
Changes in v2:
- Call parent mask when masking GPIO interrupt
Changes in v1:
- Fix bug when unmasking PDC interrupt
---
 drivers/pinctrl/qcom/pinctrl-msm.c | 137 -
 1 file changed, 114 insertions(+), 23 deletions(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c 
b/drivers/pinctrl/qcom/pinctrl-msm.c
index ee8119879c4c..e52c1c300bcc 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -27,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -69,6 +71,7 @@ struct msm_pinctrl {
 
DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
+   DECLARE_BITMAP(wakeup_masked_irqs, MAX_NR_GPIO);
 
const struct msm_pinctrl_soc_data *soc;
void __iomem *regs[MAX_NR_TILES];
@@ -703,6 +706,13 @@ static void msm_gpio_irq_mask(struct irq_data *d)
 
g = >soc->groups[d->hwirq];
 
+   if (d->parent_data)
+   irq_chip_mask_parent(d);
+
+   /* Monitored by parent wakeup controller?*/
+   if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs))
+   return;
+
raw_spin_lock_irqsave(>lock, flags);
 
val = msm_readl_intr_cfg(pctrl, g);
@@ -747,6 +757,13 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
 
g = >soc->groups[d->hwirq];
 
+   if (d->parent_data)
+   irq_chip_unmask_parent(d);
+
+   /* Monitored by parent wakeup controller? Keep masked */
+   if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs))
+   return;
+
raw_spin_lock_irqsave(>lock, flags);
 
val = msm_readl_intr_cfg(pctrl, g);
@@ -767,6 +784,10 @@ static void msm_gpio_irq_ack(struct irq_data *d)
unsigned long flags;
u32 val;
 
+   /* Handled by parent wakeup controller? Do nothing */
+   if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs))
+   return;
+
g = >soc->groups[d->hwirq];
 
raw_spin_lock_irqsave(>lock, flags);
@@ -794,6 +815,13 @@ static int msm_gpio_irq_set_type(struct irq_data *d, 
unsigned int type)
 
g = >soc->groups[d->hwirq];
 
+   if (d->parent_data)
+   irq_chip_set_type_parent(d, type);
+
+   /* Monitored by parent wakeup controller? Keep masked */
+   if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs))
+   return 0;
+
raw_spin_lock_irqsave(>lock, flags);
 
/*
@@ -880,17 +908,10 @@ static int msm_gpio_irq_set_type(struct irq_data *d, 
unsigned int type)
 
 static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 {
-   struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-   struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
-   unsigned long flags;
-
-   raw_spin_lock_irqsave(>lock, flags);
-
-   irq_set_irq_wake(pctrl->irq, on);
-
-   raw_spin_unlock_irqrestore(>lock, flags);
+   if (d->parent_data)
+   return irq_chip_set_wake_parent(d, on);
 
-   return 0;
+   return -ENODEV;
 }
 
 static int msm_gpio_irq_reqres(struct irq_data *d)
@@ -967,11 +988,75 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl 
*pctrl)
return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
 }
 
+static int msm_gpio_domain_translate(struct irq_domain *d,
+struct irq_fwspec *fwspec,
+unsigned long *hwirq, unsigned int *type)
+{
+   if (is_of_node(fwspec->fwnode)) {
+   if (fwspec->param_count < 2)
+   return -EINVAL;
+   *hwirq = fwspec->param[0];
+   *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+   return 0;
+   }
+
+   return -EINVAL;
+}
+
+static int msm_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
+unsigned int nr_irqs

[PATCH v5 01/11] gpio: Add support for hierarchical IRQ domains

2019-05-07 Thread Lina Iyer
From: Thierry Reding 

Hierarchical IRQ domains can be used to stack different IRQ controllers
on top of each other. One specific use-case where this can be useful is
if a power management controller has top-level controls for wakeup
interrupts. In such cases, the power management controller can be a
parent to other interrupt controllers and program additional registers
when an IRQ has its wake capability enabled or disabled.

Signed-off-by: Thierry Reding 
Signed-off-by: Lina Iyer 
---
 drivers/gpio/gpiolib.c  | 15 +++
 include/linux/gpio/driver.h |  6 ++
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index bca3e7740ef6..4a9a6d4afe6e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1936,7 +1936,9 @@ static int gpiochip_add_irqchip(struct gpio_chip 
*gpiochip,
type = IRQ_TYPE_NONE;
}
 
-   gpiochip->to_irq = gpiochip_to_irq;
+   if (!gpiochip->to_irq)
+   gpiochip->to_irq = gpiochip_to_irq;
+
gpiochip->irq.default_type = type;
gpiochip->irq.lock_key = lock_key;
gpiochip->irq.request_key = request_key;
@@ -1946,9 +1948,14 @@ static int gpiochip_add_irqchip(struct gpio_chip 
*gpiochip,
else
ops = _domain_ops;
 
-   gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
-gpiochip->irq.first,
-ops, gpiochip);
+   if (gpiochip->irq.parent_domain)
+   gpiochip->irq.domain = 
irq_domain_add_hierarchy(gpiochip->irq.parent_domain,
+   0, 
gpiochip->ngpio,
+   np, ops, 
gpiochip);
+   else
+   gpiochip->irq.domain = irq_domain_add_simple(np, 
gpiochip->ngpio,
+
gpiochip->irq.first,
+ops, gpiochip);
if (!gpiochip->irq.domain)
return -EINVAL;
 
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 01497910f023..f481862f1bb0 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -48,6 +48,12 @@ struct gpio_irq_chip {
 */
const struct irq_domain_ops *domain_ops;
 
+   /**
+* @parent_domain:
+*
+*/
+   struct irq_domain *parent_domain;
+
/**
 * @handler:
 *
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v5 05/11] of: irq: add helper to remap interrupts to another irqdomain

2019-05-07 Thread Lina Iyer
From: Stephen Boyd 

Sometimes interrupts are routed from an interrupt controller to another
in no specific order. Having these in the drivers makes it difficult to
maintain when the same drivers supports multiple variants with different
mapping. Also, specifying them in DT makes little sense with a bunch of
numbers like -
<0, 13>, <5, 32>,

It makes more sense when we can have the parent handle along with
interrupt specifiers for the incoming interrupt as well as that of the
outgoing interrupt like -
<22 0  36 0>,
<24 0  37 0>,
<26 0  38 0>,

And the interrupt specifiers can be interpreted using these optional
properties -
irqdomain-map-mask = <0xff 0>;
irqdomain-map-pass-thru = <0 0xff>;

The irqdomain-map-mask reads the input interrupt specifier to parse the
incoming interrupt port. The format of the output port is specified with
the irqdomain-map-pass-thru property.

Let's add a helper function to parse this from DT and match a struct
irq_fwspec using the input interrupt specifier from the irqdomain-map
and the valid bits specified in the irqdomain-map-mask and copy the
output interrupt specifier from the map to irq_fwspec per the mask in
irqdomain-map-pass-thru property for the matched interrupt.

Signed-off-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
Changes in v5:
- Fix returning 0 when no match is found
Changes in v4:
- Fix commit text spelling and verbosity
---
 drivers/of/irq.c   | 129 +
 include/linux/of_irq.h |   1 +
 2 files changed, 130 insertions(+)

diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index e1f6f392a4c0..6186904b2b6b 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -273,6 +273,135 @@ int of_irq_parse_raw(const __be32 *addr, struct 
of_phandle_args *out_irq)
 }
 EXPORT_SYMBOL_GPL(of_irq_parse_raw);
 
+int of_irq_domain_map(const struct irq_fwspec *in, struct irq_fwspec *out)
+{
+   char *stem_name;
+   char *cells_name, *map_name = NULL, *mask_name = NULL;
+   char *pass_name = NULL;
+   struct device_node *cur, *new = NULL;
+   const __be32 *map, *mask, *pass;
+   static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
+   static const __be32 dummy_pass[] = { [0 ... MAX_PHANDLE_ARGS] = 0 };
+   __be32 initial_match_array[MAX_PHANDLE_ARGS];
+   const __be32 *match_array = initial_match_array;
+   int i, ret, map_len, match;
+   u32 in_size, out_size;
+
+   stem_name = "";
+   cells_name = "#interrupt-cells";
+
+   ret = -ENOMEM;
+   map_name = kasprintf(GFP_KERNEL, "irqdomain%s-map", stem_name);
+   if (!map_name)
+   goto free;
+
+   mask_name = kasprintf(GFP_KERNEL, "irqdomain%s-map-mask", stem_name);
+   if (!mask_name)
+   goto free;
+
+   pass_name = kasprintf(GFP_KERNEL, "irqdomain%s-map-pass-thru", 
stem_name);
+   if (!pass_name)
+   goto free;
+
+   /* Get the #interrupt-cells property */
+   cur = to_of_node(in->fwnode);
+   ret = of_property_read_u32(cur, cells_name, _size);
+   if (ret < 0)
+   goto put;
+
+   /* Precalculate the match array - this simplifies match loop */
+   for (i = 0; i < in_size; i++)
+   initial_match_array[i] = cpu_to_be32(in->param[i]);
+
+   ret = -EINVAL;
+   /* Get the irqdomain-map property */
+   map = of_get_property(cur, map_name, _len);
+   if (!map) {
+   ret = 0;
+   goto free;
+   }
+   map_len /= sizeof(u32);
+
+   /* Get the irqdomain-map-mask property (optional) */
+   mask = of_get_property(cur, mask_name, NULL);
+   if (!mask)
+   mask = dummy_mask;
+   /* Iterate through irqdomain-map property */
+   match = 0;
+   while (map_len > (in_size + 1) && !match) {
+   /* Compare specifiers */
+   match = 1;
+   for (i = 0; i < in_size; i++, map_len--)
+   match &= !((match_array[i] ^ *map++) & mask[i]);
+
+   of_node_put(new);
+   new = of_find_node_by_phandle(be32_to_cpup(map));
+   map++;
+   map_len--;
+
+   /* Check if not found */
+   if (!new)
+   goto put;
+
+   if (!of_device_is_available(new))
+   match = 0;
+
+   ret = of_property_read_u32(new, cells_name, _size);
+   if (ret)
+   goto put;
+
+   /* Check for malformed properties */
+   if (WARN_ON(out_size > MAX_PHANDLE_ARGS))
+   goto put;
+   if (map_len < out_size)
+   goto put;
+
+   /* Move forward by new node's #interrupt-cells amount */
+

Re: [PATCH v4 07/10] drivers: pinctrl: msm: setup GPIO irqchip hierarchy

2019-04-22 Thread Lina Iyer

On Wed, Apr 17 2019 at 07:59 -0600, Linus Walleij wrote:

On Thu, Mar 21, 2019 at 10:54 PM Stephen Boyd  wrote:

Quoting Marc Zyngier (2019-03-16 04:39:48)> > On Fri, 15 Mar 2019 09:28:31 -0700
> Stephen Boyd  wrote:
>
> > Quoting Lina Iyer (2019-03-13 14:18:41)
> > > @@ -994,6 +1092,22 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
> > > pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
> > > pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
> > >
> > > +   chip->irq.chip = >irq_chip;
> > > +   chip->irq.domain_ops = _gpio_domain_ops;
> > > +   chip->irq.handler = handle_edge_irq;
> > > +   chip->irq.default_type = IRQ_TYPE_EDGE_RISING;
> >
> > This also changed from v3. It used to be IRQ_TYPE_NONE. Specifying this
> > here seems to cause gpiolib to print a WARN.
> >
> >
> > /*
> >  * Specifying a default trigger is a terrible idea if DT or ACPI is
> >  * used to configure the interrupts, as you may end up with
> >  * conflicting triggers. Tell the user, and reset to NONE.
> >  */
> > if (WARN(np && type != IRQ_TYPE_NONE,
> >  "%s: Ignoring %u default trigger\n", np->full_name, type))
> > type = IRQ_TYPE_NONE;
> >
> >
> > So I guess this change should be dropped. Or at the least, it should be
> > split out to it's own patch and the motivations can be discussed in the
> > commit text.
>
> It is something I requested (although I expected this to be a
> different patch, and even a clarification would have been OK).
>
> One way or another, the default trigger must match the flow handler. If
> we set it up with IRQ_TYPE_NONE, what does it mean? The fact that
> IRQ_TYPE_NONE acts as a wildcard doesn't mean the handle_edge_irq flow
> handler is a good match for all interrupt types (it is rarely OK for
> level interrupts).

I think this is a question for Thierry or Linus. I'm not sure why this
check was put in place in the code. I tried to dig into it really quick
but I didn't find anything obvious and then I gave up.

Maybe with hierarchical irqdomains we can drop this check? I don't think
the gpiolib core ever uses this 'default_type' or 'handler' for anything
once we replace the irqdomain that's used for a particular gpiochip with
a custom irqdomain. The only user I see, gpiochip_irq_map(), won't ever
be called so it really ends up being a thing that the driver specific
irqdomains should check for and reject when parsing the DT and it sees
IRQ_TYPE_NONE come out.

--8<---
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 144af0733581..fe2f7888c473 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1922,7 +1922,7 @@ static int gpiochip_add_irqchip(struct gpio_chip 
*gpiochip,
 * used to configure the interrupts, as you may end up with
 * conflicting triggers. Tell the user, and reset to NONE.
 */
-   if (WARN(np && type != IRQ_TYPE_NONE,
+   if (WARN(!gpiochip->irq.domain_ops && np && type != IRQ_TYPE_NONE,
 "%s: Ignoring %u default trigger\n", np->full_name, type))
type = IRQ_TYPE_NONE;


Sorry for taking long time to answer... this got lost in some mail
storms.

It's a bit of Marc Z question really but I try to answer and
he can correct me.

We are now getting used to ACPI and DT always specifying
the IRQ trigger type on the consumer handle: a device tells
the irqchip what kind of edge or level it wants.

Things weren't always like that.

Some boards in the kernel is still using board files. (Yeah
please help in modernizing them, I am doing my part.)

Old machines with GPIO irqchip jitted to the SoC irq controller
sometimes had a hardcoded behavior such as edge, and the
consumers would only issue something really legacy
like

request_irq(42, myhandler, 0, "myirq", data);

and expect it to work, since 0 means use the default flags,
it might have a platform device with this irq number passed
as a resource, but that is a really dumb platform device still,
and it might not have set any irqflags for the irq number
it passes. It probably doesn't even know that the irq number
is backed by an irq descriptor.

Since the code that e.g. DT has inside drivers/of/platform.c
irq_of_parse_and_map(), will incidentally create an irq
descriptor and set up these flags from the consumer flags in the
device tree and call the irqchip to set up the trigger through
.set_type() whenever the interrupt is requested, this is no
problem for DT. Or ACPI.

But on a board file, the .set_type() will eventually be called
with IRQ_TYPE_NONE, which will cause a bug, or

Re: [PATCH v4 07/10] drivers: pinctrl: msm: setup GPIO irqchip hierarchy

2019-04-17 Thread Lina Iyer

On Fri, Mar 15 2019 at 10:28 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-03-13 14:18:41)

---
Changes in v4:
- Remove irq_set_wake() on summary IRQ interrupt
Changes in v3:
- Use of_irq_domain_map() and pass PDC pin to parent irqdomain
Changes in v2:
- Call parent mask when masking GPIO interrupt
Changes in v1:
- Fix bug when unmasking PDC interrupt

[...]

+}
+
+/*
+ * TODO: Get rid of this and push it into gpiochip_to_irq()
+ */


Any chance this TODO can be resolved?



I am thinking of something like this. Would there be any issue in
setting the type to IRQ_TYPE_SENSE_MASK instead of any one particular
type?

---8<-
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
{
#ifdef CONFIG_OF_GPIO
   struct irq_fwspec fwspec;

   if (chip->of_node) {
  fwspec.fwnode = of_node_to_fwnode(chip->of_node);
  fwspec.param[0] = offset;
  fwspec.param[1] = IRQ_TYPE_SENSE_MASK;
  fwspec.param_count = 2;
  return irq_create_fwspec_mapping();
   }
#endif

   if (!gpiochip_irqchip_irq_valid(chip, offset))
   return -ENXIO;

   return irq_create_mapping(chip->irq.domain, offset);
}
---8<


Thanks,
Lina



Re: [PATCH v4 07/10] drivers: pinctrl: msm: setup GPIO irqchip hierarchy

2019-04-16 Thread Lina Iyer

On Thu, Mar 21 2019 at 15:54 -0600, Stephen Boyd wrote:

Quoting Marc Zyngier (2019-03-16 04:39:48)

On Fri, 15 Mar 2019 09:28:31 -0700
Stephen Boyd  wrote:

> Quoting Lina Iyer (2019-03-13 14:18:41)
> > @@ -994,6 +1092,22 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
> > pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
> > pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
> >
> > +   chip->irq.chip = >irq_chip;
> > +   chip->irq.domain_ops = _gpio_domain_ops;
> > +   chip->irq.handler = handle_edge_irq;
> > +   chip->irq.default_type = IRQ_TYPE_EDGE_RISING;
>
> This also changed from v3. It used to be IRQ_TYPE_NONE. Specifying this
> here seems to cause gpiolib to print a WARN.
>
>
> /*
>  * Specifying a default trigger is a terrible idea if DT or ACPI is
>  * used to configure the interrupts, as you may end up with
>  * conflicting triggers. Tell the user, and reset to NONE.
>  */
> if (WARN(np && type != IRQ_TYPE_NONE,
>  "%s: Ignoring %u default trigger\n", np->full_name, type))
> type = IRQ_TYPE_NONE;
>
>
> So I guess this change should be dropped. Or at the least, it should be
> split out to it's own patch and the motivations can be discussed in the
> commit text.

It is something I requested (although I expected this to be a
different patch, and even a clarification would have been OK).

One way or another, the default trigger must match the flow handler. If
we set it up with IRQ_TYPE_NONE, what does it mean? The fact that
IRQ_TYPE_NONE acts as a wildcard doesn't mean the handle_edge_irq flow
handler is a good match for all interrupt types (it is rarely OK for
level interrupts).


I think this is a question for Thierry or Linus. I'm not sure why this
check was put in place in the code. I tried to dig into it really quick
but I didn't find anything obvious and then I gave up.

Maybe with hierarchical irqdomains we can drop this check? I don't think
the gpiolib core ever uses this 'default_type' or 'handler' for anything
once we replace the irqdomain that's used for a particular gpiochip with
a custom irqdomain. The only user I see, gpiochip_irq_map(), won't ever
be called so it really ends up being a thing that the driver specific
irqdomains should check for and reject when parsing the DT and it sees
IRQ_TYPE_NONE come out.

--8<---
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 144af0733581..fe2f7888c473 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1922,7 +1922,7 @@ static int gpiochip_add_irqchip(struct gpio_chip 
*gpiochip,
 * used to configure the interrupts, as you may end up with
 * conflicting triggers. Tell the user, and reset to NONE.
 */
-   if (WARN(np && type != IRQ_TYPE_NONE,
+   if (WARN(!gpiochip->irq.domain_ops && np && type != IRQ_TYPE_NONE,
 "%s: Ignoring %u default trigger\n", np->full_name, type))
type = IRQ_TYPE_NONE;


Linus,

Any thoughts on this?

-- Lina



Re: [PATCH v4 03/10] of/irq: document properties for wakeup interrupt parent

2019-04-16 Thread Lina Iyer

On Tue, Apr 16 2019 at 10:54 -0600, Stephen Boyd wrote:

Quoting Lina Iyer (2019-04-04 08:58:38)

On Mon, Mar 18 2019 at 11:54 -0600, Marc Zyngier wrote:
>On Wed, 13 Mar 2019 15:18:37 -0600
>Lina Iyer  wrote:
>
>Please do Cc Rob when posting DT related patches.
>
>> Some interrupt controllers in a SoC, are always powered on and have a
>> select interrupts routed to them, so that they can wakeup the SoC from
>> suspend. Add wakeup-parent DT property to refer to these interrupt
>> controllers.
>>
>> If the interrupts routed to the wakeup parent are not sequential, than a
>> map needs to exist to associate the same interrupt line on multiple
>> interrupt controllers. Providing this map in every driver is cumbersome.
>> Let's add this in the device tree and document the properties to map the
>> interrupt specifiers
>>
>> Signed-off-by: Lina Iyer 
>> ---
>> Changes in v4:
>>  - Added this documentation
>> ---
>>  .../interrupt-controller/interrupts.txt   | 39 +++
>>  1 file changed, 39 insertions(+)
>>
>> diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt 
b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
>> index 8a3c40829899..917b598317f5 100644
>> --- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
>> +++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
>> @@ -108,3 +108,42 @@ commonly used:
>>  sensitivity = <7>;
>>  };
>>  };
>> +
>> +3) Interrupt wakeup parent
>> +--
>> +
>> +Some interrupt controllers in a SoC, are always powered on and have a select
>> +interrupts routed to them, so that they can wakeup the SoC from suspend. 
These
>> +interrupt controllers do not fall into the category of a parent interrupt
>> +controller and can be specified by the "wakeup-parent" property and contain 
a
>> +single phandle referring to the wakeup capable interrupt controller.
>> +
>> +   Example:
>> +wakeup-parent = <_intc>;
>> +
>> +
>> +4) Interrupt mapping
>> +
>> +
>> +Sometimes interrupts may be detected by more than one interrupt controller
>> +(depending on which controller is active). The interrupt controllers may not
>> +be in hierarchy and therefore the interrupt controller driver is required to
>> +establish the relationship between the same interrupt at different interrupt
>> +controllers. If these interrupts are not sequential then a map needs to be
>> +specified to help identify these interrupts.
>> +
>> +Mapping the interrupt specifiers in the device tree can be done using the
>> +"irqdomain-map" property. The property contains interrupt specifier at the
>> +current interrupt controller followed by the interrupt specifier at the 
mapped
>> +interrupt controller.
>> +
>> +   irqdomain-map = 
>> +
>> +The optional properties "irqdomain-map-mask" and "irqdomain-map-pass-thru" 
may
>> +be provided to help interpret the valid bits of the incoming and mapped
>> +interrupt specifiers respectively.
>> +
>> +   Example:
>> +irqdomain-map = <22 0  36 0>, <24 0  37 0>;
>> +irqdomain-map-mask = <0xff 0>;
>> +irqdomain-map-pass-thru = <0 0xff>;
>
>
>This doesn't quite explain how the mask and pass-thru properties are
>used. I guess that the mask is used to define the 'useful bits' on the
>incoming side, but pass-thru puzzles me. In your example, does it mean
>that incoming lines map to outgoing interrupt <0 0>?
>
Sorry about the late reply.

How about this to go with the rest of the documentation -

In the above example, the input interrupt specifier map-mask <0xff 0> applied
on the incoming interrupt specifier of the map <22 0>, <24 0>, returns the
input interrupt 22, 24 etc. The second argument being irq type is immaterial
from the map and is used from the incoming request instead. The pass-thru
specifier parses the output interrupt specifier from the rest of the unparsed
argments from the map < 36 0>, < 37 0> etc to return the output
interrupt 36, 37 etc.




I see two things going on here. Do both need to happen?

#1: Specifying wakeup parent phandle
#2: Mapping GPIO interrupts to a parent irqdomain

Do we need the method of specifying the wakeup parent if with a dt
property if we have a way to map irqdomains from one to another? I think
I may have already said on the list that we must have #1 but now I'm not
so sure. It looks like we 

Re: [PATCH v4 03/10] of/irq: document properties for wakeup interrupt parent

2019-04-15 Thread Lina Iyer

On Mon, Apr 15 2019 at 06:42 -0600, Marc Zyngier wrote:

On 04/04/2019 16:58, Lina Iyer wrote:

On Mon, Mar 18 2019 at 11:54 -0600, Marc Zyngier wrote:

On Wed, 13 Mar 2019 15:18:37 -0600
Lina Iyer  wrote:

Please do Cc Rob when posting DT related patches.


Some interrupt controllers in a SoC, are always powered on and have a
select interrupts routed to them, so that they can wakeup the SoC from
suspend. Add wakeup-parent DT property to refer to these interrupt
controllers.

If the interrupts routed to the wakeup parent are not sequential, than a
map needs to exist to associate the same interrupt line on multiple
interrupt controllers. Providing this map in every driver is cumbersome.
Let's add this in the device tree and document the properties to map the
interrupt specifiers

Signed-off-by: Lina Iyer 
---
Changes in v4:
- Added this documentation
---
 .../interrupt-controller/interrupts.txt   | 39 +++
 1 file changed, 39 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt 
b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
index 8a3c40829899..917b598317f5 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
@@ -108,3 +108,42 @@ commonly used:
sensitivity = <7>;
};
};
+
+3) Interrupt wakeup parent
+--
+
+Some interrupt controllers in a SoC, are always powered on and have a select
+interrupts routed to them, so that they can wakeup the SoC from suspend. These
+interrupt controllers do not fall into the category of a parent interrupt
+controller and can be specified by the "wakeup-parent" property and contain a
+single phandle referring to the wakeup capable interrupt controller.
+
+   Example:
+   wakeup-parent = <_intc>;
+
+
+4) Interrupt mapping
+
+
+Sometimes interrupts may be detected by more than one interrupt controller
+(depending on which controller is active). The interrupt controllers may not
+be in hierarchy and therefore the interrupt controller driver is required to
+establish the relationship between the same interrupt at different interrupt
+controllers. If these interrupts are not sequential then a map needs to be
+specified to help identify these interrupts.
+
+Mapping the interrupt specifiers in the device tree can be done using the
+"irqdomain-map" property. The property contains interrupt specifier at the
+current interrupt controller followed by the interrupt specifier at the mapped
+interrupt controller.
+
+   irqdomain-map = 
+
+The optional properties "irqdomain-map-mask" and "irqdomain-map-pass-thru" may
+be provided to help interpret the valid bits of the incoming and mapped
+interrupt specifiers respectively.
+
+   Example:
+   irqdomain-map = <22 0  36 0>, <24 0  37 0>;
+   irqdomain-map-mask = <0xff 0>;
+   irqdomain-map-pass-thru = <0 0xff>;



This doesn't quite explain how the mask and pass-thru properties are
used. I guess that the mask is used to define the 'useful bits' on the
incoming side, but pass-thru puzzles me. In your example, does it mean
that incoming lines map to outgoing interrupt <0 0>?


Sorry about the late reply.

How about this to go with the rest of the documentation -

In the above example, the input interrupt specifier map-mask <0xff 0> applied
on the incoming interrupt specifier of the map <22 0>, <24 0>, returns the
input interrupt 22, 24 etc. The second argument being irq type is immaterial
from the map and is used from the incoming request instead. The pass-thru
specifier parses the output interrupt specifier from the rest of the unparsed
argments from the map < 36 0>, < 37 0> etc to return the output
interrupt 36, 37 etc.


I think you need to add #interrupt-cells in your example, which is
otherwise hard to interpret.


Ok. Thanks, will add.

--Lina



Re: [PATCH v4 00/10] support wakeup capable GPIOs

2019-04-15 Thread Lina Iyer

On Mon, Apr 15 2019 at 06:43 -0600, Marc Zyngier wrote:

On 13/03/2019 21:18, Lina Iyer wrote:

Hi all,

This series adds support for wakeup capable GPIOs. It is based on Thierry's
hiearchical GPIO domains. This approach is based on Stephen's idea [1]. The SoC
that is used for this development is a QCOM SDM845. The current patchset is
rebased on top of 5.0 and adds documentation for the wakeup-parent and
irqdomain-map DT properties along with the the optional irqdomain-map-mask and
irqdomain-map-pass-thru properties. Also incorporating comments from Marc on
the earlier submission [2]. I cleaned up some of the change history in these
patches to match the version number with that of the submission.

The dtsi patches are based on Bjorn's changes for increased address and cell
size [3] and [4].

Kindly review the series.


What the status of this? What is the expected merge strategy?


Hi Mark,

I ran into a couple of issues, most of which have been sorted out. But
there is a hardware requirement to write up another register (to set
type), for GPIO wakeup that was missed earlier. I am trying to get that
tested out. That's the hold up. Sorry about that.

--Lina


Re: [PATCH v4 03/10] of/irq: document properties for wakeup interrupt parent

2019-04-04 Thread Lina Iyer

On Mon, Mar 18 2019 at 11:54 -0600, Marc Zyngier wrote:

On Wed, 13 Mar 2019 15:18:37 -0600
Lina Iyer  wrote:

Please do Cc Rob when posting DT related patches.


Some interrupt controllers in a SoC, are always powered on and have a
select interrupts routed to them, so that they can wakeup the SoC from
suspend. Add wakeup-parent DT property to refer to these interrupt
controllers.

If the interrupts routed to the wakeup parent are not sequential, than a
map needs to exist to associate the same interrupt line on multiple
interrupt controllers. Providing this map in every driver is cumbersome.
Let's add this in the device tree and document the properties to map the
interrupt specifiers

Signed-off-by: Lina Iyer 
---
Changes in v4:
- Added this documentation
---
 .../interrupt-controller/interrupts.txt   | 39 +++
 1 file changed, 39 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt 
b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
index 8a3c40829899..917b598317f5 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
@@ -108,3 +108,42 @@ commonly used:
sensitivity = <7>;
};
};
+
+3) Interrupt wakeup parent
+--
+
+Some interrupt controllers in a SoC, are always powered on and have a select
+interrupts routed to them, so that they can wakeup the SoC from suspend. These
+interrupt controllers do not fall into the category of a parent interrupt
+controller and can be specified by the "wakeup-parent" property and contain a
+single phandle referring to the wakeup capable interrupt controller.
+
+   Example:
+   wakeup-parent = <_intc>;
+
+
+4) Interrupt mapping
+
+
+Sometimes interrupts may be detected by more than one interrupt controller
+(depending on which controller is active). The interrupt controllers may not
+be in hierarchy and therefore the interrupt controller driver is required to
+establish the relationship between the same interrupt at different interrupt
+controllers. If these interrupts are not sequential then a map needs to be
+specified to help identify these interrupts.
+
+Mapping the interrupt specifiers in the device tree can be done using the
+"irqdomain-map" property. The property contains interrupt specifier at the
+current interrupt controller followed by the interrupt specifier at the mapped
+interrupt controller.
+
+   irqdomain-map = 
+
+The optional properties "irqdomain-map-mask" and "irqdomain-map-pass-thru" may
+be provided to help interpret the valid bits of the incoming and mapped
+interrupt specifiers respectively.
+
+   Example:
+   irqdomain-map = <22 0  36 0>, <24 0  37 0>;
+   irqdomain-map-mask = <0xff 0>;
+   irqdomain-map-pass-thru = <0 0xff>;



This doesn't quite explain how the mask and pass-thru properties are
used. I guess that the mask is used to define the 'useful bits' on the
incoming side, but pass-thru puzzles me. In your example, does it mean
that incoming lines map to outgoing interrupt <0 0>?


Sorry about the late reply.

How about this to go with the rest of the documentation -

In the above example, the input interrupt specifier map-mask <0xff 0> applied
on the incoming interrupt specifier of the map <22 0>, <24 0>, returns the
input interrupt 22, 24 etc. The second argument being irq type is immaterial
from the map and is used from the incoming request instead. The pass-thru
specifier parses the output interrupt specifier from the rest of the unparsed
argments from the map < 36 0>, < 37 0> etc to return the output
interrupt 36, 37 etc.


--Lina



Re: [PATCH v4 04/10] of: irq: add helper to remap interrupts to another irqdomain

2019-03-22 Thread Lina Iyer

I observed an issue with return value being set to 0, when a match is
not found in the irqdomain-map.

On Wed, Mar 13 2019 at 15:20 -0600, Lina Iyer wrote:

From: Stephen Boyd 

Sometimes interrupts are routed from an interrupt controller to another
in no specific order. Having these in the drivers makes it difficult to
maintain when the same drivers supports multiple variants with different
mapping. Also, specifying them in DT makes little sense with a bunch of
numbers like -
<0, 13>, <5, 32>,

It makes more sense when we can have the parent handle along with
interrupt specifiers for the incoming interrupt as well as that of the
outgoing interrupt like -
<22 0  36 0>,
<24 0  37 0>,
<26 0  38 0>,

And the interrupt specifiers can be interpreted using these optional
properties -
irqdomain-map-mask = <0xff 0>;
irqdomain-map-pass-thru = <0 0xff>;

The irqdomain-map-mask reads the input interrupt specifier to parse the
incoming interrupt port. The format of the output port is specified with
the irqdomain-map-pass-thru property.

Let's add a helper function to parse this from DT and match a struct
irq_fwspec using the input interrupt specifier from the irqdomain-map
and the valid bits specified in the irqdomain-map-mask and copy the
output interrupt specifier from the map to irq_fwspec per the mask in
irqdomain-map-pass-thru property for the matched interrupt.

Signed-off-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
Changes in v4:
- Fix commit text spelling and verbosity
---
drivers/of/irq.c   | 125 +
include/linux/of_irq.h |   1 +
2 files changed, 126 insertions(+)

diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index e1f6f392a4c0..a1534f947ed4 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -273,6 +273,131 @@ int of_irq_parse_raw(const __be32 *addr, struct 
of_phandle_args *out_irq)
}
EXPORT_SYMBOL_GPL(of_irq_parse_raw);

+int of_irq_domain_map(const struct irq_fwspec *in, struct irq_fwspec *out)
+{
+   char *stem_name;
+   char *cells_name, *map_name = NULL, *mask_name = NULL;
+   char *pass_name = NULL;
+   struct device_node *cur, *new = NULL;
+   const __be32 *map, *mask, *pass;
+   static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
+   static const __be32 dummy_pass[] = { [0 ... MAX_PHANDLE_ARGS] = 0 };
+   __be32 initial_match_array[MAX_PHANDLE_ARGS];
+   const __be32 *match_array = initial_match_array;
+   int i, ret, map_len, match;
+   u32 in_size, out_size;
+
+   stem_name = "";
+   cells_name = "#interrupt-cells";
+
+   ret = -ENOMEM;
+   map_name = kasprintf(GFP_KERNEL, "irqdomain%s-map", stem_name);
+   if (!map_name)
+   goto free;
+
+   mask_name = kasprintf(GFP_KERNEL, "irqdomain%s-map-mask", stem_name);
+   if (!mask_name)
+   goto free;
+
+   pass_name = kasprintf(GFP_KERNEL, "irqdomain%s-map-pass-thru", 
stem_name);
+   if (!pass_name)
+   goto free;
+
+   /* Get the #interrupt-cells property */
+   cur = to_of_node(in->fwnode);
+   ret = of_property_read_u32(cur, cells_name, _size);
+   if (ret < 0)
+   goto put;
+
+   /* Precalculate the match array - this simplifies match loop */
+   for (i = 0; i < in_size; i++)
+   initial_match_array[i] = cpu_to_be32(in->param[i]);
+
+   ret = -EINVAL;

This value...

+   /* Get the irqdomain-map property */
+   map = of_get_property(cur, map_name, _len);
+   if (!map) {
+   ret = 0;
+   goto free;
+   }
+   map_len /= sizeof(u32);
+
+   /* Get the irqdomain-map-mask property (optional) */
+   mask = of_get_property(cur, mask_name, NULL);
+   if (!mask)
+   mask = dummy_mask;
+   /* Iterate through irqdomain-map property */
+   match = 0;
+   while (map_len > (in_size + 1) && !match) {
+   /* Compare specifiers */
+   match = 1;
+   for (i = 0; i < in_size; i++, map_len--)
+   match &= !((match_array[i] ^ *map++) & mask[i]);
+
+   of_node_put(new);
+   new = of_find_node_by_phandle(be32_to_cpup(map));
+   map++;
+   map_len--;
+
+   /* Check if not found */
+   if (!new)
+   goto put;
+
+   if (!of_device_is_available(new))
+   match = 0;
+
+   ret = of_property_read_u32(new, cells_name, _size);

Gets overwritten by this, and set to 0.

+   if (ret)
+   goto put;
+
+   /* Check for malformed properties */
+   if (WARN_ON(out_size > MAX_PHANDLE_ARGS))
+   goto put;
+   

Re: [PATCH v4 06/10] dt-bindings: sdm845-pinctrl: add wakeup interrupt parent for GPIO

2019-03-18 Thread Lina Iyer

Thanks for the review Rob.

On Fri, Mar 15 2019 at 17:37 -0600, Rob Herring wrote:

On Wed, Mar 13, 2019 at 03:18:40PM -0600, Lina Iyer wrote:

SDM845 SoC has an always-on interrupt controller (PDC) with select GPIO
routed to the PDC as interrupts that can be used to wake the system up
from deep low power modes and suspend.

Cc: devicet...@vger.kernel.org
Signed-off-by: Lina Iyer 
---
 .../devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt| 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)


I still don't love this being specific to wake-up, but don't have a
better suggestion. One nit, otherwise:


I added this to interrupts.txt. I will remove this, if the documentation in
[PATCH v4 03/10] of/irq: document properties for wakeup interrupt parent
of this series works.

-- Lina


Reviewed-by: Rob Herring 



diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt 
b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
index 665aadb5ea28..f0fedbc5d41a 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
@@ -29,6 +29,11 @@ SDM845 platform.
Definition: must be 2. Specifying the pin number and flags, as defined
in 

+- wakeup-parent:
+   Usage: optional
+   Value type: 
+   Definition: A phandle to the wakeup interrupt controller for the SoC.
+
 - gpio-controller:
Usage: required
Value type: 
@@ -53,7 +58,6 @@ pin, a group, or a list of pins or groups. This configuration 
can include the
 mux function to select on those pin(s)/group(s), and various pin configuration
 parameters, such as pull-up, drive strength, etc.

-
 PIN CONFIGURATION NODES:

 The name of each subnode is not important; all subnodes should be enumerated
@@ -160,6 +164,7 @@ Example:
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+   wake-parent = <_intc>;


wakeup-parent



qup9_active: qup9-active {
mux {
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 01/10] gpio: Add support for hierarchical IRQ domains

2019-03-13 Thread Lina Iyer
From: Thierry Reding 

Hierarchical IRQ domains can be used to stack different IRQ controllers
on top of each other. One specific use-case where this can be useful is
if a power management controller has top-level controls for wakeup
interrupts. In such cases, the power management controller can be a
parent to other interrupt controllers and program additional registers
when an IRQ has its wake capability enabled or disabled.

Signed-off-by: Thierry Reding 
Signed-off-by: Lina Iyer 
---
 drivers/gpio/gpiolib.c  | 15 +++
 include/linux/gpio/driver.h |  6 ++
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d1adfdf50fb3..46ccb9b174b9 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1895,7 +1895,9 @@ static int gpiochip_add_irqchip(struct gpio_chip 
*gpiochip,
type = IRQ_TYPE_NONE;
}
 
-   gpiochip->to_irq = gpiochip_to_irq;
+   if (!gpiochip->to_irq)
+   gpiochip->to_irq = gpiochip_to_irq;
+
gpiochip->irq.default_type = type;
gpiochip->irq.lock_key = lock_key;
gpiochip->irq.request_key = request_key;
@@ -1905,9 +1907,14 @@ static int gpiochip_add_irqchip(struct gpio_chip 
*gpiochip,
else
ops = _domain_ops;
 
-   gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
-gpiochip->irq.first,
-ops, gpiochip);
+   if (gpiochip->irq.parent_domain)
+   gpiochip->irq.domain = 
irq_domain_add_hierarchy(gpiochip->irq.parent_domain,
+   0, 
gpiochip->ngpio,
+   np, ops, 
gpiochip);
+   else
+   gpiochip->irq.domain = irq_domain_add_simple(np, 
gpiochip->ngpio,
+
gpiochip->irq.first,
+ops, gpiochip);
if (!gpiochip->irq.domain)
return -EINVAL;
 
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 07cddbf45186..88ef196f96ec 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -48,6 +48,12 @@ struct gpio_irq_chip {
 */
const struct irq_domain_ops *domain_ops;
 
+   /**
+* @parent_domain:
+*
+*/
+   struct irq_domain *parent_domain;
+
/**
 * @handler:
 *
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 00/10] support wakeup capable GPIOs

2019-03-13 Thread Lina Iyer
Hi all,

This series adds support for wakeup capable GPIOs. It is based on Thierry's
hiearchical GPIO domains. This approach is based on Stephen's idea [1]. The SoC
that is used for this development is a QCOM SDM845. The current patchset is
rebased on top of 5.0 and adds documentation for the wakeup-parent and
irqdomain-map DT properties along with the the optional irqdomain-map-mask and
irqdomain-map-pass-thru properties. Also incorporating comments from Marc on
the earlier submission [2]. I cleaned up some of the change history in these
patches to match the version number with that of the submission.

The dtsi patches are based on Bjorn's changes for increased address and cell
size [3] and [4].

Kindly review the series.

Thanks,
Lina

[1]. https://lkml.org/lkml/2018/12/19/813
[2]. https://lkml.org/lkml/2019/2/22/716
[3]. https://patchwork.kernel.org/patch/10767511/
[4]. https://lkml.kernel.org/r/20190117042940.25487-2-bjorn.anders...@linaro.org

Lina Iyer (8):
  irqdomain: add bus token DOMAIN_BUS_WAKEUP
  of/irq: document properties for wakeup interrupt parent
  drivers: irqchip: add PDC irqdomain for wakeup capable GPIOs
  dt-bindings: sdm845-pinctrl: add wakeup interrupt parent for GPIO
  drivers: pinctrl: msm: setup GPIO irqchip hierarchy
  arm64: dts: qcom: add PDC interrupt controller for SDM845
  arm64: dts: qcom: setup PDC as wakeup parent for GPIOs for SDM845
  arm64: defconfig: enable PDC interrupt controller for Qualcomm SDM845

Stephen Boyd (1):
  of: irq: add helper to remap interrupts to another irqdomain

Thierry Reding (1):
  gpio: Add support for hierarchical IRQ domains

 .../interrupt-controller/interrupts.txt   |  39 +
 .../bindings/pinctrl/qcom,sdm845-pinctrl.txt  |   7 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi  |  87 ++
 arch/arm64/configs/defconfig  |   1 +
 drivers/gpio/gpiolib.c|  15 +-
 drivers/irqchip/qcom-pdc.c|  72 -
 drivers/of/irq.c  | 125 +++
 drivers/pinctrl/qcom/pinctrl-msm.c| 151 +++---
 include/linux/gpio/driver.h   |   6 +
 include/linux/irqdomain.h |   1 +
 include/linux/of_irq.h|   1 +
 include/linux/soc/qcom/irq.h  |  23 +++
 12 files changed, 497 insertions(+), 31 deletions(-)
 create mode 100644 include/linux/soc/qcom/irq.h

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v4 02/10] irqdomain: add bus token DOMAIN_BUS_WAKEUP

2019-03-13 Thread Lina Iyer
A single controller can handle normal interrupts and wake-up interrupts
independently, with a different numbering space. It is thus crucial to
allow the driver for such a controller discriminate between the two.

A simple way to do so is to tag the wake-up irqdomain with a "bus token"
that indicates the wake-up domain. This slightly abuses the notion of
bus, but also radically simplifies the design of such a driver. Between
two evils, we choose the least damaging.

Suggested-by: Stephen Boyd 
Signed-off-by: Lina Iyer 
---
Changes in v4:
- Update commit text
---
 include/linux/irqdomain.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 35965f41d7be..05055bc992ab 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -82,6 +82,7 @@ enum irq_domain_bus_token {
DOMAIN_BUS_NEXUS,
DOMAIN_BUS_IPI,
DOMAIN_BUS_FSL_MC_MSI,
+   DOMAIN_BUS_WAKEUP,
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



  1   2   3   4   5   6   7   8   9   10   >