Module Name:    src
Committed By:   matt
Date:           Wed Dec 15 23:38:15 UTC 2010

Modified Files:
        src/sys/dev/usb: files.usb usb_mem.c

Log Message:
Add a workaround (hopefully temporary) for corrupted usb fragments on powerpc.
With this in effect, USB is now usable on some powerpc platforms again.
Basically this prevents the DMA portion of the fragment ever overlapping the
usb_frag_hdr which is enough to solve the problem.  To enable this, add

options         USB_FRAG_DMA_WORKAROUND

to your config file.
Switch from malloc to kmem.


To generate a diff of this commit:
cvs rdiff -u -r1.102 -r1.103 src/sys/dev/usb/files.usb
cvs rdiff -u -r1.40 -r1.41 src/sys/dev/usb/usb_mem.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/files.usb
diff -u src/sys/dev/usb/files.usb:1.102 src/sys/dev/usb/files.usb:1.103
--- src/sys/dev/usb/files.usb:1.102	Wed Nov  3 19:59:34 2010
+++ src/sys/dev/usb/files.usb	Wed Dec 15 23:38:15 2010
@@ -1,10 +1,11 @@
-#	$NetBSD: files.usb,v 1.102 2010/11/03 19:59:34 christos Exp $
+#	$NetBSD: files.usb,v 1.103 2010/12/15 23:38:15 matt Exp $
 #
 # Config file and device description for machine-independent USB code.
 # Included by ports that need it.  Ports that use it must provide
 # their own "major" declarations for the appropriate devices.
 
 defflag	USBVERBOSE
+defflag	opt_usb.h	USB_FRAG_DMA_WORKAROUND
 
 defflag	opt_uvideo.h	UVIDEO_DEBUG
 

Index: src/sys/dev/usb/usb_mem.c
diff -u src/sys/dev/usb/usb_mem.c:1.40 src/sys/dev/usb/usb_mem.c:1.41
--- src/sys/dev/usb/usb_mem.c:1.40	Sat Nov 13 13:52:12 2010
+++ src/sys/dev/usb/usb_mem.c	Wed Dec 15 23:38:15 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb_mem.c,v 1.40 2010/11/13 13:52:12 uebayasi Exp $	*/
+/*	$NetBSD: usb_mem.c,v 1.41 2010/12/15 23:38:15 matt Exp $	*/
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -38,15 +38,18 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v 1.40 2010/11/13 13:52:12 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v 1.41 2010/12/15 23:38:15 matt Exp $");
+
+#include "opt_usb.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
 #include <sys/queue.h>
 #include <sys/device.h>		/* for usbdivar.h */
 #include <sys/bus.h>
+#include <sys/cpu.h>
 
 #ifdef __NetBSD__
 #include <sys/extent.h>
@@ -108,7 +111,7 @@
 		     (u_long)size, (u_long)align));
 
 #ifdef DIAGNOSTIC
-	if (!curproc) {
+	if (cpu_intr_p()) {
 		printf("usb_block_allocmem: in interrupt context, size=%lu\n",
 		    (unsigned long) size);
 	}
@@ -130,14 +133,14 @@
 	splx(s);
 
 #ifdef DIAGNOSTIC
-	if (!curproc) {
+	if (cpu_intr_p()) {
 		printf("usb_block_allocmem: in interrupt context, failed\n");
 		return (USBD_NOMEM);
 	}
 #endif
 
 	DPRINTFN(6, ("usb_block_allocmem: no free\n"));
-	p = malloc(sizeof *p, M_USB, M_NOWAIT);
+	p = kmem_zalloc(sizeof *p, KM_NOSLEEP);
 	if (p == NULL)
 		return (USBD_NOMEM);
 
@@ -166,6 +169,9 @@
 		goto destroy;
 
 	*dmap = p;
+#ifdef USB_FRAG_DMA_WORKAROUND
+	memset(p->kaddr, 0, p->size);
+#endif
 	return (USBD_NORMAL_COMPLETION);
 
  destroy:
@@ -175,7 +181,7 @@
  free1:
 	bus_dmamem_free(tag, p->segs, p->nsegs);
  free0:
-	free(p, M_USB);
+	kmem_free(p, sizeof(*p));
 	return (USBD_NOMEM);
 }
 
@@ -184,7 +190,7 @@
 usb_block_real_freemem(usb_dma_block_t *p)
 {
 #ifdef DIAGNOSTIC
-	if (!curproc) {
+	if (cpu_intr_p()) {
 		printf("usb_block_real_freemem: in interrupt context\n");
 		return;
 	}
@@ -193,7 +199,7 @@
 	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);
-	free(p, M_USB);
+	kmem_free(p, sizeof(*p));
 }
 #endif
 
@@ -238,9 +244,10 @@
 
 	s = splusb();
 	/* Check for free fragments. */
-	for (f = LIST_FIRST(&usb_frag_freelist); f; f = LIST_NEXT(f, next))
+	for (f = LIST_FIRST(&usb_frag_freelist); f; f = LIST_NEXT(f, next)) {
 		if (f->block->tag == tag)
 			break;
+	}
 	if (f == NULL) {
 		DPRINTFN(1, ("usb_allocmem: adding fragments\n"));
 		err = usb_block_allocmem(tag, USB_MEM_BLOCK, USB_MEM_SMALL,&b);
@@ -254,11 +261,17 @@
 			f->block = b;
 			f->offs = i;
 			LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
+#ifdef USB_FRAG_DMA_WORKAROUND
+			i += 1 * USB_MEM_SMALL;
+#endif
 		}
 		f = LIST_FIRST(&usb_frag_freelist);
 	}
 	p->block = f->block;
 	p->offs = f->offs;
+#ifdef USB_FRAG_DMA_WORKAROUND
+	p->offs += USB_MEM_SMALL;
+#endif
 	p->block->flags &= ~USB_DMA_RESERVE;
 	LIST_REMOVE(f, next);
 	splx(s);
@@ -277,9 +290,16 @@
 		usb_block_freemem(p->block);
 		return;
 	}
+	//usb_syncmem(p, 0, USB_MEM_SMALL, BUS_DMASYNC_POSTREAD);
 	f = KERNADDR(p, 0);
+#ifdef USB_FRAG_DMA_WORKAROUND
+	f = (void *)((uintptr_t)f - USB_MEM_SMALL);
+#endif
 	f->block = p->block;
 	f->offs = p->offs;
+#if def USB_FRAG_DMA_WORKAROUND
+	f->offs -= USB_MEM_SMALL;
+#endif
 	s = splusb();
 	LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
 	splx(s);
@@ -305,7 +325,7 @@
 	if (rs->vaddr == 0 || size > USB_MEM_RESERVE)
 		return USBD_NOMEM;
 
-	dma->block = malloc(sizeof *dma->block, M_USB, M_ZERO | M_NOWAIT);
+	dma->block = kmem_zalloc(sizeof *dma->block, KM_NOSLEEP);
 	if (dma->block == NULL)
 		return USBD_NOMEM;
 
@@ -341,7 +361,7 @@
 
 	error = extent_free(rs->extent,
 	    (u_long)(rs->paddr + dma->offs), dma->block->size, 0);
-	free(dma->block, M_USB);
+	kmem_free(dma->block, sizeof(*dma->block));
 }
 
 int

Reply via email to