mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 12:44:11 +08:00
MMC core:
- Fix CQE error recovery path MMC host: - cqhci: Fix CQE error recovery path - sdhci-pci-gli: Fix initialization of LPM - sdhci-sprd: Fix enabling/disabling of the vqmmc regulator -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmVoZ1gXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCmiRBAAjNrmB5Jg7n52+Oc5RjmTEb1y xrwhFo8zPAsGkZY2rTRRabW/0n7W+v0d3d2DK/v0flbv0gBUMsSIKqrNtjfjAYEf GRoEdt8esHuRwNLiDdPxUV20HQd/VW64nxCucX1YoO4y8MqOaOXAltB0OfGL5OJ2 59x76k9e/eXmfCE53Ace3h9xq4oeL0aeg8o+P494fEoYNesKIcj699uRuSJeXZ8B lu42jrQjRtsFEmPUxT7nkZnPVNg6ebX4V1Nh00uaqYR7uhuiE0qMW5uCbH5XQvAW YSS9JuL0eSJkh5ni7/v1ubbijZAheCrHgfXBIj4tFNAmHXK+HCyABueJLUVpXpu7 ZbVSJVPmzSOpJn9iJlARovh4vfIhEdgFaryoepOmIgGXn1EY+jR4BqCGytE4wSh+ OWwvOJo3RImcGpBrOQy9ds0rRLj2Yuz0ifYzU6W6qFmxjvth6druhHIQZWarOURT +/FdnG2F0GApGtAJZE4hWobk3FPXLHEstkZXqsuxDE7p6Os1w2gbKmfOmDvNZWHr tgBC2qVmQSXyDcxylF/yDIX6B0eAjrZnq7px3uD6IdSF30KN2w1SQ7giaYBGqExr TAbom/u2u7i73h4XaRQHoftBouzc6QBpo2OzBYeolkJgVJCx8sHj7BU1gBstp033 /kgogUJSgMGBcZeREhg= =G0uq -----END PGP SIGNATURE----- Merge tag 'mmc-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC fixes from Ulf Hansson: "MMC core: - Fix CQE error recovery path MMC host: - cqhci: Fix CQE error recovery path - sdhci-pci-gli: Fix initialization of LPM - sdhci-sprd: Fix enabling/disabling of the vqmmc regulator" * tag 'mmc-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: mmc: sdhci-sprd: Fix vqmmc not shutting down after the card was pulled mmc: sdhci-pci-gli: Disable LPM during initialization mmc: cqhci: Fix task clearing in CQE error recovery mmc: cqhci: Warn of halt or task clear failure mmc: block: Retry commands in CQE error recovery mmc: block: Be sure to wait while busy in CQE error recovery mmc: cqhci: Increase recovery halt timeout mmc: block: Do not lose cache flush during CQE error recovery
This commit is contained in:
commit
09443a144c
@ -1482,6 +1482,8 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
|
||||
blk_mq_requeue_request(req, true);
|
||||
else
|
||||
__blk_mq_end_request(req, BLK_STS_OK);
|
||||
} else if (mq->in_recovery) {
|
||||
blk_mq_requeue_request(req, true);
|
||||
} else {
|
||||
blk_mq_end_request(req, BLK_STS_OK);
|
||||
}
|
||||
|
@ -551,7 +551,9 @@ int mmc_cqe_recovery(struct mmc_host *host)
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
||||
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
|
||||
mmc_wait_for_cmd(host, &cmd, 0);
|
||||
mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
|
||||
|
||||
mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, MMC_BUSY_IO);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.opcode = MMC_CMDQ_TASK_MGMT;
|
||||
@ -559,10 +561,13 @@ int mmc_cqe_recovery(struct mmc_host *host)
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
||||
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
|
||||
|
||||
host->cqe_ops->cqe_recovery_finish(host);
|
||||
|
||||
if (err)
|
||||
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
|
||||
|
||||
mmc_retune_release(host);
|
||||
|
||||
return err;
|
||||
|
@ -942,8 +942,8 @@ static bool cqhci_clear_all_tasks(struct mmc_host *mmc, unsigned int timeout)
|
||||
ret = cqhci_tasks_cleared(cq_host);
|
||||
|
||||
if (!ret)
|
||||
pr_debug("%s: cqhci: Failed to clear tasks\n",
|
||||
mmc_hostname(mmc));
|
||||
pr_warn("%s: cqhci: Failed to clear tasks\n",
|
||||
mmc_hostname(mmc));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -976,7 +976,7 @@ static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout)
|
||||
ret = cqhci_halted(cq_host);
|
||||
|
||||
if (!ret)
|
||||
pr_debug("%s: cqhci: Failed to halt\n", mmc_hostname(mmc));
|
||||
pr_warn("%s: cqhci: Failed to halt\n", mmc_hostname(mmc));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -984,10 +984,10 @@ static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout)
|
||||
/*
|
||||
* After halting we expect to be able to use the command line. We interpret the
|
||||
* failure to halt to mean the data lines might still be in use (and the upper
|
||||
* layers will need to send a STOP command), so we set the timeout based on a
|
||||
* generous command timeout.
|
||||
* layers will need to send a STOP command), however failing to halt complicates
|
||||
* the recovery, so set a timeout that would reasonably allow I/O to complete.
|
||||
*/
|
||||
#define CQHCI_START_HALT_TIMEOUT 5
|
||||
#define CQHCI_START_HALT_TIMEOUT 500
|
||||
|
||||
static void cqhci_recovery_start(struct mmc_host *mmc)
|
||||
{
|
||||
@ -1075,28 +1075,28 @@ static void cqhci_recovery_finish(struct mmc_host *mmc)
|
||||
|
||||
ok = cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
|
||||
|
||||
if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
|
||||
ok = false;
|
||||
|
||||
/*
|
||||
* The specification contradicts itself, by saying that tasks cannot be
|
||||
* cleared if CQHCI does not halt, but if CQHCI does not halt, it should
|
||||
* be disabled/re-enabled, but not to disable before clearing tasks.
|
||||
* Have a go anyway.
|
||||
*/
|
||||
if (!ok) {
|
||||
pr_debug("%s: cqhci: disable / re-enable\n", mmc_hostname(mmc));
|
||||
cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
|
||||
cqcfg &= ~CQHCI_ENABLE;
|
||||
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
||||
cqcfg |= CQHCI_ENABLE;
|
||||
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
||||
/* Be sure that there are no tasks */
|
||||
ok = cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
|
||||
if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
|
||||
ok = false;
|
||||
WARN_ON(!ok);
|
||||
}
|
||||
if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
|
||||
ok = false;
|
||||
|
||||
/* Disable to make sure tasks really are cleared */
|
||||
cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
|
||||
cqcfg &= ~CQHCI_ENABLE;
|
||||
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
||||
|
||||
cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
|
||||
cqcfg |= CQHCI_ENABLE;
|
||||
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
||||
|
||||
cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
|
||||
|
||||
if (!ok)
|
||||
cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT);
|
||||
|
||||
cqhci_recover_mrqs(cq_host);
|
||||
|
||||
|
@ -1189,6 +1189,32 @@ static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
|
||||
sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG);
|
||||
}
|
||||
|
||||
static void gl9763e_set_low_power_negotiation(struct sdhci_pci_slot *slot,
|
||||
bool enable)
|
||||
{
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
u32 value;
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
|
||||
value &= ~GLI_9763E_VHS_REV;
|
||||
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG, &value);
|
||||
|
||||
if (enable)
|
||||
value &= ~GLI_9763E_CFG_LPSN_DIS;
|
||||
else
|
||||
value |= GLI_9763E_CFG_LPSN_DIS;
|
||||
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
|
||||
value &= ~GLI_9763E_VHS_REV;
|
||||
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
|
||||
}
|
||||
|
||||
static void sdhci_set_gl9763e_signaling(struct sdhci_host *host,
|
||||
unsigned int timing)
|
||||
{
|
||||
@ -1297,6 +1323,9 @@ static int gl9763e_add_host(struct sdhci_pci_slot *slot)
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
/* Disable LPM negotiation to avoid entering L1 state. */
|
||||
gl9763e_set_low_power_negotiation(slot, false);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
@ -1340,31 +1369,6 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void gl9763e_set_low_power_negotiation(struct sdhci_pci_slot *slot, bool enable)
|
||||
{
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
u32 value;
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
|
||||
value &= ~GLI_9763E_VHS_REV;
|
||||
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG, &value);
|
||||
|
||||
if (enable)
|
||||
value &= ~GLI_9763E_CFG_LPSN_DIS;
|
||||
else
|
||||
value |= GLI_9763E_CFG_LPSN_DIS;
|
||||
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
|
||||
value &= ~GLI_9763E_VHS_REV;
|
||||
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
|
||||
}
|
||||
|
||||
static int gl9763e_runtime_suspend(struct sdhci_pci_chip *chip)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = chip->slots[0];
|
||||
|
@ -416,12 +416,33 @@ static void sdhci_sprd_request_done(struct sdhci_host *host,
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
}
|
||||
|
||||
static void sdhci_sprd_set_power(struct sdhci_host *host, unsigned char mode,
|
||||
unsigned short vdd)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
switch (mode) {
|
||||
case MMC_POWER_OFF:
|
||||
mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, 0);
|
||||
|
||||
mmc_regulator_disable_vqmmc(mmc);
|
||||
break;
|
||||
case MMC_POWER_ON:
|
||||
mmc_regulator_enable_vqmmc(mmc);
|
||||
break;
|
||||
case MMC_POWER_UP:
|
||||
mmc_regulator_set_ocr(host->mmc, mmc->supply.vmmc, vdd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct sdhci_ops sdhci_sprd_ops = {
|
||||
.read_l = sdhci_sprd_readl,
|
||||
.write_l = sdhci_sprd_writel,
|
||||
.write_w = sdhci_sprd_writew,
|
||||
.write_b = sdhci_sprd_writeb,
|
||||
.set_clock = sdhci_sprd_set_clock,
|
||||
.set_power = sdhci_sprd_set_power,
|
||||
.get_max_clock = sdhci_sprd_get_max_clock,
|
||||
.get_min_clock = sdhci_sprd_get_min_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
@ -823,6 +844,10 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
||||
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
|
||||
SDHCI_SUPPORT_DDR50);
|
||||
|
||||
ret = mmc_regulator_get_supply(host->mmc);
|
||||
if (ret)
|
||||
goto pm_runtime_disable;
|
||||
|
||||
ret = sdhci_setup_host(host);
|
||||
if (ret)
|
||||
goto pm_runtime_disable;
|
||||
|
Loading…
Reference in New Issue
Block a user