[BACK]Return to usb_mem.c CVS log [TXT][DIR] Up to [local] / sys / dev / usb

Annotation of sys/dev/usb/usb_mem.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: usb_mem.c,v 1.20 2007/06/15 04:05:53 deraadt Exp $ */
        !             2: /*     $NetBSD: usb_mem.c,v 1.26 2003/02/01 06:23:40 thorpej Exp $     */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Lennart Augustsson (lennart@augustsson.net) at
        !            10:  * Carlstedt Research & Technology.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *        This product includes software developed by the NetBSD
        !            23:  *        Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: /*
        !            42:  * USB DMA memory allocation.
        !            43:  * We need to allocate a lot of small (many 8 byte, some larger)
        !            44:  * memory blocks that can be used for DMA.  Using the bus_dma
        !            45:  * routines directly would incur large overheads in space and time.
        !            46:  */
        !            47:
        !            48: #include <sys/param.h>
        !            49: #include <sys/systm.h>
        !            50: #include <sys/kernel.h>
        !            51: #include <sys/malloc.h>
        !            52: #include <sys/queue.h>
        !            53: #include <sys/timeout.h>
        !            54: #include <sys/device.h>                /* for usbdivar.h */
        !            55: #include <machine/bus.h>
        !            56:
        !            57: #ifdef DIAGNOSTIC
        !            58: #include <sys/proc.h>
        !            59: #endif
        !            60:
        !            61: #include <dev/usb/usb.h>
        !            62: #include <dev/usb/usbdi.h>
        !            63: #include <dev/usb/usbdivar.h>  /* just for usb_dma_t */
        !            64: #include <dev/usb/usb_mem.h>
        !            65:
        !            66: #ifdef USB_DEBUG
        !            67: #define DPRINTF(x)     do { if (usbdebug) printf x; } while (0)
        !            68: #define DPRINTFN(n,x)  do { if (usbdebug>(n)) printf x; } while (0)
        !            69: extern int usbdebug;
        !            70: #else
        !            71: #define DPRINTF(x)
        !            72: #define DPRINTFN(n,x)
        !            73: #endif
        !            74:
        !            75: #define USB_MEM_SMALL 64
        !            76: #define USB_MEM_CHUNKS 64
        !            77: #define USB_MEM_BLOCK (USB_MEM_SMALL * USB_MEM_CHUNKS)
        !            78:
        !            79: /* This struct is overlayed on free fragments. */
        !            80: struct usb_frag_dma {
        !            81:        usb_dma_block_t *block;
        !            82:        u_int offs;
        !            83:        LIST_ENTRY(usb_frag_dma) next;
        !            84: };
        !            85:
        !            86: usbd_status    usb_block_allocmem(bus_dma_tag_t, size_t, size_t,
        !            87:                                           usb_dma_block_t **);
        !            88: void           usb_block_freemem(usb_dma_block_t *);
        !            89:
        !            90: LIST_HEAD(, usb_dma_block) usb_blk_freelist =
        !            91:        LIST_HEAD_INITIALIZER(usb_blk_freelist);
        !            92: int usb_blk_nfree = 0;
        !            93: /* XXX should have different free list for different tags (for speed) */
        !            94: LIST_HEAD(, usb_frag_dma) usb_frag_freelist =
        !            95:        LIST_HEAD_INITIALIZER(usb_frag_freelist);
        !            96:
        !            97: usbd_status
        !            98: usb_block_allocmem(bus_dma_tag_t tag, size_t size, size_t align,
        !            99:                   usb_dma_block_t **dmap)
        !           100: {
        !           101:        int error;
        !           102:         usb_dma_block_t *p;
        !           103:        int s;
        !           104:
        !           105:        DPRINTFN(5, ("usb_block_allocmem: size=%lu align=%lu\n",
        !           106:                     (u_long)size, (u_long)align));
        !           107:
        !           108: #ifdef DIAGNOSTIC
        !           109:        if (!curproc) {
        !           110:                printf("usb_block_allocmem: in interrupt context, size=%lu\n",
        !           111:                    (unsigned long) size);
        !           112:        }
        !           113: #endif
        !           114:
        !           115:        s = splusb();
        !           116:        /* First check the free list. */
        !           117:        for (p = LIST_FIRST(&usb_blk_freelist); p; p = LIST_NEXT(p, next)) {
        !           118:                if (p->tag == tag && p->size >= size && p->align >= align) {
        !           119:                        LIST_REMOVE(p, next);
        !           120:                        usb_blk_nfree--;
        !           121:                        splx(s);
        !           122:                        *dmap = p;
        !           123:                        DPRINTFN(6,("usb_block_allocmem: free list size=%lu\n",
        !           124:                                    (u_long)p->size));
        !           125:                        return (USBD_NORMAL_COMPLETION);
        !           126:                }
        !           127:        }
        !           128:        splx(s);
        !           129:
        !           130: #ifdef DIAGNOSTIC
        !           131:        if (!curproc) {
        !           132:                printf("usb_block_allocmem: in interrupt context, failed\n");
        !           133:                return (USBD_NOMEM);
        !           134:        }
        !           135: #endif
        !           136:
        !           137:        DPRINTFN(6, ("usb_block_allocmem: no free\n"));
        !           138:        p = malloc(sizeof *p, M_USB, M_NOWAIT);
        !           139:        if (p == NULL)
        !           140:                return (USBD_NOMEM);
        !           141:
        !           142:        p->tag = tag;
        !           143:        p->size = size;
        !           144:        p->align = align;
        !           145:        error = bus_dmamem_alloc(tag, p->size, align, 0,
        !           146:                                 p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
        !           147:                                 &p->nsegs, BUS_DMA_NOWAIT);
        !           148:        if (error)
        !           149:                goto free0;
        !           150:
        !           151:        error = bus_dmamem_map(tag, p->segs, p->nsegs, p->size,
        !           152:                               &p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
        !           153:        if (error)
        !           154:                goto free1;
        !           155:
        !           156:        error = bus_dmamap_create(tag, p->size, 1, p->size,
        !           157:                                  0, BUS_DMA_NOWAIT, &p->map);
        !           158:        if (error)
        !           159:                goto unmap;
        !           160:
        !           161:        error = bus_dmamap_load(tag, p->map, p->kaddr, p->size, NULL,
        !           162:                                BUS_DMA_NOWAIT);
        !           163:        if (error)
        !           164:                goto destroy;
        !           165:
        !           166:        *dmap = p;
        !           167:        return (USBD_NORMAL_COMPLETION);
        !           168:
        !           169: destroy:
        !           170:        bus_dmamap_destroy(tag, p->map);
        !           171: unmap:
        !           172:        bus_dmamem_unmap(tag, p->kaddr, p->size);
        !           173: free1:
        !           174:        bus_dmamem_free(tag, p->segs, p->nsegs);
        !           175: free0:
        !           176:        free(p, M_USB);
        !           177:        return (USBD_NOMEM);
        !           178: }
        !           179:
        !           180: #if 0
        !           181: void
        !           182: usb_block_real_freemem(usb_dma_block_t *p)
        !           183: {
        !           184: #ifdef DIAGNOSTIC
        !           185:        if (!curproc) {
        !           186:                printf("usb_block_real_freemem: in interrupt context\n");
        !           187:                return;
        !           188:        }
        !           189: #endif
        !           190:        bus_dmamap_unload(p->tag, p->map);
        !           191:        bus_dmamap_destroy(p->tag, p->map);
        !           192:        bus_dmamem_unmap(p->tag, p->kaddr, p->size);
        !           193:        bus_dmamem_free(p->tag, p->segs, p->nsegs);
        !           194:        free(p, M_USB);
        !           195: }
        !           196: #endif
        !           197:
        !           198: /*
        !           199:  * Do not free the memory unconditionally since we might be called
        !           200:  * from an interrupt context and that is BAD.
        !           201:  * XXX when should we really free?
        !           202:  */
        !           203: void
        !           204: usb_block_freemem(usb_dma_block_t *p)
        !           205: {
        !           206:        int s;
        !           207:
        !           208:        DPRINTFN(6, ("usb_block_freemem: size=%lu\n", (u_long)p->size));
        !           209:        s = splusb();
        !           210:        LIST_INSERT_HEAD(&usb_blk_freelist, p, next);
        !           211:        usb_blk_nfree++;
        !           212:        splx(s);
        !           213: }
        !           214:
        !           215: usbd_status
        !           216: usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p)
        !           217: {
        !           218:        bus_dma_tag_t tag = bus->dmatag;
        !           219:        usbd_status err;
        !           220:        struct usb_frag_dma *f;
        !           221:        usb_dma_block_t *b;
        !           222:        int i;
        !           223:        int s;
        !           224:
        !           225:        /* If the request is large then just use a full block. */
        !           226:        if (size > USB_MEM_SMALL || align > USB_MEM_SMALL) {
        !           227:                DPRINTFN(1, ("usb_allocmem: large alloc %d\n", (int)size));
        !           228:                size = (size + USB_MEM_BLOCK - 1) & ~(USB_MEM_BLOCK - 1);
        !           229:                err = usb_block_allocmem(tag, size, align, &p->block);
        !           230:                if (!err) {
        !           231:                        p->block->fullblock = 1;
        !           232:                        p->offs = 0;
        !           233:                }
        !           234:                return (err);
        !           235:        }
        !           236:
        !           237:        s = splusb();
        !           238:        /* Check for free fragments. */
        !           239:        for (f = LIST_FIRST(&usb_frag_freelist); f; f = LIST_NEXT(f, next))
        !           240:                if (f->block->tag == tag)
        !           241:                        break;
        !           242:        if (f == NULL) {
        !           243:                DPRINTFN(1, ("usb_allocmem: adding fragments\n"));
        !           244:                err = usb_block_allocmem(tag, USB_MEM_BLOCK, USB_MEM_SMALL,&b);
        !           245:                if (err) {
        !           246:                        splx(s);
        !           247:                        return (err);
        !           248:                }
        !           249:                b->fullblock = 0;
        !           250:                for (i = 0; i < USB_MEM_BLOCK; i += USB_MEM_SMALL) {
        !           251:                        f = (struct usb_frag_dma *)(b->kaddr + i);
        !           252:                        f->block = b;
        !           253:                        f->offs = i;
        !           254:                        LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
        !           255:                }
        !           256:                f = LIST_FIRST(&usb_frag_freelist);
        !           257:        }
        !           258:        p->block = f->block;
        !           259:        p->offs = f->offs;
        !           260:        LIST_REMOVE(f, next);
        !           261:        splx(s);
        !           262:        DPRINTFN(5, ("usb_allocmem: use frag=%p size=%d\n", f, (int)size));
        !           263:        return (USBD_NORMAL_COMPLETION);
        !           264: }
        !           265:
        !           266: void
        !           267: usb_freemem(usbd_bus_handle bus, usb_dma_t *p)
        !           268: {
        !           269:        struct usb_frag_dma *f;
        !           270:        int s;
        !           271:
        !           272:        if (p->block->fullblock) {
        !           273:                DPRINTFN(1, ("usb_freemem: large free\n"));
        !           274:                usb_block_freemem(p->block);
        !           275:                return;
        !           276:        }
        !           277:        f = KERNADDR(p, 0);
        !           278:        f->block = p->block;
        !           279:        f->offs = p->offs;
        !           280:        s = splusb();
        !           281:        LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
        !           282:        splx(s);
        !           283:        DPRINTFN(5, ("usb_freemem: frag=%p\n", f));
        !           284: }

CVSweb