Message ID | 20210503145750.v6.1.Ib7e3a4af2f3e2cb3bd8e4adbac3bcfc966f27791@changeid |
---|---|
State | New |
Headers | show |
Series | [v6,1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node | expand |
Hi, On Mon, May 3, 2021 at 2:59 PM Douglas Anderson <dianders@chromium.org> wrote: > > The of_find_i2c_adapter_by_node() could end up failing to find an > adapter in certain conditions. Specifically it's possible that > of_dev_or_parent_node_match() could end up finding an I2C client in > the list and cause bus_find_device() to stop early even though an I2C > adapter was present later in the list. > > Let's move the i2c_verify_adapter() into the predicate function to > prevent this. Now we'll properly skip over the I2C client and be able > to find the I2C adapter. > > This issue has always been a potential problem if a single device tree > node could represent both an I2C client and an adapter. I believe this > is a sane thing to do if, for instance, an I2C-connected DP bridge > chip is present. The bridge chip is an I2C client but it can also > provide an I2C adapter (DDC tunneled over AUX channel). We don't want > to have to create a sub-node just so a panel can link to it with the > "ddc-i2c-bus" property. > > I believe that this problem got worse, however, with commit > e814e688413a ("i2c: of: Try to find an I2C adapter matching the > parent"). Starting at that commit it would be even easier to > accidentally miss finding the adapter. > > Signed-off-by: Douglas Anderson <dianders@chromium.org> > Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> > --- > Later patches in this series won't work right without this one, but > they won't crash. If we can't find the i2c bus we'll just fall back to > the hardcoded panel modes which, at least today, all panels have. > > I'll also note that part of me wonders if we should actually fix this > further to run two passes through everything: first look to see if we > find an exact match and only look at the parent pointer if there is no > match. I don't currently have a need for that and it's a slightly > bigger change, but it seems conceivable that it could affect someone? > > (no changes since v1) > > drivers/i2c/i2c-core-of.c | 17 ++++++++++------- > 1 file changed, 10 insertions(+), 7 deletions(-) FYI that I've just posted v7 of this series and I've dropped ${SUBJECT} patch from my series. I think that ${SUBJECT} patch is still correct and could be useful to land, but it's no longer needed by my series since I'm getting access to the DDC bus in a different way. If this patch needs to be spun, please let me know. ...or, feel free to land it! :-) -Doug
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 3ed74aa4b44b..de0bf5fce3a2 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -124,6 +124,14 @@ static int of_dev_or_parent_node_match(struct device *dev, const void *data) return 0; } +static int of_i2c_adapter_match(struct device *dev, const void *data) +{ + if (!of_dev_or_parent_node_match(dev, data)) + return 0; + + return !!i2c_verify_adapter(dev); +} + /* must call put_device() when done with returned i2c_client device */ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) { @@ -146,18 +154,13 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node); struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) { struct device *dev; - struct i2c_adapter *adapter; dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_or_parent_node_match); + of_i2c_adapter_match); if (!dev) return NULL; - adapter = i2c_verify_adapter(dev); - if (!adapter) - put_device(dev); - - return adapter; + return to_i2c_adapter(dev); } EXPORT_SYMBOL(of_find_i2c_adapter_by_node);