Skip to content

Commit

Permalink
Merge branch 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/wsa/linux

Pull i2c fixes from Wolfram Sang:
 "Three driver bugfixes, and two reverts because the original patches
  revealed underlying problems which the Tegra guys are now working on"

* 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: aspeed: Avoid i2c interrupt status clear race condition.
  i2c: amd-mp2-pci: Fix Oops in amd_mp2_pci_init() error handling
  Revert "i2c: tegra: Better handle case where CPU0 is busy for a long time"
  Revert "i2c: tegra: Synchronize DMA before termination"
  i2c: iproc: generate stop event for slave writes
  • Loading branch information
torvalds committed May 1, 2020
2 parents c536419 + c926c87 commit ab386c4
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 26 deletions.
2 changes: 1 addition & 1 deletion drivers/i2c/busses/i2c-amd-mp2-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,12 +349,12 @@ static int amd_mp2_pci_probe(struct pci_dev *pci_dev,
if (!privdata)
return -ENOMEM;

privdata->pci_dev = pci_dev;
rc = amd_mp2_pci_init(privdata, pci_dev);
if (rc)
return rc;

mutex_init(&privdata->c2p_lock);
privdata->pci_dev = pci_dev;

pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000);
pm_runtime_use_autosuspend(&pci_dev->dev);
Expand Down
5 changes: 4 additions & 1 deletion drivers/i2c/busses/i2c-aspeed.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
/* Ack all interrupts except for Rx done */
writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,
bus->base + ASPEED_I2C_INTR_STS_REG);
readl(bus->base + ASPEED_I2C_INTR_STS_REG);
irq_remaining = irq_received;

#if IS_ENABLED(CONFIG_I2C_SLAVE)
Expand Down Expand Up @@ -645,9 +646,11 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
irq_received, irq_handled);

/* Ack Rx done */
if (irq_received & ASPEED_I2CD_INTR_RX_DONE)
if (irq_received & ASPEED_I2CD_INTR_RX_DONE) {
writel(ASPEED_I2CD_INTR_RX_DONE,
bus->base + ASPEED_I2C_INTR_STS_REG);
readl(bus->base + ASPEED_I2C_INTR_STS_REG);
}
spin_unlock(&bus->lock);
return irq_remaining ? IRQ_NONE : IRQ_HANDLED;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/i2c/busses/i2c-bcm-iproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_RECEIVED, &value);
if (rx_status == I2C_SLAVE_RX_END)
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_STOP, &value);
}
} else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
/* Master read other than start */
Expand Down
36 changes: 12 additions & 24 deletions drivers/i2c/busses/i2c-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -996,13 +996,14 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
do {
u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);

if (status)
if (status) {
tegra_i2c_isr(i2c_dev->irq, i2c_dev);

if (completion_done(complete)) {
s64 delta = ktime_ms_delta(ktimeout, ktime);
if (completion_done(complete)) {
s64 delta = ktime_ms_delta(ktimeout, ktime);

return msecs_to_jiffies(delta) ?: 1;
return msecs_to_jiffies(delta) ?: 1;
}
}

ktime = ktime_get();
Expand All @@ -1029,18 +1030,14 @@ tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
disable_irq(i2c_dev->irq);

/*
* Under some rare circumstances (like running KASAN +
* NFS root) CPU, which handles interrupt, may stuck in
* uninterruptible state for a significant time. In this
* case we will get timeout if I2C transfer is running on
* a sibling CPU, despite of IRQ being raised.
*
* In order to handle this rare condition, the IRQ status
* needs to be checked after timeout.
* There is a chance that completion may happen after IRQ
* synchronization, which is done by disable_irq().
*/
if (ret == 0)
ret = tegra_i2c_poll_completion_timeout(i2c_dev,
complete, 0);
if (ret == 0 && completion_done(complete)) {
dev_warn(i2c_dev->dev,
"completion done after timeout\n");
ret = 1;
}
}

return ret;
Expand Down Expand Up @@ -1219,15 +1216,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
time_left = tegra_i2c_wait_completion_timeout(
i2c_dev, &i2c_dev->dma_complete, xfer_time);

/*
* Synchronize DMA first, since dmaengine_terminate_sync()
* performs synchronization after the transfer's termination
* and we want to get a completion if transfer succeeded.
*/
dmaengine_synchronize(i2c_dev->msg_read ?
i2c_dev->rx_dma_chan :
i2c_dev->tx_dma_chan);

dmaengine_terminate_sync(i2c_dev->msg_read ?
i2c_dev->rx_dma_chan :
i2c_dev->tx_dma_chan);
Expand Down

0 comments on commit ab386c4

Please sign in to comment.