aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorJohan Hovold <johan+linaro@kernel.org>2023-10-03 17:29:23 +0200
committerLee Jones <lee@kernel.org>2023-11-01 10:02:16 +0000
commita0fa44c261e448c531f9adb3a5189a3520f3e316 (patch)
tree2346d85fb18dc239e1cf819b6e7895366feeac16 /drivers/mfd
parentfe74f7a96616faa3a3ec12b6ed1371e79974f2ab (diff)
downloadlinux-a0fa44c261e448c531f9adb3a5189a3520f3e316.tar.gz
mfd: qcom-spmi-pmic: Fix reference leaks in revid helper
The Qualcomm SPMI PMIC revid implementation is broken in multiple ways. First, it totally ignores struct device_node reference counting and leaks references to the parent bus node as well as each child it iterates over using an open-coded for_each_child_of_node(). Second, it leaks references to each spmi device on the bus that it iterates over by failing to drop the reference taken by the spmi_device_from_of() helper. Fix the struct device_node leaks by reimplementing the lookup using for_each_child_of_node() and adding the missing reference count decrements. Fix the sibling struct device leaks by dropping the unnecessary lookups of devices with the wrong USID. Note that this still leaves one struct device reference leak in case a base device is found but it is not the parent of the device used for the lookup. This will be addressed in a follow-on patch. Fixes: e9c11c6e3a0e ("mfd: qcom-spmi-pmic: expose the PMIC revid information to clients") Cc: stable@vger.kernel.org # 6.0 Signed-off-by: Johan Hovold <johan+linaro@kernel.org> Acked-by: Caleb Connolly <caleb.connolly@linaro.org> Link: https://lore.kernel.org/r/20231003152927.15000-2-johan+linaro@kernel.org Signed-off-by: Lee Jones <lee@kernel.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/qcom-spmi-pmic.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c
index 7e2cd79d17ebf8..47738f7e492ca9 100644
--- a/drivers/mfd/qcom-spmi-pmic.c
+++ b/drivers/mfd/qcom-spmi-pmic.c
@@ -81,7 +81,7 @@ static struct spmi_device *qcom_pmic_get_base_usid(struct device *dev)
struct spmi_device *sdev;
struct qcom_spmi_dev *ctx;
struct device_node *spmi_bus;
- struct device_node *other_usid = NULL;
+ struct device_node *child;
int function_parent_usid, ret;
u32 pmic_addr;
@@ -105,28 +105,34 @@ static struct spmi_device *qcom_pmic_get_base_usid(struct device *dev)
* device for USID 2.
*/
spmi_bus = of_get_parent(sdev->dev.of_node);
- do {
- other_usid = of_get_next_child(spmi_bus, other_usid);
-
- ret = of_property_read_u32_index(other_usid, "reg", 0, &pmic_addr);
- if (ret)
- return ERR_PTR(ret);
+ sdev = ERR_PTR(-ENODATA);
+ for_each_child_of_node(spmi_bus, child) {
+ ret = of_property_read_u32_index(child, "reg", 0, &pmic_addr);
+ if (ret) {
+ of_node_put(child);
+ sdev = ERR_PTR(ret);
+ break;
+ }
- sdev = spmi_device_from_of(other_usid);
if (pmic_addr == function_parent_usid - (ctx->num_usids - 1)) {
- if (!sdev)
+ sdev = spmi_device_from_of(child);
+ if (!sdev) {
/*
* If the base USID for this PMIC hasn't probed yet
* but the secondary USID has, then we need to defer
* the function driver so that it will attempt to
* probe again when the base USID is ready.
*/
- return ERR_PTR(-EPROBE_DEFER);
- return sdev;
+ sdev = ERR_PTR(-EPROBE_DEFER);
+ }
+ of_node_put(child);
+ break;
}
- } while (other_usid->sibling);
+ }
+
+ of_node_put(spmi_bus);
- return ERR_PTR(-ENODATA);
+ return sdev;
}
static int pmic_spmi_load_revid(struct regmap *map, struct device *dev,