Skip to content

Commit e056a1b

Browse files
ahunter6cjb
authored andcommitted
mmc: queue: let host controllers specify maximum discard timeout
Some host controllers will not operate without a hardware timeout that is limited in value. However large discards require large timeouts, so there needs to be a way to specify the maximum discard size. A host controller driver may now specify the maximum discard timeout possible so that max_discard_sectors can be calculated. However, for eMMC when the High Capacity Erase Group Size is not in use, the timeout calculation depends on clock rate which may change. For that case Preferred Erase Size is used instead. Signed-off-by: Adrian Hunter <[email protected]> Signed-off-by: Chris Ball <[email protected]>
1 parent e8cd77e commit e056a1b

File tree

4 files changed

+101
-10
lines changed

4 files changed

+101
-10
lines changed

drivers/mmc/card/queue.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,27 @@ static void mmc_request(struct request_queue *q)
101101
wake_up_process(mq->thread);
102102
}
103103

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+
104125
/**
105126
* mmc_init_queue - initialise a queue structure.
106127
* @mq: mmc queue
@@ -130,16 +151,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
130151

131152
blk_queue_prep_rq(mq->queue, mmc_prep_request);
132153
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
133-
if (mmc_can_erase(card)) {
134-
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
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-
}
154+
if (mmc_can_erase(card))
155+
mmc_queue_setup_discard(mq->queue, card);
143156

144157
#ifdef CONFIG_MMC_BLOCK_BOUNCE
145158
if (host->max_segs == 1) {

drivers/mmc/core/core.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,82 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
15161516
}
15171517
EXPORT_SYMBOL(mmc_erase_group_aligned);
15181518

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+
15191595
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
15201596
{
15211597
struct mmc_command cmd = {0};

include/linux/mmc/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ extern int mmc_can_trim(struct mmc_card *card);
155155
extern int mmc_can_secure_erase_trim(struct mmc_card *card);
156156
extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
157157
unsigned int nr);
158+
extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
158159

159160
extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
160161

include/linux/mmc/host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ struct mmc_host {
231231
unsigned int max_req_size; /* maximum number of bytes in one req */
232232
unsigned int max_blk_size; /* maximum size of one mmc block */
233233
unsigned int max_blk_count; /* maximum number of blocks in one req */
234+
unsigned int max_discard_to; /* max. discard timeout in ms */
234235

235236
/* private data */
236237
spinlock_t lock; /* lock for claim and bus ops */

0 commit comments

Comments
 (0)