Can this be pushed upstream in a non-RTEMS specific way?
On Wed, Sep 9, 2020 at 5:16 AM Christian Mauderer <christian.maude...@embedded-brains.de> wrote: > > Some bits are in the wrong order. Beneath that, the interrupts can occur > in an unexpected order. The DATA_AVAIL interrupt can occur at the same > time as the DMA interrupt (or slightly before it). With that, the DMA > and PIO interrupt handling doesn't work well together. Beneath that the > DMA interrupt isn't only executed at block ends but also if all data is > transfered. That can lead to problems with the DATA_END interrupt. > Therefore check whether there is really data left to unload. > > Update #3869 > --- > freebsd/sys/dev/sdhci/fsl_sdhci.c | 41 +++++++++++++++++++++++++++++++ > freebsd/sys/dev/sdhci/sdhci.c | 40 ++++++++++++++++++++++++++++++ > 2 files changed, 81 insertions(+) > > diff --git a/freebsd/sys/dev/sdhci/fsl_sdhci.c > b/freebsd/sys/dev/sdhci/fsl_sdhci.c > index be3d1de3..acef1c4a 100644 > --- a/freebsd/sys/dev/sdhci/fsl_sdhci.c > +++ b/freebsd/sys/dev/sdhci/fsl_sdhci.c > @@ -74,6 +74,9 @@ uint32_t mpc85xx_get_system_clock(void); > #endif /* __rtems__ */ > #endif > > +#ifndef __rtems__ > +#include <bsp.h> > +#endif /* __rtems__ */ > #include <dev/gpio/gpiobusvar.h> > > #include <dev/ofw/ofw_bus.h> > @@ -168,6 +171,16 @@ struct fsl_sdhci_softc { > #define SDHC_PROT_CDSS (1 << 7) > > #define SDHC_SYS_CTRL 0x2c > +#ifdef __rtems__ > + > +/* > + * Freescale messed up the INT DMA ERR bit and placed it at bit 28 instead of > + * bit 25 which would be standard. > + */ > +#define SDHC_INT_DMAES (1 << 28) > + > +#define SDHC_CAN_DO_ADMA2 0x00100000 > +#endif /* __rtems__ */ > > /* > * The clock enable bits exist in different registers for ESDHC vs USDHC, but > @@ -349,6 +362,16 @@ fsl_sdhci_read_4(device_t dev, struct sdhci_slot *slot, > bus_size_t off) > val32 &= ~SDHCI_CAN_VDD_180; > val32 &= ~SDHCI_CAN_DO_SUSPEND; > val32 |= SDHCI_CAN_DO_8BITBUS; > +#ifdef __rtems__ > + /* > + * Freescale signals ADMA2 capability via bit 20 (which would > be > + * ADMA1) instead of 19. > + */ > + if (val32 & SDHC_CAN_DO_ADMA2) { > + val32 &= ~SDHC_CAN_DO_ADMA2; > + val32 |= SDHCI_CAN_DO_ADMA2; > + } > +#endif /* __rtems__ */ > return (val32); > } > > @@ -373,6 +396,13 @@ fsl_sdhci_read_4(device_t dev, struct sdhci_slot *slot, > bus_size_t off) > * command with an R1B response, mix it into the hardware status. > */ > if (off == SDHCI_INT_STATUS) { > +#ifdef __rtems__ > + /* Fix messed up DMA error. */ > + if (val32 & SDHC_INT_DMAES) { > + val32 &= ~SDHC_INT_DMAES; > + val32 |= SDHCI_INT_ADMAERR; > + } > +#endif /* __rtems__ */ > return (val32 | sc->r1bfix_intmask); > } > > @@ -519,6 +549,15 @@ fsl_sdhci_write_4(device_t dev, struct sdhci_slot *slot, > bus_size_t off, uint32_ > if (off == SDHCI_INT_STATUS) { > sc->r1bfix_intmask &= ~val; > } > +#ifdef __rtems__ > + /* Fix messed up DMA error. */ > + if (off == SDHCI_INT_STATUS || off == SDHCI_INT_ENABLE || off == > SDHCI_SIGNAL_ENABLE) { > + if (val & SDHCI_INT_ADMAERR) { > + val &= ~SDHCI_INT_ADMAERR; > + val |= SDHC_INT_DMAES; > + } > + } > +#endif /* __rtems__ */ > > WR4(sc, off, val); > } > @@ -884,10 +923,12 @@ fsl_sdhci_attach(device_t dev) > > sc->slot.quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; > > +#if !defined(__rtems__) || !defined(LIBBSP_ARM_IMX_BSP_H) > /* > * DMA is not really broken, I just haven't implemented it yet. > */ > sc->slot.quirks |= SDHCI_QUIRK_BROKEN_DMA; > +#endif /* __rtems__ */ > > /* > * Set the buffer watermark level to 128 words (512 bytes) for both > read > diff --git a/freebsd/sys/dev/sdhci/sdhci.c b/freebsd/sys/dev/sdhci/sdhci.c > index ed6010e8..53d86fe8 100644 > --- a/freebsd/sys/dev/sdhci/sdhci.c > +++ b/freebsd/sys/dev/sdhci/sdhci.c > @@ -68,6 +68,9 @@ __FBSDID("$FreeBSD$"); > #include <rtems/bsd/local/sdhci_if.h> > > #include <rtems/bsd/local/opt_mmccam.h> > +#ifdef __rtems__ > +#include <bsp.h> > +#endif /* __rtems__ */ > > SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver"); > > @@ -766,6 +769,17 @@ sdhci_dma_alloc(struct sdhci_slot *slot) > else > slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_512K; > } > +#ifdef __rtems__ > +#if defined(LIBBSP_ARM_IMX_BSP_H) > + /* > + * i.MX6ULL doesn't have the SDMA Buffer Boundary bits. Instead the > + * BLKSIZE is one bit larger and would overlap the Buffer Boundary. > + * Setting the Buffer Boundary to 4K makes sure that the highest > BLKSIZE > + * bit is always 0. > + */ > + slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_4K; > +#endif > +#endif /* __rtems__ */ > slot->sdma_bbufsz = SDHCI_SDMA_BNDRY_TO_BBUFSZ(slot->sdma_boundary); > > /* > @@ -1896,6 +1910,10 @@ sdhci_start_data(struct sdhci_slot *slot, const struct > mmc_data *data) > BUS_DMASYNC_PREWRITE); > } > WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); > +#ifdef __rtems__ > + /* Avoid PIO interrupt if we use DMA */ > + slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | > SDHCI_INT_SPACE_AVAIL); > +#endif /* __rtems__ */ > /* > * Interrupt aggregation: Mask border interrupt for the last > * bounce buffer and unmask otherwise. > @@ -1932,15 +1950,27 @@ sdhci_finish_data(struct sdhci_slot *slot) > WR4(slot, SDHCI_SIGNAL_ENABLE, > slot->intmask |= SDHCI_INT_RESPONSE); > } > +#ifdef __rtems__ > + /* Restore PIO interrupts in case they are necessary elsewhere */ > + if (slot->flags & SDHCI_USE_DMA) { > + slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; > + } > +#endif /* __rtems__ */ > /* Unload rest of data from DMA buffer. */ > if (!slot->data_done && (slot->flags & SDHCI_USE_DMA) && > slot->curcmd->data != NULL) { > if (data->flags & MMC_DATA_READ) { > left = data->len - slot->offset; > +#ifdef __rtems__ > + if (left > 0) { > +#endif /* __rtems__ */ > bus_dmamap_sync(slot->dmatag, slot->dmamap, > BUS_DMASYNC_POSTREAD); > memcpy((u_char*)data->data + slot->offset, > slot->dmamem, > ulmin(left, slot->sdma_bbufsz)); > +#ifdef __rtems__ > + } > +#endif /* __rtems__ */ > } else > bus_dmamap_sync(slot->dmatag, slot->dmamap, > BUS_DMASYNC_POSTWRITE); > @@ -2201,8 +2231,15 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t > intmask) > BUS_DMASYNC_POSTWRITE); > } > /* ... and reload it again. */ > +#ifdef __rtems__ > + slot->offset += ulmin(left, sdma_bbufsz); > +#else /* __rtems__ */ > slot->offset += sdma_bbufsz; > +#endif /* __rtems__ */ > left = data->len - slot->offset; > +#ifdef __rtems__ > + if (left > 0) { > +#endif /* __rtems__ */ > if (data->flags & MMC_DATA_READ) { > bus_dmamap_sync(slot->dmatag, slot->dmamap, > BUS_DMASYNC_PREREAD); > @@ -2222,6 +2259,9 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t > intmask) > } > /* Restart DMA. */ > WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); > +#ifdef __rtems__ > + } > +#endif /* __rtems__ */ > } > /* We have got all data. */ > if (intmask & SDHCI_INT_DATA_END) { > -- > 2.26.2 > > _______________________________________________ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel