From 103da0667d4b7cdbc667666bd0e64899f3801033 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Thu, 31 Mar 2022 00:09:07 +0300 Subject: mmc: core: block: fix sloppy typing in mmc_blk_ioctl_multi_cmd() Despite mmc_ioc_multi_cmd::num_of_cmds is a 64-bit field, its maximum value is limited to MMC_IOC_MAX_CMDS (only 255); using a 64-bit local variable to hold a copy of that field leads to gcc generating ineffective loop code: despite the source code using an *int* variable for the loop counters, the 32-bit object code uses 64-bit unsigned counters. Also, gcc has to drop the most significant word of that 64-bit variable when calling kcalloc() and assigning to mmc_queue_req::ioc_count anyway. Using the *unsigned int* variable instead results in a better code. Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Signed-off-by: Sergey Shtylyov Link: https://lore.kernel.org/r/eea3b0bd-6091-f005-7189-b5b7868abdb6@omp.ru Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 506dc900f5c7..b35e7a95798b 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -676,8 +676,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 +691,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 +727,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]); } -- cgit v1.2.3-59-g8ed1b From 9723f69d1de37ca25474372ad1753ea39bb0dce1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 8 Apr 2022 10:00:43 +0200 Subject: mmc: core: improve API to make clear that mmc_sw_reset is for cards To make it unambiguous that mmc_sw_reset() is for cards and not for controllers, we make the function argument mmc_card instead of mmc_host. There are no users to convert currently. Suggested-by: Ulf Hansson Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20220408080045.6497-3-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 3 ++- include/linux/mmc/core.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c6ae16d40766..06a9bc97be2a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2017,8 +2017,9 @@ int mmc_hw_reset(struct mmc_card *card) } EXPORT_SYMBOL(mmc_hw_reset); -int mmc_sw_reset(struct mmc_host *host) +int mmc_sw_reset(struct mmc_card *card) { + struct mmc_host *host = card->host; int ret; if (!host->bus_ops->sw_reset) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index de5c64bbdb72..6efec0b9820c 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -176,7 +176,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries); int mmc_hw_reset(struct mmc_card *card); -int mmc_sw_reset(struct mmc_host *host); +int mmc_sw_reset(struct mmc_card *card); void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card); #endif /* LINUX_MMC_CORE_H */ -- cgit v1.2.3-59-g8ed1b From 32f18e596141f40dbc5d8700b2730371ffd3055f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 8 Apr 2022 10:00:44 +0200 Subject: mmc: improve API to make clear hw_reset callback is for cards To make it unambiguous that the hw_reset callback is for cards and not for controllers, we add 'card' to the callback name and convert all users in one go. We keep the argument as mmc_host, though, because the callback is used very early when mmc_card is not yet populated. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20220408080045.6497-4-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 4 ++-- drivers/mmc/core/mmc.c | 4 ++-- drivers/mmc/host/bcm2835.c | 2 +- drivers/mmc/host/dw_mmc.c | 2 +- drivers/mmc/host/meson-mx-sdhc-mmc.c | 2 +- drivers/mmc/host/mtk-sd.c | 2 +- drivers/mmc/host/sdhci.c | 2 +- drivers/mmc/host/sunxi-mmc.c | 2 +- drivers/mmc/host/uniphier-sd.c | 2 +- include/linux/mmc/host.h | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 06a9bc97be2a..4b70cbfc6d5d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1988,9 +1988,9 @@ static void mmc_hw_reset_for_init(struct mmc_host *host) { mmc_pwrseq_reset(host); - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) + if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->card_hw_reset) return; - host->ops->hw_reset(host); + host->ops->card_hw_reset(host); } /** diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index e7ea45386c22..5d8d9f72476f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2225,11 +2225,11 @@ static int _mmc_hw_reset(struct mmc_host *host) */ _mmc_flush_cache(host); - if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset && + if ((host->caps & MMC_CAP_HW_RESET) && host->ops->card_hw_reset && mmc_can_reset(card)) { /* If the card accept RST_n signal, send it. */ mmc_set_clock(host, host->f_init); - host->ops->hw_reset(host); + host->ops->card_hw_reset(host); /* Set initial state and call mmc_set_ios */ mmc_set_initial_state(host); } else { diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 463b707d9e99..641ab4f42125 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1259,7 +1259,7 @@ static void bcm2835_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static const struct mmc_host_ops bcm2835_ops = { .request = bcm2835_request, .set_ios = bcm2835_set_ios, - .hw_reset = bcm2835_reset, + .card_hw_reset = bcm2835_reset, }; static int bcm2835_add_host(struct bcm2835_host *host) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 06dc56cbada8..581614196a84 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1812,7 +1812,7 @@ static const struct mmc_host_ops dw_mci_ops = { .set_ios = dw_mci_set_ios, .get_ro = dw_mci_get_ro, .get_cd = dw_mci_get_cd, - .hw_reset = dw_mci_hw_reset, + .card_hw_reset = dw_mci_hw_reset, .enable_sdio_irq = dw_mci_enable_sdio_irq, .ack_sdio_irq = dw_mci_ack_sdio_irq, .execute_tuning = dw_mci_execute_tuning, diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index 28aa78aa08f3..e92e63cb5641 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -511,7 +511,7 @@ static int meson_mx_sdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) } static const struct mmc_host_ops meson_mx_sdhc_ops = { - .hw_reset = meson_mx_sdhc_hw_reset, + .card_hw_reset = meson_mx_sdhc_hw_reset, .request = meson_mx_sdhc_request, .set_ios = meson_mx_sdhc_set_ios, .card_busy = meson_mx_sdhc_card_busy, diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index e61b0b98065a..195dc897188b 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -2458,7 +2458,7 @@ static const struct mmc_host_ops mt_msdc_ops = { .execute_tuning = msdc_execute_tuning, .prepare_hs400_tuning = msdc_prepare_hs400_tuning, .execute_hs400_tuning = msdc_execute_hs400_tuning, - .hw_reset = msdc_hw_reset, + .card_hw_reset = msdc_hw_reset, }; static const struct cqhci_host_ops msdc_cmdq_ops = { diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 07c6da1f2f0f..22152029e14c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2999,7 +2999,7 @@ static const struct mmc_host_ops sdhci_ops = { .set_ios = sdhci_set_ios, .get_cd = sdhci_get_cd, .get_ro = sdhci_get_ro, - .hw_reset = sdhci_hw_reset, + .card_hw_reset = sdhci_hw_reset, .enable_sdio_irq = sdhci_enable_sdio_irq, .ack_sdio_irq = sdhci_ack_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index c62afd212692..0e8fbf4957d8 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1115,7 +1115,7 @@ static const struct mmc_host_ops sunxi_mmc_ops = { .get_cd = mmc_gpio_get_cd, .enable_sdio_irq = sunxi_mmc_enable_sdio_irq, .start_signal_voltage_switch = sunxi_mmc_volt_switch, - .hw_reset = sunxi_mmc_hw_reset, + .card_hw_reset = sunxi_mmc_hw_reset, .card_busy = sunxi_mmc_card_busy, }; diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c index ccbf9885a52b..3a8defdcca77 100644 --- a/drivers/mmc/host/uniphier-sd.c +++ b/drivers/mmc/host/uniphier-sd.c @@ -597,7 +597,7 @@ static int uniphier_sd_probe(struct platform_device *pdev) ret = PTR_ERR(priv->rst_hw); goto free_host; } - host->ops.hw_reset = uniphier_sd_hw_reset; + host->ops.card_hw_reset = uniphier_sd_hw_reset; } if (host->mmc->caps & MMC_CAP_UHS) { diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 7afb57cab00b..c193c50ccd78 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -181,7 +181,7 @@ struct mmc_host_ops { unsigned int max_dtr, int host_drv, int card_drv, int *drv_type); /* Reset the eMMC card via RST_n */ - void (*hw_reset)(struct mmc_host *host); + void (*card_hw_reset)(struct mmc_host *host); void (*card_event)(struct mmc_host *host); /* -- cgit v1.2.3-59-g8ed1b From 23e09be254f95a5b75cd87f91a4014f3b46dda3f Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Sun, 24 Apr 2022 00:16:23 +0200 Subject: mmc: core: Allows to override the timeout value for ioctl() path Occasionally, user-land applications initiate longer timeout values for certain commands through ioctl() system call. But so far we are still using a fixed timeout of 10 seconds in mmc_poll_for_busy() on the ioctl() path, even if a custom timeout is specified in the userspace application. This patch allows custom timeout values to override this default timeout values on the ioctl path. Cc: stable Signed-off-by: Bean Huo Acked-by: Avri Altman Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220423221623.1074556-3-huobean@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index b35e7a95798b..6cb701aa1abc 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -609,11 +609,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; -- cgit v1.2.3-59-g8ed1b From ac9d25557dcc9fe90ed12bfbb6db401e892ca004 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 25 Apr 2022 22:54:42 +0200 Subject: mmc: core: Add CIDs for cards to the entropy pool To make the entropy pool a bit better we can toss in the CID for eMMC and SD cards into it, usually the serial number portion is at least unique. This does not count as improvement of the entropy but in practice it makes it a bit more random to mix in these numbers. Cc: Theodore Ts'o Acked-by: Jason A. Donenfeld Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20220425205442.1347837-1-linus.walleij@linaro.org Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 7 +++++++ drivers/mmc/core/sd.c | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 82ca62c8669c..89cd48fcec79 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,12 @@ static int mmc_decode_cid(struct mmc_card *card) { u32 *resp = card->raw_cid; + /* + * Add the raw card ID (cid) data to the entropy pool. It doesn't + * matter that not all of it is unique, it's just bonus entropy. + */ + add_device_randomness(&card->raw_cid, sizeof(card->raw_cid)); + /* * The selection of the format here is based upon published * specs from sandisk and from what people have reported. diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 68df6b2f49cc..c5f1df6ce4c0 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,12 @@ void mmc_decode_cid(struct mmc_card *card) { u32 *resp = card->raw_cid; + /* + * Add the raw card ID (cid) data to the entropy pool. It doesn't + * matter that not all of it is unique, it's just bonus entropy. + */ + add_device_randomness(&card->raw_cid, sizeof(card->raw_cid)); + /* * SD doesn't currently have a version field so we will * have to assume we can parse this. -- cgit v1.2.3-59-g8ed1b From 0e8bb6666e3dcf18e4920a325028647da71eb500 Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Mon, 25 Apr 2022 10:53:39 +0000 Subject: mmc: core: use kobj_to_dev() Use kobj_to_dev() instead of open-coding it. Reported-by: Zeal Robot Signed-off-by: Minghao Chi Link: https://lore.kernel.org/r/20220425105339.3515368-1-chi.minghao@zte.com.cn Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 6cb701aa1abc..9def975df52b 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -330,7 +330,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; -- cgit v1.2.3-59-g8ed1b From f7b6fc327327698924ef3afa0c3e87a5b7466af3 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Fri, 29 Apr 2022 17:21:18 +0200 Subject: mmc: core: Support zeroout using TRIM for eMMC If an eMMC card supports TRIM and indicates that it erases to zeros, we can use it to support hardware offloading of REQ_OP_WRITE_ZEROES, so let's add support for this. Signed-off-by: Vincent Whitchurch Reviewed-by: Avri Altman Link: https://lore.kernel.org/r/20220429152118.3617303-1-vincent.whitchurch@axis.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 26 ++++++++++++++++++++++---- drivers/mmc/core/queue.c | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/core') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 9def975df52b..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 @@ -1092,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)) { @@ -1113,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; @@ -1129,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) { @@ -2329,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; diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index c69b2d9df6f1..bbe2ea829ea7 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -191,6 +191,8 @@ static void mmc_queue_setup_discard(struct request_queue *q, q->limits.discard_granularity = SECTOR_SIZE; if (mmc_can_secure_erase_trim(card)) blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); + if (mmc_can_trim(card) && card->erased_byte == 0) + blk_queue_max_write_zeroes_sectors(q, max_discard); } static unsigned short mmc_get_max_segments(struct mmc_host *host) -- cgit v1.2.3-59-g8ed1b