Commit 6331d118 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull MMC fixes from Ulf Hansson:
 "Here's quite a few MMC fixes intended for v5.2-rc6. This time it also
  contains fixes for a WiFi driver, which device is attached to the SDIO
  interface. Patches for the WiFi driver have been acked by the
  corresponding maintainers.

  Summary:

  MMC core:
   - Make switch to eMMC HS400 more robust for some controllers
   - Add two SDIO func API to manage re-tuning constraints
   - Prevent processing SDIO IRQs when the card is suspended

  MMC host:
   - sdhi: Disallow broken HS400 for M3-W ES1.2, RZ/G2M and V3H
   - mtk-sd: Fixup support for SDIO IRQs
   - sdhci-pci-o2micro: Fixup support for tuning

  Wireless BRCMFMAC (SDIO):
   - Deal with expected transmission errors related to the idle states
     (handled by the Always-On-Subsystem or AOS) on the SDIO-based WiFi
     on rk3288-veyron-minnie, rk3288-veyron-speedy and
     rk3288-veyron-mickey"

* tag 'mmc-v5.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: core: Prevent processing SDIO IRQs when the card is suspended
  mmc: sdhci: sdhci-pci-o2micro: Correctly set bus width when tuning
  brcmfmac: sdio: Don't tune while the card is off
  mmc: core: Add sdio_retune_hold_now() and sdio_retune_release()
  brcmfmac: sdio: Disable auto-tuning around commands expected to fail
  mmc: core: API to temporarily disable retuning for SDIO CRC errors
  Revert "brcmfmac: disable command decode in sdio_aos"
  mmc: mediatek: fix SDIO IRQ detection issue
  mmc: mediatek: fix SDIO IRQ interrupt handle flow
  mmc: core: complete HS400 before checking status
  mmc: sdhi: disallow HS400 for M3-W ES1.2, RZ/G2M, and V3H
parents 41a247d8 83293386
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -144,8 +144,9 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
	int err = cmd->error;

	/* Flag re-tuning needed on CRC errors */
	if ((cmd->opcode != MMC_SEND_TUNING_BLOCK &&
	    cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
	if (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
	    cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
	    !host->retune_crc_disable &&
	    (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||
	    (mrq->data && mrq->data->error == -EILSEQ) ||
	    (mrq->stop && mrq->stop->error == -EILSEQ)))
+3 −3
Original line number Diff line number Diff line
@@ -1212,13 +1212,13 @@ static int mmc_select_hs400(struct mmc_card *card)
	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
	mmc_set_bus_speed(card);

	if (host->ops->hs400_complete)
		host->ops->hs400_complete(host);

	err = mmc_switch_status(card);
	if (err)
		goto out_err;

	if (host->ops->hs400_complete)
		host->ops->hs400_complete(host);

	return 0;

out_err:
+12 −1
Original line number Diff line number Diff line
@@ -937,6 +937,10 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
 */
static int mmc_sdio_suspend(struct mmc_host *host)
{
	/* Prevent processing of SDIO IRQs in suspended state. */
	mmc_card_set_suspended(host->card);
	cancel_delayed_work_sync(&host->sdio_irq_work);

	mmc_claim_host(host);

	if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host))
@@ -985,13 +989,20 @@ static int mmc_sdio_resume(struct mmc_host *host)
		err = sdio_enable_4bit_bus(host->card);
	}

	if (!err && host->sdio_irqs) {
	if (err)
		goto out;

	/* Allow SDIO IRQs to be processed again. */
	mmc_card_clr_suspended(host->card);

	if (host->sdio_irqs) {
		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
			wake_up_process(host->sdio_irq_thread);
		else if (host->caps & MMC_CAP_SDIO_IRQ)
			host->ops->enable_sdio_irq(host, 1);
	}

out:
	mmc_release_host(host);

	host->pm_flags &= ~MMC_PM_KEEP_POWER;
+77 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "sdio_ops.h"
#include "core.h"
#include "card.h"
#include "host.h"

/**
 *	sdio_claim_host - exclusively claim a bus for a certain SDIO function
@@ -734,3 +735,79 @@ int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
	return 0;
}
EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags);

/**
 *	sdio_retune_crc_disable - temporarily disable retuning on CRC errors
 *	@func: SDIO function attached to host
 *
 *	If the SDIO card is known to be in a state where it might produce
 *	CRC errors on the bus in response to commands (like if we know it is
 *	transitioning between power states), an SDIO function driver can
 *	call this function to temporarily disable the SD/MMC core behavior of
 *	triggering an automatic retuning.
 *
 *	This function should be called while the host is claimed and the host
 *	should remain claimed until sdio_retune_crc_enable() is called.
 *	Specifically, the expected sequence of calls is:
 *	- sdio_claim_host()
 *	- sdio_retune_crc_disable()
 *	- some number of calls like sdio_writeb() and sdio_readb()
 *	- sdio_retune_crc_enable()
 *	- sdio_release_host()
 */
void sdio_retune_crc_disable(struct sdio_func *func)
{
	func->card->host->retune_crc_disable = true;
}
EXPORT_SYMBOL_GPL(sdio_retune_crc_disable);

/**
 *	sdio_retune_crc_enable - re-enable retuning on CRC errors
 *	@func: SDIO function attached to host
 *
 *	This is the compement to sdio_retune_crc_disable().
 */
void sdio_retune_crc_enable(struct sdio_func *func)
{
	func->card->host->retune_crc_disable = false;
}
EXPORT_SYMBOL_GPL(sdio_retune_crc_enable);

/**
 *	sdio_retune_hold_now - start deferring retuning requests till release
 *	@func: SDIO function attached to host
 *
 *	This function can be called if it's currently a bad time to do
 *	a retune of the SDIO card.  Retune requests made during this time
 *	will be held and we'll actually do the retune sometime after the
 *	release.
 *
 *	This function could be useful if an SDIO card is in a power state
 *	where it can respond to a small subset of commands that doesn't
 *	include the retuning command.  Care should be taken when using
 *	this function since (presumably) the retuning request we might be
 *	deferring was made for a good reason.
 *
 *	This function should be called while the host is claimed.
 */
void sdio_retune_hold_now(struct sdio_func *func)
{
	mmc_retune_hold_now(func->card->host);
}
EXPORT_SYMBOL_GPL(sdio_retune_hold_now);

/**
 *	sdio_retune_release - signal that it's OK to retune now
 *	@func: SDIO function attached to host
 *
 *	This is the complement to sdio_retune_hold_now().  Calling this
 *	function won't make a retune happen right away but will allow
 *	them to be scheduled normally.
 *
 *	This function should be called while the host is claimed.
 */
void sdio_retune_release(struct sdio_func *func)
{
	mmc_retune_release(func->card->host);
}
EXPORT_SYMBOL_GPL(sdio_retune_release);
+4 −0
Original line number Diff line number Diff line
@@ -34,6 +34,10 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
	unsigned char pending;
	struct sdio_func *func;

	/* Don't process SDIO IRQs if the card is suspended. */
	if (mmc_card_suspended(card))
		return 0;

	/*
	 * Optimization, if there is only 1 function interrupt registered
	 * and we know an IRQ was signaled then call irq handler directly.
Loading