diff options
Diffstat (limited to 'drivers/mmc/core/block.c')
-rw-r--r-- | drivers/mmc/core/block.c | 100 |
1 files changed, 79 insertions, 21 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 4e67c1403cc9..1259ca22d625 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -126,6 +126,7 @@ struct mmc_blk_data { #define MMC_BLK_DISCARD BIT(2) #define MMC_BLK_SECDISCARD BIT(3) #define MMC_BLK_CQE_RECOVERY BIT(4) +#define MMC_BLK_TRIM BIT(5) /* * Only set in main mmc_blk_data associated @@ -330,7 +331,7 @@ static struct attribute *mmc_disk_attrs[] = { static umode_t mmc_disk_attrs_is_visible(struct kobject *kobj, struct attribute *a, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); umode_t mode = a->mode; @@ -609,11 +610,11 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, if (idata->rpmb || (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { /* - * Ensure RPMB/R1B command has completed by polling CMD13 - * "Send Status". + * Ensure RPMB/R1B command has completed by polling CMD13 "Send Status". Here we + * allow to override the default timeout value if a custom timeout is specified. */ - err = mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, false, - MMC_BUSY_IO); + err = mmc_poll_for_busy(card, idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS, + false, MMC_BUSY_IO); } return err; @@ -676,8 +677,9 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, struct mmc_ioc_cmd __user *cmds = user->cmds; struct mmc_card *card; struct mmc_queue *mq; - int i, err = 0, ioc_err = 0; + int err = 0, ioc_err = 0; __u64 num_of_cmds; + unsigned int i, n; struct request *req; if (copy_from_user(&num_of_cmds, &user->num_of_cmds, @@ -690,15 +692,16 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, if (num_of_cmds > MMC_IOC_MAX_CMDS) return -EINVAL; - idata = kcalloc(num_of_cmds, sizeof(*idata), GFP_KERNEL); + n = num_of_cmds; + idata = kcalloc(n, sizeof(*idata), GFP_KERNEL); if (!idata) return -ENOMEM; - for (i = 0; i < num_of_cmds; i++) { + for (i = 0; i < n; i++) { idata[i] = mmc_blk_ioctl_copy_from_user(&cmds[i]); if (IS_ERR(idata[i])) { err = PTR_ERR(idata[i]); - num_of_cmds = i; + n = i; goto cmd_err; } /* This will be NULL on non-RPMB ioctl():s */ @@ -725,18 +728,18 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, req_to_mmc_queue_req(req)->drv_op = rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idata; - req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; + req_to_mmc_queue_req(req)->ioc_count = n; blk_execute_rq(req, false); ioc_err = req_to_mmc_queue_req(req)->drv_op_result; /* copy to user if data and response */ - for (i = 0; i < num_of_cmds && !err; i++) + for (i = 0; i < n && !err; i++) err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]); blk_mq_free_request(req); cmd_err: - for (i = 0; i < num_of_cmds; i++) { + for (i = 0; i < n; i++) { kfree(idata[i]->buf); kfree(idata[i]); } @@ -993,7 +996,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, return -EEXIST; md->reset_done |= type; - err = mmc_hw_reset(host); + err = mmc_hw_reset(host->card); /* Ensure we switch back to the correct partition */ if (err) { struct mmc_blk_data *main_md = @@ -1090,12 +1093,13 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) blk_mq_end_request(req, ret ? BLK_STS_IOERR : BLK_STS_OK); } -static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) +static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req, + int type, unsigned int erase_arg) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; unsigned int from, nr; - int err = 0, type = MMC_BLK_DISCARD; + int err = 0; blk_status_t status = BLK_STS_OK; if (!mmc_can_erase(card)) { @@ -1111,13 +1115,13 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) if (card->quirks & MMC_QUIRK_INAND_CMD38) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, INAND_CMD38_ARG_EXT_CSD, - card->erase_arg == MMC_TRIM_ARG ? + erase_arg == MMC_TRIM_ARG ? INAND_CMD38_ARG_TRIM : INAND_CMD38_ARG_ERASE, card->ext_csd.generic_cmd6_time); } if (!err) - err = mmc_erase(card, from, nr, card->erase_arg); + err = mmc_erase(card, from, nr, erase_arg); } while (err == -EIO && !mmc_blk_reset(md, card->host, type)); if (err) status = BLK_STS_IOERR; @@ -1127,6 +1131,19 @@ fail: blk_mq_end_request(req, status); } +static void mmc_blk_issue_trim_rq(struct mmc_queue *mq, struct request *req) +{ + mmc_blk_issue_erase_rq(mq, req, MMC_BLK_TRIM, MMC_TRIM_ARG); +} + +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; + + mmc_blk_issue_erase_rq(mq, req, MMC_BLK_DISCARD, card->erase_arg); +} + static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, struct request *req) { @@ -1880,6 +1897,31 @@ static inline bool mmc_blk_rq_error(struct mmc_blk_request *brq) brq->data.error || brq->cmd.resp[0] & CMD_ERRORS; } +static int mmc_spi_err_check(struct mmc_card *card) +{ + u32 status = 0; + int err; + + /* + * SPI does not have a TRAN state we have to wait on, instead the + * card is ready again when it no longer holds the line LOW. + * We still have to ensure two things here before we know the write + * was successful: + * 1. The card has not disconnected during busy and we actually read our + * own pull-up, thinking it was still connected, so ensure it + * still responds. + * 2. Check for any error bits, in particular R1_SPI_IDLE to catch a + * just reconnected card after being disconnected during busy. + */ + err = __mmc_send_status(card, &status, 0); + if (err) + return err; + /* All R1 and R2 bits of SPI are errors in our case */ + if (status) + return -EIO; + return 0; +} + static int mmc_blk_busy_cb(void *cb_data, bool *busy) { struct mmc_blk_busy_data *data = cb_data; @@ -1903,9 +1945,16 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req) struct mmc_blk_busy_data cb_data; int err; - if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ) + if (rq_data_dir(req) == READ) return 0; + if (mmc_host_is_spi(card->host)) { + err = mmc_spi_err_check(card); + if (err) + mqrq->brq.data.bytes_xfered = 0; + return err; + } + cb_data.card = card; cb_data.status = 0; err = __mmc_poll_for_busy(card->host, 0, MMC_BLK_TIMEOUT_MS, @@ -2295,6 +2344,9 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req) case REQ_OP_SECURE_ERASE: mmc_blk_issue_secdiscard_rq(mq, req); break; + case REQ_OP_WRITE_ZEROES: + mmc_blk_issue_trim_rq(mq, req); + break; case REQ_OP_FLUSH: mmc_blk_issue_flush(mq, req); break; @@ -2350,6 +2402,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct mmc_blk_data *md; int devidx, ret; char cap_str[10]; + bool cache_enabled = false; + bool fua_enabled = false; devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL); if (devidx < 0) { @@ -2429,13 +2483,17 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->flags |= MMC_BLK_CMD23; } - if (mmc_card_mmc(card) && - md->flags & MMC_BLK_CMD23 && + if (md->flags & MMC_BLK_CMD23 && ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) || card->ext_csd.rel_sectors)) { md->flags |= MMC_BLK_REL_WR; - blk_queue_write_cache(md->queue.queue, true, true); + fua_enabled = true; + cache_enabled = true; } + if (mmc_cache_enabled(card->host)) + cache_enabled = true; + + blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled); string_get_size((u64)size, 512, STRING_UNITS_2, cap_str, sizeof(cap_str)); |