Skip to content

Commit

Permalink
Merge tag 'mmc-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Improve API to make it clear that mmc_hw_reset() is for cards
   - Fixup support for writeback-cache for eMMC and SD
   - Check for errors after writes on SPI

  MMC host:
   - renesas_sdhi: A couple of fixes of TAP settings for eMMC HS400 mode
   - mmci_stm32: Fixup check of all elements in sg list
   - sdhci-xenon: Revert unnecessary fix for annoying 1.8V regulator warning"

* tag 'mmc-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: core: improve API to make clear mmc_hw_reset is for cards
  mmc: renesas_sdhi: don't overwrite TAP settings when HS400 tuning is complete
  mmc: renesas_sdhi: special 4tap settings only apply to HS400
  mmc: core: Fixup support for writeback-cache for eMMC and SD
  mmc: block: Check for errors after write on SPI
  mmc: mmci: stm32: correctly check all elements of sg list
  Revert "mmc: sdhci-xenon: fix annoying 1.8V regulator warning"
  • Loading branch information
Linus Torvalds committed Apr 8, 2022
2 parents 02994fd + b71597e commit 0ccab01
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 31 deletions.
48 changes: 43 additions & 5 deletions drivers/mmc/core/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
return -EEXIST;

md->reset_done |= type;
err = mmc_hw_reset(host);
err = mmc_hw_reset(host->card);
/* Ensure we switch back to the correct partition */
if (err) {
struct mmc_blk_data *main_md =
Expand Down Expand Up @@ -1880,6 +1880,31 @@ static inline bool mmc_blk_rq_error(struct mmc_blk_request *brq)
brq->data.error || brq->cmd.resp[0] & CMD_ERRORS;
}

static int mmc_spi_err_check(struct mmc_card *card)
{
u32 status = 0;
int err;

/*
* SPI does not have a TRAN state we have to wait on, instead the
* card is ready again when it no longer holds the line LOW.
* We still have to ensure two things here before we know the write
* was successful:
* 1. The card has not disconnected during busy and we actually read our
* own pull-up, thinking it was still connected, so ensure it
* still responds.
* 2. Check for any error bits, in particular R1_SPI_IDLE to catch a
* just reconnected card after being disconnected during busy.
*/
err = __mmc_send_status(card, &status, 0);
if (err)
return err;
/* All R1 and R2 bits of SPI are errors in our case */
if (status)
return -EIO;
return 0;
}

static int mmc_blk_busy_cb(void *cb_data, bool *busy)
{
struct mmc_blk_busy_data *data = cb_data;
Expand All @@ -1903,9 +1928,16 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)
struct mmc_blk_busy_data cb_data;
int err;

if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ)
if (rq_data_dir(req) == READ)
return 0;

if (mmc_host_is_spi(card->host)) {
err = mmc_spi_err_check(card);
if (err)
mqrq->brq.data.bytes_xfered = 0;
return err;
}

cb_data.card = card;
cb_data.status = 0;
err = __mmc_poll_for_busy(card->host, 0, MMC_BLK_TIMEOUT_MS,
Expand Down Expand Up @@ -2350,6 +2382,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
struct mmc_blk_data *md;
int devidx, ret;
char cap_str[10];
bool cache_enabled = false;
bool fua_enabled = false;

devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL);
if (devidx < 0) {
Expand Down Expand Up @@ -2429,13 +2463,17 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
md->flags |= MMC_BLK_CMD23;
}

if (mmc_card_mmc(card) &&
md->flags & MMC_BLK_CMD23 &&
if (md->flags & MMC_BLK_CMD23 &&
((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
card->ext_csd.rel_sectors)) {
md->flags |= MMC_BLK_REL_WR;
blk_queue_write_cache(md->queue.queue, true, true);
fua_enabled = true;
cache_enabled = true;
}
if (mmc_cache_enabled(card->host))
cache_enabled = true;

blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled);

string_get_size((u64)size, 512, STRING_UNITS_2,
cap_str, sizeof(cap_str));
Expand Down
5 changes: 3 additions & 2 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1995,16 +1995,17 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)

/**
* mmc_hw_reset - reset the card in hardware
* @host: MMC host to which the card is attached
* @card: card to be reset
*
* Hard reset the card. This function is only for upper layers, like the
* block layer or card drivers. You cannot use it in host drivers (struct
* mmc_card might be gone then).
*
* Return: 0 on success, -errno on failure
*/
int mmc_hw_reset(struct mmc_host *host)
int mmc_hw_reset(struct mmc_card *card)
{
struct mmc_host *host = card->host;
int ret;

ret = host->bus_ops->hw_reset(host);
Expand Down
3 changes: 1 addition & 2 deletions drivers/mmc/core/mmc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2325,10 +2325,9 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
static int mmc_test_reset(struct mmc_test_card *test)
{
struct mmc_card *card = test->card;
struct mmc_host *host = card->host;
int err;

err = mmc_hw_reset(host);
err = mmc_hw_reset(card);
if (!err) {
/*
* Reset will re-enable the card's command queue, but tests
Expand Down
6 changes: 3 additions & 3 deletions drivers/mmc/host/mmci_stm32_sdmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ static int sdmmc_idma_validate_data(struct mmci_host *host,
* excepted the last element which has no constraint on idmasize
*/
for_each_sg(data->sg, sg, data->sg_len - 1, i) {
if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) ||
!IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) {
if (!IS_ALIGNED(sg->offset, sizeof(u32)) ||
!IS_ALIGNED(sg->length, SDMMC_IDMA_BURST)) {
dev_err(mmc_dev(host->mmc),
"unaligned scatterlist: ofst:%x length:%d\n",
data->sg->offset, data->sg->length);
return -EINVAL;
}
}

if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) {
if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
dev_err(mmc_dev(host->mmc),
"unaligned last scatterlist: ofst:%x length:%d\n",
data->sg->offset, data->sg->length);
Expand Down
8 changes: 4 additions & 4 deletions drivers/mmc/host/renesas_sdhi_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
return clk_get_rate(priv->clk);

if (priv->clkh) {
/* HS400 with 4TAP needs different clock settings */
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
bool need_slow_clkh = (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) ||
(host->mmc->ios.timing == MMC_TIMING_MMC_HS400);
bool need_slow_clkh = host->mmc->ios.timing == MMC_TIMING_MMC_HS400;
clkh_shift = use_4tap && need_slow_clkh ? 1 : 2;
ref_clk = priv->clkh;
}
Expand Down Expand Up @@ -396,10 +396,10 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) |
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));

/* Set the sampling clock selection range of HS400 mode */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
sd_scc_read32(host, priv,
SH_MOBILE_SDHI_SCC_DTCNTL));

/* Avoid bad TAP */
if (bad_taps & BIT(priv->tap_set)) {
Expand Down
10 changes: 0 additions & 10 deletions drivers/mmc/host/sdhci-xenon.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,6 @@ static void xenon_voltage_switch(struct sdhci_host *host)
{
/* Wait for 5ms after set 1.8V signal enable bit */
usleep_range(5000, 5500);

/*
* For some reason the controller's Host Control2 register reports
* the bit representing 1.8V signaling as 0 when read after it was
* written as 1. Subsequent read reports 1.
*
* Since this may cause some issues, do an empty read of the Host
* Control2 register here to circumvent this.
*/
sdhci_readw(host, SDHCI_HOST_CONTROL2);
}

static unsigned int xenon_get_max_clock(struct sdhci_host *host)
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/ath/ath10k/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1633,7 +1633,7 @@ static void ath10k_sdio_hif_power_down(struct ath10k *ar)
return;
}

ret = mmc_hw_reset(ar_sdio->func->card->host);
ret = mmc_hw_reset(ar_sdio->func->card);
if (ret)
ath10k_warn(ar, "unable to reset sdio: %d\n", ret);

Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -4165,7 +4165,7 @@ static int brcmf_sdio_bus_reset(struct device *dev)

/* reset the adapter */
sdio_claim_host(sdiodev->func1);
mmc_hw_reset(sdiodev->func1->card->host);
mmc_hw_reset(sdiodev->func1->card);
sdio_release_host(sdiodev->func1);

brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/marvell/mwifiex/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -2639,7 +2639,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)

/* Run a HW reset of the SDIO interface. */
sdio_claim_host(func);
ret = mmc_hw_reset(func->card->host);
ret = mmc_hw_reset(func->card);
sdio_release_host(func);

switch (ret) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/ti/wlcore/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
* To guarantee that the SDIO card is power cycled, as required to make
* the FW programming to succeed, let's do a brute force HW reset.
*/
mmc_hw_reset(card->host);
mmc_hw_reset(card);

sdio_enable_func(func);
sdio_release_host(func);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/mmc/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq);
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd,
int retries);

int mmc_hw_reset(struct mmc_host *host);
int mmc_hw_reset(struct mmc_card *card);
int mmc_sw_reset(struct mmc_host *host);
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card);

Expand Down

0 comments on commit 0ccab01

Please sign in to comment.