From 502c509ce0d7260d2f01ede9bb564623c4f67ef7 Mon Sep 17 00:00:00 2001 From: Bill Paul Date: Wed, 12 Jan 2000 17:46:40 +0000 Subject: Apply the same netisr mechanism to transmissions as well. In order to drive the transmitter, we have to check the interface's send queue in the TX end of frame handler (i.e. the usb bulk out callback) and push out new transmissions if the queue has packets in it and the transmitter is ready. But the txeof handler is also called from a USB callback running at splusb() too. Grrr. --- sys/dev/usb/if_aue.c | 3 +-- sys/dev/usb/if_kue.c | 5 ++-- sys/dev/usb/usb_ethersubr.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- sys/dev/usb/usb_ethersubr.h | 1 + 4 files changed, 58 insertions(+), 7 deletions(-) (limited to 'sys/dev/usb') diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c index 66ef16ba15969..c6d1d556efc5c 100644 --- a/sys/dev/usb/if_aue.c +++ b/sys/dev/usb/if_aue.c @@ -1024,8 +1024,7 @@ static void aue_txeof(xfer, priv, status) else ifp->if_opackets++; - if (ifp->if_snd.ifq_head != NULL) - aue_start(ifp); + usb_tx_done(ifp); splx(s); diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c index 231437497d5ea..b1888e4c83562 100644 --- a/sys/dev/usb/if_kue.c +++ b/sys/dev/usb/if_kue.c @@ -668,7 +668,7 @@ static void kue_rxeof(xfer, priv, status) usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); m = c->kue_mbuf; - if (total_len == 1) + if (total_len <= 1) goto done; len = *mtod(m, u_int16_t *); @@ -763,8 +763,7 @@ static void kue_txeof(xfer, priv, status) else ifp->if_opackets++; - if (ifp->if_snd.ifq_head != NULL) - kue_start(ifp); + usb_tx_done(ifp); splx(s); diff --git a/sys/dev/usb/usb_ethersubr.c b/sys/dev/usb/usb_ethersubr.c index ded747e61edb8..ffe8a7dbbe6c2 100644 --- a/sys/dev/usb/usb_ethersubr.c +++ b/sys/dev/usb/usb_ethersubr.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,7 @@ #include #include +#include #include #ifndef lint @@ -71,6 +73,12 @@ static const char rcsid[] = #endif static struct ifqueue usbq; +struct usb_ifent { + struct ifnet *ifp; + LIST_ENTRY(usb_ifent) list; +}; +static LIST_HEAD(, usb_ifent) usb_iflisthead; +static int usb_inited = 0; static void usbintr __P((void)); @@ -78,17 +86,33 @@ static void usbintr() { struct ether_header *eh; struct mbuf *m; + struct ifnet *ifp; + struct usb_ifent *e; int s; s = splimp(); + /* Check the RX queue */ while(1) { IF_DEQUEUE(&usbq, m); if (m == NULL) break; eh = mtod(m, struct ether_header *); m_adj(m, sizeof(struct ether_header)); - ether_input(m->m_pkthdr.rcvif, eh, m); + ifp = m->m_pkthdr.rcvif; + ether_input(ifp, eh, m); + if (ifp->if_snd.ifq_head != NULL) + (*ifp->if_start)(ifp); + } + + /* Check the TX queue */ + while (usb_iflisthead.lh_first != NULL) { + e = usb_iflisthead.lh_first; + ifp = e->ifp; + if (ifp->if_snd.ifq_head != NULL) + (*ifp->if_start)(ifp); + LIST_REMOVE(e, list); + free(e, M_USBDEV); } splx(s); @@ -98,7 +122,12 @@ static void usbintr() void usb_register_netisr() { - register_netisr(NETISR_USB, usbintr); + if (usb_inited == 0) { + register_netisr(NETISR_USB, usbintr); + LIST_INIT(&usb_iflisthead); + usb_inited++; + } + return; } @@ -116,3 +145,26 @@ void usb_ether_input(m) splx(s); return; } + +void usb_tx_done(ifp) + struct ifnet *ifp; +{ + struct usb_ifent *e; + + /* See if this if is already scheduled. */ + for (e = usb_iflisthead.lh_first; e != NULL; e = e->list.le_next) { + if (ifp == e->ifp) + return; + } + + e = malloc(sizeof(struct usb_ifent), M_USB, M_NOWAIT); + if (e == NULL) + return; + + e->ifp = ifp; + + LIST_INSERT_HEAD(&usb_iflisthead, e, list); + schednetisr(NETISR_USB); + + return; +} diff --git a/sys/dev/usb/usb_ethersubr.h b/sys/dev/usb/usb_ethersubr.h index f137c3e0f3004..1fce46cc3830a 100644 --- a/sys/dev/usb/usb_ethersubr.h +++ b/sys/dev/usb/usb_ethersubr.h @@ -41,5 +41,6 @@ void usb_register_netisr __P((void)); void usb_ether_input __P((struct mbuf *)); +void usb_tx_done __P((struct ifnet *)); #endif -- cgit v1.3