r174051 | cognet | 2007-11-28 14:21:17 -0800 (Wed, 28 Nov 2007) | 6 lines Correct the logic : we can just invalidate the cache lines, and not write-back them, only if PREWRITE is not set, and if the buffer is cache-line aligned. MFC After: 1 week Index: sys/arm/arm/busdma_machdep.c =================================================================== --- sys/arm/arm/busdma_machdep.c (revision 174050) +++ sys/arm/arm/busdma_machdep.c (revision 174051) @@ -1090,7 +1090,7 @@ cpu_l2cache_wb_range((vm_offset_t)buf, len); } if (op & BUS_DMASYNC_PREREAD) { - if ((op & BUS_DMASYNC_PREWRITE) || + if (!(op & BUS_DMASYNC_PREWRITE) && ((((vm_offset_t)(buf) | len) & arm_dcache_align_mask) == 0)) { cpu_dcache_inv_range((vm_offset_t)buf, len); cpu_l2cache_inv_range((vm_offset_t)buf, len); r177457 | sam | 2008-03-20 09:04:13 -0700 (Thu, 20 Mar 2008) | 8 lines Correct cache handling for xfer requests marked URQ_REQUEST: many (if not all uses) involve a read but usbd_start_transfer only does a PREWRITE; change this to BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE as I'm not sure if any users do write+read. Reviewed by: cognet, imp MFC after: 1 month Index: sys/dev/usb/usbdi.c =================================================================== --- sys/dev/usb/usbdi.c (revision 177456) +++ sys/dev/usb/usbdi.c (revision 177457) @@ -384,7 +384,8 @@ * sync the dmamap for the request data in the SETUP * packet. */ - bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(tag, dmap->map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); } else bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREREAD); } r177459 | sam | 2008-03-20 09:19:25 -0700 (Thu, 20 Mar 2008) | 12 lines Workaround design botch in usb: blindly mixing bus_dma with PIO does not work on architectures with a write-back cache as the PIO writes end up in the cache which the sync(BUS_DMASYNC_POSTREAD) in usb_transfer_complete then discards; compensate in the xfer methods that do PIO by pushing the writes out of the cache before usb_transfer_complete is called. This fixes USB on xscale and likely other places. Sponsored by: hobnob Reviewed by: cognet, imp MFC after: 1 month Index: sys/dev/usb/ohci.c =================================================================== --- sys/dev/usb/ohci.c (revision 177458) +++ sys/dev/usb/ohci.c (revision 177459) @@ -1560,6 +1560,20 @@ xfer->hcpriv = NULL; } +/* + * XXX write back xfer data for architectures with a write-back + * data cache; this is a hack because usb is mis-architected + * in blindly mixing bus_dma w/ PIO. + */ +static __inline void +hacksync(usbd_xfer_handle xfer) +{ + usbd_pipe_handle pipe = xfer->pipe; + bus_dma_tag_t tag = pipe->device->bus->buffer_dmatag; + struct usb_dma_mapping *dmap = &xfer->dmamap; + bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE); +} + void ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer) { @@ -1591,6 +1605,7 @@ xfer->actlen = xfer->length; xfer->status = USBD_NORMAL_COMPLETION; + hacksync(xfer); /* XXX to compensate for usb_transfer_complete */ usb_transfer_complete(xfer); } @@ -2722,6 +2737,7 @@ ret: xfer->status = err; s = splusb(); + hacksync(xfer); /* XXX to compensate for usb_transfer_complete */ usb_transfer_complete(xfer); splx(s); return (USBD_IN_PROGRESS); Index: sys/dev/usb/ehci.c =================================================================== --- sys/dev/usb/ehci.c (revision 177458) +++ sys/dev/usb/ehci.c (revision 177459) @@ -653,6 +653,20 @@ ehci_pcd_able(sc, 1); } +/* + * XXX write back xfer data for architectures with a write-back + * data cache; this is a hack because usb is mis-architected + * in blindly mixing bus_dma w/ PIO. + */ +static __inline void +hacksync(usbd_xfer_handle xfer) +{ + usbd_pipe_handle pipe = xfer->pipe; + bus_dma_tag_t tag = pipe->device->bus->buffer_dmatag; + struct usb_dma_mapping *dmap = &xfer->dmamap; + bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE); +} + void ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer) { @@ -679,6 +693,7 @@ xfer->actlen = xfer->length; xfer->status = USBD_NORMAL_COMPLETION; + hacksync(xfer); /* XXX to compensate for usb_transfer_complete */ usb_transfer_complete(xfer); } @@ -2072,6 +2087,7 @@ ret: xfer->status = err; s = splusb(); + hacksync(xfer); /* XXX to compensate for usb_transfer_complete */ usb_transfer_complete(xfer); splx(s); return (USBD_IN_PROGRESS);