Loading drivers/mmc/host/cmdq_hci.c +65 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ /* 1 sec */ #define HALT_TIMEOUT_MS 1000 static int cmdq_halt_poll(struct mmc_host *mmc); #ifdef CONFIG_PM_RUNTIME static int cmdq_runtime_pm_get(struct cmdq_host *host) { Loading Loading @@ -116,6 +118,20 @@ static void setup_trans_desc(struct cmdq_host *cq_host, u8 tag) } } static void cmdq_set_halt_irq(struct cmdq_host *cq_host, bool enable) { u32 ier; ier = cmdq_readl(cq_host, CQISTE); if (enable) { cmdq_writel(cq_host, ier | HALT, CQISTE); cmdq_writel(cq_host, ier | HALT, CQISGE); } else { cmdq_writel(cq_host, ier & ~HALT, CQISTE); cmdq_writel(cq_host, ier & ~HALT, CQISGE); } } static void cmdq_clear_set_irqs(struct cmdq_host *cq_host, u32 clear, u32 set) { u32 ier; Loading Loading @@ -369,6 +385,7 @@ static int cmdq_enable(struct mmc_host *mmc) mb(); cq_host->enabled = true; mmc_host_clr_cq_disable(mmc); if (cq_host->ops->set_block_size) cq_host->ops->set_block_size(cq_host->mmc); Loading Loading @@ -403,6 +420,7 @@ static void cmdq_disable(struct mmc_host *mmc, bool soft) cmdq_runtime_pm_put(cq_host); cq_host->enabled = false; mmc_host_set_cq_disable(mmc); } static void cmdq_reset(struct mmc_host *mmc, bool soft) Loading Loading @@ -448,6 +466,7 @@ static void cmdq_reset(struct mmc_host *mmc, bool soft) cmdq_writel(cq_host, cqcfg, CQCFG); cmdq_runtime_pm_put(cq_host); cq_host->enabled = true; mmc_host_clr_cq_disable(mmc); } static void cmdq_prep_task_desc(struct mmc_request *mrq, Loading Loading @@ -729,6 +748,7 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); unsigned long err_info = 0; struct mmc_request *mrq; int ret; status = cmdq_readl(cq_host, CQIS); cmdq_writel(cq_host, status, CQIS); Loading @@ -741,6 +761,17 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n", mmc_hostname(mmc), err, status, err_info); /* * Need to halt CQE in case of error in interrupt context itself * otherwise CQE may proceed with sending CMD to device even if * CQE/card is in error state. * CMDQ error handling will make sure that it is unhalted after * handling all the errors. */ ret = cmdq_halt_poll(mmc); if (ret) pr_err("%s: %s: halt failed ret=%d\n", mmc_hostname(mmc), __func__, ret); cmdq_dumpregs(cq_host); if (err_info & CQ_RMEFV) { Loading Loading @@ -823,6 +854,38 @@ out: } EXPORT_SYMBOL(cmdq_irq); /* cmdq_halt_poll - Halting CQE using polling method. * @mmc: struct mmc_host * This is used mainly from interrupt context to halt * CQE engine. */ static int cmdq_halt_poll(struct mmc_host *mmc) { struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); int retries = 100; cmdq_set_halt_irq(cq_host, false); cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) | HALT, CQCTL); while (retries) { if (!(cmdq_readl(cq_host, CQCTL) & HALT)) { udelay(5); retries--; continue; } else { if (cq_host->ops->post_cqe_halt) cq_host->ops->post_cqe_halt(mmc); /* halt done: re-enable legacy interrupts */ if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, false); mmc_host_set_halt(mmc); break; } } cmdq_set_halt_irq(cq_host, true); return retries ? 0 : -ETIMEDOUT; } /* May sleep */ static int cmdq_halt(struct mmc_host *mmc, bool halt) { Loading Loading @@ -965,6 +1028,8 @@ int cmdq_init(struct cmdq_host *cq_host, struct mmc_host *mmc, cq_host->dcmd_slot = DCMD_SLOT; mmc->cmdq_ops = &cmdq_host_ops; mmc->num_cq_slots = NUM_SLOTS; mmc->dcmd_cq_slot = DCMD_SLOT; cq_host->mrq_slot = kzalloc(sizeof(cq_host->mrq_slot) * cq_host->num_slots, GFP_KERNEL); Loading drivers/mmc/host/sdhci.c +3 −1 Original line number Diff line number Diff line Loading @@ -3099,19 +3099,21 @@ static irqreturn_t sdhci_cmdq_irq(struct sdhci_host *host, u32 intmask) { int err = 0; u32 mask = 0; irqreturn_t ret; if (intmask & SDHCI_INT_CMD_MASK) err = sdhci_get_cmd_err(intmask); else if (intmask & SDHCI_INT_DATA_MASK) err = sdhci_get_data_err(intmask); ret = cmdq_irq(host->mmc, err); if (err) { /* Clear the error interrupts */ mask = intmask & SDHCI_INT_ERROR_MASK; sdhci_writel(host, mask, SDHCI_INT_STATUS); } return ret; return cmdq_irq(host->mmc, err); } #else Loading include/linux/mmc/host.h +18 −0 Original line number Diff line number Diff line Loading @@ -256,6 +256,7 @@ struct mmc_cmdq_context_info { #define CMDQ_STATE_ERR 0 #define CMDQ_STATE_DCMD_ACTIVE 1 #define CMDQ_STATE_HALT 2 #define CMDQ_STATE_CQ_DISABLE 3 wait_queue_head_t queue_empty_wq; wait_queue_head_t wait; int active_small_sector_read_reqs; Loading Loading @@ -557,6 +558,8 @@ struct mmc_host { enum dev_state dev_status; bool wakeup_on_idle; struct mmc_cmdq_context_info cmdq_ctx; int num_cq_slots; int dcmd_cq_slot; u32 cmdq_thist_enabled; /* * several cmdq supporting host controllers are extensions Loading Loading @@ -697,6 +700,21 @@ static inline int mmc_host_halt(struct mmc_host *host) return test_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state); } static inline void mmc_host_set_cq_disable(struct mmc_host *host) { set_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state); } static inline void mmc_host_clr_cq_disable(struct mmc_host *host) { clear_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state); } static inline int mmc_host_cq_disable(struct mmc_host *host) { return test_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state); } #ifdef CONFIG_MMC_CLKGATE void mmc_host_clk_hold(struct mmc_host *host); void mmc_host_clk_release(struct mmc_host *host); Loading Loading
drivers/mmc/host/cmdq_hci.c +65 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ /* 1 sec */ #define HALT_TIMEOUT_MS 1000 static int cmdq_halt_poll(struct mmc_host *mmc); #ifdef CONFIG_PM_RUNTIME static int cmdq_runtime_pm_get(struct cmdq_host *host) { Loading Loading @@ -116,6 +118,20 @@ static void setup_trans_desc(struct cmdq_host *cq_host, u8 tag) } } static void cmdq_set_halt_irq(struct cmdq_host *cq_host, bool enable) { u32 ier; ier = cmdq_readl(cq_host, CQISTE); if (enable) { cmdq_writel(cq_host, ier | HALT, CQISTE); cmdq_writel(cq_host, ier | HALT, CQISGE); } else { cmdq_writel(cq_host, ier & ~HALT, CQISTE); cmdq_writel(cq_host, ier & ~HALT, CQISGE); } } static void cmdq_clear_set_irqs(struct cmdq_host *cq_host, u32 clear, u32 set) { u32 ier; Loading Loading @@ -369,6 +385,7 @@ static int cmdq_enable(struct mmc_host *mmc) mb(); cq_host->enabled = true; mmc_host_clr_cq_disable(mmc); if (cq_host->ops->set_block_size) cq_host->ops->set_block_size(cq_host->mmc); Loading Loading @@ -403,6 +420,7 @@ static void cmdq_disable(struct mmc_host *mmc, bool soft) cmdq_runtime_pm_put(cq_host); cq_host->enabled = false; mmc_host_set_cq_disable(mmc); } static void cmdq_reset(struct mmc_host *mmc, bool soft) Loading Loading @@ -448,6 +466,7 @@ static void cmdq_reset(struct mmc_host *mmc, bool soft) cmdq_writel(cq_host, cqcfg, CQCFG); cmdq_runtime_pm_put(cq_host); cq_host->enabled = true; mmc_host_clr_cq_disable(mmc); } static void cmdq_prep_task_desc(struct mmc_request *mrq, Loading Loading @@ -729,6 +748,7 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); unsigned long err_info = 0; struct mmc_request *mrq; int ret; status = cmdq_readl(cq_host, CQIS); cmdq_writel(cq_host, status, CQIS); Loading @@ -741,6 +761,17 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n", mmc_hostname(mmc), err, status, err_info); /* * Need to halt CQE in case of error in interrupt context itself * otherwise CQE may proceed with sending CMD to device even if * CQE/card is in error state. * CMDQ error handling will make sure that it is unhalted after * handling all the errors. */ ret = cmdq_halt_poll(mmc); if (ret) pr_err("%s: %s: halt failed ret=%d\n", mmc_hostname(mmc), __func__, ret); cmdq_dumpregs(cq_host); if (err_info & CQ_RMEFV) { Loading Loading @@ -823,6 +854,38 @@ out: } EXPORT_SYMBOL(cmdq_irq); /* cmdq_halt_poll - Halting CQE using polling method. * @mmc: struct mmc_host * This is used mainly from interrupt context to halt * CQE engine. */ static int cmdq_halt_poll(struct mmc_host *mmc) { struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); int retries = 100; cmdq_set_halt_irq(cq_host, false); cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) | HALT, CQCTL); while (retries) { if (!(cmdq_readl(cq_host, CQCTL) & HALT)) { udelay(5); retries--; continue; } else { if (cq_host->ops->post_cqe_halt) cq_host->ops->post_cqe_halt(mmc); /* halt done: re-enable legacy interrupts */ if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, false); mmc_host_set_halt(mmc); break; } } cmdq_set_halt_irq(cq_host, true); return retries ? 0 : -ETIMEDOUT; } /* May sleep */ static int cmdq_halt(struct mmc_host *mmc, bool halt) { Loading Loading @@ -965,6 +1028,8 @@ int cmdq_init(struct cmdq_host *cq_host, struct mmc_host *mmc, cq_host->dcmd_slot = DCMD_SLOT; mmc->cmdq_ops = &cmdq_host_ops; mmc->num_cq_slots = NUM_SLOTS; mmc->dcmd_cq_slot = DCMD_SLOT; cq_host->mrq_slot = kzalloc(sizeof(cq_host->mrq_slot) * cq_host->num_slots, GFP_KERNEL); Loading
drivers/mmc/host/sdhci.c +3 −1 Original line number Diff line number Diff line Loading @@ -3099,19 +3099,21 @@ static irqreturn_t sdhci_cmdq_irq(struct sdhci_host *host, u32 intmask) { int err = 0; u32 mask = 0; irqreturn_t ret; if (intmask & SDHCI_INT_CMD_MASK) err = sdhci_get_cmd_err(intmask); else if (intmask & SDHCI_INT_DATA_MASK) err = sdhci_get_data_err(intmask); ret = cmdq_irq(host->mmc, err); if (err) { /* Clear the error interrupts */ mask = intmask & SDHCI_INT_ERROR_MASK; sdhci_writel(host, mask, SDHCI_INT_STATUS); } return ret; return cmdq_irq(host->mmc, err); } #else Loading
include/linux/mmc/host.h +18 −0 Original line number Diff line number Diff line Loading @@ -256,6 +256,7 @@ struct mmc_cmdq_context_info { #define CMDQ_STATE_ERR 0 #define CMDQ_STATE_DCMD_ACTIVE 1 #define CMDQ_STATE_HALT 2 #define CMDQ_STATE_CQ_DISABLE 3 wait_queue_head_t queue_empty_wq; wait_queue_head_t wait; int active_small_sector_read_reqs; Loading Loading @@ -557,6 +558,8 @@ struct mmc_host { enum dev_state dev_status; bool wakeup_on_idle; struct mmc_cmdq_context_info cmdq_ctx; int num_cq_slots; int dcmd_cq_slot; u32 cmdq_thist_enabled; /* * several cmdq supporting host controllers are extensions Loading Loading @@ -697,6 +700,21 @@ static inline int mmc_host_halt(struct mmc_host *host) return test_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state); } static inline void mmc_host_set_cq_disable(struct mmc_host *host) { set_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state); } static inline void mmc_host_clr_cq_disable(struct mmc_host *host) { clear_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state); } static inline int mmc_host_cq_disable(struct mmc_host *host) { return test_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state); } #ifdef CONFIG_MMC_CLKGATE void mmc_host_clk_hold(struct mmc_host *host); void mmc_host_clk_release(struct mmc_host *host); Loading