mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
spi: oc-tiny: switch to managed controller allocation
The controller is allocated with the non-managed spi_alloc_host() while
the interrupt is registered with devm_request_irq(). During removal,
spi_bitbang_stop() only unregisters the controller; the subsequent
spi_controller_put() then frees the controller together with its
embedded driver-private devdata, which is the IRQ handler's dev_id. The
devm_request_irq() release action (free_irq()), which drains the
handler, does not run until after .remove() returns. A late or latched
interrupt can therefore reach tiny_spi_irq() and dereference
already-freed memory (e.g. hw->base).
Switch to devm_spi_alloc_host() so that the devres LIFO order releases
the controller only after free_irq() has drained the handler, and drop
the now-redundant spi_controller_put() from .remove(). The probe error
path is simplified to direct returns.
This issue was found by an in-house static analysis tool.
Fixes: ce792580ea ("spi: add OpenCores tiny SPI driver")
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Link: https://patch.msgid.link/20260719010014.3163356-1-fanwu01@zju.edu.cn
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
@@ -210,11 +210,11 @@ static int tiny_spi_probe(struct platform_device *pdev)
|
||||
struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
|
||||
struct tiny_spi *hw;
|
||||
struct spi_controller *host;
|
||||
int err = -ENODEV;
|
||||
int err;
|
||||
|
||||
host = spi_alloc_host(&pdev->dev, sizeof(struct tiny_spi));
|
||||
host = devm_spi_alloc_host(&pdev->dev, sizeof(struct tiny_spi));
|
||||
if (!host)
|
||||
return err;
|
||||
return -ENOMEM;
|
||||
|
||||
/* setup the host state. */
|
||||
host->bus_num = pdev->id;
|
||||
@@ -232,10 +232,8 @@ static int tiny_spi_probe(struct platform_device *pdev)
|
||||
|
||||
/* find and map our resources */
|
||||
hw->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hw->base)) {
|
||||
err = PTR_ERR(hw->base);
|
||||
goto exit;
|
||||
}
|
||||
if (IS_ERR(hw->base))
|
||||
return PTR_ERR(hw->base);
|
||||
/* irq is optional */
|
||||
hw->irq = platform_get_irq(pdev, 0);
|
||||
if (hw->irq >= 0) {
|
||||
@@ -243,7 +241,7 @@ static int tiny_spi_probe(struct platform_device *pdev)
|
||||
err = devm_request_irq(&pdev->dev, hw->irq, tiny_spi_irq, 0,
|
||||
pdev->name, hw);
|
||||
if (err)
|
||||
goto exit;
|
||||
return err;
|
||||
}
|
||||
/* find platform data */
|
||||
if (platp) {
|
||||
@@ -252,29 +250,23 @@ static int tiny_spi_probe(struct platform_device *pdev)
|
||||
} else {
|
||||
err = tiny_spi_of_probe(pdev);
|
||||
if (err)
|
||||
goto exit;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* register our spi controller */
|
||||
err = spi_bitbang_start(&hw->bitbang);
|
||||
if (err)
|
||||
goto exit;
|
||||
return err;
|
||||
dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
spi_controller_put(host);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tiny_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tiny_spi *hw = platform_get_drvdata(pdev);
|
||||
struct spi_controller *host = hw->bitbang.ctlr;
|
||||
|
||||
spi_bitbang_stop(&hw->bitbang);
|
||||
spi_controller_put(host);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
Reference in New Issue
Block a user