From 6335d68349a85382cc55a5260d5bfda85f8e24a8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 26 Mar 2017 20:41:32 +0200 Subject: mmc: core: add mmc_get_dma_dir Add function for determining DMA direction to core. Signed-off-by: Heiner Kallweit Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- include/linux/mmc/host.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 83f1c4a9f03b..21385ac0c9b1 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -17,6 +17,7 @@ #include #include #include +#include struct mmc_ios { unsigned int clock; /* clock rate */ @@ -499,6 +500,11 @@ static inline bool mmc_can_retune(struct mmc_host *host) return host->can_retune == 1; } +static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) +{ + return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE; +} + int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_abort_tuning(struct mmc_host *host, u32 opcode); -- cgit v1.2.3 From 7b410d074b253a44624497a18e73f666a9574f37 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 13 Mar 2017 14:36:36 +0200 Subject: mmc: queue: Share mmc request array between partitions eMMC can have multiple internal partitions that are represented as separate disks / queues. However switching between partitions is only done when the queue is empty. Consequently the array of mmc requests that are queued can be shared between partitions saving memory. Keep a pointer to the mmc request queue on the card, and use that instead of allocating a new one for each partition. Signed-off-by: Adrian Hunter Reviewed-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 11 ++- drivers/mmc/core/queue.c | 234 ++++++++++++++++++++++++++++------------------- drivers/mmc/core/queue.h | 2 + include/linux/mmc/card.h | 5 + 4 files changed, 156 insertions(+), 96 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 16c313a62129..018488e7f194 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2123,6 +2123,7 @@ static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; char cap_str[10]; + int ret; /* * Check that the card supports the command class(es) we need. @@ -2132,9 +2133,15 @@ static int mmc_blk_probe(struct mmc_card *card) mmc_fixup_device(card, mmc_blk_fixups); + ret = mmc_queue_alloc_shared_queue(card); + if (ret) + return ret; + md = mmc_blk_alloc(card); - if (IS_ERR(md)) + if (IS_ERR(md)) { + mmc_queue_free_shared_queue(card); return PTR_ERR(md); + } string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2, cap_str, sizeof(cap_str)); @@ -2172,6 +2179,7 @@ static int mmc_blk_probe(struct mmc_card *card) out: mmc_blk_remove_parts(card, md); mmc_blk_remove_req(md); + mmc_queue_free_shared_queue(card); return 0; } @@ -2189,6 +2197,7 @@ static void mmc_blk_remove(struct mmc_card *card) pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); dev_set_drvdata(&card->dev, NULL); + mmc_queue_free_shared_queue(card); } static int _mmc_blk_suspend(struct mmc_card *card) diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 4a2045527b62..3423b7acf744 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -149,17 +149,13 @@ static void mmc_request_fn(struct request_queue *q) wake_up_process(mq->thread); } -static struct scatterlist *mmc_alloc_sg(int sg_len, int *err) +static struct scatterlist *mmc_alloc_sg(int sg_len) { struct scatterlist *sg; sg = kmalloc_array(sg_len, sizeof(*sg), GFP_KERNEL); - if (!sg) - *err = -ENOMEM; - else { - *err = 0; + if (sg) sg_init_table(sg, sg_len); - } return sg; } @@ -185,6 +181,32 @@ static void mmc_queue_setup_discard(struct request_queue *q, queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q); } +static void mmc_queue_req_free_bufs(struct mmc_queue_req *mqrq) +{ + kfree(mqrq->bounce_sg); + mqrq->bounce_sg = NULL; + + kfree(mqrq->sg); + mqrq->sg = NULL; + + kfree(mqrq->bounce_buf); + mqrq->bounce_buf = NULL; +} + +static void mmc_queue_reqs_free_bufs(struct mmc_queue_req *mqrq, int qdepth) +{ + int i; + + for (i = 0; i < qdepth; i++) + mmc_queue_req_free_bufs(&mqrq[i]); +} + +static void mmc_queue_free_mqrqs(struct mmc_queue_req *mqrq, int qdepth) +{ + mmc_queue_reqs_free_bufs(mqrq, qdepth); + kfree(mqrq); +} + static struct mmc_queue_req *mmc_queue_alloc_mqrqs(int qdepth) { struct mmc_queue_req *mqrq; @@ -200,79 +222,137 @@ static struct mmc_queue_req *mmc_queue_alloc_mqrqs(int qdepth) } #ifdef CONFIG_MMC_BLOCK_BOUNCE -static bool mmc_queue_alloc_bounce_bufs(struct mmc_queue *mq, - unsigned int bouncesz) +static int mmc_queue_alloc_bounce_bufs(struct mmc_queue_req *mqrq, int qdepth, + unsigned int bouncesz) { int i; - for (i = 0; i < mq->qdepth; i++) { - mq->mqrq[i].bounce_buf = kmalloc(bouncesz, GFP_KERNEL); - if (!mq->mqrq[i].bounce_buf) - goto out_err; - } + for (i = 0; i < qdepth; i++) { + mqrq[i].bounce_buf = kmalloc(bouncesz, GFP_KERNEL); + if (!mqrq[i].bounce_buf) + return -ENOMEM; - return true; + mqrq[i].sg = mmc_alloc_sg(1); + if (!mqrq[i].sg) + return -ENOMEM; -out_err: - while (--i >= 0) { - kfree(mq->mqrq[i].bounce_buf); - mq->mqrq[i].bounce_buf = NULL; + mqrq[i].bounce_sg = mmc_alloc_sg(bouncesz / 512); + if (!mqrq[i].bounce_sg) + return -ENOMEM; } - pr_warn("%s: unable to allocate bounce buffers\n", - mmc_card_name(mq->card)); - return false; + + return 0; } -static int mmc_queue_alloc_bounce_sgs(struct mmc_queue *mq, - unsigned int bouncesz) +static bool mmc_queue_alloc_bounce(struct mmc_queue_req *mqrq, int qdepth, + unsigned int bouncesz) { - int i, ret; + int ret; - for (i = 0; i < mq->qdepth; i++) { - mq->mqrq[i].sg = mmc_alloc_sg(1, &ret); - if (ret) - return ret; + ret = mmc_queue_alloc_bounce_bufs(mqrq, qdepth, bouncesz); + if (ret) + mmc_queue_reqs_free_bufs(mqrq, qdepth); - mq->mqrq[i].bounce_sg = mmc_alloc_sg(bouncesz / 512, &ret); - if (ret) - return ret; - } + return !ret; +} + +static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host) +{ + unsigned int bouncesz = MMC_QUEUE_BOUNCESZ; + + if (host->max_segs != 1) + return 0; + + if (bouncesz > host->max_req_size) + bouncesz = host->max_req_size; + if (bouncesz > host->max_seg_size) + bouncesz = host->max_seg_size; + if (bouncesz > host->max_blk_count * 512) + bouncesz = host->max_blk_count * 512; + + if (bouncesz <= 512) + return 0; + + return bouncesz; +} +#else +static inline bool mmc_queue_alloc_bounce(struct mmc_queue_req *mqrq, + int qdepth, unsigned int bouncesz) +{ + return false; +} +static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host) +{ return 0; } #endif -static int mmc_queue_alloc_sgs(struct mmc_queue *mq, int max_segs) +static int mmc_queue_alloc_sgs(struct mmc_queue_req *mqrq, int qdepth, + int max_segs) { - int i, ret; + int i; - for (i = 0; i < mq->qdepth; i++) { - mq->mqrq[i].sg = mmc_alloc_sg(max_segs, &ret); - if (ret) - return ret; + for (i = 0; i < qdepth; i++) { + mqrq[i].sg = mmc_alloc_sg(max_segs); + if (!mqrq[i].sg) + return -ENOMEM; } return 0; } -static void mmc_queue_req_free_bufs(struct mmc_queue_req *mqrq) +void mmc_queue_free_shared_queue(struct mmc_card *card) { - kfree(mqrq->bounce_sg); - mqrq->bounce_sg = NULL; + if (card->mqrq) { + mmc_queue_free_mqrqs(card->mqrq, card->qdepth); + card->mqrq = NULL; + } +} - kfree(mqrq->sg); - mqrq->sg = NULL; +static int __mmc_queue_alloc_shared_queue(struct mmc_card *card, int qdepth) +{ + struct mmc_host *host = card->host; + struct mmc_queue_req *mqrq; + unsigned int bouncesz; + int ret = 0; - kfree(mqrq->bounce_buf); - mqrq->bounce_buf = NULL; + if (card->mqrq) + return -EINVAL; + + mqrq = mmc_queue_alloc_mqrqs(qdepth); + if (!mqrq) + return -ENOMEM; + + card->mqrq = mqrq; + card->qdepth = qdepth; + + bouncesz = mmc_queue_calc_bouncesz(host); + + if (bouncesz && !mmc_queue_alloc_bounce(mqrq, qdepth, bouncesz)) { + bouncesz = 0; + pr_warn("%s: unable to allocate bounce buffers\n", + mmc_card_name(card)); + } + + card->bouncesz = bouncesz; + + if (!bouncesz) { + ret = mmc_queue_alloc_sgs(mqrq, qdepth, host->max_segs); + if (ret) + goto out_err; + } + + return ret; + +out_err: + mmc_queue_free_shared_queue(card); + return ret; } -static void mmc_queue_reqs_free_bufs(struct mmc_queue *mq) +int mmc_queue_alloc_shared_queue(struct mmc_card *card) { - int i; - - for (i = 0; i < mq->qdepth; i++) - mmc_queue_req_free_bufs(&mq->mqrq[i]); + return __mmc_queue_alloc_shared_queue(card, 2); } /** @@ -289,7 +369,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; - bool bounce = false; int ret = -ENOMEM; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) @@ -300,10 +379,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (!mq->queue) return -ENOMEM; - mq->qdepth = 2; - mq->mqrq = mmc_queue_alloc_mqrqs(mq->qdepth); - if (!mq->mqrq) - goto blk_cleanup; + mq->mqrq = card->mqrq; + mq->qdepth = card->qdepth; mq->queue->queuedata = mq; blk_queue_prep_rq(mq->queue, mmc_prep_request); @@ -312,44 +389,17 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (mmc_can_erase(card)) mmc_queue_setup_discard(mq->queue, card); -#ifdef CONFIG_MMC_BLOCK_BOUNCE - if (host->max_segs == 1) { - unsigned int bouncesz; - - bouncesz = MMC_QUEUE_BOUNCESZ; - - if (bouncesz > host->max_req_size) - bouncesz = host->max_req_size; - if (bouncesz > host->max_seg_size) - bouncesz = host->max_seg_size; - if (bouncesz > (host->max_blk_count * 512)) - bouncesz = host->max_blk_count * 512; - - if (bouncesz > 512 && - mmc_queue_alloc_bounce_bufs(mq, bouncesz)) { - blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); - blk_queue_max_hw_sectors(mq->queue, bouncesz / 512); - blk_queue_max_segments(mq->queue, bouncesz / 512); - blk_queue_max_segment_size(mq->queue, bouncesz); - - ret = mmc_queue_alloc_bounce_sgs(mq, bouncesz); - if (ret) - goto cleanup_queue; - bounce = true; - } - } -#endif - - if (!bounce) { + if (card->bouncesz) { + blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); + blk_queue_max_hw_sectors(mq->queue, card->bouncesz / 512); + blk_queue_max_segments(mq->queue, card->bouncesz / 512); + blk_queue_max_segment_size(mq->queue, card->bouncesz); + } else { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_hw_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_segments(mq->queue, host->max_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); - - ret = mmc_queue_alloc_sgs(mq, host->max_segs); - if (ret) - goto cleanup_queue; } sema_init(&mq->thread_sem, 1); @@ -364,11 +414,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, return 0; - cleanup_queue: - mmc_queue_reqs_free_bufs(mq); - kfree(mq->mqrq); +cleanup_queue: mq->mqrq = NULL; -blk_cleanup: blk_cleanup_queue(mq->queue); return ret; } @@ -390,10 +437,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq) blk_start_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); - mmc_queue_reqs_free_bufs(mq); - kfree(mq->mqrq); mq->mqrq = NULL; - mq->card = NULL; } EXPORT_SYMBOL(mmc_cleanup_queue); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 967808df45b8..871796c3f406 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -51,6 +51,8 @@ struct mmc_queue { unsigned long qslots; }; +extern int mmc_queue_alloc_shared_queue(struct mmc_card *card); +extern void mmc_queue_free_shared_queue(struct mmc_card *card); extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *, const char *); extern void mmc_cleanup_queue(struct mmc_queue *); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 77e61e0a216a..119ef8f0155c 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -208,6 +208,7 @@ struct sdio_cis { struct mmc_host; struct sdio_func; struct sdio_func_tuple; +struct mmc_queue_req; #define SDIO_MAX_FUNCS 7 @@ -300,6 +301,10 @@ struct mmc_card { struct dentry *debugfs_root; struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */ unsigned int nr_parts; + + struct mmc_queue_req *mqrq; /* Shared queue structure */ + unsigned int bouncesz; /* Bounce buffer size */ + int qdepth; /* Shared queue depth */ }; static inline bool mmc_large_sector(struct mmc_card *card) -- cgit v1.2.3 From b658af718465cd1e8011c8da281befdfc2debefd Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 13 Mar 2017 14:36:37 +0200 Subject: mmc: mmc: Add functions to enable / disable the Command Queue Add helper functions to enable or disable the Command Queue. Signed-off-by: Adrian Hunter Reviewed-by: Linus Walleij Signed-off-by: Ulf Hansson --- Documentation/mmc/mmc-dev-attrs.txt | 1 + drivers/mmc/core/mmc.c | 2 ++ drivers/mmc/core/mmc_ops.c | 28 ++++++++++++++++++++++++++++ drivers/mmc/core/mmc_ops.h | 2 ++ include/linux/mmc/card.h | 1 + 5 files changed, 34 insertions(+) (limited to 'include/linux') diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt index 404a0e9e92b0..dcd1252877fb 100644 --- a/Documentation/mmc/mmc-dev-attrs.txt +++ b/Documentation/mmc/mmc-dev-attrs.txt @@ -30,6 +30,7 @@ All attributes are read-only. rel_sectors Reliable write sector count ocr Operation Conditions Register dsr Driver Stage Register + cmdq_en Command Queue enabled: 1 => enabled, 0 => not enabled Note on Erase Size and Preferred Erase Size: diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b502601df228..35b2d0f767ca 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -790,6 +790,7 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); MMC_DEV_ATTR(ocr, "%08x\n", card->ocr); +MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en); static ssize_t mmc_fwrev_show(struct device *dev, struct device_attribute *attr, @@ -845,6 +846,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_rel_sectors.attr, &dev_attr_ocr.attr, &dev_attr_dsr.attr, + &dev_attr_cmdq_en.attr, NULL, }; ATTRIBUTE_GROUPS(mmc_std); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index fe80f26d6971..24c58d24c19a 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -838,3 +838,31 @@ int mmc_can_ext_csd(struct mmc_card *card) { return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3); } + +static int mmc_cmdq_switch(struct mmc_card *card, bool enable) +{ + u8 val = enable ? EXT_CSD_CMDQ_MODE_ENABLED : 0; + int err; + + if (!card->ext_csd.cmdq_support) + return -EOPNOTSUPP; + + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CMDQ_MODE_EN, + val, card->ext_csd.generic_cmd6_time); + if (!err) + card->ext_csd.cmdq_en = enable; + + return err; +} + +int mmc_cmdq_enable(struct mmc_card *card) +{ + return mmc_cmdq_switch(card, true); +} +EXPORT_SYMBOL_GPL(mmc_cmdq_enable); + +int mmc_cmdq_disable(struct mmc_card *card) +{ + return mmc_cmdq_switch(card, false); +} +EXPORT_SYMBOL_GPL(mmc_cmdq_disable); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 74beea8a9c7e..978bd2e60f8a 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -46,6 +46,8 @@ 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); +int mmc_cmdq_enable(struct mmc_card *card); +int mmc_cmdq_disable(struct mmc_card *card); #endif diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 119ef8f0155c..94637796b99c 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -89,6 +89,7 @@ struct mmc_ext_csd { unsigned int boot_ro_lock; /* ro lock support */ bool boot_ro_lockable; bool ffu_capable; /* Firmware upgrade support */ + bool cmdq_en; /* Command Queue enabled */ bool cmdq_support; /* Command Queue supported */ unsigned int cmdq_depth; /* Command Queue depth */ #define MMC_FIRMWARE_LEN 8 -- cgit v1.2.3 From 9d4579a85c84340044b10ffa6cd576397f59dc93 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 13 Mar 2017 14:36:38 +0200 Subject: mmc: mmc_test: Disable Command Queue while mmc_test is used Normal read and write commands may not be used while the command queue is enabled. Disable the Command Queue when mmc_test is probed and re-enable it when it is removed. Signed-off-by: Adrian Hunter Reviewed-by: Harjani Ritesh Reviewed-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 7 +++++++ drivers/mmc/core/mmc_test.c | 14 ++++++++++++++ include/linux/mmc/card.h | 2 ++ 3 files changed, 23 insertions(+) (limited to 'include/linux') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 35b2d0f767ca..2c87dede5841 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1789,6 +1789,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } + /* + * In some cases (e.g. RPMB or mmc_test), the Command Queue must be + * disabled for a time, so a flag is needed to indicate to re-enable the + * Command Queue. + */ + card->reenable_cmdq = card->ext_csd.cmdq_en; + /* * The mandatory minimum values are defined for packed command. * read: 5, write: 3 diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index f99ac3123fd2..fd1b4b8510b9 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -26,6 +26,7 @@ #include "card.h" #include "host.h" #include "bus.h" +#include "mmc_ops.h" #define RESULT_OK 0 #define RESULT_FAIL 1 @@ -3264,6 +3265,14 @@ static int mmc_test_probe(struct mmc_card *card) if (ret) return ret; + if (card->ext_csd.cmdq_en) { + mmc_claim_host(card->host); + ret = mmc_cmdq_disable(card); + mmc_release_host(card->host); + if (ret) + return ret; + } + dev_info(&card->dev, "Card claimed for testing.\n"); return 0; @@ -3271,6 +3280,11 @@ static int mmc_test_probe(struct mmc_card *card) static void mmc_test_remove(struct mmc_card *card) { + if (card->reenable_cmdq) { + mmc_claim_host(card->host); + mmc_cmdq_enable(card); + mmc_release_host(card->host); + } mmc_test_free_result(card); mmc_test_free_dbgfs_file(card); } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 94637796b99c..85b5f2bc8bb9 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -269,6 +269,8 @@ struct mmc_card { #define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */ #define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */ + bool reenable_cmdq; /* Re-enable Command Queue */ + unsigned int erase_size; /* erase size in sectors */ unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */ -- cgit v1.2.3 From 33e6d74d65c358270f00d228877178964aab84b3 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 24 Apr 2017 13:41:55 -0500 Subject: mmc: core: Export API to allow hosts to get the card address Some hosts controllers, like Cavium, needs to know whether the card operates in byte- or block-address mode. Therefore export a new API, mmc_card_is_blockaddr(), which provides this information. Signed-off-by: Ulf Hansson Signed-off-by: Steven J. Hill Acked-by: David Daney --- drivers/mmc/core/core.c | 6 ++++++ include/linux/mmc/card.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'include/linux') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index e5f6bbfa73dd..82c45ddfa202 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2560,6 +2560,12 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) } EXPORT_SYMBOL(mmc_calc_max_discard); +bool mmc_card_is_blockaddr(struct mmc_card *card) +{ + return card ? mmc_card_blockaddr(card) : false; +} +EXPORT_SYMBOL(mmc_card_is_blockaddr); + int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) { struct mmc_command cmd = {}; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 85b5f2bc8bb9..aad015e0152b 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -315,6 +315,8 @@ static inline bool mmc_large_sector(struct mmc_card *card) return card->ext_csd.data_sector_size == 4096; } +bool mmc_card_is_blockaddr(struct mmc_card *card); + #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) #define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD) #define mmc_card_sdio(c) ((c)->type == MMC_TYPE_SDIO) -- cgit v1.2.3