2005-01-06 01:43:34 +00:00
|
|
|
/*-
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
* Copyright (c) 1997, 1998, 1999, 2000
|
|
|
|
* Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
|
|
|
|
*
|
|
|
|
* 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 Bill Paul.
|
|
|
|
* 4. Neither the name of the author nor the names of any co-contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2003-08-24 17:55:58 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
/*
|
|
|
|
* Callbacks in the USB code operate at splusb() (actually splbio()
|
|
|
|
* in FreeBSD). However adding packets to the input queues has to be
|
|
|
|
* done at splimp(). It is conceivable that this arrangement could
|
|
|
|
* trigger a condition where the splimp() is ignored and the input
|
|
|
|
* queues could get trampled in spite of our best effors to prevent
|
|
|
|
* it. To work around this, we implement a special input queue for
|
|
|
|
* USB ethernet adapter drivers. Rather than passing the frames directly
|
|
|
|
* to ether_input(), we pass them here, then schedule a soft interrupt
|
|
|
|
* to hand them to ether_input() later, outside of the USB interrupt
|
|
|
|
* context.
|
|
|
|
*
|
|
|
|
* It's questional as to whether this code should be expanded to
|
|
|
|
* handle other kinds of devices, or handle USB transfer callbacks
|
|
|
|
* in general. Right now, I need USB network interfaces to work
|
|
|
|
* properly.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/mbuf.h>
|
2000-01-12 17:46:40 +00:00
|
|
|
#include <sys/malloc.h>
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/if_arp.h>
|
|
|
|
#include <net/ethernet.h>
|
|
|
|
#include <net/netisr.h>
|
2000-01-13 20:13:58 +00:00
|
|
|
#include <net/bpf.h>
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
|
2000-01-12 17:46:40 +00:00
|
|
|
#include <dev/usb/usb.h>
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
#include <dev/usb/usb_ethersubr.h>
|
|
|
|
|
2000-04-03 20:58:30 +00:00
|
|
|
Static struct ifqueue usbq_rx;
|
|
|
|
Static struct ifqueue usbq_tx;
|
2000-10-24 22:38:54 +00:00
|
|
|
Static int mtx_inited = 0;
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
|
2002-03-20 02:08:01 +00:00
|
|
|
Static void usbintr (void);
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
|
2003-03-04 23:19:55 +00:00
|
|
|
Static void usbintr(void)
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
{
|
|
|
|
struct mbuf *m;
|
2000-01-13 20:13:58 +00:00
|
|
|
struct usb_qdat *q;
|
2000-01-12 17:46:40 +00:00
|
|
|
struct ifnet *ifp;
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
|
2000-01-12 17:46:40 +00:00
|
|
|
/* Check the RX queue */
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
while(1) {
|
2000-01-14 01:36:16 +00:00
|
|
|
IF_DEQUEUE(&usbq_rx, m);
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
if (m == NULL)
|
|
|
|
break;
|
2000-01-13 20:13:58 +00:00
|
|
|
q = (struct usb_qdat *)m->m_pkthdr.rcvif;
|
|
|
|
ifp = q->ifp;
|
|
|
|
m->m_pkthdr.rcvif = ifp;
|
2002-11-14 23:54:55 +00:00
|
|
|
(*ifp->if_input)(ifp, m);
|
2000-01-13 20:13:58 +00:00
|
|
|
|
|
|
|
/* Re-arm the receiver */
|
|
|
|
(*q->if_rxstart)(ifp);
|
2000-01-12 17:46:40 +00:00
|
|
|
if (ifp->if_snd.ifq_head != NULL)
|
|
|
|
(*ifp->if_start)(ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the TX queue */
|
2000-01-14 01:36:16 +00:00
|
|
|
while(1) {
|
|
|
|
IF_DEQUEUE(&usbq_tx, m);
|
|
|
|
if (m == NULL)
|
|
|
|
break;
|
|
|
|
ifp = m->m_pkthdr.rcvif;
|
|
|
|
m_freem(m);
|
2000-01-12 17:46:40 +00:00
|
|
|
if (ifp->if_snd.ifq_head != NULL)
|
|
|
|
(*ifp->if_start)(ifp);
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void usb_register_netisr()
|
|
|
|
{
|
2000-10-24 22:38:54 +00:00
|
|
|
if (mtx_inited)
|
|
|
|
return;
|
2003-11-08 22:28:40 +00:00
|
|
|
netisr_register(NETISR_USB, (netisr_t *)usbintr, NULL, 0);
|
2002-04-04 21:03:38 +00:00
|
|
|
mtx_init(&usbq_tx.ifq_mtx, "usbq_tx_mtx", NULL, MTX_DEF);
|
|
|
|
mtx_init(&usbq_rx.ifq_mtx, "usbq_rx_mtx", NULL, MTX_DEF);
|
2000-10-24 22:38:54 +00:00
|
|
|
mtx_inited++;
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-03-04 23:19:55 +00:00
|
|
|
* Must be called at splusb() (actually splbio()). This should be
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
* the case when called from a transfer callback routine.
|
|
|
|
*/
|
|
|
|
void usb_ether_input(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
2000-01-14 01:36:16 +00:00
|
|
|
IF_ENQUEUE(&usbq_rx, m);
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
schednetisr(NETISR_USB);
|
2000-10-24 22:38:54 +00:00
|
|
|
|
Attempt to fix a problem with receiving packets on USB ethernet interfaces.
Packets are received inside USB bulk transfer callbacks, which run at
splusb() (actually splbio()). The packet input queues are meant to be
manipulated at splimp(). However the locking apparently breaks down under
certain circumstances and the input queues can get trampled.
There's a similar problem with if_ppp, which is driven by hardware/tty
interrupts from the serial driver, but which must also manipulate the
packet input queues at splimp(). The fix there is to use a netisr, and
that's the fix I used here. (I can hear you groaning back there. Hush up.)
The usb_ethersubr module maintains a single queue of its own. When a
packet is received in the USB callback routine, it's placed on this
queue with usb_ether_input(). This routine also schedules a soft net
interrupt with schednetisr(). The ISR routine then runs later, at
splnet, outside of the USB callback/interrupt context, and passes the
packet to ether_input(), hopefully in a safe manner.
The reason this is implemented as a separate module is that there are
a limited number of NETISRs that we can use, and snarfing one up for
each driver that needs it is wasteful (there will be three once I get
the CATC driver done). It also reduces code duplication to a certain
small extent. Unfortunately, it also needs to be linked in with the
usb.ko module in order for the USB ethernet drivers to share it.
Also removed some uneeded includes from if_aue.c and if_kue.c
Fix suggested by: peter
Not rejected as a hairbrained idea by: n_hibma
2000-01-10 23:12:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2000-01-12 17:46:40 +00:00
|
|
|
|
2000-01-14 01:36:16 +00:00
|
|
|
void usb_tx_done(m)
|
|
|
|
struct mbuf *m;
|
2000-01-12 17:46:40 +00:00
|
|
|
{
|
2000-01-14 01:36:16 +00:00
|
|
|
IF_ENQUEUE(&usbq_tx, m);
|
2000-01-12 17:46:40 +00:00
|
|
|
schednetisr(NETISR_USB);
|
2000-10-24 22:38:54 +00:00
|
|
|
|
2000-01-12 17:46:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-03-25 00:44:21 +00:00
|
|
|
|
|
|
|
struct mbuf *
|
2005-03-25 12:42:30 +00:00
|
|
|
usb_ether_newbuf(void)
|
2005-03-25 00:44:21 +00:00
|
|
|
{
|
|
|
|
struct mbuf *m_new;
|
|
|
|
|
|
|
|
m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
|
2005-03-25 12:42:30 +00:00
|
|
|
if (m_new == NULL)
|
2005-03-25 00:44:21 +00:00
|
|
|
return (NULL);
|
|
|
|
m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
|
|
|
|
|
|
|
|
m_adj(m_new, ETHER_ALIGN);
|
|
|
|
return (m_new);
|
|
|
|
}
|
2005-03-25 12:42:30 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
usb_ether_rx_list_init(void *sc, struct ue_cdata *cd,
|
|
|
|
usbd_device_handle ue_udev)
|
|
|
|
{
|
|
|
|
struct ue_chain *c;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UE_RX_LIST_CNT; i++) {
|
|
|
|
c = &cd->ue_rx_chain[i];
|
|
|
|
c->ue_sc = sc;
|
|
|
|
c->ue_idx = i;
|
|
|
|
c->ue_mbuf = usb_ether_newbuf();
|
|
|
|
if (c->ue_mbuf == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
if (c->ue_xfer == NULL) {
|
|
|
|
c->ue_xfer = usbd_alloc_xfer(ue_udev);
|
|
|
|
if (c->ue_xfer == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
c->ue_buf = usbd_alloc_buffer(c->ue_xfer, UE_BUFSZ);
|
|
|
|
if (c->ue_buf == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
usb_ether_tx_list_init(void *sc, struct ue_cdata *cd,
|
|
|
|
usbd_device_handle ue_udev)
|
|
|
|
{
|
|
|
|
struct ue_chain *c;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UE_TX_LIST_CNT; i++) {
|
|
|
|
c = &cd->ue_tx_chain[i];
|
|
|
|
c->ue_sc = sc;
|
|
|
|
c->ue_idx = i;
|
|
|
|
c->ue_mbuf = NULL;
|
|
|
|
if (c->ue_xfer == NULL) {
|
|
|
|
c->ue_xfer = usbd_alloc_xfer(ue_udev);
|
|
|
|
if (c->ue_xfer == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
c->ue_buf = usbd_alloc_buffer(c->ue_xfer, UE_BUFSZ);
|
|
|
|
if (c->ue_buf == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
usb_ether_rx_list_free(struct ue_cdata *cd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UE_RX_LIST_CNT; i++) {
|
|
|
|
if (cd->ue_rx_chain[i].ue_mbuf != NULL) {
|
|
|
|
m_freem(cd->ue_rx_chain[i].ue_mbuf);
|
|
|
|
cd->ue_rx_chain[i].ue_mbuf = NULL;
|
|
|
|
}
|
|
|
|
if (cd->ue_rx_chain[i].ue_xfer != NULL) {
|
|
|
|
usbd_free_xfer(cd->ue_rx_chain[i].ue_xfer);
|
|
|
|
cd->ue_rx_chain[i].ue_xfer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
usb_ether_tx_list_free(struct ue_cdata *cd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UE_RX_LIST_CNT; i++) {
|
|
|
|
if (cd->ue_tx_chain[i].ue_mbuf != NULL) {
|
|
|
|
m_freem(cd->ue_tx_chain[i].ue_mbuf);
|
|
|
|
cd->ue_tx_chain[i].ue_mbuf = NULL;
|
|
|
|
}
|
|
|
|
if (cd->ue_tx_chain[i].ue_xfer != NULL) {
|
|
|
|
usbd_free_xfer(cd->ue_tx_chain[i].ue_xfer);
|
|
|
|
cd->ue_tx_chain[i].ue_xfer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|