Loading drivers/mmc/card/block.c +46 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,11 @@ * Author: Andrew Christian * 28 May 2002 */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/moduleparam.h> #include <linux/module.h> #include <linux/init.h> Loading Loading @@ -1537,12 +1542,19 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries) return err; } #define EXE_ERRORS \ (R1_OUT_OF_RANGE | /* Command argument out of range */ \ R1_ADDRESS_ERROR | /* Misaligned address */ \ R1_WP_VIOLATION | /* Tried to write to protected block */ \ R1_CARD_ECC_FAILED | /* ECC error */ \ R1_ERROR) /* General/unknown error */ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, bool hw_busy_detect, struct request *req, int *gen_err) { unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); int err = 0; u32 status; u32 status, first_status = 0; do { err = get_card_status(card, &status, 5); Loading @@ -1552,6 +1564,9 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, return err; } if (!first_status) first_status = status; if (status & R1_ERROR) { pr_err("%s: %s: error sending status cmd, status %#x\n", req->rq_disk->disk_name, __func__, status); Loading Loading @@ -1582,6 +1597,14 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, } while (!(status & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(status) == R1_STATE_PRG)); /* Check for errors during cmd execution. In this case * the execution was terminated. */ if (first_status & EXE_ERRORS) { pr_err("%s: error during r/w command, err status %#x, status %#x\n", req->rq_disk->disk_name, first_status, status); return MMC_BLK_ABORT; } return err; } Loading Loading @@ -2264,12 +2287,25 @@ static int mmc_blk_err_check(struct mmc_card *card, return MMC_BLK_ABORT; } /* Check execution mode errors. If stop cmd was sent, these * errors would be reported in response to it. In this case * the execution is retried using single-block read. */ if (brq->stop.resp[0] & EXE_ERRORS) { pr_err("%s: error during r/w command, stop response %#x\n", req->rq_disk->disk_name, brq->stop.resp[0]); return MMC_BLK_RETRY_SINGLE; } /* * Everything else is either success, or a data error of some * kind. If it was a write, we may have transitioned to * program mode, which we have to wait for it to complete. * If pre defined block count (CMD23) was used, no stop * cmd was sent and we need to read status to check * for errors during cmd execution. */ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { if (!mmc_host_is_spi(card->host) && (rq_data_dir(req) != READ || brq->sbc.opcode == MMC_SET_BLOCK_COUNT)) { int err; /* Check stop command response */ Loading Loading @@ -3849,6 +3885,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) break; goto cmd_abort; } case MMC_BLK_RETRY_SINGLE: case MMC_BLK_ECC_ERR: if (brq->data.blocks > 1) { /* Redo read one sector at a time */ Loading Loading @@ -4735,7 +4772,13 @@ static int mmc_blk_probe(struct mmc_card *card) } pm_runtime_use_autosuspend(&card->dev); if (mmc_card_sd(card)) pm_runtime_set_autosuspend_delay(&card->dev, MMC_SDCARD_AUTOSUSPEND_DELAY_MS); else pm_runtime_set_autosuspend_delay(&card->dev, MMC_AUTOSUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&card->dev); /* Loading drivers/mmc/core/Kconfig +16 −0 Original line number Diff line number Diff line Loading @@ -37,3 +37,19 @@ config MMC_CLKGATE support handling this in order for it to be of any use. If unsure, say N. config MMC_CMD_DEBUG bool "Debug feature to get mmc command issued" default n help This is a debug feature to get the mmc command issued in order to debug certain issues from the logs. config MMC_CMD_QUEUE_SIZE int "mmc command queue size" depends on MMC_CMD_DEBUG default 256 help Select the size of the circular queue to store the MMC command issued. drivers/mmc/core/core.c +34 −1 Original line number Diff line number Diff line Loading @@ -10,6 +10,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> Loading Loading @@ -1106,6 +1111,24 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) if (mmc_card_removed(host->card)) return -ENOMEDIUM; #ifdef CONFIG_MMC_CMD_DEBUG if (host->card) { struct mmc_cmdq *cq = NULL; cq = &host->card->cmd_stats.cmdq[host->card-> cmd_stats.next_idx]; cq->opcode = mrq->cmd->opcode; cq->arg = mrq->cmd->arg; cq->flags = mrq->cmd->flags; cq->timestamp = sched_clock(); host->card->cmd_stats.next_idx++; if (host->card->cmd_stats.next_idx == CMD_QUEUE_SIZE) { host->card->cmd_stats.next_idx = 0; host->card->cmd_stats.wrapped = 1; } } #endif if (mrq->sbc) { pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", mmc_hostname(host), mrq->sbc->opcode, Loading Loading @@ -3073,7 +3096,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) host->card_clock_off = false; /* Wait for at least 1 ms according to spec */ if (host->caps & MMC_CAP_NONREMOVABLE) mmc_delay(1); else mmc_delay(40); /* * Failure to switch is indicated by the card holding Loading Loading @@ -4184,6 +4210,8 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) return 0; if (!mmc_attach_sd(host)) return 0; else mmc_gpio_tray_close_set_uim2(host, 1); if (!mmc_attach_mmc(host)) return 0; Loading Loading @@ -4384,6 +4412,8 @@ void mmc_stop_host(struct mmc_host *host) cancel_delayed_work_sync(&host->detect); mmc_flush_scheduled_work(); mmc_gpio_set_uim2_en(host, 0); /* clear pm flags now and let card drivers set them as needed */ host->pm_flags = 0; Loading Loading @@ -4549,6 +4579,9 @@ int mmc_pm_notify(struct notifier_block *notify_block, host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); cancel_delayed_work_sync(&host->detect); #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME mmc_cd_prepare_suspend(host); #endif if (!host->bus_ops) break; Loading drivers/mmc/core/debugfs.c +55 −1 Original line number Diff line number Diff line Loading @@ -7,6 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/moduleparam.h> #include <linux/export.h> #include <linux/debugfs.h> Loading Loading @@ -866,6 +871,50 @@ static const struct file_operations mmc_dbg_bkops_stats_fops = { .write = mmc_bkops_stats_write, }; #ifdef CONFIG_MMC_CMD_DEBUG static int mmc_cmd_stats_show(struct seq_file *s, void *data) { int i; struct mmc_card *card = s->private; unsigned long long t; unsigned long rem_nsec; if (card->cmd_stats.wrapped) { for (i = card->cmd_stats.next_idx; i < CMD_QUEUE_SIZE; i++) { t = card->cmd_stats.cmdq[i].timestamp; rem_nsec = do_div(t, 1000000000); seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n", t, (rem_nsec/1000), card->cmd_stats.cmdq[i].opcode, card->cmd_stats.cmdq[i].arg, card->cmd_stats.cmdq[i].flags); } } for (i = 0; i < card->cmd_stats.next_idx; i++) { t = card->cmd_stats.cmdq[i].timestamp; rem_nsec = do_div(t, 1000000000); seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n", t, (rem_nsec/1000), card->cmd_stats.cmdq[i].opcode, card->cmd_stats.cmdq[i].arg, card->cmd_stats.cmdq[i].flags); } return 0; } static int mmc_cmd_stats_open(struct inode *inode, struct file *filp) { return single_open(filp, mmc_cmd_stats_show, inode->i_private); } static const struct file_operations mmc_dbg_card_rq_cmdq_fops = { .open = mmc_cmd_stats_open, .read = seq_read, }; #endif void mmc_add_card_debugfs(struct mmc_card *card) { struct mmc_host *host = card->host; Loading @@ -892,7 +941,12 @@ void mmc_add_card_debugfs(struct mmc_card *card) if (!debugfs_create_file("status", S_IRUSR, root, card, &mmc_dbg_card_status_fops)) goto err; #ifdef CONFIG_MMC_CMD_DEBUG if (mmc_card_mmc(card) || mmc_card_sd(card)) if (!debugfs_create_file("mmc_cmd_stats", S_IRUSR, root, card, &mmc_dbg_card_rq_cmdq_fops)) goto err; #endif if (mmc_card_mmc(card)) if (!debugfs_create_file("ext_csd", S_IRUSR, root, card, &mmc_dbg_ext_csd_fops)) Loading drivers/mmc/core/sd.c +6 −1 Original line number Diff line number Diff line Loading @@ -9,6 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/err.h> #include <linux/sizes.h> Loading Loading @@ -322,7 +327,7 @@ static int mmc_read_switch(struct mmc_card *card) * The argument does not matter, as the support bits do not * change with the arguments. */ err = mmc_sd_switch(card, 0, 0, 0, status); err = mmc_sd_switch(card, 0, 0, 1, status); if (err) { /* * If the host or the card can't do the switch, Loading Loading
drivers/mmc/card/block.c +46 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,11 @@ * Author: Andrew Christian * 28 May 2002 */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/moduleparam.h> #include <linux/module.h> #include <linux/init.h> Loading Loading @@ -1537,12 +1542,19 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries) return err; } #define EXE_ERRORS \ (R1_OUT_OF_RANGE | /* Command argument out of range */ \ R1_ADDRESS_ERROR | /* Misaligned address */ \ R1_WP_VIOLATION | /* Tried to write to protected block */ \ R1_CARD_ECC_FAILED | /* ECC error */ \ R1_ERROR) /* General/unknown error */ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, bool hw_busy_detect, struct request *req, int *gen_err) { unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); int err = 0; u32 status; u32 status, first_status = 0; do { err = get_card_status(card, &status, 5); Loading @@ -1552,6 +1564,9 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, return err; } if (!first_status) first_status = status; if (status & R1_ERROR) { pr_err("%s: %s: error sending status cmd, status %#x\n", req->rq_disk->disk_name, __func__, status); Loading Loading @@ -1582,6 +1597,14 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, } while (!(status & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(status) == R1_STATE_PRG)); /* Check for errors during cmd execution. In this case * the execution was terminated. */ if (first_status & EXE_ERRORS) { pr_err("%s: error during r/w command, err status %#x, status %#x\n", req->rq_disk->disk_name, first_status, status); return MMC_BLK_ABORT; } return err; } Loading Loading @@ -2264,12 +2287,25 @@ static int mmc_blk_err_check(struct mmc_card *card, return MMC_BLK_ABORT; } /* Check execution mode errors. If stop cmd was sent, these * errors would be reported in response to it. In this case * the execution is retried using single-block read. */ if (brq->stop.resp[0] & EXE_ERRORS) { pr_err("%s: error during r/w command, stop response %#x\n", req->rq_disk->disk_name, brq->stop.resp[0]); return MMC_BLK_RETRY_SINGLE; } /* * Everything else is either success, or a data error of some * kind. If it was a write, we may have transitioned to * program mode, which we have to wait for it to complete. * If pre defined block count (CMD23) was used, no stop * cmd was sent and we need to read status to check * for errors during cmd execution. */ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { if (!mmc_host_is_spi(card->host) && (rq_data_dir(req) != READ || brq->sbc.opcode == MMC_SET_BLOCK_COUNT)) { int err; /* Check stop command response */ Loading Loading @@ -3849,6 +3885,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) break; goto cmd_abort; } case MMC_BLK_RETRY_SINGLE: case MMC_BLK_ECC_ERR: if (brq->data.blocks > 1) { /* Redo read one sector at a time */ Loading Loading @@ -4735,7 +4772,13 @@ static int mmc_blk_probe(struct mmc_card *card) } pm_runtime_use_autosuspend(&card->dev); if (mmc_card_sd(card)) pm_runtime_set_autosuspend_delay(&card->dev, MMC_SDCARD_AUTOSUSPEND_DELAY_MS); else pm_runtime_set_autosuspend_delay(&card->dev, MMC_AUTOSUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&card->dev); /* Loading
drivers/mmc/core/Kconfig +16 −0 Original line number Diff line number Diff line Loading @@ -37,3 +37,19 @@ config MMC_CLKGATE support handling this in order for it to be of any use. If unsure, say N. config MMC_CMD_DEBUG bool "Debug feature to get mmc command issued" default n help This is a debug feature to get the mmc command issued in order to debug certain issues from the logs. config MMC_CMD_QUEUE_SIZE int "mmc command queue size" depends on MMC_CMD_DEBUG default 256 help Select the size of the circular queue to store the MMC command issued.
drivers/mmc/core/core.c +34 −1 Original line number Diff line number Diff line Loading @@ -10,6 +10,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> Loading Loading @@ -1106,6 +1111,24 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) if (mmc_card_removed(host->card)) return -ENOMEDIUM; #ifdef CONFIG_MMC_CMD_DEBUG if (host->card) { struct mmc_cmdq *cq = NULL; cq = &host->card->cmd_stats.cmdq[host->card-> cmd_stats.next_idx]; cq->opcode = mrq->cmd->opcode; cq->arg = mrq->cmd->arg; cq->flags = mrq->cmd->flags; cq->timestamp = sched_clock(); host->card->cmd_stats.next_idx++; if (host->card->cmd_stats.next_idx == CMD_QUEUE_SIZE) { host->card->cmd_stats.next_idx = 0; host->card->cmd_stats.wrapped = 1; } } #endif if (mrq->sbc) { pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", mmc_hostname(host), mrq->sbc->opcode, Loading Loading @@ -3073,7 +3096,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) host->card_clock_off = false; /* Wait for at least 1 ms according to spec */ if (host->caps & MMC_CAP_NONREMOVABLE) mmc_delay(1); else mmc_delay(40); /* * Failure to switch is indicated by the card holding Loading Loading @@ -4184,6 +4210,8 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) return 0; if (!mmc_attach_sd(host)) return 0; else mmc_gpio_tray_close_set_uim2(host, 1); if (!mmc_attach_mmc(host)) return 0; Loading Loading @@ -4384,6 +4412,8 @@ void mmc_stop_host(struct mmc_host *host) cancel_delayed_work_sync(&host->detect); mmc_flush_scheduled_work(); mmc_gpio_set_uim2_en(host, 0); /* clear pm flags now and let card drivers set them as needed */ host->pm_flags = 0; Loading Loading @@ -4549,6 +4579,9 @@ int mmc_pm_notify(struct notifier_block *notify_block, host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); cancel_delayed_work_sync(&host->detect); #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME mmc_cd_prepare_suspend(host); #endif if (!host->bus_ops) break; Loading
drivers/mmc/core/debugfs.c +55 −1 Original line number Diff line number Diff line Loading @@ -7,6 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/moduleparam.h> #include <linux/export.h> #include <linux/debugfs.h> Loading Loading @@ -866,6 +871,50 @@ static const struct file_operations mmc_dbg_bkops_stats_fops = { .write = mmc_bkops_stats_write, }; #ifdef CONFIG_MMC_CMD_DEBUG static int mmc_cmd_stats_show(struct seq_file *s, void *data) { int i; struct mmc_card *card = s->private; unsigned long long t; unsigned long rem_nsec; if (card->cmd_stats.wrapped) { for (i = card->cmd_stats.next_idx; i < CMD_QUEUE_SIZE; i++) { t = card->cmd_stats.cmdq[i].timestamp; rem_nsec = do_div(t, 1000000000); seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n", t, (rem_nsec/1000), card->cmd_stats.cmdq[i].opcode, card->cmd_stats.cmdq[i].arg, card->cmd_stats.cmdq[i].flags); } } for (i = 0; i < card->cmd_stats.next_idx; i++) { t = card->cmd_stats.cmdq[i].timestamp; rem_nsec = do_div(t, 1000000000); seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n", t, (rem_nsec/1000), card->cmd_stats.cmdq[i].opcode, card->cmd_stats.cmdq[i].arg, card->cmd_stats.cmdq[i].flags); } return 0; } static int mmc_cmd_stats_open(struct inode *inode, struct file *filp) { return single_open(filp, mmc_cmd_stats_show, inode->i_private); } static const struct file_operations mmc_dbg_card_rq_cmdq_fops = { .open = mmc_cmd_stats_open, .read = seq_read, }; #endif void mmc_add_card_debugfs(struct mmc_card *card) { struct mmc_host *host = card->host; Loading @@ -892,7 +941,12 @@ void mmc_add_card_debugfs(struct mmc_card *card) if (!debugfs_create_file("status", S_IRUSR, root, card, &mmc_dbg_card_status_fops)) goto err; #ifdef CONFIG_MMC_CMD_DEBUG if (mmc_card_mmc(card) || mmc_card_sd(card)) if (!debugfs_create_file("mmc_cmd_stats", S_IRUSR, root, card, &mmc_dbg_card_rq_cmdq_fops)) goto err; #endif if (mmc_card_mmc(card)) if (!debugfs_create_file("ext_csd", S_IRUSR, root, card, &mmc_dbg_ext_csd_fops)) Loading
drivers/mmc/core/sd.c +6 −1 Original line number Diff line number Diff line Loading @@ -9,6 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #include <linux/err.h> #include <linux/sizes.h> Loading Loading @@ -322,7 +327,7 @@ static int mmc_read_switch(struct mmc_card *card) * The argument does not matter, as the support bits do not * change with the arguments. */ err = mmc_sd_switch(card, 0, 0, 0, status); err = mmc_sd_switch(card, 0, 0, 1, status); if (err) { /* * If the host or the card can't do the switch, Loading