The branch releng/13.0 has been updated by mmel:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=15e64578cb1eab9b62b808e2ed4905294503a2c3

commit 15e64578cb1eab9b62b808e2ed4905294503a2c3
Author:     Michal Meloun <[email protected]>
AuthorDate: 2021-01-21 14:06:19 +0000
Commit:     Michal Meloun <[email protected]>
CommitDate: 2021-02-13 12:27:48 +0000

    dwmmc: Multiple busdma fixes.
    
    - limit maximum segment size to 2048 bytes.  Although dwmmc supports a 
buffer
      fragment with a maximum length of 4095 bytes, use the nearest lower power
      of two as the maximum fragment size. Otherwise, busdma create excessive
      buffer fragments.
    - fix off by one error in computation of the maximum data transfer length.
    - in addition, reserve two DMA descriptors that can be used by busdma
      bouncing. The beginning or end of the buffer can be misaligned.
    - Don’t ignore errors passed to bus_dmamap_load() callback function.
    - In theory, a DMA engine may be running at time when next dma descriptor is
      constructed. Create a full DMA descriptor before OWN bit is set.
    
    Approved by:    re (gjb)
    
    (cherry picked from commit 8727c174b0fe44766bb7ea765dac6d5f82818103)
    (cherry picked from commit e8dfdf40bed9b016b4db2ed008d2d8333073f38c)
---
 sys/dev/mmc/host/dwmmc.c | 47 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/sys/dev/mmc/host/dwmmc.c b/sys/dev/mmc/host/dwmmc.c
index 11521257ee0a..b31bb0d4e68b 100644
--- a/sys/dev/mmc/host/dwmmc.c
+++ b/sys/dev/mmc/host/dwmmc.c
@@ -107,8 +107,7 @@ __FBSDID("$FreeBSD$");
 #define        CARD_INIT_DONE  0x04
 
 #define        DWMMC_DATA_ERR_FLAGS    (SDMMC_INTMASK_DRT | SDMMC_INTMASK_DCRC 
\
-                               |SDMMC_INTMASK_HTO | SDMMC_INTMASK_SBE \
-                               |SDMMC_INTMASK_EBE)
+                               |SDMMC_INTMASK_SBE | SDMMC_INTMASK_EBE)
 #define        DWMMC_CMD_ERR_FLAGS     (SDMMC_INTMASK_RTO | SDMMC_INTMASK_RCRC 
\
                                |SDMMC_INTMASK_RE)
 #define        DWMMC_ERR_FLAGS         (DWMMC_DATA_ERR_FLAGS | 
DWMMC_CMD_ERR_FLAGS \
@@ -134,7 +133,16 @@ struct idmac_desc {
 #define        IDMAC_DESC_SEGS (PAGE_SIZE / (sizeof(struct idmac_desc)))
 #define        IDMAC_DESC_SIZE (sizeof(struct idmac_desc) * IDMAC_DESC_SEGS)
 #define        DEF_MSIZE       0x2     /* Burst size of multiple transaction */
-#define        IDMAC_MAX_SIZE  4096
+/*
+ * Size field in DMA descriptor is 13 bits long (up to 4095 bytes),
+ * but must be a multiple of the data bus size.Additionally, we must ensure
+ * that bus_dmamap_load() doesn't additionally fragments buffer (because it
+ * is processed with page size granularity). Thus limit fragment size to half
+ * of page.
+ * XXX switch descriptor format to array and use second buffer pointer for
+ * second half of page
+ */
+#define        IDMAC_MAX_SIZE  2048
 
 static void dwmmc_next_operation(struct dwmmc_softc *);
 static int dwmmc_setup_bus(struct dwmmc_softc *, int);
@@ -165,8 +173,11 @@ static void
 dwmmc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
 
+       if (nsegs != 1)
+               panic("%s: nsegs != 1 (%d)\n", __func__, nsegs);
        if (error != 0)
-               return;
+               panic("%s: error != 0 (%d)\n", __func__, error);
+
        *(bus_addr_t *)arg = segs[0].ds_addr;
 }
 
@@ -176,15 +187,13 @@ dwmmc_ring_setup(void *arg, bus_dma_segment_t *segs, int 
nsegs, int error)
        struct dwmmc_softc *sc;
        int idx;
 
-       if (error != 0)
-               return;
-
        sc = arg;
-
        dprintf("nsegs %d seg0len %lu\n", nsegs, segs[0].ds_len);
+       if (error != 0)
+               panic("%s: error != 0 (%d)\n", __func__, error);
 
        for (idx = 0; idx < nsegs; idx++) {
-               sc->desc_ring[idx].des0 = (DES0_OWN | DES0_DIC | DES0_CH);
+               sc->desc_ring[idx].des0 = DES0_DIC | DES0_CH;
                sc->desc_ring[idx].des1 = segs[idx].ds_len & DES1_BS1_MASK;
                sc->desc_ring[idx].des2 = segs[idx].ds_addr;
 
@@ -195,6 +204,8 @@ dwmmc_ring_setup(void *arg, bus_dma_segment_t *segs, int 
nsegs, int error)
                        sc->desc_ring[idx].des0 &= ~(DES0_DIC | DES0_CH);
                        sc->desc_ring[idx].des0 |= DES0_LD;
                }
+               wmb();
+               sc->desc_ring[idx].des0 |= DES0_OWN;
        }
 }
 
@@ -277,7 +288,7 @@ dma_setup(struct dwmmc_softc *sc)
 
        error = bus_dma_tag_create(
            bus_get_dma_tag(sc->dev),   /* Parent tag. */
-           CACHE_LINE_SIZE, 0,         /* alignment, boundary */
+           8, 0,                       /* alignment, boundary */
            BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
            BUS_SPACE_MAXADDR,          /* highaddr */
            NULL, NULL,                 /* filter, filterarg */
@@ -786,7 +797,7 @@ dwmmc_attach(device_t dev)
 fail:
         mtx_unlock(&sc->sim_mtx);
 #endif
-       /* 
+       /*
         * Schedule a card detection as we won't get an interrupt
         * if the card is inserted when we attach
         */
@@ -900,8 +911,8 @@ dwmmc_update_ios(device_t brdev, device_t reqdev)
        sc = device_get_softc(brdev);
        ios = &sc->host.ios;
 
-       dprintf("Setting up clk %u bus_width %d\n",
-               ios->clock, ios->bus_width);
+       dprintf("Setting up clk %u bus_width %d, timming: %d\n",
+               ios->clock, ios->bus_width, ios->timing);
 
        if (ios->bus_width == bus_width_8)
                WRITE4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT);
@@ -985,7 +996,7 @@ dma_prepare(struct dwmmc_softc *sc, struct mmc_command *cmd)
        reg = READ4(sc, SDMMC_INTMASK);
        reg &= ~(SDMMC_INTMASK_TXDR | SDMMC_INTMASK_RXDR);
        WRITE4(sc, SDMMC_INTMASK, reg);
-
+       dprintf("%s: bus_dmamap_load size: %zu\n", __func__, data->len);
        err = bus_dmamap_load(sc->buf_tag, sc->buf_map,
                data->data, data->len, dwmmc_ring_setup,
                sc, BUS_DMA_NOWAIT);
@@ -1358,7 +1369,13 @@ dwmmc_read_ivar(device_t bus, device_t child, int which, 
uintptr_t *result)
                *(int *)result = sc->host.caps;
                break;
        case MMCBR_IVAR_MAX_DATA:
-               *(int *)result = (IDMAC_MAX_SIZE * IDMAC_DESC_SEGS) / 
MMC_SECTOR_SIZE;
+               /*
+                * Busdma may bounce buffers, so we must reserve 2 descriptors
+                * (on start and on end) for bounced fragments.
+                *
+                */
+               *(int *)result = (IDMAC_MAX_SIZE * IDMAC_DESC_SEGS) /
+                   MMC_SECTOR_SIZE - 3;
                break;
        case MMCBR_IVAR_TIMING:
                *(int *)result = sc->host.ios.timing;
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to