[v3,6/6] soc: qcom: rpmh-rsc: Write CONTROL_TCS with next timer wakeup

Message ID 20221018152837.619426-7-ulf.hansson@linaro.org
State New
Headers
Series soc: qcom: Add APSS RSC to the CPU cluster PM domain |

Commit Message

Ulf Hansson Oct. 18, 2022, 3:28 p.m. UTC
  From: Maulik Shah <quic_mkshah@quicinc.com>

The next wakeup timer value needs to be set in always on domain timer
as the arch timer interrupt can not wakeup the SoC if after the deepest
CPUidle states the SoC also enters deepest low power state.

To wakeup the SoC in such scenarios the earliest wakeup time is set in
CONTROL_TCS and the firmware takes care of setting up its own timer in
always on domain with next wakeup time. The timer wakes up the RSC and
sets resources back to wake state.

Signed-off-by: Maulik Shah <quic_mkshah@quicinc.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> # SM8450
---
 drivers/soc/qcom/rpmh-internal.h |  3 ++
 drivers/soc/qcom/rpmh-rsc.c      | 61 ++++++++++++++++++++++++++++++++
 drivers/soc/qcom/rpmh.c          |  4 ++-
 3 files changed, 67 insertions(+), 1 deletion(-)
  

Comments

kernel test robot Oct. 18, 2022, 5:47 p.m. UTC | #1
Hi Ulf,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on rafael-pm/linux-next arm/for-next arm64/for-next/core clk/clk-next kvmarm/next rockchip/for-next shawnguo/for-next soc/for-next linus/master v6.1-rc1 next-20221018]
[cannot apply to xilinx-xlnx/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ulf-Hansson/soc-qcom-Add-APSS-RSC-to-the-CPU-cluster-PM-domain/20221018-233137
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20221018152837.619426-7-ulf.hansson%40linaro.org
patch subject: [PATCH v3 6/6] soc: qcom: rpmh-rsc: Write CONTROL_TCS with next timer wakeup
config: m68k-allyesconfig
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/2f9e747dca385eca0eb09df0df78572223ca9486
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Ulf-Hansson/soc-qcom-Add-APSS-RSC-to-the-CPU-cluster-PM-domain/20221018-233137
        git checkout 2f9e747dca385eca0eb09df0df78572223ca9486
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/soc/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/soc/qcom/rpmh-rsc.c: In function 'xloops_to_cycles':
>> drivers/soc/qcom/rpmh-rsc.c:160:48: warning: right shift count >= width of type [-Wshift-count-overflow]
     160 |         return (xloops * loops_per_jiffy * HZ) >> 32;
         |                                                ^~


vim +160 drivers/soc/qcom/rpmh-rsc.c

   100	
   101	/*
   102	 * Here's a high level overview of how all the registers in RPMH work
   103	 * together:
   104	 *
   105	 * - The main rpmh-rsc address is the base of a register space that can
   106	 *   be used to find overall configuration of the hardware
   107	 *   (DRV_PRNT_CHLD_CONFIG). Also found within the rpmh-rsc register
   108	 *   space are all the TCS blocks. The offset of the TCS blocks is
   109	 *   specified in the device tree by "qcom,tcs-offset" and used to
   110	 *   compute tcs_base.
   111	 * - TCS blocks come one after another. Type, count, and order are
   112	 *   specified by the device tree as "qcom,tcs-config".
   113	 * - Each TCS block has some registers, then space for up to 16 commands.
   114	 *   Note that though address space is reserved for 16 commands, fewer
   115	 *   might be present. See ncpt (num cmds per TCS).
   116	 *
   117	 * Here's a picture:
   118	 *
   119	 *  +---------------------------------------------------+
   120	 *  |RSC                                                |
   121	 *  | ctrl                                              |
   122	 *  |                                                   |
   123	 *  | Drvs:                                             |
   124	 *  | +-----------------------------------------------+ |
   125	 *  | |DRV0                                           | |
   126	 *  | | ctrl/config                                   | |
   127	 *  | | IRQ                                           | |
   128	 *  | |                                               | |
   129	 *  | | TCSes:                                        | |
   130	 *  | | +------------------------------------------+  | |
   131	 *  | | |TCS0  |  |  |  |  |  |  |  |  |  |  |  |  |  | |
   132	 *  | | | ctrl | 0| 1| 2| 3| 4| 5| .| .| .| .|14|15|  | |
   133	 *  | | |      |  |  |  |  |  |  |  |  |  |  |  |  |  | |
   134	 *  | | +------------------------------------------+  | |
   135	 *  | | +------------------------------------------+  | |
   136	 *  | | |TCS1  |  |  |  |  |  |  |  |  |  |  |  |  |  | |
   137	 *  | | | ctrl | 0| 1| 2| 3| 4| 5| .| .| .| .|14|15|  | |
   138	 *  | | |      |  |  |  |  |  |  |  |  |  |  |  |  |  | |
   139	 *  | | +------------------------------------------+  | |
   140	 *  | | +------------------------------------------+  | |
   141	 *  | | |TCS2  |  |  |  |  |  |  |  |  |  |  |  |  |  | |
   142	 *  | | | ctrl | 0| 1| 2| 3| 4| 5| .| .| .| .|14|15|  | |
   143	 *  | | |      |  |  |  |  |  |  |  |  |  |  |  |  |  | |
   144	 *  | | +------------------------------------------+  | |
   145	 *  | |                    ......                     | |
   146	 *  | +-----------------------------------------------+ |
   147	 *  | +-----------------------------------------------+ |
   148	 *  | |DRV1                                           | |
   149	 *  | | (same as DRV0)                                | |
   150	 *  | +-----------------------------------------------+ |
   151	 *  |                      ......                       |
   152	 *  +---------------------------------------------------+
   153	 */
   154	
   155	#define USECS_TO_CYCLES(time_usecs)			\
   156		xloops_to_cycles((time_usecs) * 0x10C7UL)
   157	
   158	static inline unsigned long xloops_to_cycles(unsigned long xloops)
   159	{
 > 160		return (xloops * loops_per_jiffy * HZ) >> 32;
   161	}
   162
  
Bjorn Andersson Nov. 7, 2022, 5:01 p.m. UTC | #2
On Wed, Oct 19, 2022 at 01:47:17AM +0800, kernel test robot wrote:
[..]
>    155	#define USECS_TO_CYCLES(time_usecs)			\
>    156		xloops_to_cycles((time_usecs) * 0x10C7UL)
>    157	
>    158	static inline unsigned long xloops_to_cycles(unsigned long xloops)

Any objections to me changing the type to u64 while applying the
patches?

Regards,
Bjorn

>    159	{
>  > 160		return (xloops * loops_per_jiffy * HZ) >> 32;
>    161	}
>    162
  
Ulf Hansson Nov. 8, 2022, 10:18 a.m. UTC | #3
On Mon, 7 Nov 2022 at 18:01, Bjorn Andersson <andersson@kernel.org> wrote:
>
> On Wed, Oct 19, 2022 at 01:47:17AM +0800, kernel test robot wrote:
> [..]
> >    155        #define USECS_TO_CYCLES(time_usecs)                     \
> >    156                xloops_to_cycles((time_usecs) * 0x10C7UL)
> >    157
> >    158        static inline unsigned long xloops_to_cycles(unsigned long xloops)
>
> Any objections to me changing the type to u64 while applying the
> patches?

No objections. Thanks for making the improvement!

>
> Regards,
> Bjorn
>
> >    159        {
> >  > 160                return (xloops * loops_per_jiffy * HZ) >> 32;
> >    161        }
> >    162

Kind regards
Uffe
  

Patch

diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index 7866bb1e5361..39f53586f724 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -112,6 +112,7 @@  struct rpmh_ctrlr {
  * @tcs_wait:           Wait queue used to wait for @tcs_in_use to free up a
  *                      slot
  * @client:             Handle to the DRV's client.
+ * @dev:                RSC device.
  */
 struct rsc_drv {
 	const char *name;
@@ -127,12 +128,14 @@  struct rsc_drv {
 	spinlock_t lock;
 	wait_queue_head_t tcs_wait;
 	struct rpmh_ctrlr client;
+	struct device *dev;
 };
 
 int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
 int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
 			     const struct tcs_request *msg);
 void rpmh_rsc_invalidate(struct rsc_drv *drv);
+void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv);
 
 void rpmh_tx_done(const struct tcs_request *msg, int r);
 int rpmh_flush(struct rpmh_ctrlr *ctrlr);
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 8e01697f59af..25b838bf9078 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -12,6 +12,7 @@ 
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
+#include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
@@ -25,6 +26,7 @@ 
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 
+#include <clocksource/arm_arch_timer.h>
 #include <soc/qcom/cmd-db.h>
 #include <soc/qcom/tcs.h>
 #include <dt-bindings/soc/qcom,rpmh-rsc.h>
@@ -49,6 +51,14 @@ 
 #define DRV_NCPT_MASK			0x1F
 #define DRV_NCPT_SHIFT			27
 
+/* Offsets for CONTROL TCS Registers */
+#define RSC_DRV_CTL_TCS_DATA_HI		0x38
+#define RSC_DRV_CTL_TCS_DATA_HI_MASK	0xFFFFFF
+#define RSC_DRV_CTL_TCS_DATA_HI_VALID	BIT(31)
+#define RSC_DRV_CTL_TCS_DATA_LO		0x40
+#define RSC_DRV_CTL_TCS_DATA_LO_MASK	0xFFFFFFFF
+#define RSC_DRV_CTL_TCS_DATA_SIZE	32
+
 /* Offsets for common TCS Registers, one bit per TCS */
 #define RSC_DRV_IRQ_ENABLE		0x00
 #define RSC_DRV_IRQ_STATUS		0x04
@@ -142,6 +152,14 @@ 
  *  +---------------------------------------------------+
  */
 
+#define USECS_TO_CYCLES(time_usecs)			\
+	xloops_to_cycles((time_usecs) * 0x10C7UL)
+
+static inline unsigned long xloops_to_cycles(unsigned long xloops)
+{
+	return (xloops * loops_per_jiffy * HZ) >> 32;
+}
+
 static inline void __iomem *
 tcs_reg_addr(const struct rsc_drv *drv, int reg, int tcs_id)
 {
@@ -756,6 +774,48 @@  static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv)
 	return set < max;
 }
 
+/**
+ * rpmh_rsc_write_next_wakeup() - Write next wakeup in CONTROL_TCS.
+ * @drv: The controller
+ *
+ * Writes maximum wakeup cycles when called from suspend.
+ * Writes earliest hrtimer wakeup when called from idle.
+ */
+void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv)
+{
+	ktime_t now, wakeup;
+	u64 wakeup_us, wakeup_cycles = ~0;
+	u32 lo, hi;
+
+	if (!drv->tcs[CONTROL_TCS].num_tcs || !drv->genpd_nb.notifier_call)
+		return;
+
+	/* Set highest time when system (timekeeping) is suspended */
+	if (system_state == SYSTEM_SUSPEND)
+		goto exit;
+
+	/* Find the earliest hrtimer wakeup from online cpus */
+	wakeup = dev_pm_genpd_get_next_hrtimer(drv->dev);
+
+	/* Find the relative wakeup in kernel time scale */
+	now = ktime_get();
+	wakeup = ktime_sub(wakeup, now);
+	wakeup_us = ktime_to_us(wakeup);
+
+	/* Convert the wakeup to arch timer scale */
+	wakeup_cycles = USECS_TO_CYCLES(wakeup_us);
+	wakeup_cycles += arch_timer_read_counter();
+
+exit:
+	lo = wakeup_cycles & RSC_DRV_CTL_TCS_DATA_LO_MASK;
+	hi = wakeup_cycles >> RSC_DRV_CTL_TCS_DATA_SIZE;
+	hi &= RSC_DRV_CTL_TCS_DATA_HI_MASK;
+	hi |= RSC_DRV_CTL_TCS_DATA_HI_VALID;
+
+	writel_relaxed(lo, drv->base + RSC_DRV_CTL_TCS_DATA_LO);
+	writel_relaxed(hi, drv->base + RSC_DRV_CTL_TCS_DATA_HI);
+}
+
 /**
  * rpmh_rsc_cpu_pm_callback() - Check if any of the AMCs are busy.
  * @nfb:    Pointer to the notifier block in struct rsc_drv.
@@ -1035,6 +1095,7 @@  static int rpmh_rsc_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&drv->client.batch_cache);
 
 	dev_set_drvdata(&pdev->dev, drv);
+	drv->dev = &pdev->dev;
 
 	ret = devm_of_platform_populate(&pdev->dev);
 	if (ret && pdev->dev.pm_domain) {
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 01765ee9cdfb..3a53ed99d03c 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -450,7 +450,7 @@  int rpmh_flush(struct rpmh_ctrlr *ctrlr)
 
 	if (!ctrlr->dirty) {
 		pr_debug("Skipping flush, TCS has latest data.\n");
-		goto exit;
+		goto write_next_wakeup;
 	}
 
 	/* Invalidate the TCSes first to avoid stale data */
@@ -479,6 +479,8 @@  int rpmh_flush(struct rpmh_ctrlr *ctrlr)
 
 	ctrlr->dirty = false;
 
+write_next_wakeup:
+	rpmh_rsc_write_next_wakeup(ctrlr_to_drv(ctrlr));
 exit:
 	spin_unlock(&ctrlr->cache_lock);
 	return ret;