// SPDX-License-Identifier: GPL-2.0-only/* * linux/drivers/mmc/core/core.c * * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. */#include <linux/module.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/completion.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/pagemap.h>#include <linux/err.h>#include <linux/leds.h>#include <linux/scatterlist.h>#include <linux/log2.h>#include <linux/pm_runtime.h>#include <linux/suspend.h>#include <linux/fault-inject.h>#include <linux/random.h>#include <linux/slab.h>#include <linux/of.h> #include <linux/mmc/card.h>#include <linux/mmc/host.h>#include <linux/mmc/mmc.h>#include <linux/mmc/sd.h>#include <linux/mmc/slot-gpio.h> #define CREATE_TRACE_POINTS#include <trace/events/mmc.h> #include "core.h"#include "card.h"#include "crypto.h"#include "bus.h"#include "host.h"#include "sdio_bus.h"#include "pwrseq.h" #include "mmc_ops.h"#include "sd_ops.h"#include "sdio_ops.h" /* The max erase timeout, used when host->max_busy_timeout isn't specified */#define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */#define SD_DISCARD_TIMEOUT_MS (250) static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* * Enabling software CRCs on the data blocks can be a significant (30%) * performance cost, and for other reasons may not always be desired. * So we allow it to be disabled. */bool use_spi_crc = 1;module_param(use_spi_crc, bool, 0); static int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay){ /* * We use the system_freezable_wq, because of two reasons. * First, it allows several works (not the same work item) to be * executed simultaneously. Second, the queue becomes frozen when * userspace becomes frozen during system PM. */ return queue_delayed_work(system_freezable_wq, work, delay);} #ifdef CONFIG_FAIL_MMC_REQUEST /* * Internal function. Inject random data errors. * If mmc_data is NULL no errors are injected. */static void mmc_should_fail_request(struct mmc_host *host, struct mmc_request *mrq){ struct mmc_command *cmd = mrq->cmd; struct mmc_data *data = mrq->data; static const int data_errors[] = { -ETIMEDOUT, -EILSEQ, -EIO, }; if (!data) return; if ((cmd && cmd->error) || data->error || !should_fail(&host->fail_mmc_request, data->blksz * data->blocks)) return; data->error = data_errors[get_random_u32_below(ARRAY_SIZE(data_errors))]; data->bytes_xfered = get_random_u32_below(data->bytes_xfered >> SECTOR_SHIFT) << SECTOR_SHIFT;} #else /* CONFIG_FAIL_MMC_REQUEST */ static inline void mmc_should_fail_request(struct mmc_host *host, struct mmc_request *mrq){} #endif /* CONFIG_FAIL_MMC_REQUEST */ static inline void mmc_complete_cmd(struct mmc_request *mrq){ if (mrq->cap_cmd_during_tfr && !completion_done(&mrq->cmd_completion)) complete_all(&mrq->cmd_completion);} void mmc_command_done(struct mmc_host *host, struct mmc_request *mrq){ if (!mrq->cap_cmd_during_tfr) return; mmc_complete_cmd(mrq); pr_debug("%s: cmd done, tfr ongoing (CMD%u)\n", mmc_hostname(host), mrq->cmd->opcode);}EXPORT_SYMBOL(mmc_command_done); /** * mmc_request_done - finish processing an MMC request * @host: MMC host which completed request * @mrq: MMC request which request * * MMC drivers should call this function when they have completed * their processing of a request. */void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq){ struct mmc_command *cmd = mrq->cmd; int err = cmd->error; /* Flag re-tuning needed on CRC errors */ if (!mmc_op_tuning(cmd->opcode) && !host->retune_crc_disable && (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) || (mrq->data && mrq->data->error == -EILSEQ) || (mrq->stop && mrq->stop->error == -EILSEQ))) mmc_retune_needed(host); if (err && cmd->retries && mmc_host_is_spi(host)) { if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) cmd->retries = 0; } if (host->ongoing_mrq == mrq) host->ongoing_mrq = NULL; mmc_complete_cmd(mrq); trace_mmc_request_done(host, mrq); /* * We list various conditions for the command to be considered * properly done: * * - There was no error, OK fine then * - We are not doing some kind of retry * - The card was removed (...so just complete everything no matter * if there are errors or retries) */ if (!err || !cmd->retries || mmc_card_removed(host->card)) { mmc_should_fail_request(host, mrq); if (!host->ongoing_mrq) led_trigger_event(host->led, LED_OFF); if (mrq->sbc) { pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n", mmc_hostname(host), mrq->sbc->opcode, mrq->sbc->error, mrq->sbc->resp[0], mrq->sbc->resp[1], mrq->sbc->resp[2], mrq->sbc->resp[3]); } pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (mrq->data) { pr_debug("%s: %d bytes transferred: %d\n", mmc_hostname(host), mrq->data->bytes_xfered, mrq->data->error); } if (mrq->stop) { pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), mrq->stop->opcode, mrq->stop->error, mrq->stop->resp[0], mrq->stop->resp[1], mrq->stop->resp[2], mrq->stop->resp[3]); } } /* * Request starter must handle retries - see * mmc_wait_for_req_done(). */ if (mrq->done) mrq->done(mrq);} EXPORT_SYMBOL(mmc_request_done); static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq){ int err; /* Assumes host controller has been runtime resumed by mmc_claim_host */ err = mmc_retune(host); if (err) { mrq->cmd->error = err; mmc_request_done(host, mrq); return; } /* * For sdio rw commands we must wait for card busy otherwise some * sdio devices won't work properly. * And bypass I/O abort, reset and bus suspend operations. */ if (sdio_is_io_busy(mrq->cmd->opcode, mrq->cmd->arg) && host->ops->card_busy) { int tries = 500; /* Wait aprox 500ms at maximum */ while (host->ops->card_busy(host) && --tries) mmc_delay(1); if (tries == 0) { mrq->cmd->error = -EBUSY; mmc_request_done(host, mrq); return; } } if (mrq->cap_cmd_during_tfr) { host->ongoing_mrq = mrq; /* * Retry path could come through here without having waiting on * cmd_completion, so ensure it is reinitialised. */ reinit_completion(&mrq->cmd_completion); } trace_mmc_request_start(host, mrq); if (host->cqe_on) host->cqe_ops->cqe_off(host); host->ops->request(host, mrq);} static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq, bool cqe){ if (mrq->sbc) { pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", mmc_hostname(host), mrq->sbc->opcode, mrq->sbc->arg, mrq->sbc->flags); } if (mrq->cmd) { pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n", mmc_hostname(host), cqe ? "CQE direct " : "", mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); } else if (cqe) { pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n", mmc_hostname(host), mrq->tag, mrq->data->blk_addr); } if (mrq->data) { pr_debug("%s: blksz %d blocks %d flags %08x " "tsac %d ms nsac %d\n", mmc_hostname(host), mrq->data->blksz, mrq->data->blocks, mrq->data->flags, mrq->data->timeout_ns / 1000000, mrq->data->timeout_clks); } if (mrq->stop) { pr_debug("%s: CMD%u arg %08x flags %08x\n", mmc_hostname(host), mrq->stop->opcode, mrq->stop->arg, mrq->stop->flags); }} static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq){ unsigned int i, sz = 0; struct scatterlist *sg; if (mrq->cmd) { mrq->cmd->error = 0; mrq->cmd->mrq = mrq; mrq->cmd->data = mrq->data; } if (mrq->sbc) { mrq->sbc->error = 0; mrq->sbc->mrq = mrq; } if (mrq->data) { if (mrq->data->blksz > host->max_blk_size || mrq->data->blocks > host->max_blk_count || mrq->data->blocks * mrq->data->blksz > host->max_req_size) return -EINVAL; for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) sz += sg->length; if (sz != mrq->data->blocks * mrq->data->blksz) return -EINVAL; mrq->data->error = 0; mrq->data->mrq = mrq; if (mrq->stop) { mrq->data->stop = mrq->stop; mrq->stop->error = 0; mrq->stop->mrq = mrq; } } return 0;} int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq){ int err; if (mrq->cmd->has_ext_addr) mmc_send_ext_addr(host, mrq->cmd->ext_addr); init_completion(&mrq->cmd_completion); mmc_retune_hold(host); if (mmc_card_removed(host->card)) return -ENOMEDIUM; mmc_mrq_pr_debug(host, mrq, false); WARN_ON(!host->claimed); err = mmc_mrq_prep(host, mrq); if (err) return err; if (host->uhs2_sd_tran) mmc_uhs2_prepare_cmd(host, mrq); led_trigger_event(host->led, LED_FULL); __mmc_start_request(host, mrq); return 0;}EXPORT_SYMBOL(mmc_start_request); static void mmc_wait_done(struct mmc_request *mrq){ complete(&mrq->completion);} static inline void mmc_wait_ongoing_tfr_cmd(struct mmc_host *host){ struct mmc_request *ongoing_mrq = READ_ONCE(host->ongoing_mrq); /* * If there is an ongoing transfer, wait for the command line to become * available. */ if (ongoing_mrq && !completion_done(&ongoing_mrq->cmd_completion)) wait_for_completion(&ongoing_mrq->cmd_completion);} static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq){ int err; mmc_wait_ongoing_tfr_cmd(host); init_completion(&mrq->completion); mrq->done = mmc_wait_done; err = mmc_start_request(host, mrq); if (err) { mrq->cmd->error = err; mmc_complete_cmd(mrq); complete(&mrq->completion); } return err;} void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq){ struct mmc_command *cmd; while (1) { wait_for_completion(&mrq->completion); cmd = mrq->cmd; if (!cmd->error || !cmd->retries || mmc_card_removed(host->card)) break; mmc_retune_recheck(host); pr_debug("%s: req failed (CMD%u): %d, retrying...\n", mmc_hostname(host), cmd->opcode, cmd->error); cmd->retries--; cmd->error = 0; __mmc_start_request(host, mrq); } mmc_retune_release(host);}EXPORT_SYMBOL(mmc_wait_for_req_done); /* * mmc_cqe_start_req - Start a CQE request. * @host: MMC host to start the request * @mrq: request to start * * Start the request, re-tuning if needed and it is possible. Returns an error * code if the request fails to start or -EBUSY if CQE is busy. */int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq){ int err; /* * CQE cannot process re-tuning commands. Caller must hold retuning * while CQE is in use. Re-tuning can happen here only when CQE has no * active requests i.e. this is the first. Note, re-tuning will call * ->cqe_off(). */ err = mmc_retune(host); if (err) goto out_err; mrq->host = host; mmc_mrq_pr_debug(host, mrq, true); err = mmc_mrq_prep(host, mrq); if (err) goto out_err; if (host->uhs2_sd_tran) mmc_uhs2_prepare_cmd(host, mrq); err = host->cqe_ops->cqe_request(host, mrq); if (err) goto out_err; trace_mmc_request_start(host, mrq); return 0; out_err: if (mrq->cmd) { pr_debug("%s: failed to start CQE direct CMD%u, error %d\n", mmc_hostname(host), mrq->cmd->opcode, err); } else { pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n", mmc_hostname(host), mrq->tag, err); } return err;}EXPORT_SYMBOL(mmc_cqe_start_req); /** * mmc_cqe_request_done - CQE has finished processing an MMC request * @host: MMC host which completed request * @mrq: MMC request which completed * * CQE drivers should call this function when they have completed * their processing of a request. */void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq){ mmc_should_fail_request(host, mrq); /* Flag re-tuning needed on CRC errors */ if ((mrq->cmd && mrq->cmd->error == -EILSEQ) || (mrq->data && mrq->data->error == -EILSEQ)) mmc_retune_needed(host); trace_mmc_request_done(host, mrq); Lines 1–500 of 2429. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/core.c * * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. */ #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/completion.h> #include <linux/device.h> #include <linux/delay.h> #include <linux/pagemap.h> #include <linux/err.h> #include <linux/leds.h> #include <linux/scatterlist.h> #include <linux/log2.h> #include <linux/pm_runtime.h> #include <linux/suspend.h> #include <linux/fault-inject.h> #include <linux/random.h> #include <linux/slab.h> #include <linux/of.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> #include <linux/mmc/slot-gpio.h> #define CREATE_TRACE_POINTS #include <trace/events/mmc.h> #include "core.h" #include "card.h" #include "crypto.h" #include "bus.h" #include "host.h" #include "sdio_bus.h" #include "pwrseq.h" #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" /* The max erase timeout, used when host->max_busy_timeout isn't specified */ #define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */ #define SD_DISCARD_TIMEOUT_MS (250) static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* * Enabling software CRCs on the data blocks can be a significant (30%) * performance cost, and for other reasons may not always be desired. * So we allow it to be disabled. */ bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); static int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay) { /* * We use the system_freezable_wq, because of two reasons. * First, it allows several works (not the same work item) to be * executed simultaneously. Second, the queue becomes frozen when * userspace becomes frozen during system PM. */ return queue_delayed_work(system_freezable_wq, work, delay); } #ifdef CONFIG_FAIL_MMC_REQUEST /* * Internal function. Inject random data errors. * If mmc_data is NULL no errors are injected. */ static void mmc_should_fail_request(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd = mrq->cmd; struct mmc_data *data = mrq->data; static const int data_errors[] = { -ETIMEDOUT, -EILSEQ, -EIO, }; if (!data) return; if ((cmd && cmd->error) || data->error || !should_fail(&host->fail_mmc_request, data->blksz * data->blocks)) return; data->error = data_errors[get_random_u32_below(ARRAY_SIZE(data_errors))]; data->bytes_xfered = get_random_u32_below(data->bytes_xfered >> SECTOR_SHIFT) << SECTOR_SHIFT; } #else /* CONFIG_FAIL_MMC_REQUEST */ static inline void mmc_should_fail_request(struct mmc_host *host, struct mmc_request *mrq) { } #endif /* CONFIG_FAIL_MMC_REQUEST */ static inline void mmc_complete_cmd(struct mmc_request *mrq) { if (mrq->cap_cmd_during_tfr && !completion_done(&mrq->cmd_completion)) complete_all(&mrq->cmd_completion); } void mmc_command_done(struct mmc_host *host, struct mmc_request *mrq) { if (!mrq->cap_cmd_during_tfr) return; mmc_complete_cmd(mrq); pr_debug("%s: cmd done, tfr ongoing (CMD%u)\n", mmc_hostname(host), mrq->cmd->opcode); } EXPORT_SYMBOL(mmc_command_done); /** * mmc_request_done - finish processing an MMC request * @host: MMC host which completed request * @mrq: MMC request which request * * MMC drivers should call this function when they have completed * their processing of a request. */ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd = mrq->cmd; int err = cmd->error; /* Flag re-tuning needed on CRC errors */ if (!mmc_op_tuning(cmd->opcode) && !host->retune_crc_disable && (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) || (mrq->data && mrq->data->error == -EILSEQ) || (mrq->stop && mrq->stop->error == -EILSEQ))) mmc_retune_needed(host); if (err && cmd->retries && mmc_host_is_spi(host)) { if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) cmd->retries = 0; } if (host->ongoing_mrq == mrq) host->ongoing_mrq = NULL; mmc_complete_cmd(mrq); trace_mmc_request_done(host, mrq); /* * We list various conditions for the command to be considered * properly done: * * - There was no error, OK fine then * - We are not doing some kind of retry * - The card was removed (...so just complete everything no matter * if there are errors or retries) */ if (!err || !cmd->retries || mmc_card_removed(host->card)) { mmc_should_fail_request(host, mrq); if (!host->ongoing_mrq) led_trigger_event(host->led, LED_OFF); if (mrq->sbc) { pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n", mmc_hostname(host), mrq->sbc->opcode, mrq->sbc->error, mrq->sbc->resp[0], mrq->sbc->resp[1], mrq->sbc->resp[2], mrq->sbc->resp[3]); } pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (mrq->data) { pr_debug("%s: %d bytes transferred: %d\n", mmc_hostname(host), mrq->data->bytes_xfered, mrq->data->error); } if (mrq->stop) { pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), mrq->stop->opcode, mrq->stop->error, mrq->stop->resp[0], mrq->stop->resp[1], mrq->stop->resp[2], mrq->stop->resp[3]); } } /* * Request starter must handle retries - see * mmc_wait_for_req_done(). */ if (mrq->done) mrq->done(mrq); } EXPORT_SYMBOL(mmc_request_done); static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { int err; /* Assumes host controller has been runtime resumed by mmc_claim_host */ err = mmc_retune(host); if (err) { mrq->cmd->error = err; mmc_request_done(host, mrq); return; } /* * For sdio rw commands we must wait for card busy otherwise some * sdio devices won't work properly. * And bypass I/O abort, reset and bus suspend operations. */ if (sdio_is_io_busy(mrq->cmd->opcode, mrq->cmd->arg) && host->ops->card_busy) { int tries = 500; /* Wait aprox 500ms at maximum */ while (host->ops->card_busy(host) && --tries) mmc_delay(1); if (tries == 0) { mrq->cmd->error = -EBUSY; mmc_request_done(host, mrq); return; } } if (mrq->cap_cmd_during_tfr) { host->ongoing_mrq = mrq; /* * Retry path could come through here without having waiting on * cmd_completion, so ensure it is reinitialised. */ reinit_completion(&mrq->cmd_completion); } trace_mmc_request_start(host, mrq); if (host->cqe_on) host->cqe_ops->cqe_off(host); host->ops->request(host, mrq); } static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq, bool cqe) { if (mrq->sbc) { pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", mmc_hostname(host), mrq->sbc->opcode, mrq->sbc->arg, mrq->sbc->flags); } if (mrq->cmd) { pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n", mmc_hostname(host), cqe ? "CQE direct " : "", mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); } else if (cqe) { pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n", mmc_hostname(host), mrq->tag, mrq->data->blk_addr); } if (mrq->data) { pr_debug("%s: blksz %d blocks %d flags %08x " "tsac %d ms nsac %d\n", mmc_hostname(host), mrq->data->blksz, mrq->data->blocks, mrq->data->flags, mrq->data->timeout_ns / 1000000, mrq->data->timeout_clks); } if (mrq->stop) { pr_debug("%s: CMD%u arg %08x flags %08x\n", mmc_hostname(host), mrq->stop->opcode, mrq->stop->arg, mrq->stop->flags); } } static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq) { unsigned int i, sz = 0; struct scatterlist *sg; if (mrq->cmd) { mrq->cmd->error = 0; mrq->cmd->mrq = mrq; mrq->cmd->data = mrq->data; } if (mrq->sbc) { mrq->sbc->error = 0; mrq->sbc->mrq = mrq; } if (mrq->data) { if (mrq->data->blksz > host->max_blk_size || mrq->data->blocks > host->max_blk_count || mrq->data->blocks * mrq->data->blksz > host->max_req_size) return -EINVAL; for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) sz += sg->length; if (sz != mrq->data->blocks * mrq->data->blksz) return -EINVAL; mrq->data->error = 0; mrq->data->mrq = mrq; if (mrq->stop) { mrq->data->stop = mrq->stop; mrq->stop->error = 0; mrq->stop->mrq = mrq; } } return 0; } int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { int err; if (mrq->cmd->has_ext_addr) mmc_send_ext_addr(host, mrq->cmd->ext_addr); init_completion(&mrq->cmd_completion); mmc_retune_hold(host); if (mmc_card_removed(host->card)) return -ENOMEDIUM; mmc_mrq_pr_debug(host, mrq, false); WARN_ON(!host->claimed); err = mmc_mrq_prep(host, mrq); if (err) return err; if (host->uhs2_sd_tran) mmc_uhs2_prepare_cmd(host, mrq); led_trigger_event(host->led, LED_FULL); __mmc_start_request(host, mrq); return 0; } EXPORT_SYMBOL(mmc_start_request); static void mmc_wait_done(struct mmc_request *mrq) { complete(&mrq->completion); } static inline void mmc_wait_ongoing_tfr_cmd(struct mmc_host *host) { struct mmc_request *ongoing_mrq = READ_ONCE(host->ongoing_mrq); /* * If there is an ongoing transfer, wait for the command line to become * available. */ if (ongoing_mrq && !completion_done(&ongoing_mrq->cmd_completion)) wait_for_completion(&ongoing_mrq->cmd_completion); } static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) { int err; mmc_wait_ongoing_tfr_cmd(host); init_completion(&mrq->completion); mrq->done = mmc_wait_done; err = mmc_start_request(host, mrq); if (err) { mrq->cmd->error = err; mmc_complete_cmd(mrq); complete(&mrq->completion); } return err; } void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd; while (1) { wait_for_completion(&mrq->completion); cmd = mrq->cmd; if (!cmd->error || !cmd->retries || mmc_card_removed(host->card)) break; mmc_retune_recheck(host); pr_debug("%s: req failed (CMD%u): %d, retrying...\n", mmc_hostname(host), cmd->opcode, cmd->error); cmd->retries--; cmd->error = 0; __mmc_start_request(host, mrq); } mmc_retune_release(host); } EXPORT_SYMBOL(mmc_wait_for_req_done); /* * mmc_cqe_start_req - Start a CQE request. * @host: MMC host to start the request * @mrq: request to start * * Start the request, re-tuning if needed and it is possible. Returns an error * code if the request fails to start or -EBUSY if CQE is busy. */ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq) { int err; /* * CQE cannot process re-tuning commands. Caller must hold retuning * while CQE is in use. Re-tuning can happen here only when CQE has no * active requests i.e. this is the first. Note, re-tuning will call * ->cqe_off(). */ err = mmc_retune(host); if (err) goto out_err; mrq->host = host; mmc_mrq_pr_debug(host, mrq, true); err = mmc_mrq_prep(host, mrq); if (err) goto out_err; if (host->uhs2_sd_tran) mmc_uhs2_prepare_cmd(host, mrq); err = host->cqe_ops->cqe_request(host, mrq); if (err) goto out_err; trace_mmc_request_start(host, mrq); return 0; out_err: if (mrq->cmd) { pr_debug("%s: failed to start CQE direct CMD%u, error %d\n", mmc_hostname(host), mrq->cmd->opcode, err); } else { pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n", mmc_hostname(host), mrq->tag, err); } return err; } EXPORT_SYMBOL(mmc_cqe_start_req); /** * mmc_cqe_request_done - CQE has finished processing an MMC request * @host: MMC host which completed request * @mrq: MMC request which completed * * CQE drivers should call this function when they have completed * their processing of a request. */ void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq) { mmc_should_fail_request(host, mrq); /* Flag re-tuning needed on CRC errors */ if ((mrq->cmd && mrq->cmd->error == -EILSEQ) || (mrq->data && mrq->data->error == -EILSEQ)) mmc_retune_needed(host); trace_mmc_request_done(host, mrq);