Commit 7351a879 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull MMC fixes from Ulf Hansson:
 "MMC core:
   - Prevent splat from warning when setting maximum DMA segment

  MMC host:
   - mvsdio: Drop sg_miter support for PIO as it didn't work
   - sdhci-of-dwcmshc: Prevent stale interrupt for the T-Head 1520
     variant"

* tag 'mmc-v6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: sdhci-of-dwcmshc: Prevent stale command interrupt handling
  Revert "mmc: mvsdio: Use sg_miter for PIO"
  mmc: core: Only set maximum DMA segment size if DMA is supported
parents 3700dc91 27e8fe0d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -388,6 +388,7 @@ static struct gendisk *mmc_alloc_disk(struct mmc_queue *mq,

	blk_queue_rq_timeout(mq->queue, 60 * HZ);

	if (mmc_dev(host)->dma_parms)
		dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue));

	INIT_WORK(&mq->recovery_work, mmc_mq_recovery_handler);
+18 −53
Original line number Diff line number Diff line
@@ -38,9 +38,8 @@ struct mvsd_host {
	unsigned int xfer_mode;
	unsigned int intr_en;
	unsigned int ctrl;
	bool use_pio;
	struct sg_mapping_iter sg_miter;
	unsigned int pio_size;
	void *pio_ptr;
	unsigned int sg_frags;
	unsigned int ns_per_clk;
	unsigned int clock;
@@ -115,18 +114,11 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
		 * data when the buffer is not aligned on a 64 byte
		 * boundary.
		 */
		unsigned int miter_flags = SG_MITER_ATOMIC; /* Used from IRQ */

		if (data->flags & MMC_DATA_READ)
			miter_flags |= SG_MITER_TO_SG;
		else
			miter_flags |= SG_MITER_FROM_SG;

		host->pio_size = data->blocks * data->blksz;
		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, miter_flags);
		host->pio_ptr = sg_virt(data->sg);
		if (!nodma)
			dev_dbg(host->dev, "fallback to PIO for data\n");
		host->use_pio = true;
			dev_dbg(host->dev, "fallback to PIO for data at 0x%p size %d\n",
				host->pio_ptr, host->pio_size);
		return 1;
	} else {
		dma_addr_t phys_addr;
@@ -137,7 +129,6 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
		phys_addr = sg_dma_address(data->sg);
		mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff);
		mvsd_write(MVSD_SYS_ADDR_HI,  (u32)phys_addr >> 16);
		host->use_pio = false;
		return 0;
	}
}
@@ -297,8 +288,8 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,
{
	void __iomem *iobase = host->base;

	if (host->use_pio) {
		sg_miter_stop(&host->sg_miter);
	if (host->pio_ptr) {
		host->pio_ptr = NULL;
		host->pio_size = 0;
	} else {
		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags,
@@ -353,12 +344,9 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,
static irqreturn_t mvsd_irq(int irq, void *dev)
{
	struct mvsd_host *host = dev;
	struct sg_mapping_iter *sgm = &host->sg_miter;
	void __iomem *iobase = host->base;
	u32 intr_status, intr_done_mask;
	int irq_handled = 0;
	u16 *p;
	int s;

	intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
	dev_dbg(host->dev, "intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n",
@@ -382,36 +370,15 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
	spin_lock(&host->lock);

	/* PIO handling, if needed. Messy business... */
	if (host->use_pio) {
		/*
		 * As we set sgm->consumed this always gives a valid buffer
		 * position.
		 */
		if (!sg_miter_next(sgm)) {
			/* This should not happen */
			dev_err(host->dev, "ran out of scatter segments\n");
			spin_unlock(&host->lock);
			host->intr_en &=
				~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W |
				  MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W);
			mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
			return IRQ_HANDLED;
		}
		p = sgm->addr;
		s = sgm->length;
		if (s > host->pio_size)
			s = host->pio_size;
	}

	if (host->use_pio &&
	if (host->pio_size &&
	    (intr_status & host->intr_en &
	     (MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W))) {

		u16 *p = host->pio_ptr;
		int s = host->pio_size;
		while (s >= 32 && (intr_status & MVSD_NOR_RX_FIFO_8W)) {
			readsw(iobase + MVSD_FIFO, p, 16);
			p += 16;
			s -= 32;
			sgm->consumed += 32;
			intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
		}
		/*
@@ -424,7 +391,6 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
				put_unaligned(mvsd_read(MVSD_FIFO), p++);
				put_unaligned(mvsd_read(MVSD_FIFO), p++);
				s -= 4;
				sgm->consumed += 4;
				intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
			}
			if (s && s < 4 && (intr_status & MVSD_NOR_RX_READY)) {
@@ -432,13 +398,10 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
				val[0] = mvsd_read(MVSD_FIFO);
				val[1] = mvsd_read(MVSD_FIFO);
				memcpy(p, ((void *)&val) + 4 - s, s);
				sgm->consumed += s;
				s = 0;
				intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
			}
			/* PIO transfer done */
			host->pio_size -= sgm->consumed;
			if (host->pio_size == 0) {
			if (s == 0) {
				host->intr_en &=
				     ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W);
				mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
@@ -450,10 +413,14 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
		}
		dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
			s, intr_status, mvsd_read(MVSD_HW_STATE));
		host->pio_ptr = p;
		host->pio_size = s;
		irq_handled = 1;
	} else if (host->use_pio &&
	} else if (host->pio_size &&
		   (intr_status & host->intr_en &
		    (MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W))) {
		u16 *p = host->pio_ptr;
		int s = host->pio_size;
		/*
		 * The TX_FIFO_8W bit is unreliable. When set, bursting
		 * 16 halfwords all at once in the FIFO drops data. Actually
@@ -464,7 +431,6 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
			mvsd_write(MVSD_FIFO, get_unaligned(p++));
			mvsd_write(MVSD_FIFO, get_unaligned(p++));
			s -= 4;
			sgm->consumed += 4;
			intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
		}
		if (s < 4) {
@@ -473,13 +439,10 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
				memcpy(((void *)&val) + 4 - s, p, s);
				mvsd_write(MVSD_FIFO, val[0]);
				mvsd_write(MVSD_FIFO, val[1]);
				sgm->consumed += s;
				s = 0;
				intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
			}
			/* PIO transfer done */
			host->pio_size -= sgm->consumed;
			if (host->pio_size == 0) {
			if (s == 0) {
				host->intr_en &=
				     ~(MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W);
				mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
@@ -487,6 +450,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
		}
		dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
			s, intr_status, mvsd_read(MVSD_HW_STATE));
		host->pio_ptr = p;
		host->pio_size = s;
		irq_handled = 1;
	}

+8 −0
Original line number Diff line number Diff line
@@ -852,6 +852,14 @@ static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask)

	sdhci_reset(host, mask);

	/* The T-Head 1520 SoC does not comply with the SDHCI specification
	 * regarding the "Software Reset for CMD line should clear 'Command
	 * Complete' in the Normal Interrupt Status Register." Clear the bit
	 * here to compensate for this quirk.
	 */
	if (mask & SDHCI_RESET_CMD)
		sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);

	if (priv->flags & FLAG_IO_FIXED_1V8) {
		ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
		if (!(ctrl_2 & SDHCI_CTRL_VDD_180)) {