From b4dc23335f8bdf30ca1a735a9954601b94cb529b Mon Sep 17 00:00:00 2001 From: JaeHun Jung Date: Thu, 30 May 2019 17:21:19 +0900 Subject: [PATCH] [RAMEN9610-19678][COMMON] mmc: dw_mmc: Change regulator_disable from tasklet to workqueue. 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 --- drivers/mmc/host/dw_mmc.c | 24 ++++++++++++++++-------- drivers/mmc/host/dw_mmc.h | 3 ++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d3555748d400..54f3892cdded 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -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); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index e10d91d1dc39..78a760e1ac1b 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -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; -- 2.20.1