diff options
author | raj <raj@FreeBSD.org> | 2008-02-12 11:03:29 +0000 |
---|---|---|
committer | raj <raj@FreeBSD.org> | 2008-02-12 11:03:29 +0000 |
commit | 155d019a02a65209a252a9679ccb33ea18569cca (patch) | |
tree | 270bd62b203de76f928b9d973ef7b72b220caed6 /sys | |
parent | bd45971fbf8d160b37792d6540909ae5fa44d4ec (diff) | |
download | FreeBSD-src-155d019a02a65209a252a9679ccb33ea18569cca.zip FreeBSD-src-155d019a02a65209a252a9679ccb33ea18569cca.tar.gz |
Eliminate BUS_DMA <-> cache incoherencies in USB transfers.
With write-allocate cache we get into the following scenario:
1. data has been updated in the memory by the USB HC, but
2. D-cache holds an un-flushed value of it
3. when affected cache line is being replaced, the old (un-flushed) value is
flushed and overwrites the newly arrived
This is possible due to how write-allocate works with virtual caches (ARM for
example).
In case of USB transfers it leads to fatal tags discrepancies in umass(4)
operation, which look like the following:
umass0: Invalid CSW: tag 1 should be 2
(probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR
(probe0:umass-sim0:0:0:0): Retrying Command
umass0: Invalid CSW: tag 1 should be 3
(probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR
(probe0:umass-sim0:0:0:0): Retrying Command
umass0: Invalid CSW: tag 1 should be 4
(probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR
(probe0:umass-sim0:0:0:0): Retrying Command
umass0: Invalid CSW: tag 1 should be 5
(probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR
(probe0:umass-sim0:0:0:0): Retrying Command
umass0: Invalid CSW: tag 1 should be 6
(probe0:umass-sim0:0:0:0): Request completed with CAM_REQ_CMP_ERR
(probe0:umass-sim0:0:0:0): error 5
(probe0:umass-sim0:0:0:0): Retries Exausted
To eliminate this, a BUS_DMASYNC_PREREAD sync operation is required in
usbd_start_transfer().
Credits for nailing this down go to Grzegorz Bernacki gjb AT semihalf DOT com.
Reviewed by: imp
Approved by: cognet (mentor)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/usb/usbdi.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c index 35c201c..bfc0dd9 100644 --- a/sys/dev/usb/usbdi.c +++ b/sys/dev/usb/usbdi.c @@ -383,7 +383,8 @@ usbd_start_transfer(void *arg, bus_dma_segment_t *segs, int nseg, int error) * packet. */ bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE); - } + } else + bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREREAD); } err = pipe->methods->transfer(xfer); if (err != USBD_IN_PROGRESS && err) { |