[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250818-mobileye-emmc-for-upstream-4-v4-5-34ecb3995e96@bootlin.com>
Date: Mon, 18 Aug 2025 16:02:50 +0200
From: Benoît Monin <benoit.monin@...tlin.com>
To: Ulf Hansson <ulf.hansson@...aro.org>,
Adrian Hunter <adrian.hunter@...el.com>
Cc: linux-mmc@...r.kernel.org, linux-kernel@...r.kernel.org,
Vladimir Kondratiev <vladimir.kondratiev@...ileye.com>,
Tawfik Bayouk <tawfik.bayouk@...ileye.com>,
Gregory CLEMENT <gregory.clement@...tlin.com>,
Thomas Petazzoni <thomas.petazzoni@...tlin.com>,
Benoît Monin <benoit.monin@...tlin.com>
Subject: [PATCH v4 5/6] 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@...tlin.com>
---
drivers/mmc/core/mmc_ops.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mmc/host.h | 1 +
2 files changed, 73 insertions(+)
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 66283825513cb4ff993a1b2ec1f0b0cac4e74487..a952cc8265af8f9d9587e4f21884d5f6d2fe0369 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -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);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 68f09a955a902047ac517441b6820fa6e4166a13..5ed5d203de23c1cd503061e0ef6a8bfd7253c8af 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -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 */
--
2.50.1
Powered by blists - more mailing lists