drivers/qcom: add RPMH communication support
cover drivers/qcom: add RPMH communication support
Hi,
This set of patches add the ability for platform drivers to make use of shared resources in newer Qualcomm SoCs like SDM845. Resources that are shared between different processors in a SoC are generally controlled by a dedicated remote processor. The remote processor (Resource Power Manager or RPM in previous QCOM SoCs) receives requests for resource state from other processors using the shared resource, aggregates the request and applies the result on the shared resource. SDM845 advances this concept and uses h/w (hardened I/P) blocks for aggregating requests and applying the result on the resource. The resources could be clocks, regulators or bandwidth requests for buses. This new architecture is called RPM-hardened or RPMH in short.
Since this communication mechanism is completely hardware driven without a processor intervention on the remote end, existing mechanisms like RPM-SMD are no longer useful. Also, there is no serialization of data or is data is written to a shared memory in this new format. The data used is different, unsigned 32 bits are used for representing an address, data and header. Each resource's property is a unique u32 address and have pre-defined set of property specific valid values. A request that comprises of <header, addr, data> is sent by writing to a set of registers from Linux and transmitted to the remote slave through an internal bus. The remote end aggregates this request along with requests from other processors for the <addr> and applies the result.
The hardware block that houses this functionality is called Resource State Coordinator or RSC. Inside the RSC are set of slots for sending RPMH requests called Trigger Commands Sets (TCS). The set of patches are for writing the requests into these TCSes and sending them to hardened IP blocks.
The driver design is split into two components. The RSC driver housed in rpmh-rsc.c and the set of library functions in rpmh.c that frame the request and transmit it using the controller. This first set of patches allow a simple synchronous request to be made by the platform drivers. Future patches will add more functionality that cater to complex drivers and use cases.
Thanks,
Lina
Lina Iyer (4):
drivers: qcom: rpmh-rsc: add RPMH controller for QCOM SoCs
dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs
drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
drivers: qcom: rpmh: add RPMH helper functions
.../devicetree/bindings/arm/msm/rpmh-rsc.txt | 134 ++++ drivers/soc/qcom/Kconfig | 7 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/rpmh-internal.h | 26 + drivers/soc/qcom/rpmh-rsc.c | 686 +++++++++++++++++++++ drivers/soc/qcom/rpmh.c | 264 ++++++++ include/dt-bindings/soc/qcom,rpmh-rsc.h | 16 + include/soc/qcom/rpmh.h | 41 ++ include/soc/qcom/tcs.h | 38 ++ include/trace/events/rpmh.h | 89 +++ 10 files changed, 1302 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt create mode 100644 drivers/soc/qcom/rpmh-internal.h create mode 100644 drivers/soc/qcom/rpmh-rsc.c create mode 100644 drivers/soc/qcom/rpmh.c create mode 100644 include/dt-bindings/soc/qcom,rpmh-rsc.h create mode 100644 include/soc/qcom/rpmh.h create mode 100644 include/soc/qcom/tcs.h create mode 100644 include/trace/events/rpmh.h
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/4 drivers: qcom: rpmh-rsc: add RPMH controller for QCOM SoCs
Add controller driver for QCOM SoCs that have hardware based shared resource management. The hardware IP known as RSC (Resource State Coordinator) houses multiple Direct Resource Voter (DRV) for different execution levels. A DRV is a unique voter on the state of a shared resource. A Trigger Control Set (TCS) is a bunch of slots that can house multiple resource state requests, that when triggered will issue those requests through an internal bus to the Resource Power Manager Hardened (RPMH) blocks. These hardware blocks are capable of adjusting clocks, voltages etc. The resource state request from a DRV are aggregated along with state requests from other processors in the SoC and the aggregate value is applied on the resource.
Some important aspects of the RPMH communication -
- Requests are <addr, value> with some header information
- Multiple requests (upto 16) may be sent through a TCS, at a time
- Requests in a TCS are sent in sequence
- Requests may be fire-n-forget or completion (response expected)
- Multiple TCS from the same DRV may be triggered simultaneously
- Cannot send a request if another reques for the same addr is in progress from the same DRV
- When all the requests from a TCS are complete, an IRQ is raised
- The IRQ handler needs to clear the TCS before it is available for reuse
- TCS configuration is specific to a DRV
- Platform drivers may use DRV from different RSCs to make requests
Resource state requests made when CPUs are active are called 'active' state requests. Requests made when all the CPUs are powered down (idle state) are called 'sleep' state requests. They are matched by a corresponding 'wake' state requests which puts the resources back in to previously requested active state before resuming any CPU. TCSes are dedicated for each type of requests. Control TCS are used to provide specific information to the controller.
Only active requests are currently supported by the driver.
--- drivers/soc/qcom/Kconfig | 7 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/rpmh-internal.h | 24 ++ drivers/soc/qcom/rpmh-rsc.c | 674 ++++++++++++++++++++++++++++++++ include/dt-bindings/soc/qcom,rpmh-rsc.h | 16 + include/soc/qcom/tcs.h | 38 ++ 6 files changed, 760 insertions(+) create mode 100644 drivers/soc/qcom/rpmh-internal.h create mode 100644 drivers/soc/qcom/rpmh-rsc.c create mode 100644 include/dt-bindings/soc/qcom,rpmh-rsc.h create mode 100644 include/soc/qcom/tcs.h
drivers/soc/qcom/Kconfig +7 -0
@@ -104,4 +104,11 @@ config QCOM_COMMAND_DB Command DB queries shared memory by key string for shared system resources +config QCOM_RPMH + bool "Qualcomm RPM-Hardened (RPMH) Communication" + depends on ARCH_QCOM && OF + help + Support for communication with the hardened-RPM blocks in + Qualcomm Technologies Inc (QTI) SoCs. + endmenu
drivers/soc/qcom/Makefile +1 -0
@@ -11,3 +11,4 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o +obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o
drivers/soc/qcom/rpmh-internal.h new file +24 -0
@@ -0,0 +1,24 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + + +#ifndef __RPM_INTERNAL_H__ +#define __RPM_INTERNAL_H__ + +#include <soc/qcom/tcs.h> + +struct rsc_drv ; + +int rpmh_rsc_send_data (struct rsc_drv *drv,struct tcs_mbox_msg *msg); + +#endif /* __RPM_INTERNAL_H__ */
drivers/soc/qcom/rpmh-rsc.c new file +674 -0
674 lines not on this page · raw message
include/dt-bindings/soc/qcom,rpmh-rsc.h new file +16 -0
@@ -0,0 +1,16 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#define SLEEP_TCS 0 +#define WAKE_TCS 1 +#define ACTIVE_TCS 2 +#define CONTROL_TCS 3
include/soc/qcom/tcs.h new file +38 -0
@@ -0,0 +1,38 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef __SOC_QCOM_TCS_H__ +#define __SOC_QCOM_TCS_H__ + +#define MAX_RPMH_PAYLOAD 16 + +struct tcs_cmd { +u32 addr;/* slv_id:18:16 | offset:0:15 */ +u32 data;/* data for resource (or read response) */ +bool complete;/* wait for completion before sending next */ +}; + +enum rpmh_state { +RPMH_ACTIVE_ONLY_STATE ,/* Active only (= AMC) */ +RPMH_WAKE_ONLY_STATE ,/* Wake only */ +RPMH_SLEEP_STATE ,/* Sleep */ +}; + +struct tcs_mbox_msg { +enum rpmh_state state;/* request state */ +bool is_complete;/* wait for resp from accelerator */ +u32 num_payload;/* Limited to MAX_RPMH_PAYLOAD in one msg */ +struct tcs_cmd *payload;/* array of tcs_cmds */ +}; + +#endif /* __SOC_QCOM_TCS_H__ */
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
A message that is not in the archive (sent off-list or not yet received): 20180119000157.7380-2-ilina-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
Re: [PATCH 1/4] drivers: qcom: rpmh-rsc: add RPMH controller for QCOM SoCs
Quoted 8 lines · Lina Iyer
drivers/soc/qcom/rpmh-rsc.c new file +2
-0@@ -0,0 +1,674 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +*
drivers/soc/qcom/rpmh-rsc.c line 12
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/
Please use SPDX headers for new files.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */
drivers/soc/qcom/rpmh-rsc.c line 23
Quoted 11 lines
drivers/soc/qcom/rpmh-rsc.c new file +11
-0+ +#define pr_fmt (fmt) "%s " fmt, KBUILD_MODNAME + +#include <linux/atomic.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h>
Unused?
Quoted 73 lines
drivers/soc/qcom/rpmh-rsc.c new file +73
-0+#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include <asm-generic/io.h> +#include <soc/qcom/tcs.h> +#include <dt-bindings/soc/qcom,rpmh-rsc.h> + +#include "rpmh-internal.h" + +#define MAX_CMDS_PER_TCS 16 +#define MAX_TCS_PER_TYPE 3 + +#define RSC_DRV_TCS_OFFSET 672 +#define RSC_DRV_CMD_OFFSET 20 + +/* DRV Configuration Information Register */ +#define DRV_PRNT_CHLD_CONFIG 0x0C +#define DRV_NUM_TCS_MASK 0x3F +#define DRV_NUM_TCS_SHIFT 6 +#define DRV_NCPT_MASK 0x1F +#define DRV_NCPT_SHIFT 27 + +/* Register offsets */ +#define RSC_DRV_IRQ_ENABLE 0x00 +#define RSC_DRV_IRQ_STATUS 0x04 +#define RSC_DRV_IRQ_CLEAR 0x08 +#define RSC_DRV_CMD_WAIT_FOR_CMPL 0x10 +#define RSC_DRV_CONTROL 0x14 +#define RSC_DRV_STATUS 0x18 +#define RSC_DRV_CMD_ENABLE 0x1C +#define RSC_DRV_CMD_MSGID 0x30 +#define RSC_DRV_CMD_ADDR 0x34 +#define RSC_DRV_CMD_DATA 0x38 +#define RSC_DRV_CMD_STATUS 0x3C +#define RSC_DRV_CMD_RESP_DATA 0x40 + +#define TCS_AMC_MODE_ENABLE BIT(16) +#define TCS_AMC_MODE_TRIGGER BIT(24) + +/* TCS CMD register bit mask */ +#define CMD_MSGID_LEN 8 +#define CMD_MSGID_RESP_REQ BIT(8) +#define CMD_MSGID_WRITE BIT(16) +#define CMD_STATUS_ISSUED BIT(8) +#define CMD_STATUS_COMPL BIT(16) + +#define TCS_TYPE_NR 4 +#define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR) + +struct rsc_drv ; + +/** +* tcs_response: Response object for a request +* +* @drv: the controller +* @msg: the request for this response +* @m: the tcs identifier +* @err: error reported in the response +* @list: link list object. +*/ +struct tcs_response { +struct rsc_drv *drv; +struct tcs_mbox_msg *msg; +u32 m; +int err; +struct list_head list; +}; + +/** +* tcs_mbox: group of TCSes for a request state
drivers/soc/qcom/rpmh-rsc.c line 106
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+* +* @type: type of the TCS in this group - active, sleep, wake +* @tcs_mask: mask of the TCSes relative to all the TCSes in the RSC +* @tcs_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 +* @tcs_lock: lock for synchronizing this TCS writes +* @responses: response objects for requests sent from each TCS +*/ +struct tcs_mbox {
struct tcs_group ?
Quoted 17 lines
drivers/soc/qcom/rpmh-rsc.c new file +17
-0+struct rsc_drv *drv; +int type; +u32 tcs_mask; +u32 tcs_offset; +int num_tcs; +int ncpt; +spinlock_t tcs_lock; +struct tcs_response *responses[MAX_TCS_PER_TYPE ]; +}; + +/** +* rsc_drv: the RSC controller +* +* @pdev: platform device of this controller +* @name: controller identifier +* @base: start address of the controller +* @reg_base: start address of the registers in this controller
drivers/soc/qcom/rpmh-rsc.c line 133
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+* @drv_id: instance id in the controller (DRV) +* @num_tcs: number of TCSes in this DRV +* @tasklet: handle responses, off-load work from IRQ handler +* @response_pending: list of responses that needs to be sent to caller +* @tcs: TCS groups +* @tcs_in_use: s/w state of the TCS +* @drv_lock: synchronize state of the controller +*/ +struct rsc_drv { +struct platform_device *pdev;
This is not used outside rpmh_rsc_probe() and I presume you would like to be able to use it for dev_prints(), if so store the device * instead.
drivers/soc/qcom/rpmh-rsc.c line 137
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+const char *name; +void __iomem *base; +void __iomem *reg_base; +int drv_id;
@base and @drv_id are local to rpmh_rsc_probe(), so you can make it them local variables.
drivers/soc/qcom/rpmh-rsc.c line 142
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+int num_tcs; +struct tasklet_struct tasklet; +struct list_head response_pending; +struct tcs_mbox tcs[TCS_TYPE_NR ]; +atomic_t tcs_in_use[MAX_TCS_NR ];
Does this really need to be an atomic_t? Seems like it's protected by the drv_lock.
drivers/soc/qcom/rpmh-rsc.c line 146
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+spinlock_t drv_lock; +}; + +static inline struct tcs_mbox *get_tcs_from_index (struct rsc_drv *drv,int m)
get_tcs_group_by_index(), or maybe even get_tcs_group_by_tcs()? To clarify that this resolves a group and not a single tcs.
Also, please drop the "inline".
drivers/soc/qcom/rpmh-rsc.c line 153
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c new file +7
-0+{ +struct tcs_mbox *tcs =NULL ; +int i; + +for (i =0 ; i < drv->num_tcs; i++) { + tcs = &drv->tcs[i]; +if (tcs->tcs_mask & (u32 )BIT (m))
I don't think you need this cast.
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+break ; + } + +if (i == drv->num_tcs) { +WARN (1 ,"Incorrect TCS index %d" , m); + tcs =NULL ; + } + +return tcs; +}
drivers/soc/qcom/rpmh-rsc.c line 173
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ +static struct tcs_response *setup_response (struct rsc_drv *drv, +struct tcs_mbox_msg *msg,int m) +{ +struct tcs_response *resp; +struct tcs_mbox *tcs; + + resp =kcalloc (1 ,sizeof (*resp),GFP_ATOMIC ); +if (!resp) +return ERR_PTR (-ENOMEM );
Rather than allocating a response for each write request and freeing it in the tasklet I think you should just allocate MAX_TCS_PER_TYPE responses when you're probing the driver.
drivers/soc/qcom/rpmh-rsc.c line 186
Quoted 13 lines
drivers/soc/qcom/rpmh-rsc.c new file +13
-0+ + resp->drv = drv; + resp->msg = msg; + resp->err =0 ; + + tcs =get_tcs_from_index (drv, m); +if (!tcs) +return ERR_PTR (-EINVAL ); + +/* +* We should have been called from a TCS-type locked context, and +* we overwrite the previously saved response. +*/
I assume that this overwrite wouldn't happen because we're only writing to the tcs if it's not in use? Wouldn't overwriting a valid response lead to us leaking the previously allocated resp?
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ tcs->responses[m - tcs->tcs_offset] = resp; + +return resp; +} + +static void free_response (struct tcs_response *resp) +{ +kfree (resp); +} +
drivers/soc/qcom/rpmh-rsc.c line 206
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+static inline struct tcs_response *get_response (struct rsc_drv *drv,u32 m) +{ +struct tcs_mbox *tcs =get_tcs_from_index (drv, m); + +return tcs->responses[m - tcs->tcs_offset]; +} + +static inline u32 read_drv_config (void __iomem *base) +{ +return le32_to_cpu (readl_relaxed (base +DRV_PRNT_CHLD_CONFIG ));
readl_relaxed() on arm64 is defined as le32_to_cpu(__raw_readl(c)), so I would suggest that you drop the le32_to_cpu() and just inline your readl() directly in rpmh_rsc_probe().
drivers/soc/qcom/rpmh-rsc.c line 210
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+} + +static inline u32 read_tcs_reg (void __iomem *base,int reg,int m,int n) +{
I would suggest that you pass the rsc_drv to these functions, so that it's obvious which "base" we're operating on here.
drivers/soc/qcom/rpmh-rsc.c line 212
Quoted 2 lines
drivers/soc/qcom/rpmh-rsc.c new file +2
-0+return le32_to_cpu (readl_relaxed (base + reg + +RSC_DRV_TCS_OFFSET * m +RSC_DRV_CMD_OFFSET * n));
No le32_to_cpu()
drivers/soc/qcom/rpmh-rsc.c line 219
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c new file +7
-0+} + +static inline void write_tcs_reg (void __iomem *base,int reg,int m,int n, +u32 data) +{ +writel_relaxed (cpu_to_le32 (data), base + reg + +RSC_DRV_TCS_OFFSET * m +RSC_DRV_CMD_OFFSET * n);
As with readl, writel does cpu_to_le32()
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c new file +9
-0+} + +static inline void write_tcs_reg_sync (void __iomem *base,int reg,int m,int n, +u32 data) +{ + do { + write_tcs_reg(base, reg, m, n, data); + if (data == read_tcs_reg(base, reg, m, n)) + break;
drivers/soc/qcom/rpmh-rsc.c line 238
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+udelay (1 ); + }while (1 ); +} + +static inline bool tcs_is_free (struct rsc_drv *drv,int m) +{ +void __iomem *base = drv->reg_base; + +return read_tcs_reg (base,RSC_DRV_STATUS , m,0 ) && + !atomic_read (&drv->tcs_in_use[m]);
If you flip these conditions around you won't do the io access when tcs_in_use[m].
What are the cases when tcs_in_use will tell you that the tcs is free, but the hardware will say it's not?
Quoted 26 lines
drivers/soc/qcom/rpmh-rsc.c new file +26
-0+} + +static inline struct tcs_mbox *get_tcs_of_type (struct rsc_drv *drv,int type) +{ +int i; +struct tcs_mbox *tcs; + +for (i =0 ; i <TCS_TYPE_NR ; i++) +if (type == drv->tcs[i].type) +break ; + +if (i ==TCS_TYPE_NR ) +return ERR_PTR (-EINVAL ); + + tcs = &drv->tcs[i]; +if (!tcs->num_tcs) +return ERR_PTR (-EINVAL ); + +return tcs; +} + +static inline struct tcs_mbox *get_tcs_for_msg (struct rsc_drv *drv, +struct tcs_mbox_msg *msg) +{ +int type =-1 ; +
drivers/soc/qcom/rpmh-rsc.c line 274
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+switch (msg->state) { +case RPMH_ACTIVE_ONLY_STATE : + type =ACTIVE_TCS ; +break ; +default : +break ; + } + +if (type <0 ) +return ERR_PTR (-EINVAL );
afaict you can put this return in the default case.
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+ +return get_tcs_of_type (drv, type); +} + +static inline void send_tcs_response (struct tcs_response *resp) +{
drivers/soc/qcom/rpmh-rsc.c line 290
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+struct rsc_drv *drv = resp->drv; +unsigned long flags; + +spin_lock_irqsave (&drv->drv_lock, flags); +INIT_LIST_HEAD (&resp->list); +list_add_tail (&resp->list, &drv->response_pending); +spin_unlock_irqrestore (&drv->drv_lock, flags); + +tasklet_schedule (&drv->tasklet); +}
Is there any particular reason why this uses a tasklet, instead of just handling the tx_done event from the interrupt handler directly?
Quoted 13 lines
drivers/soc/qcom/rpmh-rsc.c new file +13
-0+ +/** +* tcs_irq_handler: TX Done interrupt handler +*/ +static irqreturn_t tcs_irq_handler (int irq,void *p) +{ +struct rsc_drv *drv = p; +void __iomem *base = drv->reg_base; +int m, i; +u32 irq_status, sts; +struct tcs_response *resp; +struct tcs_cmd *cmd; +int err;
drivers/soc/qcom/rpmh-rsc.c line 313
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ + irq_status =read_tcs_reg (base,RSC_DRV_IRQ_STATUS ,0 ,0 ); + +for (m =0 ; m < drv->num_tcs; m++) { +if (!(irq_status & (u32 )BIT (m))) +continue ; + + err =0 ; + resp =get_response (drv, m); +if (!resp) {
This conditional section dereferences resp, so I suspect that the conditional is backwards.
drivers/soc/qcom/rpmh-rsc.c line 323
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+for (i =0 ; i < resp->msg->num_payload; i++) { + cmd = &resp->msg->payload[i]; + sts =read_tcs_reg (base,RSC_DRV_CMD_STATUS , + m, i); +if ((!(sts &CMD_STATUS_ISSUED )) || + ((resp->msg->is_complete || + cmd->complete) && + (!(sts &CMD_STATUS_COMPL )))) { + resp->err = -EIO ; +break ;
As this completes the response, aren't we leaking the tcs_in_use?
Quoted 16 lines
drivers/soc/qcom/rpmh-rsc.c new file +16
-0+ } + } + } + +write_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ,0 ); +write_tcs_reg (base,RSC_DRV_IRQ_CLEAR ,0 ,0 ,BIT (m)); +atomic_set (&drv->tcs_in_use[m],0 ); + +if (resp) { + resp->err = err; +send_tcs_response (resp); + } + } + +return IRQ_HANDLED ; +}
drivers/soc/qcom/rpmh-rsc.c line 349
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ +/** +* tcs_notify_tx_done: TX Done for requests that got a response +* +* @data: the tasklet argument +* +* Tasklet function to notify MBOX that we are done with the request. +* Handles all pending reponses whenever run. +*/ +static void tcs_notify_tx_done (unsigned long data)
I think you should drop the tasklet and just invoke the handling of responses directly from the irq context.
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c new file +9
-0+{ +struct rsc_drv *drv = (struct rsc_drv *)data; +struct tcs_response *resp; +unsigned long flags; +int err; + + do { + spin_lock_irqsave(&drv->drv_lock, flags); + if (list_empty(&drv->response_pending)) {
drivers/soc/qcom/rpmh-rsc.c line 368
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+spin_unlock_irqrestore (&drv->drv_lock, flags); +break ; + } + resp =list_first_entry (&drv->response_pending, + struct tcs_response, list); +list_del (&resp->list); +spin_unlock_irqrestore (&drv->drv_lock, flags); + err = resp->err; +free_response (resp); + }while (1 );
Use for (;;) {} or while (1) {}, rather than do {} while(1)
Quoted 64 lines
drivers/soc/qcom/rpmh-rsc.c new file +64
-0+} + +static void __tcs_buffer_write (struct rsc_drv *drv,int m,int n, +struct tcs_mbox_msg *msg) +{ +void __iomem *base = drv->reg_base; +u32 msgid, cmd_msgid =0 ; +u32 cmd_enable =0 ; +u32 cmd_complete; +struct tcs_cmd *cmd; +int i; + + cmd_msgid =CMD_MSGID_LEN ; + cmd_msgid |= (msg->is_complete) ?CMD_MSGID_RESP_REQ :0 ; + cmd_msgid |=CMD_MSGID_WRITE ; + + cmd_complete =read_tcs_reg (base,RSC_DRV_CMD_WAIT_FOR_CMPL , m,0 ); + +for (i =0 ; i < msg->num_payload; i++) { + cmd = &msg->payload[i]; + cmd_enable |=BIT (n + i); + cmd_complete |= cmd->complete << (n + i); + msgid = cmd_msgid; + msgid |= (cmd->complete) ?CMD_MSGID_RESP_REQ :0 ; +write_tcs_reg (base,RSC_DRV_CMD_MSGID , m, n + i, msgid); +write_tcs_reg (base,RSC_DRV_CMD_ADDR , m, n + i, cmd->addr); +write_tcs_reg (base,RSC_DRV_CMD_DATA , m, n + i, cmd->data); + } + +write_tcs_reg (base,RSC_DRV_CMD_WAIT_FOR_CMPL , m,0 , cmd_complete); + cmd_enable |=read_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ); +write_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 , cmd_enable); +} + +static void __tcs_trigger (struct rsc_drv *drv,int m) +{ +void __iomem *base = drv->reg_base; +u32 enable; + +/* +* HW req: Clear the DRV_CONTROL and enable TCS again +* While clearing ensure that the AMC mode trigger is cleared +* and then the mode enable is cleared. +*/ + enable =read_tcs_reg (base,RSC_DRV_CONTROL , m,0 ); + enable &= ~TCS_AMC_MODE_TRIGGER ; +write_tcs_reg_sync (base,RSC_DRV_CONTROL , m,0 , enable); + enable &= ~TCS_AMC_MODE_ENABLE ; +write_tcs_reg_sync (base,RSC_DRV_CONTROL , m,0 , enable); + +/* Enable the AMC mode on the TCS and then trigger the TCS */ + enable =TCS_AMC_MODE_ENABLE ; +write_tcs_reg_sync (base,RSC_DRV_CONTROL , m,0 , enable); + enable |=TCS_AMC_MODE_TRIGGER ; +write_tcs_reg_sync (base,RSC_DRV_CONTROL , m,0 , enable); +} + +static int check_for_req_inflight (struct rsc_drv *drv,struct tcs_mbox *tcs, +struct tcs_mbox_msg *msg) +{ +u32 curr_enabled, addr; +int i, j, k; +void __iomem *base = drv->reg_base; +int m = tcs->tcs_offset;
drivers/soc/qcom/rpmh-rsc.c line 442
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ +for (i =0 ; i < tcs->num_tcs; i++, m++) { +if (tcs_is_free (drv, m)) +continue ; + + curr_enabled =read_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ); + +for (j =0 ; j <MAX_CMDS_PER_TCS ; j++) { +if (!(curr_enabled & (u32 )BIT (j))) +continue ;
Consider using for_each_set_bit() here.
Quoted 66 lines
drivers/soc/qcom/rpmh-rsc.c new file +66
-0+ + addr =read_tcs_reg (base,RSC_DRV_CMD_ADDR , m, j); +for (k =0 ; k < msg->num_payload; k++) { +if (addr == msg->payload[k].addr) +return -EBUSY ; + } + } + } + +return 0 ; +} + +static int find_free_tcs (struct tcs_mbox *tcs) +{ +int m; + +for (m =0 ; m < tcs->num_tcs; m++) +if (tcs_is_free (tcs->drv, tcs->tcs_offset + m)) +break ; + +return (m != tcs->num_tcs) ? m : -EBUSY ; +} + +static int tcs_mbox_write (struct rsc_drv *drv,struct tcs_mbox_msg *msg) +{ +struct tcs_mbox *tcs; +int m; +struct tcs_response *resp =NULL ; +unsigned long flags; +int ret =0 ; + + tcs =get_tcs_for_msg (drv, msg); +if (IS_ERR (tcs)) +return PTR_ERR (tcs); + +spin_lock_irqsave (&tcs->tcs_lock, flags); + m =find_free_tcs (tcs); +if (m <0 ) { + ret = m; + goto done_write; + } + +/* +* The h/w does not like if we send a request to the same address, +* when one is already in-flight or bring processed. +*/ + ret =check_for_req_inflight (drv, tcs, msg); +if (ret) + goto done_write; + + resp =setup_response (drv, msg, m); +if (IS_ERR_OR_NULL (resp)) { + ret =PTR_ERR (resp); + goto done_write; + } + resp->m = m; + +atomic_set (&drv->tcs_in_use[m],1 ); +__tcs_buffer_write (drv, m,0 , msg); +__tcs_trigger (drv, m); + +done_write: +spin_unlock_irqrestore (&tcs->tcs_lock, flags); +return ret; +} +
drivers/soc/qcom/rpmh-rsc.c line 518
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+/** +* rpmh_rsc_send_data: Validate the incoming message and write to the +* appropriate TCS block. +* +* @drv: the controller +* @msg: the data to be sent +* +* Returns a negative error for invalid message structure and invalid +* message combination, -EBUSY if there is an other active request for +* the channel in process, otherwise bubbles up internal error.
Kernel-doc style is "Return: a negative..."
The function never returns -EBUSY, as you're looping while this is being returned.
Also, it would be nice if the doc mentions that 0 is returned on success, so perhaps just "Return: 0 on success, negative errno on error"?
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+*/ +int rpmh_rsc_send_data (struct rsc_drv *drv,struct tcs_mbox_msg *msg) +{ +int ret =0 ; +
drivers/soc/qcom/rpmh-rsc.c line 533
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+if (!msg || !msg->payload || !msg->num_payload || + msg->num_payload >MAX_RPMH_PAYLOAD ) +return -EINVAL ; + + do { + ret = tcs_mbox_write(drv, msg); + if (ret == -EBUSY) { + pr_info_ratelimited( + "TCS Busy, retrying RPMH message send: addr=0x%x\n", + msg->payload[0].addr);
Indent wrapped lines to the start parenthesis.
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+udelay (10 ); + } + }while (ret == -EBUSY ); + +return ret;
drivers/soc/qcom/rpmh-rsc.c line 548
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+} +EXPORT_SYMBOL (rpmh_rsc_send_data); + +static int rpmh_rsc_probe (struct platform_device *pdev) +{ +struct device_node *dn = pdev->dev.of_node; +struct rsc_drv *drv; +struct tcs_mbox *tcs; +int irq; +u32 val[8 ] = {0 };
8 here should be TCS_TYPE_NR * 2, but I like Tomas(?) suggestion in the PDC driver of representing arrays of tuples like this as a structured type.
Quoted 45 lines
drivers/soc/qcom/rpmh-rsc.c new file +45
-0+int st =0 ; +int i, ret, nelem; +u32 config, max_tcs, ncpt; +int tcs_type_count[TCS_TYPE_NR ] = {0 }; +struct resource *res; + + drv =devm_kzalloc (&pdev->dev,sizeof (*drv),GFP_KERNEL ); +if (!drv) +return -ENOMEM ; + + ret =of_property_read_u32 (dn,"qcom,drv-id" , &drv->drv_id); +if (ret) +return ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -EINVAL ; + drv->base =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (drv->base)) +return PTR_ERR (drv->base); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (!res) +return -EINVAL ; + drv->reg_base =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (drv->reg_base)) +return PTR_ERR (drv->reg_base); + + config =read_drv_config (drv->base); + max_tcs = config & (DRV_NUM_TCS_MASK << + (DRV_NUM_TCS_SHIFT * drv->drv_id)); + max_tcs = max_tcs >> (DRV_NUM_TCS_SHIFT * drv->drv_id); + ncpt = config & (DRV_NCPT_MASK <<DRV_NCPT_SHIFT ); + ncpt = ncpt >>DRV_NCPT_SHIFT ; + + nelem =of_property_count_elems_of_size (dn,"qcom,tcs-config" , +sizeof (u32)); +if (!nelem || (nelem %2 ) || (nelem >2 *TCS_TYPE_NR )) +return -EINVAL ; + + ret =of_property_read_u32_array (dn,"qcom,tcs-config" , val, nelem); +if (ret) +return ret; + +for (i =0 ; i < (nelem /2 ); i++) {
drivers/soc/qcom/rpmh-rsc.c line 603
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+if (val[2 * i] >=TCS_TYPE_NR ) +return -EINVAL ; + tcs_type_count[val[2 * i]]++; +if (tcs_type_count[val[2 * i]] >1 ) +return -EINVAL ; + } + +for (i =0 ; i <ARRAY_SIZE (tcs_type_count); i++) +if (!tcs_type_count[i]) +return -EINVAL ;
I think it's better if replace these two loops by adding a check in below loop to ensure that tcs->drv is NULL and that tcs->type is valid and then follow up with a loop checking that each drv->tcs was initialized.
That way you don't need to do the counting of the various types.
Quoted 36 lines
drivers/soc/qcom/rpmh-rsc.c new file +36
-0+ +for (i =0 ; i < (nelem /2 ); i++) { + tcs = &drv->tcs[val[2 * i]]; + tcs->drv = drv; + tcs->type = val[2 * i]; + tcs->num_tcs = val[2 * i +1 ]; + tcs->ncpt = ncpt; +spin_lock_init (&tcs->tcs_lock); + +if (tcs->num_tcs <=0 || tcs->type ==CONTROL_TCS ) +continue ; + +if (tcs->num_tcs >MAX_TCS_PER_TYPE || + st + tcs->num_tcs > max_tcs || + st + tcs->num_tcs >=8 *sizeof (tcs->tcs_mask)) +return -EINVAL ; + + tcs->tcs_mask = ((1 << tcs->num_tcs) -1 ) << st; + tcs->tcs_offset = st; + st += tcs->num_tcs; + } + + drv->num_tcs = st; + drv->pdev = pdev; +INIT_LIST_HEAD (&drv->response_pending); +spin_lock_init (&drv->drv_lock); +tasklet_init (&drv->tasklet, tcs_notify_tx_done, (unsigned long )drv); + + drv->name =of_get_property (pdev->dev.of_node,"label" ,NULL ); +if (!drv->name) + drv->name =dev_name (&pdev->dev); + + irq =of_irq_get (dn,0 ); +if (irq <0 ) +return irq; +
drivers/soc/qcom/rpmh-rsc.c line 649
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ ret =devm_request_irq (&pdev->dev, irq, tcs_irq_handler, +IRQF_TRIGGER_HIGH |IRQF_NO_SUSPEND , drv->name, drv); +if (ret) +return ret; + +write_tcs_reg (drv->reg_base,RSC_DRV_IRQ_ENABLE ,0 ,0 , + drv->tcs[ACTIVE_TCS ].tcs_mask); + +for (i =0 ; i <ARRAY_SIZE (drv->tcs_in_use); i++) +atomic_set (&drv->tcs_in_use[i],0 );
Perhaps do this before requesting the irq? If nothing else that saves future readers from wondering if it makes any difference...
drivers/soc/qcom/rpmh-rsc.c line 651
Quoted 2 lines
drivers/soc/qcom/rpmh-rsc.c new file +2
-0+ +dev_set_drvdata (&pdev->dev, drv);
This isn't used until the next patch, so move it there to clarify its purpose.
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+ +return of_platform_populate (pdev->dev.of_node,NULL ,NULL , &pdev->dev); +} + +static const struct of_device_id rpmh_drv_match[] = {
drivers/soc/qcom/rpmh-rsc.c line 666
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ { .compatible = "qcom,rpmh-rsc", }, + { } +}; +MODULE_DEVICE_TABLE (of, rpm_drv_match); + +static struct platform_driver rpmh_driver = { + .probe = rpmh_rsc_probe, + .driver = { + .name =KBUILD_MODNAME , + .of_match_table = rpmh_drv_match,
As we don't want to handle unbind, add:
.suppress_bind_attrs = true,
Quoted 49 lines
drivers/soc/qcom/rpmh-rsc.c new file +8
-0+ }, +}; + +static int __init rpmh_driver_init (void ) +{ +return platform_driver_register (&rpmh_driver); +} +arch_initcall (rpmh_driver_init);include/dt-bindings/soc/qcom,rpmh-rsc.h new file +16
-0@@ -0,0 +1,16 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#define SLEEP_TCS 0 +#define WAKE_TCS 1 +#define ACTIVE_TCS 2 +#define CONTROL_TCS 3include/soc/qcom/tcs.h new file +13
-0@@ -0,0 +1,38 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ +
include/soc/qcom/tcs.h line 23
Quoted 10 lines
include/soc/qcom/tcs.h new file +10
-0+#ifndef __SOC_QCOM_TCS_H__ +#define __SOC_QCOM_TCS_H__ + +#define MAX_RPMH_PAYLOAD 16 + +struct tcs_cmd { +u32 addr;/* slv_id:18:16 | offset:0:15 */ +u32 data;/* data for resource (or read response) */ +bool complete;/* wait for completion before sending next */ +};
I think you should use kernel-doc to describe the structs.
include/soc/qcom/tcs.h line 31
Quoted 8 lines
include/soc/qcom/tcs.h new file +8
-0+ +enum rpmh_state { +RPMH_ACTIVE_ONLY_STATE ,/* Active only (= AMC) */ +RPMH_WAKE_ONLY_STATE ,/* Wake only */ +RPMH_SLEEP_STATE ,/* Sleep */ +}; + +struct tcs_mbox_msg {
struct tcs_request ?
include/soc/qcom/tcs.h line 38
Quoted 7 lines
include/soc/qcom/tcs.h new file +7
-0+enum rpmh_state state;/* request state */ +bool is_complete;/* wait for resp from accelerator */ +u32 num_payload;/* Limited to MAX_RPMH_PAYLOAD in one msg */ + struct tcs_cmd *payload;/* array of tcs_cmds */ +}; + +#endif /* __SOC_QCOM_TCS_H__ */
Regards,
Bjorn
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/4] drivers: qcom: rpmh-rsc: add RPMH controller for QCOM SoCs
Quoted 22 lines · Bjorn Andersson
Quoted 8 lines · Lina Iyer
drivers/soc/qcom/rpmh-rsc.c new file +2
-0@@ -0,0 +1,674 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* drivers/soc/qcom/rpmh-rsc.c line 12
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ Please use SPDX headers for new files.
Quoted 5 lines
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */
OK.
Quoted 5 lines
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+ +#define pr_fmt (fmt) "%s " fmt, KBUILD_MODNAME + +#include <linux/atomic.h> +#include <linux/delay.h>
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 23
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> Unused?
Will remove.
Quoted 6 lines
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+/** +* tcs_mbox: group of TCSes for a request state +* +* @type: type of the TCS in this group - active, sleep, wake +* @tcs_mask: mask of the TCSes relative to all the TCSes in the RSC +* @tcs_offset: start of the TCS group relative to the TCSes in the RSC
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 106
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+* @num_tcs: number of TCSes in this type +* @ncpt: number of commands in each TCS +* @tcs_lock: lock for synchronizing this TCS writes +* @responses: response objects for requests sent from each TCS +*/ +struct tcs_mbox {struct
tcs_group?
Hmm.. I am okay with that.
Quoted 22 lines
Quoted 22 lines
drivers/soc/qcom/rpmh-rsc.c new file +22
-0+struct rsc_drv *drv; +int type; +u32 tcs_mask; +u32 tcs_offset; +int num_tcs; +int ncpt; +spinlock_t tcs_lock; +struct tcs_response *responses[MAX_TCS_PER_TYPE ]; +}; + +/** +* rsc_drv: the RSC controller +* +* @pdev: platform device of this controller +* @name: controller identifier +* @base: start address of the controller +* @reg_base: start address of the registers in this controller +* @drv_id: instance id in the controller (DRV) +* @num_tcs: number of TCSes in this DRV +* @tasklet: handle responses, off-load work from IRQ handler +* @response_pending: list of responses that needs to be sent to caller +* @tcs: TCS groups
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 133
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+* @tcs_in_use: s/w state of the TCS +* @drv_lock: synchronize state of the controller +*/ +struct rsc_drv { +struct platform_device *pdev;This is not used outside
rpmh_rsc_probe()and I presume you would like to be able to use it fordev_prints(), if so store the device * instead.
I don't need it. Will remove.
Quoted 8 lines
drivers/soc/qcom/rpmh-rsc.c line 137
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+const char *name; +void __iomem *base; +void __iomem *reg_base; +int drv_id;@base and @drv_id are local to
rpmh_rsc_probe(), so you can make it them local variables.
They are used in the other functions and are needed in this structure. See IRQ handler and tcs_is_free().
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 142
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+int num_tcs; +struct tasklet_struct tasklet; +struct list_head response_pending; +struct tcs_mbox tcs[TCS_TYPE_NR ]; +atomic_t tcs_in_use[MAX_TCS_NR ];Does this really need to be an
atomic_t? Seems like it's protected by thedrv_lock.
Not in the irq handler.
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c line 146
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+spinlock_t drv_lock; +}; + +static inline struct tcs_mbox *get_tcs_from_index (struct rsc_drv *drv,int m)
get_tcs_group_by_index(), or maybe evenget_tcs_group_by_tcs()? To clarify that this resolves a group and not a single tcs.Also, please drop the "inline".
Ok.
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c line 153
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c new file +7
-0+{ +struct tcs_mbox *tcs =NULL ; +int i; + +for (i =0 ; i < drv->num_tcs; i++) { + tcs = &drv->tcs[i]; +if (tcs->tcs_mask & (u32 )BIT (m))I don't think you need this cast.
OK.
Quoted 16 lines
Quoted 16 lines
drivers/soc/qcom/rpmh-rsc.c new file +16
-0+break ; + } + +if (i == drv->num_tcs) { +WARN (1 ,"Incorrect TCS index %d" , m); + tcs =NULL ; + } + +return tcs; +} + +static struct tcs_response *setup_response (struct rsc_drv *drv, +struct tcs_mbox_msg *msg,int m) +{ +struct tcs_response *resp; +struct tcs_mbox *tcs;
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 173
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+ + resp =kcalloc (1 ,sizeof (*resp),GFP_ATOMIC ); +if (!resp) +return ERR_PTR (-ENOMEM );Rather than allocating a response for each write request and freeing it in the tasklet I think you should just allocate
MAX_TCS_PER_TYPEresponses when you're probing the driver.
I am keeping this simple for now. Ideally, a pool of responses would be more helpful and instead of this. I will probably bring that in later.
Quoted 9 lines
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c new file +9
-0+ + resp->drv = drv; + resp->msg = msg; + resp->err =0 ; + + tcs =get_tcs_from_index (drv, m); +if (!tcs) +return ERR_PTR (-EINVAL ); +
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 186
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+/* +* We should have been called from a TCS-type locked context, and +* we overwrite the previously saved response. +*/ I assume that this overwrite wouldn't happen because we're only writing to the tcs if it's not in use? Wouldn't overwriting a valid response lead to us leaking the previously allocated resp?
No. The freeing of the response is handled in the tasklet. Here we just start using a new response object while the old one is still being processed.
Quoted 16 lines
Quoted 16 lines
drivers/soc/qcom/rpmh-rsc.c new file +16
-0+ tcs->responses[m - tcs->tcs_offset] = resp; + +return resp; +} + +static void free_response (struct tcs_response *resp) +{ +kfree (resp); +} + +static inline struct tcs_response *get_response (struct rsc_drv *drv,u32 m) +{ +struct tcs_mbox *tcs =get_tcs_from_index (drv, m); + +return tcs->responses[m - tcs->tcs_offset]; +}
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 206
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+ +static inline u32 read_drv_config (void __iomem *base) +{ +return le32_to_cpu (readl_relaxed (base +DRV_PRNT_CHLD_CONFIG ));
readl_relaxed()on arm64 is defined as le32_to_cpu(__raw_readl(c)), so I would suggest that you drop thele32_to_cpu()and just inline yourreadl()directly inrpmh_rsc_probe().
Ok.
Quoted 8 lines
drivers/soc/qcom/rpmh-rsc.c line 210
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+} + +static inline u32 read_tcs_reg (void __iomem *base,int reg,int m,int n) +{I would suggest that you pass the
rsc_drvto these functions, so that it's obvious which "base" we're operating on here.
Hmm. Ok. I used the void * because they are simple register functions and have no bearing on the DRV they operate on.
But sure.
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c line 212
Quoted 2 lines
drivers/soc/qcom/rpmh-rsc.c new file +2
-0+return le32_to_cpu (readl_relaxed (base + reg + +RSC_DRV_TCS_OFFSET * m +RSC_DRV_CMD_OFFSET * n));No
le32_to_cpu()
Ok.
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c line 219
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c new file +7
-0+} + +static inline void write_tcs_reg (void __iomem *base,int reg,int m,int n, +u32 data) +{ +writel_relaxed (cpu_to_le32 (data), base + reg + +RSC_DRV_TCS_OFFSET * m +RSC_DRV_CMD_OFFSET * n);As with readl, writel does
cpu_to_le32()
Ok
Quoted 14 lines
Quoted 14 lines
drivers/soc/qcom/rpmh-rsc.c new file +14
-0+} + +static inline void write_tcs_reg_sync (void __iomem *base,int reg,int m,int n, +u32 data) +{ +do { +write_tcs_reg (base, reg, m, n, data); +if (data ==read_tcs_reg (base, reg, m, n)) +break ; +udelay (1 ); + }while (1 ); +} + +static inline bool tcs_is_free (struct rsc_drv *drv,int m)
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 238
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+{ +void __iomem *base = drv->reg_base; + +return read_tcs_reg (base,RSC_DRV_STATUS , m,0 ) && + !atomic_read (&drv->tcs_in_use[m]);If you flip these conditions around you won't do the io access when tcs_in_use[m].
Sure.
Quoted 3 lines
What are the cases when
tcs_in_usewill tell you that the tcs is free, but the hardware will say it's not?
In the case of display RSC, which could be directly used by the display driver, my state in tcs_in_use() would not reflect the state of the hardware. This should not happen, but I would like to ensure that it doesn't.
Quoted 30 lines
Quoted 30 lines
drivers/soc/qcom/rpmh-rsc.c new file +30
-0+} + +static inline struct tcs_mbox *get_tcs_of_type (struct rsc_drv *drv,int type) +{ +int i; +struct tcs_mbox *tcs; + +for (i =0 ; i <TCS_TYPE_NR ; i++) +if (type == drv->tcs[i].type) +break ; + +if (i ==TCS_TYPE_NR ) +return ERR_PTR (-EINVAL ); + + tcs = &drv->tcs[i]; +if (!tcs->num_tcs) +return ERR_PTR (-EINVAL ); + +return tcs; +} + +static inline struct tcs_mbox *get_tcs_for_msg (struct rsc_drv *drv, +struct tcs_mbox_msg *msg) +{ +int type =-1 ; + +switch (msg->state) { +case RPMH_ACTIVE_ONLY_STATE : + type =ACTIVE_TCS ; +break ;
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 274
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+default : +break ; + } + +if (type <0 ) +return ERR_PTR (-EINVAL );afaict you can put this return in the default case.
Ok.
Quoted 11 lines
Quoted 11 lines
drivers/soc/qcom/rpmh-rsc.c new file +11
-0+ +return get_tcs_of_type (drv, type); +} + +static inline void send_tcs_response (struct tcs_response *resp) +{ +struct rsc_drv *drv = resp->drv; +unsigned long flags; + +spin_lock_irqsave (&drv->drv_lock, flags); +INIT_LIST_HEAD (&resp->list);
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 290
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+list_add_tail (&resp->list, &drv->response_pending); +spin_unlock_irqrestore (&drv->drv_lock, flags); + +tasklet_schedule (&drv->tasklet); +}Is there any particular reason why this uses a tasklet, instead of just handling the
tx_doneevent from the interrupt handler directly?
Its a bit too heavy for the interrupt handler to do all this locking and respond back and signal completion (done in the next patches). Hence the work is offloaded to the tasklet, we can be faster in responding to other requests that have received the responses.
Quoted 18 lines
Quoted 18 lines
drivers/soc/qcom/rpmh-rsc.c new file +18
-0+ +/** +* tcs_irq_handler: TX Done interrupt handler +*/ +static irqreturn_t tcs_irq_handler (int irq,void *p) +{ +struct rsc_drv *drv = p; +void __iomem *base = drv->reg_base; +int m, i; +u32 irq_status, sts; +struct tcs_response *resp; +struct tcs_cmd *cmd; +int err; + + irq_status =read_tcs_reg (base,RSC_DRV_IRQ_STATUS ,0 ,0 ); + +for (m =0 ; m < drv->num_tcs; m++) { +if (!(irq_status & (u32 )BIT (m)))
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 313
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+continue ; + + err =0 ; + resp =get_response (drv, m); +if (!resp) {This conditional section dereferences resp, so I suspect that the conditional is backwards.
Jeez, how did it not fail. Thanks for catching this..
Quoted 4 lines
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+for (i =0 ; i < resp->msg->num_payload; i++) { + cmd = &resp->msg->payload[i]; + sts =read_tcs_reg (base,RSC_DRV_CMD_STATUS , + m, i);
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 323
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+if ((!(sts &CMD_STATUS_ISSUED )) || + ((resp->msg->is_complete || + cmd->complete) && + (!(sts &CMD_STATUS_COMPL )))) { + resp->err = -EIO ; +break ;As this completes the response, aren't we leaking the
tcs_in_use?
No, we would break out of this loop and set the tcs_in_use. We have no use of this TCS anymore. The h/w status is also reset.
Quoted 21 lines
Quoted 21 lines
drivers/soc/qcom/rpmh-rsc.c new file +21
-0+ } + } + } + +write_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ,0 ); +write_tcs_reg (base,RSC_DRV_IRQ_CLEAR ,0 ,0 ,BIT (m)); +atomic_set (&drv->tcs_in_use[m],0 ); + +if (resp) { + resp->err = err; +send_tcs_response (resp); + } + } + +return IRQ_HANDLED ; +} + +/** +* tcs_notify_tx_done: TX Done for requests that got a response +* +* @data: the tasklet argument
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 349
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+* +* Tasklet function to notify MBOX that we are done with the request. +* Handles all pending reponses whenever run. +*/ +static void tcs_notify_tx_done (unsigned long data)I think you should drop the tasklet and just invoke the handling of responses directly from the irq context.
I think, it will affect performance in multi-threaded usecases if we do that. It is performance critical that we free up the TCS as soon as possible. We only have 2 of them and there could be multiple clients competing for that at the same time. Any work offloaded from the IRQ handler will help move the pipe faster.
Quoted 13 lines
Quoted 13 lines
drivers/soc/qcom/rpmh-rsc.c new file +13
-0+{ + struct rsc_drv *drv = (struct rsc_drv *)data; + struct tcs_response *resp; + unsigned long flags; + int err; + + do { + spin_lock_irqsave(&drv->drv_lock, flags); + if (list_empty(&drv->response_pending)) { + spin_unlock_irqrestore(&drv->drv_lock, flags); + break; + } + resp = list_first_entry(&drv->response_pending,
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 368
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+ struct tcs_response, list); +list_del (&resp->list); +spin_unlock_irqrestore (&drv->drv_lock, flags); + err = resp->err; +free_response (resp); + }while (1 );Use for (;;) {} or while (1) {}, rather than do {} while(1)
OK.
Quoted 8 lines
drivers/soc/qcom/rpmh-rsc.c line 442
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+ curr_enabled =read_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ); + +for (j =0 ; j <MAX_CMDS_PER_TCS ; j++) { +if (!(curr_enabled & (u32 )BIT (j))) +continue ;Consider using
for_each_set_bit()here.
Ok
Quoted 11 lines
drivers/soc/qcom/rpmh-rsc.c line 518
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+/** +* rpmh_rsc_send_data: Validate the incoming message and write to the +* appropriate TCS block. +* +* @drv: the controller +* @msg: the data to be sent +* +* Returns a negative error for invalid message structure and invalid +* message combination, -EBUSY if there is an other active request for +* the channel in process, otherwise bubbles up internal error.
Quoted 9 lines
Kernel-doc style is "Return: a negative..."
The function never returns
-EBUSY, as you're looping while this is being returned.Also, it would be nice if the doc mentions that 0 is returned on success, so perhaps just "Return: 0 on success, negative errno on error"?
Sure.
Quoted 9 lines
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c new file +9
-0+*/ +int rpmh_rsc_send_data (struct rsc_drv *drv,struct tcs_mbox_msg *msg) +{ +int ret =0 ; + +if (!msg || !msg->payload || !msg->num_payload || + msg->num_payload >MAX_RPMH_PAYLOAD ) +return -EINVAL ; +
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 533
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c new file +6
-0+ do { + ret = tcs_mbox_write(drv, msg); + if (ret == -EBUSY) { + pr_info_ratelimited( + "TCS Busy, retrying RPMH message send: addr=0x%x\n", + msg->payload[0].addr);Indent wrapped lines to the start parenthesis.
It was hard with the message overflowing the 80 char limit. Will try to clean it up.
Quoted 11 lines
Quoted 11 lines
drivers/soc/qcom/rpmh-rsc.c new file +11
-0+udelay (10 ); + } + }while (ret == -EBUSY ); + +return ret; +} +EXPORT_SYMBOL (rpmh_rsc_send_data); + +static int rpmh_rsc_probe (struct platform_device *pdev) +{ +struct device_node *dn = pdev->dev.of_node;
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 548
Quoted 4 lines
drivers/soc/qcom/rpmh-rsc.c new file +4
-0+struct rsc_drv *drv; +struct tcs_mbox *tcs; +int irq; +u32 val[8 ] = {0 };8 here should be
TCS_TYPE_NR* 2, but I like Tomas(?) suggestion in the PDC driver of representing arrays of tuples like this as a structured type.
OK.
Quoted 61 lines
Quoted 45 lines
drivers/soc/qcom/rpmh-rsc.c new file +45
-0+int st =0 ; +int i, ret, nelem; +u32 config, max_tcs, ncpt; +int tcs_type_count[TCS_TYPE_NR ] = {0 }; +struct resource *res; + + drv =devm_kzalloc (&pdev->dev,sizeof (*drv),GFP_KERNEL ); +if (!drv) +return -ENOMEM ; + + ret =of_property_read_u32 (dn,"qcom,drv-id" , &drv->drv_id); +if (ret) +return ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -EINVAL ; + drv->base =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (drv->base)) +return PTR_ERR (drv->base); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (!res) +return -EINVAL ; + drv->reg_base =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (drv->reg_base)) +return PTR_ERR (drv->reg_base); + + config =read_drv_config (drv->base); + max_tcs = config & (DRV_NUM_TCS_MASK << + (DRV_NUM_TCS_SHIFT * drv->drv_id)); + max_tcs = max_tcs >> (DRV_NUM_TCS_SHIFT * drv->drv_id); + ncpt = config & (DRV_NCPT_MASK <<DRV_NCPT_SHIFT ); + ncpt = ncpt >>DRV_NCPT_SHIFT ; + + nelem =of_property_count_elems_of_size (dn,"qcom,tcs-config" , +sizeof (u32)); +if (!nelem || (nelem %2 ) || (nelem >2 *TCS_TYPE_NR )) +return -EINVAL ; + + ret =of_property_read_u32_array (dn,"qcom,tcs-config" , val, nelem); +if (ret) +return ret; + +for (i =0 ; i < (nelem /2 ); i++) {drivers/soc/qcom/rpmh-rsc.c line 603
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+if (val[2 * i] >=TCS_TYPE_NR ) +return -EINVAL ; + tcs_type_count[val[2 * i]]++; +if (tcs_type_count[val[2 * i]] >1 ) +return -EINVAL ; + } + +for (i =0 ; i <ARRAY_SIZE (tcs_type_count); i++) +if (!tcs_type_count[i]) +return -EINVAL ;I think it's better if replace these two loops by adding a check in below loop to ensure that
tcs->drvis NULL and thattcs->typeis valid and then follow up with a loop checking that eachdrv->tcswas initialized.
Quoted 2 lines
That way you don't need to do the counting of the various types.
I need to count to ensure that all types are mentioned in the DT.
Quoted 41 lines
Quoted 41 lines
drivers/soc/qcom/rpmh-rsc.c new file +41
-0+ +for (i =0 ; i < (nelem /2 ); i++) { + tcs = &drv->tcs[val[2 * i]]; + tcs->drv = drv; + tcs->type = val[2 * i]; + tcs->num_tcs = val[2 * i +1 ]; + tcs->ncpt = ncpt; +spin_lock_init (&tcs->tcs_lock); + +if (tcs->num_tcs <=0 || tcs->type ==CONTROL_TCS ) +continue ; + +if (tcs->num_tcs >MAX_TCS_PER_TYPE || + st + tcs->num_tcs > max_tcs || + st + tcs->num_tcs >=8 *sizeof (tcs->tcs_mask)) +return -EINVAL ; + + tcs->tcs_mask = ((1 << tcs->num_tcs) -1 ) << st; + tcs->tcs_offset = st; + st += tcs->num_tcs; + } + + drv->num_tcs = st; + drv->pdev = pdev; +INIT_LIST_HEAD (&drv->response_pending); +spin_lock_init (&drv->drv_lock); +tasklet_init (&drv->tasklet, tcs_notify_tx_done, (unsigned long )drv); + + drv->name =of_get_property (pdev->dev.of_node,"label" ,NULL ); +if (!drv->name) + drv->name =dev_name (&pdev->dev); + + irq =of_irq_get (dn,0 ); +if (irq <0 ) +return irq; + + ret =devm_request_irq (&pdev->dev, irq, tcs_irq_handler, +IRQF_TRIGGER_HIGH |IRQF_NO_SUSPEND , drv->name, drv); +if (ret) +return ret; +
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c line 649
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+write_tcs_reg (drv->reg_base,RSC_DRV_IRQ_ENABLE ,0 ,0 , + drv->tcs[ACTIVE_TCS ].tcs_mask); + +for (i =0 ; i <ARRAY_SIZE (drv->tcs_in_use); i++) +atomic_set (&drv->tcs_in_use[i],0 );Perhaps do this before requesting the irq? If nothing else that saves future readers from wondering if it makes any difference...
Ok. No difference to me.
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c line 651
Quoted 2 lines
drivers/soc/qcom/rpmh-rsc.c new file +2
-0+ +dev_set_drvdata (&pdev->dev, drv);This isn't used until the next patch, so move it there to clarify its purpose.
OK.
Quoted 18 lines
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c new file +5
-0+ +return of_platform_populate (pdev->dev.of_node,NULL ,NULL , &pdev->dev); +} + +static const struct of_device_id rpmh_drv_match[] = {drivers/soc/qcom/rpmh-rsc.c line 666
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c new file +10
-0+ { .compatible = "qcom,rpmh-rsc", }, + { } +}; +MODULE_DEVICE_TABLE (of, rpm_drv_match); + +static struct platform_driver rpmh_driver = { + .probe = rpmh_rsc_probe, + .driver = { + .name =KBUILD_MODNAME , + .of_match_table = rpmh_drv_match,As we don't want to handle unbind, add:
Quoted 2 lines
.suppress_bind_attrs = true,
OK.
Quoted 9 lines
Quoted 8 lines
drivers/soc/qcom/rpmh-rsc.c new file +3
-0+ }, +}; +include/dt-bindings/soc/qcom,rpmh-rsc.h new file +0
-0
Quoted 8 lines
include/dt-bindings/soc/qcom,rpmh-rsc.h
Quoted 5 lines
include/dt-bindings/soc/qcom,rpmh-rsc.h new file +5
-0+struct tcs_cmd { +u32 addr;/* slv_id:18:16 | offset:0:15 */ +u32 data;/* data for resource (or read response) */ +bool complete;/* wait for completion before sending next */ +};I think you should use kernel-doc to describe the structs.
Ok.
Quoted 11 lines
include/dt-bindings/soc/qcom,rpmh-rsc.h
Quoted 8 lines
include/dt-bindings/soc/qcom,rpmh-rsc.h new file +8
-0+ +enum rpmh_state { +RPMH_ACTIVE_ONLY_STATE ,/* Active only (= AMC) */ +RPMH_WAKE_ONLY_STATE ,/* Wake only */ +RPMH_SLEEP_STATE ,/* Sleep */ +}; + +struct tcs_mbox_msg {struct
tcs_request?
Hmm.. ok
Quoted 8 lines
include/dt-bindings/soc/qcom,rpmh-rsc.h
Quoted 7 lines
include/dt-bindings/soc/qcom,rpmh-rsc.h new file +7
-0+enum rpmh_state state;/* request state */ +bool is_complete;/* wait for resp from accelerator */ +u32 num_payload;/* Limited to MAX_RPMH_PAYLOAD in one msg */ + struct tcs_cmd *payload;/* array of tcs_cmds */ +}; + +#endif /* __SOC_QCOM_TCS_H__ */
Thanks for the review Bjorn.
-- Lina
PATCH 2/4 dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs
In reply to Lina IyerAdd device binding documentation for Qualcomm Technology Inc's RPMH RSC driver. The hardware block is used for communicating resource state requests for shared resources.
--- .../devicetree/bindings/arm/msm/rpmh-rsc.txt | 134 +++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +134 -0
@@ -0,0 +1,134 @@ +RPMH RSC: +------------ + +RPMH is the mechanism for communicating with the hardened resource +accelerators. Requests to the resources can be written to the TCS mailbox +registers and using a (addr, val) pair and triggered. Messages in the TCS are +then sent in sequence over an internal bus. + +The hardware block (Direct Resource Voter or DRV) is a part of the h/w entity +(Resource State Coordinator a.k.a RSC) that can handle a multiple sleep and +active/wake resource requests. Multiple such DRVs can exist in a SoC and can +be written to from Linux. The structure of each DRV follows the same template +with a few variations that are captured by the properties here. + +Each DRV could have 'm' TCS instances. Each TCS could have 'n' slots. Each +slot has a header (u32), address (u32), data (u32), status (u32) and a +read-response (u32). A TCS when triggered will send all the enabled commands +of the 'n' commands in that slot in sequence. + +A TCS may be triggered from Linux or triggered by the F/W after all the CPUs +have powered off to faciliate idle power saving. TCS could be classified as - + + SLEEP, /* Triggered by F/W */ + WAKE, /* Triggered by F/W */ + ACTIVE, /* Triggered by Linux */ + CONTROL /* Triggered by F/W */ + +The order in which they are described in the DT, should match the hardware +configuration. + +Requests can be made for the state of a resource, when the subsystem is active +or idle. When all subsystems like Modem, GPU, CPU are idle, the resource state +will be an aggregeate of the sleep votes from each of those subsystem. Drivers +may request a sleep value for their shared resources in addition to the active +mode requests. + +Control requests are instance specific requests that may or may not reach an +accelerator. Only one platform device in Linux can request a control channel +on a DRV. + +CONTROLLER: +---------- + +PROPERTIES: + +- compatible: + Usage: required + Value type: <string> + Definition: Should be "qcom,rpmh-rsc". + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: the first element specifies the base address of the DRV, + the second element specifies the size of the region. + +- interrupts: + Usage: required + Value type: <prop-encoded-interrupt> + Definition: the interrupt that trips when a message complete/response + is received for this DRV from the accelertors. + +- qcom,drv-id: + Usage: required + Value type: <u32> + Definition: the id of the DRV in the RSC block. + +- qcom, tcs-config: + Usage: required + Value type: <prop-encoded-array> + Definition: the tuple definining the configuration of TCS. + Must have 2 cells which describe each TCS type. + <type number_of_tcs> + - Cell #1 (TCS Type): TCS types can be specified - + SLEEP_TCS + WAKE_TCS + ACTIVE_TCS + CONTROL_TCS + - Cell #2 (Number of TCS): <u32> + +- label: + Usage: optional + Value type: <string> + Definition: Name for the RSC. The name would be used in trace logs. + +Clients the want to use the RSC to communicate with RPMH would specify their +bindings as child of the corresponding RSC controllers. + +EXAMPLE 1: + +For a TCS whose RSC base address is is 0x179C0000 and is at a DRV of 2, the +register offsets for DRV2 start at 0D00, the register calculations are like +this - +First tuple: 0x179C0000 + 0x10000 * 2 = 0x179E0000 +Second tuple: 0x179E0000 + 0xD00 = 0x179E0D00 + + apps_rsc: rsc@179e000 { + compatible = "qcom,rpmh-rsc"; + label = "apps_rsc"; + reg = <0x179e0000 0x10000>, <0x179e0d00 0x3000>; + interrupts = <0 5 0>; + qcom,drv-id = <2>; + qcom,tcs-config = <SLEEP_TCS 3>, + <WAKE_TCS 3>, + <ACTIVE_TCS 2>, + <CONTROL_TCS 1>; + + foo-clk { + compatible = "foo-clk"; + }; + }; + +EXAMPLE 2: + +For a TCS whose RSC base address is 0xAF20000 and is at DRV of 0, the register +offsets for DRV0 start at 01C00, the register calculations are like this - +First tuple: 0xAF20000 +Second tuple: 0xAF20000 + 0x1C00 + + disp_rsc: rsc@af20000 { + label = "disp_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0xaf20000 0x10000>, <0xaf21c00 0x3000>; + interrupts = <0 129 0>; + qcom,drv-id = <0>; + qcom,tcs-config = <SLEEP_TCS 1>, + <WAKE_TCS 1>, + <ACTIVE_TCS 0>, + <CONTROL_TCS 1>; + + foo-clk { + compatible = "foo-clk"; + }; + };
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Rob Herring
maintainerRe: [PATCH 2/4] dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs
Quoted 8 lines · Lina Iyer
Add device binding documentation for Qualcomm Technology Inc's RPMH RSC driver. The hardware block is used for communicating resource state requests for shared resources.
Signed-off-by Lina Iyer <[email protected]>--- .../devicetree/bindings/arm/msm/rpmh-rsc.txt | 134 +++++++++++++++++++++
bindings/mailbox instead?
Quoted 67 lines
1 file changed, 134 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txtDocumentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +58
-0@@ -0,0 +1,134 @@ +RPMH RSC: +------------ + +RPMH is the mechanism for communicating with the hardened resource +accelerators. Requests to the resources can be written to the TCS mailbox +registers and using a (addr, val) pair and triggered. Messages in the TCS are +then sent in sequence over an internal bus. + +The hardware block (Direct Resource Voter or DRV) is a part of the h/w entity +(Resource State Coordinator a.k.a RSC) that can handle a multiple sleep and +active/wake resource requests. Multiple such DRVs can exist in a SoC and can +be written to from Linux. The structure of each DRV follows the same template +with a few variations that are captured by the properties here. + +Each DRV could have 'm' TCS instances. Each TCS could have 'n' slots. Each +slot has a header (u32), address (u32), data (u32), status (u32) and a +read-response (u32). A TCS when triggered will send all the enabled commands +of the 'n' commands in that slot in sequence. + +A TCS may be triggered from Linux or triggered by the F/W after all the CPUs +have powered off to faciliate idle power saving. TCS could be classified as - + + SLEEP, /* Triggered by F/W */ + WAKE, /* Triggered by F/W */ + ACTIVE, /* Triggered by Linux */ + CONTROL /* Triggered by F/W */ + +The order in which they are described in the DT, should match the hardware +configuration. + +Requests can be made for the state of a resource, when the subsystem is active +or idle. When all subsystems like Modem, GPU, CPU are idle, the resource state +will be an aggregeate of the sleep votes from each of those subsystem. Drivers +may request a sleep value for their shared resources in addition to the active +mode requests. + +Control requests are instance specific requests that may or may not reach an +accelerator. Only one platform device in Linux can request a control channel +on a DRV. + +CONTROLLER: +---------- + +PROPERTIES: + +- compatible: + Usage: required + Value type: <string> + Definition: Should be "qcom,rpmh-rsc". + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: the first element specifies the base address of the DRV, + the second element specifies the size of the region. + +- interrupts: + Usage: required
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 68
Quoted 10 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +10
-0+ Value type: <prop-encoded-interrupt> + Definition: the interrupt that trips when a message complete/response + is received for this DRV from the accelertors. + +- qcom,drv-id: + Usage: required + Value type: <u32> + Definition: the id of the DRV in the RSC block. + +- qcom, tcs-config:
^
space
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 78
Quoted 10 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +10
-0+ Usage: required + Value type: <prop-encoded-array> + Definition: the tuple definining the configuration of TCS. + Must have 2 cells which describe each TCS type. + <type number_of_tcs> + - Cell #1 (TCS Type): TCS types can be specified - + SLEEP_TCS + WAKE_TCS + ACTIVE_TCS + CONTROL_TCS
These defines belong in this patch.
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 79
Quoted 1 line
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +1
-0+ - Cell #2 (Number of TCS): <u32>
Is there some sort of range of numbers?
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 86
Quoted 7 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +7
-0+ +- label: + Usage: optional + Value type: <string> + Definition: Name for the RSC. The name would be used in trace logs. + +Clients the want to use the RSC to communicate with RPMH would specify their
Clients the want?
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 87
Quoted 1 line
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +1
-0+bindings as child of the corresponding RSC controllers.
Need to be specific here about what the child nodes are.
Quoted 55 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +47
-0+ +EXAMPLE 1: + +For a TCS whose RSC base address is is 0x179C0000 and is at a DRV of 2, the +register offsets for DRV2 start at 0D00, the register calculations are like +this - +First tuple: 0x179C0000 + 0x10000 * 2 = 0x179E0000 +Second tuple: 0x179E0000 + 0xD00 = 0x179E0D00 + + apps_rsc: rsc@179e000 { + compatible = "qcom,rpmh-rsc"; + label = "apps_rsc"; + reg = <0x179e0000 0x10000>, <0x179e0d00 0x3000>; + interrupts = <0 5 0>; + qcom,drv-id = <2>; + qcom,tcs-config = <SLEEP_TCS 3>, + <WAKE_TCS 3>, + <ACTIVE_TCS 2>, + <CONTROL_TCS 1>; + + foo-clk { + compatible = "foo-clk"; + }; + }; + +EXAMPLE 2: + +For a TCS whose RSC base address is 0xAF20000 and is at DRV of 0, the register +offsets for DRV0 start at 01C00, the register calculations are like this - +First tuple: 0xAF20000 +Second tuple: 0xAF20000 + 0x1C00 + + disp_rsc: rsc@af20000 { + label = "disp_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0xaf20000 0x10000>, <0xaf21c00 0x3000>; + interrupts = <0 129 0>; + qcom,drv-id = <0>; + qcom,tcs-config = <SLEEP_TCS 1>, + <WAKE_TCS 1>, + <ACTIVE_TCS 0>, + <CONTROL_TCS 1>; + + foo-clk { + compatible = "foo-clk"; + }; + };Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/4] dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs
Hi Rob,
Quoted 5 lines · Rob Herring
Quoted 4 lines · Lina Iyer
Add device binding documentation for Qualcomm Technology Inc's RPMH RSC driver. The hardware block is used for communicating resource state requests for shared resources.
Quoted 7 lines
Quoted 4 lines
Signed-off-by Lina Iyer <[email protected]>--- .../devicetree/bindings/arm/msm/rpmh-rsc.txt | 134 +++++++++++++++++++++bindings/mailbox instead?
This doesn't use the mailbox framework, but is that still okay?
Quoted 9 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 68
Quoted 6 lines
+- qcom,drv-id:
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +5
-0+ Usage: required + Value type: <u32> + Definition: the id of the DRV in the RSC block. + +- qcom, tcs-config:^space
Ok.
Quoted 4 lines
Quoted 4 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +4
-0+ Usage: required + Value type: <prop-encoded-array> + Definition: the tuple definining the configuration of TCS. + Must have 2 cells which describe each TCS type.
Quoted 9 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 78
Quoted 6 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +6
-0+ <type number_of_tcs> + - Cell #1 (TCS Type): TCS types can be specified - + SLEEP_TCS + WAKE_TCS + ACTIVE_TCS + CONTROL_TCSThese defines belong in this patch.
The defines are also used by the driver, so it ended up there to avoid compilation errors. I guess I can make this patch a precursor to the driver patch.
Quoted 4 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 79
Quoted 1 line
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +1
-0+ - Cell #2 (Number of TCS): <u32>Is there some sort of range of numbers?
The range is limited by the area available and the complexity supported by the processor. Generally 1-3 per TCS type.
Quoted 10 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 86
Quoted 7 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +7
-0+ +- label: + Usage: optional + Value type: <string> + Definition: Name for the RSC. The name would be used in trace logs. + +Clients the want to use the RSC to communicate with RPMH would specify theirClients the want?
Argh! Will fix.
Quoted 4 lines
Quoted 1 line
+bindings as child of the corresponding RSC controllers.
Need to be specific here about what the child nodes are.
Ok. The child nodes are the clients that would want to use RPMH communication.
Thanks,
Lina
Re: [PATCH 2/4] dt-bindings: introduce RPMH RSC bindings for Qualcomm SoCs
In reply to Lina IyerDocumentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 55
Quoted 5 lines · Lina Iyer
+- reg:
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +4
-0+ Usage: required + Value type: <prop-encoded-array> + Definition: the first element specifies the base address of the DRV, + the second element specifies the size of the region.
This doesn't capture the fact that there are two memory regions that needs to be described.
[..]
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 73
Quoted 6 lines
+- qcom, tcs-config:
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +5
-0+ Usage: required + Value type: <prop-encoded-array> + Definition: the tuple definining the configuration of TCS. + Must have 2 cells which describe each TCS type. + <type number_of_tcs>
I think this definition should capture that it's a list of tuples and they are describing the functional allocation of the available TCSs.
Quoted 7 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +7
-0+ - Cell #1 (TCS Type): TCS types can be specified - + SLEEP_TCS + WAKE_TCS + ACTIVE_TCS + CONTROL_TCS + - Cell #2 (Number of TCS): <u32> +
[..]
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 95
Quoted 7 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +7
-0+EXAMPLE 1: + +For a TCS whose RSC base address is is 0x179C0000 and is at a DRV of 2, the +register offsets for DRV2 start at 0D00, the register calculations are like +this - +First tuple: 0x179C0000 + 0x10000 * 2 = 0x179E0000 +Second tuple: 0x179E0000 + 0xD00 = 0x179E0D00
So the first region is the DRV base and the second describe the TCSs? I think that the purpose of the two regions should be clarified.
If this is the case then I would suggest also adding a
reg-names = "drv", "tcs";
in order to make the dts self-explaining.
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 101
Quoted 6 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +6
-0+ + apps_rsc: rsc@179e000 { + compatible = "qcom,rpmh-rsc"; + label = "apps_rsc"; + reg = <0x179e0000 0x10000>, <0x179e0d00 0x3000>; + interrupts = <0 5 0>;
<GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt line 112
Quoted 11 lines
Documentation/devicetree/bindings/arm/msm/rpmh-rsc.txt new file +11
-0+ qcom,drv-id = <2>; + qcom,tcs-config = <SLEEP_TCS 3>, + <WAKE_TCS 3>, + <ACTIVE_TCS 2>, + <CONTROL_TCS 1>; + + foo-clk { + compatible = "foo-clk"; + }; + }; +
Regards,
Bjorn
PATCH 3/4 drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
In reply to Lina IyerLog sent RPMH requests and interrupt responses in FTRACE.
--- drivers/soc/qcom/rpmh-rsc.c | 13 ++++++- include/trace/events/rpmh.h | 89 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 include/trace/events/rpmh.h
drivers/soc/qcom/rpmh-rsc.c +12 -1
@@ -33,6 +33,9 @@#include "rpmh-internal.h" +#define CREATE_TRACE_POINTS +#include <trace/events/rpmh.h> +#define MAX_CMDS_PER_TCS 16#define MAX_TCS_PER_TYPE 3
@@ -325,6 +328,8 @@ static irqreturn_t tcs_irq_handler(int irq, void *p) } } +trace_rpmh_notify_irq (drv->name, m, resp->msg->payload[0 ].addr, + resp->err);write_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ,0 );write_tcs_reg (base,RSC_DRV_IRQ_CLEAR ,0 ,0 ,BIT (m));atomic_set (&drv->tcs_in_use[m],0 );
@@ -351,7 +356,8 @@ static void tcs_notify_tx_done(unsigned long data)struct rsc_drv *drv = (struct rsc_drv *)data;struct tcs_response *resp;unsigned long flags; -int err; +int err, m; +struct tcs_mbox_msg *msg; do { spin_lock_irqsave(&drv->drv_lock, flags);
@@ -364,7 +370,10 @@ static void tcs_notify_tx_done(unsigned long data)list_del (&resp->list);spin_unlock_irqrestore (&drv->drv_lock, flags); err = resp->err; + m = resp->m; + msg = resp->msg;free_response (resp); +trace_rpmh_notify (drv->name, m, msg->payload[0 ].addr, err); }while (1 ); }
@@ -393,6 +402,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int m, int n,write_tcs_reg (base,RSC_DRV_CMD_MSGID , m, n + i, msgid);write_tcs_reg (base,RSC_DRV_CMD_ADDR , m, n + i, cmd->addr);write_tcs_reg (base,RSC_DRV_CMD_DATA , m, n + i, cmd->data); +trace_rpmh_send_msg (drv->name, m, n + i, msgid, cmd->addr, + cmd->data, cmd->complete); }write_tcs_reg (base,RSC_DRV_CMD_WAIT_FOR_CMPL , m,0 , cmd_complete);
include/trace/events/rpmh.h new file +89 -0
89 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
A message that is not in the archive (sent off-list or not yet received): 20180119000157.7380-4-ilina-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
Re: [PATCH 3/4] drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
I wasn't Cc'd on the rest of the patches and this wasn't Cc'd to LKML, and I'm not on any of the mailing lists that were Cc'd, I gotta just look at what I have here in this patch.
Quoted 25 lines · On Thu, 18 Jan 2018 17:01:56 -0700 Lina Iyer…
Log sent RPMH requests and interrupt responses in FTRACE.
Cc Steven Rostedt <[email protected]>Signed-off-by Lina Iyer <[email protected]>--- drivers/soc/qcom/rpmh-rsc.c | 13 ++++++- include/trace/events/rpmh.h | 89 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 include/trace/events/rpmh.hdrivers/soc/qcom/rpmh-rsc.c +3
-0@@ -33,6 +33,9 @@#include "rpmh-internal.h" +#define CREATE_TRACE_POINTS +#include <trace/events/rpmh.h> +#define MAX_CMDS_PER_TCS 16#define MAX_TCS_PER_TYPE 3
drivers/soc/qcom/rpmh-rsc.c static irqreturn_t tcs_irq_handler(int irq, void *p) · line 332
Quoted 5 lines
drivers/soc/qcom/rpmh-rsc.c +2
-0@@ -325,6 +328,8 @@ static irqreturn_t tcs_irq_handler(int irq, void *p) } } +trace_rpmh_notify_irq (drv->name, m, resp->msg->payload[0 ].addr, + resp->err);
Below, m came from resp->m, is it the same here?
Quoted 14 lines
drivers/soc/qcom/rpmh-rsc.c +2
-1write_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ,0 );write_tcs_reg (base,RSC_DRV_IRQ_CLEAR ,0 ,0 ,BIT (m));atomic_set (&drv->tcs_in_use[m],0 );@@ -351,7 +356,8 @@ static void tcs_notify_tx_done(unsigned long data)struct rsc_drv *drv = (struct rsc_drv *)data;struct tcs_response *resp;unsigned long flags; -int err; +int err, m; +struct tcs_mbox_msg *msg; do { spin_lock_irqsave(&drv->drv_lock, flags);
drivers/soc/qcom/rpmh-rsc.c static void tcs_notify_tx_done(unsigned long data) · line 376
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c +3
-0@@ -364,7 +370,10 @@ static void tcs_notify_tx_done(unsigned long data)list_del (&resp->list);spin_unlock_irqrestore (&drv->drv_lock, flags); err = resp->err; + m = resp->m; + msg = resp->msg;free_response (resp); +trace_rpmh_notify (drv->name, m, msg->payload[0 ].addr, err);
The reason I ask, is that this is causing more code to be executed even when tracing is off. What about passing in resp and assigning it within the tracepoint.
trace_rpmh_notify(drv->name, resp);
That would keep extra code from being used within the normal code path and only executed in the tracepoint. Get rid of the m = resp->m, msg = resp->msg.
Even if m is something different above, you can still just pass in:
trace_rpmh_notify(drv->name, m, resp);
drivers/soc/qcom/rpmh-rsc.c static void __tcs_buffer_write(struct rsc_drv *drv, int m, int n, · line 406
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c +2
-0}while (1 ); }@@ -393,6 +402,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int m, int n,write_tcs_reg (base,RSC_DRV_CMD_MSGID , m, n + i, msgid);write_tcs_reg (base,RSC_DRV_CMD_ADDR , m, n + i, cmd->addr);write_tcs_reg (base,RSC_DRV_CMD_DATA , m, n + i, cmd->data); +trace_rpmh_send_msg (drv->name, m, n + i, msgid, cmd->addr, + cmd->data, cmd->complete);
Here just pass in cmd. The less the parameters of a tracepoints, the more likely gcc wont leak code that would be executed when tracing is off.
Quoted 24 lines
drivers/soc/qcom/rpmh-rsc.c +0
-0}write_tcs_reg (base,RSC_DRV_CMD_WAIT_FOR_CMPL , m,0 , cmd_complete);include/trace/events/rpmh.h new file +15
-0@@ -0,0 +1,89 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rpmh +
include/trace/events/rpmh.h line 25
Quoted 10 lines
include/trace/events/rpmh.h new file +10
-0+#if !defined(_TRACE_RPMH_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_RPMH_H + +#include <linux/tracepoint.h> + +DECLARE_EVENT_CLASS(rpmh_ack_recvd, + + TP_PROTO(const char *s, int m, u32 addr, int errno), + + TP_ARGS(s, m, addr, errno),
Then we could just do:
TP_PROTO(const char *s, struct tcs_response *resp), TP_ARGS(s, resp),
include/trace/events/rpmh.h line 38
Quoted 13 lines
include/trace/events/rpmh.h new file +13
-0+ +TP_STRUCT__entry ( +__field (const char *,name ) +__field (int, m) +__field (u32, addr) +__field (int, errno) + ), + +TP_fast_assign ( + __entry->name = s; + __entry->m = m; + __entry->addr = addr; + __entry->errno = errno;
__entry->m = resp->m; __entry->addr = resp->msg->payload[0].addr; __entry->errno = resp->err;
-- Steve
Quoted 41 lines
include/trace/events/rpmh.h new file +41
-0+ ), + +TP_printk ("%s: ack: tcs-m:%d addr: 0x%08x errno: %d" , + __entry->name, __entry->m, __entry->addr, __entry->errno) +); + +DEFINE_EVENT (rpmh_ack_recvd, rpmh_notify_irq, + TP_PROTO(const char *s, int m, u32 addr, int err), +TP_ARGS (s, m, addr, err) +); + +DEFINE_EVENT (rpmh_ack_recvd, rpmh_notify, + TP_PROTO(const char *s, int m, u32 addr, int err), +TP_ARGS (s, m, addr, err) +); + +TRACE_EVENT(rpmh_send_msg, + + TP_PROTO(const char *s, int m, int n, u32 h, u32 a, u32 v, bool c), + + TP_ARGS(s, m, n, h, a, v, c), + + TP_STRUCT__entry( + __field(const char*, name) + __field(int, m) + __field(int, n) + __field(u32, hdr) + __field(u32, addr) + __field(u32, data) + __field(bool, complete) + ), + + TP_fast_assign( + __entry->name = s; + __entry->m = m; + __entry->n = n; + __entry->hdr = h; + __entry->addr = a; + __entry->data = v; + __entry->complete = c; + ),
include/trace/events/rpmh.h line 89
Quoted 10 lines
include/trace/events/rpmh.h new file +10
-0+ +TP_printk ("%s: send-msg: tcs(m): %d cmd(n): %d msgid: 0x%08x addr: 0x%08x data: 0x%08x complete: %d" , + __entry->name, __entry->m, __entry->n, __entry->hdr, + __entry->addr, __entry->data, __entry->complete) +); + +#endif /* _TRACE_RPMH_H */ + +#define TRACE_INCLUDE_FILE rpmh +#include <trace/define_trace.h>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/4] drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
Hi Steven,
Quoted 5 lines · Steven Rostedt
I wasn't Cc'd on the rest of the patches and this wasn't Cc'd to LKML, and I'm not on any of the mailing lists that were Cc'd, I gotta just look at what I have here in this patch.
I am so sorry. Will add LKML in the future.
Quoted 4 lines
On Thu, 18 Jan 2018 17:01:56 -0700
Lina Iyer <[email protected]> wrote:
Quoted 9 lines
drivers/soc/qcom/rpmh-rsc.c static irqreturn_t tcs_irq_handler(int irq, void *p) · line 332
Quoted 6 lines
drivers/soc/qcom/rpmh-rsc.c +2
-0@@ -325,6 +328,8 @@ static irqreturn_t tcs_irq_handler(int irq, void *p) } } +trace_rpmh_notify_irq (drv->name, m, resp->msg->payload[0 ].addr, + resp->err);Below, m came from
resp->m, is it the same here?
Yes, they will be the same.
Quoted 26 lines
Quoted 14 lines
drivers/soc/qcom/rpmh-rsc.c +2
-1write_tcs_reg (base,RSC_DRV_CMD_ENABLE , m,0 ,0 );write_tcs_reg (base,RSC_DRV_IRQ_CLEAR ,0 ,0 ,BIT (m));atomic_set (&drv->tcs_in_use[m],0 );@@ -351,7 +356,8 @@ static void tcs_notify_tx_done(unsigned long data)struct rsc_drv *drv = (struct rsc_drv *)data;struct tcs_response *resp;unsigned long flags; -int err; +int err, m; +struct tcs_mbox_msg *msg; do { spin_lock_irqsave(&drv->drv_lock, flags);drivers/soc/qcom/rpmh-rsc.c static void tcs_notify_tx_done(unsigned long data) · line 376
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c +3
-0@@ -364,7 +370,10 @@ static void tcs_notify_tx_done(unsigned long data)list_del (&resp->list);spin_unlock_irqrestore (&drv->drv_lock, flags); err = resp->err; + m = resp->m; + msg = resp->msg;free_response (resp); +trace_rpmh_notify (drv->name, m, msg->payload[0 ].addr, err);The reason I ask, is that this is causing more code to be executed even when tracing is off. What about passing in resp and assigning it within the tracepoint.
Quoted 2 lines
trace_rpmh_notify(drv->name, resp);
The free_response(resp) will free the resp object and accessing resp->m is invalid after that.
Quoted 11 lines
That would keep extra code from being used within the normal code path and only executed in the tracepoint. Get rid of the m =
resp->m, msg =resp->msg.Even if m is something different above, you can still just pass in:
trace_rpmh_notify(drv->name, m, resp);Quoted 2 lines
drivers/soc/qcom/rpmh-rsc.c +0
-0}while (1 ); }
May be I can just move the free_response() afer the trace_rpmh_notify().
Quoted 12 lines
drivers/soc/qcom/rpmh-rsc.c static void __tcs_buffer_write(struct rsc_drv *drv, int m, int n, · line 406
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c +2
-0@@ -393,6 +402,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int m, int n,write_tcs_reg (base,RSC_DRV_CMD_MSGID , m, n + i, msgid);write_tcs_reg (base,RSC_DRV_CMD_ADDR , m, n + i, cmd->addr);write_tcs_reg (base,RSC_DRV_CMD_DATA , m, n + i, cmd->data); +trace_rpmh_send_msg (drv->name, m, n + i, msgid, cmd->addr, + cmd->data, cmd->complete);Here just pass in cmd. The less the parameters of a tracepoints, the more likely gcc wont leak code that would be executed when tracing is off.
OK.
Quoted 10 lines
include/trace/events/rpmh.h line 25
Quoted 7 lines
include/trace/events/rpmh.h new file +7
-0+#include <linux/tracepoint.h> + +DECLARE_EVENT_CLASS(rpmh_ack_recvd, + + TP_PROTO(const char *s, int m, u32 addr, int errno), + + TP_ARGS(s, m, addr, errno),Then we could just do:
Quoted 4 lines
TP_PROTO(const char *s, struct tcs_response *resp), TP_ARGS(s, resp),
Nice. Will use this.
Quoted 18 lines
include/trace/events/rpmh.h line 38
Quoted 13 lines
include/trace/events/rpmh.h new file +13
-0+ +TP_STRUCT__entry ( +__field (const char *,name ) +__field (int, m) +__field (u32, addr) +__field (int, errno) + ), + +TP_fast_assign ( + __entry->name = s; + __entry->m = m; + __entry->addr = addr; + __entry->errno = errno;__entry->m = resp->m; __entry->addr = resp->msg->payload[0].addr; __entry->errno = resp->err;
Quoted 2 lines
-- Steve
Thanks for the review.
-- Lina
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH 3/4] drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
Quoted 9 lines · On Fri, 19 Jan 2018 07:35:01 +0000 Lina Iyer…
Hi Steven,
Quoted 5 lines · Steven Rostedt
I wasn't Cc'd on the rest of the patches and this wasn't Cc'd to LKML, and I'm not on any of the mailing lists that were Cc'd, I gotta just look at what I have here in this patch.
I am so sorry. Will add LKML in the future.
Thanks. It's just that I had little context to review the patch from.
Quoted 22 lines
Quoted 22 lines
Quoted 10 lines
drivers/soc/qcom/rpmh-rsc.c +2
-1struct rsc_drv *drv = (struct rsc_drv *)data;struct tcs_response *resp;unsigned long flags; -int err; +int err, m; +struct tcs_mbox_msg *msg; do { spin_lock_irqsave(&drv->drv_lock, flags);drivers/soc/qcom/rpmh-rsc.c static void tcs_notify_tx_done(unsigned long data) · line 376
Quoted 7 lines
drivers/soc/qcom/rpmh-rsc.c +3
-0@@ -364,7 +370,10 @@ static void tcs_notify_tx_done(unsigned long data)list_del (&resp->list);spin_unlock_irqrestore (&drv->drv_lock, flags); err = resp->err; + m = resp->m; + msg = resp->msg;free_response (resp); +trace_rpmh_notify (drv->name, m, msg->payload[0 ].addr, err);The reason I ask, is that this is causing more code to be executed even when tracing is off. What about passing in resp and assigning it within the tracepoint.
Quoted 4 lines
Quoted 2 lines
trace_rpmh_notify(drv->name, resp);The
free_response(resp)will free the resp object and accessingresp->mis invalid after that.
What about placing the trace before the free?
-- Steve
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20180119094443.39e5f020-f9ZlEuEWxVcJvu8Pb33WZ0EMvNT87kid@public.gmane.org
Re: [PATCH 3/4] drivers: qcom: rpmh-rsc: log RPMH requests in FTRACE
Quoted 5 lines · Steven Rostedt
Quoted 2 lines · On Fri, 19 Jan 2018 07:35:01 +0000 Lina Iyer…
Hi Steven,
Quoted 9 lines
Quoted 6 lines · Steven Rostedt
Quoted 3 lines
trace_rpmh_notify(drv->name, resp);The
free_response(resp)will free the resp object and accessingresp->mis invalid after that.What about placing the trace before the free?
Sure. Will do that.
-- Lina
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 4/4 drivers: qcom: rpmh: add RPMH helper functions
In reply to Lina IyerSending RPMH requests and waiting for response from the controller through a callback is common functionality across all platform drivers. To simplify drivers, add a library functions to create RPMH client and send resource state requests.
rpmh_write() is a synchronous blocking call that can be used to send active state requests.
--- drivers/soc/qcom/Makefile | 2 +- drivers/soc/qcom/rpmh-internal.h | 2 + drivers/soc/qcom/rpmh-rsc.c | 1 + drivers/soc/qcom/rpmh.c | 264 +++++++++++++++++++++++++++++++++++++++ include/soc/qcom/rpmh.h | 41 ++++++ 5 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/qcom/rpmh.c create mode 100644 include/soc/qcom/rpmh.h
drivers/soc/qcom/Makefile +1 -1
@@ -11,4 +11,4 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o -obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o +obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o rpmh.o
drivers/soc/qcom/rpmh-internal.h +2 -0
@@ -21,4 +21,6 @@ struct rsc_drv;int rpmh_rsc_send_data (struct rsc_drv *drv,struct tcs_mbox_msg *msg); +void rpmh_tx_done (struct tcs_mbox_msg *msg,int r); +#endif /* __RPM_INTERNAL_H__ */
drivers/soc/qcom/rpmh-rsc.c +1 -0
@@ -374,6 +374,7 @@ static void tcs_notify_tx_done(unsigned long data) msg = resp->msg;free_response (resp);trace_rpmh_notify (drv->name, m, msg->payload[0 ].addr, err); +rpmh_tx_done (msg, err); }while (1 ); }
drivers/soc/qcom/rpmh.c new file +264 -0
264 lines not on this page · raw message
include/soc/qcom/rpmh.h new file +41 -0
41 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH 4/4] drivers: qcom: rpmh: add RPMH helper functions
drivers/soc/qcom/Makefile obj-$(CONFIG_QCOM_SMP2P) += smp2p.o · line 14
Quoted 10 lines · Lina Iyer
drivers/soc/qcom/Makefile +1
-1@@ -11,4 +11,4 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o -obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o +obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o rpmh.o
I think it would be better if you built these two objects into the same module;
obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o
qcom_rpmh-y += rpmh-rsc.o
qcom_rpmh-y += rpmh.o
Quoted 1 line
drivers/soc/qcom/rpmh-internal.h +0
-0
[..]
Quoted 1 line
drivers/soc/qcom/rpmh.c +0
-0
[..]
Quoted 1 line
+#define
RPMH_TIMEOUTmsecs_to_jiffies(10000)
10 * HZ
Quoted 16 lines
drivers/soc/qcom/rpmh.c +16
-0+ +#define DEFINE_RPMH_MSG_ONSTACK (rc, s, q, c, name) \ + struct rpmh_msg name = { \ + .msg = { \ + .state = s, \ + .payload = name.cmd, \ + .num_payload = 0, \ + .is_complete = true, \ + .invalidate = false, \ + }, \ + .cmd = { { 0 } }, \ + .completion = q, \ + .wait_count = c, \ + .rc = rc, \ + } +
drivers/soc/qcom/rpmh.c line 56
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+/** +* rpmh_msg: the message to be sent to rpmh-rsc +* +* @msg: the request +* @cmd: the payload that will be part of the @msg +* @completion: triggered when request is done +* @wait_count: count of waiters for this completion +* @err: err return from the controller +*/ +struct rpmh_msg {
struct rpmh_request ?
drivers/soc/qcom/rpmh.c line 60
Quoted 4 lines
drivers/soc/qcom/rpmh.c +4
-0+struct tcs_mbox_msg msg; +struct tcs_cmd cmd[MAX_RPMH_PAYLOAD ]; +struct completion *completion; +atomic_t *wait_count;
When will @wait_count > 1? As far as I can see the only purpose would be to be able to control whether you should complete @completion 0 or N times; but 0 times is covered already by not specifying a @completion.
drivers/soc/qcom/rpmh.c line 71
Quoted 11 lines
drivers/soc/qcom/rpmh.c +11
-0+struct rpmh_client *rc; +int err; +}; + +/** +* rpmh_ctrlr: our representation of the controller +* +* @drv: the controller instance +*/ +struct rpmh_ctrlr { +struct rsc_drv *drv;
Is this going to grow in the future? Otherwise just drop it and reference the rsc_drv directly. (Even if it's growing it might be cleaner to introduce it at that point)
Quoted 5 lines
drivers/soc/qcom/rpmh.c +5
-0+}; + +/** +* rpmh_client: the client object +*
drivers/soc/qcom/rpmh.c line 86
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+* @dev: the platform device that is the owner +* @ctrlr: the controller associated with this client. +*/ +struct rpmh_client { +struct device *dev; +struct rpmh_ctrlr *ctrlr; +}; + +static struct rpmh_ctrlr rpmh_rsc[RPMH_MAX_MBOXES ]; +static DEFINE_MUTEX (rpmh_ctrlr_mutex);
The client needs a reference to the rsc_drv, using the rpmh_ctrlr abstraction and these global variables only seems to add unnecessary complexity.
Quoted 8 lines
drivers/soc/qcom/rpmh.c +8
-0+ +void rpmh_tx_done (struct tcs_mbox_msg *msg,int r) +{ + struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg); +atomic_t *wc = rpm_msg->wait_count; +struct completion *compl = rpm_msg->completion; + + rpm_msg->err = r;
drivers/soc/qcom/rpmh.c line 104
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+ +if (r) +dev_err (rpm_msg->rc->dev, +"RPMH TX fail in msg addr 0x%x, err=%d\n" , + rpm_msg->msg.payload[0 ].addr, r); + +/* Signal the blocking thread we are done */ +if (wc &&atomic_dec_and_test (wc)) +if (compl) +complete (compl);
I think that you should drop this function and just complete @rpm_msg->completion in the rcs driver.
Quoted 16 lines
drivers/soc/qcom/rpmh.c +16
-0+} +EXPORT_SYMBOL (rpmh_tx_done); + +/** +* wait_for_tx_done: Wait until the response is received. +* +* @rc: The RPMH client +* @compl: The completion object +* @addr: An addr that we sent in that request +* @data: The data for the address in that request +* +*/ +static inline int wait_for_tx_done (struct rpmh_client *rc, +struct completion *compl,u32 addr,u32 data) +{ +int ret;
drivers/soc/qcom/rpmh.c line 130
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+ + ret =wait_for_completion_timeout (compl,RPMH_TIMEOUT ); +if (ret) +dev_dbg (rc->dev, +"RPMH response received addr=0x%x data=0x%x\n" , + addr, data); +else +dev_err (rc->dev, +"RPMH response timeout addr=0x%x data=0x%x\n" , + addr, data);
The request can contain a number of commands and these error messages ends up printing the first one, on behalf of the client. I suspect that this isn't useful enough in most cases, causing the client to print another time.
I therefor suggest that you omit these prints.
Quoted 21 lines
drivers/soc/qcom/rpmh.c +21
-0+ +return (ret >0 ) ?0 : -ETIMEDOUT ; +} + +/** +* __rpmh_write: send the RPMH request +* +* @rc: The RPMH client +* @state: Active/Sleep request type +* @rpm_msg: The data that needs to be sent (payload). +*/ +int __rpmh_write (struct rpmh_client *rc,enum rpmh_state state, +struct rpmh_msg *rpm_msg) +{ +int ret = -EFAULT ; + + rpm_msg->msg.state = state; + +if (state ==RPMH_ACTIVE_ONLY_STATE ) { +WARN_ON (irqs_disabled ()); + ret =rpmh_rsc_send_data (rc->ctrlr->drv, &rpm_msg->msg);
drivers/soc/qcom/rpmh.c line 161
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+if (!ret) +dev_dbg (rc->dev, +"RPMH request sent addr=0x%x, data=0x%x\n" , + rpm_msg->msg.payload[0 ].addr, + rpm_msg->msg.payload[0 ].data); +else +dev_warn (rc->dev, +"Error in RPMH request addr=0x%x, data=0x%x\n" , + rpm_msg->msg.payload[0 ].addr, + rpm_msg->msg.payload[0 ].data);
Same thing here, for the user to be able to make sense of this error the client will have to print something with more context. So I think you should omit these too.
tracing failing addr/data pairs might make sense though!
Quoted 26 lines
drivers/soc/qcom/rpmh.c +26
-0+ } + +return ret; +} + +/** +* rpmh_write: Write a set of RPMH commands and block until response +* +* @rc: The RPMh handle got from rpmh_get_dev_channel +* @state: Active/sleep set +* @cmd: The payload data +* @n: The number of elements in payload +* +* May sleep. Do not call from atomic contexts. +*/ +int rpmh_write (struct rpmh_client *rc,enum rpmh_state state, +struct tcs_cmd *cmd,int n) +{ +DECLARE_COMPLETION_ONSTACK (compl); +atomic_t wait_count =ATOMIC_INIT (1 ); +DEFINE_RPMH_MSG_ONSTACK (rc, state, &compl, &wait_count, rpm_msg); +int ret; + +if (IS_ERR_OR_NULL (rc) || !cmd || n <=0 || n >MAX_RPMH_PAYLOAD ) +return -EINVAL ; +
drivers/soc/qcom/rpmh.c line 197
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+might_sleep (); + +memcpy (rpm_msg.cmd, cmd, n *sizeof (*cmd)); + rpm_msg.msg.num_payload = n; + + ret =__rpmh_write (rc, state, &rpm_msg); +if (ret) +return ret; + +return wait_for_tx_done (rc, &compl, cmd[0 ].addr, cmd[0 ].data);
As you're returning here the completion object on the stack will be trash, so you must inform rpmh_rsc that it may no longer complete it.
I suggest that you provide two functions in the rsc driver; rpmh_rsc_send_sync() and rpmh_rsc_send_async(), and move the wait-for-completion into the sync one. Also make the sync one return the msg->err (and drop the tx_done cross-call).
(Or call them rpmh_rsc_send_wait() and rpmh_rsc_send_nowait())
Quoted 16 lines
drivers/soc/qcom/rpmh.c +16
-0+} +EXPORT_SYMBOL (rpmh_write); + +static struct rpmh_ctrlr *get_rpmh_ctrlr (struct platform_device *pdev) +{ +int i; +struct rsc_drv *drv =dev_get_drvdata (pdev->dev.parent); +struct rpmh_ctrlr *ctrlr =ERR_PTR (-EFAULT ); + +if (!drv) +return ctrlr; + +mutex_lock (&rpmh_ctrlr_mutex); +for (i =0 ; i <RPMH_MAX_MBOXES ; i++) +if (rpmh_rsc[i].drv == drv) { + ctrlr = &rpmh_rsc[i];
drivers/soc/qcom/rpmh.c line 223
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+ goto unlock; + } + +if (i ==RPMH_MAX_MBOXES ) +for (i =0 ; i <RPMH_MAX_MBOXES ; i++) +if (rpmh_rsc[i].drv ==NULL ) { + ctrlr = &rpmh_rsc[i]; + ctrlr->drv = drv; +break ; + }
I fail to see the reason for tracking rsc_drv references in a global array and try to find an existing one here. Just return the rsc_drv acquired from dev_get_drvdata() to the caller.
drivers/soc/qcom/rpmh.c line 236
Quoted 13 lines
drivers/soc/qcom/rpmh.c +13
-0+unlock: +mutex_unlock (&rpmh_ctrlr_mutex); +return ctrlr; +} + +/** +* rpmh_get_client: Get the RPMh handle +* +* @pdev: the platform device which needs to communicate with RPM +* accelerators +* May sleep. +*/ +struct rpmh_client *rpmh_get_client (struct platform_device *pdev)
To make this analog to previous rpm drivers I think you should take the device * of the parent here. I.e. client does:
rpmh = rpmh_get_client(&pdev->dev.parent).
I recognize that this removes the possibility of providing error messages indicating which client caused the fault, but by above suggestions these functions would be moved into the rsc driver; or the error would be propagated to the client which could print these themselves.
Quoted 16 lines
drivers/soc/qcom/rpmh.c +16
-0+{ +struct rpmh_client *rc; + + rc =kzalloc (sizeof (*rc),GFP_KERNEL ); +if (!rc) +return ERR_PTR (-ENOMEM ); + + rc->dev = &pdev->dev; + rc->ctrlr =get_rpmh_ctrlr (pdev); +if (IS_ERR (rc->ctrlr)) { +kfree (rc); +return ERR_PTR (-EFAULT ); + } + +return rc; +}
drivers/soc/qcom/rpmh.c line 262
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+EXPORT_SYMBOL (rpmh_get_client); + +/** +* rpmh_release: Release the RPMH client +* +* @rc: The RPMh handle to be freed. +*/ +void rpmh_release (struct rpmh_client *rc) +{ +kfree (rc);
If you reduce above function to just return a rsc_drv reference you don't even need a release function, which simplifies clients further.
Quoted 3 lines
drivers/soc/qcom/rpmh.c +2
-0+} +EXPORT_SYMBOL (rpmh_release);include/soc/qcom/rpmh.h +0
-0
[..]
include/soc/qcom/rpmh.h line 21
Quoted 3 lines
include/soc/qcom/rpmh.h +3
-0+struct rpmh_client ; + +#ifdef CONFIG_QCOM_RPMH
I think it would be fine to just make clients depend on QCOM_RPMH. If you would prefer to get the compile testing in those drivers then make this:
#if IS_ENABLED(CONFIG_QCOM_RPMH)
In case someone in the future decides to make RPMH tristate.
Regards,
Bjorn
Re: [PATCH 4/4] drivers: qcom: rpmh: add RPMH helper functions
Quoted 15 lines · Bjorn Andersson
drivers/soc/qcom/Makefile obj-$(CONFIG_QCOM_SMP2P) += smp2p.o · line 14
Quoted 10 lines · Lina Iyer
drivers/soc/qcom/Makefile +1
-1@@ -11,4 +11,4 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o -obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o +obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o rpmh.oI think it would be better if you built these two objects into the same module;
Quoted 4 lines
obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o
qcom_rpmh-y += rpmh-rsc.o
qcom_rpmh-y += rpmh.o
Curious, how this would be better?
Quoted 28 lines
Quoted 1 line
drivers/soc/qcom/rpmh-internal.h +0
-0[..]
Quoted 1 line
drivers/soc/qcom/rpmh.c +0
-0[..]
Quoted 1 line
+#define
RPMH_TIMEOUTmsecs_to_jiffies(10000)10 * HZ
Quoted 20 lines
drivers/soc/qcom/rpmh.c +20
-0+ +#define DEFINE_RPMH_MSG_ONSTACK (rc, s, q, c, name) \ + struct rpmh_msg name = { \ + .msg = { \ + .state = s, \ + .payload = name.cmd, \ + .num_payload = 0, \ + .is_complete = true, \ + .invalidate = false, \ + }, \ + .cmd = { { 0 } }, \ + .completion = q, \ + .wait_count = c, \ + .rc = rc, \ + } + +/** +* rpmh_msg: the message to be sent to rpmh-rsc +* +* @msg: the request
Quoted 9 lines
Quoted 6 lines
+ * @cmd: the payload that will be part of the @msg
+ * @completion: triggered when request is done
+ * @wait_count: count of waiters for this completion
+ * @err: err return from the controller
+ */
+structrpmh_msg{struct
rpmh_request?
Hmm.. ok.
Quoted 9 lines
drivers/soc/qcom/rpmh.c line 60
Quoted 4 lines
drivers/soc/qcom/rpmh.c +4
-0+struct tcs_mbox_msg msg; +struct tcs_cmd cmd[MAX_RPMH_PAYLOAD ]; +struct completion *completion; +atomic_t *wait_count;When will @wait_count > 1? As far as I can see the only purpose would be to be able to control whether you should complete @completion 0 or N times; but 0 times is covered already by not specifying a @completion.
There is a patch that I haven't posted in this series. It sends a batch of requests instead of just 1. The wait count is equal to the number of requests in that batch. Sorry it is a bit ahead of its real use. Adding it later, increases unnecessary changes in the patches.
Quoted 7 lines
Quoted 7 lines
drivers/soc/qcom/rpmh.c +7
-0+struct rpmh_client *rc; +int err; +}; + +/** +* rpmh_ctrlr: our representation of the controller +*
Quoted 9 lines
drivers/soc/qcom/rpmh.c line 71
Quoted 4 lines
+ * @drv: the controller instance
+ */drivers/soc/qcom/rpmh.c +2
-0+struct rpmh_ctrlr { +struct rsc_drv *drv;Is this going to grow in the future? Otherwise just drop it and reference the
rsc_drvdirectly. (Even if it's growing it might be cleaner to introduce it at that point)
Will grow :)
Quoted 11 lines
Quoted 11 lines
drivers/soc/qcom/rpmh.c +11
-0+}; + +/** +* rpmh_client: the client object +* +* @dev: the platform device that is the owner +* @ctrlr: the controller associated with this client. +*/ +struct rpmh_client { +struct device *dev; +struct rpmh_ctrlr *ctrlr;
Quoted 9 lines
drivers/soc/qcom/rpmh.c line 86
Quoted 4 lines
drivers/soc/qcom/rpmh.c +4
-0+}; + +static struct rpmh_ctrlr rpmh_rsc[RPMH_MAX_MBOXES ]; +static DEFINE_MUTEX (rpmh_ctrlr_mutex);The client needs a reference to the
rsc_drv, using therpmh_ctrlrabstraction and these global variables only seems to add unnecessary complexity.
There would be more functionality that needs these as structures and a list of RSCs and therefore the global mutex and array.
Please bear with me on this.
Quoted 13 lines
Quoted 13 lines
drivers/soc/qcom/rpmh.c +13
-0+ +void rpmh_tx_done (struct tcs_mbox_msg *msg,int r) +{ + struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg); +atomic_t *wc = rpm_msg->wait_count; +struct completion *compl = rpm_msg->completion; + + rpm_msg->err = r; + +if (r) +dev_err (rpm_msg->rc->dev, +"RPMH TX fail in msg addr 0x%x, err=%d\n" , + rpm_msg->msg.payload[0 ].addr, r);
Quoted 9 lines
drivers/soc/qcom/rpmh.c line 104
Quoted 5 lines
drivers/soc/qcom/rpmh.c +5
-0+ +/* Signal the blocking thread we are done */ +if (wc &&atomic_dec_and_test (wc)) +if (compl) +complete (compl);I think that you should drop this function and just complete @rpm_msg->completion in the rcs driver.
I am not sure how much of it I can upstream. Downstream I add more functionality to this function to make it easier to debug on production. If its not a bother I would like to keep it as is. Who knows, may be I can get the debug code upstream.
Quoted 32 lines
Quoted 16 lines
drivers/soc/qcom/rpmh.c +16
-0+} +EXPORT_SYMBOL (rpmh_tx_done); + +/** +* wait_for_tx_done: Wait until the response is received. +* +* @rc: The RPMH client +* @compl: The completion object +* @addr: An addr that we sent in that request +* @data: The data for the address in that request +* +*/ +static inline int wait_for_tx_done (struct rpmh_client *rc, +struct completion *compl,u32 addr,u32 data) +{ +int ret;drivers/soc/qcom/rpmh.c line 130
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+ + ret =wait_for_completion_timeout (compl,RPMH_TIMEOUT ); +if (ret) +dev_dbg (rc->dev, +"RPMH response received addr=0x%x data=0x%x\n" , + addr, data); +else +dev_err (rc->dev, +"RPMH response timeout addr=0x%x data=0x%x\n" , + addr, data);The request can contain a number of commands and these error messages ends up printing the first one, on behalf of the client. I suspect that this isn't useful enough in most cases, causing the client to print another time.
Quoted 2 lines
I therefor suggest that you omit these prints.
On the contrary, just the first address in the request is quite sufficient to know what request failed. The rest of the requests in dumped in the FTRACE while sending the request. That is enough to know what was sent and correlate with what failed.
Quoted 37 lines
Quoted 21 lines
drivers/soc/qcom/rpmh.c +21
-0+ +return (ret >0 ) ?0 : -ETIMEDOUT ; +} + +/** +* __rpmh_write: send the RPMH request +* +* @rc: The RPMH client +* @state: Active/Sleep request type +* @rpm_msg: The data that needs to be sent (payload). +*/ +int __rpmh_write (struct rpmh_client *rc,enum rpmh_state state, +struct rpmh_msg *rpm_msg) +{ +int ret = -EFAULT ; + + rpm_msg->msg.state = state; + +if (state ==RPMH_ACTIVE_ONLY_STATE ) { +WARN_ON (irqs_disabled ()); + ret =rpmh_rsc_send_data (rc->ctrlr->drv, &rpm_msg->msg);drivers/soc/qcom/rpmh.c line 161
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+if (!ret) +dev_dbg (rc->dev, +"RPMH request sent addr=0x%x, data=0x%x\n" , + rpm_msg->msg.payload[0 ].addr, + rpm_msg->msg.payload[0 ].data); +else +dev_warn (rc->dev, +"Error in RPMH request addr=0x%x, data=0x%x\n" , + rpm_msg->msg.payload[0 ].addr, + rpm_msg->msg.payload[0 ].data);Same thing here, for the user to be able to make sense of this error the client will have to print something with more context. So I think you should omit these too.
Quoted 2 lines
tracing failing addr/data pairs might make sense though!
See explanation above.
Quoted 40 lines
Quoted 26 lines
drivers/soc/qcom/rpmh.c +26
-0+ } + +return ret; +} + +/** +* rpmh_write: Write a set of RPMH commands and block until response +* +* @rc: The RPMh handle got from rpmh_get_dev_channel +* @state: Active/sleep set +* @cmd: The payload data +* @n: The number of elements in payload +* +* May sleep. Do not call from atomic contexts. +*/ +int rpmh_write (struct rpmh_client *rc,enum rpmh_state state, +struct tcs_cmd *cmd,int n) +{ +DECLARE_COMPLETION_ONSTACK (compl); +atomic_t wait_count =ATOMIC_INIT (1 ); +DEFINE_RPMH_MSG_ONSTACK (rc, state, &compl, &wait_count, rpm_msg); +int ret; + +if (IS_ERR_OR_NULL (rc) || !cmd || n <=0 || n >MAX_RPMH_PAYLOAD ) +return -EINVAL ; +drivers/soc/qcom/rpmh.c line 197
Quoted 10 lines
drivers/soc/qcom/rpmh.c +10
-0+might_sleep (); + +memcpy (rpm_msg.cmd, cmd, n *sizeof (*cmd)); + rpm_msg.msg.num_payload = n; + + ret =__rpmh_write (rc, state, &rpm_msg); +if (ret) +return ret; + +return wait_for_tx_done (rc, &compl, cmd[0 ].addr, cmd[0 ].data);As you're returning here the completion object on the stack will be trash, so you must inform
rpmh_rscthat it may no longer complete it.
Quoted 7 lines
I suggest that you provide two functions in the rsc driver;
rpmh_rsc_send_sync()andrpmh_rsc_send_async(), and move the wait-for-completion into the sync one. Also make the sync one return themsg->err(and drop thetx_donecross-call).(Or call them
rpmh_rsc_send_wait()andrpmh_rsc_send_nowait())
This is the sync variant. The async variant follows this patch.
The wait_for_tx_done() is blocking and the compl object will not be trashed until the completion is completed or it fails.
Quoted 22 lines
Quoted 22 lines
drivers/soc/qcom/rpmh.c +22
-0+} +EXPORT_SYMBOL (rpmh_write); + +static struct rpmh_ctrlr *get_rpmh_ctrlr (struct platform_device *pdev) +{ +int i; +struct rsc_drv *drv =dev_get_drvdata (pdev->dev.parent); +struct rpmh_ctrlr *ctrlr =ERR_PTR (-EFAULT ); + +if (!drv) +return ctrlr; + +mutex_lock (&rpmh_ctrlr_mutex); +for (i =0 ; i <RPMH_MAX_MBOXES ; i++) +if (rpmh_rsc[i].drv == drv) { + ctrlr = &rpmh_rsc[i]; + goto unlock; + } + +if (i ==RPMH_MAX_MBOXES ) +for (i =0 ; i <RPMH_MAX_MBOXES ; i++) +if (rpmh_rsc[i].drv ==NULL ) {
Quoted 9 lines
drivers/soc/qcom/rpmh.c line 223
Quoted 4 lines
drivers/soc/qcom/rpmh.c +4
-0+ ctrlr = &rpmh_rsc[i]; + ctrlr->drv = drv; +break ; + }I fail to see the reason for tracking
rsc_drvreferences in a global array and try to find an existing one here. Just return thersc_drvacquired fromdev_get_drvdata()to the caller.
There are multiple RSCs and clients would refer to one of them.
Future patches add information to the RSC as dictated by the client (display driver is using the RSC) and therefore take action accordingly.
Quoted 17 lines
drivers/soc/qcom/rpmh.c line 236
Quoted 13 lines
drivers/soc/qcom/rpmh.c +13
-0+unlock: +mutex_unlock (&rpmh_ctrlr_mutex); +return ctrlr; +} + +/** +* rpmh_get_client: Get the RPMh handle +* +* @pdev: the platform device which needs to communicate with RPM +* accelerators +* May sleep. +*/ +struct rpmh_client *rpmh_get_client (struct platform_device *pdev)To make this analog to previous rpm drivers I think you should take the device * of the parent here. I.e. client does:
Quoted 9 lines
rpmh = rpmh_get_client(&pdev->dev.parent).I recognize that this removes the possibility of providing error messages indicating which client caused the fault, but by above suggestions these functions would be moved into the rsc driver; or the error would be propagated to the client which could print these themselves.
I don't see a particular reason to be analogous with RPM. But, let me think about it.
Quoted 21 lines
Quoted 21 lines
drivers/soc/qcom/rpmh.c +21
-0+{ +struct rpmh_client *rc; + + rc =kzalloc (sizeof (*rc),GFP_KERNEL ); +if (!rc) +return ERR_PTR (-ENOMEM ); + + rc->dev = &pdev->dev; + rc->ctrlr =get_rpmh_ctrlr (pdev); +if (IS_ERR (rc->ctrlr)) { +kfree (rc); +return ERR_PTR (-EFAULT ); + } + +return rc; +} +EXPORT_SYMBOL (rpmh_get_client); + +/** +* rpmh_release: Release the RPMH client +*
Quoted 9 lines
drivers/soc/qcom/rpmh.c line 262
Quoted 5 lines
+ * @rc: The RPMh handle to be freed.
+ */drivers/soc/qcom/rpmh.c +3
-0+void rpmh_release (struct rpmh_client *rc) +{ +kfree (rc);If you reduce above function to just return a
rsc_drvreference you don't even need a release function, which simplifies clients further.
Hmm.. not sure I understand. I need to release the allocated memory.
Quoted 12 lines
Quoted 3 lines
drivers/soc/qcom/rpmh.c +2
-0+} +EXPORT_SYMBOL (rpmh_release);include/soc/qcom/rpmh.h +0
-0[..]
include/soc/qcom/rpmh.h line 21
Quoted 3 lines
include/soc/qcom/rpmh.h +3
-0+struct rpmh_client ; + +#ifdef CONFIG_QCOM_RPMH I think it would be fine to just make clients depend on
QCOM_RPMH. If you would prefer to get the compile testing in those drivers then make this:
Quoted 4 lines
#if
IS_ENABLED(CONFIG_QCOM_RPMH)In case someone in the future decides to make RPMH tristate.
OK.
Thanks,
Lina
A message that is not in the archive (sent off-list or not yet received): 20180119000157.7380-5-ilina-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
Re: [PATCH 4/4] drivers: qcom: rpmh: add RPMH helper functions
[]..
Quoted 35 lines
drivers/soc/qcom/rpmh.c new file +29
-0@@ -0,0 +1,264 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/atomic.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/wait.h> + +#include <soc/qcom/rpmh.h> + +#include "rpmh-internal.h" + +#define RPMH_MAX_MBOXES 2
drivers/soc/qcom/rpmh.c line 39
Quoted 10 lines
drivers/soc/qcom/rpmh.c new file +10
-0+#define RPMH_TIMEOUT msecs_to_jiffies(10000) + +#define DEFINE_RPMH_MSG_ONSTACK (rc, s, q, c, name) +struct rpmh_msg name = { \ + .msg = { \ + .state = s, \ + .payload = name.cmd, \ + .num_payload =0 , \ + .is_complete = true, \ + .invalidate = false, \
There seems to be no field called 'invalidate' as part of the struct
Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 4/4] drivers: qcom: rpmh: add RPMH helper functions
Quoted 41 lines · Rajendra Nayak
[]..
Quoted 39 lines
drivers/soc/qcom/rpmh.c new file +33
-0@@ -0,0 +1,264 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include <linux/atomic.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/wait.h> + +#include <soc/qcom/rpmh.h> + +#include "rpmh-internal.h" + +#define RPMH_MAX_MBOXES 2 +#define RPMH_TIMEOUT msecs_to_jiffies(10000) + +#define DEFINE_RPMH_MSG_ONSTACK (rc, s, q, c, name) +struct rpmh_msg name = { \
Quoted 9 lines
drivers/soc/qcom/rpmh.c line 39
Quoted 6 lines
drivers/soc/qcom/rpmh.c new file +6
-0+ .msg = { \ + .state = s, \ + .payload = name.cmd, \ + .num_payload = 0, \ + .is_complete = true, \ + .invalidate = false, \There seems to be no field called 'invalidate' as part of the struct
Yup. Sorry, I will remove it in the next revision. I should be posting one in a day or so.
Thanks,
Lina