Message ID | 20240822092006.3134096-1-wenst@chromium.org |
---|---|
Headers | show |
Series | platform/chrome: Introduce DT hardware prober | expand |
On Thu, Aug 22, 2024 at 4:20 AM Chen-Yu Tsai <wenst@chromium.org> wrote: > > Add a helper function to add string property updates to an OF changeset. > This is similar to of_changeset_add_prop_string(), but instead of adding > the property (and failing if it exists), it will update the property. > > This shall be used later in the DT hardware prober. > > Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> > --- > Changes since v4: > - Use modern designated initializer for |prop| > > Changes since v3: > - Use new __of_prop_free() helper > - Add new line before header declaration > > Changes since v2: > - New patch added in v3 > --- > drivers/of/dynamic.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/of.h | 4 ++++ > 2 files changed, 48 insertions(+) Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
On Thu, Aug 22, 2024 at 05:20:00PM +0800, Chen-Yu Tsai wrote: > This adds regulator management to the I2C OF component prober. > Components that the prober intends to probe likely require their > regulator supplies be enabled, and GPIOs be toggled to enable them or > bring them out of reset before they will respond to probe attempts. > GPIOs will be handled in the next patch. > > Without specific knowledge of each component's resource names or > power sequencing requirements, the prober can only enable the > regulator supplies all at once, and toggle the GPIOs all at once. > Luckily, reset pins tend to be active low, while enable pins tend to > be active high, so setting the raw status of all GPIO pins to high > should work. The wait time before and after resources are enabled > are collected from existing drivers and device trees. > > The prober collects resources from all possible components and enables > them together, instead of enabling resources and probing each component > one by one. The latter approach does not provide any boot time benefits > over simply enabling each component and letting each driver probe > sequentially. > > The prober will also deduplicate the resources, since on a component > swap out or co-layout design, the resources are always the same. > While duplicate regulator supplies won't cause much issue, shared > GPIOs don't work reliably, especially with other drivers. For the > same reason, the prober will release the GPIOs before the successfully > probed component is actually enabled. ... > /* > * address responds. > * > * TODO: > - * - Support handling common regulators and GPIOs. > + * - Support handling common GPIOs. You can split this to two lines in the first place and have less churn in this patch and the other one. > * - Support I2C muxes > */ .. > +/* Returns number of regulator supplies found for node, or error. */ > +static int i2c_of_probe_get_regulator(struct device *dev, struct device_node *node, > + struct i2c_of_probe_data *data) > +{ > + struct regulator_bulk_data *tmp, *new_regulators; > + int ret; > + > + ret = of_regulator_bulk_get_all(dev, node, &tmp); > + if (ret <= 0) > + return ret; I would split this and explain 0 case. > + if (!data->regulators) { > + data->regulators = tmp; > + data->regulators_num = ret; > + return ret; > + }; > + > + new_regulators = krealloc(data->regulators, > + sizeof(*tmp) * (data->regulators_num + ret), krealloc_array() > + GFP_KERNEL); > + if (!new_regulators) { > + regulator_bulk_free(ret, tmp); > + return -ENOMEM; > + } > + > + data->regulators = new_regulators; > + for (unsigned int i = 0; i < ret; i++) > + memcpy(&data->regulators[data->regulators_num++], &tmp[i], sizeof(*tmp)); Seems like copying array to array, no? If so, can't be done in a single memcpy() call? > + return ret; > +} ... > +static int i2c_of_probe_get_res(struct device *dev, struct device_node *node, > + struct i2c_of_probe_data *data) > +{ > + struct property *prop; > + int ret; > + > + ret = i2c_of_probe_get_regulator(dev, node, data); > + if (ret < 0) { > + dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node); > + goto err_cleanup; > + } > + > + return 0; > + > +err_cleanup: > + i2c_of_probe_free_res(data); > + return ret; > +} Hmm... why not static int i2c_of_probe_get_res(struct device *dev, struct device_node *node, struct i2c_of_probe_data *data) { struct property *prop; int ret; ret = i2c_of_probe_get_regulator(dev, node, data); if (ret < 0) { i2c_of_probe_free_res(data); return dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node); } return 0; } ... > +static int i2c_of_probe_enable_res(struct device *dev, struct i2c_of_probe_data *data) > +{ > + int ret = 0; Redundant assignment. > + dev_dbg(dev, "Enabling regulator supplies\n"); > + > + ret = regulator_bulk_enable(data->regulators_num, data->regulators); > + if (ret) > + return ret; > + > + /* largest post-power-on pre-reset-deassert delay seen among drivers */ > + msleep(500); How would we monitor if any [new] driver wants to use bigger timeout? > + return 0; > +} ... > struct i2c_adapter *i2c; > + struct i2c_of_probe_data probe_data = {0}; Reversed xmas tree order? '0' is not needed. ... > + /* Grab resources */ > + for_each_child_of_node_scoped(i2c_node, node) { > + u32 addr; > + > + if (!of_node_name_prefix(node, type)) > + continue; Is it third or fourth copy of this code? At some point you probably want #define for_each_child_of_node_with_prefix_scoped() for_each_if(...) (or equivalent) > + if (of_property_read_u32(node, "reg", &addr)) > + continue; > + > + dev_dbg(dev, "Requesting resources for %pOF\n", node); > + ret = i2c_of_probe_get_res(dev, node, &probe_data); > + if (ret) > + return ret; > + }
On Thu, Aug 22, 2024 at 05:19:58PM +0800, Chen-Yu Tsai wrote: > The I2C device tree component prober needs to get and toggle GPIO lines > for the components it intends to probe. These components may not use the > same name for their GPIO lines, so the prober must go through the device > tree, check each property to see it is a GPIO property, and get the GPIO > line. > > Instead of duplicating the GPIO suffixes, or exporting them to the > prober to do pattern matching, simply add and export a new function that > does the pattern matching and returns the length of the GPIO name. The > caller can then use that to copy out the name if it needs to. ... > +/** > + * gpio_property_name_length - Returns the GPIO name length from a property name > + * @str: string to check It's property name, so, I would name this 'propname'. > + * This function checks if the given name matches the GPIO property patterns, and > + * returns the length of the name of the GPIO. The pattern is "*-<GPIO suffix>" > + * or just "<GPIO suffix>". > + * > + * Returns: > + * The length of the string before '-' if it matches "*-<GPIO suffix>", or What about "x-y-gpios"? It's unclear what will be the behaviour. > + * 0 if no name part, just the suffix, or > + * -EINVAL if the string doesn't match the pattern. > + */ > +int gpio_property_name_length(const char *str) gpio_get_... ? > +{ > + size_t len; > + > + len = strlen(str); If it has a thousands characters...? > + /* string need to be at minimum len(gpio) */ > + if (len < 4) > + return -EINVAL; Do we really need it here? See below as well. > + /* Check for no-name case: "gpio" / "gpios" */ > + for (const char *const *p = gpio_suffixes; *p; p++) > + if (!strcmp(str, *p)) > + return 0; > + for (size_t i = len - 4; i > 0; i--) { > + /* find right-most '-' and check if remainder matches suffix */ > + if (str[i] != '-') > + continue; > + > + for (const char *const *p = gpio_suffixes; *p; p++) > + if (!strcmp(str + i + 1, *p)) > + return i; > + > + return -EINVAL; > + } This can be combined with the above for (const char *const *p = gpio_suffixes; *p; p++) { /* * Find right-most '-' and check if remainder matches suffix. * If no separator found, check for no-name cases. */ dash = strrchr(propname, '-'); if (!strcmp(dash ? dash + 1 : propname, *p)) return i; } > + return -EINVAL; > +}
On Thu, Aug 22, 2024 at 10:37 PM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote: > > On Thu, Aug 22, 2024 at 05:19:58PM +0800, Chen-Yu Tsai wrote: > > The I2C device tree component prober needs to get and toggle GPIO lines > > for the components it intends to probe. These components may not use the > > same name for their GPIO lines, so the prober must go through the device > > tree, check each property to see it is a GPIO property, and get the GPIO > > line. > > > > Instead of duplicating the GPIO suffixes, or exporting them to the > > prober to do pattern matching, simply add and export a new function that > > does the pattern matching and returns the length of the GPIO name. The > > caller can then use that to copy out the name if it needs to. > > ... > > > +/** > > + * gpio_property_name_length - Returns the GPIO name length from a property name > > + * @str: string to check > > It's property name, so, I would name this 'propname'. Ack. > > + * This function checks if the given name matches the GPIO property patterns, and > > + * returns the length of the name of the GPIO. The pattern is "*-<GPIO suffix>" > > + * or just "<GPIO suffix>". > > + * > > + * Returns: > > + * The length of the string before '-' if it matches "*-<GPIO suffix>", or > > What about "x-y-gpios"? It's unclear what will be the behaviour. I thought it was implied that the '-' mentioned here is the one before the suffix. I made it more explicit. > > + * 0 if no name part, just the suffix, or > > + * -EINVAL if the string doesn't match the pattern. > > + */ > > +int gpio_property_name_length(const char *str) > > gpio_get_... ? Ack. > > +{ > > + size_t len; > > + > > + len = strlen(str); > > If it has a thousands characters...? Shouldn't matter much? I suppose using strrchr() as you suggested requires one less pass. > > + /* string need to be at minimum len(gpio) */ > > + if (len < 4) > > + return -EINVAL; > > Do we really need it here? See below as well. > > > + /* Check for no-name case: "gpio" / "gpios" */ > > + for (const char *const *p = gpio_suffixes; *p; p++) > > + if (!strcmp(str, *p)) > > + return 0; > > > + for (size_t i = len - 4; i > 0; i--) { > > + /* find right-most '-' and check if remainder matches suffix */ > > + if (str[i] != '-') > > + continue; > > + > > + for (const char *const *p = gpio_suffixes; *p; p++) > > + if (!strcmp(str + i + 1, *p)) > > + return i; > > + > > + return -EINVAL; > > + } > > This can be combined with the above > > for (const char *const *p = gpio_suffixes; *p; p++) { > /* > * Find right-most '-' and check if remainder matches suffix. > * If no separator found, check for no-name cases. > */ > dash = strrchr(propname, '-'); I believe this line could be moved out of the for-loop. Otherwise it looks much more concise compared to my version. I'll omit the comment though, as it is just rehashing the kerneldoc description, and now that the function is so short, it shouldn't be hard to read. I'll add you as "Suggested-by". Thanks ChenYu > if (!strcmp(dash ? dash + 1 : propname, *p)) > return i; > } > > > + return -EINVAL; > > +} > > -- > With Best Regards, > Andy Shevchenko > >
On Thu, Aug 22, 2024 at 10:09 PM Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote: > > On Thu, Aug 22, 2024 at 05:20:00PM +0800, Chen-Yu Tsai wrote: > > This adds regulator management to the I2C OF component prober. > > Components that the prober intends to probe likely require their > > regulator supplies be enabled, and GPIOs be toggled to enable them or > > bring them out of reset before they will respond to probe attempts. > > GPIOs will be handled in the next patch. > > > > Without specific knowledge of each component's resource names or > > power sequencing requirements, the prober can only enable the > > regulator supplies all at once, and toggle the GPIOs all at once. > > Luckily, reset pins tend to be active low, while enable pins tend to > > be active high, so setting the raw status of all GPIO pins to high > > should work. The wait time before and after resources are enabled > > are collected from existing drivers and device trees. > > > > The prober collects resources from all possible components and enables > > them together, instead of enabling resources and probing each component > > one by one. The latter approach does not provide any boot time benefits > > over simply enabling each component and letting each driver probe > > sequentially. > > > > The prober will also deduplicate the resources, since on a component > > swap out or co-layout design, the resources are always the same. > > While duplicate regulator supplies won't cause much issue, shared > > GPIOs don't work reliably, especially with other drivers. For the > > same reason, the prober will release the GPIOs before the successfully > > probed component is actually enabled. > > ... > > > /* > > > * address responds. > > * > > * TODO: > > - * - Support handling common regulators and GPIOs. > > + * - Support handling common GPIOs. > > You can split this to two lines in the first place and have less churn in this > patch and the other one. Ack. > > * - Support I2C muxes > > */ > > .. > > > +/* Returns number of regulator supplies found for node, or error. */ > > +static int i2c_of_probe_get_regulator(struct device *dev, struct device_node *node, > > + struct i2c_of_probe_data *data) > > +{ > > + struct regulator_bulk_data *tmp, *new_regulators; > > + int ret; > > + > > + ret = of_regulator_bulk_get_all(dev, node, &tmp); > > + if (ret <= 0) > > + return ret; > > I would split this and explain 0 case. Ack. > > + if (!data->regulators) { > > + data->regulators = tmp; > > + data->regulators_num = ret; > > + return ret; > > + }; > > + > > + new_regulators = krealloc(data->regulators, > > + sizeof(*tmp) * (data->regulators_num + ret), > > krealloc_array() Ack. Somehow I didn't find this function while I was rewriting the code. > > + GFP_KERNEL); > > + if (!new_regulators) { > > + regulator_bulk_free(ret, tmp); > > + return -ENOMEM; > > + } > > + > > + data->regulators = new_regulators; > > > + for (unsigned int i = 0; i < ret; i++) > > + memcpy(&data->regulators[data->regulators_num++], &tmp[i], sizeof(*tmp)); > > Seems like copying array to array, no? If so, can't be done in a single memcpy() call? Ack. > > + return ret; > > +} > > ... > > > +static int i2c_of_probe_get_res(struct device *dev, struct device_node *node, > > + struct i2c_of_probe_data *data) > > +{ > > + struct property *prop; > > + int ret; > > + > > + ret = i2c_of_probe_get_regulator(dev, node, data); > > + if (ret < 0) { > > + dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node); > > + goto err_cleanup; > > + } > > + > > + return 0; > > + > > +err_cleanup: > > + i2c_of_probe_free_res(data); > > + return ret; > > +} > > Hmm... why not > > static int i2c_of_probe_get_res(struct device *dev, struct device_node *node, > struct i2c_of_probe_data *data) > { > struct property *prop; > int ret; > > ret = i2c_of_probe_get_regulator(dev, node, data); > if (ret < 0) { > i2c_of_probe_free_res(data); > return dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node); > } > > return 0; > } > > ... That would be more churn in the next patch, which introduces another error condition requiring the same cleanup. > > +static int i2c_of_probe_enable_res(struct device *dev, struct i2c_of_probe_data *data) > > +{ > > + int ret = 0; > > Redundant assignment. Ack. > > + dev_dbg(dev, "Enabling regulator supplies\n"); > > + > > + ret = regulator_bulk_enable(data->regulators_num, data->regulators); > > + if (ret) > > + return ret; > > + > > + /* largest post-power-on pre-reset-deassert delay seen among drivers */ > > + msleep(500); > > How would we monitor if any [new] driver wants to use bigger timeout? The assumption is that the person doing the integration should test for this. This prober doesn't get called everywhere. It needs a driver to call it, and that driver is written by someone for some specific platform. Maybe I should explicitly spell that out in the function description? Or even make it a parameter? Also, having an arbitrarily large number here doesn't help platforms that want to minimize boot time. On that front I'm also thinking about whether it is possible to do a handover to the actual driver so that the latter doesn't have to go through the whole power sequence again. > > + return 0; > > +} > > ... > > > struct i2c_adapter *i2c; > > + struct i2c_of_probe_data probe_data = {0}; > > Reversed xmas tree order? OK... > '0' is not needed. Ack. > ... > > > + /* Grab resources */ > > + for_each_child_of_node_scoped(i2c_node, node) { > > + u32 addr; > > + > > + if (!of_node_name_prefix(node, type)) > > + continue; > > Is it third or fourth copy of this code? At some point you probably want > > #define for_each_child_of_node_with_prefix_scoped() > for_each_if(...) > > (or equivalent) Ack. Thank you for the review. ChenYu > > + if (of_property_read_u32(node, "reg", &addr)) > > + continue; > > + > > + dev_dbg(dev, "Requesting resources for %pOF\n", node); > > + ret = i2c_of_probe_get_res(dev, node, &probe_data); > > + if (ret) > > + return ret; > > + } > > -- > With Best Regards, > Andy Shevchenko > >
On Fri, Aug 23, 2024 at 03:50:55PM +0800, Chen-Yu Tsai wrote: > On Thu, Aug 22, 2024 at 10:37 PM Andy Shevchenko > <andriy.shevchenko@linux.intel.com> wrote: > > On Thu, Aug 22, 2024 at 05:19:58PM +0800, Chen-Yu Tsai wrote: ... > > > + len = strlen(str); > > > > If it has a thousands characters...? > > Shouldn't matter much? I suppose using strrchr() as you suggested > requires one less pass. Yes, this is the point. ... > > This can be combined with the above > > > > for (const char *const *p = gpio_suffixes; *p; p++) { > > /* > > * Find right-most '-' and check if remainder matches suffix. > > * If no separator found, check for no-name cases. > > */ > > dash = strrchr(propname, '-'); > > I believe this line could be moved out of the for-loop. Otherwise it > looks much more concise compared to my version. I'll omit the comment > though, as it is just rehashing the kerneldoc description, and now > that the function is so short, it shouldn't be hard to read. Agree. And I put comment inside the loop, while it should be outside. But then, as you said, the function becomes so little that kernel-doc above does the job, hence no comment in the code needed. > I'll add you as "Suggested-by". Fine with me. > > if (!strcmp(dash ? dash + 1 : propname, *p)) > > return i; > > }
On Fri, Aug 23, 2024 at 05:35:59PM +0800, Chen-Yu Tsai wrote: > On Thu, Aug 22, 2024 at 10:09 PM Andy Shevchenko > <andriy.shevchenko@linux.intel.com> wrote: > > On Thu, Aug 22, 2024 at 05:20:00PM +0800, Chen-Yu Tsai wrote: ... > > Hmm... why not > > > > static int i2c_of_probe_get_res(struct device *dev, struct device_node *node, > > struct i2c_of_probe_data *data) > > { > > struct property *prop; > > int ret; > > > > ret = i2c_of_probe_get_regulator(dev, node, data); > > if (ret < 0) { > > i2c_of_probe_free_res(data); > > return dev_err_probe(dev, ret, "Failed to get regulator supplies from %pOF\n", node); > > } > > > > return 0; > > } > > That would be more churn in the next patch, which introduces another > error condition requiring the same cleanup. OK! ... > > > + /* largest post-power-on pre-reset-deassert delay seen among drivers */ > > > + msleep(500); > > > > How would we monitor if any [new] driver wants to use bigger timeout? > > The assumption is that the person doing the integration should test for > this. This prober doesn't get called everywhere. It needs a driver to > call it, and that driver is written by someone for some specific platform. > Maybe I should explicitly spell that out in the function description? > Or even make it a parameter? > > Also, having an arbitrarily large number here doesn't help platforms that > want to minimize boot time. On that front I'm also thinking about whether > it is possible to do a handover to the actual driver so that the latter > doesn't have to go through the whole power sequence again. Yeah, I think the best effort is to have a parameter.