mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
mmc: core: add mmc_read_tuning
Provide a function to the MMC hosts to read some blocks of data as part of their tuning. This function only returns the status of the read operation, not the data read. Signed-off-by: Benoît Monin <benoit.monin@bootlin.com> Link: https://lore.kernel.org/r/20250818-mobileye-emmc-for-upstream-4-v4-5-34ecb3995e96@bootlin.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
f33bba9b64
commit
99e6cc80d5
|
|
@ -1077,3 +1077,75 @@ int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms)
|
|||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_sanitize);
|
||||
|
||||
/**
|
||||
* mmc_read_tuning() - read data blocks from the mmc
|
||||
* @host: mmc host doing the read
|
||||
* @blksz: data block size
|
||||
* @blocks: number of blocks to read
|
||||
*
|
||||
* Read one or more blocks of data from the beginning of the mmc. This is a
|
||||
* low-level helper for tuning operation. It is assumed that CMD23 can be used
|
||||
* for multi-block read if the host supports it.
|
||||
*
|
||||
* Note: Allocate and free a temporary buffer to store the data read. The data
|
||||
* is not available outside of the function, only the status of the read
|
||||
* operation.
|
||||
*
|
||||
* Return: 0 in case of success, otherwise -EIO / -ENOMEM / -E2BIG
|
||||
*/
|
||||
int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks)
|
||||
{
|
||||
struct mmc_request mrq = {};
|
||||
struct mmc_command sbc = {};
|
||||
struct mmc_command cmd = {};
|
||||
struct mmc_command stop = {};
|
||||
struct mmc_data data = {};
|
||||
struct scatterlist sg;
|
||||
void *buf;
|
||||
unsigned int len;
|
||||
|
||||
if (blocks > 1) {
|
||||
if (mmc_host_can_cmd23(host)) {
|
||||
mrq.sbc = &sbc;
|
||||
sbc.opcode = MMC_SET_BLOCK_COUNT;
|
||||
sbc.arg = blocks;
|
||||
sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
}
|
||||
cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
|
||||
mrq.stop = &stop;
|
||||
stop.opcode = MMC_STOP_TRANSMISSION;
|
||||
stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
} else {
|
||||
cmd.opcode = MMC_READ_SINGLE_BLOCK;
|
||||
}
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
mrq.data = &data;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.blksz = blksz;
|
||||
data.blocks = blocks;
|
||||
data.blk_addr = 0;
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
data.timeout_ns = 1000000000;
|
||||
|
||||
if (check_mul_overflow(blksz, blocks, &len))
|
||||
return -E2BIG;
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
sg_init_one(&sg, buf, len);
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
kfree(buf);
|
||||
|
||||
if (sbc.error || cmd.error || data.error)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_read_tuning);
|
||||
|
|
|
|||
|
|
@ -743,5 +743,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
|
|||
int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
|
||||
int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
|
||||
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
|
||||
int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks);
|
||||
|
||||
#endif /* LINUX_MMC_HOST_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user