diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 12:04:54 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 12:04:54 -0800 |
commit | e67bd12d6036ae3de9eeb0ba52e43691264ec850 (patch) | |
tree | 0232867e68e2b56fd601f7c31b0d5f87d7ec3792 /drivers/mmc/core | |
parent | cdc194705d26fdd7fc5446b5d830f2bbe2b22c30 (diff) | |
parent | 8c7cdbf9272c300dc093da3c62fa3b4bc6dc960e (diff) |
Merge tag 'mmc-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Add support for Marvell SD8787 Wifi/BT chip
- Improve UHS support for SDIO
- Invent MMC_CAP_3_3V_DDR and a DT binding for eMMC DDR 3.3V mode
- Detect Auto BKOPS enable bit
- Export eMMC device lifetime information through sysfs
- First take to slim down the public mmc headers to avoid abuse
- Re-factoring of the mmc block device driver to prepare for blkmq
- Cleanup code for the mmc block device driver
- Clarify and cleanup code dealing with data requests
- Cleanup some code by converting to ida_simple_ functions
- Cleanup code dealing with card quirks
- Cleanup private and public mmc header files
MMC host:
- Don't rely on public mmc headers to include non-mmc related headers
- meson: Add support for eMMC HS400 mode
- meson: Various cleanups and improvements
- omap_hsmmc: Use the proper provided busy timeout from the core
- sunxi: Enable new timings for the A64 MMC controllers
- sunxi: Improvements for clock management
- tmio: Improvements for SDIO interrupts
- mxs-mmc: Add CMD23 support
- sdhci-msm: Enable HS400 enhanced strobe mode support
- sdhci-msm: Correct HS400 tuning sequence
- sdhci-acpi: Support deferred probe
- sdhci-pci: Add support for eMMC HS200 tuning mode on AMD
- mediatek: Correct the implementation of card busy detection
- dw_mmc: Initial support for ZX mmc controller
- sh_mobile_sdhi: Enable support for eMMC HS200 mode
- sh_mmcif: Various cleanups and improvements"
* tag 'mmc-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (145 commits)
mmc: core: add mmc prefix for blk_fixups
mmc: core: move all quirks together into quirks.h
mmc: core: improve the quirks for sdio devices
mmc: core: move some sdio IDs out of quirks file
mmc: core: change quirks.c to be a header file
mmc: sdhci-cadence: fix bit shift of read data from PHY port
mmc: Adding AUTO_BKOPS_EN bit set for Auto BKOPS support
mmc: MAN_BKOPS_EN inverse debug message logic
mmc: meson-gx: add support for HS400 mode
mmc: meson-gx: remove unneeded checks in remove
mmc: meson-gx: reduce bounce buffer size
mmc: meson-gx: set max block count and request size
mmc: meson-gx: improve interrupt handling
mmc: meson-gx: improve meson_mmc_irq_thread
mmc: meson-gx: improve meson_mmc_clk_set
mmc: meson-gx: minor improvements in meson_mmc_set_ios
mmc: meson: Assign the minimum clk rate as close to 400KHz as possible
mmc: core: start to break apart mmc_start_areq()
mmc: block: respect bool returned from blk_end_request()
mmc: block: return errorcode from mmc_sd_num_wr_blocks()
...
Diffstat (limited to 'drivers/mmc/core')
36 files changed, 1110 insertions, 562 deletions
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index cdfa8520a4b1..fc1ecdaaa9ca 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -12,6 +12,16 @@ config PWRSEQ_EMMC This driver can also be built as a module. If so, the module will be called pwrseq_emmc. +config PWRSEQ_SD8787 + tristate "HW reset support for SD8787 BT + Wifi module" + depends on OF && (MWIFIEX || BT_MRVL_SDIO) + help + This selects hardware reset support for the SD8787 BT + Wifi + module. By default this option is set to n. + + This driver can also be built as a module. If so, the module + will be called pwrseq_sd8787. + config PWRSEQ_SIMPLE tristate "Simple HW reset support for MMC" default y diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index b2a257dc644f..7e3ed1aeada2 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,9 +7,10 @@ mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ - quirks.o slot-gpio.o + slot-gpio.o mmc_core-$(CONFIG_OF) += pwrseq.o obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o +obj-$(CONFIG_PWRSEQ_SD8787) += pwrseq_sd8787.o obj-$(CONFIG_PWRSEQ_EMMC) += pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_MMC_BLOCK) += mmc_block.o diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index cb1698f268f1..1621fa08e206 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -47,6 +47,13 @@ #include "queue.h" #include "block.h" +#include "core.h" +#include "card.h" +#include "host.h" +#include "bus.h" +#include "mmc_ops.h" +#include "quirks.h" +#include "sd_ops.h" MODULE_ALIAS("mmc:block"); #ifdef MODULE_PARAM_PREFIX @@ -54,12 +61,6 @@ MODULE_ALIAS("mmc:block"); #endif #define MODULE_PARAM_PREFIX "mmcblk." -#define INAND_CMD38_ARG_EXT_CSD 113 -#define INAND_CMD38_ARG_ERASE 0x00 -#define INAND_CMD38_ARG_TRIM 0x01 -#define INAND_CMD38_ARG_SECERASE 0x80 -#define INAND_CMD38_ARG_SECTRIM1 0x81 -#define INAND_CMD38_ARG_SECTRIM2 0x88 #define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ #define MMC_SANITIZE_REQ_TIMEOUT 240000 #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16) @@ -84,7 +85,6 @@ static int max_devices; #define MAX_DEVICES 256 static DEFINE_IDA(mmc_blk_ida); -static DEFINE_SPINLOCK(mmc_blk_lock); /* * There is one mmc_blk_data per slot. @@ -157,11 +157,7 @@ static void mmc_blk_put(struct mmc_blk_data *md) if (md->usage == 0) { int devidx = mmc_get_devidx(md->disk); blk_cleanup_queue(md->queue.queue); - - spin_lock(&mmc_blk_lock); - ida_remove(&mmc_blk_ida, devidx); - spin_unlock(&mmc_blk_lock); - + ida_simple_remove(&mmc_blk_ida, devidx); put_disk(md->disk); kfree(md); } @@ -442,9 +438,9 @@ out: static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_blk_ioc_data *idata) { - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; - struct mmc_request mrq = {NULL}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; + struct mmc_request mrq = {}; struct scatterlist sg; int err; int is_rpmb = false; @@ -762,15 +758,15 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, return 0; } -static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) +static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks) { int err; u32 result; __be32 *blocks; - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; @@ -780,9 +776,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) - return (u32)-1; + return err; if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) - return (u32)-1; + return -EIO; memset(&cmd, 0, sizeof(struct mmc_command)); @@ -802,7 +798,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) blocks = kmalloc(4, GFP_KERNEL); if (!blocks) - return (u32)-1; + return -ENOMEM; sg_init_one(&sg, blocks, 4); @@ -812,14 +808,16 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) kfree(blocks); if (cmd.error || data.error) - result = (u32)-1; + return -EIO; + + *written_blocks = result; - return result; + return 0; } static int get_card_status(struct mmc_card *card, u32 *status, int retries) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; cmd.opcode = MMC_SEND_STATUS; @@ -884,7 +882,7 @@ static int send_stop(struct mmc_card *card, unsigned int timeout_ms, struct request *req, bool *gen_err, u32 *stop_status) { struct mmc_host *host = card->host; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; bool use_r1b_resp = rq_data_dir(req) == WRITE; @@ -1143,7 +1141,7 @@ int mmc_access_rpmb(struct mmc_queue *mq) return false; } -static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) +static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1152,7 +1150,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) if (!mmc_can_erase(card)) { err = -EOPNOTSUPP; - goto out; + goto fail; } from = blk_rq_pos(req); @@ -1164,29 +1162,26 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) arg = MMC_TRIM_ARG; else arg = MMC_ERASE_ARG; -retry: - if (card->quirks & MMC_QUIRK_INAND_CMD38) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - INAND_CMD38_ARG_EXT_CSD, - arg == MMC_TRIM_ARG ? - INAND_CMD38_ARG_TRIM : - INAND_CMD38_ARG_ERASE, - 0); - if (err) - goto out; - } - err = mmc_erase(card, from, nr, arg); -out: - if (err == -EIO && !mmc_blk_reset(md, card->host, type)) - goto retry; + do { + err = 0; + if (card->quirks & MMC_QUIRK_INAND_CMD38) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + INAND_CMD38_ARG_EXT_CSD, + arg == MMC_TRIM_ARG ? + INAND_CMD38_ARG_TRIM : + INAND_CMD38_ARG_ERASE, + 0); + } + if (!err) + err = mmc_erase(card, from, nr, arg); + } while (err == -EIO && !mmc_blk_reset(md, card->host, type)); if (!err) mmc_blk_reset_success(md, type); +fail: blk_end_request(req, err, blk_rq_bytes(req)); - - return err ? 0 : 1; } -static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, +static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; @@ -1249,11 +1244,9 @@ out_retry: mmc_blk_reset_success(md, type); out: blk_end_request(req, err, blk_rq_bytes(req)); - - return err ? 0 : 1; } -static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) +static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1264,8 +1257,6 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) ret = -EIO; blk_end_request_all(req, ret); - - return ret ? 0 : 1; } /* @@ -1303,7 +1294,7 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card, struct mmc_async_req *areq) { struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req, - mmc_active); + areq); struct mmc_blk_request *brq = &mq_mrq->brq; struct request *req = mq_mrq->req; int need_retune = card->host->need_retune; @@ -1559,17 +1550,19 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, brq->data.sg_len = i; } - mqrq->mmc_active.mrq = &brq->mrq; - mqrq->mmc_active.err_check = mmc_blk_err_check; + mqrq->areq.mrq = &brq->mrq; + mqrq->areq.err_check = mmc_blk_err_check; mmc_queue_bounce_pre(mqrq); } -static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, - struct mmc_blk_request *brq, struct request *req, - int ret) +static bool mmc_blk_rw_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, + struct mmc_blk_request *brq, struct request *req, + bool old_req_pending) { struct mmc_queue_req *mq_rq; + bool req_pending; + mq_rq = container_of(brq, struct mmc_queue_req, brq); /* @@ -1582,62 +1575,104 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, */ if (mmc_card_sd(card)) { u32 blocks; + int err; - blocks = mmc_sd_num_wr_blocks(card); - if (blocks != (u32)-1) { - ret = blk_end_request(req, 0, blocks << 9); - } + err = mmc_sd_num_wr_blocks(card, &blocks); + if (err) + req_pending = old_req_pending; + else + req_pending = blk_end_request(req, 0, blocks << 9); } else { - ret = blk_end_request(req, 0, brq->data.bytes_xfered); + req_pending = blk_end_request(req, 0, brq->data.bytes_xfered); } - return ret; + return req_pending; +} + +static void mmc_blk_rw_cmd_abort(struct mmc_card *card, struct request *req) +{ + if (mmc_card_removed(card)) + req->rq_flags |= RQF_QUIET; + while (blk_end_request(req, -EIO, blk_rq_cur_bytes(req))); +} + +/** + * mmc_blk_rw_try_restart() - tries to restart the current async request + * @mq: the queue with the card and host to restart + * @req: a new request that want to be started after the current one + */ +static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req) +{ + if (!req) + return; + + /* + * If the card was removed, just cancel everything and return. + */ + if (mmc_card_removed(mq->card)) { + req->rq_flags |= RQF_QUIET; + blk_end_request_all(req, -EIO); + return; + } + /* Else proceed and try to restart the current async request */ + mmc_blk_rw_rq_prep(mq->mqrq_cur, mq->card, 0, mq); + mmc_start_areq(mq->card->host, &mq->mqrq_cur->areq, NULL); } -static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) +static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; struct mmc_blk_request *brq; - int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0; + int disable_multi = 0, retry = 0, type, retune_retry_done = 0; enum mmc_blk_status status; struct mmc_queue_req *mq_rq; - struct request *req; - struct mmc_async_req *areq; + struct request *old_req; + struct mmc_async_req *new_areq; + struct mmc_async_req *old_areq; + bool req_pending = true; - if (!rqc && !mq->mqrq_prev->req) - return 0; + if (!new_req && !mq->mqrq_prev->req) + return; do { - if (rqc) { + if (new_req) { /* * When 4KB native sector is enabled, only 8 blocks * multiple read or write is allowed */ if (mmc_large_sector(card) && - !IS_ALIGNED(blk_rq_sectors(rqc), 8)) { + !IS_ALIGNED(blk_rq_sectors(new_req), 8)) { pr_err("%s: Transfer size is not 4KB sector size aligned\n", - rqc->rq_disk->disk_name); - mq_rq = mq->mqrq_cur; - req = rqc; - rqc = NULL; - goto cmd_abort; + new_req->rq_disk->disk_name); + mmc_blk_rw_cmd_abort(card, new_req); + return; } mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); - areq = &mq->mqrq_cur->mmc_active; + new_areq = &mq->mqrq_cur->areq; } else - areq = NULL; - areq = mmc_start_req(card->host, areq, &status); - if (!areq) { + new_areq = NULL; + + old_areq = mmc_start_areq(card->host, new_areq, &status); + if (!old_areq) { + /* + * We have just put the first request into the pipeline + * and there is nothing more to do until it is + * complete. + */ if (status == MMC_BLK_NEW_REQUEST) - mq->flags |= MMC_QUEUE_NEW_REQUEST; - return 0; + mq->new_request = true; + return; } - mq_rq = container_of(areq, struct mmc_queue_req, mmc_active); + /* + * An asynchronous request has been completed and we proceed + * to handle the result of it. + */ + mq_rq = container_of(old_areq, struct mmc_queue_req, areq); brq = &mq_rq->brq; - req = mq_rq->req; - type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; + old_req = mq_rq->req; + type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; mmc_queue_bounce_post(mq_rq); switch (status) { @@ -1648,28 +1683,32 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) */ mmc_blk_reset_success(md, type); - ret = blk_end_request(req, 0, - brq->data.bytes_xfered); - + req_pending = blk_end_request(old_req, 0, + brq->data.bytes_xfered); /* * If the blk_end_request function returns non-zero even * though all data has been transferred and no errors * were returned by the host controller, it's a bug. */ - if (status == MMC_BLK_SUCCESS && ret) { + if (status == MMC_BLK_SUCCESS && req_pending) { pr_err("%s BUG rq_tot %d d_xfer %d\n", - __func__, blk_rq_bytes(req), + __func__, blk_rq_bytes(old_req), brq->data.bytes_xfered); - rqc = NULL; - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, old_req); + return; } break; case MMC_BLK_CMD_ERR: - ret = mmc_blk_cmd_err(md, card, brq, req, ret); - if (mmc_blk_reset(md, card->host, type)) - goto cmd_abort; - if (!ret) - goto start_new_req; + req_pending = mmc_blk_rw_cmd_err(md, card, brq, old_req, req_pending); + if (mmc_blk_reset(md, card->host, type)) { + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_try_restart(mq, new_req); + return; + } + if (!req_pending) { + mmc_blk_rw_try_restart(mq, new_req); + return; + } break; case MMC_BLK_RETRY: retune_retry_done = brq->retune_retry_done; @@ -1679,22 +1718,27 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) case MMC_BLK_ABORT: if (!mmc_blk_reset(md, card->host, type)) break; - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_try_restart(mq, new_req); + return; case MMC_BLK_DATA_ERR: { int err; err = mmc_blk_reset(md, card->host, type); if (!err) break; - if (err == -ENODEV) - goto cmd_abort; + if (err == -ENODEV) { + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_try_restart(mq, new_req); + return; + } /* Fall through */ } case MMC_BLK_ECC_ERR: if (brq->data.blocks > 1) { /* Redo read one sector at a time */ pr_warn("%s: retrying using single block read\n", - req->rq_disk->disk_name); + old_req->rq_disk->disk_name); disable_multi = 1; break; } @@ -1703,57 +1747,40 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) * time, so we only reach here after trying to * read a single sector. */ - ret = blk_end_request(req, -EIO, - brq->data.blksz); - if (!ret) - goto start_new_req; + req_pending = blk_end_request(old_req, -EIO, + brq->data.blksz); + if (!req_pending) { + mmc_blk_rw_try_restart(mq, new_req); + return; + } break; case MMC_BLK_NOMEDIUM: - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_try_restart(mq, new_req); + return; default: pr_err("%s: Unhandled return value (%d)", - req->rq_disk->disk_name, status); - goto cmd_abort; + old_req->rq_disk->disk_name, status); + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_try_restart(mq, new_req); + return; } - if (ret) { + if (req_pending) { /* * In case of a incomplete request * prepare it again and resend. */ mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq); - mmc_start_req(card->host, - &mq_rq->mmc_active, NULL); + mmc_start_areq(card->host, + &mq_rq->areq, NULL); mq_rq->brq.retune_retry_done = retune_retry_done; } - } while (ret); - - return 1; - - cmd_abort: - if (mmc_card_removed(card)) - req->rq_flags |= RQF_QUIET; - while (ret) - ret = blk_end_request(req, -EIO, - blk_rq_cur_bytes(req)); - - start_new_req: - if (rqc) { - if (mmc_card_removed(card)) { - rqc->rq_flags |= RQF_QUIET; - blk_end_request_all(rqc, -EIO); - } else { - mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); - mmc_start_req(card->host, - &mq->mqrq_cur->mmc_active, NULL); - } - } - - return 0; + } while (req_pending); } -int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) +void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { int ret; struct mmc_blk_data *md = mq->blkdata; @@ -1769,32 +1796,31 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) if (req) { blk_end_request_all(req, -EIO); } - ret = 0; goto out; } - mq->flags &= ~MMC_QUEUE_NEW_REQUEST; + mq->new_request = false; if (req && req_op(req) == REQ_OP_DISCARD) { /* complete ongoing async transfer before issuing discard */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_discard_rq(mq, req); + mmc_blk_issue_discard_rq(mq, req); } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) { /* complete ongoing async transfer before issuing secure erase*/ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_secdiscard_rq(mq, req); + mmc_blk_issue_secdiscard_rq(mq, req); } else if (req && req_op(req) == REQ_OP_FLUSH) { /* complete ongoing async transfer before issuing flush */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_flush(mq, req); + mmc_blk_issue_flush(mq, req); } else { - ret = mmc_blk_issue_rw_rq(mq, req); + mmc_blk_issue_rw_rq(mq, req); } out: - if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || req_is_special) + if ((!req && !mq->new_request) || req_is_special) /* * Release host when there are no more requests * and after special request(discard, flush) is done. @@ -1802,7 +1828,6 @@ out: * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'. */ mmc_put_card(card); - return ret; } static inline int mmc_blk_readonly(struct mmc_card *card) @@ -1821,23 +1846,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct mmc_blk_data *md; int devidx, ret; -again: - if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL)) - return ERR_PTR(-ENOMEM); - - spin_lock(&mmc_blk_lock); - ret = ida_get_new(&mmc_blk_ida, &devidx); - spin_unlock(&mmc_blk_lock); - - if (ret == -EAGAIN) - goto again; - else if (ret) - return ERR_PTR(ret); - - if (devidx >= max_devices) { - ret = -ENOSPC; - goto out; - } + devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL); + if (devidx < 0) + return ERR_PTR(devidx); md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); if (!md) { @@ -1926,9 +1937,7 @@ again: err_kfree: kfree(md); out: - spin_lock(&mmc_blk_lock); - ida_remove(&mmc_blk_ida, devidx); - spin_unlock(&mmc_blk_lock); + ida_simple_remove(&mmc_blk_ida, devidx); return ERR_PTR(ret); } @@ -2093,80 +2102,6 @@ force_ro_fail: return ret; } -static const struct mmc_fixup blk_fixups[] = -{ - MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - - /* - * Some MMC cards experience performance degradation with CMD23 - * instead of CMD12-bounded multiblock transfers. For now we'll - * black list what's bad... - * - Certain Toshiba cards. - * - * N.B. This doesn't affect SD cards. - */ - MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - - /* - * Some MMC cards need longer data read timeout than indicated in CSD. - */ - MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, - MMC_QUIRK_LONG_READ_TIME), - MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_LONG_READ_TIME), - - /* - * On these Samsung MoviNAND parts, performing secure erase or - * secure trim can result in unrecoverable corruption due to a - * firmware bug. - */ - MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - - /* - * On Some Kingston eMMCs, performing trim can result in - * unrecoverable data conrruption occasionally due to a firmware bug. - */ - MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_TRIM_BROKEN), - MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_TRIM_BROKEN), - - END_FIXUP -}; - static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; @@ -2178,7 +2113,7 @@ static int mmc_blk_probe(struct mmc_card *card) if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; - mmc_fixup_device(card, blk_fixups); + mmc_fixup_device(card, mmc_blk_fixups); md = mmc_blk_alloc(card); if (IS_ERR(md)) diff --git a/drivers/mmc/core/block.h b/drivers/mmc/core/block.h index cdabb2ee74be..860ca7c8df86 100644 --- a/drivers/mmc/core/block.h +++ b/drivers/mmc/core/block.h @@ -1 +1,9 @@ -int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req); +#ifndef _MMC_CORE_BLOCK_H +#define _MMC_CORE_BLOCK_H + +struct mmc_queue; +struct request; + +void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req); + +#endif diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index c64266f5a399..301246513a37 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -23,6 +23,8 @@ #include <linux/mmc/host.h> #include "core.h" +#include "card.h" +#include "host.h" #include "sdio_cis.h" #include "bus.h" diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 00a19710b6b4..72b0ef03f10a 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -11,6 +11,11 @@ #ifndef _MMC_CORE_BUS_H #define _MMC_CORE_BUS_H +#include <linux/device.h> + +struct mmc_host; +struct mmc_card; + #define MMC_DEV_ATTR(name, fmt, args...) \ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ @@ -27,5 +32,14 @@ void mmc_remove_card(struct mmc_card *card); int mmc_register_bus(void); void mmc_unregister_bus(void); -#endif +struct mmc_driver { + struct device_driver drv; + int (*probe)(struct mmc_card *card); + void (*remove)(struct mmc_card *card); + void (*shutdown)(struct mmc_card *card); +}; +int mmc_register_driver(struct mmc_driver *drv); +void mmc_unregister_driver(struct mmc_driver *drv); + +#endif diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h new file mode 100644 index 000000000000..f06cd91964ce --- /dev/null +++ b/drivers/mmc/core/card.h @@ -0,0 +1,221 @@ +/* + * Private header for the mmc subsystem + * + * Copyright (C) 2016 Linaro Ltd + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef _MMC_CORE_CARD_H +#define _MMC_CORE_CARD_H + +#include <linux/mmc/card.h> + +#define mmc_card_name(c) ((c)->cid.prod_name) +#define mmc_card_id(c) (dev_name(&(c)->dev)) +#define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev) + +/* Card states */ +#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ +#define MMC_STATE_READONLY (1<<1) /* card is read-only */ +#define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */ +#define MMC_CARD_SDXC (1<<3) /* card is SDXC */ +#define MMC_CARD_REMOVED (1<<4) /* card has been removed */ +#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */ +#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */ + +#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) +#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) +#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) +#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) +#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) +#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS) +#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED) + +#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) +#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) +#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) +#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) +#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) +#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED) +#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED) + +/* + * The world is not perfect and supplies us with broken mmc/sdio devices. + * For at least some of these bugs we need a work-around. + */ +struct mmc_fixup { + /* CID-specific fields. */ + const char *name; + + /* Valid revision range */ + u64 rev_start, rev_end; + + unsigned int manfid; + unsigned short oemid; + + /* SDIO-specific fields. You can use SDIO_ANY_ID here of course */ + u16 cis_vendor, cis_device; + + /* for MMC cards */ + unsigned int ext_csd_rev; + + void (*vendor_fixup)(struct mmc_card *card, int data); + int data; +}; + +#define CID_MANFID_ANY (-1u) +#define CID_OEMID_ANY ((unsigned short) -1) +#define CID_NAME_ANY (NULL) + +#define EXT_CSD_REV_ANY (-1u) + +#define CID_MANFID_SANDISK 0x2 +#define CID_MANFID_TOSHIBA 0x11 +#define CID_MANFID_MICRON 0x13 +#define CID_MANFID_SAMSUNG 0x15 +#define CID_MANFID_KINGSTON 0x70 +#define CID_MANFID_HYNIX 0x90 + +#define END_FIXUP { NULL } + +#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \ + _cis_vendor, _cis_device, \ + _fixup, _data, _ext_csd_rev) \ + { \ + .name = (_name), \ + .manfid = (_manfid), \ + .oemid = (_oemid), \ + .rev_start = (_rev_start), \ + .rev_end = (_rev_end), \ + .cis_vendor = (_cis_vendor), \ + .cis_device = (_cis_device), \ + .vendor_fixup = (_fixup), \ + .data = (_data), \ + .ext_csd_rev = (_ext_csd_rev), \ + } + +#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \ + _fixup, _data, _ext_csd_rev) \ + _FIXUP_EXT(_name, _manfid, \ + _oemid, _rev_start, _rev_end, \ + SDIO_ANY_ID, SDIO_ANY_ID, \ + _fixup, _data, _ext_csd_rev) \ + +#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \ + MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \ + EXT_CSD_REV_ANY) + +#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data, \ + _ext_csd_rev) \ + MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \ + _ext_csd_rev) + +#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \ + _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, \ + CID_OEMID_ANY, 0, -1ull, \ + _vendor, _device, \ + _fixup, _data, EXT_CSD_REV_ANY) \ + +#define cid_rev(hwrev, fwrev, year, month) \ + (((u64) hwrev) << 40 | \ + ((u64) fwrev) << 32 | \ + ((u64) year) << 16 | \ + ((u64) month)) + +#define cid_rev_card(card) \ + cid_rev(card->cid.hwrev, \ + card->cid.fwrev, \ + card->cid.year, \ + card->cid.month) + +/* + * Unconditionally quirk add/remove. + */ +static inline void __maybe_unused add_quirk(struct mmc_card *card, int data) +{ + card->quirks |= data; +} + +static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) +{ + card->quirks &= ~data; +} + +/* + * Quirk add/remove for MMC products. + */ +static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data) +{ + if (mmc_card_mmc(card)) + card->quirks |= data; +} + +static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card, + int data) +{ + if (mmc_card_mmc(card)) + card->quirks &= ~data; +} + +/* + * Quirk add/remove for SD products. + */ +static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data) +{ + if (mmc_card_sd(card)) + card->quirks |= data; +} + +static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card, + int data) +{ + if (mmc_card_sd(card)) + card->quirks &= ~data; +} + +static inline int mmc_card_lenient_fn0(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_LENIENT_FN0; +} + +static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; +} + +static inline int mmc_card_disable_cd(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_DISABLE_CD; +} + +static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF; +} + +static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512; +} + +static inline int mmc_card_long_read_time(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_LONG_READ_TIME; +} + +static inline int mmc_card_broken_irq_polling(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING; +} + +static inline int mmc_card_broken_hpi(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BROKEN_HPI; +} + +#endif diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 1076b9d89df3..926e0fde07d7 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -40,6 +40,7 @@ #include <trace/events/mmc.h> #include "core.h" +#include "card.h" #include "bus.h" #include "host.h" #include "sdio_bus.h" @@ -630,10 +631,41 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, } /** - * mmc_start_req - start a non-blocking request + * mmc_finalize_areq() - finalize an asynchronous request + * @host: MMC host to finalize any ongoing request on + * + * Returns the status of the ongoing asynchronous request, but + * MMC_BLK_SUCCESS if no request was going on. + */ +static enum mmc_blk_status mmc_finalize_areq(struct mmc_host *host) +{ + enum mmc_blk_status status; + + if (!host->areq) + return MMC_BLK_SUCCESS; + + status = mmc_wait_for_data_req_done(host, host->areq->mrq); + if (status == MMC_BLK_NEW_REQUEST) + return status; + + /* + * Check BKOPS urgency for each R1 response + */ + 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)) { + mmc_start_bkops(host->card, true); + } + + return status; +} + +/** + * mmc_start_areq - start an asynchronous request * @host: MMC host to start command - * @areq: async request to start - * @error: out parameter returns 0 for success, otherwise non zero + * @areq: asynchronous request to start + * @ret_stat: out parameter for status * * Start a new MMC custom command request for a host. * If there is on ongoing async request wait for completion @@ -645,11 +677,11 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, * return the completed request. If there is no ongoing request, NULL * is returned without waiting. NULL is not an error condition. */ -struct mmc_async_req *mmc_start_req(struct mmc_host *host, - struct mmc_async_req *areq, - enum mmc_blk_status *ret_stat) +struct mmc_async_req *mmc_start_areq(struct mmc_host *host, + struct mmc_async_req *areq, + enum mmc_blk_status *ret_stat) { - enum mmc_blk_status status = MMC_BLK_SUCCESS; + enum mmc_blk_status status; int start_err = 0; struct mmc_async_req *data = host->areq; @@ -657,44 +689,25 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, if (areq) mmc_pre_req(host, areq->mrq); - if (host->areq) { - status = mmc_wait_for_data_req_done(host, host->areq->mrq); - if (status == MMC_BLK_NEW_REQUEST) { - if (ret_stat) - *ret_stat = status; - /* - * The previous request was not completed, - * nothing to return - */ - return NULL; - } - /* - * Check BKOPS urgency for each R1 response - */ - 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)) { - - /* Cancel the prepared request */ - if (areq) - mmc_post_req(host, areq->mrq, -EINVAL); - - mmc_start_bkops(host->card, true); + /* Finalize previous request */ + status = mmc_finalize_areq(host); - /* prepare the request again */ - if (areq) - mmc_pre_req(host, areq->mrq); - } + /* The previous request is still going on... */ + if (status == MMC_BLK_NEW_REQUEST) { + if (ret_stat) + *ret_stat = status; + return NULL; } + /* Fine so far, start the new request! */ if (status == MMC_BLK_SUCCESS && areq) start_err = __mmc_start_data_req(host, areq->mrq); + /* Postprocess the old request at this point */ if (host->areq) mmc_post_req(host, host->areq->mrq, 0); - /* Cancel a prepared request if it was not started. */ + /* Cancel a prepared request if it was not started. */ if ((status != MMC_BLK_SUCCESS || start_err) && areq) mmc_post_req(host, areq->mrq, -EINVAL); @@ -707,7 +720,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, *ret_stat = status; return data; } -EXPORT_SYMBOL(mmc_start_req); +EXPORT_SYMBOL(mmc_start_areq); /** * mmc_wait_for_req - start a request and wait for completion @@ -807,7 +820,7 @@ EXPORT_SYMBOL(mmc_interrupt_hpi); */ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {}; WARN_ON(!host->claimed); @@ -1630,7 +1643,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) return ocr; } -int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) { int err = 0; int old_signal_voltage = host->ios.signal_voltage; @@ -1646,20 +1659,13 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) } -int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) +int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err = 0; u32 clock; /* - * Send CMD11 only if the request is to switch the card to - * 1.8V signalling. - */ - if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) - return __mmc_set_signal_voltage(host, signal_voltage); - - /* * If we cannot switch voltages, return failure so the caller * can continue without UHS mode */ @@ -1697,7 +1703,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) host->ios.clock = 0; mmc_set_ios(host); - if (__mmc_set_signal_voltage(host, signal_voltage)) { + if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) { /* * Voltages may not have been switched, but we've already * sent CMD11, so a power cycle is required anyway @@ -1806,11 +1812,11 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) 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) + if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); - else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180) == 0) + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); - else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120) == 0) + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); /* @@ -2129,7 +2135,7 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card, static int mmc_do_erase(struct mmc_card *card, unsigned int from, unsigned int to, unsigned int arg) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; unsigned int qty = 0, busy_timeout = 0; bool use_r1b_resp = false; unsigned long timeout; @@ -2551,7 +2557,7 @@ EXPORT_SYMBOL(mmc_calc_max_discard); int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) || mmc_card_hs400(card) || mmc_card_hs400es(card)) @@ -2567,7 +2573,7 @@ EXPORT_SYMBOL(mmc_set_blocklen); int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, bool is_rel_write) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SET_BLOCK_COUNT; cmd.arg = blockcount & 0x0000FFFF; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 0fa86a2afc26..55f543fd37c4 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -12,6 +12,11 @@ #define _MMC_CORE_CORE_H #include <linux/delay.h> +#include <linux/sched.h> + +struct mmc_host; +struct mmc_card; +struct mmc_request; #define MMC_CMD_RETRIES 3 @@ -43,8 +48,8 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz); void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_width(struct mmc_host *host, unsigned int width); u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); -int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr); -int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); +int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr); +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr, @@ -69,6 +74,7 @@ void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); int _mmc_detect_card_removed(struct mmc_host *host); +int mmc_detect_card_removed(struct mmc_host *host); int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); @@ -98,5 +104,38 @@ static inline void mmc_register_pm_notifier(struct mmc_host *host) { } static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { } #endif -#endif +void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq); +bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq); + +int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, + unsigned int arg); +int mmc_can_erase(struct mmc_card *card); +int mmc_can_trim(struct mmc_card *card); +int mmc_can_discard(struct mmc_card *card); +int mmc_can_sanitize(struct mmc_card *card); +int mmc_can_secure_erase_trim(struct mmc_card *card); +int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, + unsigned int nr); +unsigned int mmc_calc_max_discard(struct mmc_card *card); + +int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); +int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, + bool is_rel_write); + +int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); +void mmc_release_host(struct mmc_host *host); +void mmc_get_card(struct mmc_card *card); +void mmc_put_card(struct mmc_card *card); + +/** + * mmc_claim_host - exclusively claim a host + * @host: mmc host to claim + * + * Claim a host for a set of operations. + */ +static inline void mmc_claim_host(struct mmc_host *host) +{ + __mmc_claim_host(host, NULL); +} +#endif diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 30623b8b86a4..a1fba5732d66 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -20,6 +20,8 @@ #include <linux/mmc/host.h> #include "core.h" +#include "card.h" +#include "host.h" #include "mmc_ops.h" #ifdef CONFIG_FAIL_MMC_REQUEST diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 98f25ffb4258..3f8c85d5aa09 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -34,14 +34,11 @@ #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) static DEFINE_IDA(mmc_host_ida); -static DEFINE_SPINLOCK(mmc_host_lock); static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); - spin_lock(&mmc_host_lock); - ida_remove(&mmc_host_ida, host->index); - spin_unlock(&mmc_host_lock); + ida_simple_remove(&mmc_host_ida, host->index); kfree(host); } @@ -301,6 +298,8 @@ int mmc_of_parse(struct mmc_host *host) if (of_property_read_bool(np, "wakeup-source") || of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */ host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + if (of_property_read_bool(np, "mmc-ddr-3_3v")) + host->caps |= MMC_CAP_3_3V_DDR; if (of_property_read_bool(np, "mmc-ddr-1_8v")) host->caps |= MMC_CAP_1_8V_DDR; if (of_property_read_bool(np, "mmc-ddr-1_2v")) @@ -354,22 +353,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) /* scanning will be enabled when we're ready */ host->rescan_disable = 1; -again: - if (!ida_pre_get(&mmc_host_ida, GFP_KERNEL)) { + err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL); + if (err < 0) { kfree(host); return NULL; } - spin_lock(&mmc_host_lock); - err = ida_get_new(&mmc_host_ida, &host->index); - spin_unlock(&mmc_host_lock); - - if (err == -EAGAIN) { - goto again; - } else if (err) { - kfree(host); - return NULL; - } + host->index = err; dev_set_name(&host->class_dev, "mmc%d", host->index); @@ -381,6 +371,8 @@ again: if (mmc_gpio_alloc(host)) { put_device(&host->class_dev); + ida_simple_remove(&mmc_host_ida, host->index); + kfree(host); return NULL; } diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 992bf5397633..fb6a76a03833 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -10,6 +10,7 @@ */ #ifndef _MMC_CORE_HOST_H #define _MMC_CORE_HOST_H + #include <linux/mmc/host.h> int mmc_register_host_class(void); @@ -20,6 +21,53 @@ void mmc_retune_disable(struct mmc_host *host); void mmc_retune_hold(struct mmc_host *host); void mmc_retune_release(struct mmc_host *host); int mmc_retune(struct mmc_host *host); +void mmc_retune_pause(struct mmc_host *host); +void mmc_retune_unpause(struct mmc_host *host); + +static inline void mmc_retune_recheck(struct mmc_host *host) +{ + if (host->hold_retune <= 1) + host->retune_now = 1; +} + +static inline int mmc_host_cmd23(struct mmc_host *host) +{ + return host->caps & MMC_CAP_CMD23; +} + +static inline int mmc_boot_partition_access(struct mmc_host *host) +{ + return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); +} + +static inline int mmc_host_uhs(struct mmc_host *host) +{ + return host->caps & + (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_DDR50); +} + +static inline bool mmc_card_hs200(struct mmc_card *card) +{ + return card->host->ios.timing == MMC_TIMING_MMC_HS200; +} + +static inline bool mmc_card_ddr52(struct mmc_card *card) +{ + return card->host->ios.timing == MMC_TIMING_MMC_DDR52; +} + +static inline bool mmc_card_hs400(struct mmc_card *card) +{ + return card->host->ios.timing == MMC_TIMING_MMC_HS400; +} + +static inline bool mmc_card_hs400es(struct mmc_card *card) +{ + return card->host->ios.enhanced_strobe; +} + #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 0fccca075e29..7fd722868875 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -21,9 +21,11 @@ #include <linux/mmc/mmc.h> #include "core.h" +#include "card.h" #include "host.h" #include "bus.h" #include "mmc_ops.h" +#include "quirks.h" #include "sd_ops.h" #define DEFAULT_CMD6_TIMEOUT_MS 500 @@ -47,17 +49,6 @@ static const unsigned int tacc_mant[] = { 35, 40, 45, 50, 55, 60, 70, 80, }; -static const struct mmc_fixup mmc_ext_csd_fixups[] = { - /* - * Certain Hynix eMMC 4.41 cards might get broken when HPI feature - * is used so disable the HPI feature for such buggy cards. - */ - MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX, - 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5), - - END_FIXUP -}; - #define UNSTUFF_BITS(resp,start,size) \ ({ \ const int __size = size; \ @@ -212,7 +203,7 @@ static void mmc_select_card_type(struct mmc_card *card) avail_type |= EXT_CSD_CARD_TYPE_HS_52; } - if (caps & MMC_CAP_1_8V_DDR && + if (caps & (MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR) && card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) { hs_max_dtr = MMC_HIGH_DDR_MAX_DTR; avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; @@ -307,6 +298,18 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd) } } +static void mmc_part_add(struct mmc_card *card, unsigned int size, + unsigned int part_cfg, char *name, int idx, bool ro, + int area_type) +{ + card->part[card->nr_parts].size = size; + card->part[card->nr_parts].part_cfg = part_cfg; + sprintf(card->part[card->nr_parts].name, name, idx); + card->part[card->nr_parts].force_ro = ro; + card->part[card->nr_parts].area_type = area_type; + card->nr_parts++; +} + static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) { int idx; @@ -530,8 +533,14 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) EXT_CSD_MANUAL_BKOPS_MASK); card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; - if (!card->ext_csd.man_bkops_en) - pr_debug("%s: MAN_BKOPS_EN bit is not set\n", + if (card->ext_csd.man_bkops_en) + pr_debug("%s: MAN_BKOPS_EN bit is set\n", + mmc_hostname(card->host)); + card->ext_csd.auto_bkops_en = + (ext_csd[EXT_CSD_BKOPS_EN] & + EXT_CSD_AUTO_BKOPS_MASK); + if (card->ext_csd.auto_bkops_en) + pr_debug("%s: AUTO_BKOPS_EN bit is set\n", mmc_hostname(card->host)); } @@ -617,6 +626,12 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.ffu_capable = (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) && !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1); + + card->ext_csd.pre_eol_info = ext_csd[EXT_CSD_PRE_EOL_INFO]; + card->ext_csd.device_life_time_est_typ_a = + ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]; + card->ext_csd.device_life_time_est_typ_b = + ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; } /* eMMC v5.1 or later */ @@ -764,6 +779,10 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv); +MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info); +MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n", + card->ext_csd.device_life_time_est_typ_a, + card->ext_csd.device_life_time_est_typ_b); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", card->ext_csd.enhanced_area_offset); @@ -817,6 +836,8 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_name.attr, &dev_attr_oemid.attr, &dev_attr_prv.attr, + &dev_attr_pre_eol_info.attr, + &dev_attr_life_time.attr, &dev_attr_serial.attr, &dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_size.attr, @@ -1095,16 +1116,19 @@ static int mmc_select_hs_ddr(struct mmc_card *card) * * WARNING: eMMC rules are NOT the same as SD DDR */ - err = -EINVAL; - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) { + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + if (!err) + return 0; + } - if (err && (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V && + host->caps & MMC_CAP_1_8V_DDR) + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); /* make sure vccq is 3.3v after switching disaster */ if (err) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); return err; } @@ -1271,10 +1295,10 @@ static int mmc_select_hs400es(struct mmc_card *card) } if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); /* If fails try again during next card power cycle */ if (err) @@ -1380,10 +1404,10 @@ static int mmc_select_hs200(struct mmc_card *card) old_signal_voltage = host->ios.signal_voltage; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); /* If fails try again during next card power cycle */ if (err) @@ -1425,7 +1449,7 @@ static int mmc_select_hs200(struct mmc_card *card) err: if (err) { /* fall back to the old signal voltage, if fails report error */ - if (__mmc_set_signal_voltage(host, old_signal_voltage)) + if (mmc_set_signal_voltage(host, old_signal_voltage)) err = -EIO; pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host), @@ -1805,7 +1829,7 @@ static int mmc_can_sleep(struct mmc_card *card) static int mmc_sleep(struct mmc_host *host) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; struct mmc_card *card = host->card; unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000); int err; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index e6ea8503f40c..fe80f26d6971 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -57,7 +57,7 @@ static const u8 tuning_blk_pattern_8bit[] = { int mmc_send_status(struct mmc_card *card, u32 *status) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SEND_STATUS; if (!mmc_host_is_spi(card->host)) @@ -79,7 +79,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status) static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SELECT_CARD; @@ -115,7 +115,7 @@ int mmc_deselect_cards(struct mmc_host *host) */ int mmc_set_dsr(struct mmc_host *host) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SET_DSR; @@ -128,7 +128,7 @@ int mmc_set_dsr(struct mmc_host *host) int mmc_go_idle(struct mmc_host *host) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; /* * Non-SPI hosts need to prevent chipselect going active during @@ -164,7 +164,7 @@ int mmc_go_idle(struct mmc_host *host) int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int i, err = 0; cmd.opcode = MMC_SEND_OP_COND; @@ -203,7 +203,7 @@ 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 err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; @@ -220,7 +220,7 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) int mmc_set_relative_addr(struct mmc_card *card) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = card->rca << 16; @@ -233,7 +233,7 @@ static int mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = opcode; cmd.arg = arg; @@ -256,9 +256,9 @@ static int mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, u32 opcode, void *buf, unsigned len) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; mrq.cmd = &cmd; @@ -387,7 +387,7 @@ EXPORT_SYMBOL_GPL(mmc_get_ext_csd); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; cmd.opcode = MMC_SPI_READ_OCR; @@ -402,7 +402,7 @@ 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) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; cmd.opcode = MMC_SPI_CRC_ON_OFF; @@ -530,7 +530,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, { struct mmc_host *host = card->host; int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; bool use_r1b_resp = use_busy_signal; unsigned char old_timing = host->ios.timing; @@ -610,9 +610,9 @@ EXPORT_SYMBOL_GPL(mmc_switch); int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; struct mmc_ios *ios = &host->ios; const u8 *tuning_block_pattern; @@ -679,7 +679,7 @@ EXPORT_SYMBOL_GPL(mmc_send_tuning); int mmc_abort_tuning(struct mmc_host *host, u32 opcode) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; /* * eMMC specification specifies that CMD12 can be used to stop a tuning @@ -706,9 +706,9 @@ static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; u8 *data_buf; u8 *test_buf; @@ -802,7 +802,7 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; unsigned int opcode; int err; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index abd525ed74be..74beea8a9c7e 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -12,6 +12,11 @@ #ifndef _MMC_MMC_OPS_H #define _MMC_MMC_OPS_H +#include <linux/types.h> + +struct mmc_host; +struct mmc_card; + int mmc_select_card(struct mmc_card *card); int mmc_deselect_cards(struct mmc_host *host); int mmc_set_dsr(struct mmc_host *host); @@ -26,12 +31,21 @@ 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_interrupt_hpi(struct mmc_card *card); int mmc_can_ext_csd(struct mmc_card *card); +int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); int mmc_switch_status(struct mmc_card *card); int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal); int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, unsigned char timing, bool use_busy_signal, bool send_status, bool retry_crc_err); +int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, + unsigned int timeout_ms); +int mmc_stop_bkops(struct mmc_card *card); +int mmc_read_bkops_status(struct mmc_card *card); +void mmc_start_bkops(struct mmc_card *card, bool from_exception); +int mmc_can_reset(struct mmc_card *card); +int mmc_flush_cache(struct mmc_card *card); #endif diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 3ab6e52d106c..f99ac3123fd2 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -22,6 +22,11 @@ #include <linux/seq_file.h> #include <linux/module.h> +#include "core.h" +#include "card.h" +#include "host.h" +#include "bus.h" + #define RESULT_OK 0 #define RESULT_FAIL 1 #define RESULT_UNSUP_HOST 2 @@ -260,7 +265,7 @@ static int mmc_test_busy(struct mmc_command *cmd) static int mmc_test_wait_busy(struct mmc_test_card *test) { int ret, busy; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; busy = 0; do { @@ -277,8 +282,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) if (!busy && mmc_test_busy(&cmd)) { busy = 1; if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) - pr_info("%s: Warning: Host did not " - "wait for busy state to end.\n", + pr_info("%s: Warning: Host did not wait for busy state to end.\n", mmc_hostname(test->card->host)); } } while (mmc_test_busy(&cmd)); @@ -292,10 +296,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) static int mmc_test_buffer_transfer(struct mmc_test_card *test, u8 *buffer, unsigned addr, unsigned blksz, int write) { - struct mmc_request mrq = {0}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_command stop = {}; + struct mmc_data data = {}; struct scatterlist sg; @@ -357,12 +361,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, if (max_segs > max_page_cnt) max_segs = max_page_cnt; - mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL); + mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) return NULL; - mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs, - GFP_KERNEL); + mem->arr = kcalloc(max_segs, sizeof(*mem->arr), GFP_KERNEL); if (!mem->arr) goto out_free; @@ -546,7 +549,7 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test, if (!test->gr) return; - tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL); + tr = kmalloc(sizeof(*tr), GFP_KERNEL); if (!tr) return; @@ -641,11 +644,11 @@ static int __mmc_test_prepare(struct mmc_test_card *test, int write) if (write) memset(test->buffer, 0xDF, 512); else { - for (i = 0;i < 512;i++) + for (i = 0; i < 512; i++) test->buffer[i] = i; } - for (i = 0;i < BUFFER_SIZE / 512;i++) { + for (i = 0; i < BUFFER_SIZE / 512; i++) { ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1); if (ret) return ret; @@ -674,7 +677,7 @@ static int mmc_test_cleanup(struct mmc_test_card *test) memset(test->buffer, 0, 512); - for (i = 0;i < BUFFER_SIZE / 512;i++) { + for (i = 0; i < BUFFER_SIZE / 512; i++) { ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1); if (ret) return ret; @@ -850,7 +853,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, for (i = 0; i < count; i++) { mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr, blocks, blksz, write); - done_areq = mmc_start_req(test->card->host, cur_areq, &status); + done_areq = mmc_start_areq(test->card->host, cur_areq, &status); if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) { ret = RESULT_FAIL; @@ -869,7 +872,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, dev_addr += blocks; } - done_areq = mmc_start_req(test->card->host, NULL, &status); + done_areq = mmc_start_areq(test->card->host, NULL, &status); if (status != MMC_BLK_SUCCESS) ret = RESULT_FAIL; @@ -885,10 +888,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test, struct scatterlist *sg, unsigned sg_len, unsigned dev_addr, unsigned blocks, unsigned blksz, int write) { - struct mmc_request mrq = {0}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_command stop = {}; + struct mmc_data data = {}; mrq.cmd = &cmd; mrq.data = &data; @@ -910,10 +913,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test, static int mmc_test_broken_transfer(struct mmc_test_card *test, unsigned blocks, unsigned blksz, int write) { - struct mmc_request mrq = {0}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_command stop = {}; + struct mmc_data data = {}; struct scatterlist sg; @@ -946,7 +949,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, unsigned long flags; if (write) { - for (i = 0;i < blocks * blksz;i++) + for (i = 0; i < blocks * blksz; i++) test->scratch[i] = i; } else { memset(test->scratch, 0, BUFFER_SIZE); @@ -980,7 +983,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, memset(test->buffer, 0, sectors * 512); - for (i = 0;i < sectors;i++) { + for (i = 0; i < sectors; i++) { ret = mmc_test_buffer_transfer(test, test->buffer + i * 512, dev_addr + i, 512, 0); @@ -988,12 +991,12 @@ static int mmc_test_transfer(struct mmc_test_card *test, return ret; } - for (i = 0;i < blocks * blksz;i++) { + for (i = 0; i < blocks * blksz; i++) { if (test->buffer[i] != (u8)i) return RESULT_FAIL; } - for (;i < sectors * 512;i++) { + for (; i < sectors * 512; i++) { if (test->buffer[i] != 0xDF) return RESULT_FAIL; } @@ -1001,7 +1004,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, local_irq_save(flags); sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); local_irq_restore(flags); - for (i = 0;i < blocks * blksz;i++) { + for (i = 0; i < blocks * blksz; i++) { if (test->scratch[i] != (u8)i) return RESULT_FAIL; } @@ -1086,7 +1089,7 @@ static int mmc_test_multi_write(struct mmc_test_card *test) sg_init_one(&sg, test->buffer, size); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); } static int mmc_test_multi_read(struct mmc_test_card *test) @@ -1107,7 +1110,7 @@ static int mmc_test_multi_read(struct mmc_test_card *test) sg_init_one(&sg, test->buffer, size); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); } static int mmc_test_pow2_write(struct mmc_test_card *test) @@ -1118,7 +1121,7 @@ static int mmc_test_pow2_write(struct mmc_test_card *test) if (!test->card->csd.write_partial) return RESULT_UNSUP_CARD; - for (i = 1; i < 512;i <<= 1) { + for (i = 1; i < 512; i <<= 1) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1); if (ret) @@ -1136,7 +1139,7 @@ static int mmc_test_pow2_read(struct mmc_test_card *test) if (!test->card->csd.read_partial) return RESULT_UNSUP_CARD; - for (i = 1; i < 512;i <<= 1) { + for (i = 1; i < 512; i <<= 1) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0); if (ret) @@ -1154,7 +1157,7 @@ static int mmc_test_weird_write(struct mmc_test_card *test) if (!test->card->csd.write_partial) return RESULT_UNSUP_CARD; - for (i = 3; i < 512;i += 7) { + for (i = 3; i < 512; i += 7) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1); if (ret) @@ -1172,7 +1175,7 @@ static int mmc_test_weird_read(struct mmc_test_card *test) if (!test->card->csd.read_partial) return RESULT_UNSUP_CARD; - for (i = 3; i < 512;i += 7) { + for (i = 3; i < 512; i += 7) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0); if (ret) @@ -1231,7 +1234,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test) for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, size); - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); + ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); if (ret) return ret; } @@ -1258,7 +1261,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test) for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, size); - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); + ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); if (ret) return ret; } @@ -1357,7 +1360,7 @@ static int mmc_test_multi_write_high(struct mmc_test_card *test) sg_init_table(&sg, 1); sg_set_page(&sg, test->highmem, size, 0); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); } static int mmc_test_multi_read_high(struct mmc_test_card *test) @@ -1379,7 +1382,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test) sg_init_table(&sg, 1); sg_set_page(&sg, test->highmem, size, 0); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); } #else @@ -1533,7 +1536,7 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test) /* * Initialize an area for testing large transfers. The test area is set to the - * middle of the card because cards may have different charateristics at the + * middle of the card because cards may have different characteristics at the * front (for FAT file system optimization). Optionally, the area is erased * (if the card supports it) which may improve write performance. Optionally, * the area is filled with data for subsequent read tests. @@ -1579,7 +1582,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) if (!t->mem) return -ENOMEM; - t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL); + t->sg = kmalloc_array(t->max_segs, sizeof(*t->sg), GFP_KERNEL); if (!t->sg) { ret = -ENOMEM; goto out_free; @@ -2147,7 +2150,7 @@ static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test, int i; for (i = 0 ; i < rw->len && ret == 0; i++) { - ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size, + ret = mmc_test_rw_multiple(test, rw, 512 * 1024, rw->size, rw->sg_len[i]); if (ret) break; @@ -2399,7 +2402,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, /* Start ongoing data request */ if (use_areq) { - mmc_start_req(host, &test_areq.areq, &blkstat); + mmc_start_areq(host, &test_areq.areq, &blkstat); if (blkstat != MMC_BLK_SUCCESS) { ret = RESULT_FAIL; goto out_free; @@ -2437,7 +2440,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, /* Wait for data request to complete */ if (use_areq) { - mmc_start_req(host, NULL, &blkstat); + mmc_start_areq(host, NULL, &blkstat); if (blkstat != MMC_BLK_SUCCESS) ret = RESULT_FAIL; } else { @@ -2954,7 +2957,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) mmc_claim_host(test->card->host); - for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { + for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) { struct mmc_test_general_result *gr; if (testcase && ((i + 1) != testcase)) @@ -2967,16 +2970,14 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) if (mmc_test_cases[i].prepare) { ret = mmc_test_cases[i].prepare(test); if (ret) { - pr_info("%s: Result: Prepare " - "stage failed! (%d)\n", + pr_info("%s: Result: Prepare stage failed! (%d)\n", mmc_hostname(test->card->host), ret); continue; } } - gr = kzalloc(sizeof(struct mmc_test_general_result), - GFP_KERNEL); + gr = kzalloc(sizeof(*gr), GFP_KERNEL); if (gr) { INIT_LIST_HEAD(&gr->tr_lst); @@ -3005,13 +3006,11 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) mmc_hostname(test->card->host)); break; case RESULT_UNSUP_HOST: - pr_info("%s: Result: UNSUPPORTED " - "(by host)\n", + pr_info("%s: Result: UNSUPPORTED (by host)\n", mmc_hostname(test->card->host)); break; case RESULT_UNSUP_CARD: - pr_info("%s: Result: UNSUPPORTED " - "(by card)\n", + pr_info("%s: Result: UNSUPPORTED (by card)\n", mmc_hostname(test->card->host)); break; default: @@ -3026,8 +3025,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) if (mmc_test_cases[i].cleanup) { ret = mmc_test_cases[i].cleanup(test); if (ret) { - pr_info("%s: Warning: Cleanup " - "stage failed! (%d)\n", + pr_info("%s: Warning: Cleanup stage failed! (%d)\n", mmc_hostname(test->card->host), ret); } @@ -3113,7 +3111,7 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf, if (ret) return ret; - test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); + test = kzalloc(sizeof(*test), GFP_KERNEL); if (!test) return -ENOMEM; @@ -3163,9 +3161,9 @@ static int mtf_testlist_show(struct seq_file *sf, void *data) mutex_lock(&mmc_test_lock); - seq_printf(sf, "0:\tRun all tests\n"); + seq_puts(sf, "0:\tRun all tests\n"); for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) - seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name); + seq_printf(sf, "%d:\t%s\n", i + 1, mmc_test_cases[i].name); mutex_unlock(&mmc_test_lock); @@ -3218,7 +3216,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card, return -ENODEV; } - df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL); + df = kmalloc(sizeof(*df), GFP_KERNEL); if (!df) { debugfs_remove(file); dev_err(&card->dev, diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h index d69e751f148b..39c911aa6ebb 100644 --- a/drivers/mmc/core/pwrseq.h +++ b/drivers/mmc/core/pwrseq.h @@ -8,7 +8,11 @@ #ifndef _MMC_CORE_PWRSEQ_H #define _MMC_CORE_PWRSEQ_H -#include <linux/mmc/host.h> +#include <linux/types.h> + +struct mmc_host; +struct device; +struct module; struct mmc_pwrseq_ops { void (*pre_power_on)(struct mmc_host *host); diff --git a/drivers/mmc/core/pwrseq_sd8787.c b/drivers/mmc/core/pwrseq_sd8787.c new file mode 100644 index 000000000000..1a21e14458d3 --- /dev/null +++ b/drivers/mmc/core/pwrseq_sd8787.c @@ -0,0 +1,117 @@ +/* + * pwrseq_sd8787.c - power sequence support for Marvell SD8787 BT + Wifi chip + * + * Copyright (C) 2016 Matt Ranostay <matt@ranostay.consulting> + * + * Based on the original work pwrseq_simple.c + * Copyright (C) 2014 Linaro Ltd + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> + +#include <linux/mmc/host.h> + +#include "pwrseq.h" + +struct mmc_pwrseq_sd8787 { + struct mmc_pwrseq pwrseq; + struct gpio_desc *reset_gpio; + struct gpio_desc *pwrdn_gpio; +}; + +#define to_pwrseq_sd8787(p) container_of(p, struct mmc_pwrseq_sd8787, pwrseq) + +static void mmc_pwrseq_sd8787_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq); + + gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); + + msleep(300); + gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1); +} + +static void mmc_pwrseq_sd8787_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq); + + gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 0); + gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); +} + +static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = { + .pre_power_on = mmc_pwrseq_sd8787_pre_power_on, + .power_off = mmc_pwrseq_sd8787_power_off, +}; + +static const struct of_device_id mmc_pwrseq_sd8787_of_match[] = { + { .compatible = "mmc-pwrseq-sd8787",}, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, mmc_pwrseq_sd8787_of_match); + +static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev) +{ + struct mmc_pwrseq_sd8787 *pwrseq; + struct device *dev = &pdev->dev; + + pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); + if (!pwrseq) + return -ENOMEM; + + pwrseq->pwrdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW); + if (IS_ERR(pwrseq->pwrdn_gpio)) + return PTR_ERR(pwrseq->pwrdn_gpio); + + pwrseq->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(pwrseq->reset_gpio)) + return PTR_ERR(pwrseq->reset_gpio); + + pwrseq->pwrseq.dev = dev; + pwrseq->pwrseq.ops = &mmc_pwrseq_sd8787_ops; + pwrseq->pwrseq.owner = THIS_MODULE; + platform_set_drvdata(pdev, pwrseq); + + return mmc_pwrseq_register(&pwrseq->pwrseq); +} + +static int mmc_pwrseq_sd8787_remove(struct platform_device *pdev) +{ + struct mmc_pwrseq_sd8787 *pwrseq = platform_get_drvdata(pdev); + + mmc_pwrseq_unregister(&pwrseq->pwrseq); + + return 0; +} + +static struct platform_driver mmc_pwrseq_sd8787_driver = { + .probe = mmc_pwrseq_sd8787_probe, + .remove = mmc_pwrseq_sd8787_remove, + .driver = { + .name = "pwrseq_sd8787", + .of_match_table = mmc_pwrseq_sd8787_of_match, + }, +}; + +module_platform_driver(mmc_pwrseq_sd8787_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 033f641eb8b7..493eb10ce580 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -20,6 +20,8 @@ #include "queue.h" #include "block.h" +#include "core.h" +#include "card.h" #define MMC_QUEUE_BOUNCESZ 65536 @@ -75,8 +77,8 @@ static int mmc_queue_thread(void *d) set_current_state(TASK_RUNNING); mmc_blk_issue_rq(mq, req); cond_resched(); - if (mq->flags & MMC_QUEUE_NEW_REQUEST) { - mq->flags &= ~MMC_QUEUE_NEW_REQUEST; + if (mq->new_request) { + mq->new_request = false; continue; /* fetch again */ } @@ -143,7 +145,7 @@ static struct scatterlist *mmc_alloc_sg(int sg_len, int *err) { struct scatterlist *sg; - sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL); + sg = kmalloc_array(sg_len, sizeof(*sg), GFP_KERNEL); if (!sg) *err = -ENOMEM; else { @@ -390,8 +392,8 @@ void mmc_queue_suspend(struct mmc_queue *mq) struct request_queue *q = mq->queue; unsigned long flags; - if (!(mq->flags & MMC_QUEUE_SUSPENDED)) { - mq->flags |= MMC_QUEUE_SUSPENDED; + if (!mq->suspended) { + mq->suspended |= true; spin_lock_irqsave(q->queue_lock, flags); blk_stop_queue(q); @@ -410,8 +412,8 @@ void mmc_queue_resume(struct mmc_queue *mq) struct request_queue *q = mq->queue; unsigned long flags; - if (mq->flags & MMC_QUEUE_SUSPENDED) { - mq->flags &= ~MMC_QUEUE_SUSPENDED; + if (mq->suspended) { + mq->suspended = false; up(&mq->thread_sem); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index dac8c3d010dd..e298f100101b 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -1,6 +1,11 @@ #ifndef MMC_QUEUE_H #define MMC_QUEUE_H +#include <linux/types.h> +#include <linux/blkdev.h> +#include <linux/mmc/core.h> +#include <linux/mmc/host.h> + static inline bool mmc_req_is_special(struct request *req) { return req && @@ -9,7 +14,6 @@ static inline bool mmc_req_is_special(struct request *req) req_op(req) == REQ_OP_SECURE_ERASE); } -struct request; struct task_struct; struct mmc_blk_data; @@ -29,16 +33,15 @@ struct mmc_queue_req { char *bounce_buf; struct scatterlist *bounce_sg; unsigned int bounce_sg_len; - struct mmc_async_req mmc_active; + struct mmc_async_req areq; }; struct mmc_queue { struct mmc_card *card; struct task_struct *thread; struct semaphore thread_sem; - unsigned int flags; -#define MMC_QUEUE_SUSPENDED (1 << 0) -#define MMC_QUEUE_NEW_REQUEST (1 << 1) + bool new_request; + bool suspended; bool asleep; struct mmc_blk_data *blkdata; struct request_queue *queue; diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c deleted file mode 100644 index ca9cade317c7..000000000000 --- a/drivers/mmc/core/quirks.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file contains work-arounds for many known SD/MMC - * and SDIO hardware bugs. - * - * Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com> - * Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com> - * Inspired from pci fixup code: - * Copyright (c) 1999 Martin Mares <mj@ucw.cz> - * - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/export.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sdio_ids.h> - -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI 0x0097 -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1271 -#define SDIO_DEVICE_ID_TI_WL1271 0x4076 -#endif - -#ifndef SDIO_VENDOR_ID_STE -#define SDIO_VENDOR_ID_STE 0x0020 -#endif - -#ifndef SDIO_DEVICE_ID_STE_CW1200 -#define SDIO_DEVICE_ID_STE_CW1200 0x2280 -#endif - -#ifndef SDIO_DEVICE_ID_MARVELL_8797_F0 -#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 -#endif - -static const struct mmc_fixup mmc_fixup_methods[] = { - SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, - add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), - - SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, - add_quirk, MMC_QUIRK_DISABLE_CD), - - SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200, - add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512), - - SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0, - add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING), - - END_FIXUP -}; - -void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) -{ - const struct mmc_fixup *f; - u64 rev = cid_rev_card(card); - - /* Non-core specific workarounds. */ - if (!table) - table = mmc_fixup_methods; - - for (f = table; f->vendor_fixup; f++) { - if ((f->manfid == CID_MANFID_ANY || - f->manfid == card->cid.manfid) && - (f->oemid == CID_OEMID_ANY || - f->oemid == card->cid.oemid) && - (f->name == CID_NAME_ANY || - !strncmp(f->name, card->cid.prod_name, - sizeof(card->cid.prod_name))) && - (f->cis_vendor == card->cis.vendor || - f->cis_vendor == (u16) SDIO_ANY_ID) && - (f->cis_device == card->cis.device || - f->cis_device == (u16) SDIO_ANY_ID) && - (f->ext_csd_rev == EXT_CSD_REV_ANY || - f->ext_csd_rev == card->ext_csd.rev) && - rev >= f->rev_start && rev <= f->rev_end) { - dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup); - f->vendor_fixup(card, f->data); - } - } -} -EXPORT_SYMBOL(mmc_fixup_device); diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h new file mode 100644 index 000000000000..fb725934fa21 --- /dev/null +++ b/drivers/mmc/core/quirks.h @@ -0,0 +1,148 @@ +/* + * This file contains work-arounds for many known SD/MMC + * and SDIO hardware bugs. + * + * Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com> + * Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com> + * Inspired from pci fixup code: + * Copyright (c) 1999 Martin Mares <mj@ucw.cz> + * + */ + +#include <linux/mmc/sdio_ids.h> + +#include "card.h" + +static const struct mmc_fixup mmc_blk_fixups[] = { +#define INAND_CMD38_ARG_EXT_CSD 113 +#define INAND_CMD38_ARG_ERASE 0x00 +#define INAND_CMD38_ARG_TRIM 0x01 +#define INAND_CMD38_ARG_SECERASE 0x80 +#define INAND_CMD38_ARG_SECTRIM1 0x81 +#define INAND_CMD38_ARG_SECTRIM2 0x88 + /* CMD38 argument is passed through EXT_CSD[113] */ + MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + + /* + * Some MMC cards experience performance degradation with CMD23 + * instead of CMD12-bounded multiblock transfers. For now we'll + * black list what's bad... + * - Certain Toshiba cards. + * + * N.B. This doesn't affect SD cards. + */ + MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + + /* + * Some MMC cards need longer data read timeout than indicated in CSD. + */ + MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, + MMC_QUIRK_LONG_READ_TIME), + MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_LONG_READ_TIME), + + /* + * On these Samsung MoviNAND parts, performing secure erase or + * secure trim can result in unrecoverable corruption due to a + * firmware bug. + */ + MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + + /* + * On Some Kingston eMMCs, performing trim can result in + * unrecoverable data conrruption occasionally due to a firmware bug. + */ + MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_TRIM_BROKEN), + MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_TRIM_BROKEN), + + END_FIXUP +}; + +static const struct mmc_fixup mmc_ext_csd_fixups[] = { + /* + * Certain Hynix eMMC 4.41 cards might get broken when HPI feature + * is used so disable the HPI feature for such buggy cards. + */ + MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX, + 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5), + + END_FIXUP +}; + +static const struct mmc_fixup sdio_fixup_methods[] = { + SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, + add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), + + SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, + add_quirk, MMC_QUIRK_DISABLE_CD), + + SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200, + add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512), + + SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0, + add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING), + + END_FIXUP +}; + +static inline void mmc_fixup_device(struct mmc_card *card, + const struct mmc_fixup *table) +{ + const struct mmc_fixup *f; + u64 rev = cid_rev_card(card); + + for (f = table; f->vendor_fixup; f++) { + if ((f->manfid == CID_MANFID_ANY || + f->manfid == card->cid.manfid) && + (f->oemid == CID_OEMID_ANY || + f->oemid == card->cid.oemid) && + (f->name == CID_NAME_ANY || + !strncmp(f->name, card->cid.prod_name, + sizeof(card->cid.prod_name))) && + (f->cis_vendor == card->cis.vendor || + f->cis_vendor == (u16) SDIO_ANY_ID) && + (f->cis_device == card->cis.device || + f->cis_device == (u16) SDIO_ANY_ID) && + (f->ext_csd_rev == EXT_CSD_REV_ANY || + f->ext_csd_rev == card->ext_csd.rev) && + rev >= f->rev_start && rev <= f->rev_end) { + dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup); + f->vendor_fixup(card, f->data); + } + } +} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index a614f37faf27..89531b48ae84 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -22,6 +22,8 @@ #include <linux/mmc/sd.h> #include "core.h" +#include "card.h" +#include "host.h" #include "bus.h" #include "mmc_ops.h" #include "sd.h" @@ -786,8 +788,7 @@ try_again: */ if (!mmc_host_is_spi(host) && rocr && ((*rocr & 0x41000000) == 0x41000000)) { - err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - pocr); + err = mmc_set_uhs_voltage(host, pocr); if (err == -EAGAIN) { retries--; goto try_again; diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h index aab824a9a7f3..1ada9808c329 100644 --- a/drivers/mmc/core/sd.h +++ b/drivers/mmc/core/sd.h @@ -1,10 +1,13 @@ #ifndef _MMC_CORE_SD_H #define _MMC_CORE_SD_H -#include <linux/mmc/card.h> +#include <linux/types.h> extern struct device_type sd_type; +struct mmc_host; +struct mmc_card; + int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr); int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card); void mmc_decode_cid(struct mmc_card *card); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index de125a41aa7a..9d5824a37586 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -25,7 +25,7 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; if (WARN_ON(card && card->host != host)) return -EINVAL; @@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd); int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {}; int i, err; @@ -120,7 +120,7 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd); int mmc_app_set_bus_width(struct mmc_card *card, int width) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; @@ -141,7 +141,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int i, err = 0; cmd.opcode = SD_APP_OP_COND; @@ -185,7 +185,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) int mmc_send_if_cond(struct mmc_host *host, u32 ocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; static const u8 test_pattern = 0xAA; u8 result_pattern; @@ -217,7 +217,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; @@ -235,9 +235,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) int mmc_app_send_scr(struct mmc_card *card, u32 *scr) { int err; - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; void *data_buf; @@ -290,9 +290,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; /* NOTE: caller guarantees resp is heap-allocated */ @@ -332,9 +332,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, int mmc_app_sd_status(struct mmc_card *card, void *ssr) { int err; - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; /* NOTE: caller guarantees ssr is heap-allocated */ diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h index ffc2305d905f..784f8e6b6baa 100644 --- a/drivers/mmc/core/sd_ops.h +++ b/drivers/mmc/core/sd_ops.h @@ -12,6 +12,12 @@ #ifndef _MMC_SD_OPS_H #define _MMC_SD_OPS_H +#include <linux/types.h> + +struct mmc_card; +struct mmc_host; +struct mmc_command; + int mmc_app_set_bus_width(struct mmc_card *card, int width); int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_send_if_cond(struct mmc_host *host, u32 ocr); @@ -20,6 +26,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr); int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp); int mmc_app_sd_status(struct mmc_card *card, void *ssr); +int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card); +int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, + struct mmc_command *cmd, int retries); #endif diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ecbc52981ba5..fae732c870a9 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -20,7 +20,10 @@ #include <linux/mmc/sdio_ids.h> #include "core.h" +#include "card.h" +#include "host.h" #include "bus.h" +#include "quirks.h" #include "sd.h" #include "sdio_bus.h" #include "mmc_ops.h" @@ -541,6 +544,15 @@ out: return err; } +static void mmc_sdio_resend_if_cond(struct mmc_host *host, + struct mmc_card *card) +{ + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->ocr_avail); + mmc_remove_card(card); +} + /* * Handle the detection and initialisation of a card. * @@ -624,24 +636,21 @@ try_again: * to switch to 1.8V signaling level. No 1.8v signalling if * UHS mode is not enabled to maintain compatibility and some * systems that claim 1.8v signalling in fact do not support - * it. + * it. Per SDIO spec v3, section 3.1.2, if the voltage is already + * 1.8v, the card sets S18A to 0 in the R4 response. So it will + * fails to check rocr & R4_18V_PRESENT, but we still need to + * try to init uhs card. sdio_read_cccr will take over this task + * to make sure which speed mode should work. */ if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { - err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - ocr_card); + err = mmc_set_uhs_voltage(host, ocr_card); if (err == -EAGAIN) { - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->ocr_avail); - mmc_remove_card(card); + mmc_sdio_resend_if_cond(host, card); retries--; goto try_again; } else if (err) { ocr &= ~R4_18V_PRESENT; } - err = 0; - } else { - ocr &= ~R4_18V_PRESENT; } /* @@ -698,11 +707,20 @@ try_again: } /* - * Read the common registers. + * Read the common registers. Note that we should try to + * validate whether UHS would work or not. */ err = sdio_read_cccr(card, ocr); - if (err) - goto remove; + if (err) { + mmc_sdio_resend_if_cond(host, card); + if (ocr & R4_18V_PRESENT) { + /* Retry init sequence, but without R4_18V_PRESENT. */ + retries = 0; + goto try_again; + } else { + goto remove; + } + } /* * Read the common CIS tuples. @@ -721,7 +739,7 @@ try_again: card = oldcard; } card->ocr = ocr_card; - mmc_fixup_device(card, NULL); + mmc_fixup_device(card, sdio_fixup_methods); if (card->type == MMC_TYPE_SD_COMBO) { err = mmc_sd_setup_card(host, card, oldcard != NULL); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 86f5b3223aae..e992a7f8a16f 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -25,6 +25,7 @@ #include <linux/of.h> #include "core.h" +#include "card.h" #include "sdio_cis.h" #include "sdio_bus.h" diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h index 567a76821ba7..b69a2540a076 100644 --- a/drivers/mmc/core/sdio_bus.h +++ b/drivers/mmc/core/sdio_bus.h @@ -11,6 +11,9 @@ #ifndef _MMC_CORE_SDIO_BUS_H #define _MMC_CORE_SDIO_BUS_H +struct mmc_card; +struct sdio_func; + struct sdio_func *sdio_alloc_func(struct mmc_card *card); int sdio_add_func(struct sdio_func *func); void sdio_remove_func(struct sdio_func *func); diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h index 4d903c2e425e..16aa563faa00 100644 --- a/drivers/mmc/core/sdio_cis.h +++ b/drivers/mmc/core/sdio_cis.h @@ -14,6 +14,9 @@ #ifndef _MMC_SDIO_CIS_H #define _MMC_SDIO_CIS_H +struct mmc_card; +struct sdio_func; + int sdio_read_common_cis(struct mmc_card *card); void sdio_free_common_cis(struct mmc_card *card); diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 406e5f037e32..74195d772f5a 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -16,6 +16,8 @@ #include <linux/mmc/sdio_func.h> #include "sdio_ops.h" +#include "core.h" +#include "card.h" /** * sdio_claim_host - exclusively claim a bus for a certain SDIO function diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index f1faf9acc007..d29faf2addfe 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -27,6 +27,8 @@ #include <linux/mmc/sdio_func.h> #include "sdio_ops.h" +#include "core.h" +#include "card.h" static int process_sdio_pending_irqs(struct mmc_host *host) { diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 90fe5545c677..3c0d3ab4324c 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -21,7 +21,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int i, err = 0; cmd.opcode = SD_IO_SEND_OP_COND; @@ -66,7 +66,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn, unsigned addr, u8 in, u8 *out) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; if (fn > 7) @@ -118,9 +118,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg, *sg_ptr; struct sg_table sgtable; unsigned int nents, left_size, i; diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index 5660c7f459e9..bed8a8377fec 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -12,14 +12,19 @@ #ifndef _MMC_SDIO_OPS_H #define _MMC_SDIO_OPS_H +#include <linux/types.h> #include <linux/mmc/sdio.h> +struct mmc_host; +struct mmc_card; + int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); int sdio_reset(struct mmc_host *host); +unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz); static inline bool mmc_is_io_op(u32 opcode) { diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index babe591aea96..a8450a8701e4 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -235,9 +235,6 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, struct gpio_desc *desc; int ret; - if (!con_id) - con_id = ctx->cd_label; - desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -289,9 +286,6 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, struct gpio_desc *desc; int ret; - if (!con_id) - con_id = ctx->ro_label; - desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN); if (IS_ERR(desc)) return PTR_ERR(desc); diff --git a/drivers/mmc/core/slot-gpio.h b/drivers/mmc/core/slot-gpio.h index 8c1854dc5d58..a06fd843f025 100644 --- a/drivers/mmc/core/slot-gpio.h +++ b/drivers/mmc/core/slot-gpio.h @@ -8,6 +8,8 @@ #ifndef _MMC_CORE_SLOTGPIO_H #define _MMC_CORE_SLOTGPIO_H +struct mmc_host; + int mmc_gpio_alloc(struct mmc_host *host); #endif |