Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: sh_mobile: terminate DMA reads properly

DMA read requests could miss proper termination, so two more bytes would
have been read via PIO overwriting the end of the buffer with wrong
data. Make DMA stop handling more readable while we are here.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Wolfram Sang and committed by
Wolfram Sang
32e22409 d5fd120e

+11 -1
+11 -1
drivers/i2c/busses/i2c-sh_mobile.c
··· 139 139 int pos; 140 140 int sr; 141 141 bool send_stop; 142 + bool stop_after_dma; 142 143 143 144 struct resource *res; 144 145 struct dma_chan *dma_tx; ··· 408 407 409 408 if (pd->pos == pd->msg->len) { 410 409 /* Send stop if we haven't yet (DMA case) */ 411 - if (pd->send_stop && (iic_rd(pd, ICCR) & ICCR_BBSY)) 410 + if (pd->send_stop && pd->stop_after_dma) 412 411 i2c_op(pd, OP_TX_STOP, 0); 413 412 return 1; 414 413 } ··· 450 449 real_pos = pd->pos - 2; 451 450 452 451 if (pd->pos == pd->msg->len) { 452 + if (pd->stop_after_dma) { 453 + /* Simulate PIO end condition after DMA transfer */ 454 + i2c_op(pd, OP_RX_STOP, 0); 455 + pd->pos++; 456 + break; 457 + } 458 + 453 459 if (real_pos < 0) { 454 460 i2c_op(pd, OP_RX_STOP, 0); 455 461 break; ··· 544 536 545 537 sh_mobile_i2c_dma_unmap(pd); 546 538 pd->pos = pd->msg->len; 539 + pd->stop_after_dma = true; 547 540 548 541 iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); 549 542 } ··· 735 726 bool do_start = pd->send_stop || !i; 736 727 msg = &msgs[i]; 737 728 pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP; 729 + pd->stop_after_dma = false; 738 730 739 731 err = start_ch(pd, msg, do_start); 740 732 if (err)