Commit ace92fd9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-6.7-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull more i2c updates from Wolfram Sang:
 "This contains one patch which slipped through the cracks (iproc), a
  core sanitizing improvement as the new memdup_array_user() helper went
  upstream (i2c-dev), and two driver bugfixes (designware, cp2615)"

* tag 'for-6.7-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: cp2615: Fix 'assignment to __be16' warning
  i2c: dev: copy userspace array safely
  i2c: designware: Disable TX_EMPTY irq while waiting for block length byte
  i2c: iproc: handle invalid slave state
parents 12418ece bdba49cb
...@@ -316,26 +316,44 @@ static void bcm_iproc_i2c_slave_init( ...@@ -316,26 +316,44 @@ static void bcm_iproc_i2c_slave_init(
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
} }
static void bcm_iproc_i2c_check_slave_status( static bool bcm_iproc_i2c_check_slave_status
struct bcm_iproc_i2c_dev *iproc_i2c) (struct bcm_iproc_i2c_dev *iproc_i2c, u32 status)
{ {
u32 val; u32 val;
bool recover = false;
/* check slave transmit status only if slave is transmitting */
if (!iproc_i2c->slave_rx_only) {
val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET); val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET);
/* status is valid only when START_BUSY is cleared after it was set */ /* status is valid only when START_BUSY is cleared */
if (val & BIT(S_CMD_START_BUSY_SHIFT)) if (!(val & BIT(S_CMD_START_BUSY_SHIFT))) {
return;
val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) { if (val == S_CMD_STATUS_TIMEOUT ||
dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ? val == S_CMD_STATUS_MASTER_ABORT) {
dev_warn(iproc_i2c->device,
(val == S_CMD_STATUS_TIMEOUT) ?
"slave random stretch time timeout\n" : "slave random stretch time timeout\n" :
"Master aborted read transaction\n"); "Master aborted read transaction\n");
recover = true;
}
}
}
/* RX_EVENT is not valid when START_BUSY is set */
if ((status & BIT(IS_S_RX_EVENT_SHIFT)) &&
(status & BIT(IS_S_START_BUSY_SHIFT))) {
dev_warn(iproc_i2c->device, "Slave aborted read transaction\n");
recover = true;
}
if (recover) {
/* re-initialize i2c for recovery */ /* re-initialize i2c for recovery */
bcm_iproc_i2c_enable_disable(iproc_i2c, false); bcm_iproc_i2c_enable_disable(iproc_i2c, false);
bcm_iproc_i2c_slave_init(iproc_i2c, true); bcm_iproc_i2c_slave_init(iproc_i2c, true);
bcm_iproc_i2c_enable_disable(iproc_i2c, true); bcm_iproc_i2c_enable_disable(iproc_i2c, true);
} }
return recover;
} }
static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c) 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, ...@@ -420,48 +438,6 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
u32 val; u32 val;
u8 value; u8 value;
/*
* Slave events in case of master-write, master-write-read and,
* master-read
*
* Master-write : only IS_S_RX_EVENT_SHIFT event
* Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
* events
* Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
* events or only IS_S_RD_EVENT_SHIFT
*
* iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt
* (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes
* full. This can happen if Master issues write requests of more than
* 64 bytes.
*/
if (status & BIT(IS_S_RX_EVENT_SHIFT) ||
status & BIT(IS_S_RD_EVENT_SHIFT) ||
status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
/* disable slave interrupts */
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
val &= ~iproc_i2c->slave_int_mask;
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
if (status & BIT(IS_S_RD_EVENT_SHIFT))
/* Master-write-read request */
iproc_i2c->slave_rx_only = false;
else
/* Master-write request only */
iproc_i2c->slave_rx_only = true;
/* schedule tasklet to read data later */
tasklet_schedule(&iproc_i2c->slave_rx_tasklet);
/*
* clear only IS_S_RX_EVENT_SHIFT and
* IS_S_RX_FIFO_FULL_SHIFT interrupt.
*/
val = BIT(IS_S_RX_EVENT_SHIFT);
if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT))
val |= BIT(IS_S_RX_FIFO_FULL_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val);
}
if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
iproc_i2c->tx_underrun++; iproc_i2c->tx_underrun++;
...@@ -493,8 +469,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, ...@@ -493,8 +469,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
* less than PKT_LENGTH bytes were output on the SMBUS * less than PKT_LENGTH bytes were output on the SMBUS
*/ */
iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
iproc_i2c->slave_int_mask); val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
/* End of SMBUS for Master Read */ /* End of SMBUS for Master Read */
val = BIT(S_TX_WR_STATUS_SHIFT); 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, ...@@ -515,9 +492,49 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
BIT(IS_S_START_BUSY_SHIFT)); BIT(IS_S_START_BUSY_SHIFT));
} }
/* check slave transmit status only if slave is transmitting */ /* if the controller has been reset, immediately return from the ISR */
if (!iproc_i2c->slave_rx_only) if (bcm_iproc_i2c_check_slave_status(iproc_i2c, status))
bcm_iproc_i2c_check_slave_status(iproc_i2c); return true;
/*
* Slave events in case of master-write, master-write-read and,
* master-read
*
* Master-write : only IS_S_RX_EVENT_SHIFT event
* Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
* events
* Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
* events or only IS_S_RD_EVENT_SHIFT
*
* iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt
* (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes
* full. This can happen if Master issues write requests of more than
* 64 bytes.
*/
if (status & BIT(IS_S_RX_EVENT_SHIFT) ||
status & BIT(IS_S_RD_EVENT_SHIFT) ||
status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
/* disable slave interrupts */
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
val &= ~iproc_i2c->slave_int_mask;
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
if (status & BIT(IS_S_RD_EVENT_SHIFT))
/* Master-write-read request */
iproc_i2c->slave_rx_only = false;
else
/* Master-write request only */
iproc_i2c->slave_rx_only = true;
/* schedule tasklet to read data later */
tasklet_schedule(&iproc_i2c->slave_rx_tasklet);
/* clear IS_S_RX_FIFO_FULL_SHIFT interrupt */
if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
val = BIT(IS_S_RX_FIFO_FULL_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val);
}
}
return true; return true;
} }
......
...@@ -85,7 +85,7 @@ static int cp2615_init_iop_msg(struct cp2615_iop_msg *ret, enum cp2615_iop_msg_t ...@@ -85,7 +85,7 @@ static int cp2615_init_iop_msg(struct cp2615_iop_msg *ret, enum cp2615_iop_msg_t
if (!ret) if (!ret)
return -EINVAL; return -EINVAL;
ret->preamble = 0x2A2A; ret->preamble = htons(0x2A2AU);
ret->length = htons(data_len + 6); ret->length = htons(data_len + 6);
ret->msg = htons(msg); ret->msg = htons(msg);
if (data && data_len) if (data && data_len)
......
...@@ -519,10 +519,16 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) ...@@ -519,10 +519,16 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
/* /*
* Because we don't know the buffer length in the * Because we don't know the buffer length in the
* I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop the
* the transaction here. * transaction here. Also disable the TX_EMPTY IRQ
* while waiting for the data length byte to avoid the
* bogus interrupts flood.
*/ */
if (buf_len > 0 || flags & I2C_M_RECV_LEN) { if (flags & I2C_M_RECV_LEN) {
dev->status |= STATUS_WRITE_IN_PROGRESS;
intr_mask &= ~DW_IC_INTR_TX_EMPTY;
break;
} else if (buf_len > 0) {
/* more bytes to be written */ /* more bytes to be written */
dev->status |= STATUS_WRITE_IN_PROGRESS; dev->status |= STATUS_WRITE_IN_PROGRESS;
break; break;
...@@ -558,6 +564,13 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len) ...@@ -558,6 +564,13 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
msgs[dev->msg_read_idx].len = len; msgs[dev->msg_read_idx].len = len;
msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN; msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
/*
* Received buffer length, re-enable TX_EMPTY interrupt
* to resume the SMBUS transaction.
*/
regmap_update_bits(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY,
DW_IC_INTR_TX_EMPTY);
return len; return len;
} }
......
...@@ -450,8 +450,8 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -450,8 +450,8 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
return -EINVAL; return -EINVAL;
rdwr_pa = memdup_user(rdwr_arg.msgs, rdwr_pa = memdup_array_user(rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg)); rdwr_arg.nmsgs, sizeof(struct i2c_msg));
if (IS_ERR(rdwr_pa)) if (IS_ERR(rdwr_pa))
return PTR_ERR(rdwr_pa); return PTR_ERR(rdwr_pa);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment