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.
Unified · Split
| @@ -139,6 +139,7 @@ struct sh_mobile_i2c_data { · 138 unmodified lines | ||
| 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; |
| @@ -407,7 +408,7 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) · 262 unmodified lines | ||
| 407 | 408 | |
| 408 | 409 | if (pd->pos == pd->msg->len) { |
| 409 | 410 | /* Send stop if we haven't yet (DMA case) */ |
| 410 | − if (pd->send_stop && (iic_rd(pd, ICCR) & ICCR_BBSY)) | |
| 411 | + if (pd->send_stop && pd->stop_after_dma) | |
| 411 | 412 | i2c_op(pd, OP_TX_STOP, 0); |
| 412 | 413 | return 1; |
| 413 | 414 | } |
| @@ -449,6 +450,13 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) · 35 unmodified lines | ||
| 449 | 450 | real_pos = pd->pos - 2; |
| 450 | 451 | |
| 451 | 452 | if (pd->pos == pd->msg->len) { |
| 453 | + if (pd->stop_after_dma) { | |
| 454 | + /* Simulate PIO end condition after DMA transfer */ | |
| 455 | + i2c_op(pd, OP_RX_STOP, 0); | |
| 456 | + pd->pos++; | |
| 457 | + break; | |
| 458 | + } | |
| 459 | + | |
| 452 | 460 | if (real_pos < 0) { |
| 453 | 461 | i2c_op(pd, OP_RX_STOP, 0); |
| 454 | 462 | break; |
| @@ -536,6 +544,7 @@ static void sh_mobile_i2c_dma_callback(void *data) · 81 unmodified lines | ||
| 536 | 544 | |
| 537 | 545 | sh_mobile_i2c_dma_unmap(pd); |
| 538 | 546 | pd->pos = pd->msg->len; |
| 547 | + pd->stop_after_dma = true; | |
| 539 | 548 | |
| 540 | 549 | iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); |
| 541 | 550 | } |
| @@ -726,6 +735,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, · 184 unmodified lines | ||
| 726 | 735 | bool do_start = pd->send_stop || !i; |
| 727 | 736 | msg = &msgs[i]; |
| 728 | 737 | pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP; |
| 738 | + pd->stop_after_dma = false; | |
| 729 | 739 | |
| 730 | 740 | err = start_ch(pd, msg, do_start); |
| 731 | 741 | if (err) |