diff options
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/bus.c | 55 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 111 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 1 | ||||
-rw-r--r-- | drivers/mmc/core/debugfs.c | 9 | ||||
-rw-r--r-- | drivers/mmc/core/host.c | 21 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 184 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 130 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.h | 2 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 10 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_bus.c | 16 |
10 files changed, 273 insertions, 266 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8a1f1240e05..5ca562ccfcf 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -25,8 +25,6 @@ #include "sdio_cis.h" #include "bus.h" -#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) - static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -106,33 +104,14 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } -static int mmc_bus_probe(struct device *dev) -{ - struct mmc_driver *drv = to_mmc_driver(dev->driver); - struct mmc_card *card = mmc_dev_to_card(dev); - - return drv->probe(card); -} - -static int mmc_bus_remove(struct device *dev) -{ - struct mmc_driver *drv = to_mmc_driver(dev->driver); - struct mmc_card *card = mmc_dev_to_card(dev); - - drv->remove(card); - - return 0; -} - static void mmc_bus_shutdown(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; - if (dev->driver && drv->shutdown) - drv->shutdown(card); + if (dev->driver && dev->driver->shutdown) + dev->driver->shutdown(dev); if (host->bus_ops->shutdown) { ret = host->bus_ops->shutdown(host); @@ -145,16 +124,13 @@ static void mmc_bus_shutdown(struct device *dev) #ifdef CONFIG_PM_SLEEP static int mmc_bus_suspend(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; - if (dev->driver && drv->suspend) { - ret = drv->suspend(card); - if (ret) - return ret; - } + ret = pm_generic_suspend(dev); + if (ret) + return ret; ret = host->bus_ops->suspend(host); return ret; @@ -162,7 +138,6 @@ static int mmc_bus_suspend(struct device *dev) static int mmc_bus_resume(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; @@ -172,9 +147,7 @@ static int mmc_bus_resume(struct device *dev) pr_warn("%s: error %d during resume (card was removed?)\n", mmc_hostname(host), ret); - if (dev->driver && drv->resume) - ret = drv->resume(card); - + ret = pm_generic_resume(dev); return ret; } #endif @@ -207,8 +180,6 @@ static struct bus_type mmc_bus_type = { .dev_groups = mmc_dev_groups, .match = mmc_bus_match, .uevent = mmc_bus_uevent, - .probe = mmc_bus_probe, - .remove = mmc_bus_remove, .shutdown = mmc_bus_shutdown, .pm = &mmc_bus_pm_ops, }; @@ -227,24 +198,22 @@ void mmc_unregister_bus(void) * mmc_register_driver - register a media driver * @drv: MMC media driver */ -int mmc_register_driver(struct mmc_driver *drv) +int mmc_register_driver(struct device_driver *drv) { - drv->drv.bus = &mmc_bus_type; - return driver_register(&drv->drv); + drv->bus = &mmc_bus_type; + return driver_register(drv); } - EXPORT_SYMBOL(mmc_register_driver); /** * mmc_unregister_driver - unregister a media driver * @drv: MMC media driver */ -void mmc_unregister_driver(struct mmc_driver *drv) +void mmc_unregister_driver(struct device_driver *drv) { - drv->drv.bus = &mmc_bus_type; - driver_unregister(&drv->drv); + drv->bus = &mmc_bus_type; + driver_unregister(drv); } - EXPORT_SYMBOL(mmc_unregister_driver); static void mmc_release_card(struct device *dev) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f26a5f1d926..9584bffa8b2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -149,6 +149,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) led_trigger_event(host->led, LED_OFF); + if (mrq->sbc) { + pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n", + mmc_hostname(host), mrq->sbc->opcode, + mrq->sbc->error, + mrq->sbc->resp[0], mrq->sbc->resp[1], + mrq->sbc->resp[2], mrq->sbc->resp[3]); + } + pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], @@ -214,6 +222,10 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->cmd->error = 0; mrq->cmd->mrq = mrq; + if (mrq->sbc) { + mrq->sbc->error = 0; + mrq->sbc->mrq = mrq; + } if (mrq->data) { BUG_ON(mrq->data->blksz > host->max_blk_size); BUG_ON(mrq->data->blocks > host->max_blk_count); @@ -538,8 +550,18 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, if (host->card && mmc_card_mmc(host->card) && ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) || (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && - (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) + (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) { + + /* Cancel the prepared request */ + if (areq) + mmc_post_req(host, areq->mrq, -EINVAL); + mmc_start_bkops(host->card, true); + + /* prepare the request again */ + if (areq) + mmc_pre_req(host, areq->mrq, !host->areq); + } } if (!err && areq) @@ -709,27 +731,16 @@ int mmc_read_bkops_status(struct mmc_card *card) int err; u8 *ext_csd; - /* - * In future work, we should consider storing the entire ext_csd. - */ - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: could not allocate buffer to receive the ext_csd.\n", - mmc_hostname(card->host)); - return -ENOMEM; - } - mmc_claim_host(card->host); - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_get_ext_csd(card, &ext_csd); mmc_release_host(card->host); if (err) - goto out; + return err; card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS]; -out: kfree(ext_csd); - return err; + return 0; } EXPORT_SYMBOL(mmc_read_bkops_status); @@ -1088,6 +1099,22 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) mmc_host_clk_release(host); } +/* + * Set initial state after a power cycle or a hw_reset. + */ +void mmc_set_initial_state(struct mmc_host *host) +{ + if (mmc_host_is_spi(host)) + host->ios.chip_select = MMC_CS_HIGH; + else + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; + + mmc_set_ios(host); +} + /** * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number * @vdd: voltage (mV) @@ -1420,18 +1447,20 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) pr_warn("%s: cannot verify signal voltage switch\n", mmc_hostname(host)); + mmc_host_clk_hold(host); + cmd.opcode = SD_SWITCH_VOLTAGE; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, 0); if (err) - return err; + goto err_command; - if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) - return -EIO; - - mmc_host_clk_hold(host); + if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) { + err = -EIO; + goto err_command; + } /* * The card should drive cmd and dat[0:3] low immediately * after the response of cmd11, but wait 1 ms to be sure @@ -1480,6 +1509,7 @@ power_cycle: mmc_power_cycle(host, ocr); } +err_command: mmc_host_clk_release(host); return err; @@ -1526,15 +1556,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) mmc_host_clk_hold(host); host->ios.vdd = fls(ocr) - 1; - if (mmc_host_is_spi(host)) - host->ios.chip_select = MMC_CS_HIGH; - else - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; host->ios.power_mode = MMC_POWER_UP; - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0) @@ -1574,14 +1598,9 @@ void mmc_power_off(struct mmc_host *host) host->ios.clock = 0; host->ios.vdd = 0; - if (!mmc_host_is_spi(host)) { - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; - } host->ios.power_mode = MMC_POWER_OFF; - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); /* * Some configurations, such as the 802.11 SDIO card in the OLPC @@ -2259,30 +2278,16 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check) /* If the reset has happened, then a status command will fail */ if (check) { - struct mmc_command cmd = {0}; - int err; + u32 status; - cmd.opcode = MMC_SEND_STATUS; - if (!mmc_host_is_spi(card->host)) - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, 0); - if (!err) { + if (!mmc_send_status(card, &status)) { mmc_host_clk_release(host); return -ENOSYS; } } - if (mmc_host_is_spi(host)) { - host->ios.chip_select = MMC_CS_HIGH; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; - } else { - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - } - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); mmc_host_clk_release(host); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 443a584660f..d76597c65e3 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -49,6 +49,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); void mmc_power_up(struct mmc_host *host, u32 ocr); void mmc_power_off(struct mmc_host *host); void mmc_power_cycle(struct mmc_host *host, u32 ocr); +void mmc_set_initial_state(struct mmc_host *host); static inline void mmc_delay(unsigned int ms) { diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 91eb1622324..e9142108a6c 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -291,14 +291,8 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) if (!buf) return -ENOMEM; - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - err = -ENOMEM; - goto out_free; - } - mmc_get_card(card); - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_get_ext_csd(card, &ext_csd); mmc_put_card(card); if (err) goto out_free; @@ -314,7 +308,6 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) out_free: kfree(buf); - kfree(ext_csd); return err; } diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 03c53b72a2d..270d58a4c43 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -311,7 +311,8 @@ int mmc_of_parse(struct mmc_host *host) struct device_node *np; u32 bus_width; int len, ret; - bool cap_invert, gpio_invert; + bool cd_cap_invert, cd_gpio_invert = false; + bool ro_cap_invert, ro_gpio_invert = false; if (!host->parent || !host->parent->of_node) return 0; @@ -359,16 +360,13 @@ int mmc_of_parse(struct mmc_host *host) if (of_find_property(np, "non-removable", &len)) { host->caps |= MMC_CAP_NONREMOVABLE; } else { - if (of_property_read_bool(np, "cd-inverted")) - cap_invert = true; - else - cap_invert = false; + cd_cap_invert = of_property_read_bool(np, "cd-inverted"); if (of_find_property(np, "broken-cd", &len)) host->caps |= MMC_CAP_NEEDS_POLL; ret = mmc_gpiod_request_cd(host, "cd", 0, true, - 0, &gpio_invert); + 0, &cd_gpio_invert); if (ret) { if (ret == -EPROBE_DEFER) return ret; @@ -391,17 +389,14 @@ int mmc_of_parse(struct mmc_host *host) * both inverted, the end result is that the CD line is * not inverted. */ - if (cap_invert ^ gpio_invert) + if (cd_cap_invert ^ cd_gpio_invert) host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; } /* Parse Write Protection */ - if (of_property_read_bool(np, "wp-inverted")) - cap_invert = true; - else - cap_invert = false; + ro_cap_invert = of_property_read_bool(np, "wp-inverted"); - ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &gpio_invert); + ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert); if (ret) { if (ret == -EPROBE_DEFER) goto out; @@ -414,7 +409,7 @@ int mmc_of_parse(struct mmc_host *host) dev_info(host->parent, "Got WP GPIO\n"); /* See the comment on CD inversion above */ - if (cap_invert ^ gpio_invert) + if (ro_cap_invert ^ ro_gpio_invert) host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; if (of_find_property(np, "cap-sd-highspeed", &len)) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index a301a78a2bd..02ad79229f6 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -177,65 +177,6 @@ static int mmc_decode_csd(struct mmc_card *card) return 0; } -/* - * Read extended CSD. - */ -static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) -{ - int err; - u8 *ext_csd; - - BUG_ON(!card); - BUG_ON(!new_ext_csd); - - *new_ext_csd = NULL; - - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return 0; - - /* - * As the ext_csd is so large and mostly unused, we don't store the - * raw block in mmc_card. - */ - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: could not allocate a buffer to " - "receive the ext_csd.\n", mmc_hostname(card->host)); - return -ENOMEM; - } - - err = mmc_send_ext_csd(card, ext_csd); - if (err) { - kfree(ext_csd); - *new_ext_csd = NULL; - - /* If the host or the card can't do the switch, - * fail more gracefully. */ - if ((err != -EINVAL) - && (err != -ENOSYS) - && (err != -EFAULT)) - return err; - - /* - * High capacity cards should have this "magic" size - * stored in their CSD. - */ - if (card->csd.capacity == (4096 * 512)) { - pr_err("%s: unable to read EXT_CSD " - "on a possible high capacity card. " - "Card will be ignored.\n", - mmc_hostname(card->host)); - } else { - pr_warn("%s: unable to read EXT_CSD, performance might suffer\n", - mmc_hostname(card->host)); - err = 0; - } - } else - *new_ext_csd = ext_csd; - - return err; -} - static void mmc_select_card_type(struct mmc_card *card) { struct mmc_host *host = card->host; @@ -391,16 +332,11 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) /* * Decode extended CSD. */ -static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; - BUG_ON(!card); - - if (!ext_csd) - return 0; - /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { @@ -628,16 +564,56 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.data_sector_size = 512; } + /* eMMC v5 or later */ + if (card->ext_csd.rev >= 7) { + memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION], + MMC_FIRMWARE_LEN); + card->ext_csd.ffu_capable = + (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) && + !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1); + } out: return err; } -static inline void mmc_free_ext_csd(u8 *ext_csd) +static int mmc_read_ext_csd(struct mmc_card *card) { + u8 *ext_csd; + int err; + + if (!mmc_can_ext_csd(card)) + return 0; + + err = mmc_get_ext_csd(card, &ext_csd); + if (err) { + /* If the host or the card can't do the switch, + * fail more gracefully. */ + if ((err != -EINVAL) + && (err != -ENOSYS) + && (err != -EFAULT)) + return err; + + /* + * High capacity cards should have this "magic" size + * stored in their CSD. + */ + if (card->csd.capacity == (4096 * 512)) { + pr_err("%s: unable to read EXT_CSD on a possible high capacity card. Card will be ignored.\n", + mmc_hostname(card->host)); + } else { + pr_warn("%s: unable to read EXT_CSD, performance might suffer\n", + mmc_hostname(card->host)); + err = 0; + } + + return err; + } + + err = mmc_decode_ext_csd(card, ext_csd); kfree(ext_csd); + return err; } - static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) { u8 *bw_ext_csd; @@ -647,11 +623,8 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) return 0; err = mmc_get_ext_csd(card, &bw_ext_csd); - - if (err || bw_ext_csd == NULL) { - err = -EINVAL; - goto out; - } + if (err) + return err; /* only compare read only fields */ err = !((card->ext_csd.raw_partition_support == @@ -710,8 +683,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) if (err) err = -EINVAL; -out: - mmc_free_ext_csd(bw_ext_csd); + kfree(bw_ext_csd); return err; } @@ -722,7 +694,7 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9); MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9); -MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev); +MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable); MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); @@ -735,6 +707,22 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); +static ssize_t mmc_fwrev_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mmc_card *card = mmc_dev_to_card(dev); + + if (card->ext_csd.rev < 7) { + return sprintf(buf, "0x%x\n", card->cid.fwrev); + } else { + return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, + card->ext_csd.fwrev); + } +} + +static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL); + static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, &dev_attr_csd.attr, @@ -742,6 +730,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_erase_size.attr, &dev_attr_preferred_erase_size.attr, &dev_attr_fwrev.attr, + &dev_attr_ffu_capable.attr, &dev_attr_hwrev.attr, &dev_attr_manfid.attr, &dev_attr_name.attr, @@ -774,14 +763,6 @@ static int __mmc_select_powerclass(struct mmc_card *card, unsigned int pwrclass_val = 0; int err = 0; - /* Power class selection is supported for versions >= 4.0 */ - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return 0; - - /* Power class values are defined only for 4/8 bit bus */ - if (bus_width == EXT_CSD_BUS_WIDTH_1) - return 0; - switch (1 << host->ios.vdd) { case MMC_VDD_165_195: if (host->ios.clock <= MMC_HIGH_26_MAX_DTR) @@ -844,7 +825,7 @@ static int mmc_select_powerclass(struct mmc_card *card) int err, ddr; /* Power class selection is supported for versions >= 4.0 */ - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + if (!mmc_can_ext_csd(card)) return 0; bus_width = host->ios.bus_width; @@ -905,7 +886,7 @@ static int mmc_select_bus_width(struct mmc_card *card) unsigned idx, bus_width = 0; int err = 0; - if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) && + if (!mmc_can_ext_csd(card) && !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; @@ -998,7 +979,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ext_csd_bits, card->ext_csd.generic_cmd6_time); if (err) { - pr_warn("%s: switch to bus width %d ddr failed\n", + pr_err("%s: switch to bus width %d ddr failed\n", mmc_hostname(host), 1 << bus_width); return err; } @@ -1069,7 +1050,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->ext_csd.generic_cmd6_time, true, true, true); if (err) { - pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n", + pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1079,7 +1060,7 @@ static int mmc_select_hs400(struct mmc_card *card) EXT_CSD_DDR_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time); if (err) { - pr_warn("%s: switch to bus width for hs400 failed, err:%d\n", + pr_err("%s: switch to bus width for hs400 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1089,7 +1070,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->ext_csd.generic_cmd6_time, true, true, true); if (err) { - pr_warn("%s: switch to hs400 failed, err:%d\n", + pr_err("%s: switch to hs400 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1146,8 +1127,7 @@ static int mmc_select_timing(struct mmc_card *card) { int err = 0; - if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 && - card->ext_csd.hs_max_dtr == 0)) + if (!mmc_can_ext_csd(card)) goto bus_speed; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) @@ -1232,7 +1212,7 @@ static int mmc_hs200_tuning(struct mmc_card *card) mmc_host_clk_release(host); if (err) - pr_warn("%s: tuning execution failed\n", + pr_err("%s: tuning execution failed\n", mmc_hostname(host)); } @@ -1252,7 +1232,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, int err; u32 cid[4]; u32 rocr; - u8 *ext_csd = NULL; BUG_ON(!host); WARN_ON(!host->claimed); @@ -1361,14 +1340,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } if (!oldcard) { - /* - * Fetch and process extended CSD. - */ - - err = mmc_get_ext_csd(card, &ext_csd); - if (err) - goto free_card; - err = mmc_read_ext_csd(card, ext_csd); + /* Read extended CSD. */ + err = mmc_read_ext_csd(card); if (err) goto free_card; @@ -1458,18 +1431,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (mmc_card_hs200(card)) { err = mmc_hs200_tuning(card); if (err) - goto err; + goto free_card; err = mmc_select_hs400(card); if (err) - goto err; + goto free_card; } else if (mmc_card_hs(card)) { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); if (!IS_ERR_VALUE(err)) { err = mmc_select_hs_ddr(card); if (err) - goto err; + goto free_card; } } @@ -1545,15 +1518,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - mmc_free_ext_csd(ext_csd); return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - mmc_free_ext_csd(ext_csd); - return err; } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 7911e0510a1..3b044c5b029 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -264,20 +264,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; - void *data_buf; - int is_on_stack; - - is_on_stack = object_is_on_stack(buf); - if (is_on_stack) { - /* - * dma onto stack is unsafe/nonportable, but callers to this - * routine normally provide temporary on-stack buffers ... - */ - data_buf = kmalloc(len, GFP_KERNEL); - if (!data_buf) - return -ENOMEM; - } else - data_buf = buf; mrq.cmd = &cmd; mrq.data = &data; @@ -298,7 +284,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, data_buf, len); + sg_init_one(&sg, buf, len); if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) { /* @@ -312,11 +298,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, mmc_wait_for_req(host, &mrq); - if (is_on_stack) { - memcpy(buf, data_buf, len); - kfree(data_buf); - } - if (cmd.error) return cmd.error; if (data.error) @@ -334,7 +315,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd) return mmc_send_cxd_native(card->host, card->rca << 16, csd, MMC_SEND_CSD); - csd_tmp = kmalloc(16, GFP_KERNEL); + csd_tmp = kzalloc(16, GFP_KERNEL); if (!csd_tmp) return -ENOMEM; @@ -362,7 +343,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid) cid, MMC_SEND_CID); } - cid_tmp = kmalloc(16, GFP_KERNEL); + cid_tmp = kzalloc(16, GFP_KERNEL); if (!cid_tmp) return -ENOMEM; @@ -378,12 +359,35 @@ err: return ret; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) { - return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, - ext_csd, 512); + int err; + u8 *ext_csd; + + if (!card || !new_ext_csd) + return -EINVAL; + + if (!mmc_can_ext_csd(card)) + return -EOPNOTSUPP; + + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + ext_csd = kzalloc(512, GFP_KERNEL); + if (!ext_csd) + return -ENOMEM; + + err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd, + 512); + if (err) + kfree(ext_csd); + else + *new_ext_csd = ext_csd; + + return err; } -EXPORT_SYMBOL_GPL(mmc_send_ext_csd); +EXPORT_SYMBOL_GPL(mmc_get_ext_csd); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) { @@ -543,6 +547,75 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, } EXPORT_SYMBOL_GPL(mmc_switch); +int mmc_send_tuning(struct mmc_host *host) +{ + struct mmc_request mrq = {NULL}; + struct mmc_command cmd = {0}; + struct mmc_data data = {0}; + struct scatterlist sg; + struct mmc_ios *ios = &host->ios; + const u8 *tuning_block_pattern; + int size, err = 0; + u8 *data_buf; + u32 opcode; + + if (ios->bus_width == MMC_BUS_WIDTH_8) { + tuning_block_pattern = tuning_blk_pattern_8bit; + size = sizeof(tuning_blk_pattern_8bit); + opcode = MMC_SEND_TUNING_BLOCK_HS200; + } else if (ios->bus_width == MMC_BUS_WIDTH_4) { + tuning_block_pattern = tuning_blk_pattern_4bit; + size = sizeof(tuning_blk_pattern_4bit); + opcode = MMC_SEND_TUNING_BLOCK; + } else + return -EINVAL; + + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) + return -ENOMEM; + + mrq.cmd = &cmd; + mrq.data = &data; + + cmd.opcode = opcode; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = size; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + /* + * According to the tuning specs, Tuning process + * is normally shorter 40 executions of CMD19, + * and timeout value should be shorter than 150 ms + */ + data.timeout_ns = 150 * NSEC_PER_MSEC; + + data.sg = &sg; + data.sg_len = 1; + sg_init_one(&sg, data_buf, size); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error) { + err = cmd.error; + goto out; + } + + if (data.error) { + err = data.error; + goto out; + } + + if (memcmp(data_buf, tuning_block_pattern, size)) + err = -EIO; + +out: + kfree(data_buf); + return err; +} +EXPORT_SYMBOL_GPL(mmc_send_tuning); + static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) @@ -675,3 +748,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) return 0; } + +int mmc_can_ext_csd(struct mmc_card *card) +{ + return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3); +} diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 390dac665b2..6f4b00ed93d 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -20,13 +20,13 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_all_send_cid(struct mmc_host *host, u32 *cid); int mmc_set_relative_addr(struct mmc_card *card); int mmc_send_csd(struct mmc_card *card, u32 *csd); -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); +int mmc_can_ext_csd(struct mmc_card *card); #endif diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2439e717655..fd0750b5a63 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -980,8 +980,12 @@ static int mmc_sdio_resume(struct mmc_host *host) if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { sdio_reset(host); mmc_go_idle(host); - err = mmc_sdio_init_card(host, host->card->ocr, host->card, - mmc_card_keep_power(host)); + mmc_send_if_cond(host, host->card->ocr); + err = mmc_send_io_op_cond(host, 0, NULL); + if (!err) + err = mmc_sdio_init_card(host, host->card->ocr, + host->card, + mmc_card_keep_power(host)); } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); @@ -1035,7 +1039,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host) sdio_reset(host); mmc_go_idle(host); - mmc_send_if_cond(host, host->ocr_avail); + mmc_send_if_cond(host, host->card->ocr); ret = mmc_send_io_op_cond(host, 0, NULL); if (ret) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 6da97b17056..60885316afb 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -26,6 +26,8 @@ #include "sdio_cis.h" #include "sdio_bus.h" +#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) + /* show configuration fields */ #define sdio_config_attr(field, format_string) \ static ssize_t \ @@ -196,8 +198,6 @@ static int sdio_bus_remove(struct device *dev) return ret; } -#ifdef CONFIG_PM - static const struct dev_pm_ops sdio_bus_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) SET_RUNTIME_PM_OPS( @@ -207,14 +207,6 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { ) }; -#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) - -#else /* !CONFIG_PM */ - -#define SDIO_PM_OPS_PTR NULL - -#endif /* !CONFIG_PM */ - static struct bus_type sdio_bus_type = { .name = "sdio", .dev_groups = sdio_dev_groups, @@ -222,7 +214,7 @@ static struct bus_type sdio_bus_type = { .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, .remove = sdio_bus_remove, - .pm = SDIO_PM_OPS_PTR, + .pm = &sdio_bus_pm_ops, }; int sdio_register_bus(void) @@ -295,7 +287,7 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) static void sdio_acpi_set_handle(struct sdio_func *func) { struct mmc_host *host = func->card->host; - u64 addr = (host->slotno << 16) | func->num; + u64 addr = ((u64)host->slotno << 16) | func->num; acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); } |