The SDHCI DMA path already funnels through dma_map_single() (invalidate
the destination before a read) and dma_unmap_single() (invalidate it
again afterwards), but two things kept that from working in the PBL:

  - sdhci_teardown_data() short-circuited on IN_PBL, so the post-transfer
    invalidate never ran. Drop the IN_PBL guard; with CONFIG_PBL_HAS_DMA
    dma_unmap_single() now does the cache maintenance, and without it the
    call is a no-op stub, so a plain PBL is unaffected.

  - the ADMA2 descriptor table in the PBL is a plain buffer (cacheable
    once the MMU is on) rather than the dma_alloc_coherent() region used
    in barebox proper, so the CPU-written descriptors could sit in the
    D-cache while the engine reads stale DRAM. Clean the table out to
    memory right after building it. Guarded by IN_PBL (proper keeps its
    coherent table) and a no-op without CONFIG_PBL_HAS_DMA.

Together with CONFIG_PBL_HAS_DMA this makes SDMA and ADMA2 transfers
coherent in the PBL with the MMU on. No functional change for barebox
proper or for a PBL built without PBL_HAS_DMA.

Assisted-by: Claude Opus 4.8 (1M context)
Signed-off-by: Johannes Schneider <[email protected]>

---

Notes:
    v2:
    - New patch. Wire the SDHCI PBL transfer path to the new PBL DMA API
      (post-transfer invalidate + ADMA descriptor-table flush).

 drivers/mci/sdhci.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 8ed8a59342..8108e0b54f 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -732,6 +732,12 @@ void sdhci_setup_data_dma(struct sdhci *sdhci, struct 
mci_data *data,
                        return;
                }
                sdhci_set_adma_addr(sdhci, sdhci->adma_addr);
+
+               /* PBL descriptor table is cacheable; flush it before the 
engine reads it. */
+               if (IN_PBL)
+                       dma_sync_single_for_device(dev, sdhci->adma_addr,
+                                                  sdhci->adma_table_sz,
+                                                  DMA_TO_DEVICE);
        } else {
                sdhci_set_sdma_addr(sdhci, *dma);
        }
@@ -743,7 +749,7 @@ void sdhci_teardown_data(struct sdhci *sdhci,
        struct device *dev = sdhci_dev(sdhci);
        unsigned nbytes;
 
-       if (IN_PBL || !data || dma_mapping_error(dev, dma))
+       if (!data || dma_mapping_error(dev, dma))
                return;
 
        nbytes = data->blocks * data->blocksize;
-- 
2.43.0


Reply via email to