mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-08 14:13:53 +00:00
The second I2C pull request for 6.7-rc1 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). -----BEGIN PGP SIGNATURE----- iQJDBAABCgAtFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmVMgqoPHHdzYUBrZXJu ZWwub3JnAAoJEBQN5MwUoCm23X0QAIsc4vBzKsuKPPtL+STrHCoBhkYxOdb8EBH+ 48weQApP8aTyScNDAgHlNAVfZohVh2WPrMieYn123z6ep2Yu+mxF7WyGfCryHSvl OoB5r5XAfDIERlx1a4Zbm4CMsx9TDbMyHk/2XZKVWWQYCT2PLNXVT+HgA3z6GTuL jbmzho2YEcgZpVzd2l3zSgoOWcBH2mECG1WuFC/67/HFRz08FOlNQgF18LjgAg+X 4U4VZGB3utl4Rgum3eE/i3/MJWUCLM28Ltn68iZoVZVf7MBdHRt0Vwh1350+oGbu R8qz5rXJKfhqe12NXLrpzrlXYIgLAFjx3IICav7/7Lo+na7ufdLOQhtAxDQnzvvp aIVH3sqDRXutKW0JwJXnpbJGRSiRtVb+9K8LmpviTBiGMabkZGYIeRS9lMX0JZEo 7UufwQpMaL3i0r+gVnhoOJAhgFAWfHkt1LqhnirWX34F9rzZrDkl1uiM01yw0Ltn dXS2IW6FYjywgfRMTERxMJX3N80e4ZC5tx1bMvvJlEO6nFMKjyo7xN8yHS+Bnk70 YH1Jm0/hr8VzAGkLQ0oyVu3uRYzPJccsMTtlu5LAxCLydZReDbeVirNLxHdMFjra fOuR2mzcAXqnahDmd40k6VRif/XkhhlyEglAIVbPWqrNBlDBFvh+XjxwDZ5Jw7Vb 3/monZ4/ =TSKf -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
ace92fd984
@ -316,26 +316,44 @@ static void bcm_iproc_i2c_slave_init(
|
||||
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
|
||||
}
|
||||
|
||||
static void bcm_iproc_i2c_check_slave_status(
|
||||
struct bcm_iproc_i2c_dev *iproc_i2c)
|
||||
static bool bcm_iproc_i2c_check_slave_status
|
||||
(struct bcm_iproc_i2c_dev *iproc_i2c, u32 status)
|
||||
{
|
||||
u32 val;
|
||||
bool recover = false;
|
||||
|
||||
val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET);
|
||||
/* status is valid only when START_BUSY is cleared after it was set */
|
||||
if (val & BIT(S_CMD_START_BUSY_SHIFT))
|
||||
return;
|
||||
/* 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);
|
||||
/* status is valid only when START_BUSY is cleared */
|
||||
if (!(val & BIT(S_CMD_START_BUSY_SHIFT))) {
|
||||
val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
|
||||
if (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" :
|
||||
"Master aborted read transaction\n");
|
||||
recover = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
|
||||
if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) {
|
||||
dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ?
|
||||
"slave random stretch time timeout\n" :
|
||||
"Master aborted read transaction\n");
|
||||
/* 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 */
|
||||
bcm_iproc_i2c_enable_disable(iproc_i2c, false);
|
||||
bcm_iproc_i2c_slave_init(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)
|
||||
@ -420,6 +438,64 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
u32 val;
|
||||
u8 value;
|
||||
|
||||
|
||||
if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
|
||||
iproc_i2c->tx_underrun++;
|
||||
if (iproc_i2c->tx_underrun == 1)
|
||||
/* Start of SMBUS for Master Read */
|
||||
i2c_slave_event(iproc_i2c->slave,
|
||||
I2C_SLAVE_READ_REQUESTED,
|
||||
&value);
|
||||
else
|
||||
/* Master read other than start */
|
||||
i2c_slave_event(iproc_i2c->slave,
|
||||
I2C_SLAVE_READ_PROCESSED,
|
||||
&value);
|
||||
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
|
||||
/* start transfer */
|
||||
val = BIT(S_CMD_START_BUSY_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
|
||||
|
||||
/* clear interrupt */
|
||||
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
|
||||
BIT(IS_S_TX_UNDERRUN_SHIFT));
|
||||
}
|
||||
|
||||
/* Stop received from master in case of master read transaction */
|
||||
if (status & BIT(IS_S_START_BUSY_SHIFT)) {
|
||||
/*
|
||||
* Disable interrupt for TX FIFO becomes empty and
|
||||
* less than PKT_LENGTH bytes were output on the SMBUS
|
||||
*/
|
||||
iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
|
||||
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
|
||||
val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
|
||||
|
||||
/* End of SMBUS for Master Read */
|
||||
val = BIT(S_TX_WR_STATUS_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, val);
|
||||
|
||||
val = BIT(S_CMD_START_BUSY_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
|
||||
|
||||
/* flush TX FIFOs */
|
||||
val = iproc_i2c_rd_reg(iproc_i2c, S_FIFO_CTRL_OFFSET);
|
||||
val |= (BIT(S_FIFO_TX_FLUSH_SHIFT));
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val);
|
||||
|
||||
i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
|
||||
|
||||
/* clear interrupt */
|
||||
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
|
||||
BIT(IS_S_START_BUSY_SHIFT));
|
||||
}
|
||||
|
||||
/* if the controller has been reset, immediately return from the ISR */
|
||||
if (bcm_iproc_i2c_check_slave_status(iproc_i2c, status))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Slave events in case of master-write, master-write-read and,
|
||||
* master-read
|
||||
@ -453,72 +529,13 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
/* 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);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
|
||||
iproc_i2c->tx_underrun++;
|
||||
if (iproc_i2c->tx_underrun == 1)
|
||||
/* Start of SMBUS for Master Read */
|
||||
i2c_slave_event(iproc_i2c->slave,
|
||||
I2C_SLAVE_READ_REQUESTED,
|
||||
&value);
|
||||
else
|
||||
/* Master read other than start */
|
||||
i2c_slave_event(iproc_i2c->slave,
|
||||
I2C_SLAVE_READ_PROCESSED,
|
||||
&value);
|
||||
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
|
||||
/* start transfer */
|
||||
val = BIT(S_CMD_START_BUSY_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
|
||||
|
||||
/* clear interrupt */
|
||||
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
|
||||
BIT(IS_S_TX_UNDERRUN_SHIFT));
|
||||
}
|
||||
|
||||
/* Stop received from master in case of master read transaction */
|
||||
if (status & BIT(IS_S_START_BUSY_SHIFT)) {
|
||||
/*
|
||||
* Disable interrupt for TX FIFO becomes empty and
|
||||
* less than PKT_LENGTH bytes were output on the SMBUS
|
||||
*/
|
||||
iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET,
|
||||
iproc_i2c->slave_int_mask);
|
||||
|
||||
/* End of SMBUS for Master Read */
|
||||
val = BIT(S_TX_WR_STATUS_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, val);
|
||||
|
||||
val = BIT(S_CMD_START_BUSY_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
|
||||
|
||||
/* flush TX FIFOs */
|
||||
val = iproc_i2c_rd_reg(iproc_i2c, S_FIFO_CTRL_OFFSET);
|
||||
val |= (BIT(S_FIFO_TX_FLUSH_SHIFT));
|
||||
iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val);
|
||||
|
||||
i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
|
||||
|
||||
/* clear interrupt */
|
||||
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
|
||||
BIT(IS_S_START_BUSY_SHIFT));
|
||||
}
|
||||
|
||||
/* check slave transmit status only if slave is transmitting */
|
||||
if (!iproc_i2c->slave_rx_only)
|
||||
bcm_iproc_i2c_check_slave_status(iproc_i2c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ static int cp2615_init_iop_msg(struct cp2615_iop_msg *ret, enum cp2615_iop_msg_t
|
||||
if (!ret)
|
||||
return -EINVAL;
|
||||
|
||||
ret->preamble = 0x2A2A;
|
||||
ret->preamble = htons(0x2A2AU);
|
||||
ret->length = htons(data_len + 6);
|
||||
ret->msg = htons(msg);
|
||||
if (data && data_len)
|
||||
|
@ -519,10 +519,16 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
||||
|
||||
/*
|
||||
* Because we don't know the buffer length in the
|
||||
* I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
|
||||
* the transaction here.
|
||||
* I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop the
|
||||
* 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 */
|
||||
dev->status |= STATUS_WRITE_IN_PROGRESS;
|
||||
break;
|
||||
@ -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].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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
return -EINVAL;
|
||||
|
||||
rdwr_pa = memdup_user(rdwr_arg.msgs,
|
||||
rdwr_arg.nmsgs * sizeof(struct i2c_msg));
|
||||
rdwr_pa = memdup_array_user(rdwr_arg.msgs,
|
||||
rdwr_arg.nmsgs, sizeof(struct i2c_msg));
|
||||
if (IS_ERR(rdwr_pa))
|
||||
return PTR_ERR(rdwr_pa);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user