diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/core/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mmc/core/block.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/core/block.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 36 | ||||
| -rw-r--r-- | drivers/mmc/core/queue.c | 120 | ||||
| -rw-r--r-- | drivers/mmc/core/queue.h | 7 | ||||
| -rw-r--r-- | drivers/mmc/core/quirks.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/cavium-thunderx.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/cavium.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/dw_mmc-zx.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/dw_mmc.c | 107 | ||||
| -rw-r--r-- | drivers/mmc/host/meson-gx-mmc.c | 26 | ||||
| -rw-r--r-- | drivers/mmc/host/pxamci.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/pxamci.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/renesas_sdhi_internal_dmac.c | 17 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 17 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pci.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-xenon.c | 24 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-xenon.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/tmio_mmc_core.c | 60 | 
23 files changed, 222 insertions, 220 deletions
| diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 7e3ed1aeada2..abba078f7f49 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  #  # Makefile for the kernel mmc core.  # diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 29fc1e662891..2ad7b5c69156 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1634,8 +1634,6 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,  	}  	mqrq->areq.mrq = &brq->mrq; - -	mmc_queue_bounce_pre(mqrq);  }  static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, @@ -1829,7 +1827,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req)  		brq = &mq_rq->brq;  		old_req = mmc_queue_req_to_req(mq_rq);  		type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; -		mmc_queue_bounce_post(mq_rq);  		switch (status) {  		case MMC_BLK_SUCCESS: diff --git a/drivers/mmc/core/block.h b/drivers/mmc/core/block.h index 860ca7c8df86..5946636101ef 100644 --- a/drivers/mmc/core/block.h +++ b/drivers/mmc/core/block.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _MMC_CORE_BLOCK_H  #define _MMC_CORE_BLOCK_H diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index a7eb623f8daa..36217ad5e9b1 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1286,6 +1286,23 @@ out_err:  	return err;  } +static void mmc_select_driver_type(struct mmc_card *card) +{ +	int card_drv_type, drive_strength, drv_type; + +	card_drv_type = card->ext_csd.raw_driver_strength | +			mmc_driver_type_mask(0); + +	drive_strength = mmc_select_drive_strength(card, +						   card->ext_csd.hs200_max_dtr, +						   card_drv_type, &drv_type); + +	card->drive_strength = drive_strength; + +	if (drv_type) +		mmc_set_driver_type(card->host, drv_type); +} +  static int mmc_select_hs400es(struct mmc_card *card)  {  	struct mmc_host *host = card->host; @@ -1341,6 +1358,8 @@ static int mmc_select_hs400es(struct mmc_card *card)  		goto out_err;  	} +	mmc_select_driver_type(card); +  	/* Switch card to HS400 */  	val = EXT_CSD_TIMING_HS400 |  	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT; @@ -1374,23 +1393,6 @@ out_err:  	return err;  } -static void mmc_select_driver_type(struct mmc_card *card) -{ -	int card_drv_type, drive_strength, drv_type; - -	card_drv_type = card->ext_csd.raw_driver_strength | -			mmc_driver_type_mask(0); - -	drive_strength = mmc_select_drive_strength(card, -						   card->ext_csd.hs200_max_dtr, -						   card_drv_type, &drv_type); - -	card->drive_strength = drive_strength; - -	if (drv_type) -		mmc_set_driver_type(card->host, drv_type); -} -  /*   * For device supporting HS200 mode, the following sequence   * should be done before executing the tuning process. diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index affa7370ba82..0a4e77a5ba33 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -23,8 +23,6 @@  #include "core.h"  #include "card.h" -#define MMC_QUEUE_BOUNCESZ	65536 -  /*   * Prepare a MMC request. This just filters out odd stuff.   */ @@ -150,26 +148,6 @@ static void mmc_queue_setup_discard(struct request_queue *q,  		queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);  } -static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host) -{ -	unsigned int bouncesz = MMC_QUEUE_BOUNCESZ; - -	if (host->max_segs != 1 || (host->caps & MMC_CAP_NO_BOUNCE_BUFF)) -		return 0; - -	if (bouncesz > host->max_req_size) -		bouncesz = host->max_req_size; -	if (bouncesz > host->max_seg_size) -		bouncesz = host->max_seg_size; -	if (bouncesz > host->max_blk_count * 512) -		bouncesz = host->max_blk_count * 512; - -	if (bouncesz <= 512) -		return 0; - -	return bouncesz; -} -  /**   * mmc_init_request() - initialize the MMC-specific per-request data   * @q: the request queue @@ -184,26 +162,9 @@ static int mmc_init_request(struct request_queue *q, struct request *req,  	struct mmc_card *card = mq->card;  	struct mmc_host *host = card->host; -	if (card->bouncesz) { -		mq_rq->bounce_buf = kmalloc(card->bouncesz, gfp); -		if (!mq_rq->bounce_buf) -			return -ENOMEM; -		if (card->bouncesz > 512) { -			mq_rq->sg = mmc_alloc_sg(1, gfp); -			if (!mq_rq->sg) -				return -ENOMEM; -			mq_rq->bounce_sg = mmc_alloc_sg(card->bouncesz / 512, -							gfp); -			if (!mq_rq->bounce_sg) -				return -ENOMEM; -		} -	} else { -		mq_rq->bounce_buf = NULL; -		mq_rq->bounce_sg = NULL; -		mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); -		if (!mq_rq->sg) -			return -ENOMEM; -	} +	mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); +	if (!mq_rq->sg) +		return -ENOMEM;  	return 0;  } @@ -212,13 +173,6 @@ static void mmc_exit_request(struct request_queue *q, struct request *req)  {  	struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req); -	/* It is OK to kfree(NULL) so this will be smooth */ -	kfree(mq_rq->bounce_sg); -	mq_rq->bounce_sg = NULL; - -	kfree(mq_rq->bounce_buf); -	mq_rq->bounce_buf = NULL; -  	kfree(mq_rq->sg);  	mq_rq->sg = NULL;  } @@ -265,18 +219,11 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,  	if (mmc_can_erase(card))  		mmc_queue_setup_discard(mq->queue, card); -	card->bouncesz = mmc_queue_calc_bouncesz(host); -	if (card->bouncesz) { -		blk_queue_max_hw_sectors(mq->queue, card->bouncesz / 512); -		blk_queue_max_segments(mq->queue, card->bouncesz / 512); -		blk_queue_max_segment_size(mq->queue, card->bouncesz); -	} else { -		blk_queue_bounce_limit(mq->queue, limit); -		blk_queue_max_hw_sectors(mq->queue, -			min(host->max_blk_count, host->max_req_size / 512)); -		blk_queue_max_segments(mq->queue, host->max_segs); -		blk_queue_max_segment_size(mq->queue, host->max_seg_size); -	} +	blk_queue_bounce_limit(mq->queue, limit); +	blk_queue_max_hw_sectors(mq->queue, +		min(host->max_blk_count, host->max_req_size / 512)); +	blk_queue_max_segments(mq->queue, host->max_segs); +	blk_queue_max_segment_size(mq->queue, host->max_seg_size);  	sema_init(&mq->thread_sem, 1); @@ -365,56 +312,7 @@ void mmc_queue_resume(struct mmc_queue *mq)   */  unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)  { -	unsigned int sg_len; -	size_t buflen; -	struct scatterlist *sg;  	struct request *req = mmc_queue_req_to_req(mqrq); -	int i; - -	if (!mqrq->bounce_buf) -		return blk_rq_map_sg(mq->queue, req, mqrq->sg); - -	sg_len = blk_rq_map_sg(mq->queue, req, mqrq->bounce_sg); - -	mqrq->bounce_sg_len = sg_len; - -	buflen = 0; -	for_each_sg(mqrq->bounce_sg, sg, sg_len, i) -		buflen += sg->length; - -	sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen); - -	return 1; -} - -/* - * If writing, bounce the data to the buffer before the request - * is sent to the host driver - */ -void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq) -{ -	if (!mqrq->bounce_buf) -		return; - -	if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != WRITE) -		return; - -	sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len, -		mqrq->bounce_buf, mqrq->sg[0].length); -} - -/* - * If reading, bounce the data from the buffer after the request - * has been handled by the host driver - */ -void mmc_queue_bounce_post(struct mmc_queue_req *mqrq) -{ -	if (!mqrq->bounce_buf) -		return; - -	if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != READ) -		return; -	sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len, -		mqrq->bounce_buf, mqrq->sg[0].length); +	return blk_rq_map_sg(mq->queue, req, mqrq->sg);  } diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 04fc89360a7a..6bfba32ffa66 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef MMC_QUEUE_H  #define MMC_QUEUE_H @@ -49,9 +50,6 @@ enum mmc_drv_op {  struct mmc_queue_req {  	struct mmc_blk_request	brq;  	struct scatterlist	*sg; -	char			*bounce_buf; -	struct scatterlist	*bounce_sg; -	unsigned int		bounce_sg_len;  	struct mmc_async_req	areq;  	enum mmc_drv_op		drv_op;  	int			drv_op_result; @@ -81,11 +79,8 @@ extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,  extern void mmc_cleanup_queue(struct mmc_queue *);  extern void mmc_queue_suspend(struct mmc_queue *);  extern void mmc_queue_resume(struct mmc_queue *); -  extern unsigned int mmc_queue_map_sg(struct mmc_queue *,  				     struct mmc_queue_req *); -extern void mmc_queue_bounce_pre(struct mmc_queue_req *); -extern void mmc_queue_bounce_post(struct mmc_queue_req *);  extern int mmc_access_rpmb(struct mmc_queue *); diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index fb725934fa21..f664e9cbc9f8 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  /*   *  This file contains work-arounds for many known SD/MMC   *  and SDIO hardware bugs. diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h index 1ada9808c329..497c026a5c5a 100644 --- a/drivers/mmc/core/sd.h +++ b/drivers/mmc/core/sd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _MMC_CORE_SD_H  #define _MMC_CORE_SD_H diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 02179ed2a40d..8c15637178ff 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -5,7 +5,7 @@  comment "MMC/SD/SDIO Host Controller Drivers"  config MMC_DEBUG -	bool "MMC host drivers debugginG" +	bool "MMC host drivers debugging"  	depends on MMC != n  	help  	  This is an option for use by developers; most people should diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 303f5cd46cd9..7c7b29ff591a 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  #  # Makefile for MMC/SD host controller drivers  # diff --git a/drivers/mmc/host/cavium-thunderx.c b/drivers/mmc/host/cavium-thunderx.c index b9cc95998799..eee08d81b242 100644 --- a/drivers/mmc/host/cavium-thunderx.c +++ b/drivers/mmc/host/cavium-thunderx.c @@ -7,6 +7,7 @@   *   * Copyright (C) 2016 Cavium Inc.   */ +#include <linux/device.h>  #include <linux/dma-mapping.h>  #include <linux/interrupt.h>  #include <linux/mmc/mmc.h> @@ -149,8 +150,11 @@ error:  	for (i = 0; i < CAVIUM_MAX_MMC; i++) {  		if (host->slot[i])  			cvm_mmc_of_slot_remove(host->slot[i]); -		if (host->slot_pdev[i]) +		if (host->slot_pdev[i]) { +			get_device(&host->slot_pdev[i]->dev);  			of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL); +			put_device(&host->slot_pdev[i]->dev); +		}  	}  	clk_disable_unprepare(host->clk);  	return ret; diff --git a/drivers/mmc/host/cavium.c b/drivers/mmc/host/cavium.c index 27fb625cbcf3..fbd29f00fca0 100644 --- a/drivers/mmc/host/cavium.c +++ b/drivers/mmc/host/cavium.c @@ -1038,7 +1038,7 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host)  	 */  	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |  		     MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD | -		     MMC_CAP_3_3V_DDR | MMC_CAP_NO_BOUNCE_BUFF; +		     MMC_CAP_3_3V_DDR;  	if (host->use_sg)  		mmc->max_segs = 16; diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h index f369997a39ec..09ac52766f14 100644 --- a/drivers/mmc/host/dw_mmc-zx.h +++ b/drivers/mmc/host/dw_mmc-zx.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _DW_MMC_ZX_H_  #define _DW_MMC_ZX_H_ diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 860313bd952a..4f2806720c5c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -401,16 +401,37 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)  static inline void dw_mci_set_cto(struct dw_mci *host)  {  	unsigned int cto_clks; +	unsigned int cto_div;  	unsigned int cto_ms; +	unsigned long irqflags;  	cto_clks = mci_readl(host, TMOUT) & 0xff; -	cto_ms = DIV_ROUND_UP(cto_clks, host->bus_hz / 1000); +	cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; +	if (cto_div == 0) +		cto_div = 1; +	cto_ms = DIV_ROUND_UP(MSEC_PER_SEC * cto_clks * cto_div, host->bus_hz);  	/* add a bit spare time */  	cto_ms += 10; -	mod_timer(&host->cto_timer, -		  jiffies + msecs_to_jiffies(cto_ms) + 1); +	/* +	 * The durations we're working with are fairly short so we have to be +	 * extra careful about synchronization here.  Specifically in hardware a +	 * command timeout is _at most_ 5.1 ms, so that means we expect an +	 * interrupt (either command done or timeout) to come rather quickly +	 * after the mci_writel.  ...but just in case we have a long interrupt +	 * latency let's add a bit of paranoia. +	 * +	 * In general we'll assume that at least an interrupt will be asserted +	 * in hardware by the time the cto_timer runs.  ...and if it hasn't +	 * been asserted in hardware by that time then we'll assume it'll never +	 * come. +	 */ +	spin_lock_irqsave(&host->irq_lock, irqflags); +	if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) +		mod_timer(&host->cto_timer, +			jiffies + msecs_to_jiffies(cto_ms) + 1); +	spin_unlock_irqrestore(&host->irq_lock, irqflags);  }  static void dw_mci_start_command(struct dw_mci *host, @@ -425,11 +446,11 @@ static void dw_mci_start_command(struct dw_mci *host,  	wmb(); /* drain writebuffer */  	dw_mci_wait_while_busy(host, cmd_flags); +	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); +  	/* response expected command only */  	if (cmd_flags & SDMMC_CMD_RESP_EXP)  		dw_mci_set_cto(host); - -	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);  }  static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) @@ -1915,10 +1936,15 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)  static void dw_mci_set_drto(struct dw_mci *host)  {  	unsigned int drto_clks; +	unsigned int drto_div;  	unsigned int drto_ms;  	drto_clks = mci_readl(host, TMOUT) >> 8; -	drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000); +	drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; +	if (drto_div == 0) +		drto_div = 1; +	drto_ms = DIV_ROUND_UP(MSEC_PER_SEC * drto_clks * drto_div, +			       host->bus_hz);  	/* add a bit spare time */  	drto_ms += 10; @@ -1926,6 +1952,24 @@ static void dw_mci_set_drto(struct dw_mci *host)  	mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));  } +static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host) +{ +	if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) +		return false; + +	/* +	 * Really be certain that the timer has stopped.  This is a bit of +	 * paranoia and could only really happen if we had really bad +	 * interrupt latency and the interrupt routine and timeout were +	 * running concurrently so that the del_timer() in the interrupt +	 * handler couldn't run. +	 */ +	WARN_ON(del_timer_sync(&host->cto_timer)); +	clear_bit(EVENT_CMD_COMPLETE, &host->pending_events); + +	return true; +} +  static void dw_mci_tasklet_func(unsigned long priv)  {  	struct dw_mci *host = (struct dw_mci *)priv; @@ -1952,8 +1996,7 @@ static void dw_mci_tasklet_func(unsigned long priv)  		case STATE_SENDING_CMD11:  		case STATE_SENDING_CMD: -			if (!test_and_clear_bit(EVENT_CMD_COMPLETE, -						&host->pending_events)) +			if (!dw_mci_clear_pending_cmd_complete(host))  				break;  			cmd = host->cmd; @@ -2122,8 +2165,7 @@ static void dw_mci_tasklet_func(unsigned long priv)  			/* fall through */  		case STATE_SENDING_STOP: -			if (!test_and_clear_bit(EVENT_CMD_COMPLETE, -						&host->pending_events)) +			if (!dw_mci_clear_pending_cmd_complete(host))  				break;  			/* CMD error in data command */ @@ -2570,6 +2612,8 @@ done:  static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)  { +	del_timer(&host->cto_timer); +  	if (!host->cmd_status)  		host->cmd_status = status; @@ -2594,6 +2638,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)  	struct dw_mci *host = dev_id;  	u32 pending;  	struct dw_mci_slot *slot = host->slot; +	unsigned long irqflags;  	pending = mci_readl(host, MINTSTS); /* read-only mask reg */ @@ -2601,8 +2646,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)  		/* Check volt switch first, since it can look like an error */  		if ((host->state == STATE_SENDING_CMD11) &&  		    (pending & SDMMC_INT_VOLT_SWITCH)) { -			unsigned long irqflags; -  			mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);  			pending &= ~SDMMC_INT_VOLT_SWITCH; @@ -2618,11 +2661,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)  		}  		if (pending & DW_MCI_CMD_ERROR_FLAGS) { +			spin_lock_irqsave(&host->irq_lock, irqflags); +  			del_timer(&host->cto_timer);  			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);  			host->cmd_status = pending;  			smp_wmb(); /* drain writebuffer */  			set_bit(EVENT_CMD_COMPLETE, &host->pending_events); + +			spin_unlock_irqrestore(&host->irq_lock, irqflags);  		}  		if (pending & DW_MCI_DATA_ERROR_FLAGS) { @@ -2662,9 +2709,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)  		}  		if (pending & SDMMC_INT_CMD_DONE) { -			del_timer(&host->cto_timer); +			spin_lock_irqsave(&host->irq_lock, irqflags); +  			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);  			dw_mci_cmd_interrupt(host, pending); + +			spin_unlock_irqrestore(&host->irq_lock, irqflags);  		}  		if (pending & SDMMC_INT_CD) { @@ -2938,7 +2988,35 @@ static void dw_mci_cmd11_timer(unsigned long arg)  static void dw_mci_cto_timer(unsigned long arg)  {  	struct dw_mci *host = (struct dw_mci *)arg; +	unsigned long irqflags; +	u32 pending; +	spin_lock_irqsave(&host->irq_lock, irqflags); + +	/* +	 * If somehow we have very bad interrupt latency it's remotely possible +	 * that the timer could fire while the interrupt is still pending or +	 * while the interrupt is midway through running.  Let's be paranoid +	 * and detect those two cases.  Note that this is paranoia is somewhat +	 * justified because in this function we don't actually cancel the +	 * pending command in the controller--we just assume it will never come. +	 */ +	pending = mci_readl(host, MINTSTS); /* read-only mask reg */ +	if (pending & (DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_CMD_DONE)) { +		/* The interrupt should fire; no need to act but we can warn */ +		dev_warn(host->dev, "Unexpected interrupt latency\n"); +		goto exit; +	} +	if (test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) { +		/* Presumably interrupt handler couldn't delete the timer */ +		dev_warn(host->dev, "CTO timeout when already completed\n"); +		goto exit; +	} + +	/* +	 * Continued paranoia to make sure we're in the state we expect. +	 * This paranoia isn't really justified but it seems good to be safe. +	 */  	switch (host->state) {  	case STATE_SENDING_CMD11:  	case STATE_SENDING_CMD: @@ -2957,6 +3035,9 @@ static void dw_mci_cto_timer(unsigned long arg)  			 host->state);  		break;  	} + +exit: +	spin_unlock_irqrestore(&host->irq_lock, irqflags);  }  static void dw_mci_dto_timer(unsigned long arg) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index c885c2d4b904..85745ef179e2 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -531,8 +531,7 @@ static int meson_mmc_clk_init(struct meson_host *host)  	div->shift = __ffs(CLK_DIV_MASK);  	div->width = __builtin_popcountl(CLK_DIV_MASK);  	div->hw.init = &init; -	div->flags = (CLK_DIVIDER_ONE_BASED | -		      CLK_DIVIDER_ROUND_CLOSEST); +	div->flags = CLK_DIVIDER_ONE_BASED;  	clk = devm_clk_register(host->dev, &div->hw);  	if (WARN_ON(IS_ERR(clk))) @@ -717,6 +716,22 @@ static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode,  static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)  {  	struct meson_host *host = mmc_priv(mmc); +	int ret; + +	/* +	 * If this is the initial tuning, try to get a sane Rx starting +	 * phase before doing the actual tuning. +	 */ +	if (!mmc->doing_retune) { +		ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); + +		if (ret) +			return ret; +	} + +	ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->tx_clk); +	if (ret) +		return ret;  	return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk);  } @@ -746,6 +761,11 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	case MMC_POWER_UP:  		if (!IS_ERR(mmc->supply.vmmc))  			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + +		/* Reset phases */ +		clk_set_phase(host->rx_clk, 0); +		clk_set_phase(host->tx_clk, 270); +  		break;  	case MMC_POWER_ON: @@ -759,8 +779,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  				host->vqmmc_enabled = true;  		} -		/* Reset rx phase */ -		clk_set_phase(host->rx_clk, 0);  		break;  	} diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 59ab194cb009..c763b404510f 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -702,11 +702,7 @@ static int pxamci_probe(struct platform_device *pdev)  	pxamci_init_ocr(host); -	/* -	 * This architecture used to disable bounce buffers through its -	 * defconfig, now it is done at runtime as a host property. -	 */ -	mmc->caps = MMC_CAP_NO_BOUNCE_BUFF; +	mmc->caps = 0;  	host->cmdat = 0;  	if (!cpu_is_pxa25x()) {  		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h index f6c2e2fcce37..d301ca18c5d4 100644 --- a/drivers/mmc/host/pxamci.h +++ b/drivers/mmc/host/pxamci.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #define MMC_STRPCL	0x0000  #define STOP_CLOCK		(1 << 0)  #define START_CLOCK		(2 << 0) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index f905f2361d12..8bae88a150fd 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -146,11 +146,8 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,  	WARN_ON(host->sg_len > 1);  	/* This DMAC cannot handle if buffer is not 8-bytes alignment */ -	if (!IS_ALIGNED(sg->offset, 8)) { -		host->force_pio = true; -		renesas_sdhi_internal_dmac_enable_dma(host, false); -		return; -	} +	if (!IS_ALIGNED(sg->offset, 8)) +		goto force_pio;  	if (data->flags & MMC_DATA_READ) {  		dtran_mode |= DTRAN_MODE_CH_NUM_CH1; @@ -163,8 +160,8 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,  	}  	ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir); -	if (ret < 0) -		return; +	if (ret == 0) +		goto force_pio;  	renesas_sdhi_internal_dmac_enable_dma(host, true); @@ -176,6 +173,12 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,  					    dtran_mode);  	renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,  					    sg->dma_address); + +	return; + +force_pio: +	host->force_pio = true; +	renesas_sdhi_internal_dmac_enable_dma(host, false);  }  static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index bbaddf18a1b3..67d787fa3306 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -392,6 +392,7 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {  enum {  	INTEL_DSM_FNS		=  0, +	INTEL_DSM_V18_SWITCH	=  3,  	INTEL_DSM_DRV_STRENGTH	=  9,  	INTEL_DSM_D3_RETUNE	= 10,  }; @@ -447,6 +448,8 @@ static void intel_dsm_init(struct intel_host *intel_host, struct device *dev,  	int err;  	u32 val; +	intel_host->d3_retune = true; +  	err = __intel_dsm(intel_host, dev, INTEL_DSM_FNS, &intel_host->dsm_fns);  	if (err) {  		pr_debug("%s: DSM not supported, error %d\n", @@ -557,6 +560,19 @@ static void intel_hs400_enhanced_strobe(struct mmc_host *mmc,  	sdhci_writel(host, val, INTEL_HS400_ES_REG);  } +static void sdhci_intel_voltage_switch(struct sdhci_host *host) +{ +	struct sdhci_pci_slot *slot = sdhci_priv(host); +	struct intel_host *intel_host = sdhci_pci_priv(slot); +	struct device *dev = &slot->chip->pdev->dev; +	u32 result = 0; +	int err; + +	err = intel_dsm(intel_host, dev, INTEL_DSM_V18_SWITCH, &result); +	pr_debug("%s: %s DSM error %d result %u\n", +		 mmc_hostname(host->mmc), __func__, err, result); +} +  static const struct sdhci_ops sdhci_intel_byt_ops = {  	.set_clock		= sdhci_set_clock,  	.set_power		= sdhci_intel_set_power, @@ -565,6 +581,7 @@ static const struct sdhci_ops sdhci_intel_byt_ops = {  	.reset			= sdhci_reset,  	.set_uhs_signaling	= sdhci_set_uhs_signaling,  	.hw_reset		= sdhci_pci_hw_reset, +	.voltage_switch		= sdhci_intel_voltage_switch,  };  static void byt_read_dsm(struct sdhci_pci_slot *slot) diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 75196a2b5289..3e8ea3e566f6 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef __SDHCI_PCI_H  #define __SDHCI_PCI_H diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 2eec2e652c53..0842bbc2d7ad 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -466,6 +466,7 @@ static int xenon_probe(struct platform_device *pdev)  {  	struct sdhci_pltfm_host *pltfm_host;  	struct sdhci_host *host; +	struct xenon_priv *priv;  	int err;  	host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata, @@ -474,6 +475,7 @@ static int xenon_probe(struct platform_device *pdev)  		return PTR_ERR(host);  	pltfm_host = sdhci_priv(host); +	priv = sdhci_pltfm_priv(pltfm_host);  	/*  	 * Link Xenon specific mmc_host_ops function, @@ -491,9 +493,20 @@ static int xenon_probe(struct platform_device *pdev)  	if (err)  		goto free_pltfm; +	priv->axi_clk = devm_clk_get(&pdev->dev, "axi"); +	if (IS_ERR(priv->axi_clk)) { +		err = PTR_ERR(priv->axi_clk); +		if (err == -EPROBE_DEFER) +			goto err_clk; +	} else { +		err = clk_prepare_enable(priv->axi_clk); +		if (err) +			goto err_clk; +	} +  	err = mmc_of_parse(host->mmc);  	if (err) -		goto err_clk; +		goto err_clk_axi;  	sdhci_get_of_property(pdev); @@ -502,11 +515,11 @@ static int xenon_probe(struct platform_device *pdev)  	/* Xenon specific dt parse */  	err = xenon_probe_dt(pdev);  	if (err) -		goto err_clk; +		goto err_clk_axi;  	err = xenon_sdhc_prepare(host);  	if (err) -		goto err_clk; +		goto err_clk_axi;  	pm_runtime_get_noresume(&pdev->dev);  	pm_runtime_set_active(&pdev->dev); @@ -527,6 +540,8 @@ remove_sdhc:  	pm_runtime_disable(&pdev->dev);  	pm_runtime_put_noidle(&pdev->dev);  	xenon_sdhc_unprepare(host); +err_clk_axi: +	clk_disable_unprepare(priv->axi_clk);  err_clk:  	clk_disable_unprepare(pltfm_host->clk);  free_pltfm: @@ -538,6 +553,7 @@ static int xenon_remove(struct platform_device *pdev)  {  	struct sdhci_host *host = platform_get_drvdata(pdev);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);  	pm_runtime_get_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev); @@ -546,7 +562,7 @@ static int xenon_remove(struct platform_device *pdev)  	sdhci_remove_host(host, 0);  	xenon_sdhc_unprepare(host); - +	clk_disable_unprepare(priv->axi_clk);  	clk_disable_unprepare(pltfm_host->clk);  	sdhci_pltfm_free(pdev); diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h index 2bc0510c0769..9994995c7c56 100644 --- a/drivers/mmc/host/sdhci-xenon.h +++ b/drivers/mmc/host/sdhci-xenon.h @@ -83,6 +83,7 @@ struct xenon_priv {  	unsigned char	bus_width;  	unsigned char	timing;  	unsigned int	clock; +	struct clk      *axi_clk;  	int		phy_type;  	/* diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 12cf8288d663..9c4e6199b854 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -47,6 +47,7 @@  #include <linux/mmc/sdio.h>  #include <linux/scatterlist.h>  #include <linux/spinlock.h> +#include <linux/swiotlb.h>  #include <linux/workqueue.h>  #include "tmio_mmc.h" @@ -129,50 +130,6 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host)  #define CMDREQ_TIMEOUT	5000 -#ifdef CONFIG_MMC_DEBUG - -#define STATUS_TO_TEXT(a, status, i) \ -	do { \ -		if ((status) & TMIO_STAT_##a) { \ -			if ((i)++) \ -				printk(KERN_DEBUG " | "); \ -			printk(KERN_DEBUG #a); \ -		} \ -	} while (0) - -static void pr_debug_status(u32 status) -{ -	int i = 0; - -	pr_debug("status: %08x = ", status); -	STATUS_TO_TEXT(CARD_REMOVE, status, i); -	STATUS_TO_TEXT(CARD_INSERT, status, i); -	STATUS_TO_TEXT(SIGSTATE, status, i); -	STATUS_TO_TEXT(WRPROTECT, status, i); -	STATUS_TO_TEXT(CARD_REMOVE_A, status, i); -	STATUS_TO_TEXT(CARD_INSERT_A, status, i); -	STATUS_TO_TEXT(SIGSTATE_A, status, i); -	STATUS_TO_TEXT(CMD_IDX_ERR, status, i); -	STATUS_TO_TEXT(STOPBIT_ERR, status, i); -	STATUS_TO_TEXT(ILL_FUNC, status, i); -	STATUS_TO_TEXT(CMD_BUSY, status, i); -	STATUS_TO_TEXT(CMDRESPEND, status, i); -	STATUS_TO_TEXT(DATAEND, status, i); -	STATUS_TO_TEXT(CRCFAIL, status, i); -	STATUS_TO_TEXT(DATATIMEOUT, status, i); -	STATUS_TO_TEXT(CMDTIMEOUT, status, i); -	STATUS_TO_TEXT(RXOVERFLOW, status, i); -	STATUS_TO_TEXT(TXUNDERRUN, status, i); -	STATUS_TO_TEXT(RXRDY, status, i); -	STATUS_TO_TEXT(TXRQ, status, i); -	STATUS_TO_TEXT(ILL_ACCESS, status, i); -	printk("\n"); -} - -#else -#define pr_debug_status(s)  do { } while (0) -#endif -  static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)  {  	struct tmio_mmc_host *host = mmc_priv(mmc); @@ -762,9 +719,6 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)  	status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS);  	ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; -	pr_debug_status(status); -	pr_debug_status(ireg); -  	/* Clear the status except the interrupt status */  	sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, TMIO_MASK_IRQ); @@ -1262,6 +1216,18 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,  	mmc->max_blk_count = pdata->max_blk_count ? :  		(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;  	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; +	/* +	 * Since swiotlb has memory size limitation, this will calculate +	 * the maximum size locally (because we don't have any APIs for it now) +	 * and check the current max_req_size. And then, this will update +	 * the max_req_size if needed as a workaround. +	 */ +	if (swiotlb_max_segment()) { +		unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE; + +		if (mmc->max_req_size > max_size) +			mmc->max_req_size = max_size; +	}  	mmc->max_seg_size = mmc->max_req_size;  	_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || |