Skip to content

Commit ba15a14

Browse files
roman-brcmwsakernel
authored andcommitted
i2c: iproc: handle invalid slave state
Add the code to handle an invalid state when both bits S_RX_EVENT (indicating a transaction) and S_START_BUSY (indicating the end of transaction - transition of START_BUSY from 1 to 0) are set in the interrupt status register during a slave read. Signed-off-by: Roman Bacik <[email protected]> Fixes: 1ca1b45 ("i2c: iproc: handle Master aborted error") Acked-by: Ray Jui <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 3052301 commit ba15a14

File tree

1 file changed

+75
-58
lines changed

1 file changed

+75
-58
lines changed

drivers/i2c/busses/i2c-bcm-iproc.c

Lines changed: 75 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -316,26 +316,44 @@ static void bcm_iproc_i2c_slave_init(
316316
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
317317
}
318318

319-
static void bcm_iproc_i2c_check_slave_status(
320-
struct bcm_iproc_i2c_dev *iproc_i2c)
319+
static bool bcm_iproc_i2c_check_slave_status
320+
(struct bcm_iproc_i2c_dev *iproc_i2c, u32 status)
321321
{
322322
u32 val;
323+
bool recover = false;
323324

324-
val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET);
325-
/* status is valid only when START_BUSY is cleared after it was set */
326-
if (val & BIT(S_CMD_START_BUSY_SHIFT))
327-
return;
325+
/* check slave transmit status only if slave is transmitting */
326+
if (!iproc_i2c->slave_rx_only) {
327+
val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET);
328+
/* status is valid only when START_BUSY is cleared */
329+
if (!(val & BIT(S_CMD_START_BUSY_SHIFT))) {
330+
val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
331+
if (val == S_CMD_STATUS_TIMEOUT ||
332+
val == S_CMD_STATUS_MASTER_ABORT) {
333+
dev_warn(iproc_i2c->device,
334+
(val == S_CMD_STATUS_TIMEOUT) ?
335+
"slave random stretch time timeout\n" :
336+
"Master aborted read transaction\n");
337+
recover = true;
338+
}
339+
}
340+
}
341+
342+
/* RX_EVENT is not valid when START_BUSY is set */
343+
if ((status & BIT(IS_S_RX_EVENT_SHIFT)) &&
344+
(status & BIT(IS_S_START_BUSY_SHIFT))) {
345+
dev_warn(iproc_i2c->device, "Slave aborted read transaction\n");
346+
recover = true;
347+
}
328348

329-
val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
330-
if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) {
331-
dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ?
332-
"slave random stretch time timeout\n" :
333-
"Master aborted read transaction\n");
349+
if (recover) {
334350
/* re-initialize i2c for recovery */
335351
bcm_iproc_i2c_enable_disable(iproc_i2c, false);
336352
bcm_iproc_i2c_slave_init(iproc_i2c, true);
337353
bcm_iproc_i2c_enable_disable(iproc_i2c, true);
338354
}
355+
356+
return recover;
339357
}
340358

341359
static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c)
@@ -420,48 +438,6 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
420438
u32 val;
421439
u8 value;
422440

423-
/*
424-
* Slave events in case of master-write, master-write-read and,
425-
* master-read
426-
*
427-
* Master-write : only IS_S_RX_EVENT_SHIFT event
428-
* Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
429-
* events
430-
* Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
431-
* events or only IS_S_RD_EVENT_SHIFT
432-
*
433-
* iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt
434-
* (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes
435-
* full. This can happen if Master issues write requests of more than
436-
* 64 bytes.
437-
*/
438-
if (status & BIT(IS_S_RX_EVENT_SHIFT) ||
439-
status & BIT(IS_S_RD_EVENT_SHIFT) ||
440-
status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
441-
/* disable slave interrupts */
442-
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
443-
val &= ~iproc_i2c->slave_int_mask;
444-
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
445-
446-
if (status & BIT(IS_S_RD_EVENT_SHIFT))
447-
/* Master-write-read request */
448-
iproc_i2c->slave_rx_only = false;
449-
else
450-
/* Master-write request only */
451-
iproc_i2c->slave_rx_only = true;
452-
453-
/* schedule tasklet to read data later */
454-
tasklet_schedule(&iproc_i2c->slave_rx_tasklet);
455-
456-
/*
457-
* clear only IS_S_RX_EVENT_SHIFT and
458-
* IS_S_RX_FIFO_FULL_SHIFT interrupt.
459-
*/
460-
val = BIT(IS_S_RX_EVENT_SHIFT);
461-
if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT))
462-
val |= BIT(IS_S_RX_FIFO_FULL_SHIFT);
463-
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val);
464-
}
465441

466442
if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
467443
iproc_i2c->tx_underrun++;
@@ -493,8 +469,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
493469
* less than PKT_LENGTH bytes were output on the SMBUS
494470
*/
495471
iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
496-
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET,
497-
iproc_i2c->slave_int_mask);
472+
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
473+
val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
474+
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
498475

499476
/* End of SMBUS for Master Read */
500477
val = BIT(S_TX_WR_STATUS_SHIFT);
@@ -515,9 +492,49 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
515492
BIT(IS_S_START_BUSY_SHIFT));
516493
}
517494

518-
/* check slave transmit status only if slave is transmitting */
519-
if (!iproc_i2c->slave_rx_only)
520-
bcm_iproc_i2c_check_slave_status(iproc_i2c);
495+
/* if the controller has been reset, immediately return from the ISR */
496+
if (bcm_iproc_i2c_check_slave_status(iproc_i2c, status))
497+
return true;
498+
499+
/*
500+
* Slave events in case of master-write, master-write-read and,
501+
* master-read
502+
*
503+
* Master-write : only IS_S_RX_EVENT_SHIFT event
504+
* Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
505+
* events
506+
* Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
507+
* events or only IS_S_RD_EVENT_SHIFT
508+
*
509+
* iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt
510+
* (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes
511+
* full. This can happen if Master issues write requests of more than
512+
* 64 bytes.
513+
*/
514+
if (status & BIT(IS_S_RX_EVENT_SHIFT) ||
515+
status & BIT(IS_S_RD_EVENT_SHIFT) ||
516+
status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
517+
/* disable slave interrupts */
518+
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
519+
val &= ~iproc_i2c->slave_int_mask;
520+
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
521+
522+
if (status & BIT(IS_S_RD_EVENT_SHIFT))
523+
/* Master-write-read request */
524+
iproc_i2c->slave_rx_only = false;
525+
else
526+
/* Master-write request only */
527+
iproc_i2c->slave_rx_only = true;
528+
529+
/* schedule tasklet to read data later */
530+
tasklet_schedule(&iproc_i2c->slave_rx_tasklet);
531+
532+
/* clear IS_S_RX_FIFO_FULL_SHIFT interrupt */
533+
if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
534+
val = BIT(IS_S_RX_FIFO_FULL_SHIFT);
535+
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val);
536+
}
537+
}
521538

522539
return true;
523540
}

0 commit comments

Comments
 (0)