]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mmc: omap: Use sg_miter for PIO
authorLinus Walleij <linus.walleij@linaro.org>
Sat, 27 Jan 2024 00:19:54 +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.

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-7-d8e732aa97d1@linaro.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/omap.c

index 9fb8995b43a1c8669063e894708db20b1dd05054..088f8ed4fdc4640d706a98d317e79668a6942748 100644 (file)
@@ -148,10 +148,8 @@ struct mmc_omap_host {
        struct work_struct      send_stop_work;
        struct mmc_data         *stop_data;
 
+       struct sg_mapping_iter  sg_miter;
        unsigned int            sg_len;
-       int                     sg_idx;
-       u16 *                   buffer;
-       u32                     buffer_bytes_left;
        u32                     total_bytes_left;
 
        unsigned                features;
@@ -456,6 +454,8 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
 {
        if (host->dma_in_use)
                mmc_omap_release_dma(host, data, data->error);
+       else
+               sg_miter_stop(&host->sg_miter);
 
        host->data = NULL;
        host->sg_len = 0;
@@ -651,19 +651,6 @@ mmc_omap_cmd_timer(struct timer_list *t)
        spin_unlock_irqrestore(&host->slot_lock, flags);
 }
 
-/* PIO only */
-static void
-mmc_omap_sg_to_buf(struct mmc_omap_host *host)
-{
-       struct scatterlist *sg;
-
-       sg = host->data->sg + host->sg_idx;
-       host->buffer_bytes_left = sg->length;
-       host->buffer = sg_virt(sg);
-       if (host->buffer_bytes_left > host->total_bytes_left)
-               host->buffer_bytes_left = host->total_bytes_left;
-}
-
 static void
 mmc_omap_clk_timer(struct timer_list *t)
 {
@@ -676,33 +663,37 @@ mmc_omap_clk_timer(struct timer_list *t)
 static void
 mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
 {
+       struct sg_mapping_iter *sgm = &host->sg_miter;
        int n, nwords;
+       u16 *buffer;
 
-       if (host->buffer_bytes_left == 0) {
-               host->sg_idx++;
-               BUG_ON(host->sg_idx == host->sg_len);
-               mmc_omap_sg_to_buf(host);
+       if (!sg_miter_next(sgm)) {
+               /* This should not happen */
+               dev_err(mmc_dev(host->mmc), "ran out of scatterlist prematurely\n");
+               return;
        }
+       buffer = sgm->addr;
+
        n = 64;
-       if (n > host->buffer_bytes_left)
-               n = host->buffer_bytes_left;
+       if (n > sgm->length)
+               n = sgm->length;
+       if (n > host->total_bytes_left)
+               n = host->total_bytes_left;
 
        /* Round up to handle odd number of bytes to transfer */
        nwords = DIV_ROUND_UP(n, 2);
 
-       host->buffer_bytes_left -= n;
+       sgm->consumed = n;
        host->total_bytes_left -= n;
        host->data->bytes_xfered += n;
 
        if (write) {
                __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA),
-                             host->buffer, nwords);
+                             buffer, nwords);
        } else {
                __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA),
-                            host->buffer, nwords);
+                            buffer, nwords);
        }
-
-       host->buffer += nwords;
 }
 
 #ifdef CONFIG_MMC_DEBUG
@@ -956,6 +947,7 @@ static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_reque
 static void
 mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
 {
+       unsigned int miter_flags = SG_MITER_ATOMIC; /* Used from IRQ */
        struct mmc_data *data = req->data;
        int i, use_dma = 1, block_size;
        struct scatterlist *sg;
@@ -990,7 +982,6 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
                }
        }
 
-       host->sg_idx = 0;
        if (use_dma) {
                enum dma_data_direction dma_data_dir;
                struct dma_async_tx_descriptor *tx;
@@ -1071,7 +1062,11 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
        OMAP_MMC_WRITE(host, BUF, 0x1f1f);
        host->total_bytes_left = data->blocks * block_size;
        host->sg_len = sg_len;
-       mmc_omap_sg_to_buf(host);
+       if (data->flags & MMC_DATA_READ)
+               miter_flags |= SG_MITER_TO_SG;
+       else
+               miter_flags |= SG_MITER_FROM_SG;
+       sg_miter_start(&host->sg_miter, data->sg, data->sg_len, miter_flags);
        host->dma_in_use = 0;
 }