summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>2002-12-20 18:47:39 +0000
committerdillon <dillon@FreeBSD.org>2002-12-20 18:47:39 +0000
commit5102bb345b29f0e4de8f3eb411873ba911ead652 (patch)
treeed871033868980604eada74c14f336af4d245228 /sys/dev/usb
parent516031bb16a53f60e882d65dda86706001769b7d (diff)
downloadFreeBSD-src-5102bb345b29f0e4de8f3eb411873ba911ead652.zip
FreeBSD-src-5102bb345b29f0e4de8f3eb411873ba911ead652.tar.gz
Fix two bugs in the DMA chaining code for OHCI. The first bug is that
the dataphysend calculation could only possibly work if the virtual buffer is also physically contiguous. Calculate dataphysend by calculating the ending virtual address first, then converting to a physical address. The second bug applies only to NetBSD and OpenBSD and involves the curlen calculation in the two-contiguous-physical-pages case (which we don't support). Also cleanup the use of the OHIC_PAGE() macro on dataphysend and add a panic if len goes negative (meaning we lost the physical page translation representing the end of the buffer). IMHO the dataphysend is still bokered since it might be misrepresented by shared userland page mappings. The whole section needs to be rewritten to use the virtual address range. MFC after: 3 days
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/ohci.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index a7db2d5..5a5ae49 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -501,9 +501,8 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
len = alen;
cur = sp;
-
dataphys = DMAADDR(dma, 0);
- dataphysend = OHCI_PAGE(dataphys + len - 1);
+ dataphysend = OHCI_PAGE(DMAADDR(dma, len - 1));
tdflags = htole32(
(rd ? OHCI_TD_IN : OHCI_TD_OUT) |
(flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) |
@@ -518,8 +517,8 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
/* The OHCI hardware can handle at most one page crossing. */
#if defined(__NetBSD__) || defined(__OpenBSD__)
- if (OHCI_PAGE(dataphys) == OHCI_PAGE(dataphysend) ||
- OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == OHCI_PAGE(dataphysend))
+ if (OHCI_PAGE(dataphys) == dataphysend ||
+ OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend)
#elif defined(__FreeBSD__)
/* XXX This is pretty broken: Because we do not allocate
* a contiguous buffer (contiguous in physical pages) we
@@ -527,7 +526,7 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
* So check whether the start and end of the buffer are on
* the same page.
*/
- if (OHCI_PAGE(dataphys) == OHCI_PAGE(dataphysend))
+ if (OHCI_PAGE(dataphys) == dataphysend)
#endif
{
/* we can handle it in this TD */
@@ -544,6 +543,8 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
/* must use multiple TDs, fill as much as possible. */
curlen = 2 * OHCI_PAGE_SIZE -
OHCI_PAGE_MASK(dataphys);
+ if (curlen > len) /* may have fit in one page */
+ curlen = len;
#elif defined(__FreeBSD__)
/* See comment above (XXX) */
curlen = OHCI_PAGE_SIZE -
@@ -568,6 +569,9 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
dataphys, dataphys + curlen - 1));
if (len == 0)
break;
+ if (len < 0)
+ panic("Length went negative: %d curlen %d dma %p offset %08x", len, curlen, *dma, (int)offset);
+
DPRINTFN(10,("ohci_alloc_std_chain: extend chain\n"));
offset += curlen;
cur = next;
OpenPOWER on IntegriCloud