USBNET(9) | Kernel Developer's Manual | USBNET(9) |
usbnet
—
#include <dev/usb/usbnet.h>
usbnet_set_link
(struct
usbnet *un, bool
link);
void
usbnet_set_dying
(struct
usbnet *un, bool
dying);
struct ifnet *
usbnet_ifp
(struct
usbnet *un);
struct ethercom *
usbnet_ec
(struct
usbnet *un);
struct mii_data *
usbnet_mii
(struct
usbnet *un);
krndsource_t *
usbnet_rndsrc
(struct
usbnet *un);
void *
usbnet_softc
(struct
usbnet *un);
bool
usbnet_havelink
(struct
usbnet *un);
bool
usbnet_isdying
(struct
usbnet *un);
void
usbnet_lock
(struct
usbnet *un);
void
usbnet_unlock
(struct
usbnet *un);
kmutex_t *
usbnet_mutex
(struct
usbnet *un);
void
usbnet_isowned
(struct
usbnet *un);
void
usbnet_lock_rx
(struct
usbnet *un);
void
usbnet_unlock_rx
(struct
usbnet *un);
kmutex_t *
usbnet_mutex_rx
(struct
usbnet *un);
void
usbnet_isowned_rx
(struct
usbnet *un);
void
usbnet_lock_tx
(struct
usbnet *un);
void
usbnet_unlock_tx
(struct
usbnet *un);
kmutex_t *
usbnet_mutex_tx
(struct
usbnet *un);
void
usbnet_isowned_tx
(struct
usbnet *un);
int
usbnet_init_rx_tx
(struct
usbnet *un, unsigned
rxflags, unsigned
txflags);
void
usbnet_lock_mii
(struct
usbnet *un);
void
usbnet_lock_mii_un_locked
(struct
usbnet *un);
void
usbnet_unlock_mii
(struct
usbnet *un);
void
usbnet_unlock_mii_un_locked
(struct
usbnet *un);
kmutex_t *
usbnet_mutex_mii
(struct
usbnet *un);
void
usbnet_isowned_mii
(struct
usbnet *un);
int
usbnet_miibus_readreg
(device_t
dev, int phy,
int reg,
uint16_t *val);
int
usbnet_miibus_writereg
(device_t
dev, int phy,
int reg,
uint16_t val);
void
usbnet_miibus_statchg
(struct
ifnet *);
void
usbnet_enqueue
(struct
usbnet *un, uint8_t
*buf, size_t
buflen, int
csum_flags, uint32_t
csum_data, int
mbuf_flags);
void
usbnet_input
(struct
usbnet *un, uint8_t
*buf, size_t
buflen);
void
usbnet_attach
(struct
usbnet *un, const char
*detname);
void
usbnet_attach_ifp
(struct
usbnet *un, unsigned
if_flags, unsigned
if_extflags, const struct
usbnet_mii *unm);
int
usbnet_detach
(device_t
dev, int
flags);
int
usbnet_activate
(device_t
dev, devact_t
act);
void
usbnet_stop
(struct
usbnet *un, struct ifnet
*ifp, int
disable);
usbnet
framework provides methods usable for USB
Ethernet drivers. The framework has support for these features:
usbnet
provides many or all of the
traditional “softc” members inside struct
usbnet, which can be used directly as the device softc structure if no
additional storage is required. A structure exists for receive and transmit
chain management, struct usbnet_chain, that tracks the
metadata for each transfer descriptor available, minimum of one each for Rx
and Tx slot, and will be passed to the Rx and Tx callbacks.
There is a struct usbnet_ops structure that provides a number of optional and required callbacks that will be described below.
For autoconfiguration the device attach routine is expected to
ensure that this device's struct usbnet is the first
member of the device softc, if it can not be used directly as the device
softc, as well as set up the necessary structure members, find end-points,
find the Ethernet address if relevant, call
usbnet_attach
(), set up interface, Ethernet, and MII
capabilities, and finally call usbnet_attach_ifp
().
The device detach routine should free any resources allocated by attach and
then call usbnet_detach
(), possibly directly using
usbnet_detach
() as most consumers have no additional
resources not owned and released by the usbnet
framework itself. The device activate function should be set to
usbnet_activate
().
To manage all Rx and Tx chains the “uno_init”
callback of struct usbnet_ops should perform any
device specific initialization and then call
usbnet_init_rx_tx
() which will allocate chains, set
up and open pipes, and start the Rx transfers so that packets can arrived.
These allocations and pipes can be closed and destroyed by calling
usbnet_stop
(). Both of
usbnet_init_rx_tx
() and
usbnet_stop
() must be called with the
usbnet
lock held, see
usbnet_lock
() and
usbnet_unlock
(). See the
RECEIVE AND SEND section for
details on using the chains.
The interface init, ioctl, start, and stop, routines are handled
by the framework with callbacks for device-specific handling. For interface
init (i.e., when bringing the interface up), the “uno_init”
callback should perform any device specific initialization and then call
usbnet_init_rx_tx
() to finalize Rx and Tx queue
initialization. For interface ioctl, most of the handling is in the
framework and the optional “uno_ioctl” callback should be used
to program special settings like multicast filters or offload handling. If
ioctl handling requires capturing device-specific ioctls then the
“uno_override_ioctl” callback may be used instead to replace
the framework's ioctl handler completely (i.e., the replacement should call
any generic ioctl handlers such as ether_ioctl
() as
required.) For interface start, the “uno_tx_prepare” callback
must be used to convert an mbuf into a chain buffer ready for transmission.
For interface stop, there is an optional “uno_stop” callback
to turn off any chipset specific values if required.
For devices requiring MII handling there are callbacks for reading
and writing registers, and for status change events. The framework provides
an MII-specific lock per interface which will be held when calling these
functions, and these locks should be used by internal code that also
requires serialized access to registers with the
usbnet_lock_mii
(),
usbnet_unlock_mii
(),
usbnet_lock_mii_un_locked
(), and
usbnet_unlock_mii_un_locked
() functions. These
functions handle device detach events safely, and as such take and release a
reference on this device and use the usbnet lock for this. Sometimes the
usbnet lock is already held and instead the “un_locked”
versions should be used.
As receive must handle the case of multiple packets in one buffer,
the support is split between the driver and the framework. A
“uno_rx_loop” callback must be provided that loops over the
incoming packet data found in a chain, performs necessary checking and
passes the network frame up the stack via either
usbnet_enqueue
() or
usbnet_input
(). Typically Ethernet devices prefer
usbnet_enqueue
().
General accessor functions for struct usbnet:
usbnet_set_link
(un,
link)usbnet_set_dying
(un,
dying)usbnet_ifp
(un)usbnet_ec
(un)usbnet_mii
(un)usbnet_rndsrc
(un)usbnet_softc
(un)bool
(usbnet_havelink,
un)bool
(usbnet_isdying,
un)Lock handling functions for struct usbnet:
usbnet_lock
(un)usbnet_unlock
(un)usbnet_isowned
(un)usbnet_lock_rx
(un)usbnet_unlock_rx
(un)usbnet_isowned_rx
(un)usbnet_lock_tx
(un)usbnet_unlock_tx
(un)usbnet_isowned_tx
(un)usbnet_lock_mii
(un)usbnet_lock_mii_un_locked
(un)usbnet_unlock_mii
(un)usbnet_unlock_mii_un_locked
(un)usbnet_isowned_mii
(un)usbnet
. The four locks are the
“softc” lock, the “Tx” lock, the
“Rx” lock, and the “MII” lock. The MII lock is
special in that it blocks device detach using an internal reference count
and is frequently required when both the “softc” lock is
held or unheld, and two versions are provided that either hold the
“softc” lock while increasing or decreasing the reference
count, or assume (and in debug builds, assert) the lock is held for the
“un_locked” versions.MII access functions for struct usbnet:
usbnet_mii_readreg
(dev,
phy, reg,
valp)usbnet_mii_writereg
(dev,
phy, reg,
val)usbnet_mii_statchg
(ifp)Buffer enqueue handling for struct usbnet:
usbnet_enqueue
(un,
buf, buflen,
csum_flags, csum_data,
mbuf_flags)usbnet_input
(un,
buf, buflen)Autoconfiguration handling for struct usbnet. See the AUTOCONFIGURATION section for more details about these functions.
usbnet_attach
(un,
detachname)usbnet_attach_ifp
(un,
if_flags, if_extflags,
unm)NULL
then an MII
interface will be created using the values provided in the
struct usbnet_mii structure, which has these members
passed to mii_attach
():
A default unm can be set using the
USBNET_MII_DECL_DEFAULT
() macro. The
if_flags and if_extflags
will be or-ed into the interface flags and extflags.
usbnet_detach
(dev,
flags)usbnet_activate
(dev,
act)usbnet_stop
(un,
ifp, disable)usbd_device2interface_handle
() for more
details.(*uno_stop)
(struct ifnet
*ifp, int disable)(*uno_ioctl)
(struct ifnet
*ifp, u_long cmd, void
*data)(*uno_override_ioctl)
(struct
ifnet *ifp, u_long cmd, void
*data)(*uno_init)
(struct ifnet
*ifp)usbnet_rx_tx_init
().(*uno_read_reg)
(struct usbnet
*un, int phy, int reg,
uint16_t *val)(*uno_write_reg)
(struct usbnet
*un, int phy, int reg,
uint16_t val)(*uno_statchg)
(struct ifnet
*ifp)(*uno_tx_prepare)
(struct usbnet
*un, struct mbuf *m, struct
usbnet_chain *c)(*uno_rx_loop)
(struct usbnet
*un, struct usbnet_chain *c,
uint32_t total_len)(*uno_intr)
(struct usbnet
*un, usbd_status status)(*uno_tick)
(struct usbnet
*un)NULL
, points to a buffer passed to
usbd_open_pipe_intr
() in the device init
callback, along with the size and interval.USBNET_ENDPT_RX
,
USBNET_ENDPT_TX
, and
USBNET_ENDPT_INTR
. The Rx and Tx endpoints are
required.usbnet
.usbnet_attach_ifp
() if the device has
Ethernet.usbnet
framework will
not touch this value.usbd_setup_xfer
() for receiving
packets.usbd_setup_xfer
() for sending
packets.The device detach and activate callbacks can typically be set to
usbnet_detach
() and
usbnet_activate
() unless device-specific handling is
required, in which case, they can be called before or after such
handling.
The capabilities described in both struct
ifp and struct ethercom must be set before
calling usbnet_attach_ifp
().
un_ed
,
un_rx_xfer_flags
, and
un_tx_xfer_flags
members, and the
uno_stop
(), uno_init
(),
uno_tx_prepare
(), and
uno_rx_loop
() callbacks of
usbnet_ops.
Typically, the device attach routine will fill in members of the
usbnet structure, as listed in
AUTOCONFIGURATION. The
un_ed
() member should have the
USBNET_ENDPT_RX
and
USBNET_ENDPT_TX
array entries filled in, and
optionally the USBNET_ENDPT_INTR
entry filled in if
applicable.
The optional uno_stop
() callback performs
device-specific operations to shutdown the transmit or receive handling.
uno_stop
() will be called with the usbnet lock
held.
The uno_init
() callback both performs
device-specific enablement and then calls
usbnet_rx_tx_init
(), which sets up the receive,
transmit, and, optionally, the interrupt pipes, as well as starting the
receive pipes. All USB transfer setup is handled internally to the
framework, and the driver callbacks merely copy data in or out of a chain
entry using what is typically a device-specific method.
The uno_rx_loop
() callback converts the
provided usbnet_chain data and length into a series
(one or more) of packets that are enqueued with the higher layers using
either usbnet_enqueue
() (for most devices) or
usbnet_input
() for devices that use
if_input
() (this currently relies upon the
struct ifnet having the “_if_input”
member set as well, which is true for current consumers.) The Rx lock will
be held during this call, see usbnet_lock_rx
() and
usbnet_unlock_rx
().
The uno_tx_prepare
() callback must convert
the provided struct mbuf into the provided
struct usbnet_chain performing any device-specific
padding, checksum, header or other. Note that this callback must check that
it is not attempting to copy more than the chain buffer size, as set in the
usbnet “un_tx_bufsz” member. This
callback is only called once per packet. The Tx lock will be held during
this call, see usbnet_lock_tx
() and
usbnet_unlock_tx
().
The struct usbnet_chain structure which contains a “unc_buf” member which has the chain buffer allocated where data should be copied to or from for receive or transmit operations. It also contains pointers back to the owning struct usbnet, and the struct usbd_xfer associated with this transfer.
usbnet_lock_mii
() and
usbnet_unlock_mii
().
usbnet
using the
usbd_open_pipe_intr
() function (instead of the
usbd_open_pipe
() function.) The
usbnet
framework provides most of the interrupt
handling and the callback simply inspects the returned buffer as necessary. To
enable the this callback point the struct usbnet member
“un_intr” to a struct usbnet_intr
structure with these members set:
These values will be passed to
usbd_open_pipe_intr
().
usbnet
framework
is largely an effort in deleting code. The process involves making these
changes:
Many drivers can use the usbnet
structure as the device private storage passed to
CFATTACH_DECL_NEW
. Many internal functions to
the driver may look better if switched to operate on the device's
usbnet as, for example, the
usbd_device value is now available (and must be
set by the driver) in the usbnet, which may be
needed for any call to usbd_do_request
(). The
standard endpoint values must be stored in the
usbnet
“un_ed[]” array.
As usbnet
manages xfer chains all code
related to the opening, closing, aborting and transferring of data on
pipes is performed by the framework based upon the buffer size and more
provided in subnet, so all code related to them
should be deleted.
usbnet_attach_ifp
(). All calls to
ifmedia_init
(),
mii_attach
(),
ifmedia_add
(),
ifmedia_set
(),
if_attach
(),
ether_ifattach
(),
rnd_attach_source
(), and
usbd_add_drv_event
() should be eliminated. The
device “ioctl” routine can use the default handling with a
callback for additional device specific programming (multicast filters,
etc.), which can be empty, or, the override ioctl can be used for heavier
requirements. The device “stop” routine is replaced with a
simple call that turns off the device-specific transmitter and receiver if
necessary, as the framework handles pipes and transfers and buffers.usbnet
framework provides four locks for the
system: normal device/softc lock, receive and transmit locks, and the MII
lock. The normal locking order for these locks is ifnet lock -> usbnet
lock -> usbnet rxlock -> usbne txlock, or, ifnet lock -> usbnet
lock -> MII lock.usbnet_isowned_mii
()”), and do not
require any checking for running, or up, or dying devices unless they drop
and retake the MII lock. Local “link” variables need to be
replaced with accesses to usbnet_set_link
() and
usbnet_havelink
(). Other ifmedia callbacks that
were passed to ifmedia_init
() should be deleted
and any work moved into “uno_statchg”.usbnet
framework handles the majority of
handling of both network directions. The interface init routine should
keep all of the device specific setup but replace all pipe management with
a call to usbnet_init_rx_tx
(). The typical receive
handling will normally be replaced with a receive loop functions that can
accept one or more packets, “uno_rx_loop”, which can use
either usbnet_enqueue
() or
usbnet_input
() to pass the packets upto higher
layers. The typical interface “if_start” function and any
additional functions used will normal be replaced with a relatively simple
“uno_tx_prepare” function that simply converts an
mbuf into a usbnet_chain
useful for this device that will be passed onto
usbd_transfer
(). The framework's handling of the
Tx interrupt is all internal.usbd_open_pipe_intr
() method), most of the
interrupt handler should be deleted, leaving only code that inspects the
result of the interrupt transfer.usbent_set_link
() during any status change
event.
Many locking issues are hidden without
LOCKDEBUG
, including hard-hangs. It's highly
recommended to develop with LOCKDEBUG
.
The usbnet “un_ed” array is unsigned and should use “0” as the no-endpoint value.
usbnet
interface first appeared in
NetBSD 9.0. Portions of the original design are based
upon ideas from Nick Hudson
<skrll@NetBSD.org>.
August 22, 2019 | NetBSD 9.2 |