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--