usbd_status usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p) { bus_dma_tag_t tag = bus->parent_dmatag; usbd_status err; struct usb_frag_dma *f; usb_dma_block_t *b; int i; int s; /* compat w/ Net/OpenBSD */ if (align == 0) align = 1; /* If the request is large then just use a full block. */ if (size > USB_MEM_SMALL || align > USB_MEM_SMALL) { DPRINTFN(1, ("usb_allocmem: large alloc %d\n", (int)size)); size = (size + USB_MEM_BLOCK - 1) & ~(USB_MEM_BLOCK - 1); err = usb_block_allocmem(tag, size, align, &p->block); if (!err) { p->block->fullblock = 1; p->offs = 0; p->len = size; } return (err); } s = splusb(); /* Check for free fragments. */ 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); if (err) { splx(s); return (err); } b->fullblock = 0; /* XXX - override the tag, ok since we never free it */ b->tag = tag; KASSERT(sizeof *f <= USB_MEM_SMALL, ("USB_MEM_SMALL(%d) is too small for struct usb_frag_dma(%zd)\n", USB_MEM_SMALL, sizeof *f)); for (i = 0; i < USB_MEM_BLOCK; i += USB_MEM_SMALL) { f = (struct usb_frag_dma *)((char *)b->kaddr + i); f->block = b; f->offs = i; LIST_INSERT_HEAD(&usb_frag_freelist, f, next); } f = LIST_FIRST(&usb_frag_freelist); } p->block = f->block; p->offs = f->offs; p->len = USB_MEM_SMALL; LIST_REMOVE(f, next); splx(s); DPRINTFN(5, ("usb_allocmem: use frag=%p size=%d\n", f, (int)size)); return (USBD_NORMAL_COMPLETION); }
usbd_status usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p) { bus_dma_tag_t tag = bus->dmatag; usbd_status err; struct usb_frag_dma *f; usb_dma_block_t *b; int i; int s; /* If the request is large then just use a full block. */ if (size > USB_MEM_SMALL || align > USB_MEM_SMALL) { DPRINTFN(1, ("usb_allocmem: large alloc %d\n", (int)size)); size = (size + USB_MEM_BLOCK - 1) & ~(USB_MEM_BLOCK - 1); err = usb_block_allocmem(tag, size, align, &p->block); if (!err) { p->block->fullblock = 1; p->offs = 0; } return (err); } s = splusb(); /* Check for free fragments. */ 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); if (err) { splx(s); return (err); } b->fullblock = 0; for (i = 0; i < USB_MEM_BLOCK; i += USB_MEM_SMALL) { f = (struct usb_frag_dma *)(b->kaddr + i); f->block = b; f->offs = i; LIST_INSERT_HEAD(&usb_frag_freelist, f, next); } f = LIST_FIRST(&usb_frag_freelist); } p->block = f->block; p->offs = f->offs; LIST_REMOVE(f, next); splx(s); DPRINTFN(5, ("usb_allocmem: use frag=%p size=%d\n", f, (int)size)); return (USBD_NORMAL_COMPLETION); }