提交 126a3483 编写于 作者: L Linus Torvalds

Merge tag 'mmc-fixes-for-3.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

Pull MMC fixes from Chris Ball:
 - Build fix for omap_hsmmc with OF against 3.4-rc1.
 - Fix CONFIG_MMC_UNSAFE_RESUME semantics regression against 3.3, which
   broke hotplug card detection when UNSAFE_RESUME is set.
 - Fix a race condition in omap_hsmmc with runtime PM.
 - Fix two libertas SDIO-powered-resume regressions.
 - Small fixes for discard/sanitize, dw_mmc, cd-gpio and esdhc-imx.

* tag 'mmc-fixes-for-3.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc:
  mmc: core: Do not pre-claim host in suspend
  mmc: dw_mmc: prevent NULL dereference for dma_ops
  mmc: unbreak sdhci-esdhc-imx on i.MX25
  mmc: cd-gpio: Include header to pickup exported symbol prototypes
  mmc: sdhci: refine non-removable card checking for card detection
  mmc: dw_mmc: Fix switch from DMA to PIO
  mmc: remove MMC bus legacy suspend/resume method
  mmc: omap_hsmmc: Get rid of of_have_populated_dt() usage
  mmc: omap_hsmmc: build fix for CONFIG_OF=y and CONFIG_MMC_OMAP_HS=m
  mmc: fixes for eMMC v4.5 sanitize operation
  mmc: fixes for eMMC v4.5 discard operation
...@@ -873,7 +873,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, ...@@ -873,7 +873,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
{ {
struct mmc_blk_data *md = mq->data; struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card; struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg; unsigned int from, nr, arg, trim_arg, erase_arg;
int err = 0, type = MMC_BLK_SECDISCARD; int err = 0, type = MMC_BLK_SECDISCARD;
if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) { if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
...@@ -881,20 +881,26 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, ...@@ -881,20 +881,26 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
goto out; goto out;
} }
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
/* The sanitize operation is supported at v4.5 only */ /* The sanitize operation is supported at v4.5 only */
if (mmc_can_sanitize(card)) { if (mmc_can_sanitize(card)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, erase_arg = MMC_ERASE_ARG;
EXT_CSD_SANITIZE_START, 1, 0); trim_arg = MMC_TRIM_ARG;
goto out; } else {
erase_arg = MMC_SECURE_ERASE_ARG;
trim_arg = MMC_SECURE_TRIM1_ARG;
} }
from = blk_rq_pos(req); if (mmc_erase_group_aligned(card, from, nr))
nr = blk_rq_sectors(req); arg = erase_arg;
else if (mmc_can_trim(card))
if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr)) arg = trim_arg;
arg = MMC_SECURE_TRIM1_ARG; else {
else err = -EINVAL;
arg = MMC_SECURE_ERASE_ARG; goto out;
}
retry: retry:
if (card->quirks & MMC_QUIRK_INAND_CMD38) { if (card->quirks & MMC_QUIRK_INAND_CMD38) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
...@@ -904,25 +910,41 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, ...@@ -904,25 +910,41 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
INAND_CMD38_ARG_SECERASE, INAND_CMD38_ARG_SECERASE,
0); 0);
if (err) if (err)
goto out; goto out_retry;
} }
err = mmc_erase(card, from, nr, arg); err = mmc_erase(card, from, nr, arg);
if (!err && arg == MMC_SECURE_TRIM1_ARG) { if (err == -EIO)
goto out_retry;
if (err)
goto out;
if (arg == MMC_SECURE_TRIM1_ARG) {
if (card->quirks & MMC_QUIRK_INAND_CMD38) { if (card->quirks & MMC_QUIRK_INAND_CMD38) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
INAND_CMD38_ARG_EXT_CSD, INAND_CMD38_ARG_EXT_CSD,
INAND_CMD38_ARG_SECTRIM2, INAND_CMD38_ARG_SECTRIM2,
0); 0);
if (err) if (err)
goto out; goto out_retry;
} }
err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG); err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
if (err == -EIO)
goto out_retry;
if (err)
goto out;
} }
out:
if (err == -EIO && !mmc_blk_reset(md, card->host, type)) if (mmc_can_sanitize(card))
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_SANITIZE_START, 1, 0);
out_retry:
if (err && !mmc_blk_reset(md, card->host, type))
goto retry; goto retry;
if (!err) if (!err)
mmc_blk_reset_success(md, type); mmc_blk_reset_success(md, type);
out:
spin_lock_irq(&md->lock); spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req)); __blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock); spin_unlock_irq(&md->lock);
...@@ -1802,7 +1824,7 @@ static void mmc_blk_remove(struct mmc_card *card) ...@@ -1802,7 +1824,7 @@ static void mmc_blk_remove(struct mmc_card *card)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state) static int mmc_blk_suspend(struct mmc_card *card)
{ {
struct mmc_blk_data *part_md; struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card); struct mmc_blk_data *md = mmc_get_drvdata(card);
......
...@@ -139,7 +139,7 @@ static void mmc_queue_setup_discard(struct request_queue *q, ...@@ -139,7 +139,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
q->limits.max_discard_sectors = max_discard; q->limits.max_discard_sectors = max_discard;
if (card->erased_byte == 0) if (card->erased_byte == 0 && !mmc_can_discard(card))
q->limits.discard_zeroes_data = 1; q->limits.discard_zeroes_data = 1;
q->limits.discard_granularity = card->pref_erase << 9; q->limits.discard_granularity = card->pref_erase << 9;
/* granularity must not be greater than max. discard */ /* granularity must not be greater than max. discard */
......
...@@ -122,14 +122,14 @@ static int mmc_bus_remove(struct device *dev) ...@@ -122,14 +122,14 @@ static int mmc_bus_remove(struct device *dev)
return 0; return 0;
} }
static int mmc_bus_suspend(struct device *dev, pm_message_t state) static int mmc_bus_suspend(struct device *dev)
{ {
struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_card *card = mmc_dev_to_card(dev);
int ret = 0; int ret = 0;
if (dev->driver && drv->suspend) if (dev->driver && drv->suspend)
ret = drv->suspend(card, state); ret = drv->suspend(card);
return ret; return ret;
} }
...@@ -165,20 +165,14 @@ static int mmc_runtime_idle(struct device *dev) ...@@ -165,20 +165,14 @@ static int mmc_runtime_idle(struct device *dev)
return pm_runtime_suspend(dev); return pm_runtime_suspend(dev);
} }
#endif /* !CONFIG_PM_RUNTIME */
static const struct dev_pm_ops mmc_bus_pm_ops = { static const struct dev_pm_ops mmc_bus_pm_ops = {
.runtime_suspend = mmc_runtime_suspend, SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume,
.runtime_resume = mmc_runtime_resume, mmc_runtime_idle)
.runtime_idle = mmc_runtime_idle, SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)
}; };
#define MMC_PM_OPS_PTR (&mmc_bus_pm_ops)
#else /* !CONFIG_PM_RUNTIME */
#define MMC_PM_OPS_PTR NULL
#endif /* !CONFIG_PM_RUNTIME */
static struct bus_type mmc_bus_type = { static struct bus_type mmc_bus_type = {
.name = "mmc", .name = "mmc",
.dev_attrs = mmc_dev_attrs, .dev_attrs = mmc_dev_attrs,
...@@ -186,9 +180,7 @@ static struct bus_type mmc_bus_type = { ...@@ -186,9 +180,7 @@ static struct bus_type mmc_bus_type = {
.uevent = mmc_bus_uevent, .uevent = mmc_bus_uevent,
.probe = mmc_bus_probe, .probe = mmc_bus_probe,
.remove = mmc_bus_remove, .remove = mmc_bus_remove,
.suspend = mmc_bus_suspend, .pm = &mmc_bus_pm_ops,
.resume = mmc_bus_resume,
.pm = MMC_PM_OPS_PTR,
}; };
int mmc_register_bus(void) int mmc_register_bus(void)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/mmc/cd-gpio.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
......
...@@ -1409,7 +1409,10 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card, ...@@ -1409,7 +1409,10 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
{ {
unsigned int erase_timeout; unsigned int erase_timeout;
if (card->ext_csd.erase_group_def & 1) { if (arg == MMC_DISCARD_ARG ||
(arg == MMC_TRIM_ARG && card->ext_csd.rev >= 6)) {
erase_timeout = card->ext_csd.trim_timeout;
} else if (card->ext_csd.erase_group_def & 1) {
/* High Capacity Erase Group Size uses HC timeouts */ /* High Capacity Erase Group Size uses HC timeouts */
if (arg == MMC_TRIM_ARG) if (arg == MMC_TRIM_ARG)
erase_timeout = card->ext_csd.trim_timeout; erase_timeout = card->ext_csd.trim_timeout;
...@@ -1681,8 +1684,6 @@ int mmc_can_trim(struct mmc_card *card) ...@@ -1681,8 +1684,6 @@ int mmc_can_trim(struct mmc_card *card)
{ {
if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
return 1; return 1;
if (mmc_can_discard(card))
return 1;
return 0; return 0;
} }
EXPORT_SYMBOL(mmc_can_trim); EXPORT_SYMBOL(mmc_can_trim);
...@@ -1701,6 +1702,8 @@ EXPORT_SYMBOL(mmc_can_discard); ...@@ -1701,6 +1702,8 @@ EXPORT_SYMBOL(mmc_can_discard);
int mmc_can_sanitize(struct mmc_card *card) int mmc_can_sanitize(struct mmc_card *card)
{ {
if (!mmc_can_trim(card) && !mmc_can_erase(card))
return 0;
if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
return 1; return 1;
return 0; return 0;
...@@ -2235,6 +2238,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable) ...@@ -2235,6 +2238,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
mmc_card_is_removable(host)) mmc_card_is_removable(host))
return err; return err;
mmc_claim_host(host);
if (card && mmc_card_mmc(card) && if (card && mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0)) { (card->ext_csd.cache_size > 0)) {
enable = !!enable; enable = !!enable;
...@@ -2252,6 +2256,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable) ...@@ -2252,6 +2256,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
card->ext_csd.cache_ctrl = enable; card->ext_csd.cache_ctrl = enable;
} }
} }
mmc_release_host(host);
return err; return err;
} }
...@@ -2269,49 +2274,32 @@ int mmc_suspend_host(struct mmc_host *host) ...@@ -2269,49 +2274,32 @@ int mmc_suspend_host(struct mmc_host *host)
cancel_delayed_work(&host->detect); cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work(); mmc_flush_scheduled_work();
if (mmc_try_claim_host(host)) {
err = mmc_cache_ctrl(host, 0);
mmc_release_host(host);
} else {
err = -EBUSY;
}
err = mmc_cache_ctrl(host, 0);
if (err) if (err)
goto out; goto out;
mmc_bus_get(host); mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) { if (host->bus_ops && !host->bus_dead) {
/* if (host->bus_ops->suspend)
* A long response time is not acceptable for device drivers err = host->bus_ops->suspend(host);
* when doing suspend. Prevent mmc_claim_host in the suspend
* sequence, to potentially wait "forever" by trying to
* pre-claim the host.
*/
if (mmc_try_claim_host(host)) {
if (host->bus_ops->suspend) {
err = host->bus_ops->suspend(host);
}
mmc_release_host(host);
if (err == -ENOSYS || !host->bus_ops->resume) { if (err == -ENOSYS || !host->bus_ops->resume) {
/* /*
* We simply "remove" the card in this case. * We simply "remove" the card in this case.
* It will be redetected on resume. (Calling * It will be redetected on resume. (Calling
* bus_ops->remove() with a claimed host can * bus_ops->remove() with a claimed host can
* deadlock.) * deadlock.)
*/ */
if (host->bus_ops->remove) if (host->bus_ops->remove)
host->bus_ops->remove(host); host->bus_ops->remove(host);
mmc_claim_host(host); mmc_claim_host(host);
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_power_off(host); mmc_power_off(host);
mmc_release_host(host); mmc_release_host(host);
host->pm_flags = 0; host->pm_flags = 0;
err = 0; err = 0;
}
} else {
err = -EBUSY;
} }
} }
mmc_bus_put(host); mmc_bus_put(host);
......
...@@ -526,8 +526,10 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) ...@@ -526,8 +526,10 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
return -ENODEV; return -ENODEV;
sg_len = dw_mci_pre_dma_transfer(host, data, 0); sg_len = dw_mci_pre_dma_transfer(host, data, 0);
if (sg_len < 0) if (sg_len < 0) {
host->dma_ops->stop(host);
return sg_len; return sg_len;
}
host->using_dma = 1; host->using_dma = 1;
...@@ -1879,7 +1881,8 @@ static void dw_mci_init_dma(struct dw_mci *host) ...@@ -1879,7 +1881,8 @@ static void dw_mci_init_dma(struct dw_mci *host)
if (!host->dma_ops) if (!host->dma_ops)
goto no_dma; goto no_dma;
if (host->dma_ops->init) { if (host->dma_ops->init && host->dma_ops->start &&
host->dma_ops->stop && host->dma_ops->cleanup) {
if (host->dma_ops->init(host)) { if (host->dma_ops->init(host)) {
dev_err(&host->dev, "%s: Unable to initialize " dev_err(&host->dev, "%s: Unable to initialize "
"DMA Controller.\n", __func__); "DMA Controller.\n", __func__);
......
...@@ -249,7 +249,7 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, ...@@ -249,7 +249,7 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
* the pbias cell programming support is still missing when * the pbias cell programming support is still missing when
* booting with Device tree * booting with Device tree
*/ */
if (of_have_populated_dt() && !vdd) if (dev->of_node && !vdd)
return 0; return 0;
if (mmc_slot(host).before_set_reg) if (mmc_slot(host).before_set_reg)
...@@ -1549,7 +1549,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1549,7 +1549,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* can't be allowed when booting with device * can't be allowed when booting with device
* tree. * tree.
*/ */
(!of_have_populated_dt())) { !host->dev->of_node) {
/* /*
* The mmc_select_voltage fn of the core does * The mmc_select_voltage fn of the core does
* not seem to set the power_mode to * not seem to set the power_mode to
...@@ -1741,7 +1741,7 @@ static const struct of_device_id omap_mmc_of_match[] = { ...@@ -1741,7 +1741,7 @@ static const struct of_device_id omap_mmc_of_match[] = {
.data = &omap4_reg_offset, .data = &omap4_reg_offset,
}, },
{}, {},
} };
MODULE_DEVICE_TABLE(of, omap_mmc_of_match); MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
......
...@@ -467,8 +467,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -467,8 +467,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
clk_prepare_enable(clk); clk_prepare_enable(clk);
pltfm_host->clk = clk; pltfm_host->clk = clk;
if (!is_imx25_esdhc(imx_data)) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
......
...@@ -147,7 +147,7 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) ...@@ -147,7 +147,7 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
u32 present, irqs; u32 present, irqs;
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
!mmc_card_is_removable(host->mmc)) (host->mmc->caps & MMC_CAP_NONREMOVABLE))
return; return;
present = sdhci_readl(host, SDHCI_PRESENT_STATE) & present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
......
...@@ -481,7 +481,7 @@ struct mmc_driver { ...@@ -481,7 +481,7 @@ struct mmc_driver {
struct device_driver drv; struct device_driver drv;
int (*probe)(struct mmc_card *); int (*probe)(struct mmc_card *);
void (*remove)(struct mmc_card *); void (*remove)(struct mmc_card *);
int (*suspend)(struct mmc_card *, pm_message_t); int (*suspend)(struct mmc_card *);
int (*resume)(struct mmc_card *); int (*resume)(struct mmc_card *);
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册