Message ID | 1474441040-11946-8-git-send-email-yangbo.lu@nxp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
>Среда, 21 сентября 2016, 9:57 +03:00 от Yangbo Lu <yangbo.lu@nxp.com>: > >From: Arnd Bergmann < arnd@arndb.de > > >We keep running into cases where device drivers want to know the exact >version of the a SoC they are currently running on. In the past, this has >usually been done through a vendor specific API that can be called by a >driver, or by directly accessing some kind of version register that is >not part of the device itself but that belongs to a global register area >of the chip. ... >+const struct soc_device_attribute *soc_device_match( >+const struct soc_device_attribute *matches) >+{ >+int ret = 0; >+ >+if (!matches) >+return NULL; >+ >+while (!ret) { >+if (!(matches->machine || matches->family || >+ matches->revision || matches->soc_id)) >+break; >+ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches, >+ soc_device_match_one); >+if (!ret) >+matches++; So, what happen if next "matches" (after increment) will be NULL? I think you should use while(matches) at the start of this procedure. ---
On 2016-09-21 09:56, Alexander Shiyan wrote: >> Среда, 21 сентября 2016, 9:57 +03:00 от Yangbo Lu <yangbo.lu@nxp.com>: >> >> From: Arnd Bergmann < arnd@arndb.de > >> >> We keep running into cases where device drivers want to know the exact >> version of the a SoC they are currently running on. In the past, this has >> usually been done through a vendor specific API that can be called by a >> driver, or by directly accessing some kind of version register that is >> not part of the device itself but that belongs to a global register area >> of the chip. > ... >> +const struct soc_device_attribute *soc_device_match( >> +const struct soc_device_attribute *matches) >> +{ >> +int ret = 0; >> + >> +if (!matches) >> +return NULL; >> + >> +while (!ret) { >> +if (!(matches->machine || matches->family || >> + matches->revision || matches->soc_id)) >> +break; >> +ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches, >> + soc_device_match_one); >> +if (!ret) >> +matches++; > > So, what happen if next "matches" (after increment) will be NULL? A crash? > I think you should use while(matches) at the start of this procedure. *arrgh* *If* matches wrap, you indeed have *big* problems. *Elsewhere* Hint: Please read the review comments on the previous version of this series [1] before commenting further. Cheers, Peter [1] https://www.mail-archive.com/netdev@vger.kernel.org/msg126617.html
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 98504ec..f1591ad2 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -225,6 +225,7 @@ config GENERIC_CPU_AUTOPROBE config SOC_BUS bool + select GLOB source "drivers/base/regmap/Kconfig" diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 75b98aa..d2fd1ad 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -14,6 +14,7 @@ #include <linux/spinlock.h> #include <linux/sys_soc.h> #include <linux/err.h> +#include <linux/glob.h> static DEFINE_IDA(soc_ida); @@ -168,3 +169,68 @@ static void __exit soc_bus_unregister(void) bus_unregister(&soc_bus_type); } module_exit(soc_bus_unregister); + +static int soc_device_match_one(struct device *dev, void *arg) +{ + struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); + const struct soc_device_attribute *match = arg; + + if (match->machine && + !glob_match(match->machine, soc_dev->attr->machine)) + return 0; + + if (match->family && + !glob_match(match->family, soc_dev->attr->family)) + return 0; + + if (match->revision && + !glob_match(match->revision, soc_dev->attr->revision)) + return 0; + + if (match->soc_id && + !glob_match(match->soc_id, soc_dev->attr->soc_id)) + return 0; + + return 1; +} + +/* + * soc_device_match - identify the SoC in the machine + * @matches: zero-terminated array of possible matches + * + * returns the first matching entry of the argument array, or NULL + * if none of them match. + * + * This function is meant as a helper in place of of_match_node() + * in cases where either no device tree is available or the information + * in a device node is insufficient to identify a particular variant + * by its compatible strings or other properties. For new devices, + * the DT binding should always provide unique compatible strings + * that allow the use of of_match_node() instead. + * + * The calling function can use the .data entry of the + * soc_device_attribute to pass a structure or function pointer for + * each entry. + */ +const struct soc_device_attribute *soc_device_match( + const struct soc_device_attribute *matches) +{ + int ret = 0; + + if (!matches) + return NULL; + + while (!ret) { + if (!(matches->machine || matches->family || + matches->revision || matches->soc_id)) + break; + ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches, + soc_device_match_one); + if (!ret) + matches++; + else + return matches; + } + return NULL; +} +EXPORT_SYMBOL_GPL(soc_device_match); diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h index 2739ccb..9f5eb06 100644 --- a/include/linux/sys_soc.h +++ b/include/linux/sys_soc.h @@ -13,6 +13,7 @@ struct soc_device_attribute { const char *family; const char *revision; const char *soc_id; + const void *data; }; /** @@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev); */ struct device *soc_device_to_device(struct soc_device *soc); +const struct soc_device_attribute *soc_device_match( + const struct soc_device_attribute *matches); #endif /* __SOC_BUS_H */