From 07918df724f2fed02327e3cbfe58a5d5568b2cc2 Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:45 +0300 Subject: spi: dw: Discard IRQ threshold macro The macro has been unused since a half of FIFO length was defined to be a marker of the IRQ. Let's remove it definition. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-2-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 90dfd21622d6..51bab30b9f85 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -92,9 +92,6 @@ #define SPI_DMA_RDMAE (1 << 0) #define SPI_DMA_TDMAE (1 << 1) -/* TX RX interrupt level threshold, max can be 256 */ -#define SPI_INT_THRESHOLD 32 - enum dw_ssi_type { SSI_MOTO_SPI = 0, SSI_TI_SSP, -- cgit v1.2.3 From 8225c1c9a073c323f68833d136fcf94fbc75a275 Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:47 +0300 Subject: spi: dw: Initialize n_bytes before the memory barrier Since n_bytes field of the DW SPI private data is also utilized by the IRQ handler, we need to make sure it' initialization is done before the memory barrier. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-4-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 55afdcee7d2b..dc54990bff6b 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -299,6 +299,7 @@ static int dw_spi_transfer_one(struct spi_controller *master, dws->dma_mapped = 0; spin_lock_irqsave(&dws->buf_lock, flags); + dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); dws->tx = (void *)transfer->tx_buf; dws->tx_end = dws->tx + transfer->len; dws->rx = transfer->rx_buf; @@ -323,7 +324,6 @@ static int dw_spi_transfer_one(struct spi_controller *master, } transfer->effective_speed_hz = dws->max_freq / chip->clk_div; - dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); cr0 = dws->update_cr0(master, spi, transfer); dw_writel(dws, DW_SPI_CTRLR0, cr0); -- cgit v1.2.3 From a128f6ecd56a32e559889145003425b0c7d406e3 Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:49 +0300 Subject: spi: dw: Clear IRQ status on DW SPI controller reset It turns out the IRQ status isn't cleared after switching the controller off and getting it back on, which may cause raising false error interrupts if controller has been unsuccessfully used by, for instance, a bootloader before the driver is loaded. Let's explicitly clear the interrupts status in the dedicated controller reset method. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-6-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 51bab30b9f85..6b30f5089218 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -230,14 +230,15 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) } /* - * This does disable the SPI controller, interrupts, and re-enable the - * controller back. Transmit and receive FIFO buffers are cleared when the - * device is disabled. + * This disables the SPI controller, interrupts, clears the interrupts status, + * and re-enable the controller back. Transmit and receive FIFO buffers are + * cleared when the device is disabled. */ static inline void spi_reset_chip(struct dw_spi *dws) { spi_enable_chip(dws, 0); spi_mask_intr(dws, 0xff); + dw_readl(dws, DW_SPI_ICR); spi_enable_chip(dws, 1); } -- cgit v1.2.3 From a1d5aa6f7f97b15e8fd917169239088823471741 Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:50 +0300 Subject: spi: dw: Disable all IRQs when controller is unused It's a good practice to disable all IRQs if a device is fully unused. In our case it is supposed to be done before requesting the IRQ and after the last byte of an SPI transfer is received. In the former case it's required to prevent the IRQ handler invocation before the driver data is fully initialized (which may happen if the IRQs status has been left uncleared before the device is probed). So we just moved the spi_hw_init() method invocation to the earlier stage before requesting the IRQ. In the later case there is just no point in having any of the IRQs enabled between SPI transfers and when there is no SPI message currently being processed. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-7-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index dc54990bff6b..7a75068037e7 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -204,7 +204,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) dw_reader(dws); if (dws->rx_end == dws->rx) { - spi_mask_intr(dws, SPI_INT_TXEI); + spi_mask_intr(dws, 0xff); spi_finalize_current_transfer(dws->master); return IRQ_HANDLED; } @@ -228,7 +228,7 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id) return IRQ_NONE; if (!master->cur_msg) { - spi_mask_intr(dws, SPI_INT_TXEI); + spi_mask_intr(dws, 0xff); return IRQ_HANDLED; } @@ -468,6 +468,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) spi_controller_set_devdata(master, dws); + /* Basic HW init */ + spi_hw_init(dev, dws); + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), master); if (ret < 0) { @@ -498,9 +501,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) device_property_read_u32(dev, "rx-sample-delay-ns", &dws->def_rx_sample_dly_ns); - /* Basic HW init */ - spi_hw_init(dev, dws); - if (dws->dma_ops && dws->dma_ops->dma_init) { ret = dws->dma_ops->dma_init(dev, dws); if (ret) { -- cgit v1.2.3 From 7e31cea7d1e0f4b683dc45c21530cd3ee82559b4 Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:51 +0300 Subject: spi: dw: Use relaxed IO-methods to access FIFOs In accordance with [1] the relaxed methods are guaranteed to be ordered with respect to other accesses from the same CPU thread to the same peripheral. This is what we need during the data read/write from/to the controller FIFOs being executed within a single IRQ handler or a kernel task. Such optimization shall significantly speed the data reader and writer up. For instance, the relaxed IO-accessors utilization on Baikal-T1 lets the driver to support the SPI memory operations with bus frequency three-fold faster than if normal IO-accessors would be used. [1] "LINUX KERNEL MEMORY BARRIERS", Documentation/memory-barriers.txt, Section "KERNEL I/O BARRIER EFFECTS" Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-8-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw.h | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 6b30f5089218..40b2c8c0c2a2 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -162,29 +162,19 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset) return __raw_readl(dws->regs + offset); } -static inline u16 dw_readw(struct dw_spi *dws, u32 offset) -{ - return __raw_readw(dws->regs + offset); -} - static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val) { __raw_writel(val, dws->regs + offset); } -static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val) -{ - __raw_writew(val, dws->regs + offset); -} - static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset) { switch (dws->reg_io_width) { case 2: - return dw_readw(dws, offset); + return readw_relaxed(dws->regs + offset); case 4: default: - return dw_readl(dws, offset); + return readl_relaxed(dws->regs + offset); } } @@ -192,11 +182,11 @@ static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val) { switch (dws->reg_io_width) { case 2: - dw_writew(dws, offset, val); + writew_relaxed(val, dws->regs + offset); break; case 4: default: - dw_writel(dws, offset, val); + writel_relaxed(val, dws->regs + offset); break; } } -- cgit v1.2.3 From 675e7c9d71cedee3988b554c47971be77e72d2db Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:52 +0300 Subject: spi: dw: Discard DW SSI chip type storages Keeping SPI peripheral devices type is pointless since first it hasn't been functionally utilized by any of the client drivers/code and second it won't work for Microwire type at the very least. Moreover there is no point in setting up the type by means of the chip-data in the modern kernel. The peripheral devices with specific interface type need to be detected in order to activate the corresponding frame format. It most likely will require some peripheral device specific DT property or whatever to find out the interface protocol. So let's remove the serial interface type fields from the DW APB SSI controller and the SPI peripheral device private data. Note we'll preserve the explicit SSI_MOTO_SPI interface type setting up to signify the only currently supported interface protocol. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-9-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw-core.c | 6 ++---- drivers/spi/spi-dw.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 7a75068037e7..cbb65d3ea13e 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -23,7 +23,6 @@ /* Slave spi_dev related */ struct chip_data { u8 tmode; /* TR/TO/RO/EEPROM */ - u8 type; /* SPI/SSP/MicroWire */ u16 clk_div; /* baud rate divider */ u32 speed_hz; /* baud rate */ @@ -244,7 +243,7 @@ u32 dw_spi_update_cr0(struct spi_controller *master, struct spi_device *spi, /* Default SPI mode is SCPOL = 0, SCPH = 0 */ cr0 = (transfer->bits_per_word - 1) - | (chip->type << SPI_FRF_OFFSET) + | (SSI_MOTO_SPI << SPI_FRF_OFFSET) | ((((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET) | (((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET) | (((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET)) @@ -266,7 +265,7 @@ u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master, cr0 = (transfer->bits_per_word - 1); /* CTRLR0[ 7: 6] Frame Format */ - cr0 |= chip->type << DWC_SSI_CTRLR0_FRF_OFFSET; + cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET; /* * SPI mode (SCPOL|SCPH) @@ -462,7 +461,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) return -ENOMEM; dws->master = master; - dws->type = SSI_MOTO_SPI; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); spin_lock_init(&dws->buf_lock); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 40b2c8c0c2a2..66ef35dd8b6e 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -111,7 +111,6 @@ struct dw_spi_dma_ops { struct dw_spi { struct spi_controller *master; - enum dw_ssi_type type; void __iomem *regs; unsigned long paddr; -- cgit v1.2.3 From cc760f3143f53ea8387cd76cffc43bdc89db9df4 Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:53 +0300 Subject: spi: dw: Convert CS-override to DW SPI capabilities There are several vendor-specific versions of the DW SPI controllers, each of which may have some peculiarities with respect to the original IP-core. Seeing it has already caused adding flags and a callback into the DW SPI private data, let's introduce a generic capabilities interface to tune the generic DW SPI controller driver up in accordance with the particular controller specifics. It's done by converting a simple Alpine-specific CS-override capability into the DW SPI controller capability activated by setting the DW_SPI_CAP_CS_OVERRIDE flag. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-10-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw-core.c | 4 ++-- drivers/spi/spi-dw-mmio.c | 2 +- drivers/spi/spi-dw.h | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index cbb65d3ea13e..f01a43b1954c 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -104,7 +104,7 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) */ if (cs_high == enable) dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select)); - else if (dws->cs_override) + else if (dws->caps & DW_SPI_CAP_CS_OVERRIDE) dw_writel(dws, DW_SPI_SER, 0); } EXPORT_SYMBOL_GPL(dw_spi_set_cs); @@ -444,7 +444,7 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws) } /* enable HW fixup for explicit CS deselect for Amazon's alpine chip */ - if (dws->cs_override) + if (dws->caps & DW_SPI_CAP_CS_OVERRIDE) dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF); } diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 18772c0c9220..7111cb7ca23b 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -204,7 +204,7 @@ static int dw_spi_mscc_sparx5_init(struct platform_device *pdev, static int dw_spi_alpine_init(struct platform_device *pdev, struct dw_spi_mmio *dwsmmio) { - dwsmmio->dws.cs_override = 1; + dwsmmio->dws.caps = DW_SPI_CAP_CS_OVERRIDE; /* Register hook to configure CTRLR0 */ dwsmmio->dws.update_cr0 = dw_spi_update_cr0; diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 66ef35dd8b6e..b11fc873c3a7 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -2,6 +2,7 @@ #ifndef DW_SPI_HEADER_H #define DW_SPI_HEADER_H +#include <linux/bits.h> #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/irqreturn.h> @@ -98,6 +99,9 @@ enum dw_ssi_type { SSI_NS_MICROWIRE, }; +/* DW SPI capabilities */ +#define DW_SPI_CAP_CS_OVERRIDE BIT(0) + struct dw_spi; struct dw_spi_dma_ops { int (*dma_init)(struct device *dev, struct dw_spi *dws); @@ -118,7 +122,8 @@ struct dw_spi { u32 fifo_len; /* depth of the FIFO buffer */ u32 max_freq; /* max bus freq supported */ - int cs_override; + u32 caps; /* DW SPI capabilities */ + u32 reg_io_width; /* DR I/O width in bytes */ u16 bus_num; u16 num_cs; /* supported slave numbers */ -- cgit v1.2.3 From ffb7ca54c95b4c76ad8a9aa1b2b16d61df2a7139 Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:54 +0300 Subject: spi: dw: Add KeemBay Master capability In a further commit we'll have to get rid of the update_cr0() callback and define a DW SSI capability instead. Since Keem Bay master/slave functionality is controller by the CTRL0 register bitfield, we need to first move the master mode selection into the internal corresponding update_cr0 method, which would be activated by means of the dedicated DW_SPI_CAP_KEEMBAY_MST capability setup. Note this will be also useful if the driver will be ever altered to support the DW SPI slave interface. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-11-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw-core.c | 4 ++++ drivers/spi/spi-dw-mmio.c | 20 +++----------------- drivers/spi/spi-dw.h | 8 ++++++++ 3 files changed, 15 insertions(+), 17 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index f01a43b1954c..467f149364fa 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -258,6 +258,7 @@ u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master, struct spi_device *spi, struct spi_transfer *transfer) { + struct dw_spi *dws = spi_controller_get_devdata(master); struct chip_data *chip = spi_get_ctldata(spi); u32 cr0; @@ -281,6 +282,9 @@ u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master, /* CTRLR0[13] Shift Register Loop */ cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET; + if (dws->caps & DW_SPI_CAP_KEEMBAY_MST) + cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST; + return cr0; } EXPORT_SYMBOL_GPL(dw_spi_update_cr0_v1_01a); diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 7111cb7ca23b..c0d351fde782 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -48,13 +48,6 @@ struct dw_spi_mmio { #define SPARX5_FORCE_ENA 0xa4 #define SPARX5_FORCE_VAL 0xa8 -/* - * For Keem Bay, CTRLR0[31] is used to select controller mode. - * 0: SSI is slave - * 1: SSI is master - */ -#define KEEMBAY_CTRLR0_SSIC_IS_MST BIT(31) - struct dw_spi_mscc { struct regmap *syscon; void __iomem *spi_mst; /* Not sparx5 */ @@ -234,20 +227,13 @@ static int dw_spi_dwc_ssi_init(struct platform_device *pdev, return 0; } -static u32 dw_spi_update_cr0_keembay(struct spi_controller *master, - struct spi_device *spi, - struct spi_transfer *transfer) -{ - u32 cr0 = dw_spi_update_cr0_v1_01a(master, spi, transfer); - - return cr0 | KEEMBAY_CTRLR0_SSIC_IS_MST; -} - static int dw_spi_keembay_init(struct platform_device *pdev, struct dw_spi_mmio *dwsmmio) { + dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST; + /* Register hook to configure CTRLR0 */ - dwsmmio->dws.update_cr0 = dw_spi_update_cr0_keembay; + dwsmmio->dws.update_cr0 = dw_spi_update_cr0_v1_01a; return 0; } diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index b11fc873c3a7..56be1ad2ac0e 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -71,6 +71,13 @@ #define DWC_SSI_CTRLR0_FRF_OFFSET 6 #define DWC_SSI_CTRLR0_DFS_OFFSET 0 +/* + * For Keem Bay, CTRLR0[31] is used to select controller mode. + * 0: SSI is slave + * 1: SSI is master + */ +#define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31) + /* Bit fields in SR, 7 bits */ #define SR_MASK 0x7f /* cover 7 bits */ #define SR_BUSY (1 << 0) @@ -101,6 +108,7 @@ enum dw_ssi_type { /* DW SPI capabilities */ #define DW_SPI_CAP_CS_OVERRIDE BIT(0) +#define DW_SPI_CAP_KEEMBAY_MST BIT(1) struct dw_spi; struct dw_spi_dma_ops { -- cgit v1.2.3 From 0b6bfad4cee4a3d5c49e01fa00284db4b676360e Mon Sep 17 00:00:00 2001 From: Serge Semin <Sergey.Semin@baikalelectronics.ru> Date: Sun, 20 Sep 2020 14:28:48 +0300 Subject: spi: spi-dw: Remove extraneous locking There is no point in having the commit 19b61392c5a8 ("spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls") applied. The commit author made an assumption that the problem with the rx data mismatch was due to the lack of the data protection. While most likely it was caused by the lack of the memory barrier. So having the commit bfda044533b2 ("spi: dw: use "smp_mb()" to avoid sending spi data error") applied would be enough to fix the problem. Indeed the spin unlock operation makes sure each memory operation issued before the release will be completed before it's completed. In other words it works as an implicit one way memory barrier. So having both smp_mb() and the spin_unlock_irqrestore() here is just redundant. One of them would be enough. It's better to leave the smp_mb() since the Tx/Rx buffers consistency is provided by the data transfer algorithm implementation: first we initialize the buffers pointers, then make sure the assignments are visible by the other CPUs by calling the smp_mb(), only after that enable the interrupt, which handler uses the buffers. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20200920112914.26501-5-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown <broonie@kernel.org> --- drivers/spi/spi-dw-core.c | 14 ++------------ drivers/spi/spi-dw.h | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 467f149364fa..d8e92f53e2bc 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -141,11 +141,9 @@ static inline u32 rx_max(struct dw_spi *dws) static void dw_writer(struct dw_spi *dws) { - u32 max; + u32 max = tx_max(dws); u16 txw = 0; - spin_lock(&dws->buf_lock); - max = tx_max(dws); while (max--) { /* Set the tx word if the transfer's original "tx" is not null */ if (dws->tx_end - dws->len) { @@ -157,16 +155,13 @@ static void dw_writer(struct dw_spi *dws) dw_write_io_reg(dws, DW_SPI_DR, txw); dws->tx += dws->n_bytes; } - spin_unlock(&dws->buf_lock); } static void dw_reader(struct dw_spi *dws) { - u32 max; + u32 max = rx_max(dws); u16 rxw; - spin_lock(&dws->buf_lock); - max = rx_max(dws); while (max--) { rxw = dw_read_io_reg(dws, DW_SPI_DR); /* Care rx only if the transfer's original "rx" is not null */ @@ -178,7 +173,6 @@ static void dw_reader(struct dw_spi *dws) } dws->rx += dws->n_bytes; } - spin_unlock(&dws->buf_lock); } static void int_error_stop(struct dw_spi *dws, const char *msg) @@ -294,21 +288,18 @@ static int dw_spi_transfer_one(struct spi_controller *master, { struct dw_spi *dws = spi_controller_get_devdata(master); struct chip_data *chip = spi_get_ctldata(spi); - unsigned long flags; u8 imask = 0; u16 txlevel = 0; u32 cr0; int ret; dws->dma_mapped = 0; - spin_lock_irqsave(&dws->buf_lock, flags); dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); dws->tx = (void *)transfer->tx_buf; dws->tx_end = dws->tx + transfer->len; dws->rx = transfer->rx_buf; dws->rx_end = dws->rx + transfer->len; dws->len = transfer->len; - spin_unlock_irqrestore(&dws->buf_lock, flags); /* Ensure dw->rx and dw->rx_end are visible */ smp_mb(); @@ -466,7 +457,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->master = master; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); - spin_lock_init(&dws->buf_lock); spi_controller_set_devdata(master, dws); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 56be1ad2ac0e..da9b543322c9 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -143,7 +143,6 @@ struct dw_spi { size_t len; void *tx; void *tx_end; - spinlock_t buf_lock; void *rx; void *rx_end; int dma_mapped; -- cgit v1.2.3