Commit ab386c46 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/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
parents c5364190 c926c87b
...@@ -349,12 +349,12 @@ static int amd_mp2_pci_probe(struct pci_dev *pci_dev, ...@@ -349,12 +349,12 @@ static int amd_mp2_pci_probe(struct pci_dev *pci_dev,
if (!privdata) if (!privdata)
return -ENOMEM; return -ENOMEM;
privdata->pci_dev = pci_dev;
rc = amd_mp2_pci_init(privdata, pci_dev); rc = amd_mp2_pci_init(privdata, pci_dev);
if (rc) if (rc)
return rc; return rc;
mutex_init(&privdata->c2p_lock); mutex_init(&privdata->c2p_lock);
privdata->pci_dev = pci_dev;
pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000); pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000);
pm_runtime_use_autosuspend(&pci_dev->dev); pm_runtime_use_autosuspend(&pci_dev->dev);
......
...@@ -603,6 +603,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) ...@@ -603,6 +603,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
/* Ack all interrupts except for Rx done */ /* Ack all interrupts except for Rx done */
writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,
bus->base + ASPEED_I2C_INTR_STS_REG); bus->base + ASPEED_I2C_INTR_STS_REG);
readl(bus->base + ASPEED_I2C_INTR_STS_REG);
irq_remaining = irq_received; irq_remaining = irq_received;
#if IS_ENABLED(CONFIG_I2C_SLAVE) #if IS_ENABLED(CONFIG_I2C_SLAVE)
...@@ -645,9 +646,11 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) ...@@ -645,9 +646,11 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
irq_received, irq_handled); irq_received, irq_handled);
/* Ack Rx done */ /* 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, writel(ASPEED_I2CD_INTR_RX_DONE,
bus->base + ASPEED_I2C_INTR_STS_REG); bus->base + ASPEED_I2C_INTR_STS_REG);
readl(bus->base + ASPEED_I2C_INTR_STS_REG);
}
spin_unlock(&bus->lock); spin_unlock(&bus->lock);
return irq_remaining ? IRQ_NONE : IRQ_HANDLED; return irq_remaining ? IRQ_NONE : IRQ_HANDLED;
} }
......
...@@ -360,6 +360,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, ...@@ -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); value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
i2c_slave_event(iproc_i2c->slave, i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_RECEIVED, &value); 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)) { } else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
/* Master read other than start */ /* Master read other than start */
......
...@@ -996,7 +996,7 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev, ...@@ -996,7 +996,7 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
do { do {
u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS); u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
if (status) if (status) {
tegra_i2c_isr(i2c_dev->irq, i2c_dev); tegra_i2c_isr(i2c_dev->irq, i2c_dev);
if (completion_done(complete)) { if (completion_done(complete)) {
...@@ -1004,6 +1004,7 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev, ...@@ -1004,6 +1004,7 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
return msecs_to_jiffies(delta) ?: 1; return msecs_to_jiffies(delta) ?: 1;
} }
}
ktime = ktime_get(); ktime = ktime_get();
...@@ -1029,18 +1030,14 @@ tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev, ...@@ -1029,18 +1030,14 @@ tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
disable_irq(i2c_dev->irq); disable_irq(i2c_dev->irq);
/* /*
* Under some rare circumstances (like running KASAN + * There is a chance that completion may happen after IRQ
* NFS root) CPU, which handles interrupt, may stuck in * synchronization, which is done by disable_irq().
* 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.
*/ */
if (ret == 0) if (ret == 0 && completion_done(complete)) {
ret = tegra_i2c_poll_completion_timeout(i2c_dev, dev_warn(i2c_dev->dev,
complete, 0); "completion done after timeout\n");
ret = 1;
}
} }
return ret; return ret;
...@@ -1219,15 +1216,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, ...@@ -1219,15 +1216,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
time_left = tegra_i2c_wait_completion_timeout( time_left = tegra_i2c_wait_completion_timeout(
i2c_dev, &i2c_dev->dma_complete, xfer_time); 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 ? dmaengine_terminate_sync(i2c_dev->msg_read ?
i2c_dev->rx_dma_chan : i2c_dev->rx_dma_chan :
i2c_dev->tx_dma_chan); i2c_dev->tx_dma_chan);
......
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