* [PATCH v2 2/3] mfd: core: Fix formatting of MFD helpers
2020-06-11 19:10 [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Lee Jones
@ 2020-06-11 19:10 ` Lee Jones
2020-06-12 12:27 ` Frank Rowand
2020-06-11 19:10 ` [PATCH v2 3/3] mfd: core: Add OF_MFD_CELL_REG() helper Lee Jones
` (4 subsequent siblings)
5 siblings, 1 reply; 25+ messages in thread
From: Lee Jones @ 2020-06-11 19:10 UTC (permalink / raw)
To: andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh
Cc: Lee Jones, linux-kernel, linux-arm-kernel
Remove unnecessary '\'s and leading tabs.
This will help to clean-up future diffs when subsequent changes are
made.
Hint: The aforementioned changes follow this patch.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
include/linux/mfd/core.h | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index a148b907bb7f1..ae1c6f90388ba 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -26,20 +26,20 @@
.id = (_id), \
}
-#define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat) \
- MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL) \
+#define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat) \
+ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)
-#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
- MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match) \
+#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
+ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)
-#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
- MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL) \
+#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
+ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)
-#define MFD_CELL_RES(_name, _res) \
- MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL) \
+#define MFD_CELL_RES(_name, _res) \
+ MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)
-#define MFD_CELL_NAME(_name) \
- MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL) \
+#define MFD_CELL_NAME(_name) \
+ MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)
struct irq_domain;
struct property_entry;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v2 2/3] mfd: core: Fix formatting of MFD helpers
2020-06-11 19:10 ` [PATCH v2 2/3] mfd: core: Fix formatting of MFD helpers Lee Jones
@ 2020-06-12 12:27 ` Frank Rowand
0 siblings, 0 replies; 25+ messages in thread
From: Frank Rowand @ 2020-06-12 12:27 UTC (permalink / raw)
To: Lee Jones, andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh,
Frank Rowand
Cc: linux-kernel, linux-arm-kernel
+Frank (me)
On 2020-06-11 14:10, Lee Jones wrote:
> Remove unnecessary '\'s and leading tabs.
>
> This will help to clean-up future diffs when subsequent changes are
> made.
>
> Hint: The aforementioned changes follow this patch.
>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
> include/linux/mfd/core.h | 20 ++++++++++----------
> 1 file changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index a148b907bb7f1..ae1c6f90388ba 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -26,20 +26,20 @@
> .id = (_id), \
> }
>
> -#define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat) \
> - MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL) \
> +#define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat) \
> + MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)
>
> -#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
> - MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match) \
> +#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
> + MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)
>
> -#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
> - MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL) \
> +#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
> + MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)
>
> -#define MFD_CELL_RES(_name, _res) \
> - MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL) \
> +#define MFD_CELL_RES(_name, _res) \
> + MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)
>
> -#define MFD_CELL_NAME(_name) \
> - MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL) \
> +#define MFD_CELL_NAME(_name) \
> + MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)
>
> struct irq_domain;
> struct property_entry;
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2 3/3] mfd: core: Add OF_MFD_CELL_REG() helper
2020-06-11 19:10 [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Lee Jones
2020-06-11 19:10 ` [PATCH v2 2/3] mfd: core: Fix formatting of MFD helpers Lee Jones
@ 2020-06-11 19:10 ` Lee Jones
2020-06-12 12:28 ` Frank Rowand
2020-06-12 12:26 ` [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Frank Rowand
` (3 subsequent siblings)
5 siblings, 1 reply; 25+ messages in thread
From: Lee Jones @ 2020-06-11 19:10 UTC (permalink / raw)
To: andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh
Cc: Lee Jones, linux-kernel, linux-arm-kernel
Extend current list of helpers to provide support for parent drivers
wishing to match specific child devices to particular OF nodes.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
include/linux/mfd/core.h | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index ae1c6f90388ba..7ce1de99cd8b8 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -14,7 +14,7 @@
#define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
-#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _match)\
+#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, _use_of_reg,_match) \
{ \
.name = (_name), \
.resources = (_res), \
@@ -22,24 +22,29 @@
.platform_data = (_pdata), \
.pdata_size = (_pdsize), \
.of_compatible = (_compat), \
+ .of_reg = (_of_reg), \
+ .use_of_reg = (_use_of_reg), \
.acpi_match = (_match), \
.id = (_id), \
}
+#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize,_id, _compat, _of_reg) \
+ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, true, NULL)
+
#define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat) \
- MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)
+ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, 0, false, NULL)
#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
- MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)
+ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, _match)
#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
- MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)
+ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, NULL)
#define MFD_CELL_RES(_name, _res) \
- MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)
+ MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, 0, false, NULL)
#define MFD_CELL_NAME(_name) \
- MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)
+ MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, 0, false, NULL)
struct irq_domain;
struct property_entry;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v2 3/3] mfd: core: Add OF_MFD_CELL_REG() helper
2020-06-11 19:10 ` [PATCH v2 3/3] mfd: core: Add OF_MFD_CELL_REG() helper Lee Jones
@ 2020-06-12 12:28 ` Frank Rowand
0 siblings, 0 replies; 25+ messages in thread
From: Frank Rowand @ 2020-06-12 12:28 UTC (permalink / raw)
To: Lee Jones, andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh,
Frank Rowand
Cc: linux-kernel, linux-arm-kernel
+Frank (me)
On 2020-06-11 14:10, Lee Jones wrote:
> Extend current list of helpers to provide support for parent drivers
> wishing to match specific child devices to particular OF nodes.
>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
> include/linux/mfd/core.h | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index ae1c6f90388ba..7ce1de99cd8b8 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -14,7 +14,7 @@
>
> #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
>
> -#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _match)\
> +#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, _use_of_reg,_match) \
> { \
> .name = (_name), \
> .resources = (_res), \
> @@ -22,24 +22,29 @@
> .platform_data = (_pdata), \
> .pdata_size = (_pdsize), \
> .of_compatible = (_compat), \
> + .of_reg = (_of_reg), \
> + .use_of_reg = (_use_of_reg), \
> .acpi_match = (_match), \
> .id = (_id), \
> }
>
> +#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize,_id, _compat, _of_reg) \
> + MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, true, NULL)
> +
> #define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat) \
> - MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL)
> + MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, 0, false, NULL)
>
> #define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
> - MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match)
> + MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, _match)
>
> #define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
> - MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL)
> + MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, NULL)
>
> #define MFD_CELL_RES(_name, _res) \
> - MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL)
> + MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, 0, false, NULL)
>
> #define MFD_CELL_NAME(_name) \
> - MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL)
> + MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, 0, false, NULL)
>
> struct irq_domain;
> struct property_entry;
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-11 19:10 [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Lee Jones
2020-06-11 19:10 ` [PATCH v2 2/3] mfd: core: Fix formatting of MFD helpers Lee Jones
2020-06-11 19:10 ` [PATCH v2 3/3] mfd: core: Add OF_MFD_CELL_REG() helper Lee Jones
@ 2020-06-12 12:26 ` Frank Rowand
2020-06-15 1:19 ` Frank Rowand
` (2 subsequent siblings)
5 siblings, 0 replies; 25+ messages in thread
From: Frank Rowand @ 2020-06-12 12:26 UTC (permalink / raw)
To: Lee Jones, andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh,
Frank Rowand
Cc: linux-kernel, linux-arm-kernel
+ Frank (me)
On 2020-06-11 14:10, Lee Jones wrote:
> Currently, when a child platform device (sometimes referred to as a
> sub-device) is registered via the Multi-Functional Device (MFD) API,
> the framework attempts to match the newly registered platform device
> with its associated Device Tree (OF) node. Until now, the device has
> been allocated the first node found with an identical OF compatible
> string. Unfortunately, if there are, say for example '3' devices
> which are to be handled by the same driver and therefore have the same
> compatible string, each of them will be allocated a pointer to the
> *first* node.
>
> An example Device Tree entry might look like this:
>
> mfd_of_test {
> compatible = "mfd,of-test-parent";
> #address-cells = <0x02>;
> #size-cells = <0x02>;
>
> child@aaaaaaaaaaaaaaaa {
> compatible = "mfd,of-test-child";
> reg = <0xaaaaaaaa 0xaaaaaaaa 0 0x11>,
> <0xbbbbbbbb 0xbbbbbbbb 0 0x22>;
> };
>
> child@cccccccc {
> compatible = "mfd,of-test-child";
> reg = <0x00000000 0xcccccccc 0 0x33>;
> };
>
> child@dddddddd00000000 {
> compatible = "mfd,of-test-child";
> reg = <0xdddddddd 0x00000000 0 0x44>;
> };
> };
>
> When used with example sub-device registration like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 0, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child")
> };
>
> ... the current implementation will result in all devices being allocated
> the first OF node found containing a matching compatible string:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@aaaaaaaaaaaaaaaa
>
> After this patch each device will be allocated a unique OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@cccccccc
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@dddddddd00000000
>
> Which is fine if all OF nodes are identical. However if we wish to
> apply an attribute to particular device, we really need to ensure the
> correct OF node will be associated with the device containing the
> correct address. We accomplish this by matching the device's address
> expressed in DT with one provided during sub-device registration.
> Like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child", 0xdddddddd00000000),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> This will ensure a specific device (designated here using the
> platform_ids; 1, 2 and 3) is matched with a particular OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@dddddddd00000000
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@cccccccc
>
> This implementation is still not infallible, hence the mention of
> "best effort" in the commit subject. Since we have not *insisted* on
> the existence of 'reg' properties (in some scenarios they just do not
> make sense) and no device currently uses the new 'of_reg' attribute,
> we have to make an on-the-fly judgement call whether to associate the
> OF node anyway. Which we do in cases where parent drivers haven't
> specified a particular OF node to match to. So there is a *slight*
> possibility of the following result (note: the implementation here is
> convoluted, but it shows you one means by which this process can
> still break):
>
> /*
> * First entry will match to the first OF node with matching compatible
> * Second will fail, since the first took its OF node and is no longer available
> * Third will succeed
> */
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> The result:
>
> [0.753869] mfd-of-test-parent mfd_of_test: Registering 3 devices
> [0.756597] mfd-of-test-child: Failed to locate of_node [id: 2]
> [0.759999] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.760314] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.760908] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.761183] mfd-of-test-child mfd-of-test-child.2: No OF node associated with this device
> [0.761621] mfd-of-test-child mfd-of-test-child.3: Probing platform device: 3
> [0.761899] mfd-of-test-child mfd-of-test-child.3: Using OF node: child@cccccccc
>
> We could code around this with some pre-parsing semantics, but the
> added complexity required to cover each and every corner-case is not
> justified. Merely patching the current failing (via this patch) is
> already working with some pretty small corner-cases. Other issues
> should be patched in the parent drivers which can be achieved simply
> by implementing OF_MFD_CELL_REG().
>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
>
> Changelog:
>
> v1 => v2:
> * Simply return -EAGAIN if node is already in use
> * Allow for valid of_reg=0 by introducing use_of_reg boolean flag
> * Split helpers out into separate patch
>
> drivers/mfd/mfd-core.c | 99 +++++++++++++++++++++++++++++++++++-----
> include/linux/mfd/core.h | 10 ++++
> 2 files changed, 97 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> index e831e733b38cf..120803717b828 100644
> --- a/drivers/mfd/mfd-core.c
> +++ b/drivers/mfd/mfd-core.c
> @@ -10,6 +10,7 @@
> #include <linux/kernel.h>
> #include <linux/platform_device.h>
> #include <linux/acpi.h>
> +#include <linux/list.h>
> #include <linux/property.h>
> #include <linux/mfd/core.h>
> #include <linux/pm_runtime.h>
> @@ -17,8 +18,17 @@
> #include <linux/module.h>
> #include <linux/irqdomain.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/regulator/consumer.h>
>
> +static LIST_HEAD(mfd_of_node_list);
> +
> +struct mfd_of_node_entry {
> + struct list_head list;
> + struct device *dev;
> + struct device_node *np;
> +};
> +
> static struct device_type mfd_dev_type = {
> .name = "mfd_device",
> };
> @@ -107,6 +117,54 @@ static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
> }
> #endif
>
> +static int mfd_match_of_node_to_dev(struct platform_device *pdev,
> + struct device_node *np,
> + const struct mfd_cell *cell)
> +{
> + struct mfd_of_node_entry *of_entry;
> + const __be32 *reg;
> + u64 of_node_addr;
> +
> + /* Skip devices 'disabled' by Device Tree */
> + if (!of_device_is_available(np))
> + return -ENODEV;
> +
> + /* Skip if OF node has previously been allocated to a device */
> + list_for_each_entry(of_entry, &mfd_of_node_list, list)
> + if (of_entry->np == np)
> + return -EAGAIN;
> +
> + if (!cell->use_of_reg)
> + /* No of_reg defined - allocate first free compatible match */
> + goto allocate_of_node;
> +
> + /* We only care about each node's first defined address */
> + reg = of_get_address(np, 0, NULL, NULL);
> + if (!reg)
> + /* OF node does not contatin a 'reg' property to match to */
> + return -EAGAIN;
> +
> + of_node_addr = of_read_number(reg, of_n_addr_cells(np));
> +
> + if (cell->of_reg != of_node_addr)
> + /* No match */
> + return -EAGAIN;
> +
> +allocate_of_node:
> + of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
> + if (!of_entry)
> + return -ENOMEM;
> +
> + of_entry->dev = &pdev->dev;
> + of_entry->np = np;
> + list_add_tail(&of_entry->list, &mfd_of_node_list);
> +
> + pdev->dev.of_node = np;
> + pdev->dev.fwnode = &np->fwnode;
> +
> + return 0;
> +}
> +
> static int mfd_add_device(struct device *parent, int id,
> const struct mfd_cell *cell,
> struct resource *mem_base,
> @@ -115,6 +173,7 @@ static int mfd_add_device(struct device *parent, int id,
> struct resource *res;
> struct platform_device *pdev;
> struct device_node *np = NULL;
> + struct mfd_of_node_entry *of_entry, *tmp;
> int ret = -ENOMEM;
> int platform_id;
> int r;
> @@ -149,19 +208,22 @@ static int mfd_add_device(struct device *parent, int id,
> if (ret < 0)
> goto fail_res;
>
> - if (parent->of_node && cell->of_compatible) {
> + if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
> for_each_child_of_node(parent->of_node, np) {
> if (of_device_is_compatible(np, cell->of_compatible)) {
> - if (!of_device_is_available(np)) {
> - /* Ignore disabled devices error free */
> - ret = 0;
> + ret = mfd_match_of_node_to_dev(pdev, np, cell);
> + if (ret == -EAGAIN)
> + continue;
> + if (ret)
> goto fail_alias;
> - }
> - pdev->dev.of_node = np;
> - pdev->dev.fwnode = &np->fwnode;
> +
> break;
> }
> }
> +
> + if (!pdev->dev.of_node)
> + pr_warn("%s: Failed to locate of_node [id: %d]\n",
> + cell->name, platform_id);
> }
>
> mfd_acpi_add_device(cell, pdev);
> @@ -170,13 +232,13 @@ static int mfd_add_device(struct device *parent, int id,
> ret = platform_device_add_data(pdev,
> cell->platform_data, cell->pdata_size);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> if (cell->properties) {
> ret = platform_device_add_properties(pdev, cell->properties);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> for (r = 0; r < cell->num_resources; r++) {
> @@ -213,18 +275,18 @@ static int mfd_add_device(struct device *parent, int id,
> if (has_acpi_companion(&pdev->dev)) {
> ret = acpi_check_resource_conflict(&res[r]);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
> }
> }
>
> ret = platform_device_add_resources(pdev, res, cell->num_resources);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> ret = platform_device_add(pdev);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> if (cell->pm_runtime_no_callbacks)
> pm_runtime_no_callbacks(&pdev->dev);
> @@ -233,6 +295,12 @@ static int mfd_add_device(struct device *parent, int id,
>
> return 0;
>
> +fail_of_entry:
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == &pdev->dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> fail_alias:
> regulator_bulk_unregister_supply_alias(&pdev->dev,
> cell->parent_supplies,
> @@ -287,6 +355,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> {
> struct platform_device *pdev;
> const struct mfd_cell *cell;
> + struct mfd_of_node_entry *of_entry, *tmp;
>
> if (dev->type != &mfd_dev_type)
> return 0;
> @@ -297,6 +366,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
> cell->num_parent_supplies);
>
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> +
> kfree(cell);
>
> platform_device_unregister(pdev);
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index d01d1299e49dc..a148b907bb7f1 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -78,6 +78,16 @@ struct mfd_cell {
> */
> const char *of_compatible;
>
> + /*
> + * Address as defined in Device Tree. Used to compement 'of_compatible'
> + * (above) when matching OF nodes with devices that have identical
> + * compatible strings
> + */
> + const u64 of_reg;
> +
> + /* Set to 'true' to use 'of_reg' (above) - allows for of_reg=0 */
> + bool use_of_reg;
> +
> /* Matches ACPI */
> const struct mfd_cell_acpi_match *acpi_match;
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-11 19:10 [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Lee Jones
` (2 preceding siblings ...)
2020-06-12 12:26 ` [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Frank Rowand
@ 2020-06-15 1:19 ` Frank Rowand
2020-06-15 9:26 ` Lee Jones
2020-06-23 22:21 ` Frank Rowand
2020-06-23 23:03 ` Frank Rowand
5 siblings, 1 reply; 25+ messages in thread
From: Frank Rowand @ 2020-06-15 1:19 UTC (permalink / raw)
To: Lee Jones, andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh
Cc: Frank Rowand, linux-kernel, linux-arm-kernel
Hi Lee,
I'm looking at 5.8-rc1.
The only use of OF_MFD_CELL() where the same compatible is specified
for multiple elements of a struct mfd_cell array is for compatible
"stericsson,ab8500-pwm" in drivers/mfd/ab8500-core.c:
OF_MFD_CELL("ab8500-pwm",
NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
OF_MFD_CELL("ab8500-pwm",
NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
OF_MFD_CELL("ab8500-pwm",
NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
The only .dts or .dtsi files where I see compatible "stericsson,ab8500-pwm"
are:
arch/arm/boot/dts/ste-ab8500.dtsi
arch/arm/boot/dts/ste-ab8505.dtsi
These two .dtsi files only have a single node with this compatible.
Chasing back to .dts and .dtsi files that include these two .dtsi
files, I see no case where there are multiple nodes with this
compatible.
So it looks to me like there is no .dts in mainline that is providing
the three "stericsson,ab8500-pwm" nodes that drivers/mfd/ab8500-core.c
is expecting. No case that there are multiple mfd child nodes where
mfd_add_device() would assign the first of n child nodes with the
same compatible to multiple devices.
So it appears to me that drivers/mfd/ab8500-core.c is currently broken.
Am I missing something here?
If I am correct, then either drivers/mfd/ab8500-core.c or
ste-ab8500.dtsi and ste-ab8505.dtsi need to be fixed.
Moving forward, your proposed OF_MFD_CELL_REG() method seems a good
approach (I have not completely read the actual code in the patch yet
though).
On 2020-06-11 14:10, Lee Jones wrote:
> Currently, when a child platform device (sometimes referred to as a
> sub-device) is registered via the Multi-Functional Device (MFD) API,
> the framework attempts to match the newly registered platform device
> with its associated Device Tree (OF) node. Until now, the device has
> been allocated the first node found with an identical OF compatible
> string. Unfortunately, if there are, say for example '3' devices
> which are to be handled by the same driver and therefore have the same
> compatible string, each of them will be allocated a pointer to the
> *first* node.
>
> An example Device Tree entry might look like this:
>
> mfd_of_test {
> compatible = "mfd,of-test-parent";
> #address-cells = <0x02>;
> #size-cells = <0x02>;
>
> child@aaaaaaaaaaaaaaaa {
> compatible = "mfd,of-test-child";
> reg = <0xaaaaaaaa 0xaaaaaaaa 0 0x11>,
> <0xbbbbbbbb 0xbbbbbbbb 0 0x22>;
> };
>
> child@cccccccc {
> compatible = "mfd,of-test-child";
> reg = <0x00000000 0xcccccccc 0 0x33>;
> };
>
> child@dddddddd00000000 {
> compatible = "mfd,of-test-child";
> reg = <0xdddddddd 0x00000000 0 0x44>;
> };
> };
>
> When used with example sub-device registration like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 0, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child")
> };
>
> ... the current implementation will result in all devices being allocated
> the first OF node found containing a matching compatible string:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@aaaaaaaaaaaaaaaa
>
> After this patch each device will be allocated a unique OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@cccccccc
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@dddddddd00000000
>
> Which is fine if all OF nodes are identical. However if we wish to
> apply an attribute to particular device, we really need to ensure the
> correct OF node will be associated with the device containing the
> correct address. We accomplish this by matching the device's address
> expressed in DT with one provided during sub-device registration.
> Like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child", 0xdddddddd00000000),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> This will ensure a specific device (designated here using the
> platform_ids; 1, 2 and 3) is matched with a particular OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@dddddddd00000000
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@cccccccc
>
> This implementation is still not infallible, hence the mention of
> "best effort" in the commit subject. Since we have not *insisted* on
> the existence of 'reg' properties (in some scenarios they just do not
> make sense) and no device currently uses the new 'of_reg' attribute,
> we have to make an on-the-fly judgement call whether to associate the
> OF node anyway. Which we do in cases where parent drivers haven't
> specified a particular OF node to match to. So there is a *slight*
> possibility of the following result (note: the implementation here is
> convoluted, but it shows you one means by which this process can
> still break):
>
> /*
> * First entry will match to the first OF node with matching compatible
> * Second will fail, since the first took its OF node and is no longer available
> * Third will succeed
> */
The following mfd_of_test_cell[] looks like a bug to me. For a given
compatible value, either reg is required or is not allowed.
One could add validation code to mfd_add_devices(), which would scan the
parameter "cells", checking for multiple array elements with the same
compatible value where one of the elements does not have .use_of_reg
set. This seems to be a pain to program and not needed, because the
validation process, using the binding definition, would detect the
problem in the .dts source file, because either the required reg
property would be missing or the not to be specified reg property exists.
Whether reg is required or not allowed is based on the compatible value.
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> The result:
>
> [0.753869] mfd-of-test-parent mfd_of_test: Registering 3 devices
> [0.756597] mfd-of-test-child: Failed to locate of_node [id: 2]
> [0.759999] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.760314] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.760908] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.761183] mfd-of-test-child mfd-of-test-child.2: No OF node associated with this device
> [0.761621] mfd-of-test-child mfd-of-test-child.3: Probing platform device: 3
> [0.761899] mfd-of-test-child mfd-of-test-child.3: Using OF node: child@cccccccc
>
> We could code around this with some pre-parsing semantics, but the
> added complexity required to cover each and every corner-case is not
So this should problem should not occur.
> justified. Merely patching the current failing (via this patch) is
> already working with some pretty small corner-cases. Other issues
If there are existing corner cases, I did not search the source tree
sufficiently. What are the current corner cases?
-Frank
> should be patched in the parent drivers which can be achieved simply
> by implementing OF_MFD_CELL_REG().
>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
>
> Changelog:
>
> v1 => v2:
> * Simply return -EAGAIN if node is already in use
> * Allow for valid of_reg=0 by introducing use_of_reg boolean flag
> * Split helpers out into separate patch
>
> drivers/mfd/mfd-core.c | 99 +++++++++++++++++++++++++++++++++++-----
> include/linux/mfd/core.h | 10 ++++
> 2 files changed, 97 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> index e831e733b38cf..120803717b828 100644
> --- a/drivers/mfd/mfd-core.c
> +++ b/drivers/mfd/mfd-core.c
> @@ -10,6 +10,7 @@
> #include <linux/kernel.h>
> #include <linux/platform_device.h>
> #include <linux/acpi.h>
> +#include <linux/list.h>
> #include <linux/property.h>
> #include <linux/mfd/core.h>
> #include <linux/pm_runtime.h>
> @@ -17,8 +18,17 @@
> #include <linux/module.h>
> #include <linux/irqdomain.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/regulator/consumer.h>
>
> +static LIST_HEAD(mfd_of_node_list);
> +
> +struct mfd_of_node_entry {
> + struct list_head list;
> + struct device *dev;
> + struct device_node *np;
> +};
> +
> static struct device_type mfd_dev_type = {
> .name = "mfd_device",
> };
> @@ -107,6 +117,54 @@ static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
> }
> #endif
>
> +static int mfd_match_of_node_to_dev(struct platform_device *pdev,
> + struct device_node *np,
> + const struct mfd_cell *cell)
> +{
> + struct mfd_of_node_entry *of_entry;
> + const __be32 *reg;
> + u64 of_node_addr;
> +
> + /* Skip devices 'disabled' by Device Tree */
> + if (!of_device_is_available(np))
> + return -ENODEV;
> +
> + /* Skip if OF node has previously been allocated to a device */
> + list_for_each_entry(of_entry, &mfd_of_node_list, list)
> + if (of_entry->np == np)
> + return -EAGAIN;
> +
> + if (!cell->use_of_reg)
> + /* No of_reg defined - allocate first free compatible match */
> + goto allocate_of_node;
> +
> + /* We only care about each node's first defined address */
> + reg = of_get_address(np, 0, NULL, NULL);
> + if (!reg)
> + /* OF node does not contatin a 'reg' property to match to */
> + return -EAGAIN;
> +
> + of_node_addr = of_read_number(reg, of_n_addr_cells(np));
> +
> + if (cell->of_reg != of_node_addr)
> + /* No match */
> + return -EAGAIN;
> +
> +allocate_of_node:
> + of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
> + if (!of_entry)
> + return -ENOMEM;
> +
> + of_entry->dev = &pdev->dev;
> + of_entry->np = np;
> + list_add_tail(&of_entry->list, &mfd_of_node_list);
> +
> + pdev->dev.of_node = np;
> + pdev->dev.fwnode = &np->fwnode;
> +
> + return 0;
> +}
> +
> static int mfd_add_device(struct device *parent, int id,
> const struct mfd_cell *cell,
> struct resource *mem_base,
> @@ -115,6 +173,7 @@ static int mfd_add_device(struct device *parent, int id,
> struct resource *res;
> struct platform_device *pdev;
> struct device_node *np = NULL;
> + struct mfd_of_node_entry *of_entry, *tmp;
> int ret = -ENOMEM;
> int platform_id;
> int r;
> @@ -149,19 +208,22 @@ static int mfd_add_device(struct device *parent, int id,
> if (ret < 0)
> goto fail_res;
>
> - if (parent->of_node && cell->of_compatible) {
> + if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
> for_each_child_of_node(parent->of_node, np) {
> if (of_device_is_compatible(np, cell->of_compatible)) {
> - if (!of_device_is_available(np)) {
> - /* Ignore disabled devices error free */
> - ret = 0;
> + ret = mfd_match_of_node_to_dev(pdev, np, cell);
> + if (ret == -EAGAIN)
> + continue;
> + if (ret)
> goto fail_alias;
> - }
> - pdev->dev.of_node = np;
> - pdev->dev.fwnode = &np->fwnode;
> +
> break;
> }
> }
> +
> + if (!pdev->dev.of_node)
> + pr_warn("%s: Failed to locate of_node [id: %d]\n",
> + cell->name, platform_id);
> }
>
> mfd_acpi_add_device(cell, pdev);
> @@ -170,13 +232,13 @@ static int mfd_add_device(struct device *parent, int id,
> ret = platform_device_add_data(pdev,
> cell->platform_data, cell->pdata_size);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> if (cell->properties) {
> ret = platform_device_add_properties(pdev, cell->properties);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> for (r = 0; r < cell->num_resources; r++) {
> @@ -213,18 +275,18 @@ static int mfd_add_device(struct device *parent, int id,
> if (has_acpi_companion(&pdev->dev)) {
> ret = acpi_check_resource_conflict(&res[r]);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
> }
> }
>
> ret = platform_device_add_resources(pdev, res, cell->num_resources);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> ret = platform_device_add(pdev);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> if (cell->pm_runtime_no_callbacks)
> pm_runtime_no_callbacks(&pdev->dev);
> @@ -233,6 +295,12 @@ static int mfd_add_device(struct device *parent, int id,
>
> return 0;
>
> +fail_of_entry:
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == &pdev->dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> fail_alias:
> regulator_bulk_unregister_supply_alias(&pdev->dev,
> cell->parent_supplies,
> @@ -287,6 +355,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> {
> struct platform_device *pdev;
> const struct mfd_cell *cell;
> + struct mfd_of_node_entry *of_entry, *tmp;
>
> if (dev->type != &mfd_dev_type)
> return 0;
> @@ -297,6 +366,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
> cell->num_parent_supplies);
>
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> +
> kfree(cell);
>
> platform_device_unregister(pdev);
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index d01d1299e49dc..a148b907bb7f1 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -78,6 +78,16 @@ struct mfd_cell {
> */
> const char *of_compatible;
>
> + /*
> + * Address as defined in Device Tree. Used to compement 'of_compatible'
> + * (above) when matching OF nodes with devices that have identical
> + * compatible strings
> + */
> + const u64 of_reg;
> +
> + /* Set to 'true' to use 'of_reg' (above) - allows for of_reg=0 */
> + bool use_of_reg;
> +
> /* Matches ACPI */
> const struct mfd_cell_acpi_match *acpi_match;
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-15 1:19 ` Frank Rowand
@ 2020-06-15 9:26 ` Lee Jones
2020-06-18 17:34 ` Frank Rowand
0 siblings, 1 reply; 25+ messages in thread
From: Lee Jones @ 2020-06-15 9:26 UTC (permalink / raw)
To: Frank Rowand
Cc: devicetree, gregkh, broonie, michael, linux-kernel,
andy.shevchenko, robh+dt, linux-arm-kernel, andriy.shevchenko,
robin.murphy, linus.walleij, linux
On Sun, 14 Jun 2020, Frank Rowand wrote:
> Hi Lee,
>
> I'm looking at 5.8-rc1.
>
> The only use of OF_MFD_CELL() where the same compatible is specified
> for multiple elements of a struct mfd_cell array is for compatible
> "stericsson,ab8500-pwm" in drivers/mfd/ab8500-core.c:
>
> OF_MFD_CELL("ab8500-pwm",
> NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
> OF_MFD_CELL("ab8500-pwm",
> NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
> OF_MFD_CELL("ab8500-pwm",
> NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
>
> The only .dts or .dtsi files where I see compatible "stericsson,ab8500-pwm"
> are:
>
> arch/arm/boot/dts/ste-ab8500.dtsi
> arch/arm/boot/dts/ste-ab8505.dtsi
>
> These two .dtsi files only have a single node with this compatible.
> Chasing back to .dts and .dtsi files that include these two .dtsi
> files, I see no case where there are multiple nodes with this
> compatible.
>
> So it looks to me like there is no .dts in mainline that is providing
> the three "stericsson,ab8500-pwm" nodes that drivers/mfd/ab8500-core.c
> is expecting. No case that there are multiple mfd child nodes where
> mfd_add_device() would assign the first of n child nodes with the
> same compatible to multiple devices.
>
> So it appears to me that drivers/mfd/ab8500-core.c is currently broken.
> Am I missing something here?
>
> If I am correct, then either drivers/mfd/ab8500-core.c or
> ste-ab8500.dtsi and ste-ab8505.dtsi need to be fixed.
Your analysis is correct.
Although it's not "broken", it just works when it really shouldn't.
I will be fixing the 'ab8500-pwm' case in due course.
> Moving forward, your proposed OF_MFD_CELL_REG() method seems a good
> approach (I have not completely read the actual code in the patch yet
> though).
Thanks.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-15 9:26 ` Lee Jones
@ 2020-06-18 17:34 ` Frank Rowand
[not found] ` <20200622085009.GP954398@dell>
0 siblings, 1 reply; 25+ messages in thread
From: Frank Rowand @ 2020-06-18 17:34 UTC (permalink / raw)
To: Lee Jones
Cc: devicetree, gregkh, broonie, michael, linux-kernel,
andy.shevchenko, robh+dt, linux-arm-kernel, andriy.shevchenko,
robin.murphy, linus.walleij, linux
On 2020-06-15 04:26, Lee Jones wrote:
> On Sun, 14 Jun 2020, Frank Rowand wrote:
>
>> Hi Lee,
>>
>> I'm looking at 5.8-rc1.
>>
>> The only use of OF_MFD_CELL() where the same compatible is specified
>> for multiple elements of a struct mfd_cell array is for compatible
>> "stericsson,ab8500-pwm" in drivers/mfd/ab8500-core.c:
>>
>> OF_MFD_CELL("ab8500-pwm",
>> NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
>> OF_MFD_CELL("ab8500-pwm",
>> NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
>> OF_MFD_CELL("ab8500-pwm",
>> NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
OF_MFD_CELL("ab8500-pwm",
NULL, NULL, 0, 0, "stericsson,ab8500-pwm"),
OF_MFD_CELL_REG("ab8500-pwm-mc",
NULL, NULL, 0, 0, "stericsson,ab8500-pwm", 0),
OF_MFD_CELL_REG("ab8500-pwm-mc",
NULL, NULL, 0, 1, "stericsson,ab8500-pwm", 1),
OF_MFD_CELL_REG("ab8500-pwm-mc",
NULL, NULL, 0, 2, "stericsson,ab8500-pwm", 2),
>>
>> The only .dts or .dtsi files where I see compatible "stericsson,ab8500-pwm"
>> are:
>>
>> arch/arm/boot/dts/ste-ab8500.dtsi
>> arch/arm/boot/dts/ste-ab8505.dtsi
>>
>> These two .dtsi files only have a single node with this compatible.
>> Chasing back to .dts and .dtsi files that include these two .dtsi
>> files, I see no case where there are multiple nodes with this
>> compatible.
>>
>> So it looks to me like there is no .dts in mainline that is providing
>> the three "stericsson,ab8500-pwm" nodes that drivers/mfd/ab8500-core.c
>> is expecting. No case that there are multiple mfd child nodes where
>> mfd_add_device() would assign the first of n child nodes with the
>> same compatible to multiple devices.
>>
>> So it appears to me that drivers/mfd/ab8500-core.c is currently broken.
>> Am I missing something here?
>>
>> If I am correct, then either drivers/mfd/ab8500-core.c or
>> ste-ab8500.dtsi and ste-ab8505.dtsi need to be fixed.
>
> Your analysis is correct.
OK, if I'm not overlooking anything, that is good news.
Existing .dts source files only have one "ab8500-pwm" child. They already
work correcly.
Create a new compatible for the case of multiple children. In my example
I will add "-mc" (multiple children) to the existing compatible. There
is likely a better name, but this lets me provide an example.
Modify drivers/mfd/ab8500-core.c to use the new compatible, and new .dts
source files with multiple children use the new compatible:
OF_MFD_CELL("ab8500-pwm",
NULL, NULL, 0, 0, "stericsson,ab8500-pwm"),
OF_MFD_CELL_REG("ab8500-pwm-mc",
NULL, NULL, 0, 0, "stericsson,ab8500-pwm", 0),
OF_MFD_CELL_REG("ab8500-pwm-mc",
NULL, NULL, 0, 1, "stericsson,ab8500-pwm", 1),
OF_MFD_CELL_REG("ab8500-pwm-mc",
NULL, NULL, 0, 2, "stericsson,ab8500-pwm", 2),
The "OF_MFD_CELL" entry is the existing entry, which will handle current
.dts source files. The new "OF_MFD_CELL_REG" entries will handle new
.dts source files.
And of course the patch that creates OF_MFD_CELL_REG() needs to precede
this change.
I would remove the fallback code in the existing patch that tries to
handle an incorrect binding. Just error out if the binding is not
used properly.
-Frank
>
> Although it's not "broken", it just works when it really shouldn't.
>
> I will be fixing the 'ab8500-pwm' case in due course.
>
>> Moving forward, your proposed OF_MFD_CELL_REG() method seems a good
>> approach (I have not completely read the actual code in the patch yet
>> though).
>
> Thanks.
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-11 19:10 [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Lee Jones
` (3 preceding siblings ...)
2020-06-15 1:19 ` Frank Rowand
@ 2020-06-23 22:21 ` Frank Rowand
2020-06-24 6:45 ` Lee Jones
2020-06-23 23:03 ` Frank Rowand
5 siblings, 1 reply; 25+ messages in thread
From: Frank Rowand @ 2020-06-23 22:21 UTC (permalink / raw)
To: Lee Jones, andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh
Cc: Frank Rowand, linux-kernel, linux-arm-kernel
On 2020-06-11 14:10, Lee Jones wrote:
> Currently, when a child platform device (sometimes referred to as a
> sub-device) is registered via the Multi-Functional Device (MFD) API,
> the framework attempts to match the newly registered platform device
> with its associated Device Tree (OF) node. Until now, the device has
> been allocated the first node found with an identical OF compatible
> string. Unfortunately, if there are, say for example '3' devices
> which are to be handled by the same driver and therefore have the same
> compatible string, each of them will be allocated a pointer to the
> *first* node.
>
> An example Device Tree entry might look like this:
>
> mfd_of_test {
> compatible = "mfd,of-test-parent";
> #address-cells = <0x02>;
> #size-cells = <0x02>;
>
> child@aaaaaaaaaaaaaaaa {
> compatible = "mfd,of-test-child";
> reg = <0xaaaaaaaa 0xaaaaaaaa 0 0x11>,
> <0xbbbbbbbb 0xbbbbbbbb 0 0x22>;
> };
>
> child@cccccccc {
> compatible = "mfd,of-test-child";
> reg = <0x00000000 0xcccccccc 0 0x33>;
> };
>
> child@dddddddd00000000 {
> compatible = "mfd,of-test-child";
> reg = <0xdddddddd 0x00000000 0 0x44>;
> };
> };
>
> When used with example sub-device registration like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 0, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child")
> };
>
> ... the current implementation will result in all devices being allocated
> the first OF node found containing a matching compatible string:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@aaaaaaaaaaaaaaaa
>
> After this patch each device will be allocated a unique OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@cccccccc
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@dddddddd00000000
>
> Which is fine if all OF nodes are identical. However if we wish to
> apply an attribute to particular device, we really need to ensure the
> correct OF node will be associated with the device containing the
> correct address. We accomplish this by matching the device's address
> expressed in DT with one provided during sub-device registration.
> Like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child", 0xdddddddd00000000),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> This will ensure a specific device (designated here using the
> platform_ids; 1, 2 and 3) is matched with a particular OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@dddddddd00000000
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@cccccccc
>
> This implementation is still not infallible, hence the mention of
> "best effort" in the commit subject. Since we have not *insisted* on
> the existence of 'reg' properties (in some scenarios they just do not
> make sense) and no device currently uses the new 'of_reg' attribute,
> we have to make an on-the-fly judgement call whether to associate the
> OF node anyway. Which we do in cases where parent drivers haven't
> specified a particular OF node to match to. So there is a *slight*
> possibility of the following result (note: the implementation here is
> convoluted, but it shows you one means by which this process can
> still break):
>
> /*
> * First entry will match to the first OF node with matching compatible
> * Second will fail, since the first took its OF node and is no longer available
> * Third will succeed
> */
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> The result:
>
> [0.753869] mfd-of-test-parent mfd_of_test: Registering 3 devices
> [0.756597] mfd-of-test-child: Failed to locate of_node [id: 2]
> [0.759999] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.760314] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.760908] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.761183] mfd-of-test-child mfd-of-test-child.2: No OF node associated with this device
> [0.761621] mfd-of-test-child mfd-of-test-child.3: Probing platform device: 3
> [0.761899] mfd-of-test-child mfd-of-test-child.3: Using OF node: child@cccccccc
>
> We could code around this with some pre-parsing semantics, but the
> added complexity required to cover each and every corner-case is not
> justified. Merely patching the current failing (via this patch) is
> already working with some pretty small corner-cases. Other issues
> should be patched in the parent drivers which can be achieved simply
> by implementing OF_MFD_CELL_REG().
>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
>
> Changelog:
>
> v1 => v2:
> * Simply return -EAGAIN if node is already in use
> * Allow for valid of_reg=0 by introducing use_of_reg boolean flag
> * Split helpers out into separate patch
>
> drivers/mfd/mfd-core.c | 99 +++++++++++++++++++++++++++++++++++-----
> include/linux/mfd/core.h | 10 ++++
> 2 files changed, 97 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> index e831e733b38cf..120803717b828 100644
> --- a/drivers/mfd/mfd-core.c
> +++ b/drivers/mfd/mfd-core.c
> @@ -10,6 +10,7 @@
> #include <linux/kernel.h>
> #include <linux/platform_device.h>
> #include <linux/acpi.h>
> +#include <linux/list.h>
> #include <linux/property.h>
> #include <linux/mfd/core.h>
> #include <linux/pm_runtime.h>
> @@ -17,8 +18,17 @@
> #include <linux/module.h>
> #include <linux/irqdomain.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/regulator/consumer.h>
>
> +static LIST_HEAD(mfd_of_node_list);
> +
> +struct mfd_of_node_entry {
> + struct list_head list;
> + struct device *dev;
> + struct device_node *np;
> +};
> +
> static struct device_type mfd_dev_type = {
> .name = "mfd_device",
> };
> @@ -107,6 +117,54 @@ static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
> }
> #endif
>
> +static int mfd_match_of_node_to_dev(struct platform_device *pdev,
> + struct device_node *np,
> + const struct mfd_cell *cell)
> +{
> + struct mfd_of_node_entry *of_entry;
> + const __be32 *reg;
> + u64 of_node_addr;
> +
> + /* Skip devices 'disabled' by Device Tree */
> + if (!of_device_is_available(np))
> + return -ENODEV;
> +
> + /* Skip if OF node has previously been allocated to a device */
> + list_for_each_entry(of_entry, &mfd_of_node_list, list)
> + if (of_entry->np == np)
> + return -EAGAIN;
> +
> + if (!cell->use_of_reg)
> + /* No of_reg defined - allocate first free compatible match */
> + goto allocate_of_node;
> +
> + /* We only care about each node's first defined address */
> + reg = of_get_address(np, 0, NULL, NULL);
> + if (!reg)
> + /* OF node does not contatin a 'reg' property to match to */
> + return -EAGAIN;
> +
> + of_node_addr = of_read_number(reg, of_n_addr_cells(np));
> +
> + if (cell->of_reg != of_node_addr)
> + /* No match */
> + return -EAGAIN;
> +
> +allocate_of_node:
> + of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
> + if (!of_entry)
> + return -ENOMEM;
> +
> + of_entry->dev = &pdev->dev;
> + of_entry->np = np;
> + list_add_tail(&of_entry->list, &mfd_of_node_list);
> +
> + pdev->dev.of_node = np;
> + pdev->dev.fwnode = &np->fwnode;
> +
> + return 0;
> +}
> +
> static int mfd_add_device(struct device *parent, int id,
> const struct mfd_cell *cell,
> struct resource *mem_base,
> @@ -115,6 +173,7 @@ static int mfd_add_device(struct device *parent, int id,
> struct resource *res;
> struct platform_device *pdev;
> struct device_node *np = NULL;
> + struct mfd_of_node_entry *of_entry, *tmp;
> int ret = -ENOMEM;
> int platform_id;
> int r;
> @@ -149,19 +208,22 @@ static int mfd_add_device(struct device *parent, int id,
> if (ret < 0)
> goto fail_res;
>
> - if (parent->of_node && cell->of_compatible) {
> + if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
> for_each_child_of_node(parent->of_node, np) {
> if (of_device_is_compatible(np, cell->of_compatible)) {
> - if (!of_device_is_available(np)) {
> - /* Ignore disabled devices error free */
> - ret = 0;
> + ret = mfd_match_of_node_to_dev(pdev, np, cell);
> + if (ret == -EAGAIN)
> + continue;
> + if (ret)
> goto fail_alias;
> - }
> - pdev->dev.of_node = np;
> - pdev->dev.fwnode = &np->fwnode;
> +
> break;
> }
> }
> +
> + if (!pdev->dev.of_node)
> + pr_warn("%s: Failed to locate of_node [id: %d]\n",
> + cell->name, platform_id);
> }
>
> mfd_acpi_add_device(cell, pdev);
> @@ -170,13 +232,13 @@ static int mfd_add_device(struct device *parent, int id,
> ret = platform_device_add_data(pdev,
> cell->platform_data, cell->pdata_size);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> if (cell->properties) {
> ret = platform_device_add_properties(pdev, cell->properties);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> for (r = 0; r < cell->num_resources; r++) {
> @@ -213,18 +275,18 @@ static int mfd_add_device(struct device *parent, int id,
> if (has_acpi_companion(&pdev->dev)) {
> ret = acpi_check_resource_conflict(&res[r]);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
> }
> }
>
> ret = platform_device_add_resources(pdev, res, cell->num_resources);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> ret = platform_device_add(pdev);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> if (cell->pm_runtime_no_callbacks)
> pm_runtime_no_callbacks(&pdev->dev);
> @@ -233,6 +295,12 @@ static int mfd_add_device(struct device *parent, int id,
>
> return 0;
>
> +fail_of_entry:
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == &pdev->dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> fail_alias:
> regulator_bulk_unregister_supply_alias(&pdev->dev,
> cell->parent_supplies,
> @@ -287,6 +355,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> {
> struct platform_device *pdev;
> const struct mfd_cell *cell;
> + struct mfd_of_node_entry *of_entry, *tmp;
>
> if (dev->type != &mfd_dev_type)
> return 0;
> @@ -297,6 +366,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
> cell->num_parent_supplies);
>
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> +
> kfree(cell);
>
> platform_device_unregister(pdev);
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index d01d1299e49dc..a148b907bb7f1 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -78,6 +78,16 @@ struct mfd_cell {
> */
> const char *of_compatible;
>
> + /*
> + * Address as defined in Device Tree. Used to compement 'of_compatible'
> + * (above) when matching OF nodes with devices that have identical
> + * compatible strings
> + */
Instead of the above comment, suggest something like instead (I have not properly
line wrapped, to make it easier to see the difference):
> + /*
> + * Address as defined in Device Tree mfd child node "reg" property. Used in combination with 'of_compatible'
> + * (above) when matching OF nodes with devices that have identical
> + * compatible strings
> + */
> + const u64 of_reg;
> +
> + /* Set to 'true' to use 'of_reg' (above) - allows for of_reg=0 */
> + bool use_of_reg;
> +
> /* Matches ACPI */
> const struct mfd_cell_acpi_match *acpi_match;
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-23 22:21 ` Frank Rowand
@ 2020-06-24 6:45 ` Lee Jones
0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2020-06-24 6:45 UTC (permalink / raw)
To: Frank Rowand
Cc: devicetree, gregkh, broonie, michael, linux-kernel,
andy.shevchenko, robh+dt, linux-arm-kernel, andriy.shevchenko,
robin.murphy, linus.walleij, linux
On Tue, 23 Jun 2020, Frank Rowand wrote:
> On 2020-06-11 14:10, Lee Jones wrote:
> > Currently, when a child platform device (sometimes referred to as a
> > sub-device) is registered via the Multi-Functional Device (MFD) API,
> > the framework attempts to match the newly registered platform device
> > with its associated Device Tree (OF) node. Until now, the device has
> > been allocated the first node found with an identical OF compatible
> > string. Unfortunately, if there are, say for example '3' devices
> > which are to be handled by the same driver and therefore have the same
> > compatible string, each of them will be allocated a pointer to the
> > *first* node.
> >
> > An example Device Tree entry might look like this:
> >
> > mfd_of_test {
> > compatible = "mfd,of-test-parent";
> > #address-cells = <0x02>;
> > #size-cells = <0x02>;
> >
> > child@aaaaaaaaaaaaaaaa {
> > compatible = "mfd,of-test-child";
> > reg = <0xaaaaaaaa 0xaaaaaaaa 0 0x11>,
> > <0xbbbbbbbb 0xbbbbbbbb 0 0x22>;
> > };
> >
> > child@cccccccc {
> > compatible = "mfd,of-test-child";
> > reg = <0x00000000 0xcccccccc 0 0x33>;
> > };
> >
> > child@dddddddd00000000 {
> > compatible = "mfd,of-test-child";
> > reg = <0xdddddddd 0x00000000 0 0x44>;
> > };
> > };
> >
> > When used with example sub-device registration like this:
> >
> > static const struct mfd_cell mfd_of_test_cell[] = {
> > OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 0, "mfd,of-test-child"),
> > OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> > OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child")
> > };
> >
> > ... the current implementation will result in all devices being allocated
> > the first OF node found containing a matching compatible string:
> >
> > [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> > [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> > [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> > [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> > [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> > [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@aaaaaaaaaaaaaaaa
> >
> > After this patch each device will be allocated a unique OF node:
> >
> > [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> > [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> > [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> > [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@cccccccc
> > [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> > [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@dddddddd00000000
> >
> > Which is fine if all OF nodes are identical. However if we wish to
> > apply an attribute to particular device, we really need to ensure the
> > correct OF node will be associated with the device containing the
> > correct address. We accomplish this by matching the device's address
> > expressed in DT with one provided during sub-device registration.
> > Like this:
> >
> > static const struct mfd_cell mfd_of_test_cell[] = {
> > OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child", 0xdddddddd00000000),
> > OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> > OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> > };
> >
> > This will ensure a specific device (designated here using the
> > platform_ids; 1, 2 and 3) is matched with a particular OF node:
> >
> > [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> > [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@dddddddd00000000
> > [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> > [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> > [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> > [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@cccccccc
> >
> > This implementation is still not infallible, hence the mention of
> > "best effort" in the commit subject. Since we have not *insisted* on
> > the existence of 'reg' properties (in some scenarios they just do not
> > make sense) and no device currently uses the new 'of_reg' attribute,
> > we have to make an on-the-fly judgement call whether to associate the
> > OF node anyway. Which we do in cases where parent drivers haven't
> > specified a particular OF node to match to. So there is a *slight*
> > possibility of the following result (note: the implementation here is
> > convoluted, but it shows you one means by which this process can
> > still break):
> >
> > /*
> > * First entry will match to the first OF node with matching compatible
> > * Second will fail, since the first took its OF node and is no longer available
> > * Third will succeed
> > */
> > static const struct mfd_cell mfd_of_test_cell[] = {
> > OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> > OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> > OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> > };
> >
> > The result:
> >
> > [0.753869] mfd-of-test-parent mfd_of_test: Registering 3 devices
> > [0.756597] mfd-of-test-child: Failed to locate of_node [id: 2]
> > [0.759999] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> > [0.760314] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> > [0.760908] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> > [0.761183] mfd-of-test-child mfd-of-test-child.2: No OF node associated with this device
> > [0.761621] mfd-of-test-child mfd-of-test-child.3: Probing platform device: 3
> > [0.761899] mfd-of-test-child mfd-of-test-child.3: Using OF node: child@cccccccc
> >
> > We could code around this with some pre-parsing semantics, but the
> > added complexity required to cover each and every corner-case is not
> > justified. Merely patching the current failing (via this patch) is
> > already working with some pretty small corner-cases. Other issues
> > should be patched in the parent drivers which can be achieved simply
> > by implementing OF_MFD_CELL_REG().
> >
> > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > ---
> >
> > Changelog:
> >
> > v1 => v2:
> > * Simply return -EAGAIN if node is already in use
> > * Allow for valid of_reg=0 by introducing use_of_reg boolean flag
> > * Split helpers out into separate patch
> >
> > drivers/mfd/mfd-core.c | 99 +++++++++++++++++++++++++++++++++++-----
> > include/linux/mfd/core.h | 10 ++++
> > 2 files changed, 97 insertions(+), 12 deletions(-)
[...]
> > diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> > index d01d1299e49dc..a148b907bb7f1 100644
> > --- a/include/linux/mfd/core.h
> > +++ b/include/linux/mfd/core.h
> > @@ -78,6 +78,16 @@ struct mfd_cell {
> > */
> > const char *of_compatible;
> >
> > + /*
> > + * Address as defined in Device Tree. Used to compement 'of_compatible'
> > + * (above) when matching OF nodes with devices that have identical
> > + * compatible strings
> > + */
>
> Instead of the above comment, suggest something like instead (I have not properly
> line wrapped, to make it easier to see the difference):
>
> > + /*
> > + * Address as defined in Device Tree mfd child node "reg" property. Used in combination with 'of_compatible'
> > + * (above) when matching OF nodes with devices that have identical
> > + * compatible strings
> > + */
I'll split the difference and make it more clear, thanks.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-11 19:10 [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes Lee Jones
` (4 preceding siblings ...)
2020-06-23 22:21 ` Frank Rowand
@ 2020-06-23 23:03 ` Frank Rowand
2020-06-24 6:41 ` Lee Jones
5 siblings, 1 reply; 25+ messages in thread
From: Frank Rowand @ 2020-06-23 23:03 UTC (permalink / raw)
To: Lee Jones, andy.shevchenko, michael, robh+dt, broonie, devicetree,
linus.walleij, linux, andriy.shevchenko, robin.murphy, gregkh
Cc: linux-kernel, linux-arm-kernel
On 2020-06-11 14:10, Lee Jones wrote:
> Currently, when a child platform device (sometimes referred to as a
> sub-device) is registered via the Multi-Functional Device (MFD) API,
> the framework attempts to match the newly registered platform device
> with its associated Device Tree (OF) node. Until now, the device has
> been allocated the first node found with an identical OF compatible
> string. Unfortunately, if there are, say for example '3' devices
> which are to be handled by the same driver and therefore have the same
> compatible string, each of them will be allocated a pointer to the
> *first* node.
As you mentioned elsewhere in this thread, this series "fixes" the
problem related to the "stericsson,ab8500-pwm" compatible.
I know, I said I would drop discussion of that compatible, but bear
with me for a second. :-)
The "problem" is that the devices for multiple mfd child nodes with
the same compatible value of "stericsson,ab8500-pwm" will all have
a pointer to the first child node. At the moment the same child
of_node being used by more than one device does not cause any
incorrect behavior.
Just in case the driver for "stericsson,ab8500-pwm" is modified
in a way that the child of_node needs to be distinct for each
device, and that changes gets back ported, it would be useful
to have Fixes: tags for this patch series.
So, at your discretion (and I'll let you worry about the correct
Fixes: tag format), this series fixes:
bad76991d7847b7877ae797cc79745d82ffd9120 mfd: Register ab8500 devices using the newly DT:ed MFD API
c94bb233a9fee3314dc5d9c7de9fa702e91283f2 mfd: Make MFD core code Device Tree and IRQ domain aware
-Frank
>
> An example Device Tree entry might look like this:
>
> mfd_of_test {
> compatible = "mfd,of-test-parent";
> #address-cells = <0x02>;
> #size-cells = <0x02>;
>
> child@aaaaaaaaaaaaaaaa {
> compatible = "mfd,of-test-child";
> reg = <0xaaaaaaaa 0xaaaaaaaa 0 0x11>,
> <0xbbbbbbbb 0xbbbbbbbb 0 0x22>;
> };
>
> child@cccccccc {
> compatible = "mfd,of-test-child";
> reg = <0x00000000 0xcccccccc 0 0x33>;
> };
>
> child@dddddddd00000000 {
> compatible = "mfd,of-test-child";
> reg = <0xdddddddd 0x00000000 0 0x44>;
> };
> };
>
> When used with example sub-device registration like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 0, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child")
> };
>
> ... the current implementation will result in all devices being allocated
> the first OF node found containing a matching compatible string:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@aaaaaaaaaaaaaaaa
>
> After this patch each device will be allocated a unique OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@cccccccc
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@dddddddd00000000
>
> Which is fine if all OF nodes are identical. However if we wish to
> apply an attribute to particular device, we really need to ensure the
> correct OF node will be associated with the device containing the
> correct address. We accomplish this by matching the device's address
> expressed in DT with one provided during sub-device registration.
> Like this:
>
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child", 0xdddddddd00000000),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> This will ensure a specific device (designated here using the
> platform_ids; 1, 2 and 3) is matched with a particular OF node:
>
> [0.712511] mfd-of-test-child mfd-of-test-child.0: Probing platform device: 0
> [0.712710] mfd-of-test-child mfd-of-test-child.0: Using OF node: child@dddddddd00000000
> [0.713033] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.713381] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.713691] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.713889] mfd-of-test-child mfd-of-test-child.2: Using OF node: child@cccccccc
>
> This implementation is still not infallible, hence the mention of
> "best effort" in the commit subject. Since we have not *insisted* on
> the existence of 'reg' properties (in some scenarios they just do not
> make sense) and no device currently uses the new 'of_reg' attribute,
> we have to make an on-the-fly judgement call whether to associate the
> OF node anyway. Which we do in cases where parent drivers haven't
> specified a particular OF node to match to. So there is a *slight*
> possibility of the following result (note: the implementation here is
> convoluted, but it shows you one means by which this process can
> still break):
>
> /*
> * First entry will match to the first OF node with matching compatible
> * Second will fail, since the first took its OF node and is no longer available
> * Third will succeed
> */
> static const struct mfd_cell mfd_of_test_cell[] = {
> OF_MFD_CELL("mfd-of-test-child", NULL, NULL, 0, 1, "mfd,of-test-child"),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 2, "mfd,of-test-child", 0xaaaaaaaaaaaaaaaa),
> OF_MFD_CELL_REG("mfd-of-test-child", NULL, NULL, 0, 3, "mfd,of-test-child", 0x00000000cccccccc)
> };
>
> The result:
>
> [0.753869] mfd-of-test-parent mfd_of_test: Registering 3 devices
> [0.756597] mfd-of-test-child: Failed to locate of_node [id: 2]
> [0.759999] mfd-of-test-child mfd-of-test-child.1: Probing platform device: 1
> [0.760314] mfd-of-test-child mfd-of-test-child.1: Using OF node: child@aaaaaaaaaaaaaaaa
> [0.760908] mfd-of-test-child mfd-of-test-child.2: Probing platform device: 2
> [0.761183] mfd-of-test-child mfd-of-test-child.2: No OF node associated with this device
> [0.761621] mfd-of-test-child mfd-of-test-child.3: Probing platform device: 3
> [0.761899] mfd-of-test-child mfd-of-test-child.3: Using OF node: child@cccccccc
>
> We could code around this with some pre-parsing semantics, but the
> added complexity required to cover each and every corner-case is not
> justified. Merely patching the current failing (via this patch) is
> already working with some pretty small corner-cases. Other issues
> should be patched in the parent drivers which can be achieved simply
> by implementing OF_MFD_CELL_REG().
>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
>
> Changelog:
>
> v1 => v2:
> * Simply return -EAGAIN if node is already in use
> * Allow for valid of_reg=0 by introducing use_of_reg boolean flag
> * Split helpers out into separate patch
>
> drivers/mfd/mfd-core.c | 99 +++++++++++++++++++++++++++++++++++-----
> include/linux/mfd/core.h | 10 ++++
> 2 files changed, 97 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> index e831e733b38cf..120803717b828 100644
> --- a/drivers/mfd/mfd-core.c
> +++ b/drivers/mfd/mfd-core.c
> @@ -10,6 +10,7 @@
> #include <linux/kernel.h>
> #include <linux/platform_device.h>
> #include <linux/acpi.h>
> +#include <linux/list.h>
> #include <linux/property.h>
> #include <linux/mfd/core.h>
> #include <linux/pm_runtime.h>
> @@ -17,8 +18,17 @@
> #include <linux/module.h>
> #include <linux/irqdomain.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/regulator/consumer.h>
>
> +static LIST_HEAD(mfd_of_node_list);
> +
> +struct mfd_of_node_entry {
> + struct list_head list;
> + struct device *dev;
> + struct device_node *np;
> +};
> +
> static struct device_type mfd_dev_type = {
> .name = "mfd_device",
> };
> @@ -107,6 +117,54 @@ static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
> }
> #endif
>
> +static int mfd_match_of_node_to_dev(struct platform_device *pdev,
> + struct device_node *np,
> + const struct mfd_cell *cell)
> +{
> + struct mfd_of_node_entry *of_entry;
> + const __be32 *reg;
> + u64 of_node_addr;
> +
> + /* Skip devices 'disabled' by Device Tree */
> + if (!of_device_is_available(np))
> + return -ENODEV;
> +
> + /* Skip if OF node has previously been allocated to a device */
> + list_for_each_entry(of_entry, &mfd_of_node_list, list)
> + if (of_entry->np == np)
> + return -EAGAIN;
> +
> + if (!cell->use_of_reg)
> + /* No of_reg defined - allocate first free compatible match */
> + goto allocate_of_node;
> +
> + /* We only care about each node's first defined address */
> + reg = of_get_address(np, 0, NULL, NULL);
> + if (!reg)
> + /* OF node does not contatin a 'reg' property to match to */
> + return -EAGAIN;
> +
> + of_node_addr = of_read_number(reg, of_n_addr_cells(np));
> +
> + if (cell->of_reg != of_node_addr)
> + /* No match */
> + return -EAGAIN;
> +
> +allocate_of_node:
> + of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
> + if (!of_entry)
> + return -ENOMEM;
> +
> + of_entry->dev = &pdev->dev;
> + of_entry->np = np;
> + list_add_tail(&of_entry->list, &mfd_of_node_list);
> +
> + pdev->dev.of_node = np;
> + pdev->dev.fwnode = &np->fwnode;
> +
> + return 0;
> +}
> +
> static int mfd_add_device(struct device *parent, int id,
> const struct mfd_cell *cell,
> struct resource *mem_base,
> @@ -115,6 +173,7 @@ static int mfd_add_device(struct device *parent, int id,
> struct resource *res;
> struct platform_device *pdev;
> struct device_node *np = NULL;
> + struct mfd_of_node_entry *of_entry, *tmp;
> int ret = -ENOMEM;
> int platform_id;
> int r;
> @@ -149,19 +208,22 @@ static int mfd_add_device(struct device *parent, int id,
> if (ret < 0)
> goto fail_res;
>
> - if (parent->of_node && cell->of_compatible) {
> + if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
> for_each_child_of_node(parent->of_node, np) {
> if (of_device_is_compatible(np, cell->of_compatible)) {
> - if (!of_device_is_available(np)) {
> - /* Ignore disabled devices error free */
> - ret = 0;
> + ret = mfd_match_of_node_to_dev(pdev, np, cell);
> + if (ret == -EAGAIN)
> + continue;
> + if (ret)
> goto fail_alias;
> - }
> - pdev->dev.of_node = np;
> - pdev->dev.fwnode = &np->fwnode;
> +
> break;
> }
> }
> +
> + if (!pdev->dev.of_node)
> + pr_warn("%s: Failed to locate of_node [id: %d]\n",
> + cell->name, platform_id);
> }
>
> mfd_acpi_add_device(cell, pdev);
> @@ -170,13 +232,13 @@ static int mfd_add_device(struct device *parent, int id,
> ret = platform_device_add_data(pdev,
> cell->platform_data, cell->pdata_size);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> if (cell->properties) {
> ret = platform_device_add_properties(pdev, cell->properties);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
>
> for (r = 0; r < cell->num_resources; r++) {
> @@ -213,18 +275,18 @@ static int mfd_add_device(struct device *parent, int id,
> if (has_acpi_companion(&pdev->dev)) {
> ret = acpi_check_resource_conflict(&res[r]);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
> }
> }
> }
>
> ret = platform_device_add_resources(pdev, res, cell->num_resources);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> ret = platform_device_add(pdev);
> if (ret)
> - goto fail_alias;
> + goto fail_of_entry;
>
> if (cell->pm_runtime_no_callbacks)
> pm_runtime_no_callbacks(&pdev->dev);
> @@ -233,6 +295,12 @@ static int mfd_add_device(struct device *parent, int id,
>
> return 0;
>
> +fail_of_entry:
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == &pdev->dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> fail_alias:
> regulator_bulk_unregister_supply_alias(&pdev->dev,
> cell->parent_supplies,
> @@ -287,6 +355,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> {
> struct platform_device *pdev;
> const struct mfd_cell *cell;
> + struct mfd_of_node_entry *of_entry, *tmp;
>
> if (dev->type != &mfd_dev_type)
> return 0;
> @@ -297,6 +366,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
> regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
> cell->num_parent_supplies);
>
> + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
> + if (of_entry->dev == dev) {
> + list_del(&of_entry->list);
> + kfree(of_entry);
> + }
> +
> kfree(cell);
>
> platform_device_unregister(pdev);
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index d01d1299e49dc..a148b907bb7f1 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -78,6 +78,16 @@ struct mfd_cell {
> */
> const char *of_compatible;
>
> + /*
> + * Address as defined in Device Tree. Used to compement 'of_compatible'
> + * (above) when matching OF nodes with devices that have identical
> + * compatible strings
> + */
> + const u64 of_reg;
> +
> + /* Set to 'true' to use 'of_reg' (above) - allows for of_reg=0 */
> + bool use_of_reg;
> +
> /* Matches ACPI */
> const struct mfd_cell_acpi_match *acpi_match;
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-23 23:03 ` Frank Rowand
@ 2020-06-24 6:41 ` Lee Jones
2020-06-24 7:47 ` Michael Walle
0 siblings, 1 reply; 25+ messages in thread
From: Lee Jones @ 2020-06-24 6:41 UTC (permalink / raw)
To: Frank Rowand
Cc: devicetree, gregkh, broonie, michael, linux-kernel,
andy.shevchenko, robh+dt, linux-arm-kernel, andriy.shevchenko,
robin.murphy, linus.walleij, linux
On Tue, 23 Jun 2020, Frank Rowand wrote:
> On 2020-06-11 14:10, Lee Jones wrote:
> > Currently, when a child platform device (sometimes referred to as a
> > sub-device) is registered via the Multi-Functional Device (MFD) API,
> > the framework attempts to match the newly registered platform device
> > with its associated Device Tree (OF) node. Until now, the device has
> > been allocated the first node found with an identical OF compatible
> > string. Unfortunately, if there are, say for example '3' devices
> > which are to be handled by the same driver and therefore have the same
> > compatible string, each of them will be allocated a pointer to the
> > *first* node.
>
> As you mentioned elsewhere in this thread, this series "fixes" the
> problem related to the "stericsson,ab8500-pwm" compatible.
>
> I know, I said I would drop discussion of that compatible, but bear
> with me for a second. :-)
>
> The "problem" is that the devices for multiple mfd child nodes with
> the same compatible value of "stericsson,ab8500-pwm" will all have
> a pointer to the first child node. At the moment the same child
> of_node being used by more than one device does not cause any
> incorrect behavior.
>
> Just in case the driver for "stericsson,ab8500-pwm" is modified
> in a way that the child of_node needs to be distinct for each
> device, and that changes gets back ported, it would be useful
> to have Fixes: tags for this patch series.
>
> So, at your discretion (and I'll let you worry about the correct
> Fixes: tag format), this series fixes:
>
> bad76991d7847b7877ae797cc79745d82ffd9120 mfd: Register ab8500 devices using the newly DT:ed MFD API
This patch isn't actually broken.
The issue is the DTB, which [0] addresses.
[0]
https://lkml.kernel.org/lkml/20200622083432.1491715-1-lee.jones@linaro.org/
> c94bb233a9fee3314dc5d9c7de9fa702e91283f2 mfd: Make MFD core code Device Tree and IRQ domain aware
It sounds reasonable to list this one, thanks.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-24 6:41 ` Lee Jones
@ 2020-06-24 7:47 ` Michael Walle
2020-06-24 8:23 ` Lee Jones
0 siblings, 1 reply; 25+ messages in thread
From: Michael Walle @ 2020-06-24 7:47 UTC (permalink / raw)
To: Lee Jones
Cc: devicetree, robin.murphy, broonie, linux-kernel, andy.shevchenko,
robh+dt, linux-arm-kernel, gregkh, andriy.shevchenko,
Frank Rowand, linus.walleij, linux
Hi,
Am 2020-06-24 08:41, schrieb Lee Jones:
> On Tue, 23 Jun 2020, Frank Rowand wrote:
>
>> On 2020-06-11 14:10, Lee Jones wrote:
>> > Currently, when a child platform device (sometimes referred to as a
>> > sub-device) is registered via the Multi-Functional Device (MFD) API,
>> > the framework attempts to match the newly registered platform device
>> > with its associated Device Tree (OF) node. Until now, the device has
>> > been allocated the first node found with an identical OF compatible
>> > string. Unfortunately, if there are, say for example '3' devices
>> > which are to be handled by the same driver and therefore have the same
>> > compatible string, each of them will be allocated a pointer to the
>> > *first* node.
>>
>> As you mentioned elsewhere in this thread, this series "fixes" the
>> problem related to the "stericsson,ab8500-pwm" compatible.
>>
>> I know, I said I would drop discussion of that compatible, but bear
>> with me for a second. :-)
>>
>> The "problem" is that the devices for multiple mfd child nodes with
>> the same compatible value of "stericsson,ab8500-pwm" will all have
>> a pointer to the first child node. At the moment the same child
>> of_node being used by more than one device does not cause any
>> incorrect behavior.
>>
>> Just in case the driver for "stericsson,ab8500-pwm" is modified
>> in a way that the child of_node needs to be distinct for each
>> device, and that changes gets back ported, it would be useful
>> to have Fixes: tags for this patch series.
>>
>> So, at your discretion (and I'll let you worry about the correct
>> Fixes: tag format), this series fixes:
>>
>> bad76991d7847b7877ae797cc79745d82ffd9120 mfd: Register ab8500 devices
>> using the newly DT:ed MFD API
>
> This patch isn't actually broken.
>
> The issue is the DTB, which [0] addresses.
>
> [0]
> https://lkml.kernel.org/lkml/20200622083432.1491715-1-lee.jones@linaro.org/
Now, I'm confused; because this patch doesn't use the reg property
but a different node name. I'd actually prefer this for any MFD
driver which has multiple nodes of the same compatible string. See
my reasoning here [1]. But until now, no one has responded. Thus,
I'd rather see a OF_MFD_CELL_NAME() which matches the node name
instead of the OF_MFD_CELL_REG() macro.
This would also circumvent the fact that the unit-address has one
number space. Eg. it is not possible to have:
mfd {
compatible = "mfd,compatible";
gpio@0 {
reg = <0>;
};
gpio@1 {
reg = <1>;
};
pwm@0 {
reg = <0>;
};
};
Although Rob mentioned to maybe relax that, but I sill fail to see
the advantage to have an arbitrary reg property instead of a unique
node name.
[1]
https://lore.kernel.org/linux-devicetree/0709f20bc61afb6656bc57312eb69f56@walle.cc/
--
-michael
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-24 7:47 ` Michael Walle
@ 2020-06-24 8:23 ` Lee Jones
2020-06-24 9:19 ` Michael Walle
0 siblings, 1 reply; 25+ messages in thread
From: Lee Jones @ 2020-06-24 8:23 UTC (permalink / raw)
To: Michael Walle
Cc: devicetree, robin.murphy, broonie, linux-kernel, andy.shevchenko,
robh+dt, linux-arm-kernel, gregkh, andriy.shevchenko,
Frank Rowand, linus.walleij, linux
On Wed, 24 Jun 2020, Michael Walle wrote:
> Hi,
>
> Am 2020-06-24 08:41, schrieb Lee Jones:
> > On Tue, 23 Jun 2020, Frank Rowand wrote:
> >
> > > On 2020-06-11 14:10, Lee Jones wrote:
> > > > Currently, when a child platform device (sometimes referred to as a
> > > > sub-device) is registered via the Multi-Functional Device (MFD) API,
> > > > the framework attempts to match the newly registered platform device
> > > > with its associated Device Tree (OF) node. Until now, the device has
> > > > been allocated the first node found with an identical OF compatible
> > > > string. Unfortunately, if there are, say for example '3' devices
> > > > which are to be handled by the same driver and therefore have the same
> > > > compatible string, each of them will be allocated a pointer to the
> > > > *first* node.
> > >
> > > As you mentioned elsewhere in this thread, this series "fixes" the
> > > problem related to the "stericsson,ab8500-pwm" compatible.
> > >
> > > I know, I said I would drop discussion of that compatible, but bear
> > > with me for a second. :-)
> > >
> > > The "problem" is that the devices for multiple mfd child nodes with
> > > the same compatible value of "stericsson,ab8500-pwm" will all have
> > > a pointer to the first child node. At the moment the same child
> > > of_node being used by more than one device does not cause any
> > > incorrect behavior.
> > >
> > > Just in case the driver for "stericsson,ab8500-pwm" is modified
> > > in a way that the child of_node needs to be distinct for each
> > > device, and that changes gets back ported, it would be useful
> > > to have Fixes: tags for this patch series.
> > >
> > > So, at your discretion (and I'll let you worry about the correct
> > > Fixes: tag format), this series fixes:
> > >
> > > bad76991d7847b7877ae797cc79745d82ffd9120 mfd: Register ab8500
> > > devices using the newly DT:ed MFD API
> >
> > This patch isn't actually broken.
> >
> > The issue is the DTB, which [0] addresses.
> >
> > [0]
> > https://lkml.kernel.org/lkml/20200622083432.1491715-1-lee.jones@linaro.org/
>
> Now, I'm confused; because this patch doesn't use the reg property
> but a different node name.
The fix mentioned above is orthogonal to this set.
The *only* reason for the differing node names there is to circumvent
the following DTC warnings:
arch/arm/boot/dts/ste-ab8500.dtsi:210.16-214.7: ERROR (duplicate_node_names): /soc/prcmu@80157000/ab8500/ab8500-pwm: Duplicate node name
arch/arm/boot/dts/ste-ab8500.dtsi:216.16-220.7: ERROR (duplicate_node_names): /soc/prcmu@80157000/ab8500/ab8500-pwm: Duplicate node name
arch/arm/boot/dts/ste-ab8500.dtsi:216.16-220.7: ERROR (duplicate_node_names): /soc/prcmu@80157000/ab8500/ab8500-pwm: Duplicate node name
> I'd actually prefer this for any MFD
> driver which has multiple nodes of the same compatible string. See
> my reasoning here [1]. But until now, no one has responded. Thus,
> I'd rather see a OF_MFD_CELL_NAME() which matches the node name
> instead of the OF_MFD_CELL_REG() macro.
>
> This would also circumvent the fact that the unit-address has one
> number space. Eg. it is not possible to have:
>
> mfd {
> compatible = "mfd,compatible";
>
> gpio@0 {
> reg = <0>;
> };
> gpio@1 {
> reg = <1>;
> };
> pwm@0 {
> reg = <0>;
> };
> };
>
> Although Rob mentioned to maybe relax that, but I sill fail to see
> the advantage to have an arbitrary reg property instead of a unique
> node name.
I don't have a strong opinion either way.
We can *also* add node name matching if Rob deems it fit.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-24 8:23 ` Lee Jones
@ 2020-06-24 9:19 ` Michael Walle
2020-06-24 11:24 ` Lee Jones
0 siblings, 1 reply; 25+ messages in thread
From: Michael Walle @ 2020-06-24 9:19 UTC (permalink / raw)
To: Lee Jones
Cc: devicetree, robin.murphy, broonie, linux-kernel, andy.shevchenko,
robh+dt, linux-arm-kernel, gregkh, andriy.shevchenko,
Frank Rowand, linus.walleij, linux
Am 2020-06-24 10:23, schrieb Lee Jones:
> On Wed, 24 Jun 2020, Michael Walle wrote:
[..]
>> Although Rob mentioned to maybe relax that, but I sill fail to see
>> the advantage to have an arbitrary reg property instead of a unique
>> node name.
>
> I don't have a strong opinion either way.
>
> We can *also* add node name matching if Rob deems it fit.
Where do you see a use of the reg property? You already expressed
that you see exposing the internal offset as a hack:
"Placing "internal offsets" into the 'reg' property is a hack." [1]
So what are you putting into reg instead? Rob suggested "anything"
documented in the hardware manual. But isn't this just also something
we make up and especially for the MFD driver. Thus IMHO it doesn't
qualify as a unit-address, which - as far as I understand it - is
unique on the parent bus. To repeat my argument, its not a defined
thing like an I2C address.
[1] https://lore.kernel.org/linux-devicetree/20200609185231.GO4106@dell/
-michael
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2 1/3] mfd: core: Make a best effort attempt to match devices with the correct of_nodes
2020-06-24 9:19 ` Michael Walle
@ 2020-06-24 11:24 ` Lee Jones
0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2020-06-24 11:24 UTC (permalink / raw)
To: Michael Walle
Cc: devicetree, robin.murphy, broonie, linux-kernel, andy.shevchenko,
robh+dt, linux-arm-kernel, gregkh, andriy.shevchenko,
Frank Rowand, linus.walleij, linux
On Wed, 24 Jun 2020, Michael Walle wrote:
> Am 2020-06-24 10:23, schrieb Lee Jones:
> > On Wed, 24 Jun 2020, Michael Walle wrote:
>
> [..]
>
> > > Although Rob mentioned to maybe relax that, but I sill fail to see
> > > the advantage to have an arbitrary reg property instead of a unique
> > > node name.
> >
> > I don't have a strong opinion either way.
> >
> > We can *also* add node name matching if Rob deems it fit.
>
> Where do you see a use of the reg property?
The vast proportion of devices do and will have 'reg' properties.
> You already expressed
> that you see exposing the internal offset as a hack:
>
> "Placing "internal offsets" into the 'reg' property is a hack." [1]
>
> So what are you putting into reg instead? Rob suggested "anything"
> documented in the hardware manual. But isn't this just also something
> we make up and especially for the MFD driver. Thus IMHO it doesn't
> qualify as a unit-address, which - as far as I understand it - is
> unique on the parent bus. To repeat my argument, its not a defined
> thing like an I2C address.
So our argument in the past (although this is going back the best part
of 10 years) has always been that; if devices are different, there is
almost always a documented (in the H/W manual/datasheet) way to
differentiate/address them. Whether that's a physical address, an
offset, a bank ID, an I2C/SPI address or whatever.
As to not being able to use that address/ID due to the DT rules
surrounding address space as per the example in your previous email,
well that's a rule specific to DT and makes little sense in some real
world cases (such as, dare I say it, the AB8500).
You'll have to take the aforementioned point and the point about using
node names instead of 'reg' properties up with Rob and the other
interested DT folk.
Again, I'm happy to extend that functionality if it becomes acceptable
practice.
> [1] https://lore.kernel.org/linux-devicetree/20200609185231.GO4106@dell/
>
> -michael
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 25+ messages in thread