mmc: mxcmmc: Use sg_miter for PIO
authorLinus Walleij <linus.walleij@linaro.org>
Sat, 27 Jan 2024 00:19:53 +0000 (01:19 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 13 Feb 2024 12:40:56 +0000 (13:40 +0100)
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>
drivers/mmc/host/mxcmmc.c

index 5b3ab0e2050567c3de6eb6937dcb62e4b4b37360..1edf652913541e92d7ac53a01291e56c87b5121f 100644 (file)
@@ -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)