[zircon][sdmmc][amlogic] Move the cache ops down to the driver that pins the pages

The right place to do the cache clean and invalidate is after the pages
are committed or pinned. So this changeset moves the cache ops from
sdmmc layer to the controller driver.

Tested: vim2: iochk -bs 16384 /dev/class/block/005 -- 15 times
pixelbook: iochk -bs 16384 /dev/class/block/008

Change-Id: I3e8c79c67508e6e89555f0ee8357e864b4b20741
diff --git a/system/dev/block/aml-sd-emmc/aml-sd-emmc.c b/system/dev/block/aml-sd-emmc/aml-sd-emmc.c
index c916b0b..8b0c861 100644
--- a/system/dev/block/aml-sd-emmc/aml-sd-emmc.c
+++ b/system/dev/block/aml-sd-emmc/aml-sd-emmc.c
@@ -658,6 +658,18 @@
         zxlogf(ERROR, "aml-sd-emmc: bti-pin failed with error %d\n", st);
         return st;
     }
+    if (req->cmd_flags & SDMMC_CMD_READ) {
+        st = zx_vmo_op_range(bop->rw.vmo, ZX_VMO_OP_CACHE_CLEAN_INVALIDATE,
+                             bop->rw.offset_vmo, bop->rw.length, NULL, 0);
+    } else {
+        st = zx_vmo_op_range(bop->rw.vmo, ZX_VMO_OP_CACHE_CLEAN,
+                             bop->rw.offset_vmo, bop->rw.length, NULL, 0);
+    }
+    if (st != ZX_OK) {
+        zxlogf(ERROR, "aml-sd-emmc: cache clean failed with error  %d\n", st);
+        return st;
+    }
+
     // cache this for zx_pmt_unpin() later
     req->pmt = pmt;
 
@@ -775,6 +787,20 @@
 static zx_status_t aml_sd_emmc_finish_req(aml_sd_emmc_t* dev, sdmmc_req_t* req) {
     zx_status_t st = ZX_OK;
     if (req->use_dma && req->pmt != ZX_HANDLE_INVALID) {
+        /*
+         * Clean the cache one more time after the DMA operation because there
+         * might be a possibility of cpu prefetching while the DMA operation is
+         * going on.
+         */
+        block_op_t* bop = &req->txn->bop;
+        if ((req->cmd_flags & SDMMC_CMD_READ) && req->use_dma) {
+            st = zx_vmo_op_range(bop->rw.vmo, ZX_VMO_OP_CACHE_CLEAN_INVALIDATE,
+                                       bop->rw.offset_vmo, bop->rw.length, NULL, 0);
+            if (st != ZX_OK) {
+                zxlogf(ERROR, "aml-sd-emmc: cache clean failed with error  %d\n", st);
+            }
+        }
+
         st = zx_pmt_unpin(req->pmt);
         if (st != ZX_OK) {
             zxlogf(ERROR, "aml-sd-emmc: error %d in pmt_unpin\n", st);
diff --git a/system/dev/block/sdhci/sdhci.c b/system/dev/block/sdhci/sdhci.c
index ad87c90..3855d83 100644
--- a/system/dev/block/sdhci/sdhci.c
+++ b/system/dev/block/sdhci/sdhci.c
@@ -420,6 +420,17 @@
         zxlogf(ERROR, "sdhci: error %d bti_pin\n", st);
         return st;
     }
+    if (req->cmd_flags & SDMMC_CMD_READ) {
+        st = zx_vmo_op_range(bop->rw.vmo, ZX_VMO_OP_CACHE_CLEAN_INVALIDATE,
+                             bop->rw.offset_vmo, bop->rw.length, NULL, 0);
+    } else {
+        st = zx_vmo_op_range(bop->rw.vmo, ZX_VMO_OP_CACHE_CLEAN,
+                             bop->rw.offset_vmo, bop->rw.length, NULL, 0);
+    }
+    if (st != ZX_OK) {
+        zxlogf(ERROR, "sdhci: cache clean failed with error  %d\n", st);
+        return st;
+    }
     // cache this for zx_pmt_unpin() later
     req->pmt = pmt;
 
@@ -558,6 +569,19 @@
 static zx_status_t sdhci_finish_req(sdhci_device_t* dev, sdmmc_req_t* req) {
     zx_status_t st = ZX_OK;
     if (req->use_dma && req->pmt != ZX_HANDLE_INVALID) {
+        /*
+         * Clean the cache one more time after the DMA operation because there
+         * might be a possibility of cpu prefetching while the DMA operation is
+         * going on.
+         */
+        block_op_t* bop = &req->txn->bop;
+        if ((req->cmd_flags & SDMMC_CMD_READ) && req->use_dma) {
+            st = zx_vmo_op_range(bop->rw.vmo, ZX_VMO_OP_CACHE_CLEAN_INVALIDATE,
+                                       bop->rw.offset_vmo, bop->rw.length, NULL, 0);
+            if (st != ZX_OK) {
+                zxlogf(ERROR, "sdhci: cache clean failed with error  %d\n", st);
+            }
+        }
         st = zx_pmt_unpin(req->pmt);
         if (st != ZX_OK) {
             zxlogf(ERROR, "sdhci: error %d in pmt_unpin\n", st);
diff --git a/system/dev/block/sdmmc/sdmmc.c b/system/dev/block/sdmmc/sdmmc.c
index 88179e7..c967bfa 100644
--- a/system/dev/block/sdmmc/sdmmc.c
+++ b/system/dev/block/sdmmc/sdmmc.c
@@ -249,7 +249,6 @@
 }
 
 static void sdmmc_do_txn(sdmmc_device_t* dev, sdmmc_txn_t* txn) {
-    bool is_read = true;
     uint32_t cmd_idx = 0;
     uint32_t cmd_flags = 0;
 
@@ -263,7 +262,6 @@
             cmd_idx = SDMMC_READ_BLOCK;
             cmd_flags = SDMMC_READ_BLOCK_FLAGS;
         }
-        is_read = true;
         break;
     case BLOCK_OP_WRITE:
         if (txn->bop.rw.length > 1) {
@@ -273,7 +271,6 @@
             cmd_idx = SDMMC_WRITE_BLOCK;
             cmd_flags = SDMMC_WRITE_BLOCK_FLAGS;
         }
-        is_read = false;
         break;
     case BLOCK_OP_FLUSH:
         block_complete(&txn->bop, ZX_OK);
@@ -306,19 +303,6 @@
 
     zx_status_t st = ZX_OK;
     if (sdmmc_use_dma(dev)) {
-        if (is_read) {
-            st = zx_vmo_op_range(txn->bop.rw.vmo, ZX_VMO_OP_CACHE_CLEAN_INVALIDATE,
-                                 txn->bop.rw.offset_vmo, txn->bop.rw.length, NULL, 0);
-        } else {
-            st = zx_vmo_op_range(txn->bop.rw.vmo, ZX_VMO_OP_CACHE_CLEAN,
-                                 txn->bop.rw.offset_vmo, txn->bop.rw.length, NULL, 0);
-        }
-        if (st != ZX_OK) {
-            zxlogf(TRACE, "sdmmc: do_txn cacheop error %d\n", st);
-            block_complete(&txn->bop, st);
-            return;
-        }
-
         req->use_dma = true;
         req->virt = NULL;
         req->pmt = ZX_HANDLE_INVALID;