: support for spmi_pmic_arb v3/v5 and bug fixes
Subsystems (2)
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 --
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
@@ -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 --
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 of0x800within the block, so size -0x800will give us the area used by the table. Since each table is 4 bytes long (core_size-0x800) / 4 will gives us the number ofdata_channelsupported.
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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 84 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-)drivers/spmi/spmi-pmic-arb.c +0
-0
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
-0rc = 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
-0rc = 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
-0core =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
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 of0x800within the block, so size -0x800will give us the area used by the table. Since each table is 4 bytes long (core_size-0x800) / 4 will gives us the number ofdata_channelsupported.
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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- 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@@ -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
-0struct 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_tfor 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 usesctrl->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 usesctrl->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(structirq_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(structspmi_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(structspmi_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_devshould 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(structspmi_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
-0res =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
-0core =devm_ioremap_resource (&ctrl->dev, res);drivers/spmi/spmi-pmic-arb.c +3
-0if (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.
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 of0x800within the block, so size -0x800will give us the area used by the table. Since each table is 4 bytes long (core_size-0x800) / 4 will gives us the number ofdata_channelsupported.
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
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 of0x800within the block, so size -0x800will give us the area used by the table. Since each table is 4 bytes long (core_size-0x800) / 4 will gives us the number ofdata_channelsupported.
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.
PATCH 2/15 spmi: pmic-arb: rename spmi_pmic_arb_dev to spmi_pmic_arb
In reply to Kiran GundaFrom: 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
@@ -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 --
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
*_devbest used for structures that embed a struct device in them.spmi_pmic_arb_devdoesn'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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- 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@@ -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
-1mode_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
-6qpnpint_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
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
*_devbest used for structures that embed a struct device in them.spmi_pmic_arb_devdoesn'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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 164+++++++++++++++++++++----------------------
Would also be nice if you ran
scripts/objdiffon 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@@ -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
-1mode_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(structspmi_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
-1memcpy (buf, &data, (bc &3 ) +1 ); }@@ -209,23 +210,24 @@ static void pa_read_data(structspmi_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(structspmi_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_arbsounds 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(structspmi_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
-0dev_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
-3unsigned 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
-9return -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
-3unsigned 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
-9return -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
-0return 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
-1u8 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
-1u32 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] << 16drivers/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
-1int 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
-4unsigned 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
-6qpnpint_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
-0qpnpint_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.
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(structspmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc) * @buf: buffer to write. length must be bc + 1. */ static void
-pa_write_data(structspmi_pmic_arb_dev*dev, const u8 *buf, u32 reg, u8 bc)
+pa_write_data(structspmi_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_writehas thewritel_relaxedinside it. that's why we removed the__raw_writelto 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
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(structspmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc) * @buf: buffer to write. length must be bc + 1. */ static void
-pa_write_data(structspmi_pmic_arb_dev*dev, const u8 *buf, u32 reg, u8 bc)
+pa_write_data(structspmi_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_writehas thewritel_relaxedinside it. that's why we removed the__raw_writelto 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.
PATCH 3/15 spmi: pmic-arb: fix inconsistent use of apid and chan
In reply to Kiran GundaFrom: 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
@@ -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 --
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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 68 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-)drivers/spmi/spmi-pmic-arb.c +0
-0
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
-3if (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
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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- 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@@ -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.
*/
structspmi_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(structirq_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
-1id = (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_VALIDthen? Shouldn't it bePMIC_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
-3if (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; }
PATCH 4/15 spmi: pmic-arb: optimize table lookups
In reply to Kiran GundaFrom: 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
@@ -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 --
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@@ -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
-2int (*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
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@@ -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
-0int (*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
-5dev_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
-0if (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
-0static 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
-5break ;@@ -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 ; +} +
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@@ -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
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@@ -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.
PATCH 5/15 spmi: pmic-arb: cleanup unrequested irqs
In reply to Kiran GundaFrom: 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
@@ -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 --
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_irqlater 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
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_irqlater 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.
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_irqlater 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_STATUSregister 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
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_irqlater 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_STATUSregister 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_STATUSto 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 ?
PATCH 6/15 spmi: pmic-arb: fix missing interrupts
In reply to Kiran GundaFrom: 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
@@ -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 --
Re: [PATCH V1 06/15] spmi: pmic-arb: fix missing interrupts
Quoted 7 lines · Kiran Gunda
From: Abhijeet Dharmapurikar <[email protected]>
irq_enableis called when the device resumes. Note that theirq_enableis 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_enablecallback. This is dangerous as any interrupts that happen right before the resume could be missed. Remove theirq_enablecallback and use mask/unmask instead.Also remove struct
pmic_arb_irq_specas 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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-)drivers/spmi/spmi-pmic-arb.c +0
-11@@ -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
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_enableis called when the device resumes. Note that theirq_enableis 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_enablecallback. This is dangerous as any interrupts that happen right before the resume could be missed. Remove theirq_enablecallback and use mask/unmask instead.
Quoted 6 lines
Quoted 3 lines
Also remove struct
pmic_arb_irq_specas 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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-)drivers/spmi/spmi-pmic-arb.c +0
-11@@ -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
-0struct 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
-1static 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 !
PATCH 7/15 spmi: pmic-arb: clear the latched status of the interrupt
In reply to Kiran GundaFrom: 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
@@ -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 --
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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
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 afterDouble '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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>Reviewed-by Stephen Boyd <[email protected]>
Thanks for reviewing and acking this.
PATCH 8/15 spmi: pmic_arb: use appropriate flow handler
In reply to Kiran GundaFrom: 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
@@ -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 --
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_irqflow 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_PENDINGflag and only then masks the interrupt. ThatIRQF_PENDINGstate indicates an edge transition happened while the interrupt was being handled and the handler is called again.
Quoted 2 lines
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>
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
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
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_irqflow 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_PENDINGflag and only then masks the interrupt. ThatIRQF_PENDINGstate indicates an edge transition happened while the interrupt was being handled and the handler is called again.
Quoted 7 lines
Quoted 2 lines
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>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@@ -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
-0qpnpint_spmi_write (d,QPNPINT_REG_SET_TYPE , &type,sizeof (type)); + +if (flow_type &IRQ_TYPE_EDGE_BOTH )
IRQ_TYPE_EDGE_BOTHdoesn'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.
PATCH 9/15 spmi: pmic-arb: check apid enabled before calling the handler
In reply to Kiran GundaFrom: 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
@@ -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 --
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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)drivers/spmi/spmi-pmic-arb.c +2
-2@@ -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
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_ENABLEbit 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
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)drivers/spmi/spmi-pmic-arb.c +2
-2@@ -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_BITafter 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.
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_ENABLEbit is always set now and never cleared?Yes. It is awful. It is not because of the
ACC_ENABLEbit is set.Quoted 24 lines
Quoted 24 lines
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>---
drivers/spmi/spmi-pmic-arb.c| 10 +++++++---1 file changed, 7 insertions(+), 3 deletions(-)drivers/spmi/spmi-pmic-arb.c +2
-2@@ -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_BITafter 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_BITfrom theirq_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 theSPMI_PIC_ACC_ENABLE_BITis not enabled. That's why we have to
read this register to not service the interrupt that is not requested/enabled yet.
ThisSPMI_PIC_ACC_ENABLE_BITis enabled during theirq_unmaskwhich is called fromrequest_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_interruptfor 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
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_ENABLEbit is always set now and never cleared?Yes. It is awful. It is not because of the
ACC_ENABLEbit is set.Quoted 41 lines
Quoted 25 lines
Signed-off-by Abhijeet Dharmapurikar <[email protected]>Signed-off-by Kiran Gunda <[email protected]>---
drivers/spmi/spmi-pmic-arb.c| 10 +++++++---1 file changed, 7 insertions(+), 3 deletions(-)drivers/spmi/spmi-pmic-arb.c +2
-2@@ -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_BITafter 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_BITfrom theirq_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 theSPMI_PIC_ACC_ENABLE_BITis not enabled. That's why we have to
read this register to not service the interrupt that is not requested/enabled yet.
ThisSPMI_PIC_ACC_ENABLE_BITis enabled during theirq_unmaskwhich is called fromrequest_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_interruptfor 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 onlySPMI_PIC_ACC_ENABLE_BITwas 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.
PATCH 10/15 spmi: pmic_arb: add support for PMIC bus arbiter v3
In reply to Kiran GundaFrom: 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
@@ -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 --
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
-0res =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
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
-0res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"obsrvr" );
PATCH 11/15 spmi: spmi-pmic-arb: enable the SPMI interrupt as a wakeup source
In reply to Kiran GundaCurrently 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
@@ -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 --
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.
Signed-off-by Nicholas Troast <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 1 + 1 file changed, 1 insertion(+)drivers/spmi/spmi-pmic-arb.c +0
-0
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
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.
Signed-off-by Nicholas Troast <[email protected]>Signed-off-by Kiran Gunda <[email protected]>--- drivers/spmi/spmi-pmic-arb.c | 1 + 1 file changed, 1 insertion(+)drivers/spmi/spmi-pmic-arb.c +0
-0@@ -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
-0irq_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_wakecallback 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.
PATCH 12/15 spmi-pmic-arb: fix a possible null pointer dereference
In reply to Kiran GundaFrom: 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
@@ -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 --
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@@ -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
-0res =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
@@ -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
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@@ -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
-0res =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_sizeis smaller than0x800. 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@@ -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);
PATCH 13/15 spmi: pmic-arb: add support for HW version 5
In reply to Kiran GundaFrom: 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
@@ -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 --
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@@ -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
-0intspec[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
-0res =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
-0goto 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
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@@ -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
-1struct apid_data {u16 ppid; -u8 owner; +u8 write_owner; +u8 irq_owner;How about
irq_eeandwrite_eeinstead?
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
-0intspec[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
-0if (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
-1regval =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
-0res =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
__iomempointer to the address instead of an offset? That way we don't need to care whatpa->intris or addpa->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 withIS_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.
PATCH 14/15 spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq
In reply to Kiran GundaFrom: 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
@@ -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 --
kbuild test robot
build botRe: [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
Re: [PATCH V1 14/15] spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq
In reply to Kiran GundaQuoted 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_irqclears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable incleanup_irqraces withrequest_irq()in that it stomps over the enable issued byrequest_irq. Fix this by not writing to the pmic incleanup_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_domainto clear latched bit. This ensures that the latched, if set due to the above changes incleanup_irqor 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.
Signed-off-by Subbaraman Narayanamurthy <[email protected]>Signed-off-by Kiran Gunda <[email protected]>
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
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_irqclears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable incleanup_irqraces withrequest_irq()in that it stomps over the enable issued byrequest_irq. Fix this by not writing to the pmic incleanup_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_domainto clear latched bit. This ensures that the latched, if set due to the above changes incleanup_irqor 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
Signed-off-by Subbaraman Narayanamurthy <[email protected]>Signed-off-by Kiran Gunda <[email protected]>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.
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_irqclears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable incleanup_irqraces withrequest_irq()in that it stomps over the enable issued byrequest_irq. Fix this by not writing to the pmic incleanup_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_domainto clear latched bit. This ensures that the latched, if set due to the above changes incleanup_irqor 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
Signed-off-by Subbaraman Narayanamurthy <[email protected]>Signed-off-by Kiran Gunda <[email protected]>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.
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_irqclears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable incleanup_irqraces withrequest_irq()in that it stomps over the enable issued byrequest_irq. Fix this by not writing to the pmic incleanup_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_domainto clear latched bit. This ensures that the latched, if set due to the above changes incleanup_irqor 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
Signed-off-by Subbaraman Narayanamurthy <[email protected]>Signed-off-by Kiran Gunda <[email protected]>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_irqis 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
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_irqclears the arbiter bit, clears the pmic interrupt and disables it at the pmic in that order. The last disable incleanup_irqraces withrequest_irq()in that it stomps over the enable issued byrequest_irq. Fix this by not writing to the pmic incleanup_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_domainto clear latched bit. This ensures that the latched, if set due to the above changes incleanup_irqor 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.
Signed-off-by Subbaraman Narayanamurthy <[email protected]>Signed-off-by Kiran Gunda <[email protected]>
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_irqis 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.
PATCH 15/15 spmi: pmic-arb: instantiate spmi_devices at arch_initcall
In reply to Kiran GundaFrom: 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
@@ -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 --
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
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.