diff options
-rw-r--r-- | drivers/mmc/card/queue.c | 33 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 76 | ||||
-rw-r--r-- | include/linux/mmc/core.h | 1 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 1 |
4 files changed, 101 insertions, 10 deletions
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 6413afa318d2..defc11b4572c 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c | |||
@@ -101,6 +101,27 @@ static void mmc_request(struct request_queue *q) | |||
101 | wake_up_process(mq->thread); | 101 | wake_up_process(mq->thread); |
102 | } | 102 | } |
103 | 103 | ||
104 | static void mmc_queue_setup_discard(struct request_queue *q, | ||
105 | struct mmc_card *card) | ||
106 | { | ||
107 | unsigned max_discard; | ||
108 | |||
109 | max_discard = mmc_calc_max_discard(card); | ||
110 | if (!max_discard) | ||
111 | return; | ||
112 | |||
113 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); | ||
114 | q->limits.max_discard_sectors = max_discard; | ||
115 | if (card->erased_byte == 0) | ||
116 | q->limits.discard_zeroes_data = 1; | ||
117 | q->limits.discard_granularity = card->pref_erase << 9; | ||
118 | /* granularity must not be greater than max. discard */ | ||
119 | if (card->pref_erase > max_discard) | ||
120 | q->limits.discard_granularity = 0; | ||
121 | if (mmc_can_secure_erase_trim(card)) | ||
122 | queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); | ||
123 | } | ||
124 | |||
104 | /** | 125 | /** |
105 | * mmc_init_queue - initialise a queue structure. | 126 | * mmc_init_queue - initialise a queue structure. |
106 | * @mq: mmc queue | 127 | * @mq: mmc queue |
@@ -130,16 +151,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, | |||
130 | 151 | ||
131 | blk_queue_prep_rq(mq->queue, mmc_prep_request); | 152 | blk_queue_prep_rq(mq->queue, mmc_prep_request); |
132 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); | 153 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); |
133 | if (mmc_can_erase(card)) { | 154 | if (mmc_can_erase(card)) |
134 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue); | 155 | mmc_queue_setup_discard(mq->queue, card); |
135 | mq->queue->limits.max_discard_sectors = UINT_MAX; | ||
136 | if (card->erased_byte == 0) | ||
137 | mq->queue->limits.discard_zeroes_data = 1; | ||
138 | mq->queue->limits.discard_granularity = card->pref_erase << 9; | ||
139 | if (mmc_can_secure_erase_trim(card)) | ||
140 | queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, | ||
141 | mq->queue); | ||
142 | } | ||
143 | 156 | ||
144 | #ifdef CONFIG_MMC_BLOCK_BOUNCE | 157 | #ifdef CONFIG_MMC_BLOCK_BOUNCE |
145 | if (host->max_segs == 1) { | 158 | if (host->max_segs == 1) { |
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 7843efe22359..ac82865b8c2f 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1516,6 +1516,82 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, | |||
1516 | } | 1516 | } |
1517 | EXPORT_SYMBOL(mmc_erase_group_aligned); | 1517 | EXPORT_SYMBOL(mmc_erase_group_aligned); |
1518 | 1518 | ||
1519 | static unsigned int mmc_do_calc_max_discard(struct mmc_card *card, | ||
1520 | unsigned int arg) | ||
1521 | { | ||
1522 | struct mmc_host *host = card->host; | ||
1523 | unsigned int max_discard, x, y, qty = 0, max_qty, timeout; | ||
1524 | unsigned int last_timeout = 0; | ||
1525 | |||
1526 | if (card->erase_shift) | ||
1527 | max_qty = UINT_MAX >> card->erase_shift; | ||
1528 | else if (mmc_card_sd(card)) | ||
1529 | max_qty = UINT_MAX; | ||
1530 | else | ||
1531 | max_qty = UINT_MAX / card->erase_size; | ||
1532 | |||
1533 | /* Find the largest qty with an OK timeout */ | ||
1534 | do { | ||
1535 | y = 0; | ||
1536 | for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) { | ||
1537 | timeout = mmc_erase_timeout(card, arg, qty + x); | ||
1538 | if (timeout > host->max_discard_to) | ||
1539 | break; | ||
1540 | if (timeout < last_timeout) | ||
1541 | break; | ||
1542 | last_timeout = timeout; | ||
1543 | y = x; | ||
1544 | } | ||
1545 | qty += y; | ||
1546 | } while (y); | ||
1547 | |||
1548 | if (!qty) | ||
1549 | return 0; | ||
1550 | |||
1551 | if (qty == 1) | ||
1552 | return 1; | ||
1553 | |||
1554 | /* Convert qty to sectors */ | ||
1555 | if (card->erase_shift) | ||
1556 | max_discard = --qty << card->erase_shift; | ||
1557 | else if (mmc_card_sd(card)) | ||
1558 | max_discard = qty; | ||
1559 | else | ||
1560 | max_discard = --qty * card->erase_size; | ||
1561 | |||
1562 | return max_discard; | ||
1563 | } | ||
1564 | |||
1565 | unsigned int mmc_calc_max_discard(struct mmc_card *card) | ||
1566 | { | ||
1567 | struct mmc_host *host = card->host; | ||
1568 | unsigned int max_discard, max_trim; | ||
1569 | |||
1570 | if (!host->max_discard_to) | ||
1571 | return UINT_MAX; | ||
1572 | |||
1573 | /* | ||
1574 | * Without erase_group_def set, MMC erase timeout depends on clock | ||
1575 | * frequence which can change. In that case, the best choice is | ||
1576 | * just the preferred erase size. | ||
1577 | */ | ||
1578 | if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1)) | ||
1579 | return card->pref_erase; | ||
1580 | |||
1581 | max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG); | ||
1582 | if (mmc_can_trim(card)) { | ||
1583 | max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG); | ||
1584 | if (max_trim < max_discard) | ||
1585 | max_discard = max_trim; | ||
1586 | } else if (max_discard < card->erase_size) { | ||
1587 | max_discard = 0; | ||
1588 | } | ||
1589 | pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n", | ||
1590 | mmc_hostname(host), max_discard, host->max_discard_to); | ||
1591 | return max_discard; | ||
1592 | } | ||
1593 | EXPORT_SYMBOL(mmc_calc_max_discard); | ||
1594 | |||
1519 | int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) | 1595 | int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) |
1520 | { | 1596 | { |
1521 | struct mmc_command cmd = {0}; | 1597 | struct mmc_command cmd = {0}; |
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 791f060a6f1d..86d81cf75b70 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h | |||
@@ -155,6 +155,7 @@ extern int mmc_can_trim(struct mmc_card *card); | |||
155 | extern int mmc_can_secure_erase_trim(struct mmc_card *card); | 155 | extern int mmc_can_secure_erase_trim(struct mmc_card *card); |
156 | extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, | 156 | extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, |
157 | unsigned int nr); | 157 | unsigned int nr); |
158 | extern unsigned int mmc_calc_max_discard(struct mmc_card *card); | ||
158 | 159 | ||
159 | extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); | 160 | extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); |
160 | 161 | ||
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index fc24b38b48cb..c67d19b5542a 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
@@ -231,6 +231,7 @@ struct mmc_host { | |||
231 | unsigned int max_req_size; /* maximum number of bytes in one req */ | 231 | unsigned int max_req_size; /* maximum number of bytes in one req */ |
232 | unsigned int max_blk_size; /* maximum size of one mmc block */ | 232 | unsigned int max_blk_size; /* maximum size of one mmc block */ |
233 | unsigned int max_blk_count; /* maximum number of blocks in one req */ | 233 | unsigned int max_blk_count; /* maximum number of blocks in one req */ |
234 | unsigned int max_discard_to; /* max. discard timeout in ms */ | ||
234 | 235 | ||
235 | /* private data */ | 236 | /* private data */ |
236 | spinlock_t lock; /* lock for claim and bus ops */ | 237 | spinlock_t lock; /* lock for claim and bus ops */ |