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