[RAMEN9610-19678][COMMON] mmc: dw_mmc: Change regulator_disable from tasklet to workq...
authorJaeHun Jung <jh0801.jung@samsung.com>
Thu, 30 May 2019 08:21:19 +0000 (17:21 +0900)
committerKim Gunho <gunho.kim@samsung.com>
Mon, 9 Sep 2019 11:11:41 +0000 (20:11 +0900)
Regulator disable function has mutex_lock. And, mutex_lock has might_sleep().
It can not use in ISR & BH(bottom Half).
So, Using WQ with WQ_UNBOUND, WQ_HIGHPRI for execution.

Change-Id: I4f7a3d1b8d5a27000fb61ee9feb321749c956f59
Signed-off-by: JaeHun Jung <jh0801.jung@samsung.com>
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h

index d3555748d4003eb306a681dc4e9aeaf7cbabeb4d..54f3892cddedbf08cfe8470a4ed65192bb15771a 100644 (file)
@@ -2507,18 +2507,18 @@ static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
        return true;
 }
 
-static void dw_mci_sd_power_off(unsigned long priv)
+static void dw_mci_sd_power_off(struct work_struct *work)
 {
-       struct dw_mci *host = (struct dw_mci *)priv;
+       struct dw_mci *host = container_of(work, struct dw_mci, card_det_work);
        struct mmc_host *mmc = host->slot->mmc;
        struct dw_mci_slot *slot = host->slot;
 
        if (!IS_ERR(mmc->supply.vmmc))
                mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
-       if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled)
+       if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) {
                regulator_disable(mmc->supply.vqmmc);
-       slot->host->vqmmc_enabled = false;
-
+               slot->host->vqmmc_enabled = false;
+       }
 }
 
 static void dw_mci_tasklet_func(unsigned long priv)
@@ -3491,8 +3491,7 @@ static irqreturn_t dw_mci_detect_interrupt(int irq, void *dev_id)
        struct dw_mci *host = dev_id;
 
        /* sdcard power off */
-       tasklet_schedule(&host->pw_tasklet);
-
+       queue_work(host->sd_card_det_workqueue, &host->card_det_work);
        queue_work(host->card_workqueue, &host->card_work);
 
        return IRQ_HANDLED;
@@ -4299,7 +4298,6 @@ int dw_mci_probe(struct dw_mci *host)
                host->fifo_reg = host->regs + DATA_240A_OFFSET;
 
        tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
-       tasklet_init(&host->pw_tasklet, dw_mci_sd_power_off, (unsigned long)host);
 
        host->card_workqueue = alloc_workqueue("dw-mci-card", WQ_MEM_RECLAIM, 1);
        if (!host->card_workqueue) {
@@ -4308,6 +4306,14 @@ int dw_mci_probe(struct dw_mci *host)
        }
        INIT_WORK(&host->card_work, dw_mci_work_routine_card);
 
+       /* For SD card power control */
+       host->sd_card_det_workqueue = alloc_workqueue("sd-card-det-wq", WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_HIGHPRI, 1);
+       if (!host->sd_card_det_workqueue) {
+               ret = -ENOMEM;
+               goto err_dmaunmap;
+       }
+       INIT_WORK(&host->card_det_work, dw_mci_sd_power_off);
+
        /* INT min lock */
        pm_workqueue = create_freezable_workqueue("dw_mci_clk_ctrl");
        if (!pm_workqueue)
@@ -4379,6 +4385,7 @@ int dw_mci_probe(struct dw_mci *host)
 
  err_workqueue:
        destroy_workqueue(host->card_workqueue);
+       destroy_workqueue(host->sd_card_det_workqueue);
        destroy_workqueue(pm_workqueue);
        pm_qos_remove_request(&host->pm_qos_lock);
 
@@ -4420,6 +4427,7 @@ void dw_mci_remove(struct dw_mci *host)
 
        del_timer_sync(&host->timer);
        destroy_workqueue(host->card_workqueue);
+       destroy_workqueue(host->sd_card_det_workqueue);
        destroy_workqueue(pm_workqueue);
        pm_qos_remove_request(&host->pm_qos_lock);
 
index e10d91d1dc39dc9a644939d3a092f90fbe3792ad..78a760e1ac1bd4796e1d8c8fe2d1b6a89207235f 100644 (file)
@@ -176,6 +176,7 @@ struct dw_mci {
        unsigned int prev_blksz;
        unsigned char timing;
        struct workqueue_struct *card_workqueue;
+       struct workqueue_struct *sd_card_det_workqueue;
 
        /* DMA interface members */
        int use_dma;
@@ -203,8 +204,8 @@ struct dw_mci {
        u32 dir_status;
        struct tasklet_struct tasklet;
        u32 tasklet_state;
-       struct tasklet_struct pw_tasklet;
        struct work_struct card_work;
+       struct work_struct card_det_work;
        unsigned long pending_events;
        unsigned long completed_events;
        enum dw_mci_state state;