mmc: meson-gx: check for scatterlist size alignment in block mode
[linux-2.6-microblaze.git] / drivers / mmc / host / meson-gx-mmc.c
index 13f6a2c..eb6c02b 100644 (file)
@@ -227,7 +227,6 @@ static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
        struct mmc_data *data = mrq->data;
        struct scatterlist *sg;
        int i;
-       bool use_desc_chain_mode = true;
 
        /*
         * When Controller DMA cannot directly access DDR memory, disable
@@ -237,25 +236,33 @@ static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
        if (host->dram_access_quirk)
                return;
 
-       /*
-        * Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
-        * reported. For some strange reason this occurs in descriptor
-        * chain mode only. So let's fall back to bounce buffer mode
-        * for command SD_IO_RW_EXTENDED.
-        */
-       if (mrq->cmd->opcode == SD_IO_RW_EXTENDED)
-               return;
+       if (data->blocks > 1) {
+               /*
+                * In block mode DMA descriptor format, "length" field indicates
+                * number of blocks and there is no way to pass DMA size that
+                * is not multiple of SDIO block size, making it impossible to
+                * tie more than one memory buffer with single SDIO block.
+                * Block mode sg buffer size should be aligned with SDIO block
+                * size, otherwise chain mode could not be used.
+                */
+               for_each_sg(data->sg, sg, data->sg_len, i) {
+                       if (sg->length % data->blksz) {
+                               WARN_ONCE(1, "unaligned sg len %u blksize %u\n",
+                                         sg->length, data->blksz);
+                               return;
+                       }
+               }
+       }
 
-       for_each_sg(data->sg, sg, data->sg_len, i)
+       for_each_sg(data->sg, sg, data->sg_len, i) {
                /* check for 8 byte alignment */
-               if (sg->offset & 7) {
+               if (sg->offset % 8) {
                        WARN_ONCE(1, "unaligned scatterlist buffer\n");
-                       use_desc_chain_mode = false;
-                       break;
+                       return;
                }
+       }
 
-       if (use_desc_chain_mode)
-               data->host_cookie |= SD_EMMC_DESC_CHAIN_MODE;
+       data->host_cookie |= SD_EMMC_DESC_CHAIN_MODE;
 }
 
 static inline bool meson_mmc_desc_chain_mode(const struct mmc_data *data)