diff mbox series

[v2] spmi: Fix controller->node != parent->node breakage

Message ID 20250113-topic-spmi_node_breakage-v2-1-dd35a3a6daa6@oss.qualcomm.com (mailing list archive)
State New
Headers show
Series [v2] spmi: Fix controller->node != parent->node breakage | expand

Commit Message

Konrad Dybcio Jan. 13, 2025, 1:02 p.m. UTC
From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

On some platforms, like recent Qualcomm SoCs with multi-bus SPMI
arbiters, controller->node must be assigned to the individual buses'
subnodes, as the slave devices are children of these, like so:

arbiter@c400000
	spmi@c42d000
		pmic@0

	spmi@c432000
		pmic@0

The commit referenced in Fixes changed that assignment, such that
spmi_controller_alloc() always assumes the PMICs come directly under
the arbiter node (which is true when there's only a single bus per
controller).

Make controller->node specifiable to both benefit from Joe's refcount
improvements and un-break the aforementioned platforms.

Fixes: 821b07853e32 ("spmi: hisi-spmi-controller: manage the OF node reference in device initialization and cleanup")
Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
Changes in v2:
- Fix compile errors
- Link to v1: https://lore.kernel.org/r/20250111-topic-spmi_node_breakage-v1-1-3f60111a1d19@oss.qualcomm.com
---
 drivers/spmi/hisi-spmi-controller.c | 4 +++-
 drivers/spmi/spmi-devres.c          | 6 ++++--
 drivers/spmi/spmi-mtk-pmif.c        | 4 +++-
 drivers/spmi/spmi-pmic-arb.c        | 2 +-
 drivers/spmi/spmi.c                 | 4 +++-
 include/linux/spmi.h                | 5 ++++-
 6 files changed, 18 insertions(+), 7 deletions(-)


---
base-commit: 2b88851f583d3c4e40bcd40cfe1965241ec229dd
change-id: 20250111-topic-spmi_node_breakage-f67322a9c1eb

Best regards,

Comments

AngeloGioacchino Del Regno Jan. 13, 2025, 1:52 p.m. UTC | #1
Il 13/01/25 14:02, Konrad Dybcio ha scritto:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> On some platforms, like recent Qualcomm SoCs with multi-bus SPMI
> arbiters, controller->node must be assigned to the individual buses'
> subnodes, as the slave devices are children of these, like so:
> 
> arbiter@c400000
> 	spmi@c42d000
> 		pmic@0
> 
> 	spmi@c432000
> 		pmic@0
> 
> The commit referenced in Fixes changed that assignment, such that
> spmi_controller_alloc() always assumes the PMICs come directly under
> the arbiter node (which is true when there's only a single bus per
> controller).
> 
> Make controller->node specifiable to both benefit from Joe's refcount
> improvements and un-break the aforementioned platforms.
> 
> Fixes: 821b07853e32 ("spmi: hisi-spmi-controller: manage the OF node reference in device initialization and cleanup")
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

for spmi.c/.h, spmi-devres and for MediaTek:

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

Cheers!
Stephen Boyd Jan. 13, 2025, 9:52 p.m. UTC | #2
Quoting Konrad Dybcio (2025-01-13 05:02:58)
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> On some platforms, like recent Qualcomm SoCs with multi-bus SPMI
> arbiters, controller->node must be assigned to the individual buses'
> subnodes, as the slave devices are children of these, like so:
> 
> arbiter@c400000
>         spmi@c42d000
>                 pmic@0
> 
>         spmi@c432000
>                 pmic@0
> 
> The commit referenced in Fixes changed that assignment, such that
> spmi_controller_alloc() always assumes the PMICs come directly under
> the arbiter node (which is true when there's only a single bus per
> controller).
> 
> Make controller->node specifiable to both benefit from Joe's refcount
> improvements and un-break the aforementioned platforms.

How is it broken? I see spmi_pmic_arb_bus_init() calls
devm_spmi_controller_alloc() which sets the of_node to the parent device
and then spmi_pmic_arb_bus_init() overwrites that with
'ctrl->dev.of_node = node' later on in the same function. That will
cause one more of_node_put() than is expected. I don't see that removed
in this patch though, so the leak is still there?

> 
> Fixes: 821b07853e32 ("spmi: hisi-spmi-controller: manage the OF node reference in device initialization and cleanup")

I've dropped this patch from my queue. I don't know if we're really
doing anything better by managing the of_node lifetime in that function
vs. letting the callers assign the node they want and manage the
lifetime themselves. Maybe we don't need to do anything? Presumably the
parent device driver will unregister the controller anyway, so the
lifetime of the of_node will be ensured regardless. For subnodes like
qcom SPMI, the subnodes are child nodes of the parent device so they
won't be removed. If they are dynamic nodes, then the caller can manage
the lifetime.
Konrad Dybcio Jan. 13, 2025, 10:12 p.m. UTC | #3
On 1/13/25 22:52, Stephen Boyd wrote:
> Quoting Konrad Dybcio (2025-01-13 05:02:58)
>> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>>
>> On some platforms, like recent Qualcomm SoCs with multi-bus SPMI
>> arbiters, controller->node must be assigned to the individual buses'
>> subnodes, as the slave devices are children of these, like so:
>>
>> arbiter@c400000
>>          spmi@c42d000
>>                  pmic@0
>>
>>          spmi@c432000
>>                  pmic@0
>>
>> The commit referenced in Fixes changed that assignment, such that
>> spmi_controller_alloc() always assumes the PMICs come directly under
>> the arbiter node (which is true when there's only a single bus per
>> controller).
>>
>> Make controller->node specifiable to both benefit from Joe's refcount
>> improvements and un-break the aforementioned platforms.
> 
> How is it broken? I see spmi_pmic_arb_bus_init() calls
> devm_spmi_controller_alloc() which sets the of_node to the parent device
> and then spmi_pmic_arb_bus_init() overwrites that with
> 'ctrl->dev.of_node = node' later on in the same function. That will
> cause one more of_node_put() than is expected. I don't see that removed
> in this patch though, so the leak is still there?
> 
>>
>> Fixes: 821b07853e32 ("spmi: hisi-spmi-controller: manage the OF node reference in device initialization and cleanup")
> 
> I've dropped this patch from my queue. I don't know if we're really
> doing anything better by managing the of_node lifetime in that function
> vs. letting the callers assign the node they want and manage the
> lifetime themselves. Maybe we don't need to do anything? Presumably the
> parent device driver will unregister the controller anyway, so the
> lifetime of the of_node will be ensured regardless. For subnodes like
> qcom SPMI, the subnodes are child nodes of the parent device so they
> won't be removed. If they are dynamic nodes, then the caller can manage
> the lifetime.

Stephen, the wrong node gets assigned in the qcom driver with
multi-master controllers, resulting in probe failures.

Since the introduction of the commit referenced in fixes,
of_spmi_register_devices() sees the controller's subnodes
(which describe each of the two masters) as slave devices
- meaning no "real" devices ever get to probe

Konrad
diff mbox series

Patch

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index dd21c5d1ca8301d508b85dfaf61ddfabed17aca9..030b4f86af6329d1c5694ec6440aceaa60f563ad 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -267,7 +267,9 @@  static int spmi_controller_probe(struct platform_device *pdev)
 	struct resource *iores;
 	int ret;
 
-	ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
+	ctrl = devm_spmi_controller_alloc(&pdev->dev,
+					  pdev->dev.of_node,
+					  sizeof(*spmi_controller));
 	if (IS_ERR(ctrl)) {
 		dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
 		return PTR_ERR(ctrl);
diff --git a/drivers/spmi/spmi-devres.c b/drivers/spmi/spmi-devres.c
index 62c4b3f24d0656eea9b6da489b7716b9965bedbe..e84af711714d1892a5781111dc538747f5a5e835 100644
--- a/drivers/spmi/spmi-devres.c
+++ b/drivers/spmi/spmi-devres.c
@@ -11,7 +11,9 @@  static void devm_spmi_controller_release(struct device *parent, void *res)
 	spmi_controller_put(*(struct spmi_controller **)res);
 }
 
-struct spmi_controller *devm_spmi_controller_alloc(struct device *parent, size_t size)
+struct spmi_controller *devm_spmi_controller_alloc(struct device *parent,
+						   struct device_node *node,
+						   size_t size)
 {
 	struct spmi_controller **ptr, *ctrl;
 
@@ -19,7 +21,7 @@  struct spmi_controller *devm_spmi_controller_alloc(struct device *parent, size_t
 	if (!ptr)
 		return ERR_PTR(-ENOMEM);
 
-	ctrl = spmi_controller_alloc(parent, size);
+	ctrl = spmi_controller_alloc(parent, node, size);
 	if (IS_ERR(ctrl)) {
 		devres_free(ptr);
 		return ctrl;
diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c
index 160d36f7d238e7eb4122091a53b779c18e9d91a4..8cff60f68f98a9d59d8f4423d746018135514e41 100644
--- a/drivers/spmi/spmi-mtk-pmif.c
+++ b/drivers/spmi/spmi-mtk-pmif.c
@@ -453,7 +453,9 @@  static int mtk_spmi_probe(struct platform_device *pdev)
 	int err, i;
 	u32 chan_offset;
 
-	ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*arb));
+	ctrl = devm_spmi_controller_alloc(&pdev->dev,
+					  pdev->dev.of_node,
+					  sizeof(*arb));
 	if (IS_ERR(ctrl))
 		return PTR_ERR(ctrl);
 
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 73f2f19737f8cec266a051a956ce2123661a714e..226f51d94a70328c6322664d2d05a8b64645674a 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -1674,7 +1674,7 @@  static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
 	int index, ret;
 	int irq;
 
-	ctrl = devm_spmi_controller_alloc(dev, sizeof(*bus));
+	ctrl = devm_spmi_controller_alloc(dev, node, sizeof(*bus));
 	if (IS_ERR(ctrl))
 		return PTR_ERR(ctrl);
 
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 166beb2083a3f801435d8ffd843310582911e3ab..c1a03da55a265c9294f6a16bc285310cebd00726 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -435,6 +435,7 @@  EXPORT_SYMBOL_GPL(spmi_device_alloc);
 /**
  * spmi_controller_alloc() - Allocate a new SPMI controller
  * @parent:	parent device
+ * @node:	device node to associate with the controller (usually parent->of_node)
  * @size:	size of private data
  *
  * Caller is responsible for either calling spmi_controller_add() to add the
@@ -443,6 +444,7 @@  EXPORT_SYMBOL_GPL(spmi_device_alloc);
  * spmi_controller_get_drvdata()
  */
 struct spmi_controller *spmi_controller_alloc(struct device *parent,
+					      struct device_node *node,
 					      size_t size)
 {
 	struct spmi_controller *ctrl;
@@ -459,7 +461,7 @@  struct spmi_controller *spmi_controller_alloc(struct device *parent,
 	ctrl->dev.type = &spmi_ctrl_type;
 	ctrl->dev.bus = &spmi_bus_type;
 	ctrl->dev.parent = parent;
-	device_set_node(&ctrl->dev, of_fwnode_handle(of_node_get(parent->of_node)));
+	device_set_node(&ctrl->dev, of_fwnode_handle(of_node_get(node)));
 	spmi_controller_set_drvdata(ctrl, &ctrl[1]);
 
 	id = ida_alloc(&ctrl_ida, GFP_KERNEL);
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index 28e8c8bd39441fa6451be3364006fb3b47a47dc9..9de74000911456800237a3244d5e8158fadf8317 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -105,6 +105,7 @@  static inline void spmi_controller_set_drvdata(struct spmi_controller *ctrl,
 }
 
 struct spmi_controller *spmi_controller_alloc(struct device *parent,
+					      struct device_node *node,
 					      size_t size);
 
 /**
@@ -120,7 +121,9 @@  static inline void spmi_controller_put(struct spmi_controller *ctrl)
 int spmi_controller_add(struct spmi_controller *ctrl);
 void spmi_controller_remove(struct spmi_controller *ctrl);
 
-struct spmi_controller *devm_spmi_controller_alloc(struct device *parent, size_t size);
+struct spmi_controller *devm_spmi_controller_alloc(struct device *parent,
+						   struct device_node *node,
+						   size_t size);
 int devm_spmi_controller_add(struct device *parent, struct spmi_controller *ctrl);
 
 /**