All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lee Jones <lee.jones@linaro.org>
To: Michael Walle <michael@walle.cc>
Cc: devicetree@vger.kernel.org, gregkh@linuxfoundation.org,
	broonie@kernel.org, linux-kernel@vger.kernel.org,
	andy.shevchenko@gmail.com, robh+dt@kernel.org,
	linux-arm-kernel@lists.infradead.org,
	andriy.shevchenko@linux.intel.com, robin.murphy@arm.com,
	linus.walleij@linaro.org, linux@roeck-us.net
Subject: Re: [SPAM] [PATCH 1/1] mfd: Make a best effort attempt to match devices with the correct of_nodes
Date: Thu, 11 Jun 2020 11:57:48 +0100	[thread overview]
Message-ID: <20200611105748.GX4106@dell> (raw)
In-Reply-To: <79ec43b375e075cde0ed33b9dd902e75@walle.cc>

On Thu, 11 Jun 2020, Michael Walle wrote:

> Am 2020-06-11 10:56, schrieb Lee Jones:
> > 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)
> 
> Why would anyone do that? Mix and match OF_MFD_CELL() and OF_MFD_CELL_REG()
> on the same compatible string?

See above:

  "(note: the implementation here is convoluted, but it shows you one
   means by which this process can still break)"

> Wouldn't it be easier to check that there is
> no OF_MFD_CELL() when OF_MFD_CELL_REG() is used, instead of keeping a global
> list?

See below:

  "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()."

If the API isn't used properly, things will break.

We can't prevent every erroneous corner-case.

> >   };
> > 
> > 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>
> > ---
> >  drivers/mfd/mfd-core.c   | 102 ++++++++++++++++++++++++++++++++++-----
> >  include/linux/mfd/core.h |  33 ++++++++-----
> >  2 files changed, 113 insertions(+), 22 deletions(-)
> > 
> > diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> > index f5a73af60dd40..ecd5494c84747 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,59 @@ 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;
> > +	bool of_node_used;
> > +
> > +	/* 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 */
> > +	of_node_used = false;
> > +	list_for_each_entry(of_entry, &mfd_of_node_list, list)
> > +		if (of_entry->np == np)
> just return -EAGAIN here?

You're right.  This is legacy from before this was its own function
and a straight 'continue' would have just moved to the next
list_for_each_entry() list item.

Will fix.

> > +			of_node_used = true;
> > +
> > +	if (of_node_used)
> > +		return -EAGAIN;
> > +
> > +	if (!cell->of_reg)
> 
> This doesn't work if the address is actually 0. My original patch used a
> flag to detect if of_reg is actually set/used.

Good point.  Will fix.

> > +		/* No match defined - allocate the first free matching node */
> > +		goto allocate_of_node;
> > +
> > +	/* We only care about each node's first defined address */
> > +	reg = of_get_address(np, 0, NULL, NULL);
> 
> Does of_get_address() work with any (internal) addresses?

What is an internal address?

-- 
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

  reply	other threads:[~2020-06-11 10:58 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-11  8:56 [PATCH 1/1] mfd: Make a best effort attempt to match devices with the correct of_nodes Lee Jones
2020-06-11  8:56 ` Lee Jones
2020-06-11 10:07 ` [SPAM] " Michael Walle
2020-06-11 10:57   ` Lee Jones [this message]
2020-06-11 12:18     ` Michael Walle
2020-06-11 12:55       ` Lee Jones
2020-06-11 11:42 ` kernel test robot
2020-06-11 11:42   ` kernel test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200611105748.GX4106@dell \
    --to=lee.jones@linaro.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=andy.shevchenko@gmail.com \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=michael@walle.cc \
    --cc=robh+dt@kernel.org \
    --cc=robin.murphy@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.