In USB land there is a lot of freelists. Every HC driver has one
freelist per type of descriptor and the memory allocator used to
populate these lists, usb_allocmem(), is a wrapper around
bus_dma{mem,map}* that uses two more lists.
I don't see the point of having per-softc lists, but maybe somebody
has a better understanding of this.
I'd like to remove these lists and use usb_allocmem() directly. The
first reason for this change is to reduce the number of layers on top
of the memory allocator to track memleaks. Since I need to change the
way ehci(4)'s descriptor are allocated when a transfer is submitted,
this would definitively help.
This diff only removes the freelists for the descriptors used by
control, interrupt and bulk transfers. Isochronous will follow.
Ok?
Index: ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.151
diff -u -p -r1.151 ehci.c
--- ehci.c 4 May 2014 14:42:36 -0000 1.151
+++ ehci.c 4 May 2014 14:44:08 -0000
@@ -2354,83 +2354,43 @@ struct ehci_soft_qh *
ehci_alloc_sqh(struct ehci_softc *sc)
{
struct ehci_soft_qh *sqh;
- usbd_status err;
- int i, offs;
struct usb_dma dma;
- if (sc->sc_freeqhs == NULL) {
- DPRINTFN(2, ("ehci_alloc_sqh: allocating chunk\n"));
- err = usb_allocmem(&sc->sc_bus, EHCI_SQH_SIZE * EHCI_SQH_CHUNK,
- EHCI_PAGE_SIZE, &dma);
-#ifdef EHCI_DEBUG
- if (err)
- printf("ehci_alloc_sqh: usb_allocmem()=%d\n", err);
-#endif
- if (err)
- return (NULL);
- for(i = 0; i < EHCI_SQH_CHUNK; i++) {
- offs = i * EHCI_SQH_SIZE;
- sqh = KERNADDR(&dma, offs);
- sqh->physaddr = DMAADDR(&dma, offs);
- sqh->dma = dma;
- sqh->offs = offs;
- sqh->next = sc->sc_freeqhs;
- sc->sc_freeqhs = sqh;
- }
- }
- sqh = sc->sc_freeqhs;
- sc->sc_freeqhs = sqh->next;
- memset(&sqh->qh, 0, sizeof(struct ehci_qh));
+ if (usb_allocmem(&sc->sc_bus, sizeof(*sqh), EHCI_QH_ALIGN, &dma))
+ return (NULL);
+
+ sqh = KERNADDR(&dma, 0);
+ sqh->physaddr = DMAADDR(&dma, 0);
+ sqh->dma = dma;
+ sqh->offs = 0;
sqh->next = NULL;
sqh->prev = NULL;
+ memset(&sqh->qh, 0, sizeof(struct ehci_qh));
+
return (sqh);
}
void
ehci_free_sqh(struct ehci_softc *sc, struct ehci_soft_qh *sqh)
{
- sqh->next = sc->sc_freeqhs;
- sc->sc_freeqhs = sqh;
+ usb_freemem(&sc->sc_bus, &sqh->dma);
}
struct ehci_soft_qtd *
ehci_alloc_sqtd(struct ehci_softc *sc)
{
struct ehci_soft_qtd *sqtd;
- usbd_status err;
- int i, offs;
struct usb_dma dma;
- int s;
- if (sc->sc_freeqtds == NULL) {
- DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));
- err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,
- EHCI_PAGE_SIZE, &dma);
-#ifdef EHCI_DEBUG
- if (err)
- printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err);
-#endif
- if (err)
- return (NULL);
- s = splusb();
- for(i = 0; i < EHCI_SQTD_CHUNK; i++) {
- offs = i * EHCI_SQTD_SIZE;
- sqtd = KERNADDR(&dma, offs);
- sqtd->physaddr = DMAADDR(&dma, offs);
- sqtd->dma = dma;
- sqtd->offs = offs;
- sqtd->nextqtd = sc->sc_freeqtds;
- sc->sc_freeqtds = sqtd;
- }
- splx(s);
- }
-
- s = splusb();
- sqtd = sc->sc_freeqtds;
- sc->sc_freeqtds = sqtd->nextqtd;
- memset(&sqtd->qtd, 0, sizeof(struct ehci_qtd));
+ if (usb_allocmem(&sc->sc_bus, sizeof(*sqtd), EHCI_QTD_ALIGN, &dma))
+ return (NULL);
+
+ sqtd = KERNADDR(&dma, 0);
+ sqtd->physaddr = DMAADDR(&dma, 0);
+ sqtd->dma = dma;
+ sqtd->offs = 0;
sqtd->nextqtd = NULL;
- splx(s);
+ memset(&sqtd->qtd, 0, sizeof(struct ehci_qtd));
return (sqtd);
}
@@ -2438,12 +2398,7 @@ ehci_alloc_sqtd(struct ehci_softc *sc)
void
ehci_free_sqtd(struct ehci_softc *sc, struct ehci_soft_qtd *sqtd)
{
- int s;
-
- s = splusb();
- sqtd->nextqtd = sc->sc_freeqtds;
- sc->sc_freeqtds = sqtd;
- splx(s);
+ usb_freemem(&sc->sc_bus, &sqtd->dma);
}
usbd_status
Index: ehcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.31
diff -u -p -r1.31 ehcivar.h
--- ehcivar.h 29 Apr 2014 12:45:29 -0000 1.31
+++ ehcivar.h 4 May 2014 14:44:08 -0000
@@ -39,8 +39,6 @@ struct ehci_soft_qtd {
LIST_ENTRY(ehci_soft_qtd) hnext;
u_int16_t len;
};
-#define EHCI_SQTD_SIZE ((sizeof (struct ehci_soft_qtd) + EHCI_QTD_ALIGN - 1) /
EHCI_QTD_ALIGN * EHCI_QTD_ALIGN)
-#define EHCI_SQTD_CHUNK (EHCI_PAGE_SIZE / EHCI_SQTD_SIZE)
struct ehci_soft_qh {
struct ehci_qh qh;
@@ -52,8 +50,6 @@ struct ehci_soft_qh {
int offs; /* QH's offset in struct usb_dma */
int islot;
};
-#define EHCI_SQH_SIZE ((sizeof (struct ehci_soft_qh) + EHCI_QH_ALIGN - 1) /
EHCI_QH_ALIGN * EHCI_QH_ALIGN)
-#define EHCI_SQH_CHUNK (EHCI_PAGE_SIZE / EHCI_SQH_SIZE)
struct ehci_soft_itd {
struct ehci_itd itd;
@@ -107,8 +103,6 @@ struct ehci_soft_islot {
#define EHCI_HASH_SIZE 128
#define EHCI_COMPANION_MAX 8
-#define EHCI_FREE_LIST_INTERVAL 100
-
struct ehci_softc {
struct usbd_bus sc_bus; /* base device */
bus_space_tag_t iot;
@@ -134,8 +128,6 @@ struct ehci_softc {
TAILQ_HEAD(, ehci_xfer) sc_intrhead;
- struct ehci_soft_qh *sc_freeqhs;
- struct ehci_soft_qtd *sc_freeqtds;
LIST_HEAD(sc_freeitds, ehci_soft_itd) sc_freeitds;
int sc_noport;
Index: ohci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ohci.c,v
retrieving revision 1.128
diff -u -p -r1.128 ohci.c
--- ohci.c 4 May 2014 14:42:36 -0000 1.128
+++ ohci.c 4 May 2014 14:44:09 -0000
@@ -98,6 +98,7 @@ usbd_status ohci_device_request(struct u
void ohci_add_ed(struct ohci_soft_ed *, struct ohci_soft_ed *);
void ohci_rem_ed(struct ohci_soft_ed *, struct ohci_soft_ed *);
void ohci_hash_add_td(struct ohci_softc *, struct ohci_soft_td *);
+void ohci_hash_rem_td(struct ohci_softc *, struct ohci_soft_td *);
struct ohci_soft_td *ohci_hash_find_td(struct ohci_softc *, ohci_physaddr_t);
void ohci_hash_add_itd(struct ohci_softc *, struct ohci_soft_itd *);
void ohci_hash_rem_itd(struct ohci_softc *, struct ohci_soft_itd *);
@@ -405,70 +406,44 @@ struct ohci_soft_ed *
ohci_alloc_sed(struct ohci_softc *sc)
{
struct ohci_soft_ed *sed;
- usbd_status err;
- int i, offs;
struct usb_dma dma;
- if (sc->sc_freeeds == NULL) {
- DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n"));
- err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK,
- OHCI_ED_ALIGN, &dma);
- if (err)
- return (0);
- for(i = 0; i < OHCI_SED_CHUNK; i++) {
- offs = i * OHCI_SED_SIZE;
- sed = KERNADDR(&dma, offs);
- sed->physaddr = DMAADDR(&dma, offs);
- sed->next = sc->sc_freeeds;
- sc->sc_freeeds = sed;
- }
- }
- sed = sc->sc_freeeds;
- sc->sc_freeeds = sed->next;
- memset(&sed->ed, 0, sizeof(struct ohci_ed));
+ if (usb_allocmem(&sc->sc_bus, sizeof(*sed), OHCI_ED_ALIGN, &dma))
+ return (NULL);
+
+ sed = KERNADDR(&dma, 0);
+ sed->physaddr = DMAADDR(&dma, 0);
+ sed->dma = dma;
sed->next = NULL;
+ memset(&sed->ed, 0, sizeof(struct ohci_ed));
+
return (sed);
}
void
ohci_free_sed(struct ohci_softc *sc, struct ohci_soft_ed *sed)
{
- sed->next = sc->sc_freeeds;
- sc->sc_freeeds = sed;
+ usb_freemem(&sc->sc_bus, &sed->dma);
}
struct ohci_soft_td *
ohci_alloc_std(struct ohci_softc *sc)
{
struct ohci_soft_td *std;
- usbd_status err;
- int i, offs;
struct usb_dma dma;
int s;
- if (sc->sc_freetds == NULL) {
- DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
- err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK,
- OHCI_TD_ALIGN, &dma);
- if (err)
- return (NULL);
- s = splusb();
- for(i = 0; i < OHCI_STD_CHUNK; i++) {
- offs = i * OHCI_STD_SIZE;
- std = KERNADDR(&dma, offs);
- std->physaddr = DMAADDR(&dma, offs);
- std->nexttd = sc->sc_freetds;
- sc->sc_freetds = std;
- }
- splx(s);
- }
+ if (usb_allocmem(&sc->sc_bus, sizeof(*std), OHCI_TD_ALIGN, &dma))
+ return (NULL);
- s = splusb();
- std = sc->sc_freetds;
- sc->sc_freetds = std->nexttd;
- memset(&std->td, 0, sizeof(struct ohci_td));
+ std = KERNADDR(&dma, 0);
+ std->physaddr = DMAADDR(&dma, 0);
+ std->dma = dma;
std->nexttd = NULL;
std->xfer = NULL;
+ memset(&std->td, 0, sizeof(struct ohci_td));
+
+ s = splusb();
ohci_hash_add_td(sc, std);
splx(s);
@@ -481,10 +456,10 @@ ohci_free_std(struct ohci_softc *sc, str
int s;
s = splusb();
- LIST_REMOVE(std, hnext);
- std->nexttd = sc->sc_freetds;
- sc->sc_freetds = std;
+ ohci_hash_rem_td(sc, std);
splx(s);
+
+ usb_freemem(&sc->sc_bus, &std->dma);
}
usbd_status
@@ -1758,6 +1733,14 @@ ohci_hash_add_td(struct ohci_softc *sc,
SPLUSBCHECK;
LIST_INSERT_HEAD(&sc->sc_hash_tds[h], std, hnext);
+}
+
+void
+ohci_hash_rem_td(struct ohci_softc *sc, struct ohci_soft_td *std)
+{
+ SPLUSBCHECK;
+
+ LIST_REMOVE(std, hnext);
}
struct ohci_soft_td *
Index: ohcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ohcivar.h,v
retrieving revision 1.36
diff -u -p -r1.36 ohcivar.h
--- ohcivar.h 29 Apr 2014 21:51:18 -0000 1.36
+++ ohcivar.h 4 May 2014 14:44:09 -0000
@@ -36,16 +36,15 @@ struct ohci_soft_ed {
struct ohci_ed ed;
struct ohci_soft_ed *next;
ohci_physaddr_t physaddr;
+ struct usb_dma dma;
};
-#define OHCI_SED_SIZE ((sizeof (struct ohci_soft_ed) + OHCI_ED_ALIGN - 1) /
OHCI_ED_ALIGN * OHCI_ED_ALIGN)
-#define OHCI_SED_CHUNK 128
-
struct ohci_soft_td {
struct ohci_td td;
struct ohci_soft_td *nexttd; /* mirrors nexttd in TD */
struct ohci_soft_td *dnext; /* next in done list */
ohci_physaddr_t physaddr;
+ struct usb_dma dma;
LIST_ENTRY(ohci_soft_td) hnext;
struct usbd_xfer *xfer;
u_int16_t len;
@@ -53,9 +52,6 @@ struct ohci_soft_td {
#define OHCI_CALL_DONE 0x0001
#define OHCI_ADD_LEN 0x0002
};
-#define OHCI_STD_SIZE ((sizeof (struct ohci_soft_td) + OHCI_TD_ALIGN - 1) /
OHCI_TD_ALIGN * OHCI_TD_ALIGN)
-#define OHCI_STD_CHUNK 128
-
struct ohci_soft_itd {
struct ohci_itd itd;
@@ -101,8 +97,6 @@ struct ohci_softc {
char sc_softwake;
- struct ohci_soft_ed *sc_freeeds;
- struct ohci_soft_td *sc_freetds;
struct ohci_soft_itd *sc_freeitds;
struct usbd_xfer *sc_intrxfer;
Index: uhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhci.c,v
retrieving revision 1.114
diff -u -p -r1.114 uhci.c
--- uhci.c 4 May 2014 14:42:36 -0000 1.114
+++ uhci.c 4 May 2014 14:44:11 -0000
@@ -1471,33 +1471,16 @@ struct uhci_soft_td *
uhci_alloc_std(struct uhci_softc *sc)
{
struct uhci_soft_td *std;
- usbd_status err;
- int i, offs;
struct usb_dma dma;
- int s;
- if (sc->sc_freetds == NULL) {
- DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
- err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK,
- UHCI_TD_ALIGN, &dma);
- if (err)
- return (0);
- s = splusb();
- for(i = 0; i < UHCI_STD_CHUNK; i++) {
- offs = i * UHCI_STD_SIZE;
- std = KERNADDR(&dma, offs);
- std->physaddr = DMAADDR(&dma, offs);
- std->link.std = sc->sc_freetds;
- sc->sc_freetds = std;
- }
- splx(s);
- }
+ if (usb_allocmem(&sc->sc_bus, sizeof(*std), UHCI_TD_ALIGN, &dma))
+ return (NULL);
- s = splusb();
- std = sc->sc_freetds;
- sc->sc_freetds = std->link.std;
+ std = KERNADDR(&dma, 0);
+ std->physaddr = DMAADDR(&dma, 0);
+ std->dma = dma;
+ std->link.std = NULL;
memset(&std->td, 0, sizeof(struct uhci_td));
- splx(s);
return (std);
}
@@ -1505,8 +1488,6 @@ uhci_alloc_std(struct uhci_softc *sc)
void
uhci_free_std(struct uhci_softc *sc, struct uhci_soft_td *std)
{
- int s;
-
#ifdef DIAGNOSTIC
#define TD_IS_FREE 0x12345678
if (letoh32(std->td.td_token) == TD_IS_FREE) {
@@ -1516,45 +1497,31 @@ uhci_free_std(struct uhci_softc *sc, str
std->td.td_token = htole32(TD_IS_FREE);
#endif
- s = splusb();
- std->link.std = sc->sc_freetds;
- sc->sc_freetds = std;
- splx(s);
+ usb_freemem(&sc->sc_bus, &std->dma);
}
struct uhci_soft_qh *
uhci_alloc_sqh(struct uhci_softc *sc)
{
struct uhci_soft_qh *sqh;
- usbd_status err;
- int i, offs;
struct usb_dma dma;
- if (sc->sc_freeqhs == NULL) {
- DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
- err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK,
- UHCI_QH_ALIGN, &dma);
- if (err)
- return (0);
- for(i = 0; i < UHCI_SQH_CHUNK; i++) {
- offs = i * UHCI_SQH_SIZE;
- sqh = KERNADDR(&dma, offs);
- sqh->physaddr = DMAADDR(&dma, offs);
- sqh->hlink = sc->sc_freeqhs;
- sc->sc_freeqhs = sqh;
- }
- }
- sqh = sc->sc_freeqhs;
- sc->sc_freeqhs = sqh->hlink;
+ if (usb_allocmem(&sc->sc_bus, sizeof(*sqh), UHCI_QH_ALIGN, &dma))
+ return (NULL);
+
+ sqh = KERNADDR(&dma, 0);
+ sqh->physaddr = DMAADDR(&dma, 0);
+ sqh->dma = dma;
+ sqh->hlink = NULL;
memset(&sqh->qh, 0, sizeof(struct uhci_qh));
+
return (sqh);
}
void
uhci_free_sqh(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
{
- sqh->hlink = sc->sc_freeqhs;
- sc->sc_freeqhs = sqh;
+ usb_freemem(&sc->sc_bus, &sqh->dma);
}
void
Index: uhcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhcivar.h,v
retrieving revision 1.31
diff -u -p -r1.31 uhcivar.h
--- uhcivar.h 29 Apr 2014 21:51:18 -0000 1.31
+++ uhcivar.h 4 May 2014 14:44:11 -0000
@@ -81,15 +81,8 @@ struct uhci_soft_td {
struct uhci_td td; /* The real TD, must be first */
uhci_soft_td_qh_t link; /* soft version of the td_link field */
uhci_physaddr_t physaddr; /* TD's physical address. */
+ struct usb_dma dma;
};
-/*
- * Make the size such that it is a multiple of UHCI_TD_ALIGN. This way
- * we can pack a number of soft TD together and have the real TD well
- * aligned.
- * NOTE: Minimum size is 32 bytes.
- */
-#define UHCI_STD_SIZE ((sizeof (struct uhci_soft_td) + UHCI_TD_ALIGN - 1) /
UHCI_TD_ALIGN * UHCI_TD_ALIGN)
-#define UHCI_STD_CHUNK 128 /*(PAGE_SIZE / UHCI_TD_SIZE)*/
/*
* Extra information that we need for a QH.
@@ -99,11 +92,9 @@ struct uhci_soft_qh {
struct uhci_soft_qh *hlink; /* soft version of qh_hlink */
struct uhci_soft_td *elink; /* soft version of qh_elink */
uhci_physaddr_t physaddr; /* QH's physical address. */
+ struct usb_dma dma;
int pos; /* Timeslot position */
};
-/* See comment about UHCI_STD_SIZE. */
-#define UHCI_SQH_SIZE ((sizeof (struct uhci_soft_qh) + UHCI_QH_ALIGN - 1) /
UHCI_QH_ALIGN * UHCI_QH_ALIGN)
-#define UHCI_SQH_CHUNK 128 /*(PAGE_SIZE / UHCI_QH_SIZE)*/
/*
* Information about an entry in the virtual frame list.
@@ -134,9 +125,6 @@ struct uhci_softc {
struct uhci_soft_qh *sc_bulk_end; /* last bulk transfer */
struct uhci_soft_qh *sc_last_qh; /* dummy QH at the end */
u_int32_t sc_loops; /* number of QHs that wants looping */
-
- struct uhci_soft_td *sc_freetds; /* TD free list */
- struct uhci_soft_qh *sc_freeqhs; /* QH free list */
u_int8_t sc_conf; /* device configuration */