From owner-freebsd-usb@FreeBSD.ORG Sun Oct 31 21:47:11 2010 Return-Path: Delivered-To: freebsd-usb@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 29551106566B; Sun, 31 Oct 2010 21:47:11 +0000 (UTC) (envelope-from weongyo.jeong@gmail.com) Received: from mail-vw0-f54.google.com (mail-vw0-f54.google.com [209.85.212.54]) by mx1.freebsd.org (Postfix) with ESMTP id B37538FC08; Sun, 31 Oct 2010 21:47:10 +0000 (UTC) Received: by vws12 with SMTP id 12so2952574vws.13 for ; Sun, 31 Oct 2010 14:47:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:received:from:date:to:cc :subject:message-id:reply-to:mime-version:content-type :content-disposition:user-agent:organization:x-operation-sytem; bh=R1E9JAqanbqwNYCJtcpDnTh3ZmCa5qM9ISV+JYs5Msc=; b=WsOM0qMFJhkzIhqfqZNgIEbHgBwkbPs4QGa1ml6t7FXXBRRwcvDsaC24gwaQKHqru/ GYrd7AkkrYLx3S1YwwCVOqAs9Fh5JE18uj1XXH29HSwmV44vTSnDgiW8YkdERcmwkqRT V8VzyNwv97HOtegQxM3RP3ZLHNZIzD9DHEm24= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:date:to:cc:subject:message-id:reply-to:mime-version :content-type:content-disposition:user-agent:organization :x-operation-sytem; b=xP6yfE8mSswGmyxyQ6hIQUPY7pMqwTXMOn0mG/MMEbVJMVRLTvSfKcrD665aASklbb sht7xegFLLg1NQbixA+K80+PPbz9etsPtIF73lCZfL56WjUQzy1mXx/GnCmBIWuTPkwM 8V/3QHApybPqEe9PJbPs/F/ZHZcxtuI8jiPsc= Received: by 10.229.96.136 with SMTP id h8mr7249440qcn.184.1288561629695; Sun, 31 Oct 2010 14:47:09 -0700 (PDT) Received: from weongyo ([174.35.1.224]) by mx.google.com with ESMTPS id nb14sm4341254qcb.36.2010.10.31.14.47.06 (version=SSLv3 cipher=RC4-MD5); Sun, 31 Oct 2010 14:47:08 -0700 (PDT) Received: by weongyo (sSMTP sendmail emulation); Sun, 31 Oct 2010 14:47:04 -0700 From: Weongyo Jeong Date: Sun, 31 Oct 2010 14:47:04 -0700 To: freebsd-usb@freebsd.org Message-ID: <20101031214704.GA3918@weongyo> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.3i Organization: CDNetworks. X-Operation-Sytem: FreeBSD Cc: Subject: [CFR 2/n] removes uther dependency of aue(4) X-BeenThere: freebsd-usb@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Weongyo Jeong List-Id: FreeBSD support for USB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 31 Oct 2010 21:47:11 -0000 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 #include #include +#include +#include #include #include #include @@ -88,6 +90,19 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include +#include +#include +#include +#include +#include + +#include "miibus_if.h" + +#include +#include + #include #include #include @@ -96,6 +111,7 @@ __FBSDID("$FreeBSD$"); #define USB_DEBUG_VAR aue_debug #include #include +#include #include #include @@ -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, " 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_ */