Lots of device drivers especially for platform/I2C/SPI bus devices, they want to be initialized earlier than other devices, so the driver use initcall such as subsys_initcall for the device initialization.
But for those drivers, lots of them just do nothing special in xxx_initcall/module_exit, and produce lots of boilerplate.
This patch set introduces a helper macro initcall_driver() to eliminate lots of boilerplate just like module_driver() did, and use it for platform/I2C/SPI bus devices.
I use following command under the lastest kernel source code:
$grep -r -E "*_initcall" drivers/ | cut -d":" -f1 |xargs grep -E "return platform_driver_register|return i2c_add_driver|return spi_register_driver" | cut -d":" -f1 | xargs grep "module_exit" | wc -l
and get 205 hits, so if we use helper macro initcall_driver(), we can reduce thousands lines of code.
Hanjun Guo (4): driver core: introduce helper macro initcall_driver() platform device: introduce helper macro initcall_platform_driver() i2c: introduce helper macro initcall_i2c_driver() spi: introduce helper macro initcall_spi_driver()
include/linux/device.h | 27 +++++++++++++++++++++++++++ include/linux/i2c.h | 11 +++++++++++ include/linux/platform_device.h | 11 +++++++++++ include/linux/spi/spi.h | 11 +++++++++++ 4 files changed, 60 insertions(+)
For some devices especially on platform/I2C/SPI bus, they want to be initialized earlier than other devices, so the driver use initcall such as subsys_initcall to make this device initialize earlier.
But for those drivers, lots of them just do nothing special in xxx_initcall/exit, so introduce a helper macro initcall_driver() to eliminate lots of boilerplate just like module_driver() did.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- include/linux/device.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/include/linux/device.h b/include/linux/device.h index 2a9d6ed..1903f7f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -1198,4 +1198,31 @@ static void __exit __driver##_exit(void) \ } \ module_exit(__driver##_exit);
+/** + * initcall_driver() - Helper macro for drivers that don't do anything + * special in buid-in module xxx_initcall/exit. This eliminates a lot + * of boilerplate. Each driver may only use this macro once, and calling + * it replaces xxx_initcall() and module_exit(). + * + * @__type: initcall type + * @__driver: driver name + * @__register: register function for this driver type + * @__unregister: unregister function for this driver type + * @...: Additional arguments to be passed to __register and __unregister. + * + * Use this macro to construct bus specific macros for registering + * drivers, and do not use it on its own. + */ +#define initcall_driver(__type, __driver, __register, __unregister, ...) \ +static int __init __driver##_init(void) \ +{ \ + return __register(&(__driver) , ##__VA_ARGS__); \ +} \ +__type##_initcall(__driver##_init); \ +static void __exit __driver##_exit(void) \ +{ \ + __unregister(&(__driver) , ##__VA_ARGS__); \ +} \ +module_exit(__driver##_exit); + #endif /* _DEVICE_H_ */
On Mon, Sep 30, 2013 at 01:13:52PM +0800, Hanjun Guo wrote:
For some devices especially on platform/I2C/SPI bus, they want to be initialized earlier than other devices, so the driver use initcall such as subsys_initcall to make this device initialize earlier.
We're trying to move away from needing to do this and to using deferred probing to resolve init ordering issues. Should we not be able to convert the drivers to module_X_driver()?
On 2013年09月30日 17:16, Mark Brown wrote:
On Mon, Sep 30, 2013 at 01:13:52PM +0800, Hanjun Guo wrote:
For some devices especially on platform/I2C/SPI bus, they want to be initialized earlier than other devices, so the driver use initcall such as subsys_initcall to make this device initialize earlier.
We're trying to move away from needing to do this and to using deferred probing to resolve init ordering issues. Should we not be able to convert the drivers to module_X_driver()?
Hi Mark,
Thanks for your comments.
That would be great to move away *_initcall in module driver, and this patch set is not necessary if we can use deferred probe to solve all the init order issues.
Thanks Hanjun
On Mon, Sep 30, 2013 at 01:13:52PM +0800, Hanjun Guo wrote:
For some devices especially on platform/I2C/SPI bus, they want to be initialized earlier than other devices, so the driver use initcall such as subsys_initcall to make this device initialize earlier.
And this is something we want to get rid of in favor of deferred probing.
But for those drivers, lots of them just do nothing special in xxx_initcall/exit, so introduce a helper macro initcall_driver() to eliminate lots of boilerplate just like module_driver() did.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
So, NACK because using some *_initcall in drivers should not be encouraged.
Thanks,
Wolfram
On 2013年09月30日 18:15, Wolfram Sang wrote:
On Mon, Sep 30, 2013 at 01:13:52PM +0800, Hanjun Guo wrote:
For some devices especially on platform/I2C/SPI bus, they want to be initialized earlier than other devices, so the driver use initcall such as subsys_initcall to make this device initialize earlier.
And this is something we want to get rid of in favor of deferred probing.
But for those drivers, lots of them just do nothing special in xxx_initcall/exit, so introduce a helper macro initcall_driver() to eliminate lots of boilerplate just like module_driver() did.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
So, NACK because using some *_initcall in drivers should not be encouraged.
Ok, got it. I agree with you, *_initcall in module driver is really confusing people :)
Thanks Hanjun
Thanks,
Wolfram
Introduce a helper macro initcall_platform_driver() which based on initcall_driver() for platform driver to eliminate boilerplate code.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- include/linux/platform_device.h | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index ce8e4ff..0f37f9d 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -218,6 +218,17 @@ static inline void platform_set_drvdata(struct platform_device *pdev, module_driver(__platform_driver, platform_driver_register, \ platform_driver_unregister)
+/* initcall_platform_driver() - Helper macro for drivers that don't do + * anything special in build-in module xxx_initcall/exit. This eliminates + * a lot of boilerplate. Each driver may only use this macro once, and + * calling it replaces xxx_initcall() and module_exit() + * @__type: initcall type + * @__platform_driver: platform driver struct + */ +#define initcall_platform_driver(__type, __platform_driver) \ + initcall_driver(__type, __platform_driver, platform_driver_register, \ + latform_driver_unregister) + /* module_platform_driver_probe() - Helper macro for drivers that don't do * anything special in module init/exit. This eliminates a lot of * boilerplate. Each module may only use this macro once, and
Introduce a helper macro initcall_i2c_driver() which based on initcall_driver() for i2c driver to eliminate boilerplate code.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- include/linux/i2c.h | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 2ab11dc..1b87e64 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -542,6 +542,17 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap) module_driver(__i2c_driver, i2c_add_driver, \ i2c_del_driver)
+/** + * initcall_i2c_driver() - Helper macro for registering a I2C driver + * for buid-in module with doing nothing special in driver + * xxx_initcall/module_exit. This eliminates a lot of boilerplate. + * @__type: initcall type + * @__i2c_driver: i2c_driver struct + */ +#define initcall_i2c_driver(__type, __i2c_driver) \ + initcall_driver(__type, __i2c_driver, i2c_add_driver, \ + i2c_del_driver) + #endif /* I2C */
#if IS_ENABLED(CONFIG_OF)
Introduce a helper macro initcall_spi_driver() which based on initcall_driver() for spi driver to eliminate boilerplate code.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- include/linux/spi/spi.h | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 887116d..8bf8690 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -221,6 +221,17 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) spi_unregister_driver)
/** + * initcall_spi_driver() - Helper macro for registering a SPI driver + * for buid-in module with doing nothing special in driver + * xxx_initcall/module_exit. This eliminates a lot of boilerplate. + * @__type: initcall type + * @__spi_driver: spi_driver struct + */ +#define initcall_spi_driver(__type, __spi_driver) \ + initcall_driver(__type, __spi_driver, spi_register_driver, \ + spi_unregister_driver) + +/** * struct spi_master - interface to SPI master controller * @dev: device interface to this driver * @list: link with the global spi_master list