static int mmc_queue_thread(void *d) { struct mmc_queue *mq = d; struct request_queue *q = mq->queue; current->flags |= PF_MEMALLOC; down(&mq->thread_sem); do { struct request *req = NULL; struct mmc_queue_req *tmp; spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); req = blk_fetch_request(q); mq->mqrq_cur->req = req; spin_unlock_irq(q->queue_lock); if (req || mq->mqrq_prev->req) { set_current_state(TASK_RUNNING); /* Abort any current bk ops of eMMC card by issuing HPI */ if (mmc_card_mmc(mq->card) && mmc_card_doing_bkops(mq->card)) { mmc_interrupt_hpi(mq->card); } mq->issue_fn(mq, req); } else { /* * Since the queue is empty, start synchronous * background ops if there is a request for it. */ if (mmc_card_need_bkops(mq->card)) mmc_bkops_start(mq->card, false, true); if (kthread_should_stop()) { set_current_state(TASK_RUNNING); break; } up(&mq->thread_sem); schedule(); down(&mq->thread_sem); } /* Current request becomes previous request and vice versa. */ mq->mqrq_prev->brq.mrq.data = NULL; mq->mqrq_prev->req = NULL; tmp = mq->mqrq_prev; mq->mqrq_prev = mq->mqrq_cur; mq->mqrq_cur = tmp; } while (1); up(&mq->thread_sem); return 0; }
/** * __mmc_switch - modify EXT_CSD register * @card: the MMC card associated with the data transfer * @set: cmd set values * @index: EXT_CSD register index * @value: value to program into EXT_CSD register * @timeout_ms: timeout (ms) for operation performed by register write, * timeout of zero implies maximum possible timeout * @use_busy_signal: use the busy signal as response type * * Modifies the EXT_CSD register for selected card. */ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, bool use_busy_signal) { int err; struct mmc_command cmd = {0}; unsigned long timeout; u32 status; BUG_ON(!card); BUG_ON(!card->host); cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | set; cmd.flags = MMC_CMD_AC; if (use_busy_signal) cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B; else cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /* No need to check card status in case of unblocking command */ if (!use_busy_signal) return 0; /* Must check status to be sure of no errors */ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); do { err = mmc_send_status(card, &status); if (err) return err; if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; /* Timeout if the device never leaves the program state. */ if (time_after(jiffies, timeout)) { pr_err("%s: Card stuck in programming state! %s\n", mmc_hostname(card->host), __func__); if (index == EXT_CSD_SANITIZE_START) { unsigned long prg_wait; pr_err("%s: Send HPI command due to Santitize command timeout\n", __func__); err = mmc_interrupt_hpi(card); if (err && (err != -EINVAL)) { pr_err("%s Failed to send HPI command (err=%d)\n", __func__, err); } } return -ETIMEDOUT; } } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { if (status & 0xFDFFA000) pr_warning("%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } return 0; }