Some targets support only flushing or invalidating complete cache lines.
In this cases misaligned buffers might lead to unexpected results. This
patch adds a flag that allows drivers to signal to the bus dma driver
that it is OK to round a buffer to the next full cache line. That's for
example necessary if a driver wants to send out 14 byte via a USB DMA.
Only the driver knows whether these 14 bytes are located in an otherwise
unused cache line aligned buffer.
---
 freebsd/sys/dev/usb/usb_busdma.c             | 31 ++++++++++++++++++++
 freebsd/sys/dev/usb/usb_busdma.h             |  5 ++++
 freebsd/sys/dev/usb/usb_transfer.c           | 20 +++++++++++++
 freebsd/sys/dev/usb/usbdi.h                  |  4 +++
 freebsd/sys/sys/bus_dma.h                    |  6 ++++
 rtemsbsd/include/machine/rtems-bsd-bus-dma.h |  3 ++
 rtemsbsd/rtems/rtems-kernel-bus-dma-mbuf.c   |  3 ++
 rtemsbsd/rtems/rtems-kernel-bus-dma.c        |  9 ++++++
 8 files changed, 81 insertions(+)

diff --git a/freebsd/sys/dev/usb/usb_busdma.c b/freebsd/sys/dev/usb/usb_busdma.c
index dc52fe15..b74f0823 100644
--- a/freebsd/sys/dev/usb/usb_busdma.c
+++ b/freebsd/sys/dev/usb/usb_busdma.c
@@ -67,6 +67,9 @@
 #include <dev/usb/usb_controller.h>
 #include <dev/usb/usb_bus.h>
 #endif                 /* USB_GLOBAL_INCLUDE_FILE */
+#ifdef __rtems__
+#include <machine/rtems-bsd-cache.h>
+#endif /* __rtems__ */
 
 #if USB_HAVE_BUSDMA
 static void    usb_dma_tag_create(struct usb_dma_tag *, usb_size_t, 
usb_size_t);
@@ -543,6 +546,15 @@ usb_pc_alloc_mem(struct usb_page_cache *pc, struct 
usb_page *pg,
 
        uptag = pc->tag_parent;
 
+#if defined(__rtems__) && defined(CPU_DATA_CACHE_ALIGNMENT)
+       while (align % CPU_DATA_CACHE_ALIGNMENT != 0) {
+               align *= 2;
+       }
+       if (size % CPU_DATA_CACHE_ALIGNMENT != 0) {
+               size = (size + (CPU_DATA_CACHE_ALIGNMENT - 1)) &
+                   ~(CPU_DATA_CACHE_ALIGNMENT - 1);
+       }
+#endif /* __rtems__ */
        if (align != 1) {
                /*
                 * The alignment must be greater or equal to the
@@ -605,7 +617,12 @@ usb_pc_alloc_mem(struct usb_page_cache *pc, struct 
usb_page *pg,
        /* load memory into DMA */
        err = bus_dmamap_load(
            utag->tag, map, ptr, size, &usb_pc_alloc_mem_cb,
+#if defined(__rtems__) && CPU_DATA_CACHE_ALIGNMENT
+           pc, (BUS_DMA_WAITOK | BUS_DMA_COHERENT |
+           BUS_DMA_DO_CACHE_LINE_BLOW_UP));
+#else /* __rtems__ */
            pc, (BUS_DMA_WAITOK | BUS_DMA_COHERENT));
+#endif /* __rtems__ */
 
        if (err == EINPROGRESS) {
                cv_wait(uptag->cv, uptag->mtx);
@@ -662,6 +679,12 @@ usb_pc_free_mem(struct usb_page_cache *pc)
 uint8_t
 usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync)
 {
+#ifdef __rtems__
+       int flags;
+
+       flags = pc->dma_do_cache_line_blow_up ?
+           BUS_DMA_DO_CACHE_LINE_BLOW_UP : 0;
+#endif /* __rtems__ */
        /* setup page cache */
        pc->page_offset_buf = 0;
        pc->page_offset_end = size;
@@ -687,7 +710,11 @@ usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t 
size, uint8_t sync)
                         */
                        err = bus_dmamap_load(
                            pc->tag, pc->map, pc->buffer, size,
+#ifndef __rtems__
                            &usb_pc_alloc_mem_cb, pc, BUS_DMA_WAITOK);
+#else /* __rtems__ */
+                           &usb_pc_alloc_mem_cb, pc, BUS_DMA_WAITOK | flags);
+#endif /* __rtems__ */
                        if (err == EINPROGRESS) {
                                cv_wait(uptag->cv, uptag->mtx);
                                err = 0;
@@ -709,7 +736,11 @@ usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t 
size, uint8_t sync)
                         */
                        if (bus_dmamap_load(
                            pc->tag, pc->map, pc->buffer, size,
+#ifndef __rtems__
                            &usb_pc_load_mem_cb, pc, BUS_DMA_WAITOK)) {
+#else /* __rtems__ */
+                           &usb_pc_load_mem_cb, pc, BUS_DMA_WAITOK | flags)) {
+#endif /* __rtems__ */
                        }
                }
        } else {
diff --git a/freebsd/sys/dev/usb/usb_busdma.h b/freebsd/sys/dev/usb/usb_busdma.h
index d75e67ee..03eca30d 100644
--- a/freebsd/sys/dev/usb/usb_busdma.h
+++ b/freebsd/sys/dev/usb/usb_busdma.h
@@ -102,6 +102,11 @@ struct usb_page_cache {
                                         * from the memory. Else write. */
        uint8_t ismultiseg:1;           /* set if we can have multiple
                                         * segments */
+#ifdef __rtems__
+       uint8_t dma_do_cache_line_blow_up:1;
+                                       /* set if it is OK to align the buffer
+                                        * start and end to next cache line */
+#endif /* __rtems__ */
 #endif
 };
 
diff --git a/freebsd/sys/dev/usb/usb_transfer.c 
b/freebsd/sys/dev/usb/usb_transfer.c
index 3b67c20c..ee1e4c28 100644
--- a/freebsd/sys/dev/usb/usb_transfer.c
+++ b/freebsd/sys/dev/usb/usb_transfer.c
@@ -2195,6 +2195,9 @@ usbd_xfer_set_frame_data(struct usb_xfer *xfer, 
usb_frcount_t frindex,
        /* set virtual address to load and length */
        xfer->frbuffers[frindex].buffer = ptr;
        usbd_xfer_set_frame_len(xfer, frindex, len);
+#ifdef __rtems__
+       xfer->frbuffers[frindex].dma_do_cache_line_blow_up = 0;
+#endif /* __rtems__ */
 }
 
 void
@@ -2209,6 +2212,23 @@ usbd_xfer_frame_data(struct usb_xfer *xfer, 
usb_frcount_t frindex,
                *len = xfer->frlengths[frindex];
 }
 
+#ifdef __rtems__
+/*------------------------------------------------------------------------*
+ *     usbd_xfer_frame_allow_cache_line_blow_up
+ *
+ * Set a flag that the buffer start and end belonging to this frame can be
+ * aligned to the next cache line on sync and flush.
+ *------------------------------------------------------------------------*/
+void
+usbd_xfer_frame_allow_cache_line_blow_up(struct usb_xfer *xfer,
+    usb_frcount_t frindex)
+{
+       KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
+
+       xfer->frbuffers[frindex].dma_do_cache_line_blow_up = 1;
+}
+
+#endif /* __rtems__ */
 /*------------------------------------------------------------------------*
  *     usbd_xfer_old_frame_length
  *
diff --git a/freebsd/sys/dev/usb/usbdi.h b/freebsd/sys/dev/usb/usbdi.h
index 0a393844..834810a8 100644
--- a/freebsd/sys/dev/usb/usbdi.h
+++ b/freebsd/sys/dev/usb/usbdi.h
@@ -640,6 +640,10 @@ void       usbd_xfer_set_frame_data(struct usb_xfer *xfer, 
usb_frcount_t frindex,
            void *ptr, usb_frlength_t len);
 void   usbd_xfer_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex,
            void **ptr, int *len);
+#ifdef __rtems__
+void   usbd_xfer_frame_allow_cache_line_blow_up(struct usb_xfer *xfer,
+           usb_frcount_t frindex);
+#endif /* __rtems__ */
 void   usbd_xfer_set_frame_offset(struct usb_xfer *xfer, usb_frlength_t offset,
            usb_frcount_t frindex);
 usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer);
diff --git a/freebsd/sys/sys/bus_dma.h b/freebsd/sys/sys/bus_dma.h
index e99d8ece..d5a08be0 100644
--- a/freebsd/sys/sys/bus_dma.h
+++ b/freebsd/sys/sys/bus_dma.h
@@ -107,6 +107,12 @@
 #define        BUS_DMA_KEEP_PG_OFFSET  0x400
 
 #define        BUS_DMA_LOAD_MBUF       0x800
+#ifdef __rtems__
+/*
+ * Hint that the start address and size can be aligned to the next cache line.
+ */
+#define BUS_DMA_DO_CACHE_LINE_BLOW_UP  0x80000000
+#endif /* __rtems__ */
 
 /* Forwards needed by prototypes below. */
 union ccb;
diff --git a/rtemsbsd/include/machine/rtems-bsd-bus-dma.h 
b/rtemsbsd/include/machine/rtems-bsd-bus-dma.h
index ac970537..e9566882 100644
--- a/rtemsbsd/include/machine/rtems-bsd-bus-dma.h
+++ b/rtemsbsd/include/machine/rtems-bsd-bus-dma.h
@@ -75,6 +75,9 @@ struct bus_dma_tag {
 struct bus_dmamap {
        void *buffer_begin;
        bus_size_t buffer_size;
+       int flags;
+/* OK to flush / invalidate the complete cache line */
+#define DMAMAP_CACHE_ALIGNED   (1 << 0)
 };
 
 int
diff --git a/rtemsbsd/rtems/rtems-kernel-bus-dma-mbuf.c 
b/rtemsbsd/rtems/rtems-kernel-bus-dma-mbuf.c
index c435fd74..56ead4ee 100644
--- a/rtemsbsd/rtems/rtems-kernel-bus-dma-mbuf.c
+++ b/rtemsbsd/rtems/rtems-kernel-bus-dma-mbuf.c
@@ -69,6 +69,9 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map,
                int first = 1;
                bus_addr_t lastaddr = 0;
                struct mbuf *m;
+               if ((flags & BUS_DMA_LOAD_MBUF) != 0) {
+                       map->flags |= DMAMAP_CACHE_ALIGNED;
+               }
 
                for (m = m0; m != NULL && error == 0; m = m->m_next) {
                        if (m->m_len > 0) {
diff --git a/rtemsbsd/rtems/rtems-kernel-bus-dma.c 
b/rtemsbsd/rtems/rtems-kernel-bus-dma.c
index 8c15e92b..4dc634f3 100644
--- a/rtemsbsd/rtems/rtems-kernel-bus-dma.c
+++ b/rtemsbsd/rtems/rtems-kernel-bus-dma.c
@@ -365,9 +365,13 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void 
*buf,
 
        map->buffer_begin = buf;
        map->buffer_size = buflen;
+       if ((flags & BUS_DMA_DO_CACHE_LINE_BLOW_UP) != 0) {
+               map->flags |= DMAMAP_CACHE_ALIGNED;
+       }
 
        lastaddr = (vm_offset_t)0;
        nsegs = 0;
+
        error = bus_dmamap_load_buffer(dmat, dm_segments, buf, buflen,
            NULL, flags, &lastaddr, &nsegs, 1);
 
@@ -397,6 +401,11 @@ bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, 
bus_dmasync_op_t op)
        uintptr_t begin = (uintptr_t) map->buffer_begin;
        uintptr_t end = begin + size;
 
+       if ((map->flags & DMAMAP_CACHE_ALIGNED) != 0) {
+               begin &= ~CLMASK;
+               end = (end + CLMASK) & ~CLMASK;
+               size = end - begin;
+       }
        if ((op & BUS_DMASYNC_PREWRITE) != 0 && (op & BUS_DMASYNC_PREREAD) == 
0) {
                rtems_cache_flush_multiple_data_lines((void *) begin, size);
        }
-- 
2.26.2

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to