/* * Wait for the card to finish the busy state */ static int mmc_panic_wait_busy(struct mmc_card *card) { int ret, busy; struct mmc_command cmd; busy = 0; do { memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; ret = mmc_panic_wait_for_cmd(card->host, &cmd, 0); printk("#### panic send command resp = %d\n", cmd.resp[0]); if (ret) break; if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { busy = 1; printk(KERN_INFO "%s: Warning: Host did not " "wait for busy state to end.\n", mmc_hostname(card->host)); } } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd.resp[0]) == 7)); return ret; }
static void * mmc_cim_get_status( struct mmc_dev *dev, int first ) { struct mmc_slot *slot = dev->slot + dev->io_request->id; struct mmc_response_r1 r1; int retval = MMC_NO_ERROR; DEBUG(2," first=%d\n",first); if ( first ) { mmc_simple_cmd(dev, MMC_SEND_STATUS, slot->rca, RESPONSE_R1 ); return NULL; } switch (dev->request.cmd) { case MMC_SEND_STATUS: retval = mmc_unpack_r1(&dev->request,&r1,slot->state); if ( !retval || retval == MMC_ERROR_STATE_MISMATCH ) { slot->state = R1_CURRENT_STATE(r1.status); return mmc_cim_read_write_block; } break; default: break; } DEBUG(0, ": failure during cmd %d, error=%d (%s)\n", dev->request.cmd, retval, mmc_result_to_string(retval)); mmc_finish_io_request(dev,0); return mmc_cim_default_state; }
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; int retries = 3; struct mmc_command cmd; u32 status; unsigned long delay = jiffies + HZ; BUG_ON(!card); BUG_ON(!card->host); memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | set; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; mmc_delay(1); /* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status); if (err) { printk(KERN_ERR "%s: failed to get status (%d)\n", __func__, err); mmc_delay(5); retries--; continue; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; if (time_after(jiffies, delay)) { printk(KERN_ERR "failed to get card ready!!!\n"); break; } } while (retries && R1_CURRENT_STATE(status) == 7); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { if (status & 0xFDFFA000) printk(KERN_WARNING "%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } 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 * * 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) { int err; struct mmc_command cmd = {0}; 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 1 if (index == EXT_CSD_BKOPS_START /*&& card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2*/) cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; else cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; #else cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; #endif 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 BKOPS switch*/ if (index == EXT_CSD_BKOPS_START) return 0; mmc_delay(1); /* Must check status to be sure of no errors */ 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; } while (!(status & R1_READY_FOR_DATA) || (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; }
static int mmc_movi_vendor_cmd(struct mmc_card *card, u32 arg) { struct mmc_command cmd = {0}; int err; u32 status; /* CMD62 is vendor CMD, it's not defined in eMMC spec. */ cmd.opcode = 62; cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; cmd.arg = arg; err = mmc_wait_for_cmd(card->host, &cmd, 0); mdelay(10); if (err) return err; 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; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); return err; }
/** * 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 * * 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) { int err; struct mmc_command cmd = {0}; unsigned int ignore; 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_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /* Must check status to be sure of no errors */ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); ignore = (index == EXT_CSD_HS_TIMING) ? MMC_RSP_CRC : 0; do { err = mmc_send_status(card, &status, ignore); 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__); 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; }
static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, bool send_status, bool retry_crc_err) { struct mmc_host *host = card->host; int err; unsigned long timeout; u32 status = 0; bool expired = false; bool busy = false; /* We have an unspecified cmd timeout, use the fallback value. */ if (!timeout_ms) timeout_ms = MMC_OPS_TIMEOUT_MS; /* * In cases when not allowed to poll by using CMD13 or because we aren't * capable of polling by using ->card_busy(), then rely on waiting the * stated timeout to be sufficient. */ if (!send_status && !host->ops->card_busy) { mmc_delay(timeout_ms); return 0; } timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1; do { /* * Due to the possibility of being preempted while polling, * check the expiration time first. */ expired = time_after(jiffies, timeout); if (host->ops->card_busy) { busy = host->ops->card_busy(host); } else { err = mmc_send_status(card, &status); if (retry_crc_err && err == -EILSEQ) { busy = true; } else if (err) { return err; } else { err = mmc_switch_status_error(host, status); if (err) return err; busy = R1_CURRENT_STATE(status) == R1_STATE_PRG; } } /* Timeout if the device still remains busy. */ if (expired && busy) { pr_err("%s: Card stuck being busy! %s\n", mmc_hostname(host), __func__); return -ETIMEDOUT; } } while (busy); 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 * * 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) { int err; struct mmc_command cmd = {0}; 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_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /* Must check status to be sure of no errors */ do { /*The purpose of set clk here is to make 2x mode to reset the sample point * Because if switch to new timing mode,device's timing maybe change,so we * should reset the sample point to get new sample point * If our controller not use 2x mode,the change below will have no harm * */ mmc_set_clock(card->host,card->host->ios.clock); 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; } 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; }
/** * mmc_switch_bits - 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 * @check_busy: Set the 'R1B' flag or not. Some operations, such as * Sanitize, may need long time to finish. And some * host controller, such as the SDHCI host controller, * only allows limited max timeout value. So, introduce * this to skip the busy check for those operations. * @set: true when want to set value; false when want to clear value * * Modifies the EXT_CSD register for selected card. */ static int mmc_switch_bits(struct mmc_card *card, u8 cmdset, u8 index, u8 value, unsigned int timeout_ms, int check_busy, bool set) { int err; struct mmc_command cmd = {0}; u32 status; u8 access = set ? MMC_SWITCH_MODE_SET_BITS : MMC_SWITCH_MODE_CLEAR_BITS; BUG_ON(!card); BUG_ON(!card->host); cmd.opcode = MMC_SWITCH; cmd.arg = (access << 24) | (index << 16) | (value << 8) | cmdset; if (check_busy) cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; else cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /* Must check status to be sure of no errors */ 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; } 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_warn("%s: unexpected status %#x\n", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } return 0; }
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; struct mmc_command cmd; u32 status; #if defined(CONFIG_AMBARELLA_IPC) && defined(CONFIG_MMC_AMBARELLA) && !defined(CONFIG_NOT_SHARE_SD_CONTROLLER_WITH_UITRON) struct ipc_sdinfo *sdinfo = ambarella_sd_get_sdinfo(card->host); if (sdinfo->is_init) return 0; #endif BUG_ON(!card); BUG_ON(!card->host); memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | set; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /* Must check status to be sure of no errors */ 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; } while (R1_CURRENT_STATE(status) == 7); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { if (status & 0xFDFFA000) printk(KERN_WARNING "%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } 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 * * 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) { int err; struct mmc_command cmd = {0}; 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_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; #if defined(CONFIG_PHONE_ARIES_CTC) /* Add 3ms delay for SanDisk iNAND */ if (!strcmp(mmc_hostname(card->host), "mmc0")) mdelay(3); /* wait 3ms */ #endif /* Must check status to be sure of no errors */ 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; } while (R1_CURRENT_STATE(status) == 7); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { if (status & 0xFDFFA000) printk(KERN_WARNING "%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } 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 * * 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) { int err; struct mmc_command cmd = {0}; 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_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /* Must check status to be sure of no errors */ do { #if defined(CONFIG_MACH_SMDKC210) || defined(CONFIG_MACH_SMDKV310) /* HACK: in case of smdkc210, smdkv310 has problem at inand */ mmc_delay(3); #endif 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; } while (R1_CURRENT_STATE(status) == 7); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { if (status & 0xFDFFA000) printk(KERN_WARNING "%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } 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 * * 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) { int err; struct mmc_command cmd = {0}; 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_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /*add 2ms for change mode. This is inand bug*/ mdelay(2); /* Must check status to be sure of no errors */ 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; } 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; }
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; struct mmc_command cmd; u32 status; DBG("[%s] s\n",__func__); BUG_ON(!card); BUG_ON(!card->host); memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | set; // cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; //zhf: mark SPI mode temporarily by James Tian err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; /* Must check status to be sure of no errors */ 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; } while (R1_CURRENT_STATE(status) == 7); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { if (status & 0xFDFFA000) printk(KERN_WARNING "%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; } DBG("[%s] e2\n",__func__); return 0; }
int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous) { int err; struct mmc_command cmd; u32 status; BUG_ON(!card); BUG_ON(!card->host); memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_BKOPS_START << 16) | (1 << 8) | EXT_CSD_CMD_SET_NORMAL; if (is_synchronous) cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; else cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; if (!is_synchronous) return 0; /* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status); if (err) return err; if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; } while (R1_CURRENT_STATE(status) == 7); if (status & 0xFDFFA000) printk(KERN_ERR "%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; return 0; }
static int mmc_movi_erase_cmd(struct mmc_card *card, unsigned int arg1, unsigned int arg2) { struct mmc_command cmd = {0}; int err; u32 status; cmd.opcode = MMC_ERASE_GROUP_START; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.arg = arg1; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) return err; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_ERASE_GROUP_END; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.arg = arg2; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) return err; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_ERASE; cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; cmd.arg = 0x00000000; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) return err; 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; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); return err; }
int sd_send_status(struct mmc_card *card) { int err; u32 status; do { err = mmc_send_status(card, &status); if (err) { break; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; } while (R1_CURRENT_STATE(status) == 7); return err; }
int mmc_set_block_length(struct mmc_card *card, u32 length) { int err; int retries = 3; struct mmc_command cmd; u32 status = 0; unsigned long delay = jiffies + HZ; BUG_ON(!card); BUG_ON(!card->host); memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = length; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; do { err = mmc_send_status(card, &status); if (err) { printk(KERN_ERR "%s: failed to get status (%d)\n", __func__, err); mmc_delay(5); retries--; continue; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; if (time_after(jiffies, delay)) { printk(KERN_ERR "failed to get card ready!!!\n"); break; } } while (retries && R1_CURRENT_STATE(status) == 7); return 0; }
static int get_card_status(struct mmc_card *card, u32 *status) { do { int err = mmc_send_status(card, status); if (err) { mmc_release_host(card->host); return err; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) { break; } if (mmc_host_is_spi(card->host)) { break; } } while (R1_CURRENT_STATE(*status) == 7); return 0; }
/* * Wait for the card to finish the busy state */ static int mmc_test_wait_busy(struct mmc_test_card *test) { int ret, busy; struct mmc_command cmd; busy = 0; do { memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; cmd.arg = test->card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; ret = mmc_wait_for_cmd(test->card->host, &cmd, 0); if (ret){ printk(KERN_ERR "%s: error %d requesting status\n", mmc_hostname(test->card->host), ret); break; } if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { busy = 1; printk(KERN_INFO "%s: Warning: Host did not " "wait for busy state to end.\n", mmc_hostname(test->card->host)); } /* * Some cards mishandle the status bits, * so make sure to check both the busy * indication and the card state. */ } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd.resp[0]) == 7)); return ret; }
static int swrm_mmc_busy(struct mmc_command *cmd) { return !(cmd->resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG); }
void msdc_dump_card_status(u32 card_status) { static char *state[] = { "Idle", /* 0 */ "Ready", /* 1 */ "Ident", /* 2 */ "Stby", /* 3 */ "Tran", /* 4 */ "Data", /* 5 */ "Rcv", /* 6 */ "Prg", /* 7 */ "Dis", /* 8 */ "Btst", /* 9 */ "Slp", /* 10 */ "Reserved", /* 11 */ "Reserved", /* 12 */ "Reserved", /* 13 */ "Reserved", /* 14 */ "I/O mode", /* 15 */ }; if (card_status & R1_OUT_OF_RANGE) printk("\t[CARD_STATUS] Out of Range\n"); if (card_status & R1_ADDRESS_ERROR) printk("\t[CARD_STATUS] Address Error\n"); if (card_status & R1_BLOCK_LEN_ERROR) printk("\t[CARD_STATUS] Block Len Error\n"); if (card_status & R1_ERASE_SEQ_ERROR) printk("\t[CARD_STATUS] Erase Seq Error\n"); if (card_status & R1_ERASE_PARAM) printk("\t[CARD_STATUS] Erase Param\n"); if (card_status & R1_WP_VIOLATION) printk("\t[CARD_STATUS] WP Violation\n"); if (card_status & R1_CARD_IS_LOCKED) printk("\t[CARD_STATUS] Card is Locked\n"); if (card_status & R1_LOCK_UNLOCK_FAILED) printk("\t[CARD_STATUS] Lock/Unlock Failed\n"); if (card_status & R1_COM_CRC_ERROR) printk("\t[CARD_STATUS] Command CRC Error\n"); if (card_status & R1_ILLEGAL_COMMAND) printk("\t[CARD_STATUS] Illegal Command\n"); if (card_status & R1_CARD_ECC_FAILED) printk("\t[CARD_STATUS] Card ECC Failed\n"); if (card_status & R1_CC_ERROR) printk("\t[CARD_STATUS] CC Error\n"); if (card_status & R1_ERROR) printk("\t[CARD_STATUS] Error\n"); if (card_status & R1_UNDERRUN) printk("\t[CARD_STATUS] Underrun\n"); if (card_status & R1_OVERRUN) printk("\t[CARD_STATUS] Overrun\n"); if (card_status & R1_CID_CSD_OVERWRITE) printk("\t[CARD_STATUS] CID/CSD Overwrite\n"); if (card_status & R1_WP_ERASE_SKIP) printk("\t[CARD_STATUS] WP Eraser Skip\n"); if (card_status & R1_CARD_ECC_DISABLED) printk("\t[CARD_STATUS] Card ECC Disabled\n"); if (card_status & R1_ERASE_RESET) printk("\t[CARD_STATUS] Erase Reset\n"); if (card_status & R1_READY_FOR_DATA) printk("\t[CARD_STATUS] Ready for Data\n"); if (card_status & R1_SWITCH_ERROR) printk("\t[CARD_STATUS] Switch error\n"); if (card_status & R1_URGENT_BKOPS) printk("\t[CARD_STATUS] Urgent background operations\n"); if (card_status & R1_APP_CMD) printk("\t[CARD_STATUS] App Command\n"); printk("\t[CARD_STATUS] '%s' State\n", state[R1_CURRENT_STATE(card_status)]); }
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; spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); if (!blk_queue_plugged(q)) req = elv_next_request(q); mq->req = req; spin_unlock_irq(q->queue_lock); if (!req) { if (kthread_should_stop()) { set_current_state(TASK_RUNNING); break; } up(&mq->thread_sem); schedule(); down(&mq->thread_sem); continue; } set_current_state(TASK_RUNNING); #ifdef CONFIG_MMC_BLOCK_PARANOID_RESUME if (mq->check_status) { struct mmc_command cmd; do { int err; cmd.opcode = MMC_SEND_STATUS; cmd.arg = mq->card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; mmc_claim_host(mq->card->host); err = mmc_wait_for_cmd(mq->card->host, &cmd, 5); mmc_release_host(mq->card->host); if (err) { printk(KERN_ERR "%s: failed to get status (%d)\n", __func__, err); msleep(5); continue; } printk(KERN_DEBUG "%s: status 0x%.8x\n", __func__, cmd.resp[0]); } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd.resp[0]) == 7)); mq->check_status = 0; } #endif mq->issue_fn(mq, req); } while (1); up(&mq->thread_sem); return 0; }
/* * This needs to be called with host claimed * @part: GPP partition part ID, should be 1/2/3/4. * @addr: GPP write group unit */ int mmc_set_user_wp(struct mmc_card *card, unsigned int part, unsigned int wpg) { struct mmc_command cmd = {0}; int err = 0; u32 status = 0; if (!card) return -ENODEV; mmc_claim_host(card->host); /* * enable WP to partitions * set bit2 of ext_csd[171], permanent write protect */ err = mmc_switch_bits(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP, EXT_CSD_PERMANENT_WP, card->ext_csd.generic_cmd6_time, true, true); if (err) { pr_err("%s: enable permanent write protect err %d!\n", __func__, err); mmc_release_host(card->host); return err; } err = mmc_switch_part(card, part); if (err) goto switchback; cmd.opcode = MMC_SET_WRITE_PROT; cmd.arg = wpg * card->ext_csd.wpg_sz; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) { pr_err("%s: failed to set addr 0x%x write protected, err %d\n", __func__, cmd.arg, err); goto out; } /* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status); if (err) { pr_err("%s: card status get err %d, status 0x%x\n", __func__, err, status); goto out; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) { pr_err("%s: error card status 0x%x\n", __func__, status); err = -EILSEQ; goto out; } } else { if (status & 0xFDFFA000) pr_warn("%s: unexpected status %#x after switch", __func__, status); if (status & R1_SWITCH_ERROR) { pr_err("%s: card switch error, status 0x%x\n", __func__, status); err = -EIO; goto out; } if (status & R1_OUT_OF_RANGE) { pr_err("%s: addr out of range, status 0x%x\n", __func__, status); err = -EINVAL; } } out: err = mmc_switch_part(card, EXT_CSD_PART_CONFIG_ACC_USER); if (err) { pr_warn("%s: switch to USER partition failed!\n", __func__); WARN_ON(err); } switchback: /* * clear bit2 of ext_csd[171], permanent write protect */ err = mmc_switch_bits(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP, EXT_CSD_PERMANENT_WP, card->ext_csd.generic_cmd6_time, true, false); if (err) { pr_err("%s: clear write protect err %d!\n", __func__, err); } mmc_release_host(card->host); return err; }
/** * __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 int ignore; unsigned long timeout; u32 status; int retry_times = 3; 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; retry: /* Must check status to be sure of no errors */ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); ignore = (index == EXT_CSD_HS_TIMING) ? MMC_RSP_CRC : 0; do { err = mmc_send_status(card, &status, ignore); 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__); 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) { /* Means Set HS200 bit and Driver Strength value in the HS_TIMING [185]*/ if (((value & 0x3) == MMC_HS_TIMING_HS200) && retry_times) { mmc_set_timing(card->host, MMC_TIMING_MMC_HS200); retry_times--; pr_err("%s: Card set to HS200 status read should be retry! \n", mmc_hostname(card->host)); goto retry; } return -EBADMSG; } } return 0; }
/* * @part: GPP partition part number * @addr: GPP write group */ int mmc_wp_status(struct mmc_card *card, unsigned int part, unsigned int addr, u8 *wp_status) { struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct mmc_request mrq = {0}; struct scatterlist sg; u32 status = 0; int err = 0; u8 *rbuf = NULL; if (!card) return -ENODEV; if (!card->ext_csd.gpp_sz[part - EXT_CSD_PART_CONFIG_ACC_GP0]) { pr_err("%s: doesn't have GPP%d\n", __func__, part - 3); return -ENODEV; } rbuf = kzalloc(8, GFP_KERNEL); if (rbuf == NULL) { pr_err("%s: no memory\n", __func__); return -ENOMEM; } cmd.opcode = MMC_SEND_WRITE_PROT_TYPE; cmd.arg = addr * card->ext_csd.wpg_sz; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.sg = &sg; data.sg_len = 1; data.blksz = 8; data.blocks = 1; data.flags = MMC_DATA_READ; sg_init_one(data.sg, rbuf, 8); mrq.data = &data; mrq.cmd = &cmd; mmc_claim_host(card->host); mmc_set_data_timeout(&data, card); err = mmc_switch_part(card, part); if (err) { mmc_release_host(card->host); dev_err(mmc_dev(card->host), "%s: swith error %d\n", __func__, err); goto out; } mmc_wait_for_req(card->host, &mrq); if (cmd.error) { dev_err(mmc_dev(card->host), "%s: cmd error %d\n", __func__, cmd.error); } if (data.error) { dev_err(mmc_dev(card->host), "%s: data error %d\n", __func__, data.error); } /* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status); if (err) { pr_err("%s: get card status err %d, status 0x%x\n", __func__, err, status); goto out; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) { pr_err("%s: error card status 0x%x\n", __func__, status); goto out; } } else { if (status & 0xFDFFA000) pr_warn("%s: unexpected status %#x after switch", __func__, status); if (status & R1_SWITCH_ERROR) { pr_err("%s: card switch error, status 0x%x\n", __func__, status); } if (status & R1_OUT_OF_RANGE) { pr_err("%s: addr out of range, status 0x%x\n", __func__, status); goto out; } } mmc_switch_part(card, EXT_CSD_PART_CONFIG_ACC_USER); mmc_release_host(card->host); sg_copy_from_buffer(data.sg, 1, rbuf, 8); /* * the first write protect group type is in the last two * bits in the last byte read from the device. */ *wp_status = rbuf[7] & 0x3; kfree(rbuf); return 0; out: kfree(rbuf); return -EPERM; }
/** * __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 * @send_status: send status cmd to poll for busy * @ignore_crc: ignore CRC errors when sending status cmd to poll for busy * * 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, bool send_status, bool ignore_crc) { struct mmc_host *host = card->host; int err; struct mmc_command cmd = {0}; unsigned long timeout; u32 status = 0; bool use_r1b_resp = use_busy_signal; bool expired = false; mmc_retune_hold(host); /* * If the cmd timeout and the max_busy_timeout of the host are both * specified, let's validate them. A failure means we need to prevent * the host from doing hw busy detection, which is done by converting * to a R1 response instead of a R1B. */ if (timeout_ms && host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) use_r1b_resp = false; cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | set; cmd.flags = MMC_CMD_AC; if (use_r1b_resp) { cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B; /* * A busy_timeout of zero means the host can decide to use * whatever value it finds suitable. */ cmd.busy_timeout = timeout_ms; } else { cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1; } if (index == EXT_CSD_SANITIZE_START) cmd.sanitize_busy = true; err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err) goto out; /* No need to check card status in case of unblocking command */ if (!use_busy_signal) goto out; /* * CRC errors shall only be ignored in cases were CMD13 is used to poll * to detect busy completion. */ if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ignore_crc = false; /* We have an unspecified cmd timeout, use the fallback value. */ if (!timeout_ms) timeout_ms = MMC_OPS_TIMEOUT_MS; /* Must check status to be sure of no errors. */ timeout = jiffies + msecs_to_jiffies(timeout_ms); do { if (send_status) { /* * Due to the possibility of being preempted after * sending the status command, check the expiration * time first. */ expired = time_after(jiffies, timeout); err = __mmc_send_status(card, &status, ignore_crc); if (err) goto out; } if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) break; if (mmc_host_is_spi(host)) break; /* * We are not allowed to issue a status command and the host * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only * rely on waiting for the stated timeout to be sufficient. */ if (!send_status) { mmc_delay(timeout_ms); goto out; } /* Timeout if the device never leaves the program state. */ if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) { pr_err("%s: Card stuck in programming state! %s\n", mmc_hostname(host), __func__); err = -ETIMEDOUT; goto out; } } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); err = mmc_switch_status_error(host, status); out: mmc_retune_release(host); return err; }
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, bool use_busy_signal, bool ignore_timeout) { 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; cmd.ignore_timeout = ignore_timeout; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; if (!use_busy_signal) return 0; 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; if (time_after(jiffies, timeout)) { pr_err("%s: Card stuck in programming state! %s\n", mmc_hostname(card->host), __func__); 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; }
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; struct mmc_blk_request brq; int ret = 1; if (mmc_card_claim_host(card)) goto flush_queue; do { struct mmc_command cmd; u32 readcmd, writecmd; memset(&brq, 0, sizeof(struct mmc_blk_request)); brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; brq.cmd.arg = req->sector; if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); if (brq.data.blocks > card->host->max_blk_count) brq.data.blocks = card->host->max_blk_count; mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); #ifdef CONFIG_MMC_SUPPORT_MOVINAND if (mmc_card_movinand(card)) { if ((brq.data.blocks > 1) || (rq_data_dir(req) == WRITE)) { cmd.opcode = MMC_SET_BLOCK_COUNT; cmd.arg = req->nr_sectors; cmd.flags = MMC_RSP_R1; ret = mmc_wait_for_cmd(card->host, &cmd, 2); } if (rq_data_dir(req) == READ) { if (brq.data.blocks > 1) { brq.cmd.opcode = MMC_READ_MULTIPLE_BLOCK; brq.data.flags |= (MMC_DATA_READ | MMC_DATA_MULTI); // brq.mrq.stop = &brq.stop; } else { brq.cmd.opcode = MMC_READ_SINGLE_BLOCK; brq.data.flags |= MMC_DATA_READ; brq.mrq.stop = NULL; } } else { brq.cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK; brq.data.flags |= MMC_DATA_WRITE | MMC_DATA_MULTI; // brq.mrq.stop = &brq.stop; } } else { #endif /* * If the host doesn't support multiple block writes, force * block writes to single block. SD cards are excepted from * this rule as they support querying the number of * successfully written sectors. */ if (rq_data_dir(req) != READ && !(card->host->caps & MMC_CAP_MULTIWRITE) && !mmc_card_sd(card)) brq.data.blocks = 1; if (brq.data.blocks > 1) { brq.data.flags |= MMC_DATA_MULTI; brq.mrq.stop = &brq.stop; readcmd = MMC_READ_MULTIPLE_BLOCK; writecmd = MMC_WRITE_MULTIPLE_BLOCK; } else { brq.mrq.stop = NULL; readcmd = MMC_READ_SINGLE_BLOCK; writecmd = MMC_WRITE_BLOCK; } if (rq_data_dir(req) == READ) { brq.cmd.opcode = readcmd; brq.data.flags |= MMC_DATA_READ; } else { brq.cmd.opcode = writecmd; brq.data.flags |= MMC_DATA_WRITE; } #ifdef CONFIG_MMC_SUPPORT_MOVINAND } #endif brq.data.sg = mq->sg; brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); mmc_wait_for_req(card->host, &brq.mrq); if (brq.cmd.error) { printk(KERN_ERR "%s: error %d sending read/write command\n", req->rq_disk->disk_name, brq.cmd.error); goto cmd_err; } if (brq.data.error) { printk(KERN_ERR "%s: error %d transferring data\n", req->rq_disk->disk_name, brq.data.error); goto cmd_err; } if (brq.stop.error) { printk(KERN_ERR "%s: error %d sending stop command\n", req->rq_disk->disk_name, brq.stop.error); goto cmd_err; } if (rq_data_dir(req) != READ) { do { int err; cmd.opcode = MMC_SEND_STATUS; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); if (err) { printk(KERN_ERR "%s: error %d requesting status\n", req->rq_disk->disk_name, err); goto cmd_err; } #ifdef CONFIG_MMC_SUPPORT_MOVINAND /* Work-around for broken cards setting READY_FOR_DATA * when not actually ready. */ if (mmc_card_movinand(card)) { if (R1_CURRENT_STATE(cmd.resp[0]) == 7) cmd.resp[0] &= ~R1_READY_FOR_DATA; } #endif } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); #if 0 if (cmd.resp[0] & ~0x00000900) printk(KERN_ERR "%s: status = %08x\n", req->rq_disk->disk_name, cmd.resp[0]); if (mmc_decode_status(cmd.resp)) goto cmd_err; #endif } /* * A block was successfully transferred. */ spin_lock_irq(&md->lock); ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); if (!ret) { /* * The whole request completed successfully. */ add_disk_randomness(req->rq_disk); blkdev_dequeue_request(req); end_that_request_last(req, 1); } spin_unlock_irq(&md->lock); } while (ret); mmc_card_release_host(card); return 1; cmd_err: /* * If this is an SD card and we're writing, we can first * mark the known good sectors as ok. * * If the card is not SD, we can still ok written sectors * if the controller can do proper error reporting. * * For reads we just fail the entire chunk as that should * be safe in all cases. */ if (rq_data_dir(req) != READ && mmc_card_sd(card)) { u32 blocks; unsigned int bytes; blocks = mmc_sd_num_wr_blocks(card); if (blocks != (u32)-1) { if (card->csd.write_partial) bytes = blocks << md->block_bits; else bytes = blocks << 9; spin_lock_irq(&md->lock); ret = end_that_request_chunk(req, 1, bytes); spin_unlock_irq(&md->lock); } } else if (rq_data_dir(req) != READ && (card->host->caps & MMC_CAP_MULTIWRITE)) { spin_lock_irq(&md->lock); ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); spin_unlock_irq(&md->lock); } flush_queue: mmc_card_release_host(card); spin_lock_irq(&md->lock); while (ret) { ret = end_that_request_chunk(req, 0, req->current_nr_sectors << 9); } add_disk_randomness(req->rq_disk); blkdev_dequeue_request(req); end_that_request_last(req, 0); spin_unlock_irq(&md->lock); return 0; }
static int mmc_queue_thread(void *d) { struct mmc_queue *mq = d; struct request_queue *q = mq->queue; struct request *req; //ruanmeisi_20100603 int issue_ret = 0; #ifdef CONFIG_MMC_PERF_PROFILING ktime_t start, diff; struct mmc_host *host = mq->card->host; unsigned long bytes_xfer; #endif current->flags |= PF_MEMALLOC; down(&mq->thread_sem); do { req = NULL; //ruanmeisi_20100603 if (kthread_should_stop()) { remove_all_req(mq); break; } //end spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); if (!blk_queue_plugged(q)) req = blk_fetch_request(q); mq->req = req; spin_unlock_irq(q->queue_lock); if (!req) { if (kthread_should_stop()) { set_current_state(TASK_RUNNING); break; } up(&mq->thread_sem); schedule(); down(&mq->thread_sem); continue; } set_current_state(TASK_RUNNING); #ifdef CONFIG_MMC_AUTO_SUSPEND mmc_auto_suspend(mq->card->host, 0); #endif #ifdef CONFIG_MMC_BLOCK_PARANOID_RESUME if (mq->check_status) { struct mmc_command cmd; int retries = 3; do { int err; cmd.opcode = MMC_SEND_STATUS; cmd.arg = mq->card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; mmc_claim_host(mq->card->host); err = mmc_wait_for_cmd(mq->card->host, &cmd, 5); mmc_release_host(mq->card->host); if (err) { printk(KERN_ERR "%s: failed to get status (%d)\n", __func__, err); msleep(5); retries--; continue; } printk(KERN_DEBUG "%s: status 0x%.8x\n", __func__, cmd.resp[0]); } while (retries && (!(cmd.resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd.resp[0]) == 7))); mq->check_status = 0; } #endif //ruanmeisi_20100529 #ifdef CONFIG_MMC_PERF_PROFILING bytes_xfer = blk_rq_bytes(req); if (rq_data_dir(req) == READ) { start = ktime_get(); issue_ret = mq->issue_fn(mq, req); diff = ktime_sub(ktime_get(), start); host->perf.rbytes_mmcq += bytes_xfer; host->perf.rtime_mmcq = ktime_add(host->perf.rtime_mmcq, diff); } else { start = ktime_get(); issue_ret = mq->issue_fn(mq, req); diff = ktime_sub(ktime_get(), start); host->perf.wbytes_mmcq += bytes_xfer; host->perf.wtime_mmcq = ktime_add(host->perf.wtime_mmcq, diff); } #else issue_ret = mq->issue_fn(mq, req); #endif //ruanmeisi if (0 == issue_ret) { int err; mmc_claim_host(mq->card->host); err = mmc_send_status(mq->card, NULL); mmc_release_host(mq->card->host); if (err) { printk(KERN_ERR "rms:%s: failed to get status (%d) maybe the card is removed\n", __func__, err); //sdcard is removed? mmc_detect_change(mq->card->host, 0); msleep(500); //set_current_state(TASK_INTERRUPTIBLE); //schedule_timeout(HZ / 2); continue; } } } while (1); up(&mq->thread_sem); return 0; }