diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2024-01-27 01:19:53 +0100 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2024-02-13 13:40:56 +0100 |
commit | 12658af54f2ed10d812dcd0a769d62cb9e9291e5 (patch) | |
tree | f2bc7e4d74f9609f7e82f2bfaea118ae56d7c2d9 /drivers/mmc/host/mxcmmc.c | |
parent | mmc: mvsdio: Use sg_miter for PIO (diff) | |
download | linux-12658af54f2ed10d812dcd0a769d62cb9e9291e5.tar.xz linux-12658af54f2ed10d812dcd0a769d62cb9e9291e5.zip |
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: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/linux-mmc/20240122073423.GA25859@lst.de/
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20240127-mmc-proper-kmap-v2-6-d8e732aa97d1@linaro.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/mxcmmc.c')
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 5b3ab0e20505..1edf65291354 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -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; + + 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); + } - for_each_sg(data->sg, sg, data->sg_len, i) - buffer_swap32(sg_virt(sg), sg->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) |