[CFR 2/n] removes uther dependency of aue(4)
Weongyo Jeong
weongyo.jeong at gmail.com
Sun Oct 31 21:47:11 UTC 2010
Hello,
The following patch is to remove uether(4) dependency of aue(4) and
change logs would be as follows:
- removes uether module dependency of aue(4) that finally uether
module would be gone. The reasons why I'm trying to remove uether
module are that
I discussed with USB ethernet maintainers about whether it's
useful or not. yongari@ answered that it's not helpful, not
straight forward to understand and make code complex.
- adds newly two uether APIs, uether_alloc_unr and uether_free_unr for
backward compatibility because current interface names for each
ethernet devices are linux-style `ue[0-9]+'. The naming rule would
be kept at STABLE_8 but not sure at STABLE_9.
If no objections I'd like to see this patch at HEAD.
regards,
Weongyo Jeong
Index: usb_ethernet.c
===================================================================
--- usb_ethernet.c (revision 214568)
+++ usb_ethernet.c (working copy)
@@ -597,5 +597,19 @@ uether_rxflush(struct usb_ether *ue)
}
}
+int
+uether_alloc_unr(void)
+{
+
+ return (alloc_unr(ueunit));
+}
+
+void
+uether_free_unr(int unit)
+{
+
+ free_unr(ueunit, unit);
+}
+
DECLARE_MODULE(uether, uether_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_VERSION(uether, 1);
Index: if_aue.c
===================================================================
--- if_aue.c (revision 214568)
+++ if_aue.c (working copy)
@@ -81,6 +81,8 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/unistd.h>
@@ -88,6 +90,19 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/priv.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/bpf.h>
+#include <net/ethernet.h>
+
+#include "miibus_if.h"
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
@@ -96,6 +111,7 @@ __FBSDID("$FreeBSD$");
#define USB_DEBUG_VAR aue_debug
#include <dev/usb/usb_debug.h>
#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_sleepout.h>
#include <dev/usb/net/usb_ethernet.h>
#include <dev/usb/net/if_auereg.h>
@@ -197,14 +213,6 @@ static usb_callback_t aue_intr_callback;
static usb_callback_t aue_bulk_read_callback;
static usb_callback_t aue_bulk_write_callback;
-static uether_fn_t aue_attach_post;
-static uether_fn_t aue_init;
-static uether_fn_t aue_stop;
-static uether_fn_t aue_start;
-static uether_fn_t aue_tick;
-static uether_fn_t aue_setmulti;
-static uether_fn_t aue_setpromisc;
-
static uint8_t aue_csr_read_1(struct aue_softc *, uint16_t);
static uint16_t aue_csr_read_2(struct aue_softc *, uint16_t);
static void aue_csr_write_1(struct aue_softc *, uint16_t, uint8_t);
@@ -217,6 +225,20 @@ static void aue_reset_pegasus_II(struct aue_softc
static int aue_ifmedia_upd(struct ifnet *);
static void aue_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int aue_ioctl(struct ifnet *, u_long, caddr_t);
+static void aue_start(struct ifnet *);
+static void aue_start_locked(struct ifnet *);
+static void aue_init(void *);
+static void aue_stop_locked(struct aue_softc *);
+static void aue_setmulti(void *, int);
+static void aue_setmulti_locked(struct aue_softc *);
+static void aue_rxflush(struct aue_softc *);
+static int aue_rxbuf(struct aue_softc *, struct usb_page_cache *,
+ unsigned int, unsigned int);
+static void aue_setpromisc(void *, int);
+static void aue_setpromisc_locked(struct aue_softc *);
+static void aue_init_locked(struct aue_softc *);
+static void aue_watchdog(void *);
static const struct usb_config aue_config[AUE_N_TRANSFER] = {
@@ -283,24 +305,19 @@ MODULE_DEPEND(aue, ether, 1, 1, 1);
MODULE_DEPEND(aue, miibus, 1, 1, 1);
MODULE_VERSION(aue, 1);
-static const struct usb_ether_methods aue_ue_methods = {
- .ue_attach_post = aue_attach_post,
- .ue_start = aue_start,
- .ue_init = aue_init,
- .ue_stop = aue_stop,
- .ue_tick = aue_tick,
- .ue_setmulti = aue_setmulti,
- .ue_setpromisc = aue_setpromisc,
- .ue_mii_upd = aue_ifmedia_upd,
- .ue_mii_sts = aue_ifmedia_sts,
-};
-
#define AUE_SETBIT(sc, reg, x) \
aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x))
#define AUE_CLRBIT(sc, reg, x) \
aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x))
+static void
+aue_pause(struct aue_softc *sc, unsigned int _ticks)
+{
+
+ usb_pause_mtx(&sc->sc_mtx, _ticks);
+}
+
static uint8_t
aue_csr_read_1(struct aue_softc *sc, uint16_t reg)
{
@@ -314,7 +331,8 @@ aue_csr_read_1(struct aue_softc *sc, uint16_t reg)
USETW(req.wIndex, reg);
USETW(req.wLength, 1);
- err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
+ err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+ NULL, 1000);
if (err)
return (0);
return (val);
@@ -333,7 +351,8 @@ aue_csr_read_2(struct aue_softc *sc, uint16_t reg)
USETW(req.wIndex, reg);
USETW(req.wLength, 2);
- err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
+ err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+ NULL, 1000);
if (err)
return (0);
return (le16toh(val));
@@ -351,9 +370,9 @@ aue_csr_write_1(struct aue_softc *sc, uint16_t reg
USETW(req.wIndex, reg);
USETW(req.wLength, 1);
- if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) {
- /* error ignored */
- }
+ /* XXX error ignored */
+ (void)usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+ NULL, 1000);
}
static void
@@ -369,9 +388,9 @@ aue_csr_write_2(struct aue_softc *sc, uint16_t reg
val = htole16(val);
- if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) {
- /* error ignored */
- }
+ /* XXX error ignored */
+ (void)usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+ NULL, 1000);
}
/*
@@ -389,12 +408,11 @@ aue_eeprom_getword(struct aue_softc *sc, int addr,
for (i = 0; i != AUE_TIMEOUT; i++) {
if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE)
break;
- if (uether_pause(&sc->sc_ue, hz / 100))
- break;
+ aue_pause(sc, hz / 100);
}
if (i == AUE_TIMEOUT)
- device_printf(sc->sc_ue.ue_dev, "EEPROM read timed out\n");
+ device_printf(sc->sc_dev, "EEPROM read timed out\n");
word = aue_csr_read_2(sc, AUE_EE_DATA);
*dest = word;
@@ -446,12 +464,11 @@ aue_miibus_readreg(device_t dev, int phy, int reg)
for (i = 0; i != AUE_TIMEOUT; i++) {
if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
break;
- if (uether_pause(&sc->sc_ue, hz / 100))
- break;
+ aue_pause(sc, hz / 100);
}
if (i == AUE_TIMEOUT)
- device_printf(sc->sc_ue.ue_dev, "MII read timed out\n");
+ device_printf(sc->sc_dev, "MII read timed out\n");
val = aue_csr_read_2(sc, AUE_PHY_DATA);
@@ -482,12 +499,11 @@ aue_miibus_writereg(device_t dev, int phy, int reg
for (i = 0; i != AUE_TIMEOUT; i++) {
if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
break;
- if (uether_pause(&sc->sc_ue, hz / 100))
- break;
+ aue_pause(sc, hz / 100);
}
if (i == AUE_TIMEOUT)
- device_printf(sc->sc_ue.ue_dev, "MII write timed out\n");
+ device_printf(sc->sc_dev, "MII write timed out\n");
if (!locked)
AUE_UNLOCK(sc);
@@ -533,12 +549,21 @@ aue_miibus_statchg(device_t dev)
AUE_UNLOCK(sc);
}
+static void
+aue_setmulti(void *arg, int npending)
+{
+ struct aue_softc *sc = arg;
+
+ AUE_LOCK(sc);
+ aue_setmulti_locked(sc);
+ AUE_UNLOCK(sc);
+}
+
#define AUE_BITS 6
static void
-aue_setmulti(struct usb_ether *ue)
+aue_setmulti_locked(struct aue_softc *sc)
{
- struct aue_softc *sc = uether_getsc(ue);
- struct ifnet *ifp = uether_getifp(ue);
+ struct ifnet *ifp = sc->sc_ifp;
struct ifmultiaddr *ifma;
uint32_t h = 0;
uint32_t i;
@@ -572,6 +597,7 @@ static void
static void
aue_reset_pegasus_II(struct aue_softc *sc)
{
+
/* Magic constants taken from Linux driver. */
aue_csr_write_1(sc, AUE_REG_1D, 0);
aue_csr_write_1(sc, AUE_REG_7B, 2);
@@ -593,12 +619,11 @@ aue_reset(struct aue_softc *sc)
for (i = 0; i != AUE_TIMEOUT; i++) {
if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
break;
- if (uether_pause(&sc->sc_ue, hz / 100))
- break;
+ aue_pause(sc, hz / 100);
}
if (i == AUE_TIMEOUT)
- device_printf(sc->sc_ue.ue_dev, "reset failed\n");
+ device_printf(sc->sc_dev, "reset failed\n");
/*
* The PHY(s) attached to the Pegasus chip may be held
@@ -625,21 +650,9 @@ aue_reset(struct aue_softc *sc)
aue_reset_pegasus_II(sc);
/* Wait a little while for the chip to get its brains in order: */
- uether_pause(&sc->sc_ue, hz / 100);
+ aue_pause(sc, hz / 100);
}
-static void
-aue_attach_post(struct usb_ether *ue)
-{
- struct aue_softc *sc = uether_getsc(ue);
-
- /* reset the adapter */
- aue_reset(sc);
-
- /* get station address from the EEPROM */
- aue_read_eeprom(sc, ue->ue_eaddr, 0, 3);
-}
-
/*
* Probe for a Pegasus chip.
*/
@@ -676,7 +689,7 @@ aue_attach(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
struct aue_softc *sc = device_get_softc(dev);
- struct usb_ether *ue = &sc->sc_ue;
+ struct ifnet *ifp;
uint8_t iface_index;
int error;
@@ -688,7 +701,16 @@ aue_attach(device_t dev)
}
device_set_usb_desc(dev);
+ sc->sc_dev = dev;
+ sc->sc_udev = uaa->device;
+ sc->sc_unit = uether_alloc_unr();
+
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+ sx_init(&sc->sc_sx, "aue sxlock");
+ sleepout_create(&sc->sc_sleepout, "aue sleepout");
+ sleepout_init_mtx(&sc->sc_sleepout, &sc->sc_watchdog, &sc->sc_mtx, 0);
+ TASK_INIT(&sc->sc_setmulti, 0, aue_setmulti, sc);
+ TASK_INIT(&sc->sc_setpromisc, 0, aue_setpromisc, sc);
iface_index = AUE_IFACE_IDX;
error = usbd_transfer_setup(uaa->device, &iface_index,
@@ -699,19 +721,42 @@ aue_attach(device_t dev)
goto detach;
}
- ue->ue_sc = sc;
- ue->ue_dev = dev;
- ue->ue_udev = uaa->device;
- ue->ue_mtx = &sc->sc_mtx;
- ue->ue_methods = &aue_ue_methods;
+ AUE_LOCK(sc);
+ /* reset the adapter */
+ aue_reset(sc);
+ /* get station address from the EEPROM */
+ aue_read_eeprom(sc, sc->sc_eaddr, 0, 3);
+ AUE_UNLOCK(sc);
- error = uether_ifattach(ue);
+ sc->sc_ifp = ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ device_printf(sc->sc_dev, "could not allocate ifnet\n");
+ goto detach;
+ }
+
+ ifp->if_softc = sc;
+ if_initname(ifp, "ue", sc->sc_unit);
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = aue_ioctl;
+ ifp->if_start = aue_start;
+ ifp->if_init = aue_init;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+ ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp,
+ aue_ifmedia_upd, aue_ifmedia_sts,
+ BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
if (error) {
- device_printf(dev, "could not attach interface\n");
+ device_printf(sc->sc_dev, "MII without any PHY\n");
goto detach;
}
- return (0); /* success */
+ if_printf(ifp, "<USB Ethernet> on %s\n",
+ device_get_nameunit(sc->sc_dev));
+ ether_ifattach(ifp, sc->sc_eaddr);
+ return (0);
detach:
aue_detach(dev);
return (ENXIO); /* failure */
@@ -721,11 +766,26 @@ static int
aue_detach(device_t dev)
{
struct aue_softc *sc = device_get_softc(dev);
- struct usb_ether *ue = &sc->sc_ue;
+ struct ifnet *ifp = sc->sc_ifp;
+ sleepout_drain(&sc->sc_watchdog);
+ SLEEPOUT_DRAINTASK(&sc->sc_sleepout, &sc->sc_setpromisc);
+ SLEEPOUT_DRAINTASK(&sc->sc_sleepout, &sc->sc_setmulti);
usbd_transfer_unsetup(sc->sc_xfer, AUE_N_TRANSFER);
- uether_ifdetach(ue);
+
+ if (sc->sc_miibus != NULL)
+ device_delete_child(sc->sc_dev, sc->sc_miibus);
+ if (ifp != NULL) {
+ AUE_LOCK(sc);
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ AUE_UNLOCK(sc);
+ ether_ifdetach(ifp);
+ if_free(ifp);
+ }
+ sleepout_free(&sc->sc_sleepout);
+ sx_destroy(&sc->sc_sx);
mtx_destroy(&sc->sc_mtx);
+ uether_free_unr(sc->sc_unit);
return (0);
}
@@ -734,7 +794,7 @@ static void
aue_intr_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct aue_softc *sc = usbd_xfer_softc(xfer);
- struct ifnet *ifp = uether_getifp(&sc->sc_ue);
+ struct ifnet *ifp = sc->sc_ifp;
struct aue_intrpkt pkt;
struct usb_page_cache *pc;
int actlen;
@@ -743,10 +803,8 @@ aue_intr_callback(struct usb_xfer *xfer, usb_error
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
-
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
actlen >= sizeof(pkt)) {
-
pc = usbd_xfer_get_frame(xfer, 0);
usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
@@ -762,7 +820,6 @@ tr_setup:
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
usbd_transfer_submit(xfer);
return;
-
default: /* Error */
if (error != USB_ERR_CANCELLED) {
/* try to clear stall first */
@@ -777,8 +834,7 @@ static void
aue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct aue_softc *sc = usbd_xfer_softc(xfer);
- struct usb_ether *ue = &sc->sc_ue;
- struct ifnet *ifp = uether_getifp(ue);
+ struct ifnet *ifp = sc->sc_ifp;
struct aue_rxpkt stat;
struct usb_page_cache *pc;
int actlen;
@@ -791,13 +847,11 @@ aue_bulk_read_callback(struct usb_xfer *xfer, usb_
DPRINTFN(11, "received %d bytes\n", actlen);
if (sc->sc_flags & AUE_FLAG_VER_2) {
-
if (actlen == 0) {
ifp->if_ierrors++;
goto tr_setup;
}
} else {
-
if (actlen <= sizeof(stat) + ETHER_CRC_LEN) {
ifp->if_ierrors++;
goto tr_setup;
@@ -817,16 +871,14 @@ aue_bulk_read_callback(struct usb_xfer *xfer, usb_
/* No errors; receive the packet. */
actlen -= (sizeof(stat) + ETHER_CRC_LEN);
}
- uether_rxbuf(ue, pc, 0, actlen);
-
+ aue_rxbuf(sc, pc, 0, actlen);
/* FALLTHROUGH */
case USB_ST_SETUP:
tr_setup:
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
usbd_transfer_submit(xfer);
- uether_rxflush(ue);
+ aue_rxflush(sc);
return;
-
default: /* Error */
DPRINTF("bulk read error, %s\n",
usbd_errstr(error));
@@ -844,7 +896,7 @@ static void
aue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct aue_softc *sc = usbd_xfer_softc(xfer);
- struct ifnet *ifp = uether_getifp(&sc->sc_ue);
+ struct ifnet *ifp = sc->sc_ifp;
struct usb_page_cache *pc;
struct mbuf *m;
uint8_t buf[2];
@@ -857,7 +909,6 @@ aue_bulk_write_callback(struct usb_xfer *xfer, usb
case USB_ST_TRANSFERRED:
DPRINTFN(11, "transfer of %d bytes complete\n", actlen);
ifp->if_opackets++;
-
/* FALLTHROUGH */
case USB_ST_SETUP:
tr_setup:
@@ -874,13 +925,10 @@ tr_setup:
if (m->m_pkthdr.len > MCLBYTES)
m->m_pkthdr.len = MCLBYTES;
if (sc->sc_flags & AUE_FLAG_VER_2) {
-
usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
-
} else {
-
usbd_xfer_set_frame_len(xfer, 0, (m->m_pkthdr.len + 2));
/*
@@ -908,7 +956,6 @@ tr_setup:
usbd_transfer_submit(xfer);
return;
-
default: /* Error */
DPRINTFN(11, "transfer error, %s\n",
usbd_errstr(error));
@@ -925,9 +972,8 @@ tr_setup:
}
static void
-aue_tick(struct usb_ether *ue)
+aue_tick(struct aue_softc *sc)
{
- struct aue_softc *sc = uether_getsc(ue);
struct mii_data *mii = GET_MII(sc);
AUE_LOCK_ASSERT(sc, MA_OWNED);
@@ -937,15 +983,27 @@ static void
&& mii->mii_media_status & IFM_ACTIVE &&
IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
sc->sc_flags |= AUE_FLAG_LINK;
- aue_start(ue);
+ aue_start_locked(sc->sc_ifp);
}
}
static void
-aue_start(struct usb_ether *ue)
+aue_start(struct ifnet *ifp)
{
- struct aue_softc *sc = uether_getsc(ue);
+ struct aue_softc *sc = ifp->if_softc;
+ AUE_LOCK(sc);
+ aue_start_locked(ifp);
+ AUE_UNLOCK(sc);
+}
+
+static void
+aue_start_locked(struct ifnet *ifp)
+{
+ struct aue_softc *sc = ifp->if_softc;
+
+ AUE_LOCK_ASSERT(sc, MA_OWNED);
+
/*
* start the USB transfers, if not already started:
*/
@@ -955,10 +1013,21 @@ static void
}
static void
-aue_init(struct usb_ether *ue)
+aue_init(void *arg)
{
- struct aue_softc *sc = uether_getsc(ue);
- struct ifnet *ifp = uether_getifp(ue);
+ struct aue_softc *sc = arg;
+
+ AUE_SXLOCK(sc);
+ AUE_LOCK(sc);
+ aue_init_locked(sc);
+ AUE_UNLOCK(sc);
+ AUE_SXUNLOCK(sc);
+}
+
+static void
+aue_init_locked(struct aue_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
int i;
AUE_LOCK_ASSERT(sc, MA_OWNED);
@@ -973,10 +1042,10 @@ static void
aue_csr_write_1(sc, AUE_PAR0 + i, IF_LLADDR(ifp)[i]);
/* update promiscuous setting */
- aue_setpromisc(ue);
+ aue_setpromisc_locked(sc);
/* Load the multicast filter. */
- aue_setmulti(ue);
+ aue_setmulti_locked(sc);
/* Enable RX and TX */
aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
@@ -986,15 +1055,25 @@ static void
usbd_xfer_set_stall(sc->sc_xfer[AUE_BULK_DT_WR]);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
- aue_start(ue);
+ sleepout_reset(&sc->sc_watchdog, hz, aue_watchdog, sc);
+ aue_start_locked(sc->sc_ifp);
}
static void
-aue_setpromisc(struct usb_ether *ue)
+aue_setpromisc(void *arg, int npending)
{
- struct aue_softc *sc = uether_getsc(ue);
- struct ifnet *ifp = uether_getifp(ue);
+ struct aue_softc *sc = arg;
+ AUE_LOCK(sc);
+ aue_setpromisc_locked(sc);
+ AUE_UNLOCK(sc);
+}
+
+static void
+aue_setpromisc_locked(struct aue_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
AUE_LOCK_ASSERT(sc, MA_OWNED);
/* if we want promiscuous mode, set the allframes bit: */
@@ -1013,8 +1092,7 @@ aue_ifmedia_upd(struct ifnet *ifp)
struct aue_softc *sc = ifp->if_softc;
struct mii_data *mii = GET_MII(sc);
- AUE_LOCK_ASSERT(sc, MA_OWNED);
-
+ AUE_LOCK(sc);
sc->sc_flags &= ~AUE_FLAG_LINK;
if (mii->mii_instance) {
struct mii_softc *miisc;
@@ -1023,6 +1101,7 @@ aue_ifmedia_upd(struct ifnet *ifp)
mii_phy_reset(miisc);
}
mii_mediachg(mii);
+ AUE_UNLOCK(sc);
return (0);
}
@@ -1047,11 +1126,21 @@ aue_ifmedia_sts(struct ifnet *ifp, struct ifmediar
* RX and TX lists.
*/
static void
-aue_stop(struct usb_ether *ue)
+aue_stop(struct aue_softc *sc)
{
- struct aue_softc *sc = uether_getsc(ue);
- struct ifnet *ifp = uether_getifp(ue);
+ AUE_SXLOCK(sc);
+ AUE_LOCK(sc);
+ aue_stop_locked(sc);
+ AUE_UNLOCK(sc);
+ AUE_SXUNLOCK(sc);
+}
+
+static void
+aue_stop_locked(struct aue_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
AUE_LOCK_ASSERT(sc, MA_OWNED);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
@@ -1068,3 +1157,125 @@ static void
aue_csr_write_1(sc, AUE_CTL1, 0);
aue_reset(sc);
}
+
+static int
+aue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct aue_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct mii_data *mii = GET_MII(sc);
+ int error = 0, drv_flags, flags;
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+ /* Avoids race and LOR between mutex and sx lock. */
+ AUE_LOCK(sc);
+ flags = ifp->if_flags;
+ drv_flags = ifp->if_drv_flags;
+ AUE_UNLOCK(sc);
+ /* device up and down is synchronous using sx(9) lock */
+ if (flags & IFF_UP) {
+ if (drv_flags & IFF_DRV_RUNNING)
+ SLEEPOUT_RUNTASK(&sc->sc_sleepout,
+ &sc->sc_setpromisc);
+ else
+ aue_init(sc);
+ } else
+ aue_stop(sc);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /* To avoid LOR by in_multi_mtx (netinet/in_mcast.c) */
+ if (ifp->if_flags & IFF_UP &&
+ ifp->if_drv_flags & IFF_DRV_RUNNING)
+ SLEEPOUT_RUNTASK(&sc->sc_sleepout, &sc->sc_setmulti);
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+ return (error);
+}
+
+static void
+aue_rxflush(struct aue_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+
+ AUE_LOCK_ASSERT(sc, MA_OWNED);
+
+ for (;;) {
+ _IF_DEQUEUE(&sc->sc_rxq, m);
+ if (m == NULL)
+ break;
+
+ /*
+ * The USB xfer has been resubmitted so its safe to unlock now.
+ */
+ AUE_UNLOCK(sc);
+ ifp->if_input(ifp, m);
+ AUE_LOCK(sc);
+ }
+}
+
+static struct mbuf *
+aue_newbuf(void)
+{
+ struct mbuf *m_new;
+
+ m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m_new == NULL)
+ return (NULL);
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+
+ m_adj(m_new, ETHER_ALIGN);
+ return (m_new);
+}
+
+static int
+aue_rxbuf(struct aue_softc *sc, struct usb_page_cache *pc,
+ unsigned int offset, unsigned int len)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+
+ AUE_LOCK_ASSERT(sc, MA_OWNED);
+
+ if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN)
+ return (1);
+
+ m = aue_newbuf();
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return (ENOMEM);
+ }
+
+ usbd_copy_out(pc, offset, mtod(m, uint8_t *), len);
+
+ /* finalize mbuf */
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+
+ /* enqueue for later when the lock can be released */
+ _IF_ENQUEUE(&sc->sc_rxq, m);
+ return (0);
+}
+
+static void
+aue_watchdog(void *arg)
+{
+ struct aue_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ return;
+
+ aue_tick(sc);
+ sleepout_reset(&sc->sc_watchdog, hz, aue_watchdog, sc);
+}
Index: if_auereg.h
===================================================================
--- if_auereg.h (revision 214568)
+++ if_auereg.h (working copy)
@@ -183,7 +183,7 @@ enum {
#define AUE_RXSTAT_DRIBBLE 0x10
#define AUE_RXSTAT_MASK 0x1E
-#define GET_MII(sc) uether_getmii(&(sc)->sc_ue)
+#define GET_MII(sc) (device_get_softc(sc->sc_miibus))
struct aue_intrpkt {
uint8_t aue_txstat0;
@@ -202,10 +202,16 @@ struct aue_rxpkt {
} __packed;
struct aue_softc {
- struct usb_ether sc_ue;
+ struct ifnet *sc_ifp;
+ device_t sc_dev;
+ device_t sc_miibus;
+ struct usb_device *sc_udev; /* used by uether_do_request() */
+ struct usb_xfer *sc_xfer[AUE_N_TRANSFER];
struct mtx sc_mtx;
- struct usb_xfer *sc_xfer[AUE_N_TRANSFER];
-
+ struct sx sc_sx;
+ struct ifqueue sc_rxq;
+ /* ethernet address from eeprom */
+ uint8_t sc_eaddr[ETHER_ADDR_LEN];
int sc_flags;
#define AUE_FLAG_LSYS 0x0001 /* use Linksys reset */
#define AUE_FLAG_PNA 0x0002 /* has Home PNA */
@@ -213,8 +219,16 @@ struct aue_softc {
#define AUE_FLAG_LINK 0x0008 /* wait for link to come up */
#define AUE_FLAG_VER_2 0x0200 /* chip is version 2 */
#define AUE_FLAG_DUAL_PHY 0x0400 /* chip has two transcivers */
+ int sc_unit;
+
+ struct sleepout sc_sleepout;
+ struct sleepout_task sc_watchdog;
+ struct task sc_setmulti;
+ struct task sc_setpromisc;
};
+#define AUE_SXLOCK(_sc) sx_xlock(&(_sc)->sc_sx)
+#define AUE_SXUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx)
#define AUE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define AUE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define AUE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)
Index: usb_ethernet.h
===================================================================
--- usb_ethernet.h (revision 214568)
+++ usb_ethernet.h (working copy)
@@ -119,4 +119,7 @@ int uether_rxbuf(struct usb_ether *,
unsigned int, unsigned int);
void uether_rxflush(struct usb_ether *);
uint8_t uether_is_gone(struct usb_ether *);
+int uether_alloc_unr(void);
+void uether_free_unr(int);
+
#endif /* _USB_ETHERNET_H_ */
More information about the freebsd-usb
mailing list