Subject: Re: USB CF reader problems with 2.0beta
To: None <nathanw@wasabisystems.com>
From: IWAMOTO Toshihiro <toshii@w.email.ne.jp>
List: tech-kern
Date: 05/05/2004 18:17:51
--Multipart_Wed_May__5_18:17:51_2004-1
Content-Type: text/plain; charset=US-ASCII
I haven't noticed this thread until now; I no longer check port-i386
regularly.
Last night, I was playing with the same issue and made a fix for ohci.
Nathan J. Williams wrote:
> I've actually had some difficulty testing, since when I boot a fresh
> kernel with my changes, there's lots of memory avaliable; do people
> have good ways to reproduce the out-of-contig-memory situation other
> than "run a bunch of gui desktop apps for a while"?
I made a shell script (attached test.sh). On my 512MB amd64 box, it
doesn't take much time until page cache eats all memory so that 64kB
contig alloc fails.
--
IWAMOTO Toshihiro
--Multipart_Wed_May__5_18:17:51_2004-1
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="test.sh"
Content-Transfer-Encoding: 7bit
#!/bin/sh
while true; do
jot -r 100 1 499 | while read i ; do
if [ ! -f $i ]; then
rm -f $i
dd if=/dev/zero bs=64k count=32 of=$i
else
cat $i >/dev/null
fi
done
done
--Multipart_Wed_May__5_18:17:51_2004-1
Content-Type: text/plain; charset=US-ASCII
--Multipart_Wed_May__5_18:17:51_2004-1
Content-Type: application/octet-stream; type=patch
Content-Disposition: attachment; filename="usb.diff"
Content-Transfer-Encoding: 7bit
Index: ohci.c
===================================================================
RCS file: /export/kiku/NetBSD/NetBSD-CVS/src/sys/dev/usb/ohci.c,v
retrieving revision 1.146
diff -u -p -r1.146 ohci.c
--- ohci.c 2003/12/29 08:17:10 1.146
+++ ohci.c 2004/05/05 09:12:16
@@ -482,7 +482,7 @@ ohci_alloc_std_chain(struct ohci_pipe *o
ohci_soft_td_t *next, *cur;
ohci_physaddr_t dataphys, dataphysend;
u_int32_t tdflags;
- int len, curlen;
+ int len, curlen, offs = 0;
usb_dma_t *dma = &xfer->dmabuf;
u_int16_t flags = xfer->flags;
@@ -490,8 +490,7 @@ ohci_alloc_std_chain(struct ohci_pipe *o
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) |
@@ -502,9 +501,11 @@ ohci_alloc_std_chain(struct ohci_pipe *o
if (next == NULL)
goto nomem;
+ dataphys = DMAADDR(dma, offs);
/* The OHCI hardware can handle at most one page crossing. */
if (OHCI_PAGE(dataphys) == dataphysend ||
- OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) {
+ OHCI_PAGE(DMAADDR(dma, offs + OHCI_PAGE_SIZE)) ==
+ dataphysend) {
/* we can handle it in this TD */
curlen = len;
} else {
@@ -528,7 +529,7 @@ ohci_alloc_std_chain(struct ohci_pipe *o
cur->td.td_cbp = htole32(dataphys);
cur->nexttd = next;
cur->td.td_nexttd = htole32(next->physaddr);
- cur->td.td_be = htole32(dataphys + curlen - 1);
+ cur->td.td_be = htole32(DMAADDR(dma, offs + curlen - 1));
cur->len = curlen;
cur->flags = OHCI_ADD_LEN;
cur->xfer = xfer;
@@ -537,7 +538,7 @@ ohci_alloc_std_chain(struct ohci_pipe *o
if (len == 0)
break;
DPRINTFN(10,("ohci_alloc_std_chain: extend chain\n"));
- dataphys += curlen;
+ offs += curlen;
cur = next;
}
if ((flags & USBD_FORCE_SHORT_XFER) &&
@@ -3181,7 +3182,7 @@ ohci_device_isoc_enter(usbd_xfer_handle
ohci_soft_ed_t *sed = opipe->sed;
struct iso *iso = &opipe->u.iso;
ohci_soft_itd_t *sitd, *nsitd;
- ohci_physaddr_t buf, offs, noffs, bp0;
+ ohci_physaddr_t buf, offs, noffs, bp0, pgoffs = 0;
int i, ncur, nframes;
int s;
@@ -3208,7 +3209,7 @@ ohci_device_isoc_enter(usbd_xfer_handle
for (i = ncur = 0; i < nframes; i++, ncur++) {
noffs = offs + xfer->frlengths[i];
if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */
- OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */
+ noffs >= OHCI_PAGE_SIZE * 2) { /* too many page crossings */
/* Allocate next ITD */
nsitd = ohci_alloc_sitd(sc);
@@ -3228,13 +3229,17 @@ ohci_device_isoc_enter(usbd_xfer_handle
sitd->itd.itd_bp0 = htole32(bp0);
sitd->nextitd = nsitd;
sitd->itd.itd_nextitd = htole32(nsitd->physaddr);
- sitd->itd.itd_be = htole32(bp0 + offs - 1);
+ sitd->itd.itd_be = htole32(DMAADDR(&xfer->dmabuf,
+ pgoffs + offs - 1));
sitd->xfer = xfer;
sitd->flags = 0;
sitd = nsitd;
iso->next = iso->next + ncur;
- bp0 = OHCI_PAGE(buf + offs);
+ bp0 = OHCI_PAGE(DMAADDR(&xfer->dmabuf, pgoffs + offs));
+ pgoffs += OHCI_PAGE(offs);
+ noffs -= OHCI_PAGE(offs);
+ offs = OHCI_PAGE_OFFSET(offs);
ncur = 0;
}
sitd->itd.itd_offset[ncur] = htole16(OHCI_ITD_MK_OFFS(offs));
Index: uaudio.c
===================================================================
RCS file: /export/kiku/NetBSD/NetBSD-CVS/src/sys/dev/usb/uaudio.c,v
retrieving revision 1.71
diff -u -p -r1.71 uaudio.c
--- uaudio.c 2004/04/23 17:25:25 1.71
+++ uaudio.c 2004/05/05 09:12:16
@@ -2368,7 +2368,8 @@ uaudio_set_params(void *addr, int setmod
int flags = sc->sc_altflags;
int factor;
int enc, i;
- int paltidx=-1, raltidx=-1;
+ int paltidx = sc->sc_playchan.altidx,
+ raltidx = sc->sc_recchan.altidx;
void (*swcode)(void *, u_char *buf, int cnt);
struct audio_params *p;
int mode;
@@ -2387,7 +2388,10 @@ uaudio_set_params(void *addr, int setmod
for (mode = AUMODE_RECORD; mode != -1;
mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
- if ((setmode & mode) == 0)
+ if ((setmode & mode) == 0 &&
+ ((usemode & mode) == 0 ||
+ ((mode == AUMODE_PLAY) ? sc->sc_playchan.altidx :
+ sc->sc_recchan.altidx) != -1))
continue;
if ((sc->sc_mode & mode) == 0)
Index: usb_mem.c
===================================================================
RCS file: /export/kiku/NetBSD/NetBSD-CVS/src/sys/dev/usb/usb_mem.c,v
retrieving revision 1.27
diff -u -p -r1.27 usb_mem.c
--- usb_mem.c 2004/01/05 13:30:45 1.27
+++ usb_mem.c 2004/05/05 09:12:16
@@ -103,7 +103,7 @@ Static usbd_status
usb_block_allocmem(bus_dma_tag_t tag, size_t size, size_t align,
usb_dma_block_t **dmap)
{
- int error;
+ int error, nsegs;
usb_dma_block_t *p;
int s;
@@ -147,18 +147,31 @@ usb_block_allocmem(bus_dma_tag_t tag, si
p->tag = tag;
p->size = size;
p->align = align;
+ p->segp = NULL;
error = bus_dmamem_alloc(tag, p->size, align, 0,
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
&p->nsegs, BUS_DMA_NOWAIT);
+ if (error) {
+ nsegs = (size + USB_PAGE_SIZE - 1) / USB_PAGE_SIZE;
+ p->segp = malloc(sizeof(p->segp[0]) * nsegs, M_USB, M_NOWAIT);
+ if (p->segp == NULL)
+ goto free0;
+
+ printf("usb_block_allocmem: trying scatter DMA alloc\n");
+ error = bus_dmamem_alloc(tag, p->size, align, 0,
+ p->segp, nsegs,
+ &p->nsegs, BUS_DMA_NOWAIT);
+ }
if (error)
- goto free0;
+ goto free1;
- error = bus_dmamem_map(tag, p->segs, p->nsegs, p->size,
+ error = bus_dmamem_map(tag, p->segp != NULL ? p->segp : p->segs,
+ p->nsegs, p->size,
&p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
if (error)
- goto free1;
+ goto free2;
- error = bus_dmamap_create(tag, p->size, 1, p->size,
+ error = bus_dmamap_create(tag, p->size, p->nsegs, p->size,
0, BUS_DMA_NOWAIT, &p->map);
if (error)
goto unmap;
@@ -173,12 +186,19 @@ usb_block_allocmem(bus_dma_tag_t tag, si
destroy:
bus_dmamap_destroy(tag, p->map);
+ printf("error 4\n");
unmap:
bus_dmamem_unmap(tag, p->kaddr, p->size);
+ printf("error 3\n");
+ free2:
+ bus_dmamem_free(tag, p->segp != NULL ? p->segp : p->segs, p->nsegs);
+ printf("error 2\n");
free1:
- bus_dmamem_free(tag, p->segs, p->nsegs);
+ free(p->segp, M_USB);
+ printf("error 1\n");
free0:
free(p, M_USB);
+ printf("usb_block_allocmem: error %d\n", error);
return (USBD_NOMEM);
}
@@ -195,7 +215,8 @@ usb_block_real_freemem(usb_dma_block_t *
bus_dmamap_unload(p->tag, p->map);
bus_dmamap_destroy(p->tag, p->map);
bus_dmamem_unmap(p->tag, p->kaddr, p->size);
- bus_dmamem_free(p->tag, p->segs, p->nsegs);
+ bus_dmamem_free(tag, p->segp != NULL ? p->segp : p->segs, p->nsegs);
+ free(p->segp, M_USB);
free(p, M_USB);
}
#endif
@@ -287,3 +308,24 @@ usb_freemem(usbd_bus_handle bus, usb_dma
splx(s);
DPRINTFN(5, ("usb_freemem: frag=%p\n", f));
}
+
+bus_addr_t
+usb_dmaaddr(usb_dma_t *dma, int o)
+{
+ usb_dma_block_t *block = dma->block;
+ int i, offs = dma->offs + o;
+
+ if (block->nsegs == 1)
+ return block->map->dm_segs[0].ds_addr + offs;
+
+ for (i = 0; i < block->nsegs; i++) {
+ if (block->map->dm_segs[i].ds_len > offs)
+ return block->map->dm_segs[i].ds_addr + offs;
+ offs -= block->map->dm_segs[i].ds_len;
+ }
+ /* Treat extra offset within a page legal */
+ if (USB_PAGE_SIZE > offs)
+ return block->map->dm_segs[i - 1].ds_addr + offs;
+ panic("usb_dmaaddr");
+}
+
Index: usb_mem.h
===================================================================
RCS file: /export/kiku/NetBSD/NetBSD-CVS/src/sys/dev/usb/usb_mem.h,v
retrieving revision 1.20
diff -u -p -r1.20 usb_mem.h
--- usb_mem.h 2003/05/03 18:11:42 1.20
+++ usb_mem.h 2004/05/05 09:12:16
@@ -38,12 +38,15 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define USB_PAGE_SIZE 0x1000
+
#if defined(__NetBSD__) || defined(__OpenBSD__)
typedef struct usb_dma_block {
bus_dma_tag_t tag;
bus_dmamap_t map;
caddr_t kaddr;
bus_dma_segment_t segs[1];
+ bus_dma_segment_t *segp;
int nsegs;
size_t size;
size_t align;
@@ -51,13 +54,13 @@ typedef struct usb_dma_block {
LIST_ENTRY(usb_dma_block) next;
} usb_dma_block_t;
-#define DMAADDR(dma, o) ((dma)->block->map->dm_segs[0].ds_addr + (dma)->offs + (o))
+#define DMAADDR(dma, o) usb_dmaaddr(dma, o)
#define KERNADDR(dma, o) \
((void *)((char *)((dma)->block->kaddr + (dma)->offs) + (o)))
usbd_status usb_allocmem(usbd_bus_handle,size_t,size_t, usb_dma_t *);
void usb_freemem(usbd_bus_handle, usb_dma_t *);
-
+bus_addr_t usb_dmaaddr(usb_dma_t *, int);
#elif defined(__FreeBSD__)
/*
--Multipart_Wed_May__5_18:17:51_2004-1--