Loading drivers/mmc/core/core.c +57 −0 Original line number Diff line number Diff line Loading @@ -379,6 +379,63 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) } EXPORT_SYMBOL(mmc_wait_for_req); /** * mmc_interrupt_hpi - Issue for High priority Interrupt * @card: the MMC card associated with the HPI transfer * * Issued High Priority Interrupt, and check for card status * util out-of prg-state. */ int mmc_interrupt_hpi(struct mmc_card *card) { int err; u32 status; BUG_ON(!card); if (!card->ext_csd.hpi_en) { pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host)); return 1; } mmc_claim_host(card->host); err = mmc_send_status(card, &status); if (err) { pr_err("%s: Get card status fail\n", mmc_hostname(card->host)); goto out; } /* * If the card status is in PRG-state, we can send the HPI command. */ if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { do { /* * We don't know when the HPI command will finish * processing, so we need to resend HPI until out * of prg-state, and keep checking the card status * with SEND_STATUS. If a timeout error occurs when * sending the HPI command, we are already out of * prg-state. */ err = mmc_send_hpi_cmd(card, &status); if (err) pr_debug("%s: abort HPI (%d error)\n", mmc_hostname(card->host), err); err = mmc_send_status(card, &status); if (err) break; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); } else pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); out: mmc_release_host(card->host); return err; } EXPORT_SYMBOL(mmc_interrupt_hpi); /** * mmc_wait_for_cmd - start a command and wait for completion * @host: MMC host to start command Loading drivers/mmc/core/mmc.c +31 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,21 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } if (card->ext_csd.rev >= 5) { /* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; else card->ext_csd.hpi_cmd = MMC_SEND_STATUS; /* * Indicate the maximum timeout to close * a command interrupted by HPI */ card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } Loading Loading @@ -895,6 +910,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } /* * Enable HPI feature (if supported) */ if (card->ext_csd.hpi) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HPI_MGMT, 1, 0); if (err && err != -EBADMSG) goto free_card; if (err) { pr_warning("%s: Enabling HPI failed\n", mmc_hostname(card->host)); err = 0; } else card->ext_csd.hpi_en = 1; } /* * Compute bus speed. */ Loading drivers/mmc/core/mmc_ops.c +31 −0 Original line number Diff line number Diff line Loading @@ -547,3 +547,34 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); return err; } int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) { struct mmc_command cmd = {0}; unsigned int opcode; unsigned int flags; int err; opcode = card->ext_csd.hpi_cmd; if (opcode == MMC_STOP_TRANSMISSION) flags = MMC_RSP_R1 | MMC_CMD_AC; else if (opcode == MMC_SEND_STATUS) flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.opcode = opcode; cmd.arg = card->rca << 16 | 1; cmd.flags = flags; cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_warn("%s: error %d interrupting operation. " "HPI command response %#x\n", mmc_hostname(card->host), err, cmd.resp[0]); return err; } if (status) *status = cmd.resp[0]; return 0; } drivers/mmc/core/mmc_ops.h +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_card_sleepawake(struct mmc_host *host, int sleep); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); #endif include/linux/mmc/card.h +4 −0 Original line number Diff line number Diff line Loading @@ -69,10 +69,14 @@ struct mmc_ext_csd { unsigned long long enhanced_area_offset; /* Units: Byte */ unsigned int enhanced_area_size; /* Units: KB */ unsigned int cache_size; /* Units: KB */ bool hpi_en; /* HPI enablebit */ bool hpi; /* HPI support bit */ unsigned int hpi_cmd; /* cmd used as HPI */ u8 raw_partition_support; /* 160 */ u8 raw_erased_mem_count; /* 181 */ u8 raw_ext_csd_structure; /* 194 */ u8 raw_card_type; /* 196 */ u8 out_of_int_time; /* 198 */ u8 raw_s_a_timeout; /* 217 */ u8 raw_hc_erase_gap_size; /* 221 */ u8 raw_erase_timeout_mult; /* 223 */ Loading Loading
drivers/mmc/core/core.c +57 −0 Original line number Diff line number Diff line Loading @@ -379,6 +379,63 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) } EXPORT_SYMBOL(mmc_wait_for_req); /** * mmc_interrupt_hpi - Issue for High priority Interrupt * @card: the MMC card associated with the HPI transfer * * Issued High Priority Interrupt, and check for card status * util out-of prg-state. */ int mmc_interrupt_hpi(struct mmc_card *card) { int err; u32 status; BUG_ON(!card); if (!card->ext_csd.hpi_en) { pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host)); return 1; } mmc_claim_host(card->host); err = mmc_send_status(card, &status); if (err) { pr_err("%s: Get card status fail\n", mmc_hostname(card->host)); goto out; } /* * If the card status is in PRG-state, we can send the HPI command. */ if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { do { /* * We don't know when the HPI command will finish * processing, so we need to resend HPI until out * of prg-state, and keep checking the card status * with SEND_STATUS. If a timeout error occurs when * sending the HPI command, we are already out of * prg-state. */ err = mmc_send_hpi_cmd(card, &status); if (err) pr_debug("%s: abort HPI (%d error)\n", mmc_hostname(card->host), err); err = mmc_send_status(card, &status); if (err) break; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); } else pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); out: mmc_release_host(card->host); return err; } EXPORT_SYMBOL(mmc_interrupt_hpi); /** * mmc_wait_for_cmd - start a command and wait for completion * @host: MMC host to start command Loading
drivers/mmc/core/mmc.c +31 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,21 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } if (card->ext_csd.rev >= 5) { /* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; else card->ext_csd.hpi_cmd = MMC_SEND_STATUS; /* * Indicate the maximum timeout to close * a command interrupted by HPI */ card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } Loading Loading @@ -895,6 +910,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } /* * Enable HPI feature (if supported) */ if (card->ext_csd.hpi) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HPI_MGMT, 1, 0); if (err && err != -EBADMSG) goto free_card; if (err) { pr_warning("%s: Enabling HPI failed\n", mmc_hostname(card->host)); err = 0; } else card->ext_csd.hpi_en = 1; } /* * Compute bus speed. */ Loading
drivers/mmc/core/mmc_ops.c +31 −0 Original line number Diff line number Diff line Loading @@ -547,3 +547,34 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); return err; } int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) { struct mmc_command cmd = {0}; unsigned int opcode; unsigned int flags; int err; opcode = card->ext_csd.hpi_cmd; if (opcode == MMC_STOP_TRANSMISSION) flags = MMC_RSP_R1 | MMC_CMD_AC; else if (opcode == MMC_SEND_STATUS) flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.opcode = opcode; cmd.arg = card->rca << 16 | 1; cmd.flags = flags; cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_warn("%s: error %d interrupting operation. " "HPI command response %#x\n", mmc_hostname(card->host), err, cmd.resp[0]); return err; } if (status) *status = cmd.resp[0]; return 0; }
drivers/mmc/core/mmc_ops.h +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_card_sleepawake(struct mmc_host *host, int sleep); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); #endif
include/linux/mmc/card.h +4 −0 Original line number Diff line number Diff line Loading @@ -69,10 +69,14 @@ struct mmc_ext_csd { unsigned long long enhanced_area_offset; /* Units: Byte */ unsigned int enhanced_area_size; /* Units: KB */ unsigned int cache_size; /* Units: KB */ bool hpi_en; /* HPI enablebit */ bool hpi; /* HPI support bit */ unsigned int hpi_cmd; /* cmd used as HPI */ u8 raw_partition_support; /* 160 */ u8 raw_erased_mem_count; /* 181 */ u8 raw_ext_csd_structure; /* 194 */ u8 raw_card_type; /* 196 */ u8 out_of_int_time; /* 198 */ u8 raw_s_a_timeout; /* 217 */ u8 raw_hc_erase_gap_size; /* 221 */ u8 raw_erase_timeout_mult; /* 223 */ Loading