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.
This commit is contained in:
parent
49503b44fd
commit
502c509ce0
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
@ -63,6 +64,7 @@
|
||||
#include <net/ethernet.h>
|
||||
#include <net/netisr.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usb_ethersubr.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user