Skip to contentSkip to conversation

: support for spmi_pmic_arb v3/v5 and bug fixes

PATCH In review Kiran Gunda 3 participants 60 messages May 30, 2017 – Jul 18, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover : support for spmi_pmic_arb v3/v5 and bug fixes

This patch series add the support for pmic arbiter hardware v3 and v5 support along with the multiple bug fixes and code cleanup.
spmi_pmic_arb v3: Added 512 channel support. spmi_pmic_arb v5: Register offset changes.
Multiple EEs can write to a single PPID.

Abhijeet Dharmapurikar (12):
spmi: pmic_arb: block access of invalid read and writes
spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb
spmi: pmic-arb: fix inconsistent use of apid and chan
spmi: pmic-arb: optimize table lookups
spmi: pmic-arb: cleanup unrequested irqs
spmi: pmic-arb: fix missing interrupts
spmi: pmic-arb: clear the latched status of the interrupt
spmi: pmic_arb: use appropriate flow handler
spmi: pmic-arb: check apid enabled before calling the handler
spmi: pmic_arb: add support for PMIC bus arbiter v3
spmi-pmic-arb: fix a possible null pointer dereference
spmi: pmic-arb: instantiate spmi_devices at arch_initcall

David Collins (1):
spmi: pmic-arb: add support for HW version 5

Kiran Gunda (1):
spmi: spmi-pmic-arb: enable the SPMI interrupt as a wakeup source

Subbaraman Narayanamurthy (1):
spmi: pmic-arb: do not ack and clear peripheral interrupts in
cleanup_irq

 drivers/spmi/spmi-pmic-arb.c | 818 ++++++++++++++++++++++++++++++-------------
 1 file changed, 578 insertions(+), 240 deletions(-)
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#1 lore raw

PATCH 1/15 spmi: pmic_arb: block access of invalid read and writes

From: Abhijeet Dharmapurikar <[email protected]>

The system crashes due to bad access when reading from an non configured peripheral and when writing to peripheral which is not owned by current ee. This patch verifies ownership to avoid crashing on write.
For reads, since the forward mapping table, data_channel->ppid, is towards the end of the block, we use the core size to figure the max number of ppids supported. The table starts at an offset of 0x800 within the block, so size - 0x800 will give us the area used by the table. Since each table is 4 bytes long (core_size - 0x800) / 4 will gives us the number of data_channel supported.
This new protection is functional on hw v2.

---
 drivers/spmi/spmi-pmic-arb.c | 84 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)
drivers/spmi/spmi-pmic-arb.c +83 -1
index 5ec3a59..df463d4 100644
@@ -111,6 +111,7 @@ enum pmic_arb_cmd_op_code {
  * @ee:			the current Execution Environment
  * @min_apid:		minimum APID (used for bounding IRQ search)
  * @max_apid:		maximum APID
+ * @max_periph:		maximum number of PMIC peripherals supported by HW.
  * @mapping_table:	in-memory copy of PPID -> APID mapping table.
  * @domain:		irq domain object for PMIC IRQ domain
  * @spmic:		SPMI controller object
@@ -132,6 +133,7 @@ struct spmi_pmic_arb_dev {
 	u8			ee;
 	u16			min_apid;
 	u16			max_apid;
+	u16			max_periph;
 	u32			*mapping_table;
 	DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
 	struct irq_domain	*domain;
@@ -140,11 +142,13 @@ struct spmi_pmic_arb_dev {
 	const struct pmic_arb_ver_ops *ver_ops;
 	u16			*ppid_to_chan;
 	u16			last_channel;
+	u8			*chan_to_owner;
 };
 
 /**
  * pmic_arb_ver: version dependent functionality.
  *
+ * @mode:	access rights to specified pmic peripheral.
  * @non_data_cmd:	on v1 issues an spmi non-data command.
  *			on v2 no HW support, returns -EOPNOTSUPP.
  * @offset:		on v1 offset of per-ee channel.
@@ -160,6 +164,8 @@ struct spmi_pmic_arb_dev {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
+	int (*mode)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
 	int (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
 		      u32 *offset);
@@ -313,11 +319,23 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 cmd;
 	int rc;
 	u32 offset;
+	mode_t mode;
 
 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
 	if (rc)
 		return rc;
 
+	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	if (rc)
+		return rc;
+
+	if (!(mode & S_IRUSR)) {
+		dev_err(&pmic_arb->spmic->dev,
+			"error: impermissible read from peripheral sid:%d addr:0x%x\n",
+			sid, addr);
+		return -EPERM;
+	}
+
 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
 		dev_err(&ctrl->dev,
 			"pmic-arb supports 1..%d bytes per trans, but:%zu requested",
@@ -364,11 +382,23 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 cmd;
 	int rc;
 	u32 offset;
+	mode_t mode;
 
 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
 	if (rc)
 		return rc;
 
+	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	if (rc)
+		return rc;
+
+	if (!(mode & S_IWUSR)) {
+		dev_err(&pmic_arb->spmic->dev,
+			"error: impermissible write to peripheral sid:%d addr:0x%x\n",
+			sid, addr);
+		return -EPERM;
+	}
+
 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
 		dev_err(&ctrl->dev,
 			"pmic-arb supports 1..%d bytes per trans, but:%zu requested",
@@ -727,6 +757,13 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 	return 0;
 }
 
+static int
+pmic_arb_mode_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, mode_t *mode)
+{
+	*mode = S_IRUSR | S_IWUSR;
+	return 0;
+}
+
 /* v1 offset per ee */
 static int
 pmic_arb_offset_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)
@@ -745,7 +782,11 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
 	 * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.
 	 * ppid_to_chan is an in-memory invert of that table.
 	 */
-	for (chan = pa->last_channel; ; chan++) {
+	for (chan = pa->last_channel; chan < pa->max_periph; chan++) {
+		regval = readl_relaxed(pa->cnfg +
+				      SPMI_OWNERSHIP_TABLE_REG(chan));
+		pa->chan_to_owner[chan] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+
 		offset = PMIC_ARB_REG_CHNL(chan);
 		if (offset >= pa->core_size)
 			break;
@@ -767,6 +808,27 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
 }
 
 
+static int
+pmic_arb_mode_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, mode_t *mode)
+{
+	u16 ppid = (sid << 8) | (addr >> 8);
+	u16 chan;
+	u8 owner;
+
+	chan = pa->ppid_to_chan[ppid];
+	if (!(chan & PMIC_ARB_CHAN_VALID))
+		return -ENODEV;
+
+	*mode = 0;
+	*mode |= S_IRUSR;
+
+	chan &= ~PMIC_ARB_CHAN_VALID;
+	owner = pa->chan_to_owner[chan];
+	if (owner == pa->ee)
+		*mode |= S_IWUSR;
+	return 0;
+}
+
 /* v2 offset per ppid (chan) and per ee */
 static int
 pmic_arb_offset_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)
@@ -836,6 +898,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
 }
 
 static const struct pmic_arb_ver_ops pmic_arb_v1 = {
+	.mode			= pmic_arb_mode_v1,
 	.non_data_cmd		= pmic_arb_non_data_cmd_v1,
 	.offset			= pmic_arb_offset_v1,
 	.fmt_cmd		= pmic_arb_fmt_cmd_v1,
@@ -846,6 +909,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v2 = {
+	.mode			= pmic_arb_mode_v2,
 	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
 	.offset			= pmic_arb_offset_v2,
 	.fmt_cmd		= pmic_arb_fmt_cmd_v2,
@@ -879,6 +943,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
 	pa->core_size = resource_size(res);
+	if (pa->core_size <= 0x800) {
+		dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing Probe\n");
+		err = -EINVAL;
+		goto err_put_ctrl;
+	}
+
 	core = devm_ioremap_resource(&ctrl->dev, res);
 	if (IS_ERR(core)) {
 		err = PTR_ERR(core);
@@ -899,6 +969,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		pa->core = core;
 		pa->ver_ops = &pmic_arb_v2;
 
+		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
+		pa->max_periph =  (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
 		pa->rd_base = devm_ioremap_resource(&ctrl->dev, res);
@@ -923,6 +996,15 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 			err = -ENOMEM;
 			goto err_put_ctrl;
 		}
+
+		pa->chan_to_owner = devm_kcalloc(&ctrl->dev,
+						 pa->max_periph,
+						 sizeof(*pa->chan_to_owner),
+						 GFP_KERNEL);
+		if (!pa->chan_to_owner) {
+			err = -ENOMEM;
+			goto err_put_ctrl;
+		}
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#2 lore raw

Re: [PATCH V1 01/15] spmi: pmic_arb: block access of invalid read and writes

Quoted 6 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The system crashes due to bad access when reading from an non configured peripheral and when writing to peripheral which is not owned by current ee. This patch verifies ownership to avoid crashing on write.

What systems? As far as I know we don't have any bad accesses happening right now. If they are happening, we should fix the code that's accessing hardware that isn't owned by them.

Quoted 7 lines

For reads, since the forward mapping table, data_channel->ppid, is towards the end of the block, we use the core size to figure the max number of ppids supported. The table starts at an offset of 0x800 within the block, so size - 0x800 will give us the area used by the table. Since each table is 4 bytes long (core_size - 0x800) / 4 will gives us the number of data_channel supported.
This new protection is functional on hw v2.

Which brings us to the next question which is why do we need this patch at all? We aren't probing hardware to see what we have access to and then populating device structures based on that. Instead, we're just populating DT nodes that we've hardcoded in the dts files, so I'm a little lost on why we would have a node in there that we couldn't access. Please add such details to the commit text.

Quoted 12 lines
---
 drivers/spmi/spmi-pmic-arb.c | 84 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)
drivers/spmi/spmi-pmic-arb.c +0 -0
index 5ec3a59..df463d4 100644

drivers/spmi/spmi-pmic-arb.c enum pmic_arb_cmd_op_code { · line 114

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
@@ -111,6 +111,7 @@ enum pmic_arb_cmd_op_code {
  * @ee:			the current Execution Environment
  * @min_apid:		minimum APID (used for bounding IRQ search)
  * @max_apid:		maximum APID
+ * @max_periph:		maximum number of PMIC peripherals supported by HW.

Nitpick: Most of these lines don't end with a full-stop.

Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
  * @mapping_table:	in-memory copy of PPID -> APID mapping table.
  * @domain:		irq domain object for PMIC IRQ domain
  * @spmic:		SPMI controller object
@@ -132,6 +133,7 @@ struct spmi_pmic_arb_dev {
 	u8			ee;
 	u16			min_apid;
 	u16			max_apid;
+	u16			max_periph;
 	u32			*mapping_table;
 	DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
 	struct irq_domain	*domain;

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_dev { · line 145

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
@@ -140,11 +142,13 @@ struct spmi_pmic_arb_dev {
 	const struct pmic_arb_ver_ops *ver_ops;
 	u16			*ppid_to_chan;
 	u16			last_channel;
+	u8			*chan_to_owner;

And we didn't document this one.

Quoted 23 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
 };
 
 /**
  * pmic_arb_ver: version dependent functionality.
  *
+ * @mode:	access rights to specified pmic peripheral.
  * @non_data_cmd:	on v1 issues an spmi non-data command.
  *			on v2 no HW support, returns -EOPNOTSUPP.
  * @offset:		on v1 offset of per-ee channel.
@@ -160,6 +164,8 @@ struct spmi_pmic_arb_dev {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
+	int (*mode)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
 	int (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
 		      u32 *offset);
@@ -313,11 +319,23 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 cmd;
 	int rc;
 	u32 offset;
+	mode_t mode;

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · line 332

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
 
 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
 	if (rc)
 		return rc;
 
+	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	if (rc)
+		return rc;
+
+	if (!(mode & S_IRUSR)) {

Using mode_t for hardware access is odd. Perhaps just come up with some sort of READ/WRITE enum instead (if this sort of checking is even needed)?

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · line 333

Quoted 1 line
drivers/spmi/spmi-pmic-arb.c +1 -0
+		dev_err(&pmic_arb->spmic->dev,

The dev_err() just after uses ctrl->dev? Why not here?

Quoted 14 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
+			"error: impermissible read from peripheral sid:%d addr:0x%x\n",
+			sid, addr);
+		return -EPERM;
+	}
+
 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
 		dev_err(&ctrl->dev,
 			"pmic-arb supports 1..%d bytes per trans, but:%zu requested",
@@ -364,11 +382,23 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 cmd;
 	int rc;
 	u32 offset;
+	mode_t mode;
 

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · line 396

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
 	if (rc)
 		return rc;
 
+	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	if (rc)
+		return rc;
+
+	if (!(mode & S_IWUSR)) {
+		dev_err(&pmic_arb->spmic->dev,

The dev_err() just after uses ctrl->dev? Why not here?

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
+			"error: impermissible write to peripheral sid:%d addr:0x%x\n",
+			sid, addr);
+		return -EPERM;
+	}
+
 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
 		dev_err(&ctrl->dev,
 			"pmic-arb supports 1..%d bytes per trans, but:%zu requested",

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 764

Quoted 8 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
@@ -727,6 +757,13 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 	return 0;
 }
 
+static int
+pmic_arb_mode_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, mode_t *mode)
+{
+	*mode = S_IRUSR | S_IWUSR;
+	return 0;

If mode was only positive then errors could be negative and no access could be 0. Then we could just return the mode from the function instead of passing a pointer around.

Quoted 8 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
+}
+
 /* v1 offset per ee */
 static int
 pmic_arb_offset_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)
@@ -745,7 +782,11 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
 	 * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.
 	 * ppid_to_chan is an in-memory invert of that table.

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid) · line 792

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +5 -1
 	 */
-	for (chan = pa->last_channel; ; chan++) {
+	for (chan = pa->last_channel; chan < pa->max_periph; chan++) {
+		regval = readl_relaxed(pa->cnfg +
+				      SPMI_OWNERSHIP_TABLE_REG(chan));
+		pa->chan_to_owner[chan] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+
 		offset = PMIC_ARB_REG_CHNL(chan);
 		if (offset >= pa->core_size)
 			break;

Seems like an unrelated change to the mapping logic?

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid) · line 812

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
@@ -767,6 +808,27 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
 }
 
 
+static int
+pmic_arb_mode_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, mode_t *mode)

Probably spmi_pmic_arb_dev should be const here.

Quoted 23 lines
drivers/spmi/spmi-pmic-arb.c +19 -0
+{
+	u16 ppid = (sid << 8) | (addr >> 8);
+	u16 chan;
+	u8 owner;
+
+	chan = pa->ppid_to_chan[ppid];
+	if (!(chan & PMIC_ARB_CHAN_VALID))
+		return -ENODEV;
+
+	*mode = 0;
+	*mode |= S_IRUSR;
+
+	chan &= ~PMIC_ARB_CHAN_VALID;
+	owner = pa->chan_to_owner[chan];
+	if (owner == pa->ee)
+		*mode |= S_IWUSR;
+	return 0;
+}
+
 /* v2 offset per ppid (chan) and per ee */
 static int
 pmic_arb_offset_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 947

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
@@ -879,6 +943,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
 	pa->core_size = resource_size(res);
+	if (pa->core_size <= 0x800) {
+		dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing Probe\n");

Not sure why probe is capitalized.

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 951

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+		err = -EINVAL;
+		goto err_put_ctrl;
+	}
+

We don't need these sorts of DT validation checks. Please remove.

Quoted 14 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
 	core = devm_ioremap_resource(&ctrl->dev, res);
 	if (IS_ERR(core)) {
 		err = PTR_ERR(core);
@@ -899,6 +969,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		pa->core = core;
 		pa->ver_ops = &pmic_arb_v2;
 
+		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
+		pa->max_periph =  (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
 		pa->rd_base = devm_ioremap_resource(&ctrl->dev, res);
Quoted 4 lines

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");

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

P.S. Please put a newline in your signature so it doesn't exceed 80 columns.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#3 lore raw

Re: [PATCH V1 01/15] spmi: pmic_arb: block access of invalid read and writes

Quoted 12 lines · Stephen Boyd
Quoted 6 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The system crashes due to bad access when reading from an non configured peripheral and when writing to peripheral which is not owned by current ee. This patch verifies ownership to avoid crashing on write.

What systems? As far as I know we don't have any bad accesses happening right now. If they are happening, we should fix the code that's accessing hardware that isn't owned by them.

This change greatly improves the debugging effort for developers by printing a very simple and clear error message when an invalid SPMI access occurs (due to bad DT configuration, bad bootloader SPMI permission configurations, or other issues). Without this change, such accesses will cause XPU violations that crash the system and require extensive effort to decode.

Quoted 8 lines
Quoted 7 lines

For reads, since the forward mapping table, data_channel->ppid, is towards the end of the block, we use the core size to figure the max number of ppids supported. The table starts at an offset of 0x800 within the block, so size - 0x800 will give us the area used by the table. Since each table is 4 bytes long (core_size - 0x800) / 4 will gives us the number of data_channel supported.
This new protection is functional on hw v2.

Quoted 8 lines

Which brings us to the next question which is why do we need this patch at all? We aren't probing hardware to see what we have access to and then populating device structures based on that. Instead, we're just populating DT nodes that we've hardcoded in the dts files, so I'm a little lost on why we would have a node in there that we couldn't access. Please add such details to the commit text.

invalid SPMI access occurs due to bad DT configuration, bad bootloader SPMI permission configurations, or other issues. This change reduces the debugging effort for developers by printing clear error message when an invalid SPMI access occurs.

Quoted 8 lines
Quoted 8 lines
---
 drivers/spmi/spmi-pmic-arb.c | 84 
+++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)
Quoted 12 lines

drivers/spmi/spmi-pmic-arb.c enum pmic_arb_cmd_op_code { · line 114

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
index 5ec3a59..df463d4 100644
@@ -111,6 +111,7 @@ enum pmic_arb_cmd_op_code {
  * @ee:			the current Execution Environment
  * @min_apid:		minimum APID (used for bounding IRQ search)
  * @max_apid:		maximum APID
+ * @max_periph:		maximum number of PMIC peripherals supported by HW.

Nitpick: Most of these lines don't end with a full-stop.

Will address in the next clean up patch.

Quoted 10 lines
Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
  * @mapping_table:	in-memory copy of PPID -> APID mapping table.
  * @domain:		irq domain object for PMIC IRQ domain
  * @spmic:		SPMI controller object
@@ -132,6 +133,7 @@ struct spmi_pmic_arb_dev {
 	u8			ee;
 	u16			min_apid;
 	u16			max_apid;
+	u16			max_periph;
 	u32			*mapping_table;
 	DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_dev { · line 145

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
 	struct irq_domain	*domain;
@@ -140,11 +142,13 @@ struct spmi_pmic_arb_dev {
 	const struct pmic_arb_ver_ops *ver_ops;
 	u16			*ppid_to_chan;
 	u16			last_channel;
+	u8			*chan_to_owner;

And we didn't document this one.

Will document in the next clean up patch.

Quoted 29 lines
Quoted 29 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
 };
 
 /**
  * pmic_arb_ver: version dependent functionality.
  *
+ * @mode:	access rights to specified pmic peripheral.
  * @non_data_cmd:	on v1 issues an spmi non-data command.
  *			on v2 no HW support, returns -EOPNOTSUPP.
  * @offset:		on v1 offset of per-ee channel.
@@ -160,6 +164,8 @@ struct spmi_pmic_arb_dev {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
+	int (*mode)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
 	int (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
 		      u32 *offset);
@@ -313,11 +319,23 @@ static int pmic_arb_read_cmd(struct 
 spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 cmd;
 	int rc;
 	u32 offset;
+	mode_t mode;
 
 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
 	if (rc)
 		return rc;
 
Quoted 10 lines

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · line 332

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
+	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	if (rc)
+		return rc;
+
+	if (!(mode & S_IRUSR)) {

Using mode_t for hardware access is odd. Perhaps just come up with some sort of READ/WRITE enum instead (if this sort of checking is even needed)?

Sure. Will address in the next clean up patch.

Quoted 4 lines

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_read_cmd(struct · line 334

Quoted 1 line
drivers/spmi/spmi-pmic-arb.c +1 -0
+		dev_err(&pmic_arb->spmic->dev,

The dev_err() just after uses ctrl->dev? Why not here?

Will address in the next clean up patch.

Quoted 19 lines
Quoted 19 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
+			"error: impermissible read from peripheral sid:%d addr:0x%x\n",
+			sid, addr);
+		return -EPERM;
+	}
+
 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
 		dev_err(&ctrl->dev,
drivers/spmi/spmi-pmic-arb.c +1 -0
 			"pmic-arb supports 1..%d bytes per trans, but:%zu requested",
@@ -364,11 +382,23 @@ static int pmic_arb_write_cmd(struct 
 spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 cmd;
 	int rc;
 	u32 offset;
+	mode_t mode;
 
 	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
 	if (rc)
 		return rc;
 
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · line 396

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
+	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	if (rc)
+		return rc;
+
+	if (!(mode & S_IWUSR)) {
+		dev_err(&pmic_arb->spmic->dev,

The dev_err() just after uses ctrl->dev? Why not here?

Will address in the next clean up patch.

Quoted 13 lines
Quoted 13 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
+			"error: impermissible write to peripheral sid:%d addr:0x%x\n",
+			sid, addr);
+		return -EPERM;
+	}
+
 	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
 		dev_err(&ctrl->dev,
drivers/spmi/spmi-pmic-arb.c +0 -0
 			"pmic-arb supports 1..%d bytes per trans, but:%zu requested",
@@ -727,6 +757,13 @@ static int qpnpint_irq_domain_map(struct 
 irq_domain *d,
 	return 0;
 }
 
Quoted 11 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 764

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
+static int
+pmic_arb_mode_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, 
 mode_t *mode)
+{
+	*mode = S_IRUSR | S_IWUSR;
+	return 0;

If mode was only positive then errors could be negative and no access could be 0. Then we could just return the mode from the function instead of passing a pointer around.

Will modify in the next clean up patch.

Quoted 14 lines
Quoted 14 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
+}
+
 /* v1 offset per ee */

static int
pmic_arb_offset_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr,
u32 *offset)

drivers/spmi/spmi-pmic-arb.c +2 -1
@@ -745,7 +782,11 @@ static u16 pmic_arb_find_chan(struct 
 spmi_pmic_arb_dev *pa, u16 ppid)
 	 * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.
 	 * ppid_to_chan is an in-memory invert of that table.
 	 */
-	for (chan = pa->last_channel; ; chan++) {
+	for (chan = pa->last_channel; chan < pa->max_periph; chan++) {
+		regval = readl_relaxed(pa->cnfg +
Quoted 9 lines
Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
+				      SPMI_OWNERSHIP_TABLE_REG(chan));
+		pa->chan_to_owner[chan] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+
 		offset = PMIC_ARB_REG_CHNL(chan);
 		if (offset >= pa->core_size)

break;

Seems like an unrelated change to the mapping logic?

Will address in the next clean up patch.

Quoted 11 lines

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_chan(struct · line 814

Quoted 8 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
@@ -767,6 +808,27 @@ static u16 pmic_arb_find_chan(struct 
 spmi_pmic_arb_dev *pa, u16 ppid)
 }
 
 
+static int
+pmic_arb_mode_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, 
 mode_t *mode)

Probably spmi_pmic_arb_dev should be const here.

Will address in the next clean up patch.

Quoted 26 lines
Quoted 26 lines
drivers/spmi/spmi-pmic-arb.c +19 -0
+{
+	u16 ppid = (sid << 8) | (addr >> 8);
+	u16 chan;
+	u8 owner;
+
+	chan = pa->ppid_to_chan[ppid];
+	if (!(chan & PMIC_ARB_CHAN_VALID))
+		return -ENODEV;
+
+	*mode = 0;
+	*mode |= S_IRUSR;
+
+	chan &= ~PMIC_ARB_CHAN_VALID;
+	owner = pa->chan_to_owner[chan];
+	if (owner == pa->ee)
+		*mode |= S_IWUSR;
+	return 0;
+}
+
 /* v2 offset per ppid (chan) and per ee */

static int
pmic_arb_offset_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr,
u32 *offset)

drivers/spmi/spmi-pmic-arb.c +0 -0
@@ -879,6 +943,12 @@ static int spmi_pmic_arb_probe(struct 
 platform_device *pdev)
 
Quoted 8 lines

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev)

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
 	pa->core_size = resource_size(res);
+	if (pa->core_size <= 0x800) {
+		dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing 
 Probe\n");

Not sure why probe is capitalized.

Will address in the next clean up patch.

Quoted 7 lines

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 951

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+		err = -EINVAL;
+		goto err_put_ctrl;
+	}
+

We don't need these sorts of DT validation checks. Please remove.

Will remove it in the next clean up patch.

Quoted 15 lines
Quoted 15 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 	core = devm_ioremap_resource(&ctrl->dev, res);
drivers/spmi/spmi-pmic-arb.c +3 -0
 	if (IS_ERR(core)) {
 		err = PTR_ERR(core);
@@ -899,6 +969,9 @@ static int spmi_pmic_arb_probe(struct 
 platform_device *pdev)
 		pa->core = core;
 		pa->ver_ops = &pmic_arb_v2;
 
+		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
+		pa->max_periph =  (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");

pa->rd_base = devm_ioremap_resource(&ctrl->dev, res);

Quoted 7 lines
Quoted 4 lines

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation --

P.S. Please put a newline in your signature so it doesn't exceed 80 columns.

Thanks for the suggestion.

#4 lore raw

Re: [PATCH V1 01/15] spmi: pmic_arb: block access of invalid read and writes

Quoted 15 lines · On 06/12, [email protected] wrote:
Quoted 10 lines · Stephen Boyd
Quoted 8 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The system crashes due to bad access when reading from an non configured
peripheral and when writing to peripheral which is not owned by current
ee. This patch verifies ownership to avoid crashing on write.

Quoted 4 lines

What systems? As far as I know we don't have any bad accesses happening right now. If they are happening, we should fix the code that's accessing hardware that isn't owned by them.

Quoted 8 lines

This change greatly improves the debugging effort for developers by printing
a very simple and clear error message when an invalid SPMI access occurs (due to bad DT configuration, bad bootloader SPMI permission configurations,
or other issues). Without this change, such accesses will cause XPU violations
that crash the system and require extensive effort to decode.

Right, but they're easily detectable because we would know almost immediately that something isn't working when we integrate a change. If you update the DT and it stops working, the DT is bad. If you update the bootloader and it stops working, the bootloader is bad, etc.

Quoted 17 lines
Quoted 9 lines
Quoted 8 lines

For reads, since the forward mapping table, data_channel->ppid, is towards the end of the block, we use the core size to figure the max number of ppids supported. The table starts at an offset of 0x800 within the block, so size - 0x800 will give us the area used by the table. Since each table is 4 bytes long (core_size - 0x800) / 4 will gives us the number of data_channel supported.
This new protection is functional on hw v2.

Quoted 8 lines

Which brings us to the next question which is why do we need this patch at all? We aren't probing hardware to see what we have access to and then populating device structures based on that. Instead, we're just populating DT nodes that we've hardcoded in the dts files, so I'm a little lost on why we would have a node in there that we couldn't access. Please add such details to the commit text.

Quoted 7 lines

invalid SPMI access occurs due to bad DT configuration, bad bootloader SPMI
permission configurations, or other issues. This change reduces the debugging
effort for developers by printing clear error message when an invalid SPMI
access occurs.

Well we also take an overhead on every read/write. Sure things are slow so the overhead is negligible, but the permissions are on a peripheral id basis, so really we should look into _not_ populating devices that aren't accessible in the first place. Then we move the checks out of the read/write path and to a more logical place whereby we prevent a driver from attempting to even attach to read or write a register that is protected.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#5 lore raw

Re: [PATCH V1 01/15] spmi: pmic_arb: block access of invalid read and writes

Quoted 25 lines · Stephen Boyd
Quoted 15 lines · On 06/12, [email protected] wrote:
Quoted 10 lines · Stephen Boyd
Quoted 8 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The system crashes due to bad access when reading from an non configured
peripheral and when writing to peripheral which is not owned by current
ee. This patch verifies ownership to avoid crashing on write.

Quoted 4 lines

What systems? As far as I know we don't have any bad accesses happening right now. If they are happening, we should fix the code that's accessing hardware that isn't owned by them.

Quoted 8 lines

This change greatly improves the debugging effort for developers by printing
a very simple and clear error message when an invalid SPMI access occurs (due to bad DT configuration, bad bootloader SPMI permission configurations,
or other issues). Without this change, such accesses will cause XPU violations
that crash the system and require extensive effort to decode.

Quoted 6 lines

Right, but they're easily detectable because we would know almost immediately that something isn't working when we integrate a change. If you update the DT and it stops working, the DT is bad. If you update the bootloader and it stops working, the bootloader is bad, etc.

Ok. Will send a patch to remove this code in the next series.

Quoted 25 lines
Quoted 17 lines
Quoted 9 lines
Quoted 8 lines

For reads, since the forward mapping table, data_channel->ppid, is towards the end of the block, we use the core size to figure the max number of ppids supported. The table starts at an offset of 0x800 within the block, so size - 0x800 will give us the area used by the table. Since each table is 4 bytes long (core_size - 0x800) / 4 will gives us the number of data_channel supported.
This new protection is functional on hw v2.

Quoted 8 lines

Which brings us to the next question which is why do we need this patch at all? We aren't probing hardware to see what we have access to and then populating device structures based on that. Instead, we're just populating DT nodes that we've hardcoded in the dts files, so I'm a little lost on why we would have a node in there that we couldn't access. Please add such details to the commit text.

Quoted 7 lines

invalid SPMI access occurs due to bad DT configuration, bad bootloader SPMI
permission configurations, or other issues. This change reduces the debugging
effort for developers by printing clear error message when an invalid SPMI
access occurs.

Quoted 7 lines

Well we also take an overhead on every read/write. Sure things are slow so the overhead is negligible, but the permissions are on a peripheral id basis, so really we should look into _not_ populating devices that aren't accessible in the first place. Then we move the checks out of the read/write path and to a more logical place whereby we prevent a driver from attempting to even attach to read or write a register that is protected.

Ok. Will remove this code in the next patch series and try to implement it as per your suggestion.

#6 lore raw

PATCH 2/15 spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

Usually *_dev best used for structures that embed a struct device in them. spmi_pmic_arb_dev doesn't embed one. It is simply a driver data structure. Use an appropriate name for it.

Also there are many places in the driver that left shift the bit to generate a bit mask. Replace it with the BIT() macro.

---
 drivers/spmi/spmi-pmic-arb.c | 164 +++++++++++++++++++++----------------------
 1 file changed, 82 insertions(+), 82 deletions(-)
drivers/spmi/spmi-pmic-arb.c +82 -82
index df463d4..7f918ea 100644
@@ -58,10 +58,10 @@
 
 /* Channel Status fields */
 enum pmic_arb_chnl_status {
-	PMIC_ARB_STATUS_DONE	= (1 << 0),
-	PMIC_ARB_STATUS_FAILURE	= (1 << 1),
-	PMIC_ARB_STATUS_DENIED	= (1 << 2),
-	PMIC_ARB_STATUS_DROPPED	= (1 << 3),
+	PMIC_ARB_STATUS_DONE	= BIT(0),
+	PMIC_ARB_STATUS_FAILURE	= BIT(1),
+	PMIC_ARB_STATUS_DENIED	= BIT(2),
+	PMIC_ARB_STATUS_DROPPED	= BIT(3),
 };
 
 /* Command register fields */
@@ -99,7 +99,7 @@ enum pmic_arb_cmd_op_code {
 struct pmic_arb_ver_ops;
 
 /**
- * spmi_pmic_arb_dev - SPMI PMIC Arbiter object
+ * spmi_pmic_arb - SPMI PMIC Arbiter object
  *
  * @rd_base:		on v1 "core", on v2 "observer" register base off DT.
  * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
@@ -120,7 +120,7 @@ enum pmic_arb_cmd_op_code {
  * @ppid_to_chan	in-memory copy of PPID -> channel (APID) mapping table.
  *			v2 only.
  */
-struct spmi_pmic_arb_dev {
+struct spmi_pmic_arb {
 	void __iomem		*rd_base;
 	void __iomem		*wr_base;
 	void __iomem		*intr;
@@ -164,10 +164,10 @@ struct spmi_pmic_arb_dev {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
-	int (*mode)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
-	int (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+	int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 		      u32 *offset);
 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
@@ -178,16 +178,16 @@ struct pmic_arb_ver_ops {
 	u32 (*irq_clear)(u8 n);
 };
 
-static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev,
+static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,
 				       u32 offset, u32 val)
 {
-	writel_relaxed(val, dev->wr_base + offset);
+	writel_relaxed(val, pa->wr_base + offset);
 }
 
-static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb_dev *dev,
+static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pa,
 				       u32 offset, u32 val)
 {
-	writel_relaxed(val, dev->rd_base + offset);
+	writel_relaxed(val, pa->rd_base + offset);
 }
 
 /**
@@ -196,9 +196,10 @@ static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb_dev *dev,
  * @reg:	register's address
  * @buf:	output parameter, length must be bc + 1
  */
-static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
+static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, u8 bc)
 {
-	u32 data = __raw_readl(dev->rd_base + reg);
+	u32 data = __raw_readl(pa->rd_base + reg);
+
 	memcpy(buf, &data, (bc & 3) + 1);
 }
 
@@ -209,23 +210,24 @@ static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
  * @buf:	buffer to write. length must be bc + 1.
  */
 static void
-pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
+pa_write_data(struct spmi_pmic_arb *pa, const u8 *buf, u32 reg, u8 bc)
 {
 	u32 data = 0;
+
 	memcpy(&data, buf, (bc & 3) + 1);
-	__raw_writel(data, dev->wr_base + reg);
+	pmic_arb_base_write(pa, reg, data);
 }
 
 static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 				  void __iomem *base, u8 sid, u16 addr)
 {
-	struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	u32 status = 0;
 	u32 timeout = PMIC_ARB_TIMEOUT_US;
 	u32 offset;
 	int rc;
 
-	rc = dev->ver_ops->offset(dev, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
 	if (rc)
 		return rc;
 
@@ -270,22 +272,22 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 static int
 pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	unsigned long flags;
 	u32 cmd;
 	int rc;
 	u32 offset;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, &offset);
+	rc = pa->ver_ops->offset(pa, sid, 0, &offset);
 	if (rc)
 		return rc;
 
 	cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
 
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0);
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, 0);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
 	return rc;
 }
@@ -299,7 +301,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 /* Non-data command */
 static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 
 	dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid);
 
@@ -307,13 +309,13 @@ static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
 		return -EINVAL;
 
-	return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid);
+	return pa->ver_ops->non_data_cmd(ctrl, opc, sid);
 }
 
 static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 			     u16 addr, u8 *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	unsigned long flags;
 	u8 bc = len - 1;
 	u32 cmd;
@@ -321,16 +323,16 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
 	if (rc)
 		return rc;
 
-	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	rc = pa->ver_ops->mode(pa, sid, addr, &mode);
 	if (rc)
 		return rc;
 
 	if (!(mode & S_IRUSR)) {
-		dev_err(&pmic_arb->spmic->dev,
+		dev_err(&pa->spmic->dev,
 			"error: impermissible read from peripheral sid:%d addr:0x%x\n",
 			sid, addr);
 		return -EPERM;
@@ -353,30 +355,29 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
+	cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc);
 
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pmic_arb_set_rd_cmd(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->rd_base, sid, addr);
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pmic_arb_set_rd_cmd(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->rd_base, sid, addr);
 	if (rc)
 		goto done;
 
-	pa_read_data(pmic_arb, buf, offset + PMIC_ARB_RDATA0,
+	pa_read_data(pa, buf, offset + PMIC_ARB_RDATA0,
 		     min_t(u8, bc, 3));
 
 	if (bc > 3)
-		pa_read_data(pmic_arb, buf + 4,
-				offset + PMIC_ARB_RDATA1, bc - 4);
+		pa_read_data(pa, buf + 4, offset + PMIC_ARB_RDATA1, bc - 4);
 
 done:
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 	return rc;
 }
 
 static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 			      u16 addr, const u8 *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	unsigned long flags;
 	u8 bc = len - 1;
 	u32 cmd;
@@ -384,16 +385,16 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
 	if (rc)
 		return rc;
 
-	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	rc = pa->ver_ops->mode(pa, sid, addr, &mode);
 	if (rc)
 		return rc;
 
 	if (!(mode & S_IWUSR)) {
-		dev_err(&pmic_arb->spmic->dev,
+		dev_err(&pa->spmic->dev,
 			"error: impermissible write to peripheral sid:%d addr:0x%x\n",
 			sid, addr);
 		return -EPERM;
@@ -418,20 +419,18 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
+	cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc);
 
 	/* Write data to FIFOs */
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pa_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0,
-		      min_t(u8, bc, 3));
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pa_write_data(pa, buf, offset + PMIC_ARB_WDATA0, min_t(u8, bc, 3));
 	if (bc > 3)
-		pa_write_data(pmic_arb, buf + 4,
-				offset + PMIC_ARB_WDATA1, bc - 4);
+		pa_write_data(pa, buf + 4, offset + PMIC_ARB_WDATA1, bc - 4);
 
 	/* Start the transaction */
-	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr);
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, addr);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
 	return rc;
 }
@@ -457,7 +456,7 @@ struct spmi_pmic_arb_qpnpint_type {
 static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
 			       size_t len)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 sid = d->hwirq >> 24;
 	u8 per = d->hwirq >> 16;
 
@@ -470,7 +469,7 @@ static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
 
 static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 sid = d->hwirq >> 24;
 	u8 per = d->hwirq >> 16;
 
@@ -481,7 +480,7 @@ static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 				    d->irq);
 }
 
-static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
+static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
 {
 	unsigned int irq;
 	u32 status;
@@ -490,7 +489,7 @@ static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
 	status = readl_relaxed(pa->intr + pa->ver_ops->irq_status(apid));
 	while (status) {
 		id = ffs(status) - 1;
-		status &= ~(1 << id);
+		status &= ~BIT(id);
 		irq = irq_find_mapping(pa->domain,
 				       pa->apid_to_ppid[apid] << 16
 				     | id << 8
@@ -501,7 +500,7 @@ static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
 
 static void pmic_arb_chained_irq(struct irq_desc *desc)
 {
-	struct spmi_pmic_arb_dev *pa = irq_desc_get_handler_data(desc);
+	struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
@@ -516,7 +515,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 				      pa->ver_ops->owner_acc_status(pa->ee, i));
 		while (status) {
 			id = ffs(status) - 1;
-			status &= ~(1 << id);
+			status &= ~BIT(id);
 			periph_interrupt(pa, id + i * 32);
 		}
 	}
@@ -526,23 +525,23 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 
 static void qpnpint_irq_ack(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
 	u8 data;
 
 	raw_spin_lock_irqsave(&pa->lock, flags);
-	writel_relaxed(1 << irq, pa->intr + pa->ver_ops->irq_clear(apid));
+	writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid));
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
 }
 
 static void qpnpint_irq_mask(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
@@ -558,13 +557,13 @@ static void qpnpint_irq_mask(struct irq_data *d)
 	}
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
 static void qpnpint_irq_unmask(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
@@ -579,7 +578,7 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 	}
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
 }
 
@@ -590,7 +589,7 @@ static void qpnpint_irq_enable(struct irq_data *d)
 
 	qpnpint_irq_unmask(d);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
 }
 
@@ -598,25 +597,26 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
 	struct spmi_pmic_arb_qpnpint_type type;
 	u8 irq = d->hwirq >> 8;
+	u8 bit_mask_irq = BIT(irq);
 
 	qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
 
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-		type.type |= 1 << irq;
+		type.type |= bit_mask_irq;
 		if (flow_type & IRQF_TRIGGER_RISING)
-			type.polarity_high |= 1 << irq;
+			type.polarity_high |= bit_mask_irq;
 		if (flow_type & IRQF_TRIGGER_FALLING)
-			type.polarity_low  |= 1 << irq;
+			type.polarity_low  |= bit_mask_irq;
 	} else {
 		if ((flow_type & (IRQF_TRIGGER_HIGH)) &&
 		    (flow_type & (IRQF_TRIGGER_LOW)))
 			return -EINVAL;
 
-		type.type &= ~(1 << irq); /* level trig */
+		type.type &= ~bit_mask_irq; /* level trig */
 		if (flow_type & IRQF_TRIGGER_HIGH)
-			type.polarity_high |= 1 << irq;
+			type.polarity_high |= bit_mask_irq;
 		else
-			type.polarity_low  |= 1 << irq;
+			type.polarity_low  |= bit_mask_irq;
 	}
 
 	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
@@ -657,7 +657,7 @@ struct spmi_pmic_arb_irq_spec {
 	unsigned irq:3;
 };
 
-static int search_mapping_table(struct spmi_pmic_arb_dev *pa,
+static int search_mapping_table(struct spmi_pmic_arb *pa,
 				struct spmi_pmic_arb_irq_spec *spec,
 				u8 *apid)
 {
@@ -673,7 +673,7 @@ static int search_mapping_table(struct spmi_pmic_arb_dev *pa,
 
 		data = mapping_table[index];
 
-		if (ppid & (1 << SPMI_MAPPING_BIT_INDEX(data))) {
+		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
 			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
 				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
 			} else {
@@ -700,7 +700,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   unsigned long *out_hwirq,
 					   unsigned int *out_type)
 {
-	struct spmi_pmic_arb_dev *pa = d->host_data;
+	struct spmi_pmic_arb *pa = d->host_data;
 	struct spmi_pmic_arb_irq_spec spec;
 	int err;
 	u8 apid;
@@ -747,7 +747,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 				  unsigned int virq,
 				  irq_hw_number_t hwirq)
 {
-	struct spmi_pmic_arb_dev *pa = d->host_data;
+	struct spmi_pmic_arb *pa = d->host_data;
 
 	dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq);
 
@@ -758,7 +758,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 }
 
 static int
-pmic_arb_mode_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, mode_t *mode)
+pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	*mode = S_IRUSR | S_IWUSR;
 	return 0;
@@ -766,13 +766,13 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 
 /* v1 offset per ee */
 static int
-pmic_arb_offset_v1(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)
+pmic_arb_offset_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
 {
 	*offset = 0x800 + 0x80 * pa->channel;
 	return 0;
 }
 
-static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
+static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid)
 {
 	u32 regval, offset;
 	u16 chan;
@@ -809,7 +809,7 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
 
 
 static int
-pmic_arb_mode_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, mode_t *mode)
+pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
 	u16 chan;
@@ -831,7 +831,7 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb_dev *pa, u16 ppid)
 
 /* v2 offset per ppid (chan) and per ee */
 static int
-pmic_arb_offset_v2(struct spmi_pmic_arb_dev *pa, u8 sid, u16 addr, u32 *offset)
+pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
 	u16 chan;
@@ -926,7 +926,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
 
 static int spmi_pmic_arb_probe(struct platform_device *pdev)
 {
-	struct spmi_pmic_arb_dev *pa;
+	struct spmi_pmic_arb *pa;
 	struct spmi_controller *ctrl;
 	struct resource *res;
 	void __iomem *core;
@@ -1111,7 +1111,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 static int spmi_pmic_arb_remove(struct platform_device *pdev)
 {
 	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
-	struct spmi_pmic_arb_dev *pa = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	spmi_controller_remove(ctrl);
 	irq_set_chained_handler_and_data(pa->irq, NULL, NULL);
 	irq_domain_remove(pa->domain);
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#7 lore raw

Re: [PATCH V1 02/15] spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb

Quoted 8 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

Usually *_dev best used for structures that embed a struct device in them. spmi_pmic_arb_dev doesn't embed one. It is simply a driver data structure. Use an appropriate name for it.

Also there are many places in the driver that left shift the bit to generate a bit mask. Replace it with the BIT() macro.

That would be a different patch because the subject doesn't even mention this.

Quoted 5 lines
---
 drivers/spmi/spmi-pmic-arb.c | 164 +++++++++++++++++++++----------------------

Would also be nice if you ran scripts/objdiff on this so we can be confident the code didn't change.

Quoted 40 lines
 1 file changed, 82 insertions(+), 82 deletions(-)
drivers/spmi/spmi-pmic-arb.c +6 -6
index df463d4..7f918ea 100644
@@ -58,10 +58,10 @@
 
 /* Channel Status fields */
 enum pmic_arb_chnl_status {
-	PMIC_ARB_STATUS_DONE	= (1 << 0),
-	PMIC_ARB_STATUS_FAILURE	= (1 << 1),
-	PMIC_ARB_STATUS_DENIED	= (1 << 2),
-	PMIC_ARB_STATUS_DROPPED	= (1 << 3),
+	PMIC_ARB_STATUS_DONE	= BIT(0),
+	PMIC_ARB_STATUS_FAILURE	= BIT(1),
+	PMIC_ARB_STATUS_DENIED	= BIT(2),
+	PMIC_ARB_STATUS_DROPPED	= BIT(3),
 };
 
 /* Command register fields */
@@ -99,7 +99,7 @@ enum pmic_arb_cmd_op_code {
 struct pmic_arb_ver_ops;
 
 /**
- * spmi_pmic_arb_dev - SPMI PMIC Arbiter object
+ * spmi_pmic_arb - SPMI PMIC Arbiter object
  *
  * @rd_base:		on v1 "core", on v2 "observer" register base off DT.
  * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
@@ -120,7 +120,7 @@ enum pmic_arb_cmd_op_code {
  * @ppid_to_chan	in-memory copy of PPID -> channel (APID) mapping table.
  *			v2 only.
  */
-struct spmi_pmic_arb_dev {
+struct spmi_pmic_arb {
 	void __iomem		*rd_base;
 	void __iomem		*wr_base;
 	void __iomem		*intr;

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_dev { · line 167

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -164,10 +164,10 @@ struct spmi_pmic_arb_dev {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
-	int (*mode)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,

But we leave dev here? I'm losing faith that this patch is worthwhile.

Quoted 8 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
-	int (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+	int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 		      u32 *offset);
 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);

drivers/spmi/spmi-pmic-arb.c struct pmic_arb_ver_ops { · line 184

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +2 -2
@@ -178,16 +178,16 @@ struct pmic_arb_ver_ops {
 	u32 (*irq_clear)(u8 n);
 };
 
-static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev,
+static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,
 				       u32 offset, u32 val)
 {
-	writel_relaxed(val, dev->wr_base + offset);
+	writel_relaxed(val, pa->wr_base + offset);

"pa" is a little confusing with things like physical address and such. I would have gone for "arb", but the code is written already, so why change it now?

Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +2 -2
 }
 
-static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb_dev *dev,
+static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pa,
 				       u32 offset, u32 val)
 {
-	writel_relaxed(val, dev->rd_base + offset);
+	writel_relaxed(val, pa->rd_base + offset);
 }
 
 /**

drivers/spmi/spmi-pmic-arb.c static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb_dev *dev, · line 199

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -196,9 +196,10 @@ static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb_dev *dev,
  * @reg:	register's address
  * @buf:	output parameter, length must be bc + 1
  */
-static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
+static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, u8 bc)

In fact, I would rename these pa_{read,write}_data() functions as pmic_arb_{read,write}_data() to be consistent. These are the only places "pa_" is used right now.

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +2 -1
 {
-	u32 data = __raw_readl(dev->rd_base + reg);
+	u32 data = __raw_readl(pa->rd_base + reg);
+
 	memcpy(buf, &data, (bc & 3) + 1);
 }
 
@@ -209,23 +210,24 @@ static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
  * @buf:	buffer to write. length must be bc + 1.

drivers/spmi/spmi-pmic-arb.c static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc) · line 218

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +3 -2
  */
 static void
-pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
+pa_write_data(struct spmi_pmic_arb *pa, const u8 *buf, u32 reg, u8 bc)
 {
 	u32 data = 0;
+
 	memcpy(&data, buf, (bc & 3) + 1);
-	__raw_writel(data, dev->wr_base + reg);
+	pmic_arb_base_write(pa, reg, data);

This is an unrelated change. Not sure what's going on with this diff but we most likely want to keep the __raw_writel() here. See how renames introduce bugs and why we don't value them?

Quoted 20 lines
drivers/spmi/spmi-pmic-arb.c +2 -2
 }
 
@@ -270,22 +272,22 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 static int
 pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	unsigned long flags;
 	u32 cmd;
 	int rc;
 	u32 offset;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, &offset);
+	rc = pa->ver_ops->offset(pa, sid, 0, &offset);
 	if (rc)
 		return rc;
 
 	cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
 

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, · line 292

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +4 -4
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0);
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, 0);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
 	return rc;

Yeah pmic_arb sounds fine too. Not sure why we changed anything in this function.

Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 }
@@ -299,7 +301,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 /* Non-data command */
 static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 
 	dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid);
 

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) · line 312

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -307,13 +309,13 @@ static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
 		return -EINVAL;
 
-	return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid);
+	return pa->ver_ops->non_data_cmd(ctrl, opc, sid);

Same story...

Quoted 107 lines
drivers/spmi/spmi-pmic-arb.c +19 -22
 }
 
 static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 			     u16 addr, u8 *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	unsigned long flags;
 	u8 bc = len - 1;
 	u32 cmd;
@@ -321,16 +323,16 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
 	if (rc)
 		return rc;
 
-	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	rc = pa->ver_ops->mode(pa, sid, addr, &mode);
 	if (rc)
 		return rc;
 
 	if (!(mode & S_IRUSR)) {
-		dev_err(&pmic_arb->spmic->dev,
+		dev_err(&pa->spmic->dev,
 			"error: impermissible read from peripheral sid:%d addr:0x%x\n",
 			sid, addr);
 		return -EPERM;
@@ -353,30 +355,29 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
+	cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc);
 
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pmic_arb_set_rd_cmd(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->rd_base, sid, addr);
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pmic_arb_set_rd_cmd(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->rd_base, sid, addr);
 	if (rc)
 		goto done;
 
-	pa_read_data(pmic_arb, buf, offset + PMIC_ARB_RDATA0,
+	pa_read_data(pa, buf, offset + PMIC_ARB_RDATA0,
 		     min_t(u8, bc, 3));
 
 	if (bc > 3)
-		pa_read_data(pmic_arb, buf + 4,
-				offset + PMIC_ARB_RDATA1, bc - 4);
+		pa_read_data(pa, buf + 4, offset + PMIC_ARB_RDATA1, bc - 4);
 
 done:
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 	return rc;
 }
 
 static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 			      u16 addr, const u8 *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	unsigned long flags;
 	u8 bc = len - 1;
 	u32 cmd;
@@ -384,16 +385,16 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
 	if (rc)
 		return rc;
 
-	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	rc = pa->ver_ops->mode(pa, sid, addr, &mode);
 	if (rc)
 		return rc;
 
 	if (!(mode & S_IWUSR)) {
-		dev_err(&pmic_arb->spmic->dev,
+		dev_err(&pa->spmic->dev,
 			"error: impermissible write to peripheral sid:%d addr:0x%x\n",
 			sid, addr);
 		return -EPERM;
@@ -418,20 +419,18 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
+	cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc);
 
 	/* Write data to FIFOs */
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pa_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0,
-		      min_t(u8, bc, 3));
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pa_write_data(pa, buf, offset + PMIC_ARB_WDATA0, min_t(u8, bc, 3));
 	if (bc > 3)
-		pa_write_data(pmic_arb, buf + 4,
-				offset + PMIC_ARB_WDATA1, bc - 4);
+		pa_write_data(pa, buf + 4, offset + PMIC_ARB_WDATA1, bc - 4);
 

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · line 436

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +3 -3
 	/* Start the transaction */
-	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr);
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, addr);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
 	return rc;
 }

Same story for all this diff.

Quoted 117 lines
drivers/spmi/spmi-pmic-arb.c +14 -14
@@ -457,7 +456,7 @@ struct spmi_pmic_arb_qpnpint_type {
 static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
 			       size_t len)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 sid = d->hwirq >> 24;
 	u8 per = d->hwirq >> 16;
 
@@ -470,7 +469,7 @@ static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
 
 static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 sid = d->hwirq >> 24;
 	u8 per = d->hwirq >> 16;
 
@@ -481,7 +480,7 @@ static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 				    d->irq);
 }
 
-static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
+static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
 {
 	unsigned int irq;
 	u32 status;
@@ -490,7 +489,7 @@ static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
 	status = readl_relaxed(pa->intr + pa->ver_ops->irq_status(apid));
 	while (status) {
 		id = ffs(status) - 1;
-		status &= ~(1 << id);
+		status &= ~BIT(id);
 		irq = irq_find_mapping(pa->domain,
 				       pa->apid_to_ppid[apid] << 16
 				     | id << 8
@@ -501,7 +500,7 @@ static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
 
 static void pmic_arb_chained_irq(struct irq_desc *desc)
 {
-	struct spmi_pmic_arb_dev *pa = irq_desc_get_handler_data(desc);
+	struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
@@ -516,7 +515,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 				      pa->ver_ops->owner_acc_status(pa->ee, i));
 		while (status) {
 			id = ffs(status) - 1;
-			status &= ~(1 << id);
+			status &= ~BIT(id);
 			periph_interrupt(pa, id + i * 32);
 		}
 	}
@@ -526,23 +525,23 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 
 static void qpnpint_irq_ack(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
 	u8 data;
 
 	raw_spin_lock_irqsave(&pa->lock, flags);
-	writel_relaxed(1 << irq, pa->intr + pa->ver_ops->irq_clear(apid));
+	writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid));
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
 }
 
 static void qpnpint_irq_mask(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
@@ -558,13 +557,13 @@ static void qpnpint_irq_mask(struct irq_data *d)
 	}
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
 static void qpnpint_irq_unmask(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
@@ -579,7 +578,7 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 	}
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
 }
 
@@ -590,7 +589,7 @@ static void qpnpint_irq_enable(struct irq_data *d)
 
 	qpnpint_irq_unmask(d);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
 }
 

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) · line 600

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
@@ -598,25 +597,26 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
 	struct spmi_pmic_arb_qpnpint_type type;
 	u8 irq = d->hwirq >> 8;
+	u8 bit_mask_irq = BIT(irq);

Why the local variable? Just do the ~BIT(irq) thing in place and let the compiler take care of the hoist?

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec {

Quoted 29 lines
drivers/spmi/spmi-pmic-arb.c +6 -6
 	qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
 
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-		type.type |= 1 << irq;
+		type.type |= bit_mask_irq;
 		if (flow_type & IRQF_TRIGGER_RISING)
-			type.polarity_high |= 1 << irq;
+			type.polarity_high |= bit_mask_irq;
 		if (flow_type & IRQF_TRIGGER_FALLING)
-			type.polarity_low  |= 1 << irq;
+			type.polarity_low  |= bit_mask_irq;
 	} else {
 		if ((flow_type & (IRQF_TRIGGER_HIGH)) &&
 		    (flow_type & (IRQF_TRIGGER_LOW)))
 			return -EINVAL;
 
-		type.type &= ~(1 << irq); /* level trig */
+		type.type &= ~bit_mask_irq; /* level trig */
 		if (flow_type & IRQF_TRIGGER_HIGH)
-			type.polarity_high |= 1 << irq;
+			type.polarity_high |= bit_mask_irq;
 		else
-			type.polarity_low  |= 1 << irq;
+			type.polarity_low  |= bit_mask_irq;
 	}
 
 	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
@@ -657,7 +657,7 @@ struct spmi_pmic_arb_irq_spec {

Overall I see little to no value with this patch. I suggest you drop the rename. The BIT() thing may be ok, but again, not sure there's any benefit.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#8 lore raw

Re: [PATCH V1 02/15] spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb

Thanks Stephen for reviewing the patches. Responses inline.

Thanks,
Kiran

Quoted 7 lines · Stephen Boyd
Quoted 6 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

Usually *_dev best used for structures that embed a struct device in them. spmi_pmic_arb_dev doesn't embed one. It is simply a driver data structure. Use an appropriate name for it.

Quoted 6 lines
Quoted 2 lines

Also there are many places in the driver that left shift the bit to generate a bit mask. Replace it with the BIT() macro.

That would be a different patch because the subject doesn't even mention this.

Sure. Agree. Will split this in to different patch.

Quoted 10 lines
Quoted 6 lines
---
 drivers/spmi/spmi-pmic-arb.c | 164 

+++++++++++++++++++++----------------------

Would also be nice if you ran scripts/objdiff on this so we can be confident the code didn't change.

Sure. Will do that in the next patch.

Quoted 41 lines
Quoted 41 lines
 1 file changed, 82 insertions(+), 82 deletions(-)
drivers/spmi/spmi-pmic-arb.c +5 -5
index df463d4..7f918ea 100644
@@ -58,10 +58,10 @@
 
 /* Channel Status fields */
 enum pmic_arb_chnl_status {
-	PMIC_ARB_STATUS_DONE	= (1 << 0),
-	PMIC_ARB_STATUS_FAILURE	= (1 << 1),
-	PMIC_ARB_STATUS_DENIED	= (1 << 2),
-	PMIC_ARB_STATUS_DROPPED	= (1 << 3),
+	PMIC_ARB_STATUS_DONE	= BIT(0),
+	PMIC_ARB_STATUS_FAILURE	= BIT(1),
+	PMIC_ARB_STATUS_DENIED	= BIT(2),
+	PMIC_ARB_STATUS_DROPPED	= BIT(3),
 };
 
 /* Command register fields */
@@ -99,7 +99,7 @@ enum pmic_arb_cmd_op_code {
 struct pmic_arb_ver_ops;
 
 /**
- * spmi_pmic_arb_dev - SPMI PMIC Arbiter object
+ * spmi_pmic_arb - SPMI PMIC Arbiter object
  *
  * @rd_base:		on v1 "core", on v2 "observer" register base off DT.
  * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
@@ -120,7 +120,7 @@ enum pmic_arb_cmd_op_code {
  * @ppid_to_chan	in-memory copy of PPID -> channel (APID) mapping 

table.
* v2 only.
*/

drivers/spmi/spmi-pmic-arb.c +1 -1
-struct spmi_pmic_arb_dev {
+struct spmi_pmic_arb {
 	void __iomem		*rd_base;
 	void __iomem		*wr_base;
 	void __iomem		*intr;
@@ -164,10 +164,10 @@ struct spmi_pmic_arb_dev {
Quoted 8 lines

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_dev { · line 167

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
-	int (*mode)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,

But we leave dev here? I'm losing faith that this patch is worthwhile.

Ok. As per your suggestion we will drop this renaming patch.

Quoted 12 lines
Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
-	int (*offset)(struct spmi_pmic_arb_dev *dev, u8 sid, u16 addr,
+	int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 		      u32 *offset);
 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
@@ -178,16 +178,16 @@ struct pmic_arb_ver_ops {
 	u32 (*irq_clear)(u8 n);
 };
 
Quoted 11 lines

drivers/spmi/spmi-pmic-arb.c struct pmic_arb_ver_ops { · line 184

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +2 -2
-static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev,
+static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,
 				       u32 offset, u32 val)
 {
-	writel_relaxed(val, dev->wr_base + offset);
+	writel_relaxed(val, pa->wr_base + offset);

"pa" is a little confusing with things like physical address and such. I would have gone for "arb", but the code is written already, so why change it now?

Ok. As per your suggestion we will drop this renaming patch.

Quoted 10 lines
Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +2 -2
 }
 
-static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb_dev *dev,
+static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pa,
 				       u32 offset, u32 val)
 {
-	writel_relaxed(val, dev->rd_base + offset);
+	writel_relaxed(val, pa->rd_base + offset);
 }
 
Quoted 15 lines

drivers/spmi/spmi-pmic-arb.c static inline void pmic_arb_set_rd_cmd(struct · line 202

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 /**
@@ -196,9 +196,10 @@ static inline void pmic_arb_set_rd_cmd(struct 
 spmi_pmic_arb_dev *dev,
  * @reg:	register's address
  * @buf:	output parameter, length must be bc + 1
  */
-static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 
 reg, u8 bc)
+static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, 
 u8 bc)

In fact, I would rename these pa_{read,write}_data() functions as pmic_arb_{read,write}_data() to be consistent. These are the only places "pa_" is used right now.

Sure. Agree. Will rename this to pmic_arb_{read,write}_data in the next patch.

Quoted 18 lines
Quoted 18 lines
drivers/spmi/spmi-pmic-arb.c +2 -1
 {
-	u32 data = __raw_readl(dev->rd_base + reg);
+	u32 data = __raw_readl(pa->rd_base + reg);
+
drivers/spmi/spmi-pmic-arb.c +1 -1
 	memcpy(buf, &data, (bc & 3) + 1);
 }
@@ -209,23 +210,24 @@ static void pa_read_data(struct 
 spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
  * @buf:	buffer to write. length must be bc + 1.
  */
 static void
-pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, 
 u8 bc)
+pa_write_data(struct spmi_pmic_arb *pa, const u8 *buf, u32 reg, u8 
 bc)
 {
 	u32 data = 0;
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc) · line 218

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +2 -1
+
 	memcpy(&data, buf, (bc & 3) + 1);
-	__raw_writel(data, dev->wr_base + reg);
+	pmic_arb_base_write(pa, reg, data);

This is an unrelated change. Not sure what's going on with this diff but we most likely want to keep the __raw_writel() here. See how renames introduce bugs and why we don't value them?

Actually pmic_arb_base_write has the writel_relaxed inside it. that's why we removed the __raw_writel to use the common function. Anyways, we drop the renaming patch from this patch series.

Quoted 32 lines
Quoted 32 lines
drivers/spmi/spmi-pmic-arb.c +6 -6
 }
 
@@ -270,22 +272,22 @@ static int pmic_arb_wait_for_done(struct 
 spmi_controller *ctrl,
 static int
 pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 
 sid)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = 
 spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	unsigned long flags;
 	u32 cmd;
 	int rc;
 	u32 offset;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, &offset);
+	rc = pa->ver_ops->offset(pa, sid, 0, &offset);
 	if (rc)
 		return rc;
 
 	cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
 
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0);
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, 0);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
Quoted 5 lines
Quoted 1 line

return rc;

Yeah pmic_arb sounds fine too. Not sure why we changed anything in this function.

Ok. We will drop this renaming patch.

Quoted 17 lines
Quoted 17 lines

}

drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -299,7 +301,7 @@ static int pmic_arb_wait_for_done(struct 
 spmi_controller *ctrl,
 /* Non-data command */
 static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = 
 spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 
drivers/spmi/spmi-pmic-arb.c +0 -0
 	dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid);
@@ -307,13 +309,13 @@ static int pmic_arb_cmd(struct spmi_controller 
 *ctrl, u8 opc, u8 sid)
 	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
 		return -EINVAL;
 
Quoted 5 lines

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) · line 312

Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
-	return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid);
+	return pa->ver_ops->non_data_cmd(ctrl, opc, sid);

Same story...

Ok. We will drop this renaming patch.

Quoted 123 lines
Quoted 123 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 }
 
 static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 
 sid,
 			     u16 addr, u8 *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = 
 spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
drivers/spmi/spmi-pmic-arb.c +3 -3
 	unsigned long flags;
 	u8 bc = len - 1;
 	u32 cmd;
@@ -321,16 +323,16 @@ static int pmic_arb_read_cmd(struct 
 spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
 	if (rc)
 		return rc;
 
-	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	rc = pa->ver_ops->mode(pa, sid, addr, &mode);
 	if (rc)
 		return rc;
 
 	if (!(mode & S_IRUSR)) {
-		dev_err(&pmic_arb->spmic->dev,
+		dev_err(&pa->spmic->dev,
 			"error: impermissible read from peripheral sid:%d addr:0x%x\n",
 			sid, addr);
drivers/spmi/spmi-pmic-arb.c +8 -9
 		return -EPERM;
@@ -353,30 +355,29 @@ static int pmic_arb_read_cmd(struct 
 spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
+	cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc);
 
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pmic_arb_set_rd_cmd(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->rd_base, sid, addr);
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pmic_arb_set_rd_cmd(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->rd_base, sid, addr);
 	if (rc)
 		goto done;
 
-	pa_read_data(pmic_arb, buf, offset + PMIC_ARB_RDATA0,
+	pa_read_data(pa, buf, offset + PMIC_ARB_RDATA0,
 		     min_t(u8, bc, 3));
 
 	if (bc > 3)
-		pa_read_data(pmic_arb, buf + 4,
-				offset + PMIC_ARB_RDATA1, bc - 4);
+		pa_read_data(pa, buf + 4, offset + PMIC_ARB_RDATA1, bc - 4);
 
 done:
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 	return rc;
 }
 
 static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, 
 u8 sid,
 			      u16 addr, const u8 *buf, size_t len)
 {
-	struct spmi_pmic_arb_dev *pmic_arb = 
 spmi_controller_get_drvdata(ctrl);
+	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
drivers/spmi/spmi-pmic-arb.c +3 -3
 	unsigned long flags;
 	u8 bc = len - 1;
 	u32 cmd;
@@ -384,16 +385,16 @@ static int pmic_arb_write_cmd(struct 
 spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
 	if (rc)
 		return rc;
 
-	rc = pmic_arb->ver_ops->mode(pmic_arb, sid, addr, &mode);
+	rc = pa->ver_ops->mode(pa, sid, addr, &mode);
 	if (rc)
 		return rc;
 
 	if (!(mode & S_IWUSR)) {
-		dev_err(&pmic_arb->spmic->dev,
+		dev_err(&pa->spmic->dev,
 			"error: impermissible write to peripheral sid:%d addr:0x%x\n",
 			sid, addr);
drivers/spmi/spmi-pmic-arb.c +7 -9
 		return -EPERM;
@@ -418,20 +419,18 @@ static int pmic_arb_write_cmd(struct 
 spmi_controller *ctrl, u8 opc, u8 sid,
 	else
 		return -EINVAL;
 
-	cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc);
+	cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc);
 
 	/* Write data to FIFOs */
-	raw_spin_lock_irqsave(&pmic_arb->lock, flags);
-	pa_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0,
-		      min_t(u8, bc, 3));
+	raw_spin_lock_irqsave(&pa->lock, flags);
+	pa_write_data(pa, buf, offset + PMIC_ARB_WDATA0, min_t(u8, bc, 3));
 	if (bc > 3)
-		pa_write_data(pmic_arb, buf + 4,
-				offset + PMIC_ARB_WDATA1, bc - 4);
+		pa_write_data(pa, buf + 4, offset + PMIC_ARB_WDATA1, bc - 4);
 
 	/* Start the transaction */
-	pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr);
-	raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, addr);
+	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
Quoted 4 lines
Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 	return rc;

}

Same story for all this diff.

Ok. We will drop this renaming patch.

Quoted 124 lines
Quoted 124 lines
drivers/spmi/spmi-pmic-arb.c +2 -2
@@ -457,7 +456,7 @@ struct spmi_pmic_arb_qpnpint_type {
 static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
 			       size_t len)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 sid = d->hwirq >> 24;
 	u8 per = d->hwirq >> 16;
 
@@ -470,7 +469,7 @@ static void qpnpint_spmi_write(struct irq_data *d, 
 u8 reg, void *buf,
 
 static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, 
 size_t len)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 sid = d->hwirq >> 24;
drivers/spmi/spmi-pmic-arb.c +1 -1
 	u8 per = d->hwirq >> 16;
@@ -481,7 +480,7 @@ static void qpnpint_spmi_read(struct irq_data *d, 
 u8 reg, void *buf, size_t len)
 				    d->irq);
 }
 
-static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
+static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
 {
 	unsigned int irq;
drivers/spmi/spmi-pmic-arb.c +1 -1
 	u32 status;
@@ -490,7 +489,7 @@ static void periph_interrupt(struct 
 spmi_pmic_arb_dev *pa, u8 apid)
 	status = readl_relaxed(pa->intr + pa->ver_ops->irq_status(apid));
 	while (status) {
 		id = ffs(status) - 1;
-		status &= ~(1 << id);
+		status &= ~BIT(id);
 		irq = irq_find_mapping(pa->domain,
 				       pa->apid_to_ppid[apid] << 16
drivers/spmi/spmi-pmic-arb.c +1 -1
 				     | id << 8
@@ -501,7 +500,7 @@ static void periph_interrupt(struct 
 spmi_pmic_arb_dev *pa, u8 apid)
 
 static void pmic_arb_chained_irq(struct irq_desc *desc)
 {
-	struct spmi_pmic_arb_dev *pa = irq_desc_get_handler_data(desc);
+	struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	void __iomem *intr = pa->intr;
drivers/spmi/spmi-pmic-arb.c +1 -1
 	int first = pa->min_apid >> 5;
@@ -516,7 +515,7 @@ static void pmic_arb_chained_irq(struct irq_desc 
 *desc)
 				      pa->ver_ops->owner_acc_status(pa->ee, i));
 		while (status) {
 			id = ffs(status) - 1;
-			status &= ~(1 << id);
+			status &= ~BIT(id);
 			periph_interrupt(pa, id + i * 32);
 		}
drivers/spmi/spmi-pmic-arb.c +4 -4
 	}
@@ -526,23 +525,23 @@ static void pmic_arb_chained_irq(struct irq_desc 
 *desc)
 
 static void qpnpint_irq_ack(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
 	u8 data;
 
 	raw_spin_lock_irqsave(&pa->lock, flags);
-	writel_relaxed(1 << irq, pa->intr + pa->ver_ops->irq_clear(apid));
+	writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid));
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
 }
 
 static void qpnpint_irq_mask(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
drivers/spmi/spmi-pmic-arb.c +4 -4
 	unsigned long flags;
@@ -558,13 +557,13 @@ static void qpnpint_irq_mask(struct irq_data *d)
 	}
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
 static void qpnpint_irq_unmask(struct irq_data *d)
 {
-	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
 	unsigned long flags;
@@ -579,7 +578,7 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 	}
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
 }
 
@@ -590,7 +589,7 @@ static void qpnpint_irq_enable(struct irq_data *d)
 
 	qpnpint_irq_unmask(d);
 
-	data = 1 << irq;
+	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
 }
 
Quoted 10 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_set_type(struct irq_data · line 601

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
@@ -598,25 +597,26 @@ static int qpnpint_irq_set_type(struct irq_data 
 *d, unsigned int flow_type)
 {
 	struct spmi_pmic_arb_qpnpint_type type;
 	u8 irq = d->hwirq >> 8;
+	u8 bit_mask_irq = BIT(irq);

Why the local variable? Just do the ~BIT(irq) thing in place and let the compiler take care of the hoist?

Sure.. we will remove this local variable in the subsequent patch.

Quoted 27 lines
Quoted 27 lines
drivers/spmi/spmi-pmic-arb.c +6 -6
 	qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
 
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-		type.type |= 1 << irq;
+		type.type |= bit_mask_irq;
 		if (flow_type & IRQF_TRIGGER_RISING)
-			type.polarity_high |= 1 << irq;
+			type.polarity_high |= bit_mask_irq;
 		if (flow_type & IRQF_TRIGGER_FALLING)
-			type.polarity_low  |= 1 << irq;
+			type.polarity_low  |= bit_mask_irq;
 	} else {
 		if ((flow_type & (IRQF_TRIGGER_HIGH)) &&
 		    (flow_type & (IRQF_TRIGGER_LOW)))
 			return -EINVAL;
 
-		type.type &= ~(1 << irq); /* level trig */
+		type.type &= ~bit_mask_irq; /* level trig */
 		if (flow_type & IRQF_TRIGGER_HIGH)
-			type.polarity_high |= 1 << irq;
+			type.polarity_high |= bit_mask_irq;
 		else
-			type.polarity_low  |= 1 << irq;
+			type.polarity_low  |= bit_mask_irq;
 	}
 
Quoted 6 lines

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec {

Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
@@ -657,7 +657,7 @@ struct spmi_pmic_arb_irq_spec {

Overall I see little to no value with this patch. I suggest you drop the rename. The BIT() thing may be ok, but again, not sure there's any benefit.

Ok.. Sure. We drop out the renaming patch in the next version and will have only BIT() macro patch.

#9 lore raw

Re: [PATCH V1 02/15] spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb

Quoted 20 lines · On 06/01, [email protected] wrote:
Quoted 11 lines
Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
@@ -209,23 +210,24 @@ static void pa_read_data(struct
 spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
 * @buf:	buffer to write. length must be bc + 1.
 */

static void
-pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
+pa_write_data(struct spmi_pmic_arb *pa, const u8 *buf, u32 reg, u8 bc)

{
	u32 data = 0;
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc) · line 218

Quoted 4 lines

+

	memcpy(&data, buf, (bc & 3) + 1);
drivers/spmi/spmi-pmic-arb.c +1 -1
-	__raw_writel(data, dev->wr_base + reg);
+	pmic_arb_base_write(pa, reg, data);

This is an unrelated change. Not sure what's going on with this diff but we most likely want to keep the __raw_writel() here. See how renames introduce bugs and why we don't value them?

Quoted 3 lines

Actually pmic_arb_base_write has the writel_relaxed inside it. that's why we removed the __raw_writel to use the common function. Anyways, we drop the renaming patch from this patch series.

__raw_writel() is there on purpose because we're reading bytes at a time and the CPU could be big-endian or little-endian. readl_relaxed() would do a byte swap which we don't want.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#10 lore raw

Re: [PATCH V1 02/15] spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb

Quoted 21 lines · Stephen Boyd
Quoted 20 lines · On 06/01, [email protected] wrote:
Quoted 20 lines
Quoted 13 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
@@ -209,23 +210,24 @@ static void pa_read_data(struct
 spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
 * @buf:	buffer to write. length must be bc + 1.
 */

static void
-pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
+pa_write_data(struct spmi_pmic_arb *pa, const u8 *buf, u32 reg, u8 bc)

{
	u32 data = 0;
+
	memcpy(&data, buf, (bc & 3) + 1);

drivers/spmi/spmi-pmic-arb.c static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc) · line 218

Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
-	__raw_writel(data, dev->wr_base + reg);
+	pmic_arb_base_write(pa, reg, data);

This is an unrelated change. Not sure what's going on with this diff but we most likely want to keep the __raw_writel() here. See how renames introduce bugs and why we don't value them?

Quoted 7 lines
Quoted 3 lines

Actually pmic_arb_base_write has the writel_relaxed inside it. that's why we removed the __raw_writel to use the common function. Anyways, we drop the renaming patch from this patch series.

__raw_writel() is there on purpose because we're reading bytes at a time and the CPU could be big-endian or little-endian. readl_relaxed() would do a byte swap which we don't want.

ok. Thanks for clarifying it. We do not remove the __raw_writel.

#11 lore raw

PATCH 3/15 spmi: pmic-arb: fix inconsistent use of apid and chan

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently uses "apid" and "chan" to mean apid. Remove the use of chan and use only apid.

On a SPMI bus there is allocation to manage up to 4K peripherals. However, in practice only few peripherals are instantiated and only few among the instantiated ones actually interrupt.

APID is CPU's way of keeping track of peripherals that could interrupt. There is a table that maps the 256 interrupting peripherals to a number between 0 and 255. This number is called APID. Information about that interrupting peripheral is stored in registers offset by its corresponding apid.

---
 drivers/spmi/spmi-pmic-arb.c | 68 ++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 34 deletions(-)
drivers/spmi/spmi-pmic-arb.c +34 -34
index 7f918ea..7201611 100644
@@ -117,7 +117,7 @@ enum pmic_arb_cmd_op_code {
  * @spmic:		SPMI controller object
  * @apid_to_ppid:	in-memory copy of APID -> PPID mapping table.
  * @ver_ops:		version dependent operations.
- * @ppid_to_chan	in-memory copy of PPID -> channel (APID) mapping table.
+ * @ppid_to_apid	in-memory copy of PPID -> channel (APID) mapping table.
  *			v2 only.
  */
 struct spmi_pmic_arb {
@@ -140,9 +140,9 @@ struct spmi_pmic_arb {
 	struct spmi_controller	*spmic;
 	u16			*apid_to_ppid;
 	const struct pmic_arb_ver_ops *ver_ops;
-	u16			*ppid_to_chan;
-	u16			last_channel;
-	u8			*chan_to_owner;
+	u16			*ppid_to_apid;
+	u16			last_apid;
+	u8			*apid_to_owner;
 };
 
 /**
@@ -772,22 +772,22 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 	return 0;
 }
 
-static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid)
+static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 {
 	u32 regval, offset;
-	u16 chan;
+	u16 apid;
 	u16 id;
 
 	/*
 	 * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.
-	 * ppid_to_chan is an in-memory invert of that table.
+	 * ppid_to_apid is an in-memory invert of that table.
 	 */
-	for (chan = pa->last_channel; chan < pa->max_periph; chan++) {
+	for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
 		regval = readl_relaxed(pa->cnfg +
-				      SPMI_OWNERSHIP_TABLE_REG(chan));
-		pa->chan_to_owner[chan] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+				      SPMI_OWNERSHIP_TABLE_REG(apid));
+		pa->apid_to_owner[apid] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
 
-		offset = PMIC_ARB_REG_CHNL(chan);
+		offset = PMIC_ARB_REG_CHNL(apid);
 		if (offset >= pa->core_size)
 			break;
 
@@ -796,15 +796,15 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid)
 			continue;
 
 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
-		pa->ppid_to_chan[id] = chan | PMIC_ARB_CHAN_VALID;
+		pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
 		if (id == ppid) {
-			chan |= PMIC_ARB_CHAN_VALID;
+			apid |= PMIC_ARB_CHAN_VALID;
 			break;
 		}
 	}
-	pa->last_channel = chan & ~PMIC_ARB_CHAN_VALID;
+	pa->last_apid = apid & ~PMIC_ARB_CHAN_VALID;
 
-	return chan;
+	return apid;
 }
 
 
@@ -812,38 +812,38 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid)
 pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
-	u16 chan;
+	u16 apid;
 	u8 owner;
 
-	chan = pa->ppid_to_chan[ppid];
-	if (!(chan & PMIC_ARB_CHAN_VALID))
+	apid = pa->ppid_to_apid[ppid];
+	if (!(apid & PMIC_ARB_CHAN_VALID))
 		return -ENODEV;
 
 	*mode = 0;
 	*mode |= S_IRUSR;
 
-	chan &= ~PMIC_ARB_CHAN_VALID;
-	owner = pa->chan_to_owner[chan];
+	apid &= ~PMIC_ARB_CHAN_VALID;
+	owner = pa->apid_to_owner[apid];
 	if (owner == pa->ee)
 		*mode |= S_IWUSR;
 	return 0;
 }
 
-/* v2 offset per ppid (chan) and per ee */
+/* v2 offset per ppid and per ee */
 static int
 pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
-	u16 chan;
+	u16 apid;
 
-	chan = pa->ppid_to_chan[ppid];
-	if (!(chan & PMIC_ARB_CHAN_VALID))
-		chan = pmic_arb_find_chan(pa, ppid);
-	if (!(chan & PMIC_ARB_CHAN_VALID))
+	apid = pa->ppid_to_apid[ppid];
+	if (!(apid & PMIC_ARB_CHAN_VALID))
+		apid = pmic_arb_find_apid(pa, ppid);
+	if (!(apid & PMIC_ARB_CHAN_VALID))
 		return -ENODEV;
-	chan &= ~PMIC_ARB_CHAN_VALID;
+	apid &= ~PMIC_ARB_CHAN_VALID;
 
-	*offset = 0x1000 * pa->ee + 0x8000 * chan;
+	*offset = 0x1000 * pa->ee + 0x8000 * apid;
 	return 0;
 }
 
@@ -988,20 +988,20 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 			goto err_put_ctrl;
 		}
 
-		pa->ppid_to_chan = devm_kcalloc(&ctrl->dev,
+		pa->ppid_to_apid = devm_kcalloc(&ctrl->dev,
 						PMIC_ARB_MAX_PPID,
-						sizeof(*pa->ppid_to_chan),
+						sizeof(*pa->ppid_to_apid),
 						GFP_KERNEL);
-		if (!pa->ppid_to_chan) {
+		if (!pa->ppid_to_apid) {
 			err = -ENOMEM;
 			goto err_put_ctrl;
 		}
 
-		pa->chan_to_owner = devm_kcalloc(&ctrl->dev,
+		pa->apid_to_owner = devm_kcalloc(&ctrl->dev,
 						 pa->max_periph,
-						 sizeof(*pa->chan_to_owner),
+						 sizeof(*pa->apid_to_owner),
 						 GFP_KERNEL);
-		if (!pa->chan_to_owner) {
+		if (!pa->apid_to_owner) {
 			err = -ENOMEM;
 			goto err_put_ctrl;
 		}
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#12 lore raw

Re: [PATCH V1 03/15] spmi: pmic-arb: fix inconsistent use of apid and chan

Quoted 4 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently uses "apid" and "chan" to mean apid. Remove the use of chan and use only apid.

I'm not so sure. It currently uses "chan" to mean the offset to add to the "PMIC Arbiter channel registers" so that we can access the appropriate peripheral via the arbiter registers. I actually can't remember what APID or PPID stand for, so perhaps describing that as well would be helpful so we can navigate this acronym soup.

Quoted 10 lines

On a SPMI bus there is allocation to manage up to 4K peripherals. However, in practice only few peripherals are instantiated and only few among the instantiated ones actually interrupt.

APID is CPU's way of keeping track of peripherals that could interrupt. There is a table that maps the 256 interrupting peripherals to a number between 0 and 255. This number is called APID. Information about that interrupting peripheral is stored in registers offset by its corresponding apid.

That's all fine, but perhaps we shouldn't worry about "apid" being attached to interrupts? I mean, I can imagine some peripheral that doesn't interrupt, but we want to read/write it and that must be done with the "channel" or "apid" or really the "magic offset from the base of the channel registers" to do so. Probably APID is fine, as long as APID means "application processor peripheral id" or something along those lines.

Quoted 12 lines
---
 drivers/spmi/spmi-pmic-arb.c | 68 ++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 34 deletions(-)
drivers/spmi/spmi-pmic-arb.c +0 -0
index 7f918ea..7201611 100644

drivers/spmi/spmi-pmic-arb.c enum pmic_arb_cmd_op_code { · line 120

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -117,7 +117,7 @@ enum pmic_arb_cmd_op_code {
  * @spmic:		SPMI controller object
  * @apid_to_ppid:	in-memory copy of APID -> PPID mapping table.
  * @ver_ops:		version dependent operations.
- * @ppid_to_chan	in-memory copy of PPID -> channel (APID) mapping table.
+ * @ppid_to_apid	in-memory copy of PPID -> channel (APID) mapping table.

PPID->APID? No channel?

Quoted 20 lines
drivers/spmi/spmi-pmic-arb.c +3 -3
  *			v2 only.
  */
 struct spmi_pmic_arb {
@@ -140,9 +140,9 @@ struct spmi_pmic_arb {
 	struct spmi_controller	*spmic;
 	u16			*apid_to_ppid;
 	const struct pmic_arb_ver_ops *ver_ops;
-	u16			*ppid_to_chan;
-	u16			last_channel;
-	u8			*chan_to_owner;
+	u16			*ppid_to_apid;
+	u16			last_apid;
+	u8			*apid_to_owner;
 };
 
 /**
@@ -772,22 +772,22 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 	return 0;
 }
 

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 782

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +2 -2
-static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid)
+static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 {
 	u32 regval, offset;
-	u16 chan;
+	u16 apid;
 	u16 id;
 
 	/*
 	 * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.

Is this comment still relevant?

Quoted 17 lines
drivers/spmi/spmi-pmic-arb.c +5 -5
-	 * ppid_to_chan is an in-memory invert of that table.
+	 * ppid_to_apid is an in-memory invert of that table.
 	 */
-	for (chan = pa->last_channel; chan < pa->max_periph; chan++) {
+	for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
 		regval = readl_relaxed(pa->cnfg +
-				      SPMI_OWNERSHIP_TABLE_REG(chan));
-		pa->chan_to_owner[chan] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+				      SPMI_OWNERSHIP_TABLE_REG(apid));
+		pa->apid_to_owner[apid] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
 
-		offset = PMIC_ARB_REG_CHNL(chan);
+		offset = PMIC_ARB_REG_CHNL(apid);
 		if (offset >= pa->core_size)
 			break;
 

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid) · line 799

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -796,15 +796,15 @@ static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid)
 			continue;
 
 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
-		pa->ppid_to_chan[id] = chan | PMIC_ARB_CHAN_VALID;
+		pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;

Why do we still call the flag PMIC_ARB_CHAN_VALID then? Shouldn't it be PMIC_ARB_APID_VALID?

Quoted 14 lines
drivers/spmi/spmi-pmic-arb.c +3 -3
 		if (id == ppid) {
-			chan |= PMIC_ARB_CHAN_VALID;
+			apid |= PMIC_ARB_CHAN_VALID;
 			break;
 		}
 	}
-	pa->last_channel = chan & ~PMIC_ARB_CHAN_VALID;
+	pa->last_apid = apid & ~PMIC_ARB_CHAN_VALID;
 
-	return chan;
+	return apid;
 }
 
 
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#13 lore raw

Re: [PATCH V1 03/15] spmi: pmic-arb: fix inconsistent use of apid and chan

Quoted 6 lines · Stephen Boyd
Quoted 4 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently uses "apid" and "chan" to mean apid. Remove the use of chan and use only apid.

Quoted 7 lines

I'm not so sure. It currently uses "chan" to mean the offset to add to the "PMIC Arbiter channel registers" so that we can access the appropriate peripheral via the arbiter registers. I actually can't remember what APID or PPID stand for, so perhaps describing that as well would be helpful so we can navigate this acronym soup.

Yes. You are correct.
Will describe the "apid" and "ppid" in the next version patch.

Quoted 11 lines
Quoted 10 lines

On a SPMI bus there is allocation to manage up to 4K peripherals. However, in practice only few peripherals are instantiated and only few among the instantiated ones actually interrupt.

APID is CPU's way of keeping track of peripherals that could interrupt. There is a table that maps the 256 interrupting peripherals to a number between 0 and 255. This number is called APID. Information about that interrupting peripheral is stored in registers offset by its corresponding apid.

Quoted 8 lines

That's all fine, but perhaps we shouldn't worry about "apid" being attached to interrupts? I mean, I can imagine some peripheral that doesn't interrupt, but we want to read/write it and that must be done with the "channel" or "apid" or really the "magic offset from the base of the channel registers" to do so. Probably APID is fine, as long as APID means "application processor peripheral id" or something along those lines.

Yes. you are right. APID means "Application peripheral id".

Quoted 8 lines
Quoted 8 lines
---
 drivers/spmi/spmi-pmic-arb.c | 68 
++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 34 deletions(-)
Quoted 14 lines
Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +0 -1
index 7f918ea..7201611 100644
@@ -117,7 +117,7 @@ enum pmic_arb_cmd_op_code {
  * @spmic:		SPMI controller object
  * @apid_to_ppid:	in-memory copy of APID -> PPID mapping table.
  * @ver_ops:		version dependent operations.
- * @ppid_to_chan	in-memory copy of PPID -> channel (APID) mapping 
Quoted 3 lines

table.
+ * @ppid_to_apid in-memory copy of PPID -> channel (APID) mapping
table.

PPID->APID? No channel?

Sure. Will change it the next patch.

Quoted 30 lines
Quoted 30 lines

* v2 only.
*/
struct spmi_pmic_arb {

drivers/spmi/spmi-pmic-arb.c +5 -5
@@ -140,9 +140,9 @@ struct spmi_pmic_arb {
 	struct spmi_controller	*spmic;
 	u16			*apid_to_ppid;
 	const struct pmic_arb_ver_ops *ver_ops;
-	u16			*ppid_to_chan;
-	u16			last_channel;
-	u8			*chan_to_owner;
+	u16			*ppid_to_apid;
+	u16			last_apid;
+	u8			*apid_to_owner;
 };
 
 /**
@@ -772,22 +772,22 @@ static int qpnpint_irq_domain_map(struct 
 irq_domain *d,
 	return 0;
 }
 
-static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid)
+static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 {
 	u32 regval, offset;
-	u16 chan;
+	u16 apid;
 	u16 id;
 
Quoted 4 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 782

Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 	/*
 	 * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid.

Is this comment still relevant?

We will change channel to apid in the next patch.

Quoted 21 lines
Quoted 21 lines
drivers/spmi/spmi-pmic-arb.c +5 -5
-	 * ppid_to_chan is an in-memory invert of that table.
+	 * ppid_to_apid is an in-memory invert of that table.
 	 */
-	for (chan = pa->last_channel; chan < pa->max_periph; chan++) {
+	for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
 		regval = readl_relaxed(pa->cnfg +
-				      SPMI_OWNERSHIP_TABLE_REG(chan));
-		pa->chan_to_owner[chan] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+				      SPMI_OWNERSHIP_TABLE_REG(apid));
+		pa->apid_to_owner[apid] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
 
-		offset = PMIC_ARB_REG_CHNL(chan);
+		offset = PMIC_ARB_REG_CHNL(apid);
 		if (offset >= pa->core_size)
 			break;
@@ -796,15 +796,15 @@ static u16 pmic_arb_find_chan(struct 
 spmi_pmic_arb *pa, u16 ppid)
 			continue;
 
Quoted 7 lines

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_chan(struct spmi_pmic_arb *pa, u16 ppid) · line 799

Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
-		pa->ppid_to_chan[id] = chan | PMIC_ARB_CHAN_VALID;
+		pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;

Why do we still call the flag PMIC_ARB_CHAN_VALID then? Shouldn't it be PMIC_ARB_APID_VALID?

Yes. Agree. Will change it to PMIC_ARB_APID_VALID in the next patch.

Quoted 14 lines
Quoted 14 lines
drivers/spmi/spmi-pmic-arb.c +3 -3
 		if (id == ppid) {
-			chan |= PMIC_ARB_CHAN_VALID;
+			apid |= PMIC_ARB_CHAN_VALID;
 			break;
 		}
 	}
-	pa->last_channel = chan & ~PMIC_ARB_CHAN_VALID;
+	pa->last_apid = apid & ~PMIC_ARB_CHAN_VALID;
 
-	return chan;
+	return apid;
 }
 
#14 lore raw

PATCH 4/15 spmi: pmic-arb: optimize table lookups

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The current driver uses a mix of radix tree and a fwd lookup table to translate between apid and ppid. It is buggy and confusing.

Instead simply use a radix tree for v1 hardware and use the forward lookup table for v2.

---
 drivers/spmi/spmi-pmic-arb.c | 144 ++++++++++++++++++++++++++-----------------
 1 file changed, 88 insertions(+), 56 deletions(-)
drivers/spmi/spmi-pmic-arb.c +88 -56
index 7201611..6320f1f 100644
@@ -164,6 +164,8 @@ struct spmi_pmic_arb {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
+	int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+			u8 *apid);
 	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
@@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec {
 	unsigned irq:3;
 };
 
-static int search_mapping_table(struct spmi_pmic_arb *pa,
-				struct spmi_pmic_arb_irq_spec *spec,
-				u8 *apid)
-{
-	u16 ppid = spec->slave << 8 | spec->per;
-	u32 *mapping_table = pa->mapping_table;
-	int index = 0, i;
-	u32 data;
-
-	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
-		if (!test_and_set_bit(index, pa->mapping_table_valid))
-			mapping_table[index] = readl_relaxed(pa->cnfg +
-						SPMI_MAPPING_TABLE_REG(index));
-
-		data = mapping_table[index];
-
-		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
-			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
-				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
-			} else {
-				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
-				return 0;
-			}
-		} else {
-			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
-				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
-			} else {
-				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
-				return 0;
-			}
-		}
-	}
-
-	return -ENODEV;
-}
-
 static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   struct device_node *controller,
 					   const u32 *intspec,
@@ -702,7 +668,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 {
 	struct spmi_pmic_arb *pa = d->host_data;
 	struct spmi_pmic_arb_irq_spec spec;
-	int err;
+	int rc;
 	u8 apid;
 
 	dev_dbg(&pa->spmic->dev,
@@ -720,11 +686,14 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 	spec.per   = intspec[1];
 	spec.irq   = intspec[2];
 
-	err = search_mapping_table(pa, &spec, &apid);
-	if (err)
-		return err;
-
-	pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+	rc = pa->ver_ops->ppid_to_apid(pa, intspec[0],
+			(intspec[1] << 8), &apid);
+	if (rc < 0) {
+		dev_err(&pa->spmic->dev,
+		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n",
+		intspec[0], intspec[1], intspec[2], rc);
+		return rc;
+	}
 
 	/* Keep track of {max,min}_apid for bounding search during interrupt */
 	if (apid > pa->max_apid)
@@ -758,6 +727,54 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 }
 
 static int
+pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
+{
+	u16 ppid = sid << 8 | ((addr >> 8) & 0xFF);
+	u32 *mapping_table = pa->mapping_table;
+	int index = 0, i;
+	u16 apid_valid;
+	u32 data;
+
+	apid_valid = pa->ppid_to_apid[ppid];
+	if (apid_valid & PMIC_ARB_CHAN_VALID) {
+		*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);
+		return 0;
+	}
+
+	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
+		if (!test_and_set_bit(index, pa->mapping_table_valid))
+			mapping_table[index] = readl_relaxed(pa->cnfg +
+						SPMI_MAPPING_TABLE_REG(index));
+
+		data = mapping_table[index];
+
+		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
+			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+				pa->ppid_to_apid[ppid]
+					= *apid | PMIC_ARB_CHAN_VALID;
+				pa->apid_to_ppid[*apid] = ppid;
+				return 0;
+			}
+		} else {
+			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+				pa->ppid_to_apid[ppid]
+					= *apid | PMIC_ARB_CHAN_VALID;
+				pa->apid_to_ppid[*apid] = ppid;
+				return 0;
+			}
+		}
+	}
+
+	return -ENODEV;
+}
+
+static int
 pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	*mode = S_IRUSR | S_IWUSR;
@@ -797,6 +814,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
 		pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
+		pa->apid_to_ppid[apid] = id;
 		if (id == ppid) {
 			apid |= PMIC_ARB_CHAN_VALID;
 			break;
@@ -809,20 +827,35 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
 
 static int
-pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
+pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
-	u16 apid;
-	u8 owner;
+	u16 apid_valid;
 
-	apid = pa->ppid_to_apid[ppid];
-	if (!(apid & PMIC_ARB_CHAN_VALID))
+	apid_valid = pa->ppid_to_apid[ppid];
+	if (!(apid_valid & PMIC_ARB_CHAN_VALID))
+		apid_valid = pmic_arb_find_apid(pa, ppid);
+	if (!(apid_valid & PMIC_ARB_CHAN_VALID))
 		return -ENODEV;
 
+	*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);
+	return 0;
+}
+
+static int
+pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
+{
+	u8 apid;
+	u8 owner;
+	int rc;
+
+	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
+	if (rc < 0)
+		return rc;
+
 	*mode = 0;
 	*mode |= S_IRUSR;
 
-	apid &= ~PMIC_ARB_CHAN_VALID;
 	owner = pa->apid_to_owner[apid];
 	if (owner == pa->ee)
 		*mode |= S_IWUSR;
@@ -833,15 +866,12 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 static int
 pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
 {
-	u16 ppid = (sid << 8) | (addr >> 8);
-	u16 apid;
+	u8 apid;
+	int rc;
 
-	apid = pa->ppid_to_apid[ppid];
-	if (!(apid & PMIC_ARB_CHAN_VALID))
-		apid = pmic_arb_find_apid(pa, ppid);
-	if (!(apid & PMIC_ARB_CHAN_VALID))
-		return -ENODEV;
-	apid &= ~PMIC_ARB_CHAN_VALID;
+	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
+	if (rc < 0)
+		return rc;
 
 	*offset = 0x1000 * pa->ee + 0x8000 * apid;
 	return 0;
@@ -898,6 +928,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
 }
 
 static const struct pmic_arb_ver_ops pmic_arb_v1 = {
+	.ppid_to_apid		= pmic_arb_ppid_to_apid_v1,
 	.mode			= pmic_arb_mode_v1,
 	.non_data_cmd		= pmic_arb_non_data_cmd_v1,
 	.offset			= pmic_arb_offset_v1,
@@ -909,6 +940,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v2 = {
+	.ppid_to_apid		= pmic_arb_ppid_to_apid_v2,
 	.mode			= pmic_arb_mode_v2,
 	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
 	.offset			= pmic_arb_offset_v2,
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#15 lore raw

Re: [PATCH V1 04/15] spmi: pmic-arb: optimize table lookups

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb { · line 168

Quoted 10 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +2 -0
index 7201611..6320f1f 100644
@@ -164,6 +164,8 @@ struct spmi_pmic_arb {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
+	int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+			u8 *apid);

Nitpick: It's called "pa" but "dev" in the next line.

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec { · line 661

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +0 -2
 	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
@@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec {
 	unsigned irq:3;
 };
 
-static int search_mapping_table(struct spmi_pmic_arb *pa,
-				struct spmi_pmic_arb_irq_spec *spec,

Perhaps the spec should be removed at some point if this was the only place it was passed to.

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec { · line 662

Quoted 1 line
drivers/spmi/spmi-pmic-arb.c +0 -1
-				u8 *apid)

This code looks mostly unchanged, so please leave it as it is and move the pmic_arb_ppid_to_apid_v1() function here so we can see what actually changed.

Quoted 66 lines
drivers/spmi/spmi-pmic-arb.c +9 -39
-{
-	u16 ppid = spec->slave << 8 | spec->per;
-	u32 *mapping_table = pa->mapping_table;
-	int index = 0, i;
-	u32 data;
-
-	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
-		if (!test_and_set_bit(index, pa->mapping_table_valid))
-			mapping_table[index] = readl_relaxed(pa->cnfg +
-						SPMI_MAPPING_TABLE_REG(index));
-
-		data = mapping_table[index];
-
-		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
-			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
-				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
-			} else {
-				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
-				return 0;
-			}
-		} else {
-			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
-				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
-			} else {
-				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
-				return 0;
-			}
-		}
-	}
-
-	return -ENODEV;
-}
-
 static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   struct device_node *controller,
 					   const u32 *intspec,
@@ -702,7 +668,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 {
 	struct spmi_pmic_arb *pa = d->host_data;
 	struct spmi_pmic_arb_irq_spec spec;
-	int err;
+	int rc;
 	u8 apid;
 
 	dev_dbg(&pa->spmic->dev,
@@ -720,11 +686,14 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 	spec.per   = intspec[1];
 	spec.irq   = intspec[2];
 
-	err = search_mapping_table(pa, &spec, &apid);
-	if (err)
-		return err;
-
-	pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+	rc = pa->ver_ops->ppid_to_apid(pa, intspec[0],
+			(intspec[1] << 8), &apid);
+	if (rc < 0) {
+		dev_err(&pa->spmic->dev,
+		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n",
+		intspec[0], intspec[1], intspec[2], rc);
+		return rc;
+	}
 
 	/* Keep track of {max,min}_apid for bounding search during interrupt */
 	if (apid > pa->max_apid)

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 732

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
@@ -758,6 +727,54 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 }
 
 static int
+pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
+{
+	u16 ppid = sid << 8 | ((addr >> 8) & 0xFF);

The function is called ppid_to_apid, but we pass in a sid and addr. Just pass a ppid instead of both split out?

Quoted 36 lines
drivers/spmi/spmi-pmic-arb.c +11 -0
+	u32 *mapping_table = pa->mapping_table;
+	int index = 0, i;
+	u16 apid_valid;
+	u32 data;
+
+	apid_valid = pa->ppid_to_apid[ppid];
+	if (apid_valid & PMIC_ARB_CHAN_VALID) {
+		*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);
+		return 0;
+	}
+
 

From here to...

drivers/spmi/spmi-pmic-arb.c +22 -0
+	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
+		if (!test_and_set_bit(index, pa->mapping_table_valid))
+			mapping_table[index] = readl_relaxed(pa->cnfg +
+						SPMI_MAPPING_TABLE_REG(index));
+
+		data = mapping_table[index];
+
+		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
+			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+				pa->ppid_to_apid[ppid]
+					= *apid | PMIC_ARB_CHAN_VALID;
+				pa->apid_to_ppid[*apid] = ppid;
+				return 0;
+			}
+		} else {
+			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 775

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+				pa->ppid_to_apid[ppid]
+					= *apid | PMIC_ARB_CHAN_VALID;
+				pa->apid_to_ppid[*apid] = ppid;
+				return 0;
+			}
+		}
+	}
+
+	return -ENODEV;
+}

here is all unchanged? Oh except apid_to_ppid/ppid_to_apid is inserted.

Quoted 24 lines
drivers/spmi/spmi-pmic-arb.c +5 -3
+
+static int
 pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	*mode = S_IRUSR | S_IWUSR;
@@ -797,6 +814,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
 		pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
+		pa->apid_to_ppid[apid] = id;
 		if (id == ppid) {
 			apid |= PMIC_ARB_CHAN_VALID;
 			break;
@@ -809,20 +827,35 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
 
 static int
-pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
+pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
-	u16 apid;
-	u8 owner;
+	u16 apid_valid;

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 841

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +5 -2
 
-	apid = pa->ppid_to_apid[ppid];
-	if (!(apid & PMIC_ARB_CHAN_VALID))
+	apid_valid = pa->ppid_to_apid[ppid];
+	if (!(apid_valid & PMIC_ARB_CHAN_VALID))
+		apid_valid = pmic_arb_find_apid(pa, ppid);
+	if (!(apid_valid & PMIC_ARB_CHAN_VALID))
 		return -ENODEV;
 
+	*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);

Useless parenthesis. Please remove.

Why can't we just return a number that's >= 0 for apid and < 0 for an error from this op? Pointer passing is odd style.

Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
+	return 0;
+}
+
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#16 lore raw

Re: [PATCH V1 04/15] spmi: pmic-arb: optimize table lookups

Quoted 14 lines · Stephen Boyd

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb { · line 168

Quoted 10 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +2 -0
index 7201611..6320f1f 100644
@@ -164,6 +164,8 @@ struct spmi_pmic_arb {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
+	int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+			u8 *apid);

Nitpick: It's called "pa" but "dev" in the next line.

Will rename the pa -> dev in the next patch.

Quoted 7 lines
Quoted 7 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
@@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec {
 	unsigned irq:3;
 };
 
Quoted 6 lines

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec { · line 661

Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +0 -2
-static int search_mapping_table(struct spmi_pmic_arb *pa,
-				struct spmi_pmic_arb_irq_spec *spec,

Perhaps the spec should be removed at some point if this was the only place it was passed to.

Yes. This is passed only in this function. You want to remove this structure and pass the slave, per and irq as function parameters? If so we will do it in the next patch.

Quoted 6 lines

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec { · line 662

Quoted 1 line
drivers/spmi/spmi-pmic-arb.c +0 -1
-				u8 *apid)

This code looks mostly unchanged, so please leave it as it is and move the pmic_arb_ppid_to_apid_v1() function here so we can see what actually changed.

Sure. Will do that in the next patch.

Quoted 72 lines
Quoted 72 lines
drivers/spmi/spmi-pmic-arb.c +1 -34
-{
-	u16 ppid = spec->slave << 8 | spec->per;
-	u32 *mapping_table = pa->mapping_table;
-	int index = 0, i;
-	u32 data;
-
-	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
-		if (!test_and_set_bit(index, pa->mapping_table_valid))
-			mapping_table[index] = readl_relaxed(pa->cnfg +
-						SPMI_MAPPING_TABLE_REG(index));
-
-		data = mapping_table[index];
-
-		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
-			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
-				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
-			} else {
-				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
-				return 0;
-			}
-		} else {
-			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
-				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
-			} else {
-				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
-				return 0;
-			}
-		}
-	}
-
-	return -ENODEV;
-}
-
 static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   struct device_node *controller,
 					   const u32 *intspec,
@@ -702,7 +668,7 @@ static int qpnpint_irq_domain_dt_translate(struct 
 irq_domain *d,
 {
 	struct spmi_pmic_arb *pa = d->host_data;
 	struct spmi_pmic_arb_irq_spec spec;
-	int err;
+	int rc;
 	u8 apid;
 
drivers/spmi/spmi-pmic-arb.c +8 -5
 	dev_dbg(&pa->spmic->dev,
@@ -720,11 +686,14 @@ static int 
 qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 	spec.per   = intspec[1];
 	spec.irq   = intspec[2];
 
-	err = search_mapping_table(pa, &spec, &apid);
-	if (err)
-		return err;
-
-	pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+	rc = pa->ver_ops->ppid_to_apid(pa, intspec[0],
+			(intspec[1] << 8), &apid);
+	if (rc < 0) {
+		dev_err(&pa->spmic->dev,
+		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n",
+		intspec[0], intspec[1], intspec[2], rc);
+		return rc;
+	}
 
 	/* Keep track of {max,min}_apid for bounding search during interrupt 

*/

drivers/spmi/spmi-pmic-arb.c +0 -0
 	if (apid > pa->max_apid)
@@ -758,6 +727,54 @@ static int qpnpint_irq_domain_map(struct 
 irq_domain *d,
 }
 
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 732

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
 static int
+pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, 
 u8 *apid)
+{
+	u16 ppid = sid << 8 | ((addr >> 8) & 0xFF);

The function is called ppid_to_apid, but we pass in a sid and addr. Just pass a ppid instead of both split out?

Sure .. Will do that in the next patch.

Quoted 41 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 743

Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c +11 -0
+	u32 *mapping_table = pa->mapping_table;
+	int index = 0, i;
+	u16 apid_valid;
+	u32 data;
+
+	apid_valid = pa->ppid_to_apid[ppid];
+	if (apid_valid & PMIC_ARB_CHAN_VALID) {
+		*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);
+		return 0;
+	}
+

From here to...

Quoted 27 lines
drivers/spmi/spmi-pmic-arb.c +27 -0
+	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
+		if (!test_and_set_bit(index, pa->mapping_table_valid))
+			mapping_table[index] = readl_relaxed(pa->cnfg +
+						SPMI_MAPPING_TABLE_REG(index));
+
+		data = mapping_table[index];
+
+		if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) {
+			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+				pa->ppid_to_apid[ppid]
+					= *apid | PMIC_ARB_CHAN_VALID;
+				pa->apid_to_ppid[*apid] = ppid;
+				return 0;
+			}
+		} else {
+			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+				pa->ppid_to_apid[ppid]
+					= *apid | PMIC_ARB_CHAN_VALID;
+				pa->apid_to_ppid[*apid] = ppid;
+				return 0;
+			}
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 775

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +5 -0
+		}
+	}
+
+	return -ENODEV;
+}

here is all unchanged? Oh except apid_to_ppid/ppid_to_apid is inserted.

Yes. correct. Will move this part to the original place in the next patch.

Quoted 38 lines
Quoted 38 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
+
+static int
 pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t 

*mode)
{

drivers/spmi/spmi-pmic-arb.c +1 -0
 	*mode = S_IRUSR | S_IWUSR;
@@ -797,6 +814,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb 
 *pa, u16 ppid)
 
 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
 		pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
+		pa->apid_to_ppid[apid] = id;
 		if (id == ppid) {
 			apid |= PMIC_ARB_CHAN_VALID;
drivers/spmi/spmi-pmic-arb.c +6 -5
 			break;
@@ -809,20 +827,35 @@ static u16 pmic_arb_find_apid(struct 
 spmi_pmic_arb *pa, u16 ppid)
 
 
 static int
-pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t 
 *mode)
+pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, 
 u8 *apid)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
-	u16 apid;
-	u8 owner;
+	u16 apid_valid;
 
-	apid = pa->ppid_to_apid[ppid];
-	if (!(apid & PMIC_ARB_CHAN_VALID))
+	apid_valid = pa->ppid_to_apid[ppid];
+	if (!(apid_valid & PMIC_ARB_CHAN_VALID))
+		apid_valid = pmic_arb_find_apid(pa, ppid);
+	if (!(apid_valid & PMIC_ARB_CHAN_VALID))
 		return -ENODEV;
 
Quoted 4 lines

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct · line 844

Quoted 1 line
drivers/spmi/spmi-pmic-arb.c +1 -0
+	*apid = (apid_valid & ~PMIC_ARB_CHAN_VALID);

Useless parenthesis. Please remove.

Sure. Will remove it in the next patch.

Quoted 3 lines

Why can't we just return a number that's >= 0 for apid and < 0 for an error from this op? Pointer passing is odd style.

Sure. Will change it in the next patch.

Quoted 3 lines
Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
+	return 0;
+}
+
#17 lore raw

Re: [PATCH V1 04/15] spmi: pmic-arb: optimize table lookups

Quoted 17 lines · On 06/01, [email protected] wrote:
Quoted 10 lines · Stephen Boyd
Quoted 9 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +0 -0
index 7201611..6320f1f 100644
@@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec {
 	unsigned irq:3;
 };
 
Quoted 6 lines

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec { · line 661

Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +0 -2
-static int search_mapping_table(struct spmi_pmic_arb *pa,
-				struct spmi_pmic_arb_irq_spec *spec,

Perhaps the spec should be removed at some point if this was the only place it was passed to.

Quoted 3 lines

Yes. This is passed only in this function. You want to remove this structure and pass the slave, per and irq as function parameters? If so we will do it in the next patch.

We don't pass it anywhere though? So I'm just saying have local variables instead of the structure.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#18 lore raw

Re: [PATCH V1 04/15] spmi: pmic-arb: optimize table lookups

Quoted 18 lines · Stephen Boyd
Quoted 17 lines · On 06/01, [email protected] wrote:
Quoted 16 lines · Stephen Boyd

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_irq_spec { · line 661

Quoted 11 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +0 -2
index 7201611..6320f1f 100644
@@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec {
 	unsigned irq:3;
 };
 
-static int search_mapping_table(struct spmi_pmic_arb *pa,
-				struct spmi_pmic_arb_irq_spec *spec,

Perhaps the spec should be removed at some point if this was the only place it was passed to.

Quoted 6 lines
Quoted 3 lines

Yes. This is passed only in this function. You want to remove this structure and pass the slave, per and irq as function parameters? If so we will do it in the next patch.

We don't pass it anywhere though? So I'm just saying have local variables instead of the structure.

Sure. Thanks for the clarification.

#19 lore raw

PATCH 5/15 spmi: pmic-arb: cleanup unrequested irqs

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

We see a unmapped irqs trigger right around bootup. This could likely be because the bootloader exited leaving the interrupts in an unknown or unhandled state. Ack and mask the interrupt if one is found. A request_irq later will unmask it and also setup proper mapping structures.

Also the current driver ensures that no read/write transaction is in progress while it makes changes to the interrupt regions. This is not necessary because read/writes over spmi and arbiter interrupt control are independent operations. Hence, remove the synchronized accesses to interrupt region.

---
 drivers/spmi/spmi-pmic-arb.c | 101 ++++++++++++++++++-------------------------
 1 file changed, 43 insertions(+), 58 deletions(-)
drivers/spmi/spmi-pmic-arb.c +43 -58
index 6320f1f..0a5728c 100644
@@ -98,6 +98,11 @@ enum pmic_arb_cmd_op_code {
 
 struct pmic_arb_ver_ops;
 
+struct apid_data {
+	u16		ppid;
+	u8		owner;
+};
+
 /**
  * spmi_pmic_arb - SPMI PMIC Arbiter object
  *
@@ -115,7 +120,6 @@ enum pmic_arb_cmd_op_code {
  * @mapping_table:	in-memory copy of PPID -> APID mapping table.
  * @domain:		irq domain object for PMIC IRQ domain
  * @spmic:		SPMI controller object
- * @apid_to_ppid:	in-memory copy of APID -> PPID mapping table.
  * @ver_ops:		version dependent operations.
  * @ppid_to_apid	in-memory copy of PPID -> channel (APID) mapping table.
  *			v2 only.
@@ -138,11 +142,10 @@ struct spmi_pmic_arb {
 	DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
 	struct irq_domain	*domain;
 	struct spmi_controller	*spmic;
-	u16			*apid_to_ppid;
 	const struct pmic_arb_ver_ops *ver_ops;
 	u16			*ppid_to_apid;
 	u16			last_apid;
-	u8			*apid_to_owner;
+	struct apid_data	apid_data[PMIC_ARB_MAX_PERIPHS];
 };
 
 /**
@@ -482,6 +485,28 @@ static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 				    d->irq);
 }
 
+static void cleanup_irq(struct spmi_pmic_arb *pa, u8 apid, int id)
+{
+	u16 ppid = pa->apid_data[apid].ppid;
+	u8 sid = ppid >> 8;
+	u8 per = ppid & 0xFF;
+	u8 irq_mask = BIT(id);
+
+	writel_relaxed(irq_mask, pa->intr + pa->ver_ops->irq_clear(apid));
+
+	if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
+			(per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1))
+		dev_err_ratelimited(&pa->spmic->dev,
+				"failed to ack irq_mask = 0x%x for ppid = %x\n",
+				irq_mask, ppid);
+
+	if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
+			       (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1))
+		dev_err_ratelimited(&pa->spmic->dev,
+				"failed to ack irq_mask = 0x%x for ppid = %x\n",
+				irq_mask, ppid);
+}
+
 static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
 {
 	unsigned int irq;
@@ -493,9 +518,13 @@ static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
 		id = ffs(status) - 1;
 		status &= ~BIT(id);
 		irq = irq_find_mapping(pa->domain,
-				       pa->apid_to_ppid[apid] << 16
+				       pa->apid_data[apid].ppid << 16
 				     | id << 8
 				     | apid);
+		if (irq == 0) {
+			cleanup_irq(pa, apid, id);
+			continue;
+		}
 		generic_handle_irq(irq);
 	}
 }
@@ -530,12 +559,9 @@ static void qpnpint_irq_ack(struct irq_data *d)
 	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
-	unsigned long flags;
 	u8 data;
 
-	raw_spin_lock_irqsave(&pa->lock, flags);
 	writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid));
-	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
 	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
@@ -543,23 +569,9 @@ static void qpnpint_irq_ack(struct irq_data *d)
 
 static void qpnpint_irq_mask(struct irq_data *d)
 {
-	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
-	u8 apid = d->hwirq;
-	unsigned long flags;
-	u32 status;
-	u8 data;
+	u8 data = BIT(irq);
 
-	raw_spin_lock_irqsave(&pa->lock, flags);
-	status = readl_relaxed(pa->intr + pa->ver_ops->acc_enable(apid));
-	if (status & SPMI_PIC_ACC_ENABLE_BIT) {
-		status = status & ~SPMI_PIC_ACC_ENABLE_BIT;
-		writel_relaxed(status, pa->intr +
-			       pa->ver_ops->acc_enable(apid));
-	}
-	raw_spin_unlock_irqrestore(&pa->lock, flags);
-
-	data = BIT(irq);
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
@@ -568,20 +580,12 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
-	unsigned long flags;
-	u32 status;
-	u8 data;
+	u8 data = BIT(irq);
 
-	raw_spin_lock_irqsave(&pa->lock, flags);
-	status = readl_relaxed(pa->intr + pa->ver_ops->acc_enable(apid));
-	if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) {
-		writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT,
-				pa->intr + pa->ver_ops->acc_enable(apid));
-	}
-	raw_spin_unlock_irqrestore(&pa->lock, flags);
+	writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
+		pa->intr + pa->ver_ops->acc_enable(apid));
 
-	data = BIT(irq);
-	qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
+	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
 static void qpnpint_irq_enable(struct irq_data *d)
@@ -755,7 +759,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
 				pa->ppid_to_apid[ppid]
 					= *apid | PMIC_ARB_CHAN_VALID;
-				pa->apid_to_ppid[*apid] = ppid;
+				pa->apid_data[*apid].ppid = ppid;
 				return 0;
 			}
 		} else {
@@ -765,7 +769,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
 				pa->ppid_to_apid[ppid]
 					= *apid | PMIC_ARB_CHAN_VALID;
-				pa->apid_to_ppid[*apid] = ppid;
+				pa->apid_data[*apid].ppid = ppid;
 				return 0;
 			}
 		}
@@ -802,7 +806,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
 		regval = readl_relaxed(pa->cnfg +
 				      SPMI_OWNERSHIP_TABLE_REG(apid));
-		pa->apid_to_owner[apid] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+		pa->apid_data[apid].owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
 
 		offset = PMIC_ARB_REG_CHNL(apid);
 		if (offset >= pa->core_size)
@@ -814,7 +818,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
 		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
 		pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
-		pa->apid_to_ppid[apid] = id;
+		pa->apid_data[apid].ppid = id;
 		if (id == ppid) {
 			apid |= PMIC_ARB_CHAN_VALID;
 			break;
@@ -846,7 +850,6 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	u8 apid;
-	u8 owner;
 	int rc;
 
 	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
@@ -856,8 +859,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	*mode = 0;
 	*mode |= S_IRUSR;
 
-	owner = pa->apid_to_owner[apid];
-	if (owner == pa->ee)
+	if (pa->ee == pa->apid_data[apid].owner)
 		*mode |= S_IWUSR;
 	return 0;
 }
@@ -1028,15 +1030,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 			err = -ENOMEM;
 			goto err_put_ctrl;
 		}
-
-		pa->apid_to_owner = devm_kcalloc(&ctrl->dev,
-						 pa->max_periph,
-						 sizeof(*pa->apid_to_owner),
-						 GFP_KERNEL);
-		if (!pa->apid_to_owner) {
-			err = -ENOMEM;
-			goto err_put_ctrl;
-		}
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
@@ -1088,14 +1081,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 
 	pa->ee = ee;
 
-	pa->apid_to_ppid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS,
-					    sizeof(*pa->apid_to_ppid),
-					    GFP_KERNEL);
-	if (!pa->apid_to_ppid) {
-		err = -ENOMEM;
-		goto err_put_ctrl;
-	}
-
 	pa->mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS - 1,
 					sizeof(*pa->mapping_table), GFP_KERNEL);
 	if (!pa->mapping_table) {
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#20 lore raw

Re: [PATCH V1 05/15] spmi: pmic-arb: cleanup unrequested irqs

Quoted 7 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

We see a unmapped irqs trigger right around bootup. This could likely be because the bootloader exited leaving the interrupts in an unknown or unhandled state. Ack and mask the interrupt if one is found. A request_irq later will unmask it and also setup proper mapping structures.

Do we have systems where this is causing an interrupt storm due to a level high interrupt or something? Just plain acking and masking irqs at boot if we don't have an irq descriptor created yet doesn't sound like a good idea, because we'll lose all interrupts that happen before this driver probes?

Quoted 6 lines

Also the current driver ensures that no read/write transaction is in progress while it makes changes to the interrupt regions. This is not necessary because read/writes over spmi and arbiter interrupt control are independent operations. Hence, remove the synchronized accesses to interrupt region.

That's another patch for this paragraph.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#21 lore raw

Re: [PATCH V1 05/15] spmi: pmic-arb: cleanup unrequested irqs

Quoted 9 lines · Stephen Boyd
Quoted 7 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

We see a unmapped irqs trigger right around bootup. This could likely be because the bootloader exited leaving the interrupts in an unknown or unhandled state. Ack and mask the interrupt if one is found. A request_irq later will unmask it and also setup proper mapping structures.

Quoted 6 lines

Do we have systems where this is causing an interrupt storm due to a level high interrupt or something? Just plain acking and masking irqs at boot if we don't have an irq descriptor created yet doesn't sound like a good idea, because we'll lose all interrupts that happen before this driver probes?

Yes. There were instances of an interrupt storm without this patch. There is an RT_STATUS register in the peripheral address space which maintains the real time state and can be read by the client driver before it registers for the irq. Few client drivers such as charger already doing this.

Quoted 8 lines
Quoted 6 lines

Also the current driver ensures that no read/write transaction is in progress while it makes changes to the interrupt regions. This is not necessary because read/writes over spmi and arbiter interrupt control are independent operations. Hence, remove the synchronized accesses to interrupt region.

That's another patch for this paragraph.

This patch is already pulled in to Greg's tree.

#22 lore raw

Re: [PATCH V1 05/15] spmi: pmic-arb: cleanup unrequested irqs

Quoted 16 lines · On 06/06, [email protected] wrote:
Quoted 9 lines · Stephen Boyd
Quoted 7 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

We see a unmapped irqs trigger right around bootup. This could likely be because the bootloader exited leaving the interrupts in an unknown or unhandled state. Ack and mask the interrupt if one is found. A request_irq later will unmask it and also setup proper mapping structures.

Quoted 6 lines

Do we have systems where this is causing an interrupt storm due to a level high interrupt or something? Just plain acking and masking irqs at boot if we don't have an irq descriptor created yet doesn't sound like a good idea, because we'll lose all interrupts that happen before this driver probes?

Quoted 5 lines

Yes. There were instances of an interrupt storm without this patch. There is an RT_STATUS register in the peripheral address space which maintains the real time state and can be read by the client driver before it registers for the irq. Few client drivers such as charger already doing this.

So you're saying that drivers need to read RT_STATUS to know if they have a pending interrupt before requesting it? That sounds bogus.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#23 lore raw

Re: [PATCH V1 05/15] spmi: pmic-arb: cleanup unrequested irqs

Quoted 23 lines · Stephen Boyd
Quoted 16 lines · On 06/06, [email protected] wrote:
Quoted 9 lines · Stephen Boyd
Quoted 7 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

We see a unmapped irqs trigger right around bootup. This could likely be because the bootloader exited leaving the interrupts in an unknown or unhandled state. Ack and mask the interrupt if one is found. A request_irq later will unmask it and also setup proper mapping structures.

Quoted 6 lines

Do we have systems where this is causing an interrupt storm due to a level high interrupt or something? Just plain acking and masking irqs at boot if we don't have an irq descriptor created yet doesn't sound like a good idea, because we'll lose all interrupts that happen before this driver probes?

Quoted 5 lines

Yes. There were instances of an interrupt storm without this patch. There is an RT_STATUS register in the peripheral address space which maintains the real time state and can be read by the client driver before it registers for the irq. Few client drivers such as charger already doing this.

Quoted 3 lines

So you're saying that drivers need to read RT_STATUS to know if they have a pending interrupt before requesting it? That sounds bogus.

In many cases a PMIC module driver does need to know the initial state of the hardware during driver initialization and the RT_STATUS register indicates this (irrespective of the IRQ_EN status). The reset value of IRQ_EN = 0 and if an event occurs before we request an IRQ, there is no way to know the initial state even after we request this irq as there will be no pending interrupt because the HW default value of IRQ_EN = 0. This can be known only through reading the RT_STATUS.

I understand your concern of clearing the IRQ before we request it does not seem a clean way, do you have any other recommendation of this could be handled ?

#24 lore raw

PATCH 6/15 spmi: pmic-arb: fix missing interrupts

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

irq_enable is called when the device resumes. Note that the irq_enable is called regardless of whether the interrupt was marked enabled/disabled in the descriptor or whether it was masked/unmasked at the controller while resuming.

The current driver unconditionally clears the interrupt in its irq_enable callback. This is dangerous as any interrupts that happen right before the resume could be missed. Remove the irq_enable callback and use mask/unmask instead.

Also remove struct pmic_arb_irq_spec as it serves no real purpose. It is used only in the translate function and the code is much cleaner without it.

---
 drivers/spmi/spmi-pmic-arb.c | 29 +++--------------------------
 1 file changed, 3 insertions(+), 26 deletions(-)
drivers/spmi/spmi-pmic-arb.c +3 -26
index 0a5728c..bc03737 100644
@@ -588,17 +588,6 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
-static void qpnpint_irq_enable(struct irq_data *d)
-{
-	u8 irq  = d->hwirq >> 8;
-	u8 data;
-
-	qpnpint_irq_unmask(d);
-
-	data = BIT(irq);
-	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
-}
-
 static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
 	struct spmi_pmic_arb_qpnpint_type type;
@@ -647,7 +636,6 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
 
 static struct irq_chip pmic_arb_irqchip = {
 	.name		= "pmic_arb",
-	.irq_enable	= qpnpint_irq_enable,
 	.irq_ack	= qpnpint_irq_ack,
 	.irq_mask	= qpnpint_irq_mask,
 	.irq_unmask	= qpnpint_irq_unmask,
@@ -657,12 +645,6 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
 			| IRQCHIP_SKIP_SET_WAKE,
 };
 
-struct spmi_pmic_arb_irq_spec {
-	unsigned slave:4;
-	unsigned per:8;
-	unsigned irq:3;
-};
-
 static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   struct device_node *controller,
 					   const u32 *intspec,
@@ -671,7 +653,6 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   unsigned int *out_type)
 {
 	struct spmi_pmic_arb *pa = d->host_data;
-	struct spmi_pmic_arb_irq_spec spec;
 	int rc;
 	u8 apid;
 
@@ -686,10 +667,6 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 	if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7)
 		return -EINVAL;
 
-	spec.slave = intspec[0];
-	spec.per   = intspec[1];
-	spec.irq   = intspec[2];
-
 	rc = pa->ver_ops->ppid_to_apid(pa, intspec[0],
 			(intspec[1] << 8), &apid);
 	if (rc < 0) {
@@ -705,9 +682,9 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 	if (apid < pa->min_apid)
 		pa->min_apid = apid;
 
-	*out_hwirq = spec.slave << 24
-		   | spec.per   << 16
-		   | spec.irq   << 8
+	*out_hwirq = (intspec[0] & 0xF) << 24
+		   | (intspec[1] & 0xFF) << 16
+		   | (intspec[2] & 0x7) << 8
 		   | apid;
 	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
 
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#25 lore raw

Re: [PATCH V1 06/15] spmi: pmic-arb: fix missing interrupts

Quoted 7 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

irq_enable is called when the device resumes. Note that the irq_enable is called regardless of whether the interrupt was marked enabled/disabled in the descriptor or whether it was masked/unmasked at the controller while resuming.

Quoted 8 lines

The current driver unconditionally clears the interrupt in its irq_enable callback. This is dangerous as any interrupts that happen right before the resume could be missed. Remove the irq_enable callback and use mask/unmask instead.

Also remove struct pmic_arb_irq_spec as it serves no real purpose. It is used only in the translate function and the code is much cleaner without it.

Also a separate patch for that part....

Quoted 30 lines
---
 drivers/spmi/spmi-pmic-arb.c | 29 +++--------------------------
 1 file changed, 3 insertions(+), 26 deletions(-)
drivers/spmi/spmi-pmic-arb.c +0 -11
index 0a5728c..bc03737 100644
@@ -588,17 +588,6 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
-static void qpnpint_irq_enable(struct irq_data *d)
-{
-	u8 irq  = d->hwirq >> 8;
-	u8 data;
-
-	qpnpint_irq_unmask(d);
-
-	data = BIT(irq);
-	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
-}
-
 static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
 	struct spmi_pmic_arb_qpnpint_type type;

drivers/spmi/spmi-pmic-arb.c static int qpnpint_get_irqchip_state(struct irq_data *d, · line 641

Quoted 7 lines
drivers/spmi/spmi-pmic-arb.c +0 -1
@@ -647,7 +636,6 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
 
 static struct irq_chip pmic_arb_irqchip = {
 	.name		= "pmic_arb",
-	.irq_enable	= qpnpint_irq_enable,
 	.irq_ack	= qpnpint_irq_ack,
 	.irq_mask	= qpnpint_irq_mask,
 	.irq_unmask	= qpnpint_irq_unmask,

This looks ok.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#26 lore raw

Re: [PATCH V1 06/15] spmi: pmic-arb: fix missing interrupts

Quoted 13 lines · Stephen Boyd
Quoted 12 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

irq_enable is called when the device resumes. Note that the irq_enable is called regardless of whether the interrupt was marked enabled/disabled in the descriptor or whether it was masked/unmasked at the controller while resuming.

The current driver unconditionally clears the interrupt in its irq_enable callback. This is dangerous as any interrupts that happen right before the resume could be missed. Remove the irq_enable callback and use mask/unmask instead.

Quoted 6 lines
Quoted 3 lines

Also remove struct pmic_arb_irq_spec as it serves no real purpose. It is used only in the translate function and the code is much cleaner without it.

Also a separate patch for that part....

Sure. will split it in to different patch or move it in the
https://patchwork.kernel.org/patch/9754511/ patch as per your comment.

Quoted 34 lines
Quoted 34 lines
---
 drivers/spmi/spmi-pmic-arb.c | 29 +++--------------------------
 1 file changed, 3 insertions(+), 26 deletions(-)
drivers/spmi/spmi-pmic-arb.c +0 -11
index 0a5728c..bc03737 100644
@@ -588,17 +588,6 @@ static void qpnpint_irq_unmask(struct irq_data 
 *d)
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
 }
 
-static void qpnpint_irq_enable(struct irq_data *d)
-{
-	u8 irq  = d->hwirq >> 8;
-	u8 data;
-
-	qpnpint_irq_unmask(d);
-
-	data = BIT(irq);
-	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
-}
-
 static int qpnpint_irq_set_type(struct irq_data *d, unsigned int 
 flow_type)

{

drivers/spmi/spmi-pmic-arb.c +0 -0
 	struct spmi_pmic_arb_qpnpint_type type;
@@ -647,7 +636,6 @@ static int qpnpint_get_irqchip_state(struct 
 irq_data *d,
 
Quoted 8 lines
Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +0 -1
 static struct irq_chip pmic_arb_irqchip = {
 	.name		= "pmic_arb",
-	.irq_enable	= qpnpint_irq_enable,
 	.irq_ack	= qpnpint_irq_ack,
 	.irq_mask	= qpnpint_irq_mask,

.irq_unmask = qpnpint_irq_unmask,

This looks ok.

Thanks !

#27 lore raw

PATCH 7/15 spmi: pmic-arb: clear the latched status of the interrupt

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

PMIC interrupts each have an internal latched status bit which is not visible from any register. This status bit is set as soon as the conditions specified in the interrupt type and polarity registers are met even if the interrupt is not enabled. When it is set, nothing else changes within the PMIC and no interrupt notification packets are sent. If the internal latched status bit is set when an interrupt is enabled, then the value is immediately propagated into the interrupt latched status register and an interrupt notification packet is sent out from the PMIC over SPMI.

This PMIC hardware behavior can lead to a situation where the handler for a level triggered interrupt is called immediately after enable_irq() is called even though the interrupt physically triggered while it was disabled within the genirq framework. This situation takes place if the the interrupt fires twice after calling disable_irq(). The first time it fires, the level flow handler will mask and disregard it. Unfortunately, the second time it fires, the internal latched status bit is set within the PMIC and no further notification is received. When enable_irq() is called later, the interrupt is unmasked (enabled in the PMIC) which results in the PMIC immediately sending an interrupt notification packet out over SPMI. This breaks the semantics of level triggered interrupts within the genirq framework since they should be completely ignored while disabled.

The PMIC internal latched status behavior also affects how interrupts are treated during suspend. While entering suspend, all interrupts not specified as wakeup mode are masked. Upon resume, these interrupts are unmasked. Thus if any of the non-wakeup PMIC interrupts fired while the system was suspended, then the PMIC will send interrupt notification packets out via SPMI as soon as they are unmasked during resume. This behavior violates genirq semantics as well since non-wakeup interrupts should be completely ignored during suspend.

Modify the qpnpint_irq_unmask() function so that the interrupt latched status clear register is written immediately before the interrupt enable register. This clears the internal latched status bit of the interrupt so that it cannot trigger spuriously immediately upon being enabled.

Also, while resuming an irq, an unmask could be called even if it was not previously masked. So, before writing these registers, check if the interrupt is already enabled within the PMIC. If it is, then no further register writes are required. This condition check ensures that a valid latched status register bit is not cleared until it is properly handled.

---
 drivers/spmi/spmi-pmic-arb.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
drivers/spmi/spmi-pmic-arb.c +12 -2
index bc03737..1d23df0 100644
@@ -580,12 +580,22 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
 	u8 irq  = d->hwirq >> 8;
 	u8 apid = d->hwirq;
-	u8 data = BIT(irq);
+	u8 buf[2];
 
 	writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
 		pa->intr + pa->ver_ops->acc_enable(apid));
 
-	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
+	qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1);
+	if (!(buf[0] & BIT(irq))) {
+		/*
+		 * Since the interrupt is currently disabled, write to both the
+		 * LATCHED_CLR and EN_SET registers so that a spurious interrupt
+		 * cannot be triggered when the interrupt is enabled
+		 */
+		buf[0] = BIT(irq);
+		buf[1] = BIT(irq);
+		qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 2);
+	}
 }
 
 static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
Reviewed-by on v1 7/15
#28 lore raw

Re: [PATCH V1 07/15] spmi: pmic-arb: clear the latched status of the interrupt

Quoted 13 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

PMIC interrupts each have an internal latched status bit which is not visible from any register. This status bit is set as soon as the conditions specified in the interrupt type and polarity registers are met even if the interrupt is not enabled. When it is set, nothing else changes within the PMIC and no interrupt notification packets are sent. If the internal latched status bit is set when an interrupt is enabled, then the value is immediately propagated into the interrupt latched status register and an interrupt notification packet is sent out from the PMIC over SPMI.

Quoted 5 lines

This PMIC hardware behavior can lead to a situation where the handler for a level triggered interrupt is called immediately after enable_irq() is called even though the interrupt physically triggered while it was disabled within the genirq framework. This situation takes place if the the interrupt fires twice after

Double 'the'

Quoted 4 lines

calling disable_irq(). The first time it fires, the level flow handler will mask and disregard it. Unfortunately, the second time it fires, the internal latched status bit is set within the PMIC and no further notification is received.

because the interrupt has been disabled.

Quoted 6 lines

When enable_irq()
is called later, the interrupt is unmasked (enabled in the PMIC) which results in the PMIC immediately sending an interrupt notification packet out over SPMI. This breaks the semantics of level triggered interrupts within the genirq framework since they should be completely ignored while disabled.

Ok. I wonder why the hardware latches interrupts at all.

Quoted 24 lines

The PMIC internal latched status behavior also affects how interrupts are treated during suspend. While entering suspend, all interrupts not specified as wakeup mode are masked. Upon resume, these interrupts are unmasked. Thus if any of the non-wakeup PMIC interrupts fired while the system was suspended, then the PMIC will send interrupt notification packets out via SPMI as soon as they are unmasked during resume. This behavior violates genirq semantics as well since non-wakeup interrupts should be completely ignored during suspend.

Modify the qpnpint_irq_unmask() function so that the interrupt latched status clear register is written immediately before the interrupt enable register. This clears the internal latched status bit of the interrupt so that it cannot trigger spuriously immediately upon being enabled.

Also, while resuming an irq, an unmask could be called even if it was not previously masked. So, before writing these registers, check if the interrupt is already enabled within the PMIC. If it is, then no further register writes are required. This condition check ensures that a valid latched status register bit is not cleared until it is properly handled.

Quoted 2 lines
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#29 lore raw

Re: [PATCH V1 07/15] spmi: pmic-arb: clear the latched status of the interrupt

Quoted 62 lines · Stephen Boyd
Quoted 13 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

PMIC interrupts each have an internal latched status bit which is not visible from any register. This status bit is set as soon as the conditions specified in the interrupt type and polarity registers are met even if the interrupt is not enabled. When it is set, nothing else changes within the PMIC and no interrupt notification packets are sent. If the internal latched status bit is set when an interrupt is enabled, then the value is immediately propagated into the interrupt latched status register and an interrupt notification packet is sent out from the PMIC over SPMI.

Quoted 5 lines

This PMIC hardware behavior can lead to a situation where the handler for a level triggered interrupt is called immediately after enable_irq() is called even though the interrupt physically triggered while it was disabled within the genirq framework. This situation takes place if the the interrupt fires twice after

Double 'the'

Quoted 4 lines

calling disable_irq(). The first time it fires, the level flow handler will mask and disregard it. Unfortunately, the second time it fires, the internal latched status bit is set within the PMIC and no further notification is received.

because the interrupt has been disabled.

Quoted 6 lines

When enable_irq()
is called later, the interrupt is unmasked (enabled in the PMIC) which results in the PMIC immediately sending an interrupt notification packet out over SPMI. This breaks the semantics of level triggered interrupts within the genirq framework since they should be completely ignored while disabled.

Ok. I wonder why the hardware latches interrupts at all.

Quoted 24 lines

The PMIC internal latched status behavior also affects how interrupts are treated during suspend. While entering suspend, all interrupts not specified as wakeup mode are masked. Upon resume, these interrupts are unmasked. Thus if any of the non-wakeup PMIC interrupts fired while the system was suspended, then the PMIC will send interrupt notification packets out via SPMI as soon as they are unmasked during resume. This behavior violates genirq semantics as well since non-wakeup interrupts should be completely ignored during suspend.

Modify the qpnpint_irq_unmask() function so that the interrupt latched status clear register is written immediately before the interrupt enable register. This clears the internal latched status bit of the interrupt so that it cannot trigger spuriously immediately upon being enabled.

Also, while resuming an irq, an unmask could be called even if it was not previously masked. So, before writing these registers, check if the interrupt is already enabled within the PMIC. If it is, then no further register writes are required. This condition check ensures that a valid latched status register bit is not cleared until it is properly handled.

Quoted 4 lines
Quoted 2 lines

Thanks for reviewing and acking this.

#30 lore raw

PATCH 8/15 spmi: pmic_arb: use appropriate flow handler

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The current code uses handle_level_irq flow handler even if the trigger type of the interrupt is edge. This can lead to missing of an edge transition that happens when the interrupt is being handled. The level flow handler masks the interrupt while it is being handled, so if an edge transition happens at that time, that edge is lost.

Use an edge flow handler for edge type interrupts which ensures that the interrupt stays enabled while being handled - at least until it triggers at which point the flow handler sets the IRQF_PENDING flag and only then masks the interrupt. That IRQF_PENDING state indicates an edge transition happened while the interrupt was being handled and the handler is called again.

---
 drivers/spmi/spmi-pmic-arb.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/spmi/spmi-pmic-arb.c +6 -0
index 1d23df0..ad34491 100644
@@ -625,6 +625,12 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
 	}
 
 	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
+
+	if (flow_type & IRQ_TYPE_EDGE_BOTH)
+		irq_set_handler_locked(d, handle_edge_irq);
+	else
+		irq_set_handler_locked(d, handle_level_irq);
+
 	return 0;
 }
 
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#31 lore raw

Re: [PATCH V1 08/15] spmi: pmic_arb: use appropriate flow handler

Quoted 16 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The current code uses handle_level_irq flow handler even if the trigger type of the interrupt is edge. This can lead to missing of an edge transition that happens when the interrupt is being handled. The level flow handler masks the interrupt while it is being handled, so if an edge transition happens at that time, that edge is lost.

Use an edge flow handler for edge type interrupts which ensures that the interrupt stays enabled while being handled - at least until it triggers at which point the flow handler sets the IRQF_PENDING flag and only then masks the interrupt. That IRQF_PENDING state indicates an edge transition happened while the interrupt was being handled and the handler is called again.

Quoted 2 lines

Do we have any edge interrupts in the tree right now? At least RTC seems to be using edge... This should go back to stable with a Fixes tag.

Quoted 9 lines
---
 drivers/spmi/spmi-pmic-arb.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/spmi/spmi-pmic-arb.c +0 -0
index 1d23df0..ad34491 100644

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) · line 629

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
@@ -625,6 +625,12 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
 	}
 
 	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
+
+	if (flow_type & IRQ_TYPE_EDGE_BOTH)

IRQ_TYPE_EDGE_BOTH doesn't seem appropriate to use here. We're really just testing to see if the type is an edge type, not if it's BOTH edges.

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) · line 633

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+		irq_set_handler_locked(d, handle_edge_irq);
+	else
+		irq_set_handler_locked(d, handle_level_irq);
+

And we already have code that does that check:

if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))

so just put the irq_set_handler_locked() calls in those if statements please.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#32 lore raw

Re: [PATCH V1 08/15] spmi: pmic_arb: use appropriate flow handler

Quoted 17 lines · Stephen Boyd
Quoted 16 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The current code uses handle_level_irq flow handler even if the trigger type of the interrupt is edge. This can lead to missing of an edge transition that happens when the interrupt is being handled. The level flow handler masks the interrupt while it is being handled, so if an edge transition happens at that time, that edge is lost.

Use an edge flow handler for edge type interrupts which ensures that the interrupt stays enabled while being handled - at least until it triggers at which point the flow handler sets the IRQF_PENDING flag and only then masks the interrupt. That IRQF_PENDING state indicates an edge transition happened while the interrupt was being handled and the handler is called again.

Quoted 7 lines
Quoted 2 lines

Do we have any edge interrupts in the tree right now? At least RTC seems to be using edge... This should go back to stable with a Fixes tag.

Yes. A bunch of internal drivers use edge interrupts.

Quoted 12 lines
Quoted 12 lines
---
 drivers/spmi/spmi-pmic-arb.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/spmi/spmi-pmic-arb.c +0 -0
index 1d23df0..ad34491 100644
@@ -625,6 +625,12 @@ static int qpnpint_irq_set_type(struct irq_data 
 *d, unsigned int flow_type)
 	}
 
Quoted 8 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) · line 629

Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c +2 -0
 	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
+
+	if (flow_type & IRQ_TYPE_EDGE_BOTH)

IRQ_TYPE_EDGE_BOTH doesn't seem appropriate to use here. We're really just testing to see if the type is an edge type, not if it's BOTH edges.

Ok. Agree. Will fix in the follow up patch.

Quoted 11 lines

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) · line 633

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+		irq_set_handler_locked(d, handle_edge_irq);
+	else
+		irq_set_handler_locked(d, handle_level_irq);
+

And we already have code that does that check:

if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))

so just put the irq_set_handler_locked() calls in those if statements please.

Sure. Will fix in the follow up patch.

#33 lore raw

PATCH 9/15 spmi: pmic-arb: check apid enabled before calling the handler

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently invokes the apid handler (periph_handler()) once it sees that the summary status bit for that apid is set.

However the hardware is designed to set that bit even if the apid interrupts are disabled. The driver should check whether the apid is indeed enabled before calling the apid handler.

---
 drivers/spmi/spmi-pmic-arb.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/spmi/spmi-pmic-arb.c +7 -3
index ad34491..f8638fa 100644
@@ -536,8 +536,8 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
 	int last = pa->max_apid >> 5;
-	u32 status;
-	int i, id;
+	u32 status, enable;
+	int i, id, apid;
 
 	chained_irq_enter(chip, desc);
 
@@ -547,7 +547,11 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
-			periph_interrupt(pa, id + i * 32);
+			apid = id + i * 32;
+			enable = readl_relaxed(intr +
+					pa->ver_ops->acc_enable(apid));
+			if (enable & SPMI_PIC_ACC_ENABLE_BIT)
+				periph_interrupt(pa, apid);
 		}
 	}
 
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#34 lore raw

Re: [PATCH V1 09/15] spmi: pmic-arb: check apid enabled before calling the handler

Quoted 3 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently invokes the apid handler (periph_handler())

You mean periph_interrupt()?

Quoted 5 lines

once it sees that the summary status bit for that apid is set.

However the hardware is designed to set that bit even if the apid interrupts are disabled. The driver should check whether the apid is indeed enabled before calling the apid handler.

Really? Wow that is awful. Or is this because ACC_ENABLE bit is always set now and never cleared?

Quoted 23 lines
---
 drivers/spmi/spmi-pmic-arb.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/spmi/spmi-pmic-arb.c +2 -2
index ad34491..f8638fa 100644
@@ -536,8 +536,8 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
 	int last = pa->max_apid >> 5;
-	u32 status;
-	int i, id;
+	u32 status, enable;
+	int i, id, apid;
 
 	chained_irq_enter(chip, desc);
 

drivers/spmi/spmi-pmic-arb.c static void pmic_arb_chained_irq(struct irq_desc *desc) · line 552

Quoted 7 lines
drivers/spmi/spmi-pmic-arb.c +3 -1
@@ -547,7 +547,11 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
-			periph_interrupt(pa, id + i * 32);
+			apid = id + i * 32;
+			enable = readl_relaxed(intr +
+					pa->ver_ops->acc_enable(apid));

Do we need to read the hardware to figure this out? After earlier patches in this series we would never clear the SPMI_PIC_ACC_ENABLE_BIT after one of the irqs in a peripheral is unmasked for the first time (which looks to be fixing a bug in the existing driver BTW). So in practice, this should almost always be true.

In the one case that it isn't true, we'll be handling some other irq for another peripheral and then hardware will tell us there's an interrupt for a peripheral that doesn't have any interrupts unmasked. We would call periph_interrupt() and then that shouldn't see any interrupts in the status register for that APID. So we do some more work, but nothing happens still. Did I miss something? What is this fixing?

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#35 lore raw

Re: [PATCH V1 09/15] spmi: pmic-arb: check apid enabled before calling the handler

Quoted 7 lines · Stephen Boyd
Quoted 3 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently invokes the apid handler (periph_handler())

You mean periph_interrupt()?

Yes.

Quoted 9 lines
Quoted 5 lines

once it sees that the summary status bit for that apid is set.

However the hardware is designed to set that bit even if the apid interrupts are disabled. The driver should check whether the apid is indeed enabled before calling the apid handler.

Really? Wow that is awful. Or is this because ACC_ENABLE bit is always set now and never cleared?

Yes. It is awful. It is not because of the ACC_ENABLE bit is set.

Quoted 23 lines
Quoted 23 lines
---
 drivers/spmi/spmi-pmic-arb.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/spmi/spmi-pmic-arb.c +2 -2
index ad34491..f8638fa 100644
@@ -536,8 +536,8 @@ static void pmic_arb_chained_irq(struct irq_desc 
 *desc)
 	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
 	int last = pa->max_apid >> 5;
-	u32 status;
-	int i, id;
+	u32 status, enable;
+	int i, id, apid;
 
 	chained_irq_enter(chip, desc);
Quoted 17 lines

drivers/spmi/spmi-pmic-arb.c static void pmic_arb_chained_irq(struct irq_desc · line 553

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +3 -1
@@ -547,7 +547,11 @@ static void pmic_arb_chained_irq(struct irq_desc 
 *desc)
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
-			periph_interrupt(pa, id + i * 32);
+			apid = id + i * 32;
+			enable = readl_relaxed(intr +
+					pa->ver_ops->acc_enable(apid));

Do we need to read the hardware to figure this out? After earlier patches in this series we would never clear the SPMI_PIC_ACC_ENABLE_BIT after one of the irqs in a peripheral is unmasked for the first time (which looks to be fixing a bug in the existing driver BTW). So in practice, this should almost always be true.

yes. We have removed clearing the SPMI_PIC_ACC_ENABLE_BIT from the irq_mask, because if we disable this BIT it disables all the peripheral IRQs, which we don't want.

Once the peripheral fires the interrupt the summary status bit for that peripheral is set even though the SPMI_PIC_ACC_ENABLE_BIT is not enabled. That's why we have to read this register to not service the interrupt that is not requested/enabled yet. This SPMI_PIC_ACC_ENABLE_BIT is enabled during the irq_unmask which is called from request_irq.

Quoted 7 lines

In the one case that it isn't true, we'll be handling some other irq for another peripheral and then hardware will tell us there's an interrupt for a peripheral that doesn't have any interrupts unmasked. We would call periph_interrupt() and then that shouldn't see any interrupts in the status register for that APID. So we do some more work, but nothing happens still. Did I miss something? What is this fixing?

Yes. As you said this fixes the issue of calling the periph_interrupt for some other irq that is not yet requested and enabled yet.

#36 lore raw

Re: [PATCH V1 09/15] spmi: pmic-arb: check apid enabled before calling the handler

Quoted 60 lines · On 06/14, [email protected] wrote:
Quoted 7 lines · Stephen Boyd
Quoted 3 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently invokes the apid handler (periph_handler())

You mean periph_interrupt()?

Yes.

Quoted 9 lines
Quoted 5 lines

once it sees that the summary status bit for that apid is set.

However the hardware is designed to set that bit even if the apid interrupts are disabled. The driver should check whether the apid is indeed enabled before calling the apid handler.

Really? Wow that is awful. Or is this because ACC_ENABLE bit is always set now and never cleared?

Yes. It is awful. It is not because of the ACC_ENABLE bit is set.

Quoted 24 lines
Quoted 24 lines

---
drivers/spmi/spmi-pmic-arb.c | 10 +++++++---

1 file changed, 7 insertions(+), 3 deletions(-)
drivers/spmi/spmi-pmic-arb.c +2 -2
index ad34491..f8638fa 100644
@@ -536,8 +536,8 @@ static void pmic_arb_chained_irq(struct
 irq_desc *desc)
 	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
 	int last = pa->max_apid >> 5;
-	u32 status;
-	int i, id;
+	u32 status, enable;
+	int i, id, apid;
 
 	chained_irq_enter(chip, desc);
Quoted 17 lines

drivers/spmi/spmi-pmic-arb.c static void pmic_arb_chained_irq(struct · line 553

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +3 -1
@@ -547,7 +547,11 @@ static void pmic_arb_chained_irq(struct
 irq_desc *desc)
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
-			periph_interrupt(pa, id + i * 32);
+			apid = id + i * 32;
+			enable = readl_relaxed(intr +
+					pa->ver_ops->acc_enable(apid));

Do we need to read the hardware to figure this out? After earlier patches in this series we would never clear the SPMI_PIC_ACC_ENABLE_BIT after one of the irqs in a peripheral is unmasked for the first time (which looks to be fixing a bug in the existing driver BTW). So in practice, this should almost always be true.

Quoted 4 lines

yes. We have removed clearing the SPMI_PIC_ACC_ENABLE_BIT from the irq_mask,
because if we disable this BIT it disables all the peripheral IRQs, which we don't want.

Right, we could reference count it though and only clear and set the bit when we mask and unmask the last irq in the peripheral.

Quoted 9 lines

Once the peripheral fires the interrupt the summary status bit for that peripheral
is set even though the SPMI_PIC_ACC_ENABLE_BIT is not enabled. That's why we have to
read this register to not service the interrupt that is not requested/enabled yet.
This SPMI_PIC_ACC_ENABLE_BIT is enabled during the irq_unmask which is called from request_irq.

Ok. So this is again about handling the case where an interrupt is pending out of the bootloader?

Quoted 11 lines
Quoted 8 lines

In the one case that it isn't true, we'll be handling some other irq for another peripheral and then hardware will tell us there's an interrupt for a peripheral that doesn't have any interrupts unmasked. We would call periph_interrupt() and then that shouldn't see any interrupts in the status register for that APID. So we do some more work, but nothing happens still. Did I miss something? What is this fixing?

Yes. As you said this fixes the issue of calling the periph_interrupt for some other irq that is not yet requested and enabled yet.

Hmm. I seemed to miss the fact that periph_interrupt() will see an unmasked interrupt and think it's valid. I thought that only SPMI_PIC_ACC_ENABLE_BIT was broken, but you're saying that the status register for a particular peripheral will always latch interrupts even if we haven't enabled them?

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#37 lore raw

Re: [PATCH V1 09/15] spmi: pmic-arb: check apid enabled before calling the handler

Quoted 61 lines · Stephen Boyd
Quoted 60 lines · On 06/14, [email protected] wrote:
Quoted 7 lines · Stephen Boyd
Quoted 3 lines · Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The driver currently invokes the apid handler (periph_handler())

You mean periph_interrupt()?

Yes.

Quoted 9 lines
Quoted 5 lines

once it sees that the summary status bit for that apid is set.

However the hardware is designed to set that bit even if the apid interrupts are disabled. The driver should check whether the apid is indeed enabled before calling the apid handler.

Really? Wow that is awful. Or is this because ACC_ENABLE bit is always set now and never cleared?

Yes. It is awful. It is not because of the ACC_ENABLE bit is set.

Quoted 41 lines
Quoted 25 lines

---
drivers/spmi/spmi-pmic-arb.c | 10 +++++++---

1 file changed, 7 insertions(+), 3 deletions(-)
drivers/spmi/spmi-pmic-arb.c +2 -2
index ad34491..f8638fa 100644
@@ -536,8 +536,8 @@ static void pmic_arb_chained_irq(struct
 irq_desc *desc)
 	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
 	int last = pa->max_apid >> 5;
-	u32 status;
-	int i, id;
+	u32 status, enable;
+	int i, id, apid;
 
 	chained_irq_enter(chip, desc);

drivers/spmi/spmi-pmic-arb.c static void pmic_arb_chained_irq(struct · line 553

Quoted 8 lines
drivers/spmi/spmi-pmic-arb.c +3 -1
@@ -547,7 +547,11 @@ static void pmic_arb_chained_irq(struct
 irq_desc *desc)
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
-			periph_interrupt(pa, id + i * 32);
+			apid = id + i * 32;
+			enable = readl_relaxed(intr +
+					pa->ver_ops->acc_enable(apid));

Do we need to read the hardware to figure this out? After earlier patches in this series we would never clear the SPMI_PIC_ACC_ENABLE_BIT after one of the irqs in a peripheral is unmasked for the first time (which looks to be fixing a bug in the existing driver BTW). So in practice, this should almost always be true.

Quoted 8 lines
Quoted 4 lines

yes. We have removed clearing the SPMI_PIC_ACC_ENABLE_BIT from the irq_mask,
because if we disable this BIT it disables all the peripheral IRQs, which we don't want.

Right, we could reference count it though and only clear and set the bit when we mask and unmask the last irq in the peripheral.

Actually we are disabling the interrupt at peripheral level, so i believe disabling the PIC_ACC_EN_BIT is not mandatory.

Quoted 10 lines
Quoted 9 lines

Once the peripheral fires the interrupt the summary status bit for that peripheral
is set even though the SPMI_PIC_ACC_ENABLE_BIT is not enabled. That's why we have to
read this register to not service the interrupt that is not requested/enabled yet.
This SPMI_PIC_ACC_ENABLE_BIT is enabled during the irq_unmask which is called from request_irq.

Quoted 3 lines

Ok. So this is again about handling the case where an interrupt is pending out of the bootloader?

Yes.

Quoted 13 lines
Quoted 11 lines
Quoted 8 lines

In the one case that it isn't true, we'll be handling some other irq for another peripheral and then hardware will tell us there's an interrupt for a peripheral that doesn't have any interrupts unmasked. We would call periph_interrupt() and then that shouldn't see any interrupts in the status register for that APID. So we do some more work, but nothing happens still. Did I miss something? What is this fixing?

Yes. As you said this fixes the issue of calling the periph_interrupt for some other irq that is not yet requested and enabled yet.

Quoted 5 lines

Hmm. I seemed to miss the fact that periph_interrupt() will see an unmasked interrupt and think it's valid. I thought that only SPMI_PIC_ACC_ENABLE_BIT was broken, but you're saying that the status register for a particular peripheral will always latch interrupts even if we haven't enabled them?

Yes. Correct. Both SPMI_PIC_OWNERm_ACC_STATUSn and SPMI_PIC_IRQ_STATUSn are getting set when the peripheral fires the interrupt, even though we haven't enable that particular peripheral bit in SPMI_PIC_ACC_ENABLEn register.

#38 lore raw

PATCH 10/15 spmi: pmic_arb: add support for PMIC bus arbiter v3

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

PMIC bus arbiter v3 supports 512 SPMI peripherals. Add the v3 operators to support this new arbiter version.

---
 drivers/spmi/spmi-pmic-arb.c | 133 +++++++++++++++++++++++++++----------------
 1 file changed, 83 insertions(+), 50 deletions(-)
drivers/spmi/spmi-pmic-arb.c +83 -50
index f8638fa..0deac33 100644
@@ -28,6 +28,7 @@
 /* PMIC Arbiter configuration registers */
 #define PMIC_ARB_VERSION		0x0000
 #define PMIC_ARB_VERSION_V2_MIN		0x20010000
+#define PMIC_ARB_VERSION_V3_MIN		0x30000000
 #define PMIC_ARB_INT_EN			0x0004
 
 /* PMIC Arbiter channel registers offsets */
@@ -96,6 +97,17 @@ enum pmic_arb_cmd_op_code {
 /* interrupt enable bit */
 #define SPMI_PIC_ACC_ENABLE_BIT		BIT(0)
 
+#define HWIRQ(slave_id, periph_id, irq_id, apid) \
+	((((slave_id) & 0xF)   << 28) | \
+	(((periph_id) & 0xFF)  << 20) | \
+	(((irq_id)    & 0x7)   << 16) | \
+	(((apid)      & 0x1FF) << 0))
+
+#define HWIRQ_SID(hwirq)  (((hwirq) >> 28) & 0xF)
+#define HWIRQ_PER(hwirq)  (((hwirq) >> 20) & 0xFF)
+#define HWIRQ_IRQ(hwirq)  (((hwirq) >> 16) & 0x7)
+#define HWIRQ_APID(hwirq) (((hwirq) >> 0)  & 0x1FF)
+
 struct pmic_arb_ver_ops;
 
 struct apid_data {
@@ -151,7 +163,9 @@ struct spmi_pmic_arb {
 /**
  * pmic_arb_ver: version dependent functionality.
  *
- * @mode:	access rights to specified pmic peripheral.
+ * @ver_str:		version string.
+ * @ppid_to_apid:	finds the apid for a given ppid.
+ * @mode:		access rights to specified pmic peripheral.
  * @non_data_cmd:	on v1 issues an spmi non-data command.
  *			on v2 no HW support, returns -EOPNOTSUPP.
  * @offset:		on v1 offset of per-ee channel.
@@ -167,8 +181,9 @@ struct spmi_pmic_arb {
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
  */
 struct pmic_arb_ver_ops {
+	const char *ver_str;
 	int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
-			u8 *apid);
+			u16 *apid);
 	int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
@@ -177,10 +192,10 @@ struct pmic_arb_ver_ops {
 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
 	/* Interrupts controller functionality (offset of PIC registers) */
-	u32 (*owner_acc_status)(u8 m, u8 n);
-	u32 (*acc_enable)(u8 n);
-	u32 (*irq_status)(u8 n);
-	u32 (*irq_clear)(u8 n);
+	u32 (*owner_acc_status)(u8 m, u16 n);
+	u32 (*acc_enable)(u16 n);
+	u32 (*irq_status)(u16 n);
+	u32 (*irq_clear)(u16 n);
 };
 
 static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,
@@ -462,8 +477,8 @@ static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
 			       size_t len)
 {
 	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
-	u8 sid = d->hwirq >> 24;
-	u8 per = d->hwirq >> 16;
+	u8 sid = HWIRQ_SID(d->hwirq);
+	u8 per = HWIRQ_PER(d->hwirq);
 
 	if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
 			       (per << 8) + reg, buf, len))
@@ -475,8 +490,8 @@ static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
 static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 {
 	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
-	u8 sid = d->hwirq >> 24;
-	u8 per = d->hwirq >> 16;
+	u8 sid = HWIRQ_SID(d->hwirq);
+	u8 per = HWIRQ_PER(d->hwirq);
 
 	if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid,
 			      (per << 8) + reg, buf, len))
@@ -485,7 +500,7 @@ static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 				    d->irq);
 }
 
-static void cleanup_irq(struct spmi_pmic_arb *pa, u8 apid, int id)
+static void cleanup_irq(struct spmi_pmic_arb *pa, u16 apid, int id)
 {
 	u16 ppid = pa->apid_data[apid].ppid;
 	u8 sid = ppid >> 8;
@@ -507,20 +522,19 @@ static void cleanup_irq(struct spmi_pmic_arb *pa, u8 apid, int id)
 				irq_mask, ppid);
 }
 
-static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
+static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid)
 {
 	unsigned int irq;
 	u32 status;
 	int id;
+	u8 sid = (pa->apid_data[apid].ppid >> 8) & 0xF;
+	u8 per = pa->apid_data[apid].ppid & 0xFF;
 
 	status = readl_relaxed(pa->intr + pa->ver_ops->irq_status(apid));
 	while (status) {
 		id = ffs(status) - 1;
 		status &= ~BIT(id);
-		irq = irq_find_mapping(pa->domain,
-				       pa->apid_data[apid].ppid << 16
-				     | id << 8
-				     | apid);
+		irq = irq_find_mapping(pa->domain, HWIRQ(sid, per, id, apid));
 		if (irq == 0) {
 			cleanup_irq(pa, apid, id);
 			continue;
@@ -561,8 +575,8 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 static void qpnpint_irq_ack(struct irq_data *d)
 {
 	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
-	u8 irq  = d->hwirq >> 8;
-	u8 apid = d->hwirq;
+	u8 irq = HWIRQ_IRQ(d->hwirq);
+	u16 apid = HWIRQ_APID(d->hwirq);
 	u8 data;
 
 	writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid));
@@ -573,7 +587,7 @@ static void qpnpint_irq_ack(struct irq_data *d)
 
 static void qpnpint_irq_mask(struct irq_data *d)
 {
-	u8 irq  = d->hwirq >> 8;
+	u8 irq = HWIRQ_IRQ(d->hwirq);
 	u8 data = BIT(irq);
 
 	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
@@ -582,8 +596,8 @@ static void qpnpint_irq_mask(struct irq_data *d)
 static void qpnpint_irq_unmask(struct irq_data *d)
 {
 	struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
-	u8 irq  = d->hwirq >> 8;
-	u8 apid = d->hwirq;
+	u8 irq = HWIRQ_IRQ(d->hwirq);
+	u16 apid = HWIRQ_APID(d->hwirq);
 	u8 buf[2];
 
 	writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
@@ -605,7 +619,7 @@ static void qpnpint_irq_unmask(struct irq_data *d)
 static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
 	struct spmi_pmic_arb_qpnpint_type type;
-	u8 irq = d->hwirq >> 8;
+	u8 irq = HWIRQ_IRQ(d->hwirq);
 	u8 bit_mask_irq = BIT(irq);
 
 	qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
@@ -642,7 +656,7 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
 				     enum irqchip_irq_state which,
 				     bool *state)
 {
-	u8 irq = d->hwirq >> 8;
+	u8 irq = HWIRQ_IRQ(d->hwirq);
 	u8 status = 0;
 
 	if (which != IRQCHIP_STATE_LINE_LEVEL)
@@ -674,7 +688,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 {
 	struct spmi_pmic_arb *pa = d->host_data;
 	int rc;
-	u8 apid;
+	u16 apid;
 
 	dev_dbg(&pa->spmic->dev,
 		"intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
@@ -702,10 +716,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 	if (apid < pa->min_apid)
 		pa->min_apid = apid;
 
-	*out_hwirq = (intspec[0] & 0xF) << 24
-		   | (intspec[1] & 0xFF) << 16
-		   | (intspec[2] & 0x7) << 8
-		   | apid;
+	*out_hwirq = HWIRQ(intspec[0], intspec[1], intspec[2], apid);
 	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
 
 	dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
@@ -728,7 +739,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 }
 
 static int
-pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
+pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid)
 {
 	u16 ppid = sid << 8 | ((addr >> 8) & 0xFF);
 	u32 *mapping_table = pa->mapping_table;
@@ -776,7 +787,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 }
 
 static int
-pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
+pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	*mode = S_IRUSR | S_IWUSR;
 	return 0;
@@ -828,7 +839,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 
 
 static int
-pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid)
+pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid)
 {
 	u16 ppid = (sid << 8) | (addr >> 8);
 	u16 apid_valid;
@@ -846,7 +857,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 static int
 pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
-	u8 apid;
+	u16 apid;
 	int rc;
 
 	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
@@ -865,7 +876,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 static int
 pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
 {
-	u8 apid;
+	u16 apid;
 	int rc;
 
 	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
@@ -886,49 +897,55 @@ static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc)
 	return (opc << 27) | ((addr & 0xff) << 4) | (bc & 0x7);
 }
 
-static u32 pmic_arb_owner_acc_status_v1(u8 m, u8 n)
+static u32 pmic_arb_owner_acc_status_v1(u8 m, u16 n)
 {
 	return 0x20 * m + 0x4 * n;
 }
 
-static u32 pmic_arb_owner_acc_status_v2(u8 m, u8 n)
+static u32 pmic_arb_owner_acc_status_v2(u8 m, u16 n)
 {
 	return 0x100000 + 0x1000 * m + 0x4 * n;
 }
 
-static u32 pmic_arb_acc_enable_v1(u8 n)
+static u32 pmic_arb_owner_acc_status_v3(u8 m, u16 n)
+{
+	return 0x200000 + 0x1000 * m + 0x4 * n;
+}
+
+static u32 pmic_arb_acc_enable_v1(u16 n)
 {
 	return 0x200 + 0x4 * n;
 }
 
-static u32 pmic_arb_acc_enable_v2(u8 n)
+static u32 pmic_arb_acc_enable_v2(u16 n)
 {
 	return 0x1000 * n;
 }
 
-static u32 pmic_arb_irq_status_v1(u8 n)
+static u32 pmic_arb_irq_status_v1(u16 n)
 {
 	return 0x600 + 0x4 * n;
 }
 
-static u32 pmic_arb_irq_status_v2(u8 n)
+static u32 pmic_arb_irq_status_v2(u16 n)
 {
 	return 0x4 + 0x1000 * n;
 }
 
-static u32 pmic_arb_irq_clear_v1(u8 n)
+static u32 pmic_arb_irq_clear_v1(u16 n)
 {
 	return 0xA00 + 0x4 * n;
 }
 
-static u32 pmic_arb_irq_clear_v2(u8 n)
+static u32 pmic_arb_irq_clear_v2(u16 n)
 {
 	return 0x8 + 0x1000 * n;
 }
 
 static const struct pmic_arb_ver_ops pmic_arb_v1 = {
+	.ver_str		= "v1",
 	.ppid_to_apid		= pmic_arb_ppid_to_apid_v1,
-	.mode			= pmic_arb_mode_v1,
+	.mode			= pmic_arb_mode_v1_v3,
 	.non_data_cmd		= pmic_arb_non_data_cmd_v1,
 	.offset			= pmic_arb_offset_v1,
 	.fmt_cmd		= pmic_arb_fmt_cmd_v1,
@@ -939,6 +956,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v2 = {
+	.ver_str		= "v2",
 	.ppid_to_apid		= pmic_arb_ppid_to_apid_v2,
 	.mode			= pmic_arb_mode_v2,
 	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
@@ -950,6 +968,19 @@ static u32 pmic_arb_irq_clear_v2(u8 n)
 	.irq_clear		= pmic_arb_irq_clear_v2,
 };
 
+static const struct pmic_arb_ver_ops pmic_arb_v3 = {
+	.ver_str		= "v3",
+	.ppid_to_apid		= pmic_arb_ppid_to_apid_v2,
+	.mode			= pmic_arb_mode_v1_v3,
+	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
+	.offset			= pmic_arb_offset_v2,
+	.fmt_cmd		= pmic_arb_fmt_cmd_v2,
+	.owner_acc_status	= pmic_arb_owner_acc_status_v3,
+	.acc_enable		= pmic_arb_acc_enable_v2,
+	.irq_status		= pmic_arb_irq_status_v2,
+	.irq_clear		= pmic_arb_irq_clear_v2,
+};
+
 static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
 	.map	= qpnpint_irq_domain_map,
 	.xlate	= qpnpint_irq_domain_dt_translate,
@@ -963,7 +994,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	void __iomem *core;
 	u32 channel, ee, hw_ver;
 	int err;
-	bool is_v1;
 
 	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
 	if (!ctrl)
@@ -987,21 +1017,21 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	}
 
 	hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
-	is_v1  = (hw_ver < PMIC_ARB_VERSION_V2_MIN);
-
-	dev_info(&ctrl->dev, "PMIC Arb Version-%d (0x%x)\n", (is_v1 ? 1 : 2),
-		hw_ver);
 
-	if (is_v1) {
+	if (hw_ver < PMIC_ARB_VERSION_V2_MIN) {
 		pa->ver_ops = &pmic_arb_v1;
 		pa->wr_base = core;
 		pa->rd_base = core;
 	} else {
 		pa->core = core;
-		pa->ver_ops = &pmic_arb_v2;
+
+		if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
+			pa->ver_ops = &pmic_arb_v2;
+		else
+			pa->ver_ops = &pmic_arb_v3;
 
 		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
-		pa->max_periph =  (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+		pa->max_periph = (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
 
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
@@ -1029,6 +1059,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		}
 	}
 
+	dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
+		 pa->ver_ops->ver_str, hw_ver);
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
 	pa->intr = devm_ioremap_resource(&ctrl->dev, res);
 	if (IS_ERR(pa->intr)) {
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#39 lore raw

Re: [PATCH V1 10/15] spmi: pmic_arb: add support for PMIC bus arbiter v3

Quoted 6 lines · Kiran Gunda

/* PMIC Arbiter channel registers offsets */

drivers/spmi/spmi-pmic-arb.c +0 -0
@@ -96,6 +97,17 @@ enum pmic_arb_cmd_op_code {
 /* interrupt enable bit */
 #define SPMI_PIC_ACC_ENABLE_BIT		BIT(0)
 

drivers/spmi/spmi-pmic-arb.c enum pmic_arb_cmd_op_code { · line 109

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+#define HWIRQ(slave_id, periph_id, irq_id, apid) \
+	((((slave_id) & 0xF)   << 28) | \
+	(((periph_id) & 0xFF)  << 20) | \
+	(((irq_id)    & 0x7)   << 16) | \
+	(((apid)      & 0x1FF) << 0))
+
+#define HWIRQ_SID(hwirq)  (((hwirq) >> 28) & 0xF)
+#define HWIRQ_PER(hwirq)  (((hwirq) >> 20) & 0xFF)
+#define HWIRQ_IRQ(hwirq)  (((hwirq) >> 16) & 0x7)
+#define HWIRQ_APID(hwirq) (((hwirq) >> 0)  & 0x1FF)

How about lowercase and hwirq_to_*() macros? Then it's more function like style. And spec_to_hwirq() or something?

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb { · line 168

Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +4 -1
+
 struct pmic_arb_ver_ops;
 
 struct apid_data {
@@ -151,7 +163,9 @@ struct spmi_pmic_arb {
 /**
  * pmic_arb_ver: version dependent functionality.
  *
- * @mode:	access rights to specified pmic peripheral.
+ * @ver_str:		version string.
+ * @ppid_to_apid:	finds the apid for a given ppid.
+ * @mode:		access rights to specified pmic peripheral.

mode didn't need to change tabbing. Not sure why it's appearing in the diff.

Quoted 19 lines
drivers/spmi/spmi-pmic-arb.c +4 -4
  * @non_data_cmd:	on v1 issues an spmi non-data command.
  *			on v2 no HW support, returns -EOPNOTSUPP.
  * @offset:		on v1 offset of per-ee channel.
@@ -177,10 +192,10 @@ struct pmic_arb_ver_ops {
 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
 	/* Interrupts controller functionality (offset of PIC registers) */
-	u32 (*owner_acc_status)(u8 m, u8 n);
-	u32 (*acc_enable)(u8 n);
-	u32 (*irq_status)(u8 n);
-	u32 (*irq_clear)(u8 n);
+	u32 (*owner_acc_status)(u8 m, u16 n);
+	u32 (*acc_enable)(u16 n);
+	u32 (*irq_status)(u16 n);
+	u32 (*irq_clear)(u16 n);
 };
 
 static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct irq_domain *d, · line 790

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -776,7 +787,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 }
 
 static int
-pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
+pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)

Nice to know that the mode became useless in v3 and beyond! Sigh.

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1019

Quoted 8 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 {
 	*mode = S_IRUSR | S_IWUSR;
 	return 0;
@@ -987,21 +1017,21 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 
 		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
-		pa->max_periph =  (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+		pa->max_periph = (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;

This looks unrelated?

Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#40 lore raw

Re: [PATCH V1 10/15] spmi: pmic_arb: add support for PMIC bus arbiter v3

Quoted 7 lines · Stephen Boyd
Quoted 6 lines · Kiran Gunda

/* PMIC Arbiter channel registers offsets */

drivers/spmi/spmi-pmic-arb.c +0 -0
@@ -96,6 +97,17 @@ enum pmic_arb_cmd_op_code {
 /* interrupt enable bit */
 #define SPMI_PIC_ACC_ENABLE_BIT		BIT(0)
 
Quoted 14 lines

drivers/spmi/spmi-pmic-arb.c enum pmic_arb_cmd_op_code { · line 109

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+#define HWIRQ(slave_id, periph_id, irq_id, apid) \
+	((((slave_id) & 0xF)   << 28) | \
+	(((periph_id) & 0xFF)  << 20) | \
+	(((irq_id)    & 0x7)   << 16) | \
+	(((apid)      & 0x1FF) << 0))
+
+#define HWIRQ_SID(hwirq)  (((hwirq) >> 28) & 0xF)
+#define HWIRQ_PER(hwirq)  (((hwirq) >> 20) & 0xFF)
+#define HWIRQ_IRQ(hwirq)  (((hwirq) >> 16) & 0x7)
+#define HWIRQ_APID(hwirq) (((hwirq) >> 0)  & 0x1FF)

How about lowercase and hwirq_to_*() macros? Then it's more function like style. And spec_to_hwirq() or something?

Sure. Will change it in the follow up patch.

Quoted 16 lines

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb { · line 168

Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +4 -1
+
 struct pmic_arb_ver_ops;
 
 struct apid_data {
@@ -151,7 +163,9 @@ struct spmi_pmic_arb {
 /**
  * pmic_arb_ver: version dependent functionality.
  *
- * @mode:	access rights to specified pmic peripheral.
+ * @ver_str:		version string.
+ * @ppid_to_apid:	finds the apid for a given ppid.
+ * @mode:		access rights to specified pmic peripheral.

mode didn't need to change tabbing. Not sure why it's appearing in the diff.

When adding the new field description added extra tab for mode for alignment. That's why it is showing up.

Quoted 36 lines
Quoted 19 lines
drivers/spmi/spmi-pmic-arb.c +4 -4
  * @non_data_cmd:	on v1 issues an spmi non-data command.
  *			on v2 no HW support, returns -EOPNOTSUPP.
  * @offset:		on v1 offset of per-ee channel.
@@ -177,10 +192,10 @@ struct pmic_arb_ver_ops {
 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
 	/* Interrupts controller functionality (offset of PIC registers) */
-	u32 (*owner_acc_status)(u8 m, u8 n);
-	u32 (*acc_enable)(u8 n);
-	u32 (*irq_status)(u8 n);
-	u32 (*irq_clear)(u8 n);
+	u32 (*owner_acc_status)(u8 m, u16 n);
+	u32 (*acc_enable)(u16 n);
+	u32 (*irq_status)(u16 n);
+	u32 (*irq_clear)(u16 n);
 };
 
 static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_map(struct · line 793

Quoted 8 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -776,7 +787,7 @@ static int qpnpint_irq_domain_map(struct 
 irq_domain *d,
 }
 
 static int
-pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t 
 *mode)
+pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, 
 mode_t *mode)

Nice to know that the mode became useless in v3 and beyond! Sigh.

Quoted 6 lines

{

drivers/spmi/spmi-pmic-arb.c +0 -0
 	*mode = S_IRUSR | S_IWUSR;
 	return 0;
@@ -987,21 +1017,21 @@ static int spmi_pmic_arb_probe(struct 
 platform_device *pdev)
 
Quoted 6 lines

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1034

Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
 		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
-		pa->max_periph =  (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+		pa->max_periph = (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;

This looks unrelated?

Yes. Just removed the extra space after '='.

Quoted 3 lines
Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
#41 lore raw

PATCH 11/15 spmi: spmi-pmic-arb: enable the SPMI interrupt as a wakeup source

In reply to Kiran Gunda

Currently the SPMI interrupt will not wake the device. Enable this interrupt as a wakeup source.

---
 drivers/spmi/spmi-pmic-arb.c | 1 +
 1 file changed, 1 insertion(+)
drivers/spmi/spmi-pmic-arb.c +1 -0
index 0deac33..2afe359 100644
@@ -1140,6 +1140,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	}
 
 	irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa);
+	enable_irq_wake(pa->irq);
 
 	err = spmi_controller_add(ctrl);
 	if (err)
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#42 lore raw

Re: [PATCH V1 11/15] spmi: spmi-pmic-arb: enable the SPMI interrupt as a wakeup source

Quoted 14 lines · Kiran Gunda

Currently the SPMI interrupt will not wake the device. Enable this interrupt as a wakeup source.

---
 drivers/spmi/spmi-pmic-arb.c | 1 +
 1 file changed, 1 insertion(+)
drivers/spmi/spmi-pmic-arb.c +0 -0
index 0deac33..2afe359 100644

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1143

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
@@ -1140,6 +1140,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	}
 
 	irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa);
+	enable_irq_wake(pa->irq);

Why don't we do this through an irq_set_wake callback in the irqchip? That way, we don't mark this irq as wakeup if any child irqs aren't marked as wakeup.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#43 lore raw

Re: [PATCH V1 11/15] spmi: spmi-pmic-arb: enable the SPMI interrupt as a wakeup source

Quoted 18 lines · Stephen Boyd
Quoted 17 lines · Kiran Gunda

Currently the SPMI interrupt will not wake the device. Enable this interrupt as a wakeup source.

---
 drivers/spmi/spmi-pmic-arb.c | 1 +
 1 file changed, 1 insertion(+)
drivers/spmi/spmi-pmic-arb.c +0 -0
index 0deac33..2afe359 100644
@@ -1140,6 +1140,7 @@ static int spmi_pmic_arb_probe(struct 
 platform_device *pdev)
 	}
 
Quoted 6 lines

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1143

Quoted 2 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
 	irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa);
+	enable_irq_wake(pa->irq);

Why don't we do this through an irq_set_wake callback in the irqchip? That way, we don't mark this irq as wakeup if any child irqs aren't marked as wakeup.

Yes. This looks cleaner. Will change it in the subsequent patch.

#44 lore raw

PATCH 12/15 spmi-pmic-arb: fix a possible null pointer dereference

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

If "core" memory resource is not specified, the driver could end up dereferencing a null pointer.

Fix this by returning -EINVAL when core resource is missing.

---
 drivers/spmi/spmi-pmic-arb.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/spmi/spmi-pmic-arb.c +6 -0
index 2afe359..412481d 100644
@@ -1003,6 +1003,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	pa->spmic = ctrl;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+	if (!res) {
+		dev_err(&pdev->dev, "core resource not specified\n");
+		err = -EINVAL;
+		goto err_put_ctrl;
+	}
+
 	pa->core_size = resource_size(res);
 	if (pa->core_size <= 0x800) {
 		dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing Probe\n");
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#45 lore raw

Re: [PATCH V1 12/15] spmi-pmic-arb: fix a possible null pointer dereference

Quoted 7 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +0 -0
index 2afe359..412481d 100644
@@ -1003,6 +1003,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	pa->spmic = ctrl;
 

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1014

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+	if (!res) {
+		dev_err(&pdev->dev, "core resource not specified\n");
+		err = -EINVAL;
+		goto err_put_ctrl;
+	}
+
 	pa->core_size = resource_size(res);
 	if (pa->core_size <= 0x800) {
 		dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing Probe\n");

I would prefer this patch instead, so that we can piggyback on the error checking of the devm_ioremap_resource() code. Also, add a Fixes: tag please so we can backport it as needed.

drivers/spmi/spmi-pmic-arb.c +1 -1
index 5ec3a595dc7d..0cedbda60707 100644
@@ -878,12 +878,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	pa->spmic = ctrl;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
-	pa->core_size = resource_size(res);
 	core = devm_ioremap_resource(&ctrl->dev, res);
 	if (IS_ERR(core)) {
 		err = PTR_ERR(core);
 		goto err_put_ctrl;
 	}
+	pa->core_size = resource_size(res);
 
 	hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
 	is_v1  = (hw_ver < PMIC_ARB_VERSION_V2_MIN);
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#46 lore raw

Re: [PATCH V1 12/15] spmi-pmic-arb: fix a possible null pointer dereference

Quoted 9 lines · Stephen Boyd
Quoted 8 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +0 -0
index 2afe359..412481d 100644
@@ -1003,6 +1003,12 @@ static int spmi_pmic_arb_probe(struct 
 platform_device *pdev)
 	pa->spmic = ctrl;
 
Quoted 16 lines
Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+	if (!res) {
+		dev_err(&pdev->dev, "core resource not specified\n");
+		err = -EINVAL;
+		goto err_put_ctrl;
+	}
+
 	pa->core_size = resource_size(res);
 	if (pa->core_size <= 0x800) {

dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing
Probe\n");

I would prefer this patch instead, so that we can piggyback on the error checking of the devm_ioremap_resource() code. Also, add a Fixes: tag please so we can backport it as needed.

Sure. We will modify as per your suggestion in the next patch.

Quoted 20 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
index 5ec3a595dc7d..0cedbda60707 100644
@@ -878,12 +878,12 @@ static int spmi_pmic_arb_probe(struct
 platform_device *pdev)
 	pa->spmic = ctrl;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
-	pa->core_size = resource_size(res);
 	core = devm_ioremap_resource(&ctrl->dev, res);
 	if (IS_ERR(core)) {
 		err = PTR_ERR(core);
 		goto err_put_ctrl;
 	}
+	pa->core_size = resource_size(res);
 
 	hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);

is_v1 = (hw_ver < PMIC_ARB_VERSION_V2_MIN);

#47 lore raw

PATCH 13/15 spmi: pmic-arb: add support for HW version 5

In reply to Kiran Gunda

From: David Collins <[email protected]>

Add support for version 5 of the SPMI PMIC arbiter. It utilizes different offsets for registers than those found on version 3. Also, the procedure to determine if writing and IRQ access is allowed for a given PPID changes for version 5.

---
 drivers/spmi/spmi-pmic-arb.c | 248 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 224 insertions(+), 24 deletions(-)
drivers/spmi/spmi-pmic-arb.c +224 -24
index 412481d..b755c24 100644
@@ -29,6 +29,7 @@
 #define PMIC_ARB_VERSION		0x0000
 #define PMIC_ARB_VERSION_V2_MIN		0x20010000
 #define PMIC_ARB_VERSION_V3_MIN		0x30000000
+#define PMIC_ARB_VERSION_V5_MIN		0x50000000
 #define PMIC_ARB_INT_EN			0x0004
 
 /* PMIC Arbiter channel registers offsets */
@@ -39,7 +40,6 @@
 #define PMIC_ARB_WDATA1			0x14
 #define PMIC_ARB_RDATA0			0x18
 #define PMIC_ARB_RDATA1			0x1C
-#define PMIC_ARB_REG_CHNL(N)		(0x800 + 0x4 * (N))
 
 /* Mapping Table */
 #define SPMI_MAPPING_TABLE_REG(N)	(0x0B00 + (4 * (N)))
@@ -52,6 +52,8 @@
 #define SPMI_MAPPING_TABLE_TREE_DEPTH	16	/* Maximum of 16-bits */
 #define PMIC_ARB_MAX_PPID		BIT(12) /* PPID is 12bit */
 #define PMIC_ARB_CHAN_VALID		BIT(15)
+#define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg)	((reg) & BIT(24))
+#define INVALID_EE			(-1)
 
 /* Ownership Table */
 #define SPMI_OWNERSHIP_TABLE_REG(N)	(0x0700 + (4 * (N)))
@@ -86,6 +88,15 @@ enum pmic_arb_cmd_op_code {
 	PMIC_ARB_OP_ZERO_WRITE = 16,
 };
 
+/*
+ * PMIC arbiter version 5 uses different register offsets for read/write vs
+ * observer channels.
+ */
+enum pmic_arb_channel {
+	PMIC_ARB_CHANNEL_RW,
+	PMIC_ARB_CHANNEL_OBS,
+};
+
 /* Maximum number of support PMIC peripherals */
 #define PMIC_ARB_MAX_PERIPHS		512
 #define PMIC_ARB_TIMEOUT_US		100
@@ -112,7 +123,8 @@ enum pmic_arb_cmd_op_code {
 
 struct apid_data {
 	u16		ppid;
-	u8		owner;
+	u8		write_owner;
+	u8		irq_owner;
 };
 
 /**
@@ -121,6 +133,7 @@ struct apid_data {
  * @rd_base:		on v1 "core", on v2 "observer" register base off DT.
  * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
  * @intr:		address of the SPMI interrupt control registers.
+ * @acc_status:		address of SPMI ACC interrupt status registers.
  * @cnfg:		address of the PMIC Arbiter configuration registers.
  * @lock:		lock to synchronize accesses.
  * @channel:		execution environment channel to use for accesses.
@@ -140,6 +153,7 @@ struct spmi_pmic_arb {
 	void __iomem		*rd_base;
 	void __iomem		*wr_base;
 	void __iomem		*intr;
+	void __iomem		*acc_status;
 	void __iomem		*cnfg;
 	void __iomem		*core;
 	resource_size_t		core_size;
@@ -179,6 +193,7 @@ struct spmi_pmic_arb {
  *			on v2 offset of SPMI_PIC_IRQ_STATUSn.
  * @irq_clear:		on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_CLEARn
  *			on v2 offset of SPMI_PIC_IRQ_CLEARn.
+ * @channel_map_offset:	offset of PMIC_ARB_REG_CHNLn
  */
 struct pmic_arb_ver_ops {
 	const char *ver_str;
@@ -188,7 +203,7 @@ struct pmic_arb_ver_ops {
 			mode_t *mode);
 	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
 	int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr,
-		      u32 *offset);
+			enum pmic_arb_channel ch_type, u32 *offset);
 	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
 	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
 	/* Interrupts controller functionality (offset of PIC registers) */
@@ -196,6 +211,7 @@ struct pmic_arb_ver_ops {
 	u32 (*acc_enable)(u16 n);
 	u32 (*irq_status)(u16 n);
 	u32 (*irq_clear)(u16 n);
+	u32 (*channel_map_offset)(u16 n);
 };
 
 static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,
@@ -239,7 +255,8 @@ static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, u8 bc)
 }
 
 static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
-				  void __iomem *base, u8 sid, u16 addr)
+				  void __iomem *base, u8 sid, u16 addr,
+				  enum pmic_arb_channel ch_type)
 {
 	struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
 	u32 status = 0;
@@ -247,7 +264,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 	u32 offset;
 	int rc;
 
-	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, ch_type, &offset);
 	if (rc)
 		return rc;
 
@@ -298,7 +315,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 	int rc;
 	u32 offset;
 
-	rc = pa->ver_ops->offset(pa, sid, 0, &offset);
+	rc = pa->ver_ops->offset(pa, sid, 0, PMIC_ARB_CHANNEL_RW, &offset);
 	if (rc)
 		return rc;
 
@@ -306,7 +323,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
 
 	raw_spin_lock_irqsave(&pa->lock, flags);
 	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, 0);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, 0,
+				    PMIC_ARB_CHANNEL_RW);
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
 	return rc;
@@ -343,7 +361,7 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, PMIC_ARB_CHANNEL_OBS, &offset);
 	if (rc)
 		return rc;
 
@@ -379,7 +397,8 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 
 	raw_spin_lock_irqsave(&pa->lock, flags);
 	pmic_arb_set_rd_cmd(pa, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pa->rd_base, sid, addr);
+	rc = pmic_arb_wait_for_done(ctrl, pa->rd_base, sid, addr,
+				    PMIC_ARB_CHANNEL_OBS);
 	if (rc)
 		goto done;
 
@@ -405,7 +424,7 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 	u32 offset;
 	mode_t mode;
 
-	rc = pa->ver_ops->offset(pa, sid, addr, &offset);
+	rc = pa->ver_ops->offset(pa, sid, addr, PMIC_ARB_CHANNEL_RW, &offset);
 	if (rc)
 		return rc;
 
@@ -449,7 +468,8 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 
 	/* Start the transaction */
 	pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd);
-	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, addr);
+	rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, addr,
+				    PMIC_ARB_CHANNEL_RW);
 	raw_spin_unlock_irqrestore(&pa->lock, flags);
 
 	return rc;
@@ -547,7 +567,6 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 {
 	struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
-	void __iomem *intr = pa->intr;
 	int first = pa->min_apid >> 5;
 	int last = pa->max_apid >> 5;
 	u32 status, enable;
@@ -556,13 +575,13 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
 	chained_irq_enter(chip, desc);
 
 	for (i = first; i <= last; ++i) {
-		status = readl_relaxed(intr +
+		status = readl_relaxed(pa->acc_status +
 				      pa->ver_ops->owner_acc_status(pa->ee, i));
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
 			apid = id + i * 32;
-			enable = readl_relaxed(intr +
+			enable = readl_relaxed(pa->intr +
 					pa->ver_ops->acc_enable(apid));
 			if (enable & SPMI_PIC_ACC_ENABLE_BIT)
 				periph_interrupt(pa, apid);
@@ -705,11 +724,18 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 			(intspec[1] << 8), &apid);
 	if (rc < 0) {
 		dev_err(&pa->spmic->dev,
-		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n",
+		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %u rc = %d\n",
 		intspec[0], intspec[1], intspec[2], rc);
 		return rc;
 	}
 
+	if (pa->apid_data[apid].irq_owner != pa->ee) {
+		dev_err(&pa->spmic->dev, "failed to xlate sid = 0x%x, periph = 0x%x, irq = %u: ee=%u but owner=%u\n",
+			intspec[0], intspec[1], intspec[2], pa->ee,
+			pa->apid_data[apid].irq_owner);
+		return -ENODEV;
+	}
+
 	/* Keep track of {max,min}_apid for bounding search during interrupt */
 	if (apid > pa->max_apid)
 		pa->max_apid = apid;
@@ -795,7 +821,8 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
 
 /* v1 offset per ee */
 static int
-pmic_arb_offset_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
+pmic_arb_offset_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+		   enum pmic_arb_channel ch_type, u32 *offset)
 {
 	*offset = 0x800 + 0x80 * pa->channel;
 	return 0;
@@ -814,9 +841,11 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
 		regval = readl_relaxed(pa->cnfg +
 				      SPMI_OWNERSHIP_TABLE_REG(apid));
-		pa->apid_data[apid].owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+		pa->apid_data[apid].irq_owner
+			= SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+		pa->apid_data[apid].write_owner = pa->apid_data[apid].irq_owner;
 
-		offset = PMIC_ARB_REG_CHNL(apid);
+		offset = pa->ver_ops->channel_map_offset(apid);
 		if (offset >= pa->core_size)
 			break;
 
@@ -854,27 +883,110 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	return 0;
 }
 
+static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pa)
+{
+	u32 regval, offset;
+	u16 apid, prev_apid, ppid;
+	bool valid, is_irq_owner;
+
+	/*
+	 * PMIC_ARB_REG_CHNL is a table in HW mapping APID (channel) to PPID.
+	 * ppid_to_apid is an in-memory invert of that table.  In order to allow
+	 * multiple EE's to write to a single PPID in arbiter version 5, there
+	 * is more than one APID mapped to each PPID.  The owner field for each
+	 * of these mappings specifies the EE which is allowed to write to the
+	 * APID.  The owner of the last (highest) APID for a given PPID will
+	 * receive interrupts from the PPID.
+	 */
+	for (apid = 0; apid < pa->max_periph; apid++) {
+		offset = pa->ver_ops->channel_map_offset(apid);
+		if (offset >= pa->core_size)
+			break;
+
+		regval = readl_relaxed(pa->core + offset);
+		if (!regval)
+			continue;
+		ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
+		is_irq_owner = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
+
+		regval = readl_relaxed(pa->cnfg +
+				      SPMI_OWNERSHIP_TABLE_REG(apid));
+		pa->apid_data[apid].write_owner
+			= SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+
+		pa->apid_data[apid].irq_owner = is_irq_owner ?
+			pa->apid_data[apid].write_owner : INVALID_EE;
+
+		valid = pa->ppid_to_apid[ppid] & PMIC_ARB_CHAN_VALID;
+		prev_apid = pa->ppid_to_apid[ppid] & ~PMIC_ARB_CHAN_VALID;
+
+		if (valid && is_irq_owner &&
+		    pa->apid_data[prev_apid].write_owner == pa->ee) {
+			/*
+			 * Duplicate PPID mapping after the one for this EE;
+			 * override the irq owner
+			 */
+			pa->apid_data[prev_apid].irq_owner
+				= pa->apid_data[apid].irq_owner;
+		} else if (!valid || is_irq_owner) {
+			/* First PPID mapping or duplicate for another EE */
+			pa->ppid_to_apid[ppid] = apid | PMIC_ARB_CHAN_VALID;
+		}
+
+		pa->apid_data[apid].ppid = ppid;
+		pa->last_apid = apid;
+	}
+
+	/* Dump the mapping table for debug purposes. */
+	dev_dbg(&pa->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
+	for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) {
+		valid = pa->ppid_to_apid[ppid] & PMIC_ARB_CHAN_VALID;
+		apid = pa->ppid_to_apid[ppid] & ~PMIC_ARB_CHAN_VALID;
+
+		if (valid)
+			dev_dbg(&pa->spmic->dev, "0x%03X %3u %2u %2u\n",
+				ppid, apid, pa->apid_data[apid].write_owner,
+				pa->apid_data[apid].irq_owner);
+	}
+
+	return 0;
+}
+
+static int
+pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid)
+{
+	u16 ppid = (sid << 8) | (addr >> 8);
+
+	if (!(pa->ppid_to_apid[ppid] & PMIC_ARB_CHAN_VALID))
+		return -ENODEV;
+
+	*apid = pa->ppid_to_apid[ppid] & ~PMIC_ARB_CHAN_VALID;
+
+	return 0;
+}
+
 static int
 pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
 {
 	u16 apid;
 	int rc;
 
-	rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
+	rc = pa->ver_ops->ppid_to_apid(pa, sid, addr, &apid);
 	if (rc < 0)
 		return rc;
 
 	*mode = 0;
 	*mode |= S_IRUSR;
 
-	if (pa->ee == pa->apid_data[apid].owner)
+	if (pa->ee == pa->apid_data[apid].write_owner)
 		*mode |= S_IWUSR;
 	return 0;
 }
 
 /* v2 offset per ppid and per ee */
 static int
-pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset)
+pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+		   enum pmic_arb_channel ch_type, u32 *offset)
 {
 	u16 apid;
 	int rc;
@@ -887,6 +999,27 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	return 0;
 }
 
+/*
+ * v5 offset per ee and per apid for observer channels and per apid for
+ * read/write channels.
+ */
+static int
+pmic_arb_offset_v5(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+		   enum pmic_arb_channel ch_type, u32 *offset)
+{
+	u16 apid;
+	int rc;
+
+	rc = pmic_arb_ppid_to_apid_v5(pa, sid, addr, &apid);
+	if (rc < 0)
+		return rc;
+
+	*offset = (ch_type == PMIC_ARB_CHANNEL_OBS)
+			? 0x10000 * pa->ee + 0x80 * apid
+			: 0x10000 * apid;
+	return 0;
+}
+
 static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
 {
 	return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
@@ -912,6 +1045,11 @@ static u32 pmic_arb_owner_acc_status_v3(u8 m, u16 n)
 	return 0x200000 + 0x1000 * m + 0x4 * n;
 }
 
+static u32 pmic_arb_owner_acc_status_v5(u8 m, u16 n)
+{
+	return 0x10000 * m + 0x4 * n;
+}
+
 static u32 pmic_arb_acc_enable_v1(u16 n)
 {
 	return 0x200 + 0x4 * n;
@@ -922,6 +1060,11 @@ static u32 pmic_arb_acc_enable_v2(u16 n)
 	return 0x1000 * n;
 }
 
+static u32 pmic_arb_acc_enable_v5(u16 n)
+{
+	return 0x100 + 0x10000 * n;
+}
+
 static u32 pmic_arb_irq_status_v1(u16 n)
 {
 	return 0x600 + 0x4 * n;
@@ -932,6 +1075,11 @@ static u32 pmic_arb_irq_status_v2(u16 n)
 	return 0x4 + 0x1000 * n;
 }
 
+static u32 pmic_arb_irq_status_v5(u16 n)
+{
+	return 0x104 + 0x10000 * n;
+}
+
 static u32 pmic_arb_irq_clear_v1(u16 n)
 {
 	return 0xA00 + 0x4 * n;
@@ -942,6 +1090,21 @@ static u32 pmic_arb_irq_clear_v2(u16 n)
 	return 0x8 + 0x1000 * n;
 }
 
+static u32 pmic_arb_irq_clear_v5(u16 n)
+{
+	return 0x108 + 0x10000 * n;
+}
+
+static u32 pmic_arb_channel_map_offset_v2(u16 n)
+{
+	return 0x800 + 0x4 * n;
+}
+
+static u32 pmic_arb_channel_map_offset_v5(u16 n)
+{
+	return 0x900 + 0x4 * n;
+}
+
 static const struct pmic_arb_ver_ops pmic_arb_v1 = {
 	.ver_str		= "v1",
 	.ppid_to_apid		= pmic_arb_ppid_to_apid_v1,
@@ -953,6 +1116,7 @@ static u32 pmic_arb_irq_clear_v2(u16 n)
 	.acc_enable		= pmic_arb_acc_enable_v1,
 	.irq_status		= pmic_arb_irq_status_v1,
 	.irq_clear		= pmic_arb_irq_clear_v1,
+	.channel_map_offset	= pmic_arb_channel_map_offset_v2,
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v2 = {
@@ -966,6 +1130,7 @@ static u32 pmic_arb_irq_clear_v2(u16 n)
 	.acc_enable		= pmic_arb_acc_enable_v2,
 	.irq_status		= pmic_arb_irq_status_v2,
 	.irq_clear		= pmic_arb_irq_clear_v2,
+	.channel_map_offset	= pmic_arb_channel_map_offset_v2,
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v3 = {
@@ -979,6 +1144,21 @@ static u32 pmic_arb_irq_clear_v2(u16 n)
 	.acc_enable		= pmic_arb_acc_enable_v2,
 	.irq_status		= pmic_arb_irq_status_v2,
 	.irq_clear		= pmic_arb_irq_clear_v2,
+	.channel_map_offset	= pmic_arb_channel_map_offset_v2,
+};
+
+static const struct pmic_arb_ver_ops pmic_arb_v5 = {
+	.ver_str		= "v5",
+	.ppid_to_apid		= pmic_arb_ppid_to_apid_v5,
+	.mode			= pmic_arb_mode_v2,
+	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
+	.offset			= pmic_arb_offset_v5,
+	.fmt_cmd		= pmic_arb_fmt_cmd_v2,
+	.owner_acc_status	= pmic_arb_owner_acc_status_v5,
+	.acc_enable		= pmic_arb_acc_enable_v5,
+	.irq_status		= pmic_arb_irq_status_v5,
+	.irq_clear		= pmic_arb_irq_clear_v5,
+	.channel_map_offset	= pmic_arb_channel_map_offset_v5,
 };
 
 static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
@@ -1033,11 +1213,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 
 		if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
 			pa->ver_ops = &pmic_arb_v2;
-		else
+		else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
 			pa->ver_ops = &pmic_arb_v3;
+		else
+			pa->ver_ops = &pmic_arb_v5;
 
-		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
-		pa->max_periph = (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL0 */
+		pa->max_periph
+		     = (pa->core_size - pa->ver_ops->channel_map_offset(0)) / 4;
 
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
@@ -1074,6 +1257,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		err = PTR_ERR(pa->intr);
 		goto err_put_ctrl;
 	}
+	pa->acc_status = pa->intr;
+
+	/*
+	 * PMIC arbiter v5 groups the IRQ control registers in the same hardware
+	 * module as the read/write channels.
+	 */
+	if (hw_ver >= PMIC_ARB_VERSION_V5_MIN)
+		pa->intr = pa->wr_base;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
 	pa->cnfg = devm_ioremap_resource(&ctrl->dev, res);
@@ -1136,6 +1327,15 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	ctrl->read_cmd = pmic_arb_read_cmd;
 	ctrl->write_cmd = pmic_arb_write_cmd;
 
+	if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
+		err = pmic_arb_read_apid_map_v5(pa);
+		if (err) {
+			dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n",
+				err);
+			goto err_put_ctrl;
+		}
+	}
+
 	dev_dbg(&pdev->dev, "adding irq domain\n");
 	pa->domain = irq_domain_add_tree(pdev->dev.of_node,
 					 &pmic_arb_irq_domain_ops, pa);
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#48 lore raw

Re: [PATCH V1 13/15] spmi: pmic-arb: add support for HW version 5

drivers/spmi/spmi-pmic-arb.c enum pmic_arb_cmd_op_code { · line 127

Quoted 11 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +2 -1
index 412481d..b755c24 100644
@@ -112,7 +123,8 @@ enum pmic_arb_cmd_op_code {
 
 struct apid_data {
 	u16		ppid;
-	u8		owner;
+	u8		write_owner;
+	u8		irq_owner;

How about irq_ee and write_ee instead?

drivers/spmi/spmi-pmic-arb.c static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, · line 727

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 };
 
 /**

static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,

drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -705,11 +724,18 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 			(intspec[1] << 8), &apid);
 	if (rc < 0) {
 		dev_err(&pa->spmic->dev,
-		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n",
+		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %u rc = %d\n",

What is this change? Also, use %#x instead of 0x%x and the " should line up with the ( on the previous line.

Quoted 15 lines
drivers/spmi/spmi-pmic-arb.c +7 -0
 		intspec[0], intspec[1], intspec[2], rc);
 		return rc;
 	}
 
+	if (pa->apid_data[apid].irq_owner != pa->ee) {
+		dev_err(&pa->spmic->dev, "failed to xlate sid = 0x%x, periph = 0x%x, irq = %u: ee=%u but owner=%u\n",
+			intspec[0], intspec[1], intspec[2], pa->ee,
+			pa->apid_data[apid].irq_owner);
+		return -ENODEV;
+	}
+
 	/* Keep track of {max,min}_apid for bounding search during interrupt */
 	if (apid > pa->max_apid)
 		pa->max_apid = apid;

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 846

Quoted 7 lines
drivers/spmi/spmi-pmic-arb.c +3 -1
@@ -814,9 +841,11 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
 		regval = readl_relaxed(pa->cnfg +
 				      SPMI_OWNERSHIP_TABLE_REG(apid));
-		pa->apid_data[apid].owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+		pa->apid_data[apid].irq_owner
+			= SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+		pa->apid_data[apid].write_owner = pa->apid_data[apid].irq_owner;

Please use a local variable pointer *apid.

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
-		offset = PMIC_ARB_REG_CHNL(apid);
+		offset = pa->ver_ops->channel_map_offset(apid);
 		if (offset >= pa->core_size)
 			break;
 
@@ -854,27 +883,110 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	return 0;
 }
 

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 895

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pa)
+{
+	u32 regval, offset;
+	u16 apid, prev_apid, ppid;
+	bool valid, is_irq_owner;
+
+	/*
+	 * PMIC_ARB_REG_CHNL is a table in HW mapping APID (channel) to PPID.
+	 * ppid_to_apid is an in-memory invert of that table.  In order to allow
+	 * multiple EE's to write to a single PPID in arbiter version 5, there

Drop the apostrophe ^

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+	 * is more than one APID mapped to each PPID.  The owner field for each
+	 * of these mappings specifies the EE which is allowed to write to the
+	 * APID.  The owner of the last (highest) APID for a given PPID will
+	 * receive interrupts from the PPID.
+	 */
+	for (apid = 0; apid < pa->max_periph; apid++) {
+		offset = pa->ver_ops->channel_map_offset(apid);
+		if (offset >= pa->core_size)
+			break;
+

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 915

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+		regval = readl_relaxed(pa->core + offset);
+		if (!regval)
+			continue;
+		ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
+		is_irq_owner = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
+
+		regval = readl_relaxed(pa->cnfg +
+				      SPMI_OWNERSHIP_TABLE_REG(apid));
+		pa->apid_data[apid].write_owner
+			= SPMI_OWNERSHIP_PERIPH2OWNER(regval);

Please use a pointer like *apid and *prev where *apid is incremented during the for-loop. That way we have shorter lines of code:

		apid->write_owner = SPMI_OWNERSHIP_TABLE_REG(regval);

and

		if (valid && is_irq_owner && prev->write_owner == pa->ee) {

obviously the existing apid will need to be renamed to i, but that's ok because it's a counter.

Quoted 22 lines
drivers/spmi/spmi-pmic-arb.c +22 -0
+
+		pa->apid_data[apid].irq_owner = is_irq_owner ?
+			pa->apid_data[apid].write_owner : INVALID_EE;
+
+		valid = pa->ppid_to_apid[ppid] & PMIC_ARB_CHAN_VALID;
+		prev_apid = pa->ppid_to_apid[ppid] & ~PMIC_ARB_CHAN_VALID;
+
+		if (valid && is_irq_owner &&
+		    pa->apid_data[prev_apid].write_owner == pa->ee) {
+			/*
+			 * Duplicate PPID mapping after the one for this EE;
+			 * override the irq owner
+			 */
+			pa->apid_data[prev_apid].irq_owner
+				= pa->apid_data[apid].irq_owner;
+		} else if (!valid || is_irq_owner) {
+			/* First PPID mapping or duplicate for another EE */
+			pa->ppid_to_apid[ppid] = apid | PMIC_ARB_CHAN_VALID;
+		}
+
+		pa->apid_data[apid].ppid = ppid;
+		pa->last_apid = apid;

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 947

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+	}
+
+	/* Dump the mapping table for debug purposes. */
+	dev_dbg(&pa->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
+	for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) {
+		valid = pa->ppid_to_apid[ppid] & PMIC_ARB_CHAN_VALID;
+		apid = pa->ppid_to_apid[ppid] & ~PMIC_ARB_CHAN_VALID;
+
+		if (valid)
+			dev_dbg(&pa->spmic->dev, "0x%03X %3u %2u %2u\n",

Same %#x story here.

Quoted 20 lines
drivers/spmi/spmi-pmic-arb.c +15 -0
+				ppid, apid, pa->apid_data[apid].write_owner,
+				pa->apid_data[apid].irq_owner);
+	}
+
+	return 0;
+}
+
 
@@ -887,6 +999,27 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
 	return 0;
 }
 
+/*
+ * v5 offset per ee and per apid for observer channels and per apid for
+ * read/write channels.
+ */
+static int
+pmic_arb_offset_v5(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+		   enum pmic_arb_channel ch_type, u32 *offset)
+{

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 1019

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+	u16 apid;
+	int rc;
+
+	rc = pmic_arb_ppid_to_apid_v5(pa, sid, addr, &apid);
+	if (rc < 0)
+		return rc;
+
+	*offset = (ch_type == PMIC_ARB_CHANNEL_OBS)
+			? 0x10000 * pa->ee + 0x80 * apid
+			: 0x10000 * apid;

Please use a switch statement to handle the enum here. That way we can get compiler checking to make sure all enumerations are handled.

Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c +3 -1
+	return 0;
+}
+
 static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
 {
 	return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
@@ -1033,11 +1213,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 
 		if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
 			pa->ver_ops = &pmic_arb_v2;
-		else

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1223

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +6 -2
+		else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
 			pa->ver_ops = &pmic_arb_v3;
+		else
+			pa->ver_ops = &pmic_arb_v5;
 
-		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
-		pa->max_periph = (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL0 */
+		pa->max_periph
+		     = (pa->core_size - pa->ver_ops->channel_map_offset(0)) / 4;

This is really ugly. Please grow a local variable so we can keep things on one line.

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
@@ -1074,6 +1257,14 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		err = PTR_ERR(pa->intr);

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1267

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +8 -0
 		goto err_put_ctrl;
 	}
+	pa->acc_status = pa->intr;
+
+	/*
+	 * PMIC arbiter v5 groups the IRQ control registers in the same hardware
+	 * module as the read/write channels.
+	 */
+	if (hw_ver >= PMIC_ARB_VERSION_V5_MIN)
+		pa->intr = pa->wr_base;

There's some weird things going on here. How about we make the version ops return an __iomem pointer to the address instead of an offset? That way we don't need to care what pa->intr is or add pa->acc_status? That could be a patch early in the series that adjusts the ops to return an iomem pointer, and perhaps also update the 'n' variable to be 16 instead of 8 bits. We can also express errors through iomem pointers with IS_ERR() checks, so it nicely removes the need to retrieve offsets through references sometimes too.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#49 lore raw

Re: [PATCH V1 13/15] spmi: pmic-arb: add support for HW version 5

Quoted 7 lines · Stephen Boyd
Quoted 6 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +0 -0
index 412481d..b755c24 100644
@@ -112,7 +123,8 @@ enum pmic_arb_cmd_op_code {
 
Quoted 8 lines

drivers/spmi/spmi-pmic-arb.c enum pmic_arb_cmd_op_code { · line 127

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +2 -1
 struct apid_data {
 	u16		ppid;
-	u8		owner;
+	u8		write_owner;
+	u8		irq_owner;

How about irq_ee and write_ee instead?

Sure. will change it in the subsequent patch.

Quoted 15 lines

drivers/spmi/spmi-pmic-arb.c static int · line 728

Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c +0 -0
 };
 
 /**

static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa,

drivers/spmi/spmi-pmic-arb.c +1 -1
@@ -705,11 +724,18 @@ static int 
 qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 			(intspec[1] << 8), &apid);
 	if (rc < 0) {
 		dev_err(&pa->spmic->dev,
-		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n",
+		"failed to xlate sid = 0x%x, periph = 0x%x, irq = %u rc = %d\n",

What is this change? Also, use %#x instead of 0x%x and the " should line up with the ( on the previous line.

Sure. will change it in the subsequent patch.

Quoted 19 lines
Quoted 19 lines
drivers/spmi/spmi-pmic-arb.c +7 -0
 		intspec[0], intspec[1], intspec[2], rc);
 		return rc;
 	}
 
+	if (pa->apid_data[apid].irq_owner != pa->ee) {
+		dev_err(&pa->spmic->dev, "failed to xlate sid = 0x%x, periph = 
 0x%x, irq = %u: ee=%u but owner=%u\n",
+			intspec[0], intspec[1], intspec[2], pa->ee,
+			pa->apid_data[apid].irq_owner);
+		return -ENODEV;
+	}
+
 	/* Keep track of {max,min}_apid for bounding search during interrupt 

*/

drivers/spmi/spmi-pmic-arb.c +0 -0
 	if (apid > pa->max_apid)
 		pa->max_apid = apid;
@@ -814,9 +841,11 @@ static u16 pmic_arb_find_apid(struct 
 spmi_pmic_arb *pa, u16 ppid)
 	for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 846

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +3 -1
 		regval = readl_relaxed(pa->cnfg +
 				      SPMI_OWNERSHIP_TABLE_REG(apid));
-		pa->apid_data[apid].owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+		pa->apid_data[apid].irq_owner
+			= SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+		pa->apid_data[apid].write_owner = pa->apid_data[apid].irq_owner;

Please use a local variable pointer *apid.

Sure. will change it in the subsequent patch.

Quoted 11 lines
Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c +1 -1
-		offset = PMIC_ARB_REG_CHNL(apid);
+		offset = pa->ver_ops->channel_map_offset(apid);
 		if (offset >= pa->core_size)
 			break;
 
@@ -854,27 +883,110 @@ static u16 pmic_arb_find_apid(struct 
 spmi_pmic_arb *pa, u16 ppid)
 	return 0;
 }
 
Quoted 16 lines
Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +8 -0
+static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pa)
+{
+	u32 regval, offset;
+	u16 apid, prev_apid, ppid;
+	bool valid, is_irq_owner;
+
+	/*
+	 * PMIC_ARB_REG_CHNL is a table in HW mapping APID (channel) to 

PPID.

drivers/spmi/spmi-pmic-arb.c +1 -0
+	 * ppid_to_apid is an in-memory invert of that table.  In order to 

allow

drivers/spmi/spmi-pmic-arb.c +1 -0
+	 * multiple EE's to write to a single PPID in arbiter version 5, 
Quoted 1 line

there

Drop the apostrophe ^

Ok. will change it in the subsequent patch.

Quoted 27 lines
Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +1 -0
+	 * is more than one APID mapped to each PPID.  The owner field for 

each

drivers/spmi/spmi-pmic-arb.c +1 -0
+	 * of these mappings specifies the EE which is allowed to write to 

the

drivers/spmi/spmi-pmic-arb.c +8 -0
+	 * APID.  The owner of the last (highest) APID for a given PPID will
+	 * receive interrupts from the PPID.
+	 */
+	for (apid = 0; apid < pa->max_periph; apid++) {
+		offset = pa->ver_ops->channel_map_offset(apid);
+		if (offset >= pa->core_size)
+			break;
+

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 915

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+		regval = readl_relaxed(pa->core + offset);
+		if (!regval)
+			continue;
+		ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
+		is_irq_owner = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
+
+		regval = readl_relaxed(pa->cnfg +
+				      SPMI_OWNERSHIP_TABLE_REG(apid));
+		pa->apid_data[apid].write_owner
+			= SPMI_OWNERSHIP_PERIPH2OWNER(regval);

Please use a pointer like *apid and *prev where *apid is incremented during the for-loop. That way we have shorter lines of code:

Quoted 9 lines
		apid->write_owner = SPMI_OWNERSHIP_TABLE_REG(regval);

and

		if (valid && is_irq_owner && prev->write_owner == pa->ee) {

obviously the existing apid will need to be renamed to i, but that's ok because it's a counter.

Sure. will do it in the subsequent patch..

Quoted 26 lines
Quoted 26 lines
drivers/spmi/spmi-pmic-arb.c +26 -0
+
+		pa->apid_data[apid].irq_owner = is_irq_owner ?
+			pa->apid_data[apid].write_owner : INVALID_EE;
+
+		valid = pa->ppid_to_apid[ppid] & PMIC_ARB_CHAN_VALID;
+		prev_apid = pa->ppid_to_apid[ppid] & ~PMIC_ARB_CHAN_VALID;
+
+		if (valid && is_irq_owner &&
+		    pa->apid_data[prev_apid].write_owner == pa->ee) {
+			/*
+			 * Duplicate PPID mapping after the one for this EE;
+			 * override the irq owner
+			 */
+			pa->apid_data[prev_apid].irq_owner
+				= pa->apid_data[apid].irq_owner;
+		} else if (!valid || is_irq_owner) {
+			/* First PPID mapping or duplicate for another EE */
+			pa->ppid_to_apid[ppid] = apid | PMIC_ARB_CHAN_VALID;
+		}
+
+		pa->apid_data[apid].ppid = ppid;
+		pa->last_apid = apid;
+	}
+
+	/* Dump the mapping table for debug purposes. */
+	dev_dbg(&pa->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 947

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
+	for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) {
+		valid = pa->ppid_to_apid[ppid] & PMIC_ARB_CHAN_VALID;
+		apid = pa->ppid_to_apid[ppid] & ~PMIC_ARB_CHAN_VALID;
+
+		if (valid)
+			dev_dbg(&pa->spmic->dev, "0x%03X %3u %2u %2u\n",

Same %#x story here.

Sure. will change it in the subsequent patch.

Quoted 28 lines
Quoted 28 lines
drivers/spmi/spmi-pmic-arb.c +9 -0
+				ppid, apid, pa->apid_data[apid].write_owner,
+				pa->apid_data[apid].irq_owner);
+	}
+
+	return 0;
+}
+
@@ -887,6 +999,27 @@ static u16 pmic_arb_find_apid(struct 
 spmi_pmic_arb *pa, u16 ppid)
 	return 0;
 }
 
+/*
+ * v5 offset per ee and per apid for observer channels and per apid 

for
+ * read/write channels.
+ */

drivers/spmi/spmi-pmic-arb.c +10 -0
+static int
+pmic_arb_offset_v5(struct spmi_pmic_arb *pa, u8 sid, u16 addr,
+		   enum pmic_arb_channel ch_type, u32 *offset)
+{
+	u16 apid;
+	int rc;
+
+	rc = pmic_arb_ppid_to_apid_v5(pa, sid, addr, &apid);
+	if (rc < 0)
+		return rc;
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) · line 1019

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+
+	*offset = (ch_type == PMIC_ARB_CHANNEL_OBS)
+			? 0x10000 * pa->ee + 0x80 * apid
+			: 0x10000 * apid;

Please use a switch statement to handle the enum here. That way we can get compiler checking to make sure all enumerations are handled.

Sure. will change it in the subsequent patch.

Quoted 17 lines
Quoted 17 lines
drivers/spmi/spmi-pmic-arb.c +6 -1
+	return 0;
+}
+
 static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
 {
 	return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
@@ -1033,11 +1213,14 @@ static int spmi_pmic_arb_probe(struct 
 platform_device *pdev)
 
 		if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
 			pa->ver_ops = &pmic_arb_v2;
-		else
+		else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
 			pa->ver_ops = &pmic_arb_v3;
+		else
+			pa->ver_ops = &pmic_arb_v5;
 
Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1223

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c +3 -2
-		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */
-		pa->max_periph = (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4;
+		/* the apid to ppid table starts at PMIC_ARB_REG_CHNL0 */
+		pa->max_periph
+		     = (pa->core_size - pa->ver_ops->channel_map_offset(0)) / 4;

This is really ugly. Please grow a local variable so we can keep things on one line.

Ok. will change it in the subsequent patch.

Quoted 19 lines
Quoted 13 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "obsrvr");
@@ -1074,6 +1257,14 @@ static int spmi_pmic_arb_probe(struct 
 platform_device *pdev)
 		err = PTR_ERR(pa->intr);
 		goto err_put_ctrl;
 	}
+	pa->acc_status = pa->intr;
+
+	/*
+	 * PMIC arbiter v5 groups the IRQ control registers in the same 

hardware

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 1267

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+	 * module as the read/write channels.
+	 */
+	if (hw_ver >= PMIC_ARB_VERSION_V5_MIN)
+		pa->intr = pa->wr_base;

There's some weird things going on here. How about we make the

Quoted 8 lines

version ops return an __iomem pointer to the address instead of an offset? That way we don't need to care what pa->intr is or add pa->acc_status? That could be a patch early in the series that adjusts the ops to return an iomem pointer, and perhaps also update the 'n' variable to be 16 instead of 8 bits. We can also express errors through iomem pointers with IS_ERR() checks, so it nicely removes the need to retrieve offsets through references sometimes too.

Yes. This looks good. Will change it in the subsequent patch series.

#50 lore raw

PATCH 14/15 spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq

In reply to Kiran Gunda

From: Subbaraman Narayanamurthy <[email protected]>

Currently, cleanup_irq() is invoked when a peripheral's interrupt fires and there is no mapping present in the interrupt domain of spmi interrupt controller.

The cleanup_irq clears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable in cleanup_irq races with request_irq() in that it stomps over the enable issued by request_irq. Fix this by not writing to the pmic in cleanup_irq. The latched bit will be left set in the pmic, which will not send us more interrupts even if the enable bit stays enabled.

When a client wants to request an interrupt, use the activate callback on the irq_domain to clear latched bit. This ensures that the latched, if set due to the above changes in cleanup_irq or when the bootloader leaves it set, gets cleaned up, paving way for upcoming interrupts to trigger.

With this, there is a possibility of unwanted triggering of interrupt right after the latched bit is cleared - the interrupt may be left enabled too. To avoid that, clear the enable first followed by clearing the latched bit in the activate callback.

---
 drivers/spmi/spmi-pmic-arb.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)
drivers/spmi/spmi-pmic-arb.c +12 -15
index b755c24..767bd2c 100644
@@ -522,24 +522,9 @@ static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
 
 static void cleanup_irq(struct spmi_pmic_arb *pa, u16 apid, int id)
 {
-	u16 ppid = pa->apid_data[apid].ppid;
-	u8 sid = ppid >> 8;
-	u8 per = ppid & 0xFF;
 	u8 irq_mask = BIT(id);
 
 	writel_relaxed(irq_mask, pa->intr + pa->ver_ops->irq_clear(apid));
-
-	if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
-			(per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1))
-		dev_err_ratelimited(&pa->spmic->dev,
-				"failed to ack irq_mask = 0x%x for ppid = %x\n",
-				irq_mask, ppid);
-
-	if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
-			       (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1))
-		dev_err_ratelimited(&pa->spmic->dev,
-				"failed to ack irq_mask = 0x%x for ppid = %x\n",
-				irq_mask, ppid);
 }
 
 static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid)
@@ -698,6 +683,17 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
 			| IRQCHIP_SKIP_SET_WAKE,
 };
 
+static void qpnpint_irq_domain_activate(struct irq_domain *domain,
+					struct irq_data *d)
+{
+	u8 irq = HWIRQ_IRQ(d->hwirq);
+	u8 buf;
+
+	buf = BIT(irq);
+	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &buf, 1);
+	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 1);
+}
+
 static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
 					   struct device_node *controller,
 					   const u32 *intspec,
@@ -1164,6 +1160,7 @@ static u32 pmic_arb_channel_map_offset_v5(u16 n)
 static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
 	.map	= qpnpint_irq_domain_map,
 	.xlate	= qpnpint_irq_domain_dt_translate,
+	.activate	= qpnpint_irq_domain_activate,
 };
 
 static int spmi_pmic_arb_probe(struct platform_device *pdev)
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#51 lore raw

Re: [PATCH V1 14/15] spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq

url: https://github.com/0day-ci/linux/commits/Kiran-Gunda/spmi-pmic_arb-block-access-of-invalid-read-and-writes/20170531-034312 config: xtensa-allmodconfig (attached as .config) compiler…

Hi Subbaraman,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.12-rc3 next-20170530]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Kiran-Gunda/spmi-pmic_arb-block-access-of-invalid-read-and-writes/20170531-034312
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=xtensa

All error/warnings (new ones prefixed by >>):

>> drivers//spmi/spmi-pmic-arb.c:1163:2: error: unknown field 'activate' specified in initializer
     .activate = qpnpint_irq_domain_activate,
     ^
>> drivers//spmi/spmi-pmic-arb.c:1163:2: warning: excess elements in struct initializer

drivers//spmi/spmi-pmic-arb.c:1163:2: warning: (near initialization for 'pmic_arb_irq_domain_ops')

vim +/activate +1163 drivers//spmi/spmi-pmic-arb.c

1147 .ver_str = "v5",
1148 .ppid_to_apid = pmic_arb_ppid_to_apid_v5,
1149 .mode = pmic_arb_mode_v2,
1150 .non_data_cmd = pmic_arb_non_data_cmd_v2,
1151 .offset = pmic_arb_offset_v5,
1152 .fmt_cmd = pmic_arb_fmt_cmd_v2,
1153 .owner_acc_status = pmic_arb_owner_acc_status_v5,
1154 .acc_enable = pmic_arb_acc_enable_v5,
1155 .irq_status = pmic_arb_irq_status_v5,
1156 .irq_clear = pmic_arb_irq_clear_v5,
1157 .channel_map_offset = pmic_arb_channel_map_offset_v5,
1158 };
1159
1160 static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
1161 .map = qpnpint_irq_domain_map,
1162 .xlate = qpnpint_irq_domain_dt_translate,

> 1163		.activate	= qpnpint_irq_domain_activate,

1164 };
1165
1166 static int spmi_pmic_arb_probe(struct platform_device *pdev)
1167 {
1168 struct spmi_pmic_arb *pa;
1169 struct spmi_controller *ctrl;
1170 struct resource *res;
1171 void __iomem *core;

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#52 lore raw

Re: [PATCH V1 14/15] spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq

In reply to Kiran Gunda
Quoted 20 lines · Kiran Gunda

From: Subbaraman Narayanamurthy <[email protected]>

Currently, cleanup_irq() is invoked when a peripheral's interrupt fires and there is no mapping present in the interrupt domain of spmi interrupt controller.

The cleanup_irq clears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable in cleanup_irq races with request_irq() in that it stomps over the enable issued by request_irq. Fix this by not writing to the pmic in cleanup_irq. The latched bit will be left set in the pmic, which will not send us more interrupts even if the enable bit stays enabled.

When a client wants to request an interrupt, use the activate callback on the irq_domain to clear latched bit. This ensures that the latched, if set due to the above changes in cleanup_irq or when the bootloader leaves it set, gets cleaned up, paving way for upcoming interrupts to trigger.

Quoted 7 lines

With this, there is a possibility of unwanted triggering of interrupt right after the latched bit is cleared - the interrupt may be left enabled too. To avoid that, clear the enable first followed by clearing the latched bit in the activate callback.

Please squash this with the patch that adds cleanup_irq() and rewrite the commit text to combine details from both.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#53 lore raw

Re: [PATCH V1 14/15] spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq

Quoted 26 lines · Stephen Boyd
Quoted 25 lines · Kiran Gunda

From: Subbaraman Narayanamurthy <[email protected]>

Currently, cleanup_irq() is invoked when a peripheral's interrupt fires and there is no mapping present in the interrupt domain of spmi interrupt controller.

The cleanup_irq clears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable in cleanup_irq races with request_irq() in that it stomps over the enable issued by request_irq. Fix this by not writing to the pmic in cleanup_irq. The latched bit will be left set in the pmic, which will not send us more interrupts even if the enable bit stays enabled.

When a client wants to request an interrupt, use the activate callback on the irq_domain to clear latched bit. This ensures that the latched, if set due to the above changes in cleanup_irq or when the bootloader leaves it set, gets cleaned up, paving way for upcoming interrupts to trigger.

With this, there is a possibility of unwanted triggering of interrupt right after the latched bit is cleared - the interrupt may be left enabled too. To avoid that, clear the enable first followed by clearing the latched bit in the activate callback.

Quoted 5 lines
Quoted 2 lines

Please squash this with the patch that adds cleanup_irq() and rewrite the commit text to combine details from both.

Sure. Will squash it in the next patch submission.

#54 lore raw

Re: [PATCH V1 14/15] spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq

Quoted 27 lines · On 2017-06-02 12:56, [email protected] wrote:
Quoted 26 lines · Stephen Boyd
Quoted 25 lines · Kiran Gunda

From: Subbaraman Narayanamurthy <[email protected]>

Currently, cleanup_irq() is invoked when a peripheral's interrupt fires and there is no mapping present in the interrupt domain of spmi interrupt controller.

The cleanup_irq clears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable in cleanup_irq races with request_irq() in that it stomps over the enable issued by request_irq. Fix this by not writing to the pmic in cleanup_irq. The latched bit will be left set in the pmic, which will not send us more interrupts even if the enable bit stays enabled.

When a client wants to request an interrupt, use the activate callback on the irq_domain to clear latched bit. This ensures that the latched, if set due to the above changes in cleanup_irq or when the bootloader leaves it set, gets cleaned up, paving way for upcoming interrupts to trigger.

With this, there is a possibility of unwanted triggering of interrupt right after the latched bit is cleared - the interrupt may be left enabled too. To avoid that, clear the enable first followed by clearing the latched bit in the activate callback.

Quoted 6 lines
Quoted 5 lines
Quoted 2 lines

Please squash this with the patch that adds cleanup_irq() and rewrite the commit text to combine details from both.

Sure. Will squash it in the next patch submission.

Patch that adds cleanup_irq is already taken in to the tree. Lets have this patch as is now.

#55 lore raw

Re: [PATCH V1 14/15] spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq

Quoted 28 lines · On 06/06, [email protected] wrote:
Quoted 27 lines · On 2017-06-02 12:56, [email protected] wrote:
Quoted 26 lines · Stephen Boyd
Quoted 25 lines · Kiran Gunda

From: Subbaraman Narayanamurthy <[email protected]>

Currently, cleanup_irq() is invoked when a peripheral's interrupt fires and there is no mapping present in the interrupt domain of spmi interrupt controller.

The cleanup_irq clears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable in cleanup_irq races with request_irq() in that it stomps over the enable issued by request_irq. Fix this by not writing to the pmic in cleanup_irq. The latched bit will be left set in the pmic, which will not send us more interrupts even if the enable bit stays enabled.

When a client wants to request an interrupt, use the activate callback on the irq_domain to clear latched bit. This ensures that the latched, if set due to the above changes in cleanup_irq or when the bootloader leaves it set, gets cleaned up, paving way for upcoming interrupts to trigger.

With this, there is a possibility of unwanted triggering of interrupt right after the latched bit is cleared - the interrupt may be left enabled too. To avoid that, clear the enable first followed by clearing the latched bit in the activate callback.

Quoted 8 lines
Quoted 6 lines
Quoted 5 lines
Quoted 2 lines

Please squash this with the patch that adds cleanup_irq() and rewrite the commit text to combine details from both.

Sure. Will squash it in the next patch submission.

Patch that adds cleanup_irq is already taken in to the tree. Lets have this patch as is now.

Is this the one with the kbuild error? IRQ domains are not always there, so I don't know how this is expected to work.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#56 lore raw

Re: [PATCH V1 14/15] spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq

Quoted 32 lines · Stephen Boyd
Quoted 31 lines · On 06/06, [email protected] wrote:
Quoted 30 lines · On 2017-06-02 12:56, [email protected] wrote:
Quoted 29 lines · Stephen Boyd
Quoted 27 lines · Kiran Gunda

From: Subbaraman Narayanamurthy <[email protected]>

Currently, cleanup_irq() is invoked when a peripheral's interrupt fires and there is no mapping present in the interrupt domain of spmi interrupt controller.

The cleanup_irq clears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable in cleanup_irq races with request_irq() in that it stomps over the enable issued by request_irq. Fix this by not writing to the pmic in cleanup_irq. The latched bit will be left set in the pmic, which will not send us more interrupts even if the enable bit stays enabled.

When a client wants to request an interrupt, use the activate callback on the irq_domain to clear latched bit. This ensures that the latched, if set due to the above changes in cleanup_irq or when the bootloader leaves it set, gets cleaned up, paving way for upcoming interrupts to trigger.

With this, there is a possibility of unwanted triggering of interrupt right after the latched bit is cleared - the interrupt may be left enabled too. To avoid that, clear the enable first followed by clearing the latched bit in the activate callback.

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Quoted 2 lines

Please squash this with the patch that adds cleanup_irq() and rewrite the commit text to combine details from both.

Sure. Will squash it in the next patch submission.

Patch that adds cleanup_irq is already taken in to the tree. Lets have this patch as is now.

Is this the one with the kbuild error? IRQ domains are not always there, so I don't know how this is expected to work.

Dropped out this patch as it is related to clearing the interrupts those are left enabled by the boot loader. We thought of clearing all the apps owned interrupts in the UEFI itself.

#57 lore raw

PATCH 15/15 spmi: pmic-arb: instantiate spmi_devices at arch_initcall

In reply to Kiran Gunda

From: Abhijeet Dharmapurikar <[email protected]>

The spmi arbiter device spawns spmi_devices which in turn spawn platform_devices for pmic peripherals.

Move the arbiter's driver init to arch_initcall so that the subsequent devices it spawns get instantiated earlier.

---
 drivers/spmi/spmi-pmic-arb.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/spmi/spmi-pmic-arb.c +6 -1
index 767bd2c..069799c 100644
@@ -1384,7 +1384,12 @@ static int spmi_pmic_arb_remove(struct platform_device *pdev)
 		.of_match_table = spmi_pmic_arb_match_table,
 	},
 };
-module_platform_driver(spmi_pmic_arb_driver);
+
+int __init spmi_pmic_arb_init(void)
+{
+	return platform_driver_register(&spmi_pmic_arb_driver);
+}
+arch_initcall(spmi_pmic_arb_init);
 
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:spmi_pmic_arb");
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
#58 lore raw

Re: [PATCH V1 15/15] spmi: pmic-arb: instantiate spmi_devices at arch_initcall

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_remove(struct platform_device *pdev) · line 1388

Quoted 7 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +2 -1
@@ -1384,7 +1384,12 @@ static int spmi_pmic_arb_remove(struct platform_device *pdev)
 		.of_match_table = spmi_pmic_arb_match_table,
 	},
 };
-module_platform_driver(spmi_pmic_arb_driver);
+
+int __init spmi_pmic_arb_init(void)

Missing static.

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_remove(struct platform_device *pdev) · line 1392

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+{
+	return platform_driver_register(&spmi_pmic_arb_driver);
+}
+arch_initcall(spmi_pmic_arb_init);

We also lost module removal. Probably nobody tests it, but still no mention of that in commit text.

I'm not sure we need this at all though. Is there something that needs to probe early? Indicating what that is in the commit text would be helpful.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#59 lore raw

Re: [PATCH V1 15/15] spmi: pmic-arb: instantiate spmi_devices at arch_initcall

Quoted 20 lines · Stephen Boyd

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_remove(struct · line 1389

Quoted 8 lines · Kiran Gunda
drivers/spmi/spmi-pmic-arb.c +2 -1
@@ -1384,7 +1384,12 @@ static int spmi_pmic_arb_remove(struct 
 platform_device *pdev)
 		.of_match_table = spmi_pmic_arb_match_table,
 	},
 };
-module_platform_driver(spmi_pmic_arb_driver);
+
+int __init spmi_pmic_arb_init(void)

Missing static.

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_remove(struct platform_device *pdev) · line 1392

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+{
+	return platform_driver_register(&spmi_pmic_arb_driver);
+}
+arch_initcall(spmi_pmic_arb_init);

We also lost module removal. Probably nobody tests it, but still no mention of that in commit text.

Quoted 3 lines

I'm not sure we need this at all though. Is there something that needs to probe early? Indicating what that is in the commit text would be helpful.

Dropped out this patch. As this is no more required.