Commit 12658af5 authored by Linus Walleij's avatar Linus Walleij Committed by Ulf Hansson
Browse files

mmc: mxcmmc: Use sg_miter for PIO



Use the scatterlist memory iterator instead of just
dereferencing virtual memory using sg_virt().
This make highmem references work properly.

Since this driver is using a worker, no atomic trickery
is needed.

Suggested-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/linux-mmc/20240122073423.GA25859@lst.de/


Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20240127-mmc-proper-kmap-v2-6-d8e732aa97d1@linaro.org


Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 2761822c
Loading
Loading
Loading
Loading
+33 −20
Original line number Diff line number Diff line
@@ -266,11 +266,18 @@ static inline void buffer_swap32(u32 *buf, int len)

static void mxcmci_swap_buffers(struct mmc_data *data)
{
	struct scatterlist *sg;
	int i;
	struct sg_mapping_iter sgm;
	u32 *buf;

	for_each_sg(data->sg, sg, data->sg_len, i)
		buffer_swap32(sg_virt(sg), sg->length);
	sg_miter_start(&sgm, data->sg, data->sg_len,
		       SG_MITER_TO_SG | SG_MITER_FROM_SG);

	while (sg_miter_next(&sgm)) {
		buf = sgm.addr;
		buffer_swap32(buf, sgm.length);
	}

	sg_miter_stop(&sgm);
}
#else
static inline void mxcmci_swap_buffers(struct mmc_data *data) {}
@@ -526,10 +533,9 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
	} while (1);
}

static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
static int mxcmci_pull(struct mxcmci_host *host, u32 *buf, int bytes)
{
	unsigned int stat;
	u32 *buf = _buf;

	while (bytes > 3) {
		stat = mxcmci_poll_status(host,
@@ -555,10 +561,9 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
	return 0;
}

static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
static int mxcmci_push(struct mxcmci_host *host, u32 *buf, int bytes)
{
	unsigned int stat;
	u32 *buf = _buf;

	while (bytes > 3) {
		stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
@@ -586,31 +591,39 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
static int mxcmci_transfer_data(struct mxcmci_host *host)
{
	struct mmc_data *data = host->req->data;
	struct scatterlist *sg;
	int stat, i;
	struct sg_mapping_iter sgm;
	int stat;
	u32 *buf;

	host->data = data;
	host->datasize = 0;
	sg_miter_start(&sgm, data->sg, data->sg_len,
		       (data->flags & MMC_DATA_READ) ? SG_MITER_TO_SG : SG_MITER_FROM_SG);

	if (data->flags & MMC_DATA_READ) {
		for_each_sg(data->sg, sg, data->sg_len, i) {
			stat = mxcmci_pull(host, sg_virt(sg), sg->length);
		while (sg_miter_next(&sgm)) {
			buf = sgm.addr;
			stat = mxcmci_pull(host, buf, sgm.length);
			if (stat)
				return stat;
			host->datasize += sg->length;
				goto transfer_error;
			host->datasize += sgm.length;
		}
	} else {
		for_each_sg(data->sg, sg, data->sg_len, i) {
			stat = mxcmci_push(host, sg_virt(sg), sg->length);
		while (sg_miter_next(&sgm)) {
			buf = sgm.addr;
			stat = mxcmci_push(host, buf, sgm.length);
			if (stat)
				return stat;
			host->datasize += sg->length;
				goto transfer_error;
			host->datasize += sgm.length;
		}
		stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE);
		if (stat)
			return stat;
			goto transfer_error;
	}
	return 0;

transfer_error:
	sg_miter_stop(&sgm);
	return stat;
}

static void mxcmci_datawork(struct work_struct *work)