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);
|
blk_mq_requeue_request(req, true);
|
||||||
else
|
else
|
||||||
__blk_mq_end_request(req, BLK_STS_OK);
|
__blk_mq_end_request(req, BLK_STS_OK);
|
||||||
|
} else if (mq->in_recovery) {
|
||||||
|
blk_mq_requeue_request(req, true);
|
||||||
} else {
|
} else {
|
||||||
blk_mq_end_request(req, BLK_STS_OK);
|
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_R1B | MMC_CMD_AC;
|
||||||
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
||||||
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
|
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));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.opcode = MMC_CMDQ_TASK_MGMT;
|
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_R1B | MMC_CMD_AC;
|
||||||
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
||||||
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
|
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);
|
host->cqe_ops->cqe_recovery_finish(host);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
|
||||||
|
|
||||||
mmc_retune_release(host);
|
mmc_retune_release(host);
|
||||||
|
|
||||||
return err;
|
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);
|
ret = cqhci_tasks_cleared(cq_host);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
pr_debug("%s: cqhci: Failed to clear tasks\n",
|
pr_warn("%s: cqhci: Failed to clear tasks\n",
|
||||||
mmc_hostname(mmc));
|
mmc_hostname(mmc));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -976,7 +976,7 @@ static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout)
|
|||||||
ret = cqhci_halted(cq_host);
|
ret = cqhci_halted(cq_host);
|
||||||
|
|
||||||
if (!ret)
|
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;
|
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
|
* 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
|
* 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
|
* layers will need to send a STOP command), however failing to halt complicates
|
||||||
* generous command timeout.
|
* 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)
|
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);
|
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
|
* The specification contradicts itself, by saying that tasks cannot be
|
||||||
* cleared if CQHCI does not halt, but if CQHCI does not halt, it should
|
* 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.
|
* be disabled/re-enabled, but not to disable before clearing tasks.
|
||||||
* Have a go anyway.
|
* Have a go anyway.
|
||||||
*/
|
*/
|
||||||
if (!ok) {
|
if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
|
||||||
pr_debug("%s: cqhci: disable / re-enable\n", mmc_hostname(mmc));
|
ok = false;
|
||||||
cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
|
|
||||||
cqcfg &= ~CQHCI_ENABLE;
|
/* Disable to make sure tasks really are cleared */
|
||||||
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
|
||||||
cqcfg |= CQHCI_ENABLE;
|
cqcfg &= ~CQHCI_ENABLE;
|
||||||
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
||||||
/* Be sure that there are no tasks */
|
|
||||||
ok = cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
|
cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
|
||||||
if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
|
cqcfg |= CQHCI_ENABLE;
|
||||||
ok = false;
|
cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
|
||||||
WARN_ON(!ok);
|
|
||||||
}
|
cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT);
|
||||||
|
|
||||||
cqhci_recover_mrqs(cq_host);
|
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);
|
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,
|
static void sdhci_set_gl9763e_signaling(struct sdhci_host *host,
|
||||||
unsigned int timing)
|
unsigned int timing)
|
||||||
{
|
{
|
||||||
@ -1297,6 +1323,9 @@ static int gl9763e_add_host(struct sdhci_pci_slot *slot)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Disable LPM negotiation to avoid entering L1 state. */
|
||||||
|
gl9763e_set_low_power_negotiation(slot, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -1340,31 +1369,6 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#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)
|
static int gl9763e_runtime_suspend(struct sdhci_pci_chip *chip)
|
||||||
{
|
{
|
||||||
struct sdhci_pci_slot *slot = chip->slots[0];
|
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);
|
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 = {
|
static struct sdhci_ops sdhci_sprd_ops = {
|
||||||
.read_l = sdhci_sprd_readl,
|
.read_l = sdhci_sprd_readl,
|
||||||
.write_l = sdhci_sprd_writel,
|
.write_l = sdhci_sprd_writel,
|
||||||
.write_w = sdhci_sprd_writew,
|
.write_w = sdhci_sprd_writew,
|
||||||
.write_b = sdhci_sprd_writeb,
|
.write_b = sdhci_sprd_writeb,
|
||||||
.set_clock = sdhci_sprd_set_clock,
|
.set_clock = sdhci_sprd_set_clock,
|
||||||
|
.set_power = sdhci_sprd_set_power,
|
||||||
.get_max_clock = sdhci_sprd_get_max_clock,
|
.get_max_clock = sdhci_sprd_get_max_clock,
|
||||||
.get_min_clock = sdhci_sprd_get_min_clock,
|
.get_min_clock = sdhci_sprd_get_min_clock,
|
||||||
.set_bus_width = sdhci_set_bus_width,
|
.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 |
|
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
|
||||||
SDHCI_SUPPORT_DDR50);
|
SDHCI_SUPPORT_DDR50);
|
||||||
|
|
||||||
|
ret = mmc_regulator_get_supply(host->mmc);
|
||||||
|
if (ret)
|
||||||
|
goto pm_runtime_disable;
|
||||||
|
|
||||||
ret = sdhci_setup_host(host);
|
ret = sdhci_setup_host(host);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto pm_runtime_disable;
|
goto pm_runtime_disable;
|
||||||
|
Loading…
Reference in New Issue
Block a user