Commit 50635787 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull spi fixes from Mark Brown:
 "Several fixes that came in since the merge window, the major one being
  a fix for the spi-mux driver which was broken by the performance
  optimisations due to it peering inside the core's data structures more
  than it should"

* tag 'spi-fix-v6.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: spi: Fix queue hang if previous transfer failed
  spi: mux: Fix mux interaction with fast path optimisations
  spi: cadence-quadspi: Disable irqs during indirect reads
  spi: bitbang: Fix lsb-first Rx
parents c5e68c4f 9c9c9da7
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
{
	/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */

	u8 rxbit = bits - 1;
	u32 oldbit = !(word & 1);
	/* clock starts at inactive polarity */
	for (; likely(bits); bits--) {
@@ -135,7 +136,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
		/* sample LSB (from slave) on leading edge */
		word >>= 1;
		if ((flags & SPI_MASTER_NO_RX) == 0)
			word |= getmiso(spi) << (bits - 1);
			word |= getmiso(spi) << rxbit;
		setsck(spi, cpol);
	}
	return word;
@@ -148,6 +149,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
{
	/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */

	u8 rxbit = bits - 1;
	u32 oldbit = !(word & 1);
	/* clock starts at inactive polarity */
	for (; likely(bits); bits--) {
@@ -168,7 +170,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
		/* sample LSB (from slave) on trailing edge */
		word >>= 1;
		if ((flags & SPI_MASTER_NO_RX) == 0)
			word |= getmiso(spi) << (bits - 1);
			word |= getmiso(spi) << rxbit;
	}
	return word;
}
+34 −4
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#define CQSPI_DISABLE_DAC_MODE		BIT(1)
#define CQSPI_SUPPORT_EXTERNAL_DMA	BIT(2)
#define CQSPI_NO_SUPPORT_WR_COMPLETION	BIT(3)
#define CQSPI_SLOW_SRAM		BIT(4)

/* Capabilities */
#define CQSPI_SUPPORTS_OCTAL		BIT(0)
@@ -87,6 +88,7 @@ struct cqspi_st {
	bool			use_dma_read;
	u32			pd_dev_id;
	bool			wr_completion;
	bool			slow_sram;
};

struct cqspi_driver_platdata {
@@ -333,7 +335,10 @@ static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
		}
	}

	else if (!cqspi->slow_sram)
		irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
	else
		irq_status &= CQSPI_REG_IRQ_WATERMARK | CQSPI_IRQ_MASK_WR;

	if (irq_status)
		complete(&cqspi->transfer_complete);
@@ -673,7 +678,18 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
	/* Clear all interrupts. */
	writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);

	/*
	 * On SoCFPGA platform reading the SRAM is slow due to
	 * hardware limitation and causing read interrupt storm to CPU,
	 * so enabling only watermark interrupt to disable all read
	 * interrupts later as we want to run "bytes to read" loop with
	 * all the read interrupts disabled for max performance.
	 */

	if (!cqspi->slow_sram)
		writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
	else
		writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);

	reinit_completion(&cqspi->transfer_complete);
	writel(CQSPI_REG_INDIRECTRD_START_MASK,
@@ -684,6 +700,13 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
						 msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS)))
			ret = -ETIMEDOUT;

		/*
		 * Disable all read interrupts until
		 * we are out of "bytes to read"
		 */
		if (cqspi->slow_sram)
			writel(0x0, reg_base + CQSPI_REG_IRQMASK);

		bytes_to_read = cqspi_get_rd_sram_level(cqspi);

		if (ret && bytes_to_read == 0) {
@@ -715,8 +738,11 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
			bytes_to_read = cqspi_get_rd_sram_level(cqspi);
		}

		if (remaining > 0)
		if (remaining > 0) {
			reinit_completion(&cqspi->transfer_complete);
			if (cqspi->slow_sram)
				writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
		}
	}

	/* Check indirect done status */
@@ -1667,6 +1693,8 @@ static int cqspi_probe(struct platform_device *pdev)
			cqspi->use_dma_read = true;
		if (ddata->quirks & CQSPI_NO_SUPPORT_WR_COMPLETION)
			cqspi->wr_completion = false;
		if (ddata->quirks & CQSPI_SLOW_SRAM)
			cqspi->slow_sram = true;

		if (of_device_is_compatible(pdev->dev.of_node,
					    "xlnx,versal-ospi-1.0"))
@@ -1779,7 +1807,9 @@ static const struct cqspi_driver_platdata intel_lgm_qspi = {
};

static const struct cqspi_driver_platdata socfpga_qspi = {
	.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_NO_SUPPORT_WR_COMPLETION,
	.quirks = CQSPI_DISABLE_DAC_MODE
			| CQSPI_NO_SUPPORT_WR_COMPLETION
			| CQSPI_SLOW_SRAM,
};

static const struct cqspi_driver_platdata versal_ospi = {
+1 −0
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ static int spi_mux_probe(struct spi_device *spi)
	ctlr->num_chipselect = mux_control_states(priv->mux);
	ctlr->bus_num = -1;
	ctlr->dev.of_node = spi->dev.of_node;
	ctlr->must_async = true;

	ret = devm_spi_register_controller(&spi->dev, ctlr);
	if (ret)
+2 −3
Original line number Diff line number Diff line
@@ -1727,7 +1727,6 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
	spin_unlock_irqrestore(&ctlr->queue_lock, flags);

	ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
	if (!ret)
	kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);

	ctlr->cur_msg = NULL;
@@ -4033,7 +4032,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
	 * guard against reentrancy from a different context. The io_mutex
	 * will catch those cases.
	 */
	if (READ_ONCE(ctlr->queue_empty)) {
	if (READ_ONCE(ctlr->queue_empty) && !ctlr->must_async) {
		message->actual_length = 0;
		message->status = -EINPROGRESS;

+2 −0
Original line number Diff line number Diff line
@@ -469,6 +469,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
 *	SPI_TRANS_FAIL_NO_START.
 * @queue_empty: signal green light for opportunistically skipping the queue
 *	for spi_sync transfers.
 * @must_async: disable all fast paths in the core
 *
 * Each SPI controller can communicate with one or more @spi_device
 * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@ -690,6 +691,7 @@ struct spi_controller {

	/* Flag for enabling opportunistic skipping of the queue in spi_sync */
	bool			queue_empty;
	bool			must_async;
};

static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)