Insert some splusb() since memory allocation and deallocation can

occur from an interrupt.
This commit is contained in:
augustss 1998-12-09 01:02:29 +00:00
parent c8736358e3
commit 1fdafa2f13
1 changed files with 37 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: usb_mem.c,v 1.2 1998/11/25 22:32:05 augustss Exp $ */
/* $NetBSD: usb_mem.c,v 1.3 1998/12/09 01:02:29 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
* USB DMA memory allocation.
* We need to allocate a lot of small (many 8 byte, some larger)
* memory blocks that can be used for DMA. Using the bus_dma
* routines directly would uncur large overheads in space and time.
* routines directly would incur large overheads in space and time.
*/
#include <sys/param.h>
@ -50,6 +50,10 @@
#include <sys/malloc.h>
#include <sys/queue.h>
#ifdef DIAGNOSTIC
#include <sys/proc.h>
#endif
#include <machine/bus.h>
#include <dev/usb/usb.h>
@ -87,6 +91,12 @@ LIST_HEAD(, usb_block_dma) usb_blk_freelist =
LIST_HEAD(, usb_frag_dma) usb_frag_freelist =
LIST_HEAD_INITIALIZER(usb_frag_freelist);
/*
* XXX usb_block_allocmem() does not have any locks because
* it should never be called from an interrupt context, nor
* should should it block. But is that true?
*/
usbd_status
usb_block_allocmem(tag, size, align, dmap)
bus_dma_tag_t tag;
@ -99,6 +109,13 @@ usb_block_allocmem(tag, size, align, dmap)
DPRINTFN(5, ("usb_block_allocmem: size=%d align=%d\n", size, align));
#ifdef DIAGNOSTIC
if (!curproc) {
printf("usb_block_allocmem: in interrupt context\n");
return (USBD_NOMEM);
}
#endif
/* First check the free list. */
for (p = LIST_FIRST(&usb_blk_freelist); p; p = LIST_NEXT(p, next)) {
if (p->tag == tag && p->size >= size && p->align >= align) {
@ -154,6 +171,12 @@ void
usb_block_real_freemem(p)
usb_dma_block_t *p;
{
#ifdef DIAGNOSTIC
if (!curproc) {
printf("usb_block_real_freemem: in interrupt context\n");
return;
}
#endif
bus_dmamap_unload(p->tag, p->map);
bus_dmamap_destroy(p->tag, p->map);
bus_dmamem_unmap(p->tag, p->kaddr, p->size);
@ -170,6 +193,12 @@ void
usb_block_freemem(p)
usb_dma_block_t *p;
{
#ifdef DIAGNOSTIC
if (!curproc) {
printf("usb_block_freemem: in interrupt context\n");
return;
}
#endif
DPRINTFN(6, ("usb_block_freemem: size=%d\n", p->size));
LIST_INSERT_HEAD(&usb_blk_freelist, p, next);
}
@ -185,6 +214,7 @@ usb_allocmem(tag, size, align, p)
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) {
@ -198,6 +228,7 @@ usb_allocmem(tag, size, align, p)
return (r);
}
s = splusb();
/* Check for free fragments. */
for (f = LIST_FIRST(&usb_frag_freelist); f; f = LIST_NEXT(f, next))
if (f->block->tag == tag)
@ -216,6 +247,7 @@ usb_allocmem(tag, size, align, p)
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);
}
@ -226,6 +258,7 @@ usb_freemem(tag, p)
usb_dma_t *p;
{
struct usb_frag_dma *f;
int s;
if (p->block->fullblock) {
usb_block_freemem(p->block);
@ -234,6 +267,8 @@ usb_freemem(tag, p)
f = KERNADDR(p);
f->block = p->block;
f->offs = p->offs;
s = splusb();
LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
splx(s);
DPRINTFN(5, ("usb_freemem: frag=%p\n", f));
}