Skip to content

Commit 1502915

Browse files
wuxu.wugregkh
authored andcommitted
spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
commit 19b6139 upstream. dw_spi_irq() and dw_spi_transfer_one concurrent calls. I find a panic in dw_writer(): txw = *(u8 *)(dws->tx), when dw->tx==null, dw->len==4, and dw->tx_end==1. When tpm driver's message overtime dw_spi_irq() and dw_spi_transfer_one may concurrent visit dw_spi, so I think dw_spi structure lack of protection. Otherwise dw_spi_transfer_one set dw rx/tx buffer and then open irq, store dw rx/tx instructions and other cores handle irq load dw rx/tx instructions may out of order. [ 1025.321302] Call trace: ... [ 1025.321319] __crash_kexec+0x98/0x148 [ 1025.321323] panic+0x17c/0x314 [ 1025.321329] die+0x29c/0x2e8 [ 1025.321334] die_kernel_fault+0x68/0x78 [ 1025.321337] __do_kernel_fault+0x90/0xb0 [ 1025.321346] do_page_fault+0x88/0x500 [ 1025.321347] do_translation_fault+0xa8/0xb8 [ 1025.321349] do_mem_abort+0x68/0x118 [ 1025.321351] el1_da+0x20/0x8c [ 1025.321362] dw_writer+0xc8/0xd0 [ 1025.321364] interrupt_transfer+0x60/0x110 [ 1025.321365] dw_spi_irq+0x48/0x70 ... Signed-off-by: wuxu.wu <wuxu.wu@huawei.com> Link: https://lore.kernel.org/r/1577849981-31489-1-git-send-email-wuxu.wu@huawei.com Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Nobuhiro Iwamatsu (CIP) <nobuhiro1.iwamatsu@toshiba.co.jp> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 6950c27 commit 1502915

File tree

2 files changed

+13
-3
lines changed

2 files changed

+13
-3
lines changed

drivers/spi/spi-dw.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,11 @@ static inline u32 rx_max(struct dw_spi *dws)
180180

181181
static void dw_writer(struct dw_spi *dws)
182182
{
183-
u32 max = tx_max(dws);
183+
u32 max;
184184
u16 txw = 0;
185185

186+
spin_lock(&dws->buf_lock);
187+
max = tx_max(dws);
186188
while (max--) {
187189
/* Set the tx word if the transfer's original "tx" is not null */
188190
if (dws->tx_end - dws->len) {
@@ -194,13 +196,16 @@ static void dw_writer(struct dw_spi *dws)
194196
dw_write_io_reg(dws, DW_SPI_DR, txw);
195197
dws->tx += dws->n_bytes;
196198
}
199+
spin_unlock(&dws->buf_lock);
197200
}
198201

199202
static void dw_reader(struct dw_spi *dws)
200203
{
201-
u32 max = rx_max(dws);
204+
u32 max;
202205
u16 rxw;
203206

207+
spin_lock(&dws->buf_lock);
208+
max = rx_max(dws);
204209
while (max--) {
205210
rxw = dw_read_io_reg(dws, DW_SPI_DR);
206211
/* Care rx only if the transfer's original "rx" is not null */
@@ -212,6 +217,7 @@ static void dw_reader(struct dw_spi *dws)
212217
}
213218
dws->rx += dws->n_bytes;
214219
}
220+
spin_unlock(&dws->buf_lock);
215221
}
216222

217223
static void int_error_stop(struct dw_spi *dws, const char *msg)
@@ -284,18 +290,20 @@ static int dw_spi_transfer_one(struct spi_master *master,
284290
{
285291
struct dw_spi *dws = spi_master_get_devdata(master);
286292
struct chip_data *chip = spi_get_ctldata(spi);
293+
unsigned long flags;
287294
u8 imask = 0;
288295
u16 txlevel = 0;
289296
u32 cr0;
290297
int ret;
291298

292299
dws->dma_mapped = 0;
293-
300+
spin_lock_irqsave(&dws->buf_lock, flags);
294301
dws->tx = (void *)transfer->tx_buf;
295302
dws->tx_end = dws->tx + transfer->len;
296303
dws->rx = transfer->rx_buf;
297304
dws->rx_end = dws->rx + transfer->len;
298305
dws->len = transfer->len;
306+
spin_unlock_irqrestore(&dws->buf_lock, flags);
299307

300308
spi_enable_chip(dws, 0);
301309

@@ -487,6 +495,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
487495
dws->dma_inited = 0;
488496
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
489497
snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num);
498+
spin_lock_init(&dws->buf_lock);
490499

491500
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master);
492501
if (ret < 0) {

drivers/spi/spi-dw.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ struct dw_spi {
117117
size_t len;
118118
void *tx;
119119
void *tx_end;
120+
spinlock_t buf_lock;
120121
void *rx;
121122
void *rx_end;
122123
int dma_mapped;

0 commit comments

Comments
 (0)