| From 9d5a82d054d50789b520e60a01e4732acd064c5c Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sat, 17 Jul 2021 00:02:45 +0300 |
| Subject: spi: spi-bcm2835: Fix deadlock |
| |
| From: Alexandru Tachici <alexandru.tachici@analog.com> |
| |
| [ Upstream commit c45c1e82bba130db4f19d9dbc1deefcf4ea994ed ] |
| |
| The bcm2835_spi_transfer_one function can create a deadlock |
| if it is called while another thread already has the |
| CCF lock. |
| |
| Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com> |
| Fixes: f8043872e796 ("spi: add driver for BCM2835") |
| Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> |
| Link: https://lore.kernel.org/r/20210716210245.13240-2-alexandru.tachici@analog.com |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/spi/spi-bcm2835.c | 12 +++++++----- |
| 1 file changed, 7 insertions(+), 5 deletions(-) |
| |
| diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c |
| index fe40626e45aa..61cbcc7e2121 100644 |
| --- a/drivers/spi/spi-bcm2835.c |
| +++ b/drivers/spi/spi-bcm2835.c |
| @@ -84,6 +84,7 @@ MODULE_PARM_DESC(polling_limit_us, |
| * struct bcm2835_spi - BCM2835 SPI controller |
| * @regs: base address of register map |
| * @clk: core clock, divided to calculate serial clock |
| + * @clk_hz: core clock cached speed |
| * @irq: interrupt, signals TX FIFO empty or RX FIFO ¾ full |
| * @tfr: SPI transfer currently processed |
| * @ctlr: SPI controller reverse lookup |
| @@ -124,6 +125,7 @@ MODULE_PARM_DESC(polling_limit_us, |
| struct bcm2835_spi { |
| void __iomem *regs; |
| struct clk *clk; |
| + unsigned long clk_hz; |
| int irq; |
| struct spi_transfer *tfr; |
| struct spi_controller *ctlr; |
| @@ -1082,19 +1084,18 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, |
| struct spi_transfer *tfr) |
| { |
| struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); |
| - unsigned long spi_hz, clk_hz, cdiv; |
| + unsigned long spi_hz, cdiv; |
| unsigned long hz_per_byte, byte_limit; |
| u32 cs = bs->prepare_cs[spi->chip_select]; |
| |
| /* set clock */ |
| spi_hz = tfr->speed_hz; |
| - clk_hz = clk_get_rate(bs->clk); |
| |
| - if (spi_hz >= clk_hz / 2) { |
| + if (spi_hz >= bs->clk_hz / 2) { |
| cdiv = 2; /* clk_hz/2 is the fastest we can go */ |
| } else if (spi_hz) { |
| /* CDIV must be a multiple of two */ |
| - cdiv = DIV_ROUND_UP(clk_hz, spi_hz); |
| + cdiv = DIV_ROUND_UP(bs->clk_hz, spi_hz); |
| cdiv += (cdiv % 2); |
| |
| if (cdiv >= 65536) |
| @@ -1102,7 +1103,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, |
| } else { |
| cdiv = 0; /* 0 is the slowest we can go */ |
| } |
| - tfr->effective_speed_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536); |
| + tfr->effective_speed_hz = cdiv ? (bs->clk_hz / cdiv) : (bs->clk_hz / 65536); |
| bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); |
| |
| /* handle all the 3-wire mode */ |
| @@ -1320,6 +1321,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) |
| return bs->irq ? bs->irq : -ENODEV; |
| |
| clk_prepare_enable(bs->clk); |
| + bs->clk_hz = clk_get_rate(bs->clk); |
| |
| err = bcm2835_dma_init(ctlr, &pdev->dev, bs); |
| if (err) |
| -- |
| 2.30.2 |
| |