Commit 75a08b9a authored by Remi Pommarel's avatar Remi Pommarel Committed by Greg Kroah-Hartman

mmc: meson-gx: Free irq in release() callback

commit bb364890 upstream.

Because the irq was requested through device managed resources API
(devm_request_threaded_irq()) it was freed after meson_mmc_remove()
completion, thus after mmc_free_host() has reclaimed meson_host memory.
As this irq is IRQF_SHARED, while using CONFIG_DEBUG_SHIRQ, its handler
get called by free_irq(). So meson_mmc_irq() was called after the
meson_host memory reclamation and was using invalid memory.

We ended up with the following scenario:
device_release_driver()
	meson_mmc_remove()
		mmc_free_host() /* Freeing host memory */
	...
	devres_release_all()
		devm_irq_release()
			__free_irq()
				meson_mmc_irq() /* Uses freed memory */

To avoid this, the irq is released in meson_mmc_remove() and in
mseon_mmc_probe() error path before mmc_free_host() gets called.
Reported-by: default avatarElie Roudninski <xademax@gmail.com>
Signed-off-by: default avatarRemi Pommarel <repk@triplefau.lt>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4a559dfe
......@@ -174,6 +174,8 @@ struct meson_host {
struct sd_emmc_desc *descs;
dma_addr_t descs_dma_addr;
int irq;
bool vqmmc_enabled;
};
......@@ -1181,7 +1183,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
struct resource *res;
struct meson_host *host;
struct mmc_host *mmc;
int ret, irq;
int ret;
mmc = mmc_alloc_host(sizeof(struct meson_host), &pdev->dev);
if (!mmc)
......@@ -1228,8 +1230,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto free_host;
}
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
host->irq = platform_get_irq(pdev, 0);
if (host->irq <= 0) {
dev_err(&pdev->dev, "failed to get interrupt resource.\n");
ret = -EINVAL;
goto free_host;
......@@ -1283,9 +1285,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
host->regs + SD_EMMC_IRQ_EN);
ret = devm_request_threaded_irq(&pdev->dev, irq, meson_mmc_irq,
meson_mmc_irq_thread, IRQF_SHARED,
NULL, host);
ret = request_threaded_irq(host->irq, meson_mmc_irq,
meson_mmc_irq_thread, IRQF_SHARED, NULL, host);
if (ret)
goto err_init_clk;
......@@ -1303,7 +1304,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
if (host->bounce_buf == NULL) {
dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
ret = -ENOMEM;
goto err_init_clk;
goto err_free_irq;
}
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
......@@ -1322,6 +1323,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
err_bounce_buf:
dma_free_coherent(host->dev, host->bounce_buf_size,
host->bounce_buf, host->bounce_dma_addr);
err_free_irq:
free_irq(host->irq, host);
err_init_clk:
clk_disable_unprepare(host->mmc_clk);
err_core_clk:
......@@ -1339,6 +1342,7 @@ static int meson_mmc_remove(struct platform_device *pdev)
/* disable interrupts */
writel(0, host->regs + SD_EMMC_IRQ_EN);
free_irq(host->irq, host);
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
host->descs, host->descs_dma_addr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment