Add special memory allocation routines that supports allocation
DMA-able memory in small chunks (USB uses a lot of 8 byte chunks). Using the bus_dma functions directly is inefficient.
This commit is contained in:
parent
91f18e727f
commit
b916de0f86
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ohci.c,v 1.3 1998/07/23 13:41:04 augustss Exp $ */
|
||||
/* $NetBSD: ohci.c,v 1.4 1998/07/24 21:09:07 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
@ -52,14 +52,13 @@
|
||||
#include <sys/queue.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <dev/usb/usb_mem.h>
|
||||
|
||||
#include <dev/usb/ohcireg.h>
|
||||
#include <dev/usb/ohcivar.h>
|
||||
@ -82,9 +81,6 @@ void ohci_ctrl_done __P((ohci_softc_t *, usbd_request_handle));
|
||||
void ohci_intr_done __P((ohci_softc_t *, usbd_request_handle));
|
||||
void ohci_bulk_done __P((ohci_softc_t *, usbd_request_handle));
|
||||
|
||||
usbd_status ohci_allocmem __P((ohci_softc_t *,size_t,size_t, ohci_dma_t*));
|
||||
void ohci_freemem __P((ohci_softc_t *, ohci_dma_t *));
|
||||
|
||||
usbd_status ohci_device_request __P((usbd_request_handle reqh));
|
||||
void ohci_add_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *));
|
||||
void ohci_rem_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *));
|
||||
@ -146,20 +142,20 @@ struct ohci_pipe {
|
||||
union {
|
||||
/* Control pipe */
|
||||
struct {
|
||||
ohci_dma_t datadma;
|
||||
ohci_dma_t reqdma;
|
||||
usb_dma_t datadma;
|
||||
usb_dma_t reqdma;
|
||||
u_int length;
|
||||
ohci_soft_td_t *setup, *xfer, *stat;
|
||||
} ctl;
|
||||
/* Interrupt pipe */
|
||||
struct {
|
||||
ohci_dma_t datadma;
|
||||
usb_dma_t datadma;
|
||||
int nslots;
|
||||
int pos;
|
||||
} intr;
|
||||
/* Bulk pipe */
|
||||
struct {
|
||||
ohci_dma_t datadma;
|
||||
usb_dma_t datadma;
|
||||
u_int length;
|
||||
} bulk;
|
||||
} u;
|
||||
@ -197,59 +193,6 @@ struct usbd_methods ohci_device_bulk_methods = {
|
||||
ohci_device_bulk_close,
|
||||
};
|
||||
|
||||
usbd_status
|
||||
ohci_allocmem(sc, size, align, p)
|
||||
ohci_softc_t *sc;
|
||||
size_t size;
|
||||
size_t align;
|
||||
ohci_dma_t *p;
|
||||
{
|
||||
int error;
|
||||
|
||||
DPRINTFN(5, ("ohci_allocmem: size=%d align=%d\n", size, align));
|
||||
p->size = size;
|
||||
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
|
||||
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
|
||||
&p->nsegs, BUS_DMA_NOWAIT);
|
||||
if (error)
|
||||
return (USBD_NOMEM);
|
||||
|
||||
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
|
||||
&p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
|
||||
if (error)
|
||||
goto free;
|
||||
|
||||
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
|
||||
0, BUS_DMA_NOWAIT, &p->map);
|
||||
if (error)
|
||||
goto unmap;
|
||||
|
||||
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->kaddr,p->size, NULL,
|
||||
BUS_DMA_NOWAIT);
|
||||
if (error)
|
||||
goto destroy;
|
||||
return 0;
|
||||
|
||||
destroy:
|
||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
||||
unmap:
|
||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
||||
free:
|
||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
||||
return (USBD_NOMEM);
|
||||
}
|
||||
|
||||
void
|
||||
ohci_freemem(sc, p)
|
||||
ohci_softc_t *sc;
|
||||
ohci_dma_t *p;
|
||||
{
|
||||
bus_dmamap_unload(sc->sc_dmatag, p->map);
|
||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
||||
}
|
||||
|
||||
ohci_soft_ed_t *
|
||||
ohci_alloc_sed(sc)
|
||||
ohci_softc_t *sc;
|
||||
@ -257,7 +200,7 @@ ohci_alloc_sed(sc)
|
||||
ohci_soft_ed_t *sed;
|
||||
usbd_status r;
|
||||
int i, offs;
|
||||
ohci_dma_t dma;
|
||||
usb_dma_t dma;
|
||||
|
||||
if (!sc->sc_freeeds) {
|
||||
DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n"));
|
||||
@ -265,7 +208,7 @@ ohci_alloc_sed(sc)
|
||||
M_USBDEV, M_NOWAIT);
|
||||
if (!sed)
|
||||
return 0;
|
||||
r = ohci_allocmem(sc, OHCI_ED_SIZE * OHCI_ED_CHUNK,
|
||||
r = usb_allocmem(sc->sc_dmatag, OHCI_ED_SIZE * OHCI_ED_CHUNK,
|
||||
OHCI_ED_ALIGN, &dma);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
free(sed, M_USBDEV);
|
||||
@ -303,7 +246,7 @@ ohci_alloc_std(sc)
|
||||
ohci_soft_td_t *std;
|
||||
usbd_status r;
|
||||
int i, offs;
|
||||
ohci_dma_t dma;
|
||||
usb_dma_t dma;
|
||||
|
||||
if (!sc->sc_freetds) {
|
||||
DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
|
||||
@ -311,7 +254,7 @@ ohci_alloc_std(sc)
|
||||
M_USBDEV, M_NOWAIT);
|
||||
if (!std)
|
||||
return 0;
|
||||
r = ohci_allocmem(sc, OHCI_TD_SIZE * OHCI_TD_CHUNK,
|
||||
r = usb_allocmem(sc->sc_dmatag, OHCI_TD_SIZE * OHCI_TD_CHUNK,
|
||||
OHCI_TD_ALIGN, &dma);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
free(std, M_USBDEV);
|
||||
@ -367,7 +310,8 @@ ohci_init(sc)
|
||||
LIST_INIT(&sc->sc_hash_tds[i]);
|
||||
|
||||
/* Allocate the HCCA area. */
|
||||
r = ohci_allocmem(sc, OHCI_HCCA_SIZE, OHCI_HCCA_ALIGN,&sc->sc_hccadma);
|
||||
r = usb_allocmem(sc->sc_dmatag, OHCI_HCCA_SIZE,
|
||||
OHCI_HCCA_ALIGN, &sc->sc_hccadma);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
sc->sc_hcca = (struct ohci_hcca *)KERNADDR(&sc->sc_hccadma);
|
||||
@ -516,7 +460,7 @@ ohci_init(sc)
|
||||
bad2:
|
||||
ohci_free_sed(sc, sc->sc_bulk_head);
|
||||
bad1:
|
||||
ohci_freemem(sc, &sc->sc_hccadma);
|
||||
usb_freemem(sc->sc_dmatag, &sc->sc_hccadma);
|
||||
return (r);
|
||||
}
|
||||
|
||||
@ -736,7 +680,7 @@ ohci_ctrl_done(sc, reqh)
|
||||
{
|
||||
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
||||
u_int len = opipe->u.ctl.length;
|
||||
ohci_dma_t *dma;
|
||||
usb_dma_t *dma;
|
||||
|
||||
DPRINTFN(10,("ohci_ctrl_done: reqh=%p\n", reqh));
|
||||
|
||||
@ -749,7 +693,7 @@ ohci_ctrl_done(sc, reqh)
|
||||
dma = &opipe->u.ctl.datadma;
|
||||
if (reqh->request.bmRequestType & UT_READ)
|
||||
memcpy(reqh->buffer, KERNADDR(dma), len);
|
||||
ohci_freemem(sc, dma);
|
||||
usb_freemem(sc->sc_dmatag, dma);
|
||||
}
|
||||
}
|
||||
|
||||
@ -759,7 +703,7 @@ ohci_intr_done(sc, reqh)
|
||||
usbd_request_handle reqh;
|
||||
{
|
||||
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
||||
ohci_dma_t *dma;
|
||||
usb_dma_t *dma;
|
||||
ohci_soft_ed_t *sed = opipe->sed;
|
||||
ohci_soft_td_t *xfer, *tail;
|
||||
|
||||
@ -795,7 +739,7 @@ ohci_intr_done(sc, reqh)
|
||||
sed->ed->ed_tailp = tail->physaddr;
|
||||
opipe->tail = tail;
|
||||
} else {
|
||||
ohci_freemem(sc, dma);
|
||||
usb_freemem(sc->sc_dmatag, dma);
|
||||
}
|
||||
}
|
||||
|
||||
@ -805,7 +749,7 @@ ohci_bulk_done(sc, reqh)
|
||||
usbd_request_handle reqh;
|
||||
{
|
||||
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
|
||||
ohci_dma_t *dma;
|
||||
usb_dma_t *dma;
|
||||
|
||||
|
||||
DPRINTFN(10,("ohci_bulk_done: reqh=%p, actlen=%d\n",
|
||||
@ -814,7 +758,7 @@ ohci_bulk_done(sc, reqh)
|
||||
dma = &opipe->u.bulk.datadma;
|
||||
if (reqh->request.bmRequestType & UT_READ)
|
||||
memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);
|
||||
ohci_freemem(sc, dma);
|
||||
usb_freemem(sc->sc_dmatag, dma);
|
||||
}
|
||||
|
||||
void
|
||||
@ -854,7 +798,7 @@ ohci_rhsc(sc, reqh)
|
||||
|
||||
if (reqh->pipe->intrreqh != reqh) {
|
||||
sc->sc_intrreqh = 0;
|
||||
ohci_freemem(sc, &opipe->u.intr.datadma);
|
||||
usb_freemem(sc->sc_dmatag, &opipe->u.intr.datadma);
|
||||
}
|
||||
}
|
||||
|
||||
@ -903,7 +847,7 @@ ohci_device_request(reqh)
|
||||
int addr = dev->address;
|
||||
ohci_soft_td_t *setup, *xfer = 0, *stat, *next, *tail;
|
||||
ohci_soft_ed_t *sed;
|
||||
ohci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
int isread;
|
||||
int len;
|
||||
usbd_status r;
|
||||
@ -946,7 +890,7 @@ ohci_device_request(reqh)
|
||||
r = USBD_NOMEM;
|
||||
goto bad3;
|
||||
}
|
||||
r = ohci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto bad4;
|
||||
xfer->td->td_flags =
|
||||
@ -1218,8 +1162,9 @@ ohci_open(pipe)
|
||||
switch (ed->bmAttributes & UE_XFERTYPE) {
|
||||
case UE_CONTROL:
|
||||
pipe->methods = &ohci_device_ctrl_methods;
|
||||
r = ohci_allocmem(sc, sizeof(ohci_dma_t), 0,
|
||||
&opipe->u.ctl.reqdma);
|
||||
r = usb_allocmem(sc->sc_dmatag,
|
||||
sizeof(usb_device_request_t),
|
||||
0, &opipe->u.ctl.reqdma);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto bad;
|
||||
s = splusb();
|
||||
@ -1654,7 +1599,7 @@ ohci_root_intr_transfer(reqh)
|
||||
usbd_pipe_handle pipe = reqh->pipe;
|
||||
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
|
||||
struct ohci_pipe *upipe = (struct ohci_pipe *)pipe;
|
||||
ohci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
usbd_status r;
|
||||
int len;
|
||||
|
||||
@ -1663,7 +1608,7 @@ ohci_root_intr_transfer(reqh)
|
||||
if (len == 0)
|
||||
return (USBD_INVAL); /* XXX should it be? */
|
||||
|
||||
r = ohci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
sc->sc_intrreqh = reqh;
|
||||
@ -1756,7 +1701,7 @@ ohci_device_bulk_transfer(reqh)
|
||||
int addr = dev->address;
|
||||
ohci_soft_td_t *xfer, *tail;
|
||||
ohci_soft_ed_t *sed;
|
||||
ohci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
usbd_status r;
|
||||
int s, len, isread;
|
||||
|
||||
@ -1773,7 +1718,7 @@ ohci_device_bulk_transfer(reqh)
|
||||
|
||||
opipe->u.bulk.length = len;
|
||||
|
||||
r = ohci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto ret1;
|
||||
|
||||
@ -1820,7 +1765,7 @@ ohci_device_bulk_transfer(reqh)
|
||||
return (USBD_IN_PROGRESS);
|
||||
|
||||
ret2:
|
||||
ohci_freemem(sc, dmap);
|
||||
usb_freemem(sc->sc_dmatag, dmap);
|
||||
ret1:
|
||||
return (r);
|
||||
}
|
||||
@ -1869,7 +1814,7 @@ ohci_device_intr_transfer(reqh)
|
||||
ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
|
||||
ohci_soft_ed_t *sed = opipe->sed;
|
||||
ohci_soft_td_t *xfer, *tail;
|
||||
ohci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
usbd_status r;
|
||||
int len;
|
||||
int s;
|
||||
@ -1893,7 +1838,7 @@ ohci_device_intr_transfer(reqh)
|
||||
}
|
||||
tail->reqh = 0;
|
||||
|
||||
r = ohci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto ret2;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ohcivar.h,v 1.1 1998/07/12 19:51:59 augustss Exp $ */
|
||||
/* $NetBSD: ohcivar.h,v 1.2 1998/07/24 21:09:07 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
@ -36,17 +36,6 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
typedef struct ohci_dma {
|
||||
bus_dmamap_t map;
|
||||
caddr_t kaddr;
|
||||
bus_dma_segment_t segs[1];
|
||||
int nsegs;
|
||||
size_t size;
|
||||
struct ohci_dma *next;
|
||||
} ohci_dma_t;
|
||||
#define DMAADDR(dma) ((dma)->segs[0].ds_addr)
|
||||
#define KERNADDR(dma) ((void *)((dma)->kaddr))
|
||||
|
||||
typedef struct ohci_soft_ed {
|
||||
ohci_ed_t *ed;
|
||||
struct ohci_soft_ed *next;
|
||||
@ -79,7 +68,7 @@ typedef struct ohci_softc {
|
||||
bus_dma_tag_t sc_dmatag; /* DMA tag */
|
||||
/* XXX should keep track of all DMA memory */
|
||||
|
||||
ohci_dma_t sc_hccadma;
|
||||
usb_dma_t sc_hccadma;
|
||||
struct ohci_hcca *sc_hcca;
|
||||
ohci_soft_ed_t *sc_eds[OHCI_NO_EDS];
|
||||
u_int sc_bws[OHCI_NO_INTRS];
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: uhci.c,v 1.6 1998/07/23 13:44:21 augustss Exp $ */
|
||||
/* $NetBSD: uhci.c,v 1.7 1998/07/24 21:09:07 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
@ -55,15 +55,14 @@
|
||||
#include <sys/queue.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
|
||||
#include <dev/usb/usb_mem.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/usb/uhcireg.h>
|
||||
#include <dev/usb/uhcivar.h>
|
||||
|
||||
@ -78,21 +77,21 @@ struct uhci_pipe {
|
||||
/* Control pipe */
|
||||
struct {
|
||||
uhci_soft_qh_t *sqh;
|
||||
uhci_dma_t reqdma;
|
||||
uhci_dma_t datadma;
|
||||
usb_dma_t reqdma;
|
||||
usb_dma_t datadma;
|
||||
uhci_soft_td_t *setup, *stat, *xferend;
|
||||
u_int length;
|
||||
} ctl;
|
||||
/* Interrupt pipe */
|
||||
struct {
|
||||
uhci_dma_t datadma;
|
||||
usb_dma_t datadma;
|
||||
int npoll;
|
||||
uhci_soft_qh_t **qhs;
|
||||
} intr;
|
||||
/* Bulk pipe */
|
||||
struct {
|
||||
uhci_soft_qh_t *sqh;
|
||||
uhci_dma_t datadma;
|
||||
usb_dma_t datadma;
|
||||
u_int length;
|
||||
int isread;
|
||||
} bulk;
|
||||
@ -107,8 +106,6 @@ int uhci_global_init_done = 0;
|
||||
LIST_HEAD(, uhci_intr_info) uhci_ii_free;
|
||||
|
||||
void uhci_busreset __P((uhci_softc_t *));
|
||||
usbd_status uhci_allocmem __P((uhci_softc_t *,size_t,size_t,uhci_dma_t *));
|
||||
void uhci_freemem __P((uhci_softc_t *, uhci_dma_t *));
|
||||
void uhci_run __P((uhci_softc_t *, int run));
|
||||
uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *));
|
||||
void uhci_free_std __P((uhci_softc_t *, uhci_soft_td_t *));
|
||||
@ -123,7 +120,7 @@ void uhci_exit_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *));
|
||||
void uhci_free_std_chain __P((uhci_softc_t *,
|
||||
uhci_soft_td_t *, uhci_soft_td_t *));
|
||||
usbd_status uhci_alloc_std_chain __P((struct uhci_pipe *, uhci_softc_t *,
|
||||
int, int, uhci_dma_t *,
|
||||
int, int, usb_dma_t *,
|
||||
uhci_soft_td_t **,
|
||||
uhci_soft_td_t **));
|
||||
void uhci_timo __P((void *));
|
||||
@ -244,7 +241,7 @@ uhci_init(sc)
|
||||
int i, j;
|
||||
uhci_soft_qh_t *csqh, *bsqh, *sqh;
|
||||
uhci_soft_td_t *std;
|
||||
uhci_dma_t dma;
|
||||
usb_dma_t dma;
|
||||
|
||||
DPRINTFN(1,("uhci_init: start\n"));
|
||||
|
||||
@ -262,8 +259,8 @@ uhci_init(sc)
|
||||
UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
|
||||
|
||||
/* Allocate and initialize real frame array. */
|
||||
r = uhci_allocmem(sc, UHCI_FRAMELIST_COUNT *
|
||||
sizeof(uhci_physaddr_t),
|
||||
r = usb_allocmem(sc->sc_dmatag,
|
||||
UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
|
||||
UHCI_FRAMELIST_ALIGN, &dma);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
@ -443,7 +440,7 @@ uhci_timo(addr)
|
||||
if (reqh->pipe->intrreqh == reqh) {
|
||||
timeout(uhci_timo, addr, sc->sc_ival);
|
||||
} else {
|
||||
uhci_freemem(sc, &upipe->u.intr.datadma);
|
||||
usb_freemem(sc->sc_dmatag, &upipe->u.intr.datadma);
|
||||
}
|
||||
}
|
||||
|
||||
@ -696,13 +693,26 @@ uhci_ii_done(ii, timo)
|
||||
u_int32_t tst;
|
||||
int len, status;
|
||||
|
||||
DPRINTFN(10, ("uhci_check_intr: ii=%p ready\n", ii));
|
||||
DPRINTFN(10, ("uhci_ii_done: ii=%p ready %d\n", ii, timo));
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
{
|
||||
int s = splhigh();
|
||||
if (ii->isdone) {
|
||||
printf("uhci_ii_done: is done!\n");
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
ii->isdone = 1;
|
||||
splx(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The transfer is done, compute length and status. */
|
||||
for (len = status = 0, std = ii->stdstart;
|
||||
std != 0;
|
||||
std = std->td->link.std) {
|
||||
tst = std->td->td_status;;
|
||||
tst = std->td->td_status;
|
||||
status |= tst;
|
||||
#ifdef USB_DEBUG
|
||||
if ((tst & UHCI_TD_ERROR) && uhcidebug) {
|
||||
@ -743,6 +753,7 @@ uhci_ii_done(ii, timo)
|
||||
break;
|
||||
case UE_ISOCHRONOUS:
|
||||
printf("uhci_ii_done: ISO??\n");
|
||||
break;
|
||||
case UE_BULK:
|
||||
uhci_bulk_done(ii);
|
||||
break;
|
||||
@ -842,69 +853,14 @@ uhci_run(sc, run)
|
||||
|
||||
/*
|
||||
* Memory management routines.
|
||||
* uhci_allocmem allocates DMAable memory.
|
||||
* uhci_alloc_std allocates TDs
|
||||
* uhci_alloc_sqh allocates QHs
|
||||
* uhci_alloc_buffer allocates transfer buffers.
|
||||
* The latter three routines do their own free list management,
|
||||
* These two routines do their own free list management,
|
||||
* partly for speed, partly because allocating DMAable memory
|
||||
* has page size granularaity so much memory would be wasted if
|
||||
* only one TD/QH (32 bytes) was placed in each alloacted chunk.
|
||||
*/
|
||||
|
||||
usbd_status
|
||||
uhci_allocmem(sc, size, align, p)
|
||||
uhci_softc_t *sc;
|
||||
size_t size;
|
||||
size_t align;
|
||||
uhci_dma_t *p;
|
||||
{
|
||||
int error;
|
||||
|
||||
DPRINTFN(5, ("uhci_allocmem: size=%d align=%d\n", size, align));
|
||||
p->size = size;
|
||||
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
|
||||
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
|
||||
&p->nsegs, BUS_DMA_NOWAIT);
|
||||
if (error)
|
||||
return (USBD_NOMEM);
|
||||
|
||||
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
|
||||
&p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
|
||||
if (error)
|
||||
goto free;
|
||||
|
||||
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
|
||||
0, BUS_DMA_NOWAIT, &p->map);
|
||||
if (error)
|
||||
goto unmap;
|
||||
|
||||
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->kaddr,p->size, NULL,
|
||||
BUS_DMA_NOWAIT);
|
||||
if (error)
|
||||
goto destroy;
|
||||
return 0;
|
||||
|
||||
destroy:
|
||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
||||
unmap:
|
||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
||||
free:
|
||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
||||
return (USBD_NOMEM);
|
||||
}
|
||||
|
||||
void
|
||||
uhci_freemem(sc, p)
|
||||
uhci_softc_t *sc;
|
||||
uhci_dma_t *p;
|
||||
{
|
||||
bus_dmamap_unload(sc->sc_dmatag, p->map);
|
||||
bus_dmamap_destroy(sc->sc_dmatag, p->map);
|
||||
bus_dmamem_unmap(sc->sc_dmatag, p->kaddr, p->size);
|
||||
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
|
||||
}
|
||||
|
||||
uhci_soft_td_t *
|
||||
uhci_alloc_std(sc)
|
||||
uhci_softc_t *sc;
|
||||
@ -912,7 +868,7 @@ uhci_alloc_std(sc)
|
||||
uhci_soft_td_t *std;
|
||||
usbd_status r;
|
||||
int i;
|
||||
uhci_dma_t dma;
|
||||
usb_dma_t dma;
|
||||
|
||||
if (!sc->sc_freetds) {
|
||||
DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
|
||||
@ -920,7 +876,7 @@ uhci_alloc_std(sc)
|
||||
M_USBDEV, M_NOWAIT);
|
||||
if (!std)
|
||||
return 0;
|
||||
r = uhci_allocmem(sc, UHCI_TD_SIZE * UHCI_TD_CHUNK,
|
||||
r = usb_allocmem(sc->sc_dmatag, UHCI_TD_SIZE * UHCI_TD_CHUNK,
|
||||
UHCI_TD_ALIGN, &dma);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
free(std, M_USBDEV);
|
||||
@ -946,6 +902,14 @@ uhci_free_std(sc, std)
|
||||
uhci_softc_t *sc;
|
||||
uhci_soft_td_t *std;
|
||||
{
|
||||
#ifdef DIAGNOSTIC
|
||||
#define TD_IS_FREE 0x12345678
|
||||
if (std->td->td_token == TD_IS_FREE) {
|
||||
printf("uhci_free_std: freeing free TD %p\n", std);
|
||||
return;
|
||||
}
|
||||
std->td->td_token = TD_IS_FREE;
|
||||
#endif
|
||||
std->td->link.std = sc->sc_freetds;
|
||||
sc->sc_freetds = std;
|
||||
}
|
||||
@ -957,7 +921,7 @@ uhci_alloc_sqh(sc)
|
||||
uhci_soft_qh_t *sqh;
|
||||
usbd_status r;
|
||||
int i, offs;
|
||||
uhci_dma_t dma;
|
||||
usb_dma_t dma;
|
||||
|
||||
if (!sc->sc_freeqhs) {
|
||||
DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
|
||||
@ -965,7 +929,7 @@ uhci_alloc_sqh(sc)
|
||||
M_USBDEV, M_NOWAIT);
|
||||
if (!sqh)
|
||||
return 0;
|
||||
r = uhci_allocmem(sc, UHCI_QH_SIZE * UHCI_QH_CHUNK,
|
||||
r = usb_allocmem(sc->sc_dmatag, UHCI_QH_SIZE * UHCI_QH_CHUNK,
|
||||
UHCI_QH_ALIGN, &dma);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
free(sqh, M_USBDEV);
|
||||
@ -995,47 +959,6 @@ uhci_free_sqh(sc, sqh)
|
||||
sc->sc_freeqhs = sqh;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void *
|
||||
uhci_alloc_buffer(sc, size)
|
||||
uhci_softc_t *sc;
|
||||
size_t size;
|
||||
{
|
||||
struct uhci_buffer *buf;
|
||||
usbd_status r;
|
||||
int i, offs;
|
||||
uhci_dma_t dma;
|
||||
|
||||
if (!sc->sc_freebuffers) {
|
||||
DPRINTFN(2, ("uhci_alloc_buffer: allocating chunk\n"));
|
||||
r = uhci_allocmem(sc, UHCI_BUFFER_SIZE * BUFFER_CHUNK,
|
||||
0, &dma);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return 0;
|
||||
for(i = 0; i < BUFFER_CHUNK; i++, sqh++) {
|
||||
offs = i * UHCI_BUFFER_SIZE;
|
||||
sqh->physaddr = DMAADDR(&dma) + offs;
|
||||
sqh->qh = (uhci_qh_t *)
|
||||
((char *)KERNADDR(&dma) + offs);
|
||||
sqh->qh->hlink = sc->sc_freeqhs;
|
||||
sc->sc_freeqhs = sqh;
|
||||
}
|
||||
}
|
||||
sqh = sc->sc_freeqhs;
|
||||
sc->sc_freeqhs = sqh->qh->hlink;
|
||||
memset(sqh->qh, 0, UHCI_QH_SIZE);
|
||||
return sqh;
|
||||
}
|
||||
|
||||
void
|
||||
uhci_free_buffer(sc, p, size)
|
||||
uhci_softc_t *sc;
|
||||
void *p;
|
||||
size_t size;
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enter a list of transfers onto a control queue.
|
||||
* Called at splusb()
|
||||
@ -1069,7 +992,7 @@ uhci_alloc_std_chain(upipe, sc, len, rd, dma, sp, ep)
|
||||
struct uhci_pipe *upipe;
|
||||
uhci_softc_t *sc;
|
||||
int len, rd;
|
||||
uhci_dma_t *dma;
|
||||
usb_dma_t *dma;
|
||||
uhci_soft_td_t **sp, **ep;
|
||||
{
|
||||
uhci_soft_td_t *p, *lastp;
|
||||
@ -1140,7 +1063,7 @@ uhci_device_bulk_transfer(reqh)
|
||||
uhci_intr_info_t *ii = upipe->iinfo;
|
||||
uhci_soft_td_t *xfer, *xferend;
|
||||
uhci_soft_qh_t *sqh;
|
||||
uhci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
usbd_status r;
|
||||
int len, isread;
|
||||
int s;
|
||||
@ -1159,7 +1082,7 @@ uhci_device_bulk_transfer(reqh)
|
||||
upipe->u.bulk.isread = isread;
|
||||
upipe->u.bulk.length = len;
|
||||
|
||||
r = uhci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto ret1;
|
||||
r = uhci_alloc_std_chain(upipe, sc, len, isread,
|
||||
@ -1182,6 +1105,9 @@ uhci_device_bulk_transfer(reqh)
|
||||
ii->reqh = reqh;
|
||||
ii->stdstart = xfer;
|
||||
ii->stdend = xferend;
|
||||
#ifdef DIAGNOSTIC
|
||||
ii->isdone = 0;
|
||||
#endif
|
||||
|
||||
sqh->qh->elink = xfer;
|
||||
sqh->qh->qh_elink = xfer->physaddr;
|
||||
@ -1206,7 +1132,7 @@ uhci_device_bulk_transfer(reqh)
|
||||
|
||||
ret2:
|
||||
if (len != 0)
|
||||
uhci_freemem(sc, dmap);
|
||||
usb_freemem(sc->sc_dmatag, dmap);
|
||||
ret1:
|
||||
return (r);
|
||||
}
|
||||
@ -1263,7 +1189,7 @@ uhci_device_intr_transfer(reqh)
|
||||
uhci_intr_info_t *ii = upipe->iinfo;
|
||||
uhci_soft_td_t *xfer, *xferend;
|
||||
uhci_soft_qh_t *sqh;
|
||||
uhci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
usbd_status r;
|
||||
int len, i;
|
||||
int s;
|
||||
@ -1279,7 +1205,7 @@ uhci_device_intr_transfer(reqh)
|
||||
if (len == 0)
|
||||
return (USBD_INVAL); /* XXX should it be? */
|
||||
|
||||
r = uhci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto ret1;
|
||||
r = uhci_alloc_std_chain(upipe, sc, len, 1, dmap, &xfer, &xferend);
|
||||
@ -1300,6 +1226,9 @@ uhci_device_intr_transfer(reqh)
|
||||
ii->reqh = reqh;
|
||||
ii->stdstart = xfer;
|
||||
ii->stdend = xferend;
|
||||
#ifdef DIAGNOSTIC
|
||||
ii->isdone = 0;
|
||||
#endif
|
||||
|
||||
DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n", upipe->u.intr.qhs[0]));
|
||||
for (i = 0; i < upipe->u.intr.npoll; i++) {
|
||||
@ -1321,7 +1250,7 @@ DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n", upipe->u.intr.qhs[0]));
|
||||
|
||||
ret2:
|
||||
if (len != 0)
|
||||
uhci_freemem(sc, dmap);
|
||||
usb_freemem(sc->sc_dmatag, dmap);
|
||||
ret1:
|
||||
return (r);
|
||||
}
|
||||
@ -1354,6 +1283,7 @@ uhci_device_intr_abort(reqh)
|
||||
{
|
||||
struct uhci_pipe *upipe;
|
||||
|
||||
DPRINTFN(1, ("uhci_device_intr_abort: reqh=%p\n", reqh));
|
||||
/* XXX inactivate */
|
||||
usbd_delay_ms(2); /* make sure it is finished */
|
||||
if (reqh->pipe->intrreqh == reqh) {
|
||||
@ -1414,7 +1344,7 @@ uhci_device_request(reqh)
|
||||
uhci_intr_info_t *ii = upipe->iinfo;
|
||||
uhci_soft_td_t *setup, *xfer, *stat, *next, *xferend;
|
||||
uhci_soft_qh_t *sqh;
|
||||
uhci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
int len;
|
||||
u_int32_t ls;
|
||||
usbd_status r;
|
||||
@ -1437,7 +1367,7 @@ uhci_device_request(reqh)
|
||||
|
||||
/* Set up data transaction */
|
||||
if (len != 0) {
|
||||
r = uhci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto ret1;
|
||||
upipe->pipe.endpoint->toggle = 1;
|
||||
@ -1487,6 +1417,9 @@ uhci_device_request(reqh)
|
||||
ii->reqh = reqh;
|
||||
ii->stdstart = setup;
|
||||
ii->stdend = stat;
|
||||
#ifdef DIAGNOSTIC
|
||||
ii->isdone = 0;
|
||||
#endif
|
||||
|
||||
sqh->qh->elink = setup;
|
||||
sqh->qh->qh_elink = setup->physaddr;
|
||||
@ -1524,7 +1457,7 @@ uhci_device_request(reqh)
|
||||
|
||||
ret2:
|
||||
if (len != 0)
|
||||
uhci_freemem(sc, dmap);
|
||||
usb_freemem(sc->sc_dmatag, dmap);
|
||||
ret1:
|
||||
return (r);
|
||||
}
|
||||
@ -1536,7 +1469,7 @@ uhci_intr_done(ii)
|
||||
uhci_softc_t *sc = ii->sc;
|
||||
usbd_request_handle reqh = ii->reqh;
|
||||
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
||||
uhci_dma_t *dma;
|
||||
usb_dma_t *dma;
|
||||
uhci_soft_qh_t *sqh;
|
||||
int i, npoll;
|
||||
|
||||
@ -1571,13 +1504,16 @@ uhci_intr_done(ii)
|
||||
|
||||
ii->stdstart = xfer;
|
||||
ii->stdend = xferend;
|
||||
#ifdef DIAGNOSTIC
|
||||
ii->isdone = 0;
|
||||
#endif
|
||||
for (i = 0; i < npoll; i++) {
|
||||
sqh = upipe->u.intr.qhs[i];
|
||||
sqh->qh->elink = xfer;
|
||||
sqh->qh->qh_elink = xfer->physaddr;
|
||||
}
|
||||
} else {
|
||||
uhci_freemem(sc, dma);
|
||||
usb_freemem(sc->sc_dmatag, dma);
|
||||
ii->stdstart = 0; /* mark as inactive */
|
||||
}
|
||||
}
|
||||
@ -1591,11 +1527,13 @@ uhci_ctrl_done(ii)
|
||||
usbd_request_handle reqh = ii->reqh;
|
||||
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
||||
u_int len = upipe->u.ctl.length;
|
||||
uhci_dma_t *dma;
|
||||
usb_dma_t *dma;
|
||||
uhci_td_t *htd = ii->stdstart->td;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (!reqh->isreq)
|
||||
panic("uhci_ctrl_done: not a request\n");
|
||||
#endif
|
||||
|
||||
LIST_REMOVE(ii, list); /* remove from active list */
|
||||
|
||||
@ -1606,7 +1544,7 @@ uhci_ctrl_done(ii)
|
||||
if (reqh->request.bmRequestType & UT_READ)
|
||||
memcpy(reqh->buffer, KERNADDR(dma), len);
|
||||
uhci_free_std_chain(sc, htd->link.std, ii->stdend);
|
||||
uhci_freemem(sc, dma);
|
||||
usb_freemem(sc->sc_dmatag, dma);
|
||||
}
|
||||
DPRINTFN(5, ("uhci_ctrl_done: length=%d\n", reqh->actlen));
|
||||
}
|
||||
@ -1620,7 +1558,7 @@ uhci_bulk_done(ii)
|
||||
usbd_request_handle reqh = ii->reqh;
|
||||
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
|
||||
u_int len = upipe->u.bulk.length;
|
||||
uhci_dma_t *dma;
|
||||
usb_dma_t *dma;
|
||||
uhci_td_t *htd = ii->stdstart->td;
|
||||
|
||||
LIST_REMOVE(ii, list); /* remove from active list */
|
||||
@ -1632,7 +1570,7 @@ uhci_bulk_done(ii)
|
||||
if (upipe->u.bulk.isread && len != 0)
|
||||
memcpy(reqh->buffer, KERNADDR(dma), len);
|
||||
uhci_free_std_chain(sc, htd->link.std, 0);
|
||||
uhci_freemem(sc, dma);
|
||||
usb_freemem(sc->sc_dmatag, dma);
|
||||
}
|
||||
DPRINTFN(4, ("uhci_bulk_done: length=%d\n", reqh->actlen));
|
||||
/* XXX compute new toggle */
|
||||
@ -1796,8 +1734,9 @@ uhci_open(pipe)
|
||||
uhci_free_std(sc, upipe->u.ctl.setup);
|
||||
goto bad;
|
||||
}
|
||||
r = uhci_allocmem(sc, sizeof(uhci_dma_t), 0,
|
||||
&upipe->u.ctl.reqdma);
|
||||
r = usb_allocmem(sc->sc_dmatag,
|
||||
sizeof(usb_device_request_t),
|
||||
0, &upipe->u.ctl.reqdma);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
uhci_free_sqh(sc, upipe->u.ctl.sqh);
|
||||
uhci_free_std(sc, upipe->u.ctl.setup);
|
||||
@ -2269,7 +2208,7 @@ uhci_root_intr_transfer(reqh)
|
||||
usbd_pipe_handle pipe = reqh->pipe;
|
||||
uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
|
||||
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
|
||||
uhci_dma_t *dmap;
|
||||
usb_dma_t *dmap;
|
||||
usbd_status r;
|
||||
int len;
|
||||
|
||||
@ -2281,7 +2220,7 @@ uhci_root_intr_transfer(reqh)
|
||||
if (len == 0)
|
||||
return (USBD_INVAL); /* XXX should it be? */
|
||||
|
||||
r = uhci_allocmem(sc, len, 0, dmap);
|
||||
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: uhcivar.h,v 1.1 1998/07/12 19:51:59 augustss Exp $ */
|
||||
/* $NetBSD: uhcivar.h,v 1.2 1998/07/24 21:09:08 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
@ -54,17 +54,6 @@
|
||||
typedef struct uhci_soft_qh uhci_soft_qh_t;
|
||||
typedef struct uhci_soft_td uhci_soft_td_t;
|
||||
|
||||
typedef struct uhci_dma {
|
||||
bus_dmamap_t map;
|
||||
caddr_t kaddr;
|
||||
bus_dma_segment_t segs[1];
|
||||
int nsegs;
|
||||
size_t size;
|
||||
struct uhci_dma *next;
|
||||
} uhci_dma_t;
|
||||
#define DMAADDR(dma) ((dma)->segs[0].ds_addr)
|
||||
#define KERNADDR(dma) ((void *)((dma)->kaddr))
|
||||
|
||||
/*
|
||||
* An interrupt info struct contains the information needed to
|
||||
* execute a requested routine when the controller generates an
|
||||
@ -78,6 +67,9 @@ typedef struct uhci_intr_info {
|
||||
uhci_soft_td_t *stdstart;
|
||||
uhci_soft_td_t *stdend;
|
||||
LIST_ENTRY(uhci_intr_info) list;
|
||||
#ifdef DIAGNOSTIC
|
||||
int isdone;
|
||||
#endif
|
||||
} uhci_intr_info_t;
|
||||
|
||||
/*
|
||||
@ -158,7 +150,7 @@ typedef struct uhci_softc {
|
||||
#define UHCI_HAS_LOCK 1
|
||||
#define UHCI_WANT_LOCK 2
|
||||
|
||||
uhci_dma_t *sc_mallocs;
|
||||
usb_dma_t *sc_mallocs;
|
||||
} uhci_softc_t;
|
||||
|
||||
usbd_status uhci_init __P((uhci_softc_t *));
|
||||
|
238
sys/dev/usb/usb_mem.c
Normal file
238
sys/dev/usb/usb_mem.c
Normal file
@ -0,0 +1,238 @@
|
||||
/* $NetBSD: usb_mem.c,v 1.1 1998/07/24 21:09:08 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* Carlstedt Research & Technology
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usb_mem.h>
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (usbdebug) printf x
|
||||
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||
extern int usbdebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
#define USB_MEM_SMALL 64
|
||||
#define USB_MEM_CHUNKS 64
|
||||
#define USB_MEM_BLOCK (USB_MEM_SMALL * USB_MEM_CHUNKS)
|
||||
|
||||
/* This struct is overlayed on free fragments. */
|
||||
struct usb_frag_dma {
|
||||
usb_dma_block_t *block;
|
||||
u_int offs;
|
||||
LIST_ENTRY(usb_frag_dma) next;
|
||||
};
|
||||
|
||||
usbd_status usb_block_allocmem
|
||||
__P((bus_dma_tag_t, size_t, size_t, usb_dma_block_t **));
|
||||
void usb_block_real_freemem __P((usb_dma_block_t *));
|
||||
void usb_block_freemem __P((usb_dma_block_t *));
|
||||
|
||||
LIST_HEAD(, usb_block_dma) usb_blk_freelist =
|
||||
LIST_HEAD_INITIALIZER(usb_blk_freelist);
|
||||
/* XXX should have different free list for different tags */
|
||||
LIST_HEAD(, usb_frag_dma) usb_frag_freelist =
|
||||
LIST_HEAD_INITIALIZER(usb_frag_freelist);
|
||||
|
||||
usbd_status
|
||||
usb_block_allocmem(tag, size, align, dmap)
|
||||
bus_dma_tag_t tag;
|
||||
size_t size;
|
||||
size_t align;
|
||||
usb_dma_block_t **dmap;
|
||||
{
|
||||
int error;
|
||||
usb_dma_block_t *p;
|
||||
|
||||
DPRINTFN(5, ("usb_block_allocmem: size=%d align=%d\n", size, align));
|
||||
|
||||
/* 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) {
|
||||
LIST_REMOVE(p, next);
|
||||
*dmap = p;
|
||||
DPRINTFN(6, ("usb_block_allocmem: free list size=%d\n",
|
||||
p->size));
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTFN(6, ("usb_block_allocmem: no free\n"));
|
||||
p = malloc(sizeof *p, M_USB, M_NOWAIT);
|
||||
if (p == 0)
|
||||
return (USBD_NOMEM);
|
||||
*dmap = p;
|
||||
|
||||
p->tag = tag;
|
||||
p->size = size;
|
||||
p->align = align;
|
||||
error = bus_dmamem_alloc(tag, p->size, align, 0,
|
||||
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
|
||||
&p->nsegs, BUS_DMA_NOWAIT);
|
||||
if (error)
|
||||
return (USBD_NOMEM);
|
||||
|
||||
error = bus_dmamem_map(tag, p->segs, p->nsegs, p->size,
|
||||
&p->kaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
|
||||
if (error)
|
||||
goto free;
|
||||
|
||||
error = bus_dmamap_create(tag, p->size, 1, p->size,
|
||||
0, BUS_DMA_NOWAIT, &p->map);
|
||||
if (error)
|
||||
goto unmap;
|
||||
|
||||
error = bus_dmamap_load(tag, p->map, p->kaddr,p->size, NULL,
|
||||
BUS_DMA_NOWAIT);
|
||||
if (error)
|
||||
goto destroy;
|
||||
return 0;
|
||||
|
||||
destroy:
|
||||
bus_dmamap_destroy(tag, p->map);
|
||||
unmap:
|
||||
bus_dmamem_unmap(tag, p->kaddr, p->size);
|
||||
free:
|
||||
bus_dmamem_free(tag, p->segs, p->nsegs);
|
||||
return (USBD_NOMEM);
|
||||
}
|
||||
|
||||
void
|
||||
usb_block_real_freemem(p)
|
||||
usb_dma_block_t *p;
|
||||
{
|
||||
bus_dmamap_unload(p->tag, p->map);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not free the memory unconditionally since we might be called
|
||||
* from an interrupt context and that is BAD.
|
||||
* XXX when you we really free?
|
||||
*/
|
||||
void
|
||||
usb_block_freemem(p)
|
||||
usb_dma_block_t *p;
|
||||
{
|
||||
DPRINTFN(6, ("usb_block_freemem: size=%d\n", p->size));
|
||||
LIST_INSERT_HEAD(&usb_blk_freelist, p, next);
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usb_allocmem(tag, size, align, p)
|
||||
bus_dma_tag_t tag;
|
||||
size_t size;
|
||||
size_t align;
|
||||
usb_dma_t *p;
|
||||
{
|
||||
usbd_status r;
|
||||
struct usb_frag_dma *f;
|
||||
usb_dma_block_t *b;
|
||||
int i;
|
||||
|
||||
/* 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);
|
||||
r = usb_block_allocmem(tag, size, align, &p->block);
|
||||
if (r == USBD_NORMAL_COMPLETION) {
|
||||
p->block->fullblock = 1;
|
||||
p->offs = 0;
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
DPRINTFN(1, ("usb_allocmem: adding fragments\n"));
|
||||
r = usb_block_allocmem(tag, USB_MEM_BLOCK, USB_MEM_SMALL, &b);
|
||||
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);
|
||||
DPRINTFN(5, ("usb_allocmem: use frag=%p size=%d\n", f, (int)size));
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
|
||||
void
|
||||
usb_freemem(tag, p)
|
||||
bus_dma_tag_t tag;
|
||||
usb_dma_t *p;
|
||||
{
|
||||
struct usb_frag_dma *f;
|
||||
|
||||
if (p->block->fullblock) {
|
||||
usb_block_freemem(p->block);
|
||||
return;
|
||||
}
|
||||
f = KERNADDR(p);
|
||||
f->block = p->block;
|
||||
f->offs = p->offs;
|
||||
LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
|
||||
DPRINTFN(5, ("usb_freemem: frag=%p\n", f));
|
||||
}
|
60
sys/dev/usb/usb_mem.h
Normal file
60
sys/dev/usb/usb_mem.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* $NetBSD: usb_mem.h,v 1.1 1998/07/24 21:09:08 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* Carlstedt Research & Technology
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
typedef struct usb_block_dma {
|
||||
bus_dma_tag_t tag;
|
||||
bus_dmamap_t map;
|
||||
caddr_t kaddr;
|
||||
bus_dma_segment_t segs[1];
|
||||
int nsegs;
|
||||
size_t size;
|
||||
size_t align;
|
||||
int fullblock;
|
||||
LIST_ENTRY(usb_block_dma) next;
|
||||
} usb_dma_block_t;
|
||||
|
||||
typedef struct {
|
||||
usb_dma_block_t *block;
|
||||
u_int offs;
|
||||
} usb_dma_t;
|
||||
|
||||
#define DMAADDR(dma) ((dma)->block->segs[0].ds_addr + (dma)->offs)
|
||||
#define KERNADDR(dma) ((void *)((dma)->block->kaddr + (dma)->offs))
|
||||
|
||||
usbd_status usb_allocmem __P((bus_dma_tag_t, size_t, size_t, usb_dma_t *));
|
||||
void usb_freemem __P((bus_dma_tag_t, usb_dma_t *));
|
Loading…
Reference in New Issue
Block a user