[PATCH] fsi: aspeed: publish cfam_reset after drvdata is ready
Pengpeng Hou <[email protected]> Mon, 15 Jun 2026 14:59:44 +0800
| Newsgroups | org.ozlabs.lists.linux-aspeed,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
setup_cfam_reset() creates the cfam_reset sysfs file. Its store callback gets struct fsi_master_aspeed from device drvdata and locks aspeed->lock. The file is currently created before dev_set_drvdata() and before the mutex is initialized, so a sysfs write during probe can dereference missing drvdata or use an uninitialized mutex. The file is also not removed on later probe failure or device removal. Initialize drvdata and the mutex before publishing cfam_reset, remember whether the file was created, and remove it on unwind and remove. Signed-off-by: Pengpeng Hou <[email protected]> --- drivers/fsi/fsi-master-aspeed.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index aa1380cdff33..5c8806c4027d 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -25,6 +25,7 @@ struct fsi_master_aspeed { void __iomem *base; struct clk *clk; struct gpio_desc *cfam_reset_gpio; + bool cfam_reset_file; }; #define to_fsi_master_aspeed(m) \ @@ -483,6 +484,7 @@ static int setup_cfam_reset(struct fsi_master_aspeed *aspeed) devm_gpiod_put(dev, gpio); return rc; } + aspeed->cfam_reset_file = true; return 0; } @@ -570,6 +572,9 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) goto err_free_aspeed; } + dev_set_drvdata(&pdev->dev, aspeed); + mutex_init(&aspeed->lock); + rc = setup_cfam_reset(aspeed); if (rc) { dev_err(&pdev->dev, "CFAM reset GPIO setup failed\n"); @@ -620,9 +625,6 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) aspeed->master.term = aspeed_master_term; aspeed->master.link_enable = aspeed_master_link_enable; - dev_set_drvdata(&pdev->dev, aspeed); - - mutex_init(&aspeed->lock); aspeed_master_init(aspeed); rc = fsi_master_register(&aspeed->master); @@ -640,8 +642,11 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) return 0; err_release: + if (aspeed->cfam_reset_file) + device_remove_file(&pdev->dev, &dev_attr_cfam_reset); clk_disable_unprepare(aspeed->clk); err_free_aspeed: + dev_set_drvdata(&pdev->dev, NULL); kfree(aspeed); return rc; } @@ -650,6 +655,8 @@ static void fsi_master_aspeed_remove(struct platform_device *pdev) { struct fsi_master_aspeed *aspeed = platform_get_drvdata(pdev); + if (aspeed->cfam_reset_file) + device_remove_file(&pdev->dev, &dev_attr_cfam_reset); fsi_master_unregister(&aspeed->master); clk_disable_unprepare(aspeed->clk); } -- 2.50.1 (Apple Git-155)