Commit ab386c46 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+4 −1
Original line number Diff line number Diff line
@@ -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)
@@ -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;
}
+3 −0
Original line number Diff line number Diff line
@@ -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 */
+12 −24
Original line number Diff line number Diff line
@@ -996,7 +996,7 @@ 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)) {
@@ -1004,6 +1004,7 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,

				return msecs_to_jiffies(delta) ?: 1;
			}
		}

		ktime = ktime_get();

@@ -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;
@@ -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);