Skip to content

Commit 921c87b

Browse files
Allen Paisstorulf
authored andcommitted
mmc: Convert from tasklet to BH workqueue
The only generic interface to execute asynchronously in the BH context is tasklet; however, it's marked deprecated and has some design flaws. To replace tasklets, BH workqueue support was recently added. A BH workqueue behaves similarly to regular workqueues except that the queued work items are executed in the BH context. This patch converts drivers/mmc/* from tasklet to BH workqueue. Based on the work done by Tejun Heo <[email protected]> Tested-by: Christian Loehle <[email protected]> Tested-by: Aubin Constans <[email protected]> Acked-by: Aubin Constans <[email protected]> Acked-by: Michał Mirosław <[email protected]> Reviewed-by: Christian Loehle <[email protected]> Signed-off-by: Allen Pais <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent 85683fb commit 921c87b

File tree

13 files changed

+142
-135
lines changed

13 files changed

+142
-135
lines changed

drivers/mmc/host/atmel-mci.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <linux/pm.h>
3434
#include <linux/pm_runtime.h>
3535
#include <linux/pinctrl/consumer.h>
36+
#include <linux/workqueue.h>
3637

3738
#include <asm/cacheflush.h>
3839
#include <asm/io.h>
@@ -272,12 +273,12 @@ struct atmel_mci_dma {
272273
* EVENT_DATA_ERROR is pending.
273274
* @stop_cmdr: Value to be loaded into CMDR when the stop command is
274275
* to be sent.
275-
* @tasklet: Tasklet running the request state machine.
276+
* @bh_work: Work running the request state machine.
276277
* @pending_events: Bitmask of events flagged by the interrupt handler
277-
* to be processed by the tasklet.
278+
* to be processed by the work.
278279
* @completed_events: Bitmask of events which the state machine has
279280
* processed.
280-
* @state: Tasklet state.
281+
* @state: Work state.
281282
* @queue: List of slots waiting for access to the controller.
282283
* @need_clock_update: Update the clock rate before the next request.
283284
* @need_reset: Reset controller before next request.
@@ -352,7 +353,7 @@ struct atmel_mci {
352353
u32 data_status;
353354
u32 stop_cmdr;
354355

355-
struct tasklet_struct tasklet;
356+
struct work_struct bh_work;
356357
unsigned long pending_events;
357358
unsigned long completed_events;
358359
enum atmel_mci_state state;
@@ -735,7 +736,7 @@ static void atmci_timeout_timer(struct timer_list *t)
735736
host->need_reset = 1;
736737
host->state = STATE_END_REQUEST;
737738
smp_wmb();
738-
tasklet_schedule(&host->tasklet);
739+
queue_work(system_bh_wq, &host->bh_work);
739740
}
740741

741742
static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
@@ -958,7 +959,7 @@ static void atmci_pdc_complete(struct atmel_mci *host)
958959

959960
dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
960961
atmci_set_pending(host, EVENT_XFER_COMPLETE);
961-
tasklet_schedule(&host->tasklet);
962+
queue_work(system_bh_wq, &host->bh_work);
962963
}
963964

964965
static void atmci_dma_cleanup(struct atmel_mci *host)
@@ -972,7 +973,7 @@ static void atmci_dma_cleanup(struct atmel_mci *host)
972973
}
973974

974975
/*
975-
* This function is called by the DMA driver from tasklet context.
976+
* This function is called by the DMA driver from bh context.
976977
*/
977978
static void atmci_dma_complete(void *arg)
978979
{
@@ -995,7 +996,7 @@ static void atmci_dma_complete(void *arg)
995996
if (data) {
996997
dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
997998
atmci_set_pending(host, EVENT_XFER_COMPLETE);
998-
tasklet_schedule(&host->tasklet);
999+
queue_work(system_bh_wq, &host->bh_work);
9991000

10001001
/*
10011002
* Regardless of what the documentation says, we have
@@ -1008,7 +1009,7 @@ static void atmci_dma_complete(void *arg)
10081009
* haven't seen all the potential error bits yet.
10091010
*
10101011
* The interrupt handler will schedule a different
1011-
* tasklet to finish things up when the data transfer
1012+
* bh work to finish things up when the data transfer
10121013
* is completely done.
10131014
*
10141015
* We may not complete the mmc request here anyway
@@ -1745,9 +1746,9 @@ static void atmci_detect_change(struct timer_list *t)
17451746
}
17461747
}
17471748

1748-
static void atmci_tasklet_func(struct tasklet_struct *t)
1749+
static void atmci_work_func(struct work_struct *t)
17491750
{
1750-
struct atmel_mci *host = from_tasklet(host, t, tasklet);
1751+
struct atmel_mci *host = from_work(host, t, bh_work);
17511752
struct mmc_request *mrq = host->mrq;
17521753
struct mmc_data *data = host->data;
17531754
struct device *dev = host->dev;
@@ -1759,7 +1760,7 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
17591760

17601761
state = host->state;
17611762

1762-
dev_vdbg(dev, "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
1763+
dev_vdbg(dev, "bh_work: state %u pending/completed/mask %lx/%lx/%x\n",
17631764
state, host->pending_events, host->completed_events,
17641765
atmci_readl(host, ATMCI_IMR));
17651766

@@ -2118,7 +2119,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
21182119
dev_dbg(dev, "set pending data error\n");
21192120
smp_wmb();
21202121
atmci_set_pending(host, EVENT_DATA_ERROR);
2121-
tasklet_schedule(&host->tasklet);
2122+
queue_work(system_bh_wq, &host->bh_work);
21222123
}
21232124

21242125
if (pending & ATMCI_TXBUFE) {
@@ -2187,7 +2188,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
21872188
smp_wmb();
21882189
dev_dbg(dev, "set pending notbusy\n");
21892190
atmci_set_pending(host, EVENT_NOTBUSY);
2190-
tasklet_schedule(&host->tasklet);
2191+
queue_work(system_bh_wq, &host->bh_work);
21912192
}
21922193

21932194
if (pending & ATMCI_NOTBUSY) {
@@ -2196,7 +2197,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
21962197
smp_wmb();
21972198
dev_dbg(dev, "set pending notbusy\n");
21982199
atmci_set_pending(host, EVENT_NOTBUSY);
2199-
tasklet_schedule(&host->tasklet);
2200+
queue_work(system_bh_wq, &host->bh_work);
22002201
}
22012202

22022203
if (pending & ATMCI_RXRDY)
@@ -2211,7 +2212,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
22112212
smp_wmb();
22122213
dev_dbg(dev, "set pending cmd rdy\n");
22132214
atmci_set_pending(host, EVENT_CMD_RDY);
2214-
tasklet_schedule(&host->tasklet);
2215+
queue_work(system_bh_wq, &host->bh_work);
22152216
}
22162217

22172218
if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
@@ -2487,7 +2488,7 @@ static int atmci_probe(struct platform_device *pdev)
24872488

24882489
host->mapbase = regs->start;
24892490

2490-
tasklet_setup(&host->tasklet, atmci_tasklet_func);
2491+
INIT_WORK(&host->bh_work, atmci_work_func);
24912492

24922493
ret = request_irq(irq, atmci_interrupt, 0, dev_name(dev), host);
24932494
if (ret) {

drivers/mmc/host/au1xmmc.c

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <linux/leds.h>
4343
#include <linux/mmc/host.h>
4444
#include <linux/slab.h>
45+
#include <linux/workqueue.h>
4546

4647
#include <asm/io.h>
4748
#include <asm/mach-au1x00/au1000.h>
@@ -113,8 +114,8 @@ struct au1xmmc_host {
113114

114115
int irq;
115116

116-
struct tasklet_struct finish_task;
117-
struct tasklet_struct data_task;
117+
struct work_struct finish_bh_work;
118+
struct work_struct data_bh_work;
118119
struct au1xmmc_platform_data *platdata;
119120
struct platform_device *pdev;
120121
struct resource *ioarea;
@@ -253,9 +254,9 @@ static void au1xmmc_finish_request(struct au1xmmc_host *host)
253254
mmc_request_done(host->mmc, mrq);
254255
}
255256

256-
static void au1xmmc_tasklet_finish(struct tasklet_struct *t)
257+
static void au1xmmc_finish_bh_work(struct work_struct *t)
257258
{
258-
struct au1xmmc_host *host = from_tasklet(host, t, finish_task);
259+
struct au1xmmc_host *host = from_work(host, t, finish_bh_work);
259260
au1xmmc_finish_request(host);
260261
}
261262

@@ -363,9 +364,9 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
363364
au1xmmc_finish_request(host);
364365
}
365366

366-
static void au1xmmc_tasklet_data(struct tasklet_struct *t)
367+
static void au1xmmc_data_bh_work(struct work_struct *t)
367368
{
368-
struct au1xmmc_host *host = from_tasklet(host, t, data_task);
369+
struct au1xmmc_host *host = from_work(host, t, data_bh_work);
369370

370371
u32 status = __raw_readl(HOST_STATUS(host));
371372
au1xmmc_data_complete(host, status);
@@ -425,7 +426,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
425426
if (host->flags & HOST_F_STOP)
426427
SEND_STOP(host);
427428

428-
tasklet_schedule(&host->data_task);
429+
queue_work(system_bh_wq, &host->data_bh_work);
429430
}
430431
}
431432

@@ -505,7 +506,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
505506
if (host->flags & HOST_F_STOP)
506507
SEND_STOP(host);
507508

508-
tasklet_schedule(&host->data_task);
509+
queue_work(system_bh_wq, &host->data_bh_work);
509510
}
510511
}
511512

@@ -561,7 +562,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
561562

562563
if (!trans || cmd->error) {
563564
IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF);
564-
tasklet_schedule(&host->finish_task);
565+
queue_work(system_bh_wq, &host->finish_bh_work);
565566
return;
566567
}
567568

@@ -797,7 +798,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
797798
IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
798799

799800
/* IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); */
800-
tasklet_schedule(&host->finish_task);
801+
queue_work(system_bh_wq, &host->finish_bh_work);
801802
}
802803
#if 0
803804
else if (status & SD_STATUS_DD) {
@@ -806,7 +807,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
806807
au1xmmc_receive_pio(host);
807808
else {
808809
au1xmmc_data_complete(host, status);
809-
/* tasklet_schedule(&host->data_task); */
810+
/* queue_work(system_bh_wq, &host->data_bh_work); */
810811
}
811812
}
812813
#endif
@@ -854,7 +855,7 @@ static void au1xmmc_dbdma_callback(int irq, void *dev_id)
854855
if (host->flags & HOST_F_STOP)
855856
SEND_STOP(host);
856857

857-
tasklet_schedule(&host->data_task);
858+
queue_work(system_bh_wq, &host->data_bh_work);
858859
}
859860

860861
static int au1xmmc_dbdma_init(struct au1xmmc_host *host)
@@ -1039,9 +1040,9 @@ static int au1xmmc_probe(struct platform_device *pdev)
10391040
if (host->platdata)
10401041
mmc->caps &= ~(host->platdata->mask_host_caps);
10411042

1042-
tasklet_setup(&host->data_task, au1xmmc_tasklet_data);
1043+
INIT_WORK(&host->data_bh_work, au1xmmc_data_bh_work);
10431044

1044-
tasklet_setup(&host->finish_task, au1xmmc_tasklet_finish);
1045+
INIT_WORK(&host->finish_bh_work, au1xmmc_finish_bh_work);
10451046

10461047
if (has_dbdma()) {
10471048
ret = au1xmmc_dbdma_init(host);
@@ -1091,8 +1092,8 @@ static int au1xmmc_probe(struct platform_device *pdev)
10911092
if (host->flags & HOST_F_DBDMA)
10921093
au1xmmc_dbdma_shutdown(host);
10931094

1094-
tasklet_kill(&host->data_task);
1095-
tasklet_kill(&host->finish_task);
1095+
cancel_work_sync(&host->data_bh_work);
1096+
cancel_work_sync(&host->finish_bh_work);
10961097

10971098
if (host->platdata && host->platdata->cd_setup &&
10981099
!(mmc->caps & MMC_CAP_NEEDS_POLL))
@@ -1135,8 +1136,8 @@ static void au1xmmc_remove(struct platform_device *pdev)
11351136
__raw_writel(0, HOST_CONFIG2(host));
11361137
wmb(); /* drain writebuffer */
11371138

1138-
tasklet_kill(&host->data_task);
1139-
tasklet_kill(&host->finish_task);
1139+
cancel_work_sync(&host->data_bh_work);
1140+
cancel_work_sync(&host->finish_bh_work);
11401141

11411142
if (host->flags & HOST_F_DBDMA)
11421143
au1xmmc_dbdma_shutdown(host);

drivers/mmc/host/cb710-mmc.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
493493
if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
494494
cb710_mmc_command(mmc, mrq->stop);
495495

496-
tasklet_schedule(&reader->finish_req_tasklet);
496+
queue_work(system_bh_wq, &reader->finish_req_bh_work);
497497
}
498498

499499
static int cb710_mmc_powerup(struct cb710_slot *slot)
@@ -646,10 +646,10 @@ static int cb710_mmc_irq_handler(struct cb710_slot *slot)
646646
return 1;
647647
}
648648

649-
static void cb710_mmc_finish_request_tasklet(struct tasklet_struct *t)
649+
static void cb710_mmc_finish_request_bh_work(struct work_struct *t)
650650
{
651-
struct cb710_mmc_reader *reader = from_tasklet(reader, t,
652-
finish_req_tasklet);
651+
struct cb710_mmc_reader *reader = from_work(reader, t,
652+
finish_req_bh_work);
653653
struct mmc_request *mrq = reader->mrq;
654654

655655
reader->mrq = NULL;
@@ -718,8 +718,8 @@ static int cb710_mmc_init(struct platform_device *pdev)
718718

719719
reader = mmc_priv(mmc);
720720

721-
tasklet_setup(&reader->finish_req_tasklet,
722-
cb710_mmc_finish_request_tasklet);
721+
INIT_WORK(&reader->finish_req_bh_work,
722+
cb710_mmc_finish_request_bh_work);
723723
spin_lock_init(&reader->irq_lock);
724724
cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
725725

@@ -763,7 +763,7 @@ static void cb710_mmc_exit(struct platform_device *pdev)
763763
cb710_write_port_32(slot, CB710_MMC_CONFIG_PORT, 0);
764764
cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0);
765765

766-
tasklet_kill(&reader->finish_req_tasklet);
766+
cancel_work_sync(&reader->finish_req_bh_work);
767767

768768
mmc_free_host(mmc);
769769
}

drivers/mmc/host/cb710-mmc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
#define LINUX_CB710_MMC_H
99

1010
#include <linux/cb710.h>
11+
#include <linux/workqueue.h>
1112

1213
/* per-MMC-reader structure */
1314
struct cb710_mmc_reader {
14-
struct tasklet_struct finish_req_tasklet;
15+
struct work_struct finish_req_bh_work;
1516
struct mmc_request *mrq;
1617
spinlock_t irq_lock;
1718
unsigned char last_power_mode;

0 commit comments

Comments
 (0)