Skip to content

Commit 520bd7a

Browse files
committed
mmc: core: Optimize boot time by detecting cards simultaneously
The mmc workqueue is an ordered workqueue, allowing only one work to execute per given time. As this workqueue is used for card detection, the conseqeunce is that cards will be detected one by one waiting for each other. Moreover, most of the time spent during card initialization is waiting for the card's internal firmware to be ready. From a CPU perspective this typically means waiting for a completion variable to be kicked via an IRQ-handler or waiting for a sleep timer to finish. This behaviour of detecting/initializing cards is sub-optimal, especially for SOCs having several controllers/cards. Let's convert to use the system_freezable_wq for the mmc detect works. This enables several works to be executed simultaneously and thus also cards to be detected like so. Tests on UX500, which holds two eMMC cards and an SD-card (actually also an SDIO card, currently not detected), shows a significant improved behaviour due to this change. Before this change, both the eMMC cards waited for the SD card to be initialized as its detect work entered the workqueue first. In some cases, depending on the characteristic of the SD-card, they got delayed 1-1.5 s. Additionally for the second eMMC, it needed to wait for the first eMMC to be initialized which added another 120-190 ms. Converting to the system_freezable_wq, removed these delays and made both the eMMC cards available far earlier in the boot sequence. Selecting the system_freezable_wq, in favour of for example the system_wq, is because we need card detection mechanism to be disabled once userspace are frozen during system PM. Currently the mmc core deal with this via PM notifiers, but following patches may utilize the behaviour of the system_freezable_wq, to simplify the use of the PM notifiers. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Alan Cooper <alcooperx@gmail.com> Tested-by: Shawn Lin <shawn.lin@rock-chips.com>
1 parent 260b316 commit 520bd7a

File tree

1 file changed

+8
-23
lines changed

1 file changed

+8
-23
lines changed

drivers/mmc/core/core.c

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
*/
5656
#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
5757

58-
static struct workqueue_struct *workqueue;
5958
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
6059

6160
/*
@@ -66,21 +65,16 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
6665
bool use_spi_crc = 1;
6766
module_param(use_spi_crc, bool, 0);
6867

69-
/*
70-
* Internal function. Schedule delayed work in the MMC work queue.
71-
*/
7268
static int mmc_schedule_delayed_work(struct delayed_work *work,
7369
unsigned long delay)
7470
{
75-
return queue_delayed_work(workqueue, work, delay);
76-
}
77-
78-
/*
79-
* Internal function. Flush all scheduled work from the MMC work queue.
80-
*/
81-
static void mmc_flush_scheduled_work(void)
82-
{
83-
flush_workqueue(workqueue);
71+
/*
72+
* We use the system_freezable_wq, because of two reasons.
73+
* First, it allows several works (not the same work item) to be
74+
* executed simultaneously. Second, the queue becomes frozen when
75+
* userspace becomes frozen during system PM.
76+
*/
77+
return queue_delayed_work(system_freezable_wq, work, delay);
8478
}
8579

8680
#ifdef CONFIG_FAIL_MMC_REQUEST
@@ -2669,7 +2663,6 @@ void mmc_stop_host(struct mmc_host *host)
26692663

26702664
host->rescan_disable = 1;
26712665
cancel_delayed_work_sync(&host->detect);
2672-
mmc_flush_scheduled_work();
26732666

26742667
/* clear pm flags now and let card drivers set them as needed */
26752668
host->pm_flags = 0;
@@ -2852,13 +2845,9 @@ static int __init mmc_init(void)
28522845
{
28532846
int ret;
28542847

2855-
workqueue = alloc_ordered_workqueue("kmmcd", 0);
2856-
if (!workqueue)
2857-
return -ENOMEM;
2858-
28592848
ret = mmc_register_bus();
28602849
if (ret)
2861-
goto destroy_workqueue;
2850+
return ret;
28622851

28632852
ret = mmc_register_host_class();
28642853
if (ret)
@@ -2874,9 +2863,6 @@ static int __init mmc_init(void)
28742863
mmc_unregister_host_class();
28752864
unregister_bus:
28762865
mmc_unregister_bus();
2877-
destroy_workqueue:
2878-
destroy_workqueue(workqueue);
2879-
28802866
return ret;
28812867
}
28822868

@@ -2885,7 +2871,6 @@ static void __exit mmc_exit(void)
28852871
sdio_unregister_bus();
28862872
mmc_unregister_host_class();
28872873
mmc_unregister_bus();
2888-
destroy_workqueue(workqueue);
28892874
}
28902875

28912876
subsys_initcall(mmc_init);

0 commit comments

Comments
 (0)