diff --git a/share/man/man9/usbnet.9 b/share/man/man9/usbnet.9 index b839a5d620e5..2da4c7b3e06f 100644 --- a/share/man/man9/usbnet.9 +++ b/share/man/man9/usbnet.9 @@ -35,8 +35,6 @@ .Ss Functions offered by usbnet.h .Ft void .Fn usbnet_set_link "struct usbnet *un" "bool link" -.Ft void -.Fn usbnet_set_dying "struct usbnet *un" "bool dying" .Ft struct ifnet * .Fn usbnet_ifp "struct usbnet *un" .Ft struct ethercom * @@ -52,55 +50,17 @@ .Ft bool .Fn usbnet_isdying "struct usbnet *un" .Ft void -.Fn usbnet_lock_core "struct usbnet *un" -.Ft void -.Fn usbnet_unlock_core "struct usbnet *un" -.Ft kmutex_t * -.Fn usbnet_mutex_core "struct usbnet *un" -.Ft void -.Fn usbnet_isowned_core "struct usbnet *un" -.Ft void -.Fn usbnet_lock_rx "struct usbnet *un" -.Ft void -.Fn usbnet_unlock_rx "struct usbnet *un" -.Ft kmutex_t * -.Fn usbnet_mutex_rx "struct usbnet *un" -.Ft void -.Fn usbnet_isowned_rx "struct usbnet *un" -.Ft void -.Fn usbnet_lock_tx "struct usbnet *un" -.Ft void -.Fn usbnet_unlock_tx "struct usbnet *un" -.Ft kmutex_t * -.Fn usbnet_mutex_tx "struct usbnet *un" -.Ft void -.Fn usbnet_isowned_tx "struct usbnet *un" -.Ft int -.Fn usbnet_init_rx_tx "struct usbnet *un" "unsigned rxflags" "unsigned txflags" -.Ft int -.Fn usbnet_miibus_readreg "device_t dev" "int phy" "int reg" "uint16_t *val" -.Ft int -.Fn usbnet_miibus_writereg "device_t dev" "int phy" "int reg" "uint16_t val" -.Ft void -.Fn usbnet_miibus_statchg "struct ifnet *" -.Ft void -.Fn usbnet_busy "struct usbnet *un" -.Ft void -.Fn usbnet_unbusy "struct usbnet *un" -.Ft void .Fn usbnet_enqueue "struct usbnet *un" "uint8_t *buf" "size_t buflen" "int csum_flags" "uint32_t csum_data" "int mbuf_flags" .Ft void .Fn usbnet_input "struct usbnet *un" "uint8_t *buf" "size_t buflen" .Ft void -.Fn usbnet_attach "struct usbnet *un" "const char *detname" +.Fn usbnet_attach "struct usbnet *un" .Ft void .Fn usbnet_attach_ifp "struct usbnet *un" "unsigned if_flags" "unsigned if_extflags" "const struct usbnet_mii *unm" .Ft int .Fn usbnet_detach "device_t dev" "int flags" .Ft int .Fn usbnet_activate "device_t dev" "devact_t act" -.Ft void -.Fn usbnet_stop "struct usbnet *un" "struct ifnet *ifp" "int disable" .Sh DESCRIPTION The .Nm @@ -160,42 +120,66 @@ framework itself. The device activate function should be set to .Fn usbnet_activate . .Pp -To manage all Rx and Tx chains the -.Dq uno_init -callback of -.Va struct usbnet_ops -should perform any device specific initialization and then call -.Fn 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 -.Fn usbnet_stop . -Both of -.Fn usbnet_init_rx_tx -and -.Fn usbnet_stop -must be called with the +When bringing an interface up from +.Xr if_init 9 , +which happens under +.Xr IFNET_LOCK 9 , .Nm -lock held, see -.Fn usbnet_lock -and -.Fn usbnet_unlock . +will: +.Bl -enum +.It +call +.Dq uno_init +to initialize the hardware for sending and receiving packets, +.It +open the USB pipes, +.It +allocate Rx and Tx buffers for transfers, +.It +call +.Dq uno_mcast +to initially program the hardware multicast filter, and finally +.It +start the Rx transfers so packets can be received. +.El +.Pp See the .Sx RECEIVE AND SEND section for details on using the chains. .Pp -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 -.Dq uno_init -callback should perform any device specific initialization and then call -.Fn 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 +When bringing an interface down, +.Nm +will: +.Bl -enum +.It +abort the USB pipes, +.It +call +.Dq uno_stop +to stop the hardware from receiving packets (unless the device is +detaching), +.It +free Rx and Tx buffers for transfers, and +.It +close the USB pipes. +.El +.Pp +For interface ioctl, most of the handling is in the framework. +While the interface is running, the optional +.Dq uno_mcast +callback is invoked after handling the +.Dv SIOCADDMULTI +and +.Dv SIOCDELMULTI +ioctl commands to update the hardware's multicast filter from the +.Xr ethersubr 9 +lists. +The optional .Dq uno_ioctl -callback should be used to program special settings -like multicast filters or offload handling. +callback, which is invoked under +.Xr IFNET_LOCK 9 , +can be used to program special settings like offload handling. +.Pp If ioctl handling requires capturing device-specific ioctls then the .Dq uno_override_ioctl callback may be used instead to replace the framework's @@ -203,26 +187,15 @@ ioctl handler completely (i.e., the replacement should call any generic ioctl handlers such as .Fn ether_ioctl as required.) -For interface start, the +For sending packets, the .Dq 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 -.Dq uno_stop -callback to turn off any chipset specific values if required. .Pp For devices requiring MII handling there are callbacks for reading and writing registers, and for status change events. -The framework serializes MII access with the core lock, which will be -held when calling these functions, and this lock should be used by -internal code that also requires serialized access to registers with the -.Fn usbnet_lock_core -and -.Fn usbnet_unlock_core -functions. -The MII callbacks handle device detach events safely; a reference count -is taken and released around calls to the callbacks as the MII callbacks -usually block. +Access to all the MII functions is serialized by +.Nm . .Pp As receive must handle the case of multiple packets in one buffer, the support is split between the driver and the framework. @@ -245,101 +218,32 @@ Set the link status for this .Fa un to .Fa link . -.It Fn usbnet_set_dying un dying -Set the dying status for this -.Fa un -to -.Fa dying . .It Fn usbnet_ifp un Returns pointer to this -.Fa un's +.Fa un Ns 's .Va struct ifnet . .It Fn usbnet_ec un Returns pointer to this -.Fa un's +.Fa un Ns 's .Va struct ethercom . .It Fn usbnet_mii un Returns pointer to this -.Fa un's +.Fa un Ns 's .Va struct mii_data . .It Fn usbnet_rndsrc un Returns pointer to this -.Fa un's +.Fa un Ns 's .Va krndsource_t . .It Fn usbnet_softc un Returns pointer to this -.Fa un's +.Fa un Ns 's device softc. .It Fn usbnet_havelink un Returns true if link is active. .It Fn usbnet_isdying un Returns true if device is dying (has been pulled or deactivated, -pending detach.) -.El -.Pp -Reference counting functions for -.Fa struct usbnet : -.Bl -tag -width 4n -.It Fn usbnet_busy un -Increases the reference count on the driver instance, preventing -detach from occurring while the driver is blocked accessing the -device. -Must be called with the core lock held. -.It Fn usbnet_unbusy un -Decreases the reference count on the driver instance. -Once the final reference has been dropped, if a detach event -is pending, it is allowed to proceed. -Must be called with the core lock held. -.El -.Pp -Lock handling functions for -.Fa struct usbnet : -.Pp -.Bl -tag -width 4n -compact -.It Fn usbnet_lock_core un -.It Fn usbnet_unlock_core un -.It Fn usbnet_isowned_core un -.It Fn usbnet_lock_rx un -.It Fn usbnet_unlock_rx un -.It Fn usbnet_isowned_rx un -.It Fn usbnet_lock_tx un -.It Fn usbnet_unlock_tx un -.It Fn usbnet_isowned_tx un -These groups of three functions provide methods to lock, -unlock, and assert ownership of one of the three locks provided by -.Nm . -The three locks are the -.Dq core -lock, the -.Dq Tx -lock, and the -.Dq Rx -lock. -.El -.Pp -MII access functions for -.Fa struct usbnet : -.Bl -tag -width 4n -.It Fn usbnet_mii_readreg dev phy reg valp -Read register -.Fa reg -on PHY number -.Fa phy -and return the value in -.Fa valp . -Called with the core lock held. -.It Fn usbnet_mii_writereg dev phy reg val -Write register -.Fa reg -on PHY number -.Fa phy -with -.Fa val . -Called with the core lock held. -.It Fn usbnet_mii_statchg ifp -Trigger a status change update for interface -.Fa ifp . -Called with the core lock held. +pending detach). +This should be used only to abort timeout loops early. .El .Pp Buffer enqueue handling for @@ -362,7 +266,7 @@ Enqueue buffer .Fa buf for length .Fa buflen -with higher layers +with higher layers. .El .Pp Autoconfiguration handling for @@ -371,13 +275,14 @@ See the .Sx AUTOCONFIGURATION section for more details about these functions. .Bl -tag -width 4n -.It Fn usbnet_attach un detachname +.It Fn usbnet_attach un Initial stage attach of a usb network device. -The -.Fa detachname -will be used while waiting for final references to drain when detaching. +Performs internal initialization and memory allocation only \(em +nothing is published yet. .It Fn usbnet_attach_ifp un if_flags if_extflags unm Final stage attach of usb network device. +Publishes the network interface to the rest of the system. +.Pp If the passed in .Fa unm is @@ -387,7 +292,7 @@ provided in the .Fa struct usbnet_mii structure, which has these members passed to .Fn mii_attach : -.Bl -tag -width 4n +.Bl -tag -width "un_mii_capmask" .It un_mii_flags Flags. .It un_mii_capmask @@ -410,12 +315,15 @@ and will be or-ed into the interface flags and extflags. .It Fn usbnet_detach dev flags Device detach. -Usable as actual device method. +Stops all activity and frees memory. +Usable as +.Xr driver 9 +detach method. .It Fn usbnet_activate dev act Device activate (deactivate) method. -Usable as actual device method. -.It Fn usbnet_stop un ifp disable -Interface stop routine. +Usable as +.Xr driver 9 +activate method. .El .Sh AUTOCONFIGURATION The framework expects the usbnet structure to have these members @@ -440,66 +348,102 @@ Points to a structure which contains these members: .Bl -tag -width 4n .It Ft void Fn (*uno_stop) "struct ifnet *ifp" "int disable" -Stop interface +Stop hardware activity .Pq optional . -Called with the core lock held and with a busy reference. +Called under +.Xr IFNET_LOCK 9 +when bringing the interface down, except when the device is detaching. .It Ft int Fn (*uno_ioctl) "struct ifnet *ifp" "u_long cmd" "void *data" -Simple ioctl callback +Handle driver-specific ioctls .Pq optional . -May be called with the ifnet lock held. +Called under +.Xr IFNET_LOCK 9 . +.It Ft void Fn (*uno_mcast) "struct ifnet *" +Program hardware multicast filters from +.Xr ethersubr 9 +lists +.Pq optional . +Called between, and not during, +.Dq uno_init +and +.Dq uno_stop . .It Ft int Fn (*uno_override_ioctl) "struct ifnet *ifp" "u_long cmd" "void *data" -Full ioctl callback +Handle all ioctls, including standard ethernet ioctls normally handled +internally by +.Nm .Pq optional . -May be called with the ifnet lock held. +May or may not be called under +.Xr IFNET_LOCK 9 . .It Ft int Fn (*uno_init) "struct ifnet *ifp" -Initialize (bring up) interface. +Initialize hardware activity. Required. -Called with the ifnet lock held. -Must call -.Fn usbnet_rx_tx_init . +Called under +.Xr IFNET_LOCK 9 +when bringing the interface up. .It Ft int Fn (*uno_read_reg) "struct usbnet *un" "int phy" "int reg" "uint16_t *val" Read MII register. Required with MII. -Called with the core lock held and with a busy reference. +Serialized with other MII functions, and with +.Dq uno_init +and +.Dq uno_stop . .It Ft int Fn (*uno_write_reg) "struct usbnet *un" "int phy" "int reg" "uint16_t val" Write MII register. Required with MII. -Called with the core lock held and with a busy reference. +Serialized with other MII functions, and with +.Dq uno_init +and +.Dq uno_stop . .It Ft usbd_status Fn (*uno_statchg) "struct ifnet *ifp" Handle MII status change. Required with MII. -Called with the core lock held and with a busy reference. +Serialized with other MII functions, and with +.Dq uno_init +and +.Dq uno_stop . .It Ft unsigned Fn (*uno_tx_prepare) "struct usbnet *un" "struct mbuf *m" "struct usbnet_chain *c" Prepare an mbuf for transmit. Required. -Called with the Tx lock held. +Called sequentially between, and not during, +.Dq uno_init . +and +.Dq uno_stop . .It Ft void Fn (*uno_rx_loop) "struct usbnet *un" "struct usbnet_chain *c" "uint32_t total_len" Prepare one or more chain for enqueue. Required. -Called with the Rx lock held. +Called sequentially between, and not during, +.Dq uno_init +and +.Dq uno_stop . .It Ft void Fn (*uno_intr) "struct usbnet *un" "usbd_status status" Process periodic interrupt .Pq optional . -Called with no locks held. +Called sequentially between, and not during, +.Dq uno_init +and +.Dq uno_stop . .It Ft void Fn (*uno_tick) "struct usbnet *un" Called every second with USB task thread context .Pq optional . -Called with no locks held, but a busy reference is maintained across this call. +Called sequentially between, and not during, +.Dq uno_init +and +.Dq uno_stop . .El .It un_intr Points to a .Va struct usbnet_intr structure which should have these members set: .Bl -tag -width 4n -.It uni_intr_buf +.It uni_buf If .Pf non- Dv NULL , points to a buffer passed to .Fn usbd_open_pipe_intr in the device init callback, along with the size and interval. -.It uni_intr_bufsz +.It uni_bufsz Size of interrupt pipe buffer. -.It uni_intr_interval +.It uni_interval Frequency of the interrupt in milliseconds. .El .It un_ed @@ -591,8 +535,6 @@ The optional .Fn uno_stop callback performs device-specific operations to shutdown the transmit or receive handling. -.Fn uno_stop -will be called with the usbnet lock held. .Pp The .Fn uno_init @@ -606,7 +548,7 @@ what is typically a device-specific method. .Pp The .Fn uno_rx_loop -callback converts the provided +callback, called sequentially, converts the provided .Va usbnet_chain data and length into a series (one or more) of packets that are enqueued with the higher layers using either @@ -615,15 +557,12 @@ enqueued with the higher layers using either .Fn usbnet_input for devices that use .Fn if_input -(this currently relies upon the +. +(This currently relies upon the .Va struct ifnet having the .Dq _if_input member set as well, which is true for current consumers.) -The Rx lock will be held during this call, see -.Fn usbnet_lock_rx -and -.Fn usbnet_unlock_rx . .Pp The .Fn uno_tx_prepare @@ -637,11 +576,7 @@ more than the chain buffer size, as set in the .Va usbnet .Dq un_tx_bufsz member. -This callback is only called once per packet. -The Tx lock will be held during this call, see -.Fn usbnet_lock_tx -and -.Fn usbnet_unlock_tx . +This callback is only called once per packet, sequentially. .Pp The .Fa struct usbnet_chain @@ -663,6 +598,7 @@ must be provided: Read an MII register for a particular PHY. Returns standard .Xr errno 2 . +Must initialize the result even on failure. .It uno_write_reg Write an MII register for a particular PHY. Returns standard @@ -670,12 +606,6 @@ Returns standard .It uno_statchg Handle a status change event for this interface. .El -.Pp -The read and write callbacks are called with the core lock held. -See -.Fn usbnet_lock_mii -and -.Fn usbnet_unlock_mii . .Sh INTERRUPT PIPE The interrupt specific callback, .Dq uno_intr , @@ -735,8 +665,7 @@ interface, and task and callout structures (both these probably go away entirely) and all the associated watchdog handling, timevals, list size, buffer size and xfer flags for both Rx, and Tx, and interrupt notices, interface flags, device link, -PHY number, chain data, locks including Rx, Tx, MII, and the -base softc lock. +PHY number, chain data, locks including Rx, Tx, and MII. There is a driver-only .Dq un_flags in the @@ -798,28 +727,11 @@ The device 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. -.It Device locking -The -.Nm -framework provides three locks for the system: core lock, -receive lock, and transmit lock. -The normal locking order -for these locks is ifnet lock -> usbnet core lock -> usbnet rxlock -> usbnet -txlock, or, ifnet lock -> usbnet core lock. -Also note that the core lock may be taken when the ifnet lock is not -held. .It MII handling For devices with MII support the three normal callbacks .Pq read, write, and status change must be converted to .Va usbnet . -These functions are called with the core lock is held -.Po -see -.Dq Fn usbnet_isowned_core -.Pc , -and with a busy reference held and do not require any checking for running, -or up, or dying devices. Local .Dq link variables need to be replaced with accesses to diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c index 89e2c5f55447..e1598996c825 100644 --- a/sys/dev/usb/if_aue.c +++ b/sys/dev/usb/if_aue.c @@ -240,7 +240,7 @@ CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach, static void aue_reset_pegasus_II(struct aue_softc *); static void aue_uno_stop(struct ifnet *, int); -static int aue_uno_ioctl(struct ifnet *, u_long, void *); +static void aue_uno_mcast(struct ifnet *); static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void aue_uno_mii_statchg(struct ifnet *); @@ -252,7 +252,7 @@ static void aue_uno_intr(struct usbnet *, usbd_status); static const struct usbnet_ops aue_ops = { .uno_stop = aue_uno_stop, - .uno_ioctl = aue_uno_ioctl, + .uno_mcast = aue_uno_mcast, .uno_read_reg = aue_uno_mii_read_reg, .uno_write_reg = aue_uno_mii_write_reg, .uno_statchg = aue_uno_mii_statchg, @@ -284,8 +284,6 @@ aue_csr_read_1(struct aue_softc *sc, int reg) usbd_status err; uByte val = 0; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return 0; @@ -315,8 +313,6 @@ aue_csr_read_2(struct aue_softc *sc, int reg) usbd_status err; uWord val; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return 0; @@ -346,8 +342,6 @@ aue_csr_write_1(struct aue_softc *sc, int reg, int aval) usbd_status err; uByte val; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return 0; @@ -378,8 +372,6 @@ aue_csr_write_2(struct aue_softc *sc, int reg, int aval) usbd_status err; uWord val; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return 0; @@ -440,8 +432,6 @@ aue_read_mac(struct usbnet *un) int off = 0; int word; - usbnet_isowned_core(un); - AUEHIST_FUNC(); AUEHIST_CALLARGS("aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); @@ -474,8 +464,10 @@ aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) */ if (sc->aue_vendor == USB_VENDOR_ADMTEK && sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { - if (phy == 3) + if (phy == 3) { + *val = 0; return EINVAL; + } } #endif @@ -483,6 +475,10 @@ aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); for (i = 0; i < AUE_TIMEOUT; i++) { + if (usbnet_isdying(un)) { + *val = 0; + return ENXIO; + } if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) break; } @@ -490,6 +486,7 @@ aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) if (i == AUE_TIMEOUT) { AUEHIST_CALLARGS("aue%jd: phy=%#jx reg=%#jx read timed out", device_unit(un->un_dev), phy, reg, 0); + *val = 0; return ETIMEDOUT; } @@ -524,6 +521,8 @@ aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); for (i = 0; i < AUE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return ENXIO; if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) break; } @@ -607,10 +606,10 @@ aue_crc(void *addrv) } static void -aue_setiff_locked(struct usbnet *un) +aue_uno_mcast(struct ifnet *ifp) { + struct usbnet * const un = ifp->if_softc; struct aue_softc * const sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ethercom * ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -620,24 +619,21 @@ aue_setiff_locked(struct usbnet *un) AUEHIST_FUNC(); AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); - usbnet_isowned_core(un); - if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); return; } - AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); - /* now program new ones */ ETHER_LOCK(ec); ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -645,13 +641,14 @@ allmulti: hashtbl[h >> 3] |= 1 << (h & 0x7); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); + AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); + /* write the hashtable */ for (i = 0; i < 8; i++) aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); - - ifp->if_flags &= ~IFF_ALLMULTI; } static void @@ -680,6 +677,8 @@ aue_reset(struct aue_softc *sc) AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); for (i = 0; i < AUE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) break; } @@ -848,16 +847,12 @@ aue_attach(device_t parent, device_t self, void *aux) } /* First level attach. */ - usbnet_attach(un, "auedet"); - - usbnet_lock_core(un); + usbnet_attach(un); /* Reset the adapter and get station address from the EEPROM. */ aue_reset(sc); aue_read_mac(un); - usbnet_unlock_core(un); - usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, 0, &unm); } @@ -948,24 +943,17 @@ aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -aue_init_locked(struct ifnet *ifp) +aue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; struct aue_softc *sc = usbnet_softc(un); - int i, rv; + int i; const u_char *eaddr; AUEHIST_FUNC(); AUEHIST_CALLARGSN(5, "aue%jd: enter link=%jd", device_unit(un->un_dev), usbnet_havelink(un), 0, 0); - if (usbnet_isdying(un)) - return EIO; - - /* Cancel pending I/O */ - if (ifp->if_flags & IFF_RUNNING) - return 0; - /* Reset the interface. */ aue_reset(sc); @@ -979,54 +967,11 @@ aue_init_locked(struct ifnet *ifp) else AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); - rv = usbnet_init_rx_tx(un); - - /* Load the multicast filter. */ - aue_setiff_locked(un); - /* Enable RX and TX */ aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); - //mii_mediachg(mii); - - return rv; -} - -static int -aue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = aue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; -} - -static int -aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - - AUEHIST_FUNC(); - AUEHIST_CALLARGSN(5, "aue%jd: enter cmd %#jx data %#jx", - device_unit(((struct usbnet *)(ifp->if_softc))->un_dev), - cmd, (uintptr_t)data, 0); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - aue_uno_init(ifp); - break; - default: - break; - } - return 0; } diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c index eba67386e770..5ee08ed64d4d 100644 --- a/sys/dev/usb/if_axe.c +++ b/sys/dev/usb/if_axe.c @@ -259,7 +259,7 @@ CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), axe_match, axe_attach, usbnet_detach, usbnet_activate); static void axe_uno_stop(struct ifnet *, int); -static int axe_uno_ioctl(struct ifnet *, u_long, void *); +static void axe_uno_mcast(struct ifnet *); static int axe_uno_init(struct ifnet *); static int axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); @@ -276,7 +276,7 @@ static void axe_ax88772b_init(struct axe_softc *); static const struct usbnet_ops axe_ops = { .uno_stop = axe_uno_stop, - .uno_ioctl = axe_uno_ioctl, + .uno_mcast = axe_uno_mcast, .uno_read_reg = axe_uno_mii_read_reg, .uno_write_reg = axe_uno_mii_write_reg, .uno_statchg = axe_uno_mii_statchg, @@ -293,8 +293,6 @@ axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) usb_device_request_t req; usbd_status err; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return -1; @@ -326,8 +324,10 @@ axe_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) DPRINTFN(30, "phy %#jx reg %#jx\n", phy, reg, 0, 0); - if (un->un_phyno != phy) + if (un->un_phyno != phy) { + *val = 0; return EINVAL; + } axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); @@ -336,6 +336,7 @@ axe_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) if (err) { device_printf(un->un_dev, "read PHY failed\n"); + *val = 0; return EIO; } @@ -426,11 +427,11 @@ axe_uno_mii_statchg(struct ifnet *ifp) } static void -axe_rcvfilt_locked(struct usbnet *un) +axe_uno_mcast(struct ifnet *ifp) { AXEHIST_FUNC(); AXEHIST_CALLED(); + struct usbnet * const un = ifp->if_softc; struct axe_softc * const sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -512,8 +513,6 @@ static void axe_reset(struct usbnet *un) { - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return; @@ -926,15 +925,11 @@ axe_attach(device_t parent, device_t self, void *aux) } /* Set these up now for axe_cmd(). */ - usbnet_attach(un, "axedet"); + usbnet_attach(un); /* We need the PHYID for init dance in some cases */ - usbnet_lock_core(un); - usbnet_busy(un); if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) { aprint_error_dev(self, "failed to read phyaddrs\n"); - usbnet_unbusy(un); - usbnet_unlock_core(un); return; } @@ -964,15 +959,10 @@ axe_attach(device_t parent, device_t self, void *aux) } else { if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) { aprint_error_dev(self, "failed to read ipg\n"); - usbnet_unbusy(un); - usbnet_unlock_core(un); return; } } - usbnet_unbusy(un); - usbnet_unlock_core(un); - if (!AXE_IS_172(un)) usbnet_ec(un)->ec_capabilities = ETHERCAP_VLAN_MTU; if (un->un_flags & AX772B) { @@ -1140,8 +1130,6 @@ axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) size_t hdr_len = 0, tlr_len = 0; int length, boundary; - usbnet_isowned_tx(un); - if (!AXE_IS_172(un)) { /* * Copy the mbuf data into a contiguous buffer, leaving two @@ -1216,21 +1204,13 @@ axe_csum_cfg(struct axe_softc *sc) } static int -axe_init_locked(struct ifnet *ifp) +axe_uno_init(struct ifnet *ifp) { AXEHIST_FUNC(); AXEHIST_CALLED(); struct usbnet * const un = ifp->if_softc; struct axe_softc * const sc = usbnet_softc(un); int rxmode; - usbnet_isowned_core(un); - - if (usbnet_isdying(un)) - return EIO; - - /* Cancel pending I/O */ - usbnet_stop(un, ifp, 1); - /* Reset the ethernet interface. */ axe_reset(un); @@ -1306,46 +1286,6 @@ axe_init_locked(struct ifnet *ifp) axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); - /* Accept multicast frame or run promisc. mode */ - axe_rcvfilt_locked(un); - - return usbnet_init_rx_tx(un); -} - -static int -axe_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = axe_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - -static int -axe_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - axe_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - return 0; } diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c index bf91d56b356d..f0710f24fc77 100644 --- a/sys/dev/usb/if_axen.c +++ b/sys/dev/usb/if_axen.c @@ -80,6 +80,7 @@ static void axen_ax88179_init(struct usbnet *); static void axen_uno_stop(struct ifnet *, int); static int axen_uno_ioctl(struct ifnet *, u_long, void *); +static void axen_uno_mcast(struct ifnet *); static int axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void axen_uno_mii_statchg(struct ifnet *); @@ -92,6 +93,7 @@ static int axen_uno_init(struct ifnet *); static const struct usbnet_ops axen_ops = { .uno_stop = axen_uno_stop, .uno_ioctl = axen_uno_ioctl, + .uno_mcast = axen_uno_mcast, .uno_read_reg = axen_uno_mii_read_reg, .uno_write_reg = axen_uno_mii_write_reg, .uno_statchg = axen_uno_mii_statchg, @@ -106,8 +108,6 @@ axen_cmd(struct usbnet *un, int cmd, int index, int val, void *buf) usb_device_request_t req; usbd_status err; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return 0; @@ -137,12 +137,16 @@ axen_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) { uint16_t data; - if (un->un_phyno != phy) + if (un->un_phyno != phy) { + *val = 0; return EINVAL; + } usbd_status err = axen_cmd(un, AXEN_CMD_MII_READ_REG, reg, phy, &data); - if (err) + if (err) { + *val = 0; return EIO; + } *val = le16toh(data); if (reg == MII_BMSR) @@ -223,9 +227,9 @@ axen_uno_mii_statchg(struct ifnet *ifp) } static void -axen_setiff_locked(struct usbnet *un) +axen_uno_mcast(struct ifnet *ifp) { - struct ifnet * const ifp = usbnet_ifp(un); + struct usbnet * const un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -237,8 +241,6 @@ axen_setiff_locked(struct usbnet *un) if (usbnet_isdying(un)) return; - usbnet_isowned_core(un); - rxmode = 0; /* Enable receiver, set RX mode */ @@ -293,7 +295,6 @@ allmulti: static void axen_reset(struct usbnet *un) { - usbnet_isowned_core(un); if (usbnet_isdying(un)) return; /* XXX What to reset? */ @@ -365,9 +366,6 @@ axen_ax88179_init(struct usbnet *un) uint16_t wval; uint8_t val; - usbnet_lock_core(un); - usbnet_busy(un); - /* XXX: ? */ axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val); DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val)); @@ -450,8 +448,6 @@ axen_ax88179_init(struct usbnet *un) default: aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n", val); - usbnet_unbusy(un); - usbnet_unlock_core(un); return; } axen_cmd(un, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl); @@ -496,22 +492,19 @@ axen_ax88179_init(struct usbnet *un) #define GMII_PHY_PAGE_SEL 0x1e #define GMII_PHY_PAGE_SEL 0x1f #define GMII_PAGE_EXT 0x0007 - usbnet_mii_writereg(un->un_dev, un->un_phyno, GMII_PHY_PAGE_SEL, + axen_uno_mii_write_reg(un, un->un_phyno, GMII_PHY_PAGE_SEL, GMII_PAGE_EXT); - usbnet_mii_writereg(un->un_dev, un->un_phyno, GMII_PHY_PAGE, + axen_uno_mii_write_reg(un, un->un_phyno, GMII_PHY_PAGE, 0x002c); #endif #if 1 /* XXX: phy hack ? */ - usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0005); - usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x0C, 0x0000); - usbnet_mii_readreg(un->un_dev, un->un_phyno, 0x0001, &wval); - usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x01, wval | 0x0080); - usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0000); + axen_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0005); + axen_uno_mii_write_reg(un, un->un_phyno, 0x0C, 0x0000); + axen_uno_mii_read_reg(un, un->un_phyno, 0x0001, &wval); + axen_uno_mii_write_reg(un, un->un_phyno, 0x01, wval | 0x0080); + axen_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0000); #endif - - usbnet_unbusy(un); - usbnet_unlock_core(un); } static void @@ -521,7 +514,7 @@ axen_setoe_locked(struct usbnet *un) uint64_t enabled = ifp->if_capenable; uint8_t val; - usbnet_isowned_core(un); + KASSERT(IFNET_LOCKED(ifp)); val = AXEN_RXCOE_OFF; if (enabled & IFCAP_CSUM_IPv4_Rx) @@ -555,16 +548,7 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) { struct usbnet * const un = ifp->if_softc; - usbnet_lock_core(un); - usbnet_busy(un); - switch (cmd) { - case SIOCSIFFLAGS: - case SIOCSETHERCAP: - case SIOCADDMULTI: - case SIOCDELMULTI: - axen_setiff_locked(un); - break; case SIOCSIFCAP: axen_setoe_locked(un); break; @@ -572,9 +556,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) break; } - usbnet_unbusy(un); - usbnet_unlock_core(un); - return 0; } @@ -669,22 +650,16 @@ axen_attach(device_t parent, device_t self, void *aux) } /* Set these up now for axen_cmd(). */ - usbnet_attach(un, "axendet"); + usbnet_attach(un); un->un_phyno = AXEN_PHY_ID; DPRINTF(("%s: phyno %d\n", device_xname(self), un->un_phyno)); /* Get station address. */ - usbnet_lock_core(un); - usbnet_busy(un); if (axen_get_eaddr(un, &un->un_eaddr)) { - usbnet_unbusy(un); - usbnet_unlock_core(un); printf("EEPROM checksum error\n"); return; } - usbnet_unbusy(un); - usbnet_unlock_core(un); axen_ax88179_init(un); @@ -894,20 +869,15 @@ axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -axen_init_locked(struct ifnet *ifp) +axen_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; uint16_t rxmode; uint16_t wval; uint8_t bval; - usbnet_isowned_core(un); - - if (usbnet_isdying(un)) - return EIO; - /* Cancel pending I/O */ - usbnet_stop(un, ifp, 1); + axen_uno_stop(ifp, 1); /* Reset the ethernet interface. */ axen_reset(un); @@ -919,9 +889,6 @@ axen_init_locked(struct ifnet *ifp) /* Configure offloading engine. */ axen_setoe_locked(un); - /* Program promiscuous mode and multicast filters. */ - axen_setiff_locked(un); - /* Enable receiver, set RX mode */ axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); rxmode = le16toh(wval); @@ -929,21 +896,7 @@ axen_init_locked(struct ifnet *ifp) wval = htole16(rxmode); axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); - return usbnet_init_rx_tx(un); -} - -static int -axen_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = axen_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; + return 0; } static void diff --git a/sys/dev/usb/if_cdce.c b/sys/dev/usb/if_cdce.c index 3edf73d856ca..452be10fc77e 100644 --- a/sys/dev/usb/if_cdce.c +++ b/sys/dev/usb/if_cdce.c @@ -82,12 +82,10 @@ static void cdce_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static unsigned cdce_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); -static int cdce_uno_init(struct ifnet *); static const struct usbnet_ops cdce_ops = { .uno_tx_prepare = cdce_uno_tx_prepare, .uno_rx_loop = cdce_uno_rx_loop, - .uno_init = cdce_uno_init, }; static int @@ -250,37 +248,16 @@ cdce_attach(device_t parent, device_t self, void *aux) un->un_eaddr[5] = (uint8_t)(device_unit(un->un_dev)); } - usbnet_attach(un, "cdcedet"); + usbnet_attach(un); usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, 0, NULL); } -static int -cdce_uno_init(struct ifnet *ifp) -{ - struct usbnet *un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - if (usbnet_isdying(un)) - rv = EIO; - else { - usbnet_stop(un, ifp, 1); - rv = usbnet_init_rx_tx(un); - usbnet_set_link(un, rv == 0); - } - usbnet_unlock_core(un); - - return rv; -} - static void cdce_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) { struct ifnet *ifp = usbnet_ifp(un); - usbnet_isowned_rx(un); - /* Strip off CRC added by Zaurus, if present */ if (un->un_flags & CDCE_ZAURUS && total_len > 4) total_len -= 4; diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c index e730297a939d..d6eaa2852123 100644 --- a/sys/dev/usb/if_cue.c +++ b/sys/dev/usb/if_cue.c @@ -141,14 +141,14 @@ CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach, static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); -static int cue_uno_ioctl(struct ifnet *, u_long, void *); +static void cue_uno_mcast(struct ifnet *); static void cue_uno_stop(struct ifnet *, int); static int cue_uno_init(struct ifnet *); static void cue_uno_tick(struct usbnet *); static const struct usbnet_ops cue_ops = { .uno_stop = cue_uno_stop, - .uno_ioctl = cue_uno_ioctl, + .uno_mcast = cue_uno_mcast, .uno_tx_prepare = cue_uno_tx_prepare, .uno_rx_loop = cue_uno_rx_loop, .uno_init = cue_uno_init, @@ -357,11 +357,11 @@ cue_crc(const char *addr) } static void -cue_setiff_locked(struct usbnet *un) +cue_uno_mcast(struct ifnet *ifp) { + struct usbnet *un = ifp->if_softc; struct cue_softc *sc = usbnet_softc(un); struct ethercom *ec = usbnet_ec(un); - struct ifnet *ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; uint32_t h, i; @@ -370,8 +370,10 @@ cue_setiff_locked(struct usbnet *un) device_xname(un->un_dev), ifp->if_flags)); if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) sc->cue_mctab[i] = 0xFF; cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, @@ -389,7 +391,6 @@ allmulti: while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -397,10 +398,9 @@ allmulti: sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); - ifp->if_flags &= ~IFF_ALLMULTI; - /* * Also include the broadcast address in the filter * so we can receive broadcast frames. @@ -525,7 +525,7 @@ cue_attach(device_t parent, device_t self, void *aux) } /* First level attach. */ - usbnet_attach(un, "cuedet"); + usbnet_attach(un); #if 0 /* Reset the adapter. */ @@ -545,8 +545,6 @@ cue_uno_tick(struct usbnet *un) { struct ifnet *ifp = usbnet_ifp(un); - usbnet_lock_core(un); - net_stat_ref_t nsr = IF_STAT_GETREF(ifp); if (cue_csr_read_2(un, CUE_RX_FRAMEERR)) if_statinc_ref(nsr, if_ierrors); @@ -558,8 +556,6 @@ cue_uno_tick(struct usbnet *un) if_statadd_ref(nsr, if_collisions, cue_csr_read_2(un, CUE_TX_EXCESSCOLL)); IF_STAT_PUTREF(ifp); - - usbnet_unlock_core(un); } static void @@ -613,7 +609,7 @@ cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -cue_init_locked(struct ifnet *ifp) +cue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; int i, ctl; @@ -621,11 +617,8 @@ cue_init_locked(struct ifnet *ifp) DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); - if (usbnet_isdying(un)) - return -1; - /* Cancel pending I/O */ - usbnet_stop(un, ifp, 1); + cue_uno_stop(ifp, 1); /* Reset the interface. */ #if 1 @@ -647,9 +640,6 @@ cue_init_locked(struct ifnet *ifp) ctl |= CUE_ETHCTL_PROMISC; cue_csr_write_1(un, CUE_ETHCTL, ctl); - /* Load the multicast filter. */ - cue_setiff_locked(un); - /* * Set the number of RX and TX buffers that we want * to reserve inside the ASIC. @@ -664,44 +654,6 @@ cue_init_locked(struct ifnet *ifp) /* Program the LED operation. */ cue_csr_write_1(un, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); - return usbnet_init_rx_tx(un); -} - -static int -cue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = cue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; -} - -static int -cue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - cue_setiff_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - return 0; } diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c index 172bc93fa301..b34ac031559c 100644 --- a/sys/dev/usb/if_kue.c +++ b/sys/dev/usb/if_kue.c @@ -174,11 +174,11 @@ CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach, static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); -static int kue_uno_ioctl(struct ifnet *, u_long, void *); +static void kue_uno_mcast(struct ifnet *); static int kue_uno_init(struct ifnet *); static const struct usbnet_ops kue_ops = { - .uno_ioctl = kue_uno_ioctl, + .uno_mcast = kue_uno_mcast, .uno_tx_prepare = kue_uno_tx_prepare, .uno_rx_loop = kue_uno_rx_loop, .uno_init = kue_uno_init, @@ -318,11 +318,11 @@ kue_load_fw(struct usbnet *un) } static void -kue_setiff_locked(struct usbnet *un) +kue_uno_mcast(struct ifnet *ifp) { + struct usbnet * un = ifp->if_softc; struct ethercom * ec = usbnet_ec(un); struct kue_softc * sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; int i; @@ -336,8 +336,10 @@ kue_setiff_locked(struct usbnet *un) sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC; if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC; sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST; kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); @@ -353,7 +355,6 @@ allmulti: if (i == KUE_MCFILTCNT(sc) || memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -361,10 +362,9 @@ allmulti: ETHER_NEXT_MULTI(step, enm); i++; } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); - ifp->if_flags &= ~IFF_ALLMULTI; - sc->kue_rxfilt |= KUE_RXFILT_MULTICAST; kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS, i, sc->kue_mcfilters, i * ETHER_ADDR_LEN); @@ -494,7 +494,7 @@ kue_attach(device_t parent, device_t self, void *aux) } /* First level attach, so kue_ctl() works. */ - usbnet_attach(un, "kuedet"); + usbnet_attach(un); /* Read ethernet descriptor */ err = kue_ctl(un, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR, @@ -591,7 +591,7 @@ kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -kue_init_locked(struct ifnet *ifp) +kue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; struct kue_softc *sc = usbnet_softc(un); @@ -599,12 +599,6 @@ kue_init_locked(struct ifnet *ifp) DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); - if (usbnet_isdying(un)) - return EIO; - - /* Cancel pending I/O */ - usbnet_stop(un, ifp, 1); - memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); /* Set MAC address */ kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN); @@ -621,47 +615,6 @@ kue_init_locked(struct ifnet *ifp) #endif kue_setword(un, KUE_CMD_SET_URB_SIZE, 64); - /* Load the multicast filter. */ - kue_setiff_locked(un); - - return usbnet_init_rx_tx(un); -} - -static int -kue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = kue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; -} - -static int -kue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - kue_setiff_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - return 0; } diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c index 347104b7b0df..a21c0557efb6 100644 --- a/sys/dev/usb/if_mos.c +++ b/sys/dev/usb/if_mos.c @@ -145,7 +145,7 @@ CFATTACH_DECL_NEW(mos, sizeof(struct usbnet), static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); -static int mos_uno_ioctl(struct ifnet *, u_long, void *); +static void mos_uno_mcast(struct ifnet *); static int mos_uno_init(struct ifnet *); static void mos_chip_init(struct usbnet *); static void mos_uno_stop(struct ifnet *ifp, int disable); @@ -164,7 +164,7 @@ static int mos_write_mcast(struct usbnet *, uint8_t *); static const struct usbnet_ops mos_ops = { .uno_stop = mos_uno_stop, - .uno_ioctl = mos_uno_ioctl, + .uno_mcast = mos_uno_mcast, .uno_read_reg = mos_uno_mii_read_reg, .uno_write_reg = mos_uno_mii_write_reg, .uno_statchg = mos_uno_mii_statchg, @@ -364,11 +364,16 @@ mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) MOS_PHYSTS_PENDING); for (i = 0; i < MOS_TIMEOUT; i++) { + if (usbnet_isdying(un)) { + *val = 0; + return ENXIO; + } if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) break; } if (i == MOS_TIMEOUT) { aprint_error_dev(un->un_dev, "read PHY failed\n"); + *val = 0; return EIO; } @@ -396,6 +401,8 @@ mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) MOS_PHYSTS_PENDING); for (i = 0; i < MOS_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return ENXIO; if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) break; } @@ -454,9 +461,9 @@ mos_uno_mii_statchg(struct ifnet *ifp) } static void -mos_rcvfilt_locked(struct usbnet *un) +mos_uno_mcast(struct ifnet *ifp) { - struct ifnet *ifp = usbnet_ifp(un); + struct usbnet *un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -632,7 +639,7 @@ mos_attach(device_t parent, device_t self, void *aux) aprint_normal_dev(self, "MCS7832\n"); /* Set these up now for register access. */ - usbnet_attach(un, "mosdet"); + usbnet_attach(un); mos_chip_init(un); @@ -719,18 +726,12 @@ mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -mos_init_locked(struct ifnet *ifp) +mos_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; u_int8_t rxmode; unsigned char ipgs[2]; - if (usbnet_isdying(un)) - return EIO; - - /* Cancel pending I/O */ - usbnet_stop(un, ifp, 1); - /* Reset the ethernet interface. */ mos_reset(un); @@ -743,52 +744,12 @@ mos_init_locked(struct ifnet *ifp) mos_reg_write_1(un, MOS_IPG0, ipgs[0]); mos_reg_write_1(un, MOS_IPG1, ipgs[1]); - /* Accept multicast frame or run promisc. mode */ - mos_rcvfilt_locked(un); - /* Enable receiver and transmitter, bridge controls speed/duplex mode */ rxmode = mos_reg_read_1(un, MOS_CTL); rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; rxmode &= ~(MOS_CTL_SLEEP); mos_reg_write_1(un, MOS_CTL, rxmode); - return usbnet_init_rx_tx(un); -} - -static int -mos_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = mos_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - -static int -mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - mos_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - return 0; } diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c index 559b9eff2569..943fe926dc20 100644 --- a/sys/dev/usb/if_mue.c +++ b/sys/dev/usb/if_mue.c @@ -92,7 +92,7 @@ static int mue_chip_init(struct usbnet *); static void mue_set_macaddr(struct usbnet *); static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); static int mue_prepare_tso(struct usbnet *, struct mbuf *); -static void mue_setiff_locked(struct usbnet *); +static void mue_uno_mcast(struct ifnet *); static void mue_sethwcsum_locked(struct usbnet *); static void mue_setmtu_locked(struct usbnet *); static void mue_reset(struct usbnet *); @@ -111,6 +111,7 @@ static int mue_uno_init(struct ifnet *); static const struct usbnet_ops mue_ops = { .uno_stop = mue_uno_stop, .uno_ioctl = mue_uno_ioctl, + .uno_mcast = mue_uno_mcast, .uno_read_reg = mue_uno_mii_read_reg, .uno_write_reg = mue_uno_mii_write_reg, .uno_statchg = mue_uno_mii_statchg, @@ -200,6 +201,8 @@ mue_wait_for_bits(struct usbnet *un, uint32_t reg, int ntries; for (ntries = 0; ntries < 1000; ntries++) { + if (usbnet_isdying(un)) + return 1; val = mue_csr_read(un, reg); if ((val & set) || !(val & clear)) return 0; @@ -216,11 +219,14 @@ mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) { uint32_t data; - if (un->un_phyno != phy) + if (un->un_phyno != phy) { + *val = 0; return EINVAL; + } if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { MUE_PRINTF(un, "not ready\n"); + *val = 0; return EBUSY; } @@ -230,6 +236,7 @@ mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { MUE_PRINTF(un, "timed out\n"); + *val = 0; return ETIMEDOUT; } @@ -849,7 +856,7 @@ mue_attach(device_t parent, device_t self, void *aux) } /* Set these up now for mue_cmd(). */ - usbnet_attach(un, "muedet"); + usbnet_attach(un); un->un_phyno = 1; @@ -993,10 +1000,10 @@ mue_prepare_tso(struct usbnet *un, struct mbuf *m) } static void -mue_setiff_locked(struct usbnet *un) +mue_uno_mcast(struct ifnet *ifp) { + struct usbnet *un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); - struct ifnet * const ifp = usbnet_ifp(un); const uint8_t *enaddr = CLLADDR(ifp->if_sadl); struct ether_multi *enm; struct ether_multistep step; @@ -1020,10 +1027,11 @@ mue_setiff_locked(struct usbnet *un) /* Always accept broadcast frames. */ rxfilt |= MUE_RFE_CTL_BROADCAST; + ETHER_LOCK(ec); if (ifp->if_flags & IFF_PROMISC) { rxfilt |= MUE_RFE_CTL_UNICAST; allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; if (ifp->if_flags & IFF_PROMISC) DPRINTF(un, "promisc\n"); else @@ -1033,7 +1041,6 @@ allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); i = 1; - ETHER_LOCK(ec); ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, @@ -1041,7 +1048,6 @@ allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; memset(pfiltbl, 0, sizeof(pfiltbl)); memset(hashtbl, 0, sizeof(hashtbl)); rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; - ETHER_UNLOCK(ec); goto allmulti; } if (i < MUE_NUM_ADDR_FILTX) { @@ -1059,14 +1065,14 @@ allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; i++; ETHER_NEXT_MULTI(step, enm); } - ETHER_UNLOCK(ec); + ec->ec_flags &= ~ETHER_F_ALLMULTI; rxfilt |= MUE_RFE_CTL_PERFECT; - ifp->if_flags &= ~IFF_ALLMULTI; if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) DPRINTF(un, "perfect filter and hash tables\n"); else DPRINTF(un, "perfect filter\n"); } + ETHER_UNLOCK(ec); for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { hireg = (un->un_flags & LAN7500) ? @@ -1089,6 +1095,8 @@ mue_sethwcsum_locked(struct usbnet *un) struct ifnet * const ifp = usbnet_ifp(un); uint32_t reg, val; + KASSERT(IFNET_LOCKED(ifp)); + reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; val = mue_csr_read(un, reg); @@ -1121,6 +1129,8 @@ mue_setmtu_locked(struct usbnet *un) struct ifnet * const ifp = usbnet_ifp(un); uint32_t val; + KASSERT(IFNET_LOCKED(ifp)); + /* Set the maximum frame size. */ MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); val = mue_csr_read(un, MUE_MAC_RX); @@ -1219,49 +1229,22 @@ mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) } static int -mue_init_locked(struct ifnet *ifp) +mue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; - if (usbnet_isdying(un)) { - DPRINTF(un, "dying\n"); - return EIO; - } - - /* Cancel pending I/O and free all TX/RX buffers. */ - if (ifp->if_flags & IFF_RUNNING) - usbnet_stop(un, ifp, 1); - mue_reset(un); /* Set MAC address. */ mue_set_macaddr(un); - /* Load the multicast filter. */ - mue_setiff_locked(un); - /* TCP/UDP checksum offload engines. */ mue_sethwcsum_locked(un); /* Set MTU. */ mue_setmtu_locked(un); - return usbnet_init_rx_tx(un); -} - -static int -mue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = mue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; + return 0; } static int @@ -1269,16 +1252,7 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) { struct usbnet * const un = ifp->if_softc; - usbnet_lock_core(un); - usbnet_busy(un); - switch (cmd) { - case SIOCSIFFLAGS: - case SIOCSETHERCAP: - case SIOCADDMULTI: - case SIOCDELMULTI: - mue_setiff_locked(un); - break; case SIOCSIFCAP: mue_sethwcsum_locked(un); break; @@ -1289,9 +1263,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) break; } - usbnet_unbusy(un); - usbnet_unlock_core(un); - return 0; } diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c index 6cf37e507d1c..717a6866e517 100644 --- a/sys/dev/usb/if_smsc.c +++ b/sys/dev/usb/if_smsc.c @@ -174,7 +174,6 @@ static int smsc_chip_init(struct usbnet *); static int smsc_setmacaddress(struct usbnet *, const uint8_t *); static int smsc_uno_init(struct ifnet *); -static int smsc_init_locked(struct ifnet *); static void smsc_uno_stop(struct ifnet *, int); static void smsc_reset(struct smsc_softc *); @@ -187,6 +186,7 @@ static int smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *); static int smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t); static int smsc_uno_ioctl(struct ifnet *, u_long, void *); +static void smsc_uno_mcast(struct ifnet *); static unsigned smsc_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, @@ -195,6 +195,7 @@ static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, static const struct usbnet_ops smsc_ops = { .uno_stop = smsc_uno_stop, .uno_ioctl = smsc_uno_ioctl, + .uno_mcast = smsc_uno_mcast, .uno_read_reg = smsc_uno_miibus_readreg, .uno_write_reg = smsc_uno_miibus_writereg, .uno_statchg = smsc_uno_miibus_statchg, @@ -210,8 +211,6 @@ smsc_readreg(struct usbnet *un, uint32_t off, uint32_t *data) uint32_t buf; usbd_status err; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return 0; @@ -237,8 +236,6 @@ smsc_writereg(struct usbnet *un, uint32_t off, uint32_t data) uint32_t buf; usbd_status err; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return 0; @@ -264,6 +261,8 @@ smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) int err, i; for (i = 0; i < 100; i++) { + if (usbnet_isdying(un)) + return ENXIO; if ((err = smsc_readreg(un, reg, &val)) != 0) return err; if (!(val & bits)) @@ -280,11 +279,14 @@ smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) uint32_t addr; uint32_t data = 0; - if (un->un_phyno != phy) + if (un->un_phyno != phy) { + *val = 0; return EINVAL; + } if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { smsc_warn_printf(un, "MII is busy\n"); + *val = 0; return ETIMEDOUT; } @@ -293,6 +295,7 @@ smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { smsc_warn_printf(un, "MII read timeout\n"); + *val = 0; return ETIMEDOUT; } @@ -408,24 +411,25 @@ smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) } static void -smsc_setiff_locked(struct usbnet *un) +smsc_uno_mcast(struct ifnet *ifp) { USMSCHIST_FUNC(); USMSCHIST_CALLED(); + struct usbnet * const un = ifp->if_softc; struct smsc_softc * const sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; uint32_t hashtbl[2] = { 0, 0 }; uint32_t hash; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return; - if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { + if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); DPRINTF("receive all multicast enabled", 0, 0, 0, 0); sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; @@ -440,7 +444,6 @@ allmulti: ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -448,6 +451,7 @@ allmulti: hashtbl[hash >> 5] |= 1 << (hash & 0x1F); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); /* Debug */ @@ -460,7 +464,6 @@ allmulti: /* Write the hash table and mac control registers */ //XXX should we be doing this? - ifp->if_flags &= ~IFF_ALLMULTI; smsc_writereg(un, SMSC_HASHH, hashtbl[1]); smsc_writereg(un, SMSC_HASHL, hashtbl[0]); smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); @@ -474,7 +477,7 @@ smsc_setoe_locked(struct usbnet *un) uint32_t val; int err; - usbnet_isowned_core(un); + KASSERT(IFNET_LOCKED(ifp)); err = smsc_readreg(un, SMSC_COE_CTRL, &val); if (err != 0) { @@ -536,7 +539,6 @@ smsc_reset(struct smsc_softc *sc) { struct usbnet * const un = &sc->smsc_un; - usbnet_isowned_core(un); if (usbnet_isdying(un)) return; @@ -549,42 +551,17 @@ smsc_reset(struct smsc_softc *sc) static int smsc_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = smsc_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - -static int -smsc_init_locked(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; struct smsc_softc * const sc = usbnet_softc(un); - usbnet_isowned_core(un); - - if (usbnet_isdying(un)) - return EIO; - - /* Cancel pending I/O */ - usbnet_stop(un, ifp, 1); - /* Reset the ethernet interface. */ smsc_reset(sc); - /* Load the multicast filter. */ - smsc_setiff_locked(un); - /* TCP/UDP checksum offload engines. */ smsc_setoe_locked(un); - return usbnet_init_rx_tx(un); + return 0; } static void @@ -605,8 +582,6 @@ smsc_chip_init(struct usbnet *un) int burst_cap; int err; - usbnet_isowned_core(un); - /* Enter H/W config mode */ smsc_writereg(un, SMSC_HW_CFG, SMSC_HW_CFG_LRST); @@ -753,16 +728,7 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) { struct usbnet * const un = ifp->if_softc; - usbnet_lock_core(un); - usbnet_busy(un); - switch (cmd) { - case SIOCSIFFLAGS: - case SIOCSETHERCAP: - case SIOCADDMULTI: - case SIOCDELMULTI: - smsc_setiff_locked(un); - break; case SIOCSIFCAP: smsc_setoe_locked(un); break; @@ -770,9 +736,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) break; } - usbnet_unbusy(un); - usbnet_unlock_core(un); - return 0; } @@ -863,7 +826,7 @@ smsc_attach(device_t parent, device_t self, void *aux) } } - usbnet_attach(un, "smscdet"); + usbnet_attach(un); #ifdef notyet /* @@ -881,8 +844,6 @@ smsc_attach(device_t parent, device_t self, void *aux) /* Setup some of the basics */ un->un_phyno = 1; - usbnet_lock_core(un); - usbnet_busy(un); /* * Attempt to get the mac address, if an EEPROM is not attached this * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC @@ -910,8 +871,6 @@ smsc_attach(device_t parent, device_t self, void *aux) un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); } } - usbnet_unbusy(un); - usbnet_unlock_core(un); usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, 0, &unm); diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c index a38a83a53df0..9cf77d6dd869 100644 --- a/sys/dev/usb/if_udav.c +++ b/sys/dev/usb/if_udav.c @@ -69,12 +69,11 @@ static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static void udav_uno_stop(struct ifnet *, int); -static int udav_uno_ioctl(struct ifnet *, u_long, void *); +static void udav_uno_mcast(struct ifnet *); static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void udav_uno_mii_statchg(struct ifnet *); static int udav_uno_init(struct ifnet *); -static void udav_setiff_locked(struct usbnet *); static void udav_reset(struct usbnet *); static int udav_csr_read(struct usbnet *, int, void *, int); @@ -132,7 +131,7 @@ static const struct udav_type { static const struct usbnet_ops udav_ops = { .uno_stop = udav_uno_stop, - .uno_ioctl = udav_uno_ioctl, + .uno_mcast = udav_uno_mcast, .uno_read_reg = udav_uno_mii_read_reg, .uno_write_reg = udav_uno_mii_write_reg, .uno_statchg = udav_uno_mii_statchg, @@ -237,18 +236,13 @@ udav_attach(device_t parent, device_t self, void *aux) /* Not supported yet. */ un->un_ed[USBNET_ENDPT_INTR] = 0; - usbnet_attach(un, "udavdet"); - - usbnet_lock_core(un); - usbnet_busy(un); + usbnet_attach(un); // /* reset the adapter */ // udav_reset(un); /* Get Ethernet Address */ err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); - usbnet_unbusy(un); - usbnet_unlock_core(un); if (err) { aprint_error_dev(self, "read MAC address failed\n"); return; @@ -367,8 +361,8 @@ udav_csr_read(struct usbnet *un, int offset, void *buf, int len) usb_device_request_t req; usbd_status err; - usbnet_isowned_core(un); - KASSERT(!usbnet_isdying(un)); + if (usbnet_isdying(un)) + return USBD_IOERROR; DPRINTFN(0x200, ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); @@ -386,6 +380,7 @@ udav_csr_read(struct usbnet *un, int offset, void *buf, int len) if (err) { DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", device_xname(un->un_dev), __func__, offset, err)); + memset(buf, 0, len); } return err; @@ -398,8 +393,8 @@ udav_csr_write(struct usbnet *un, int offset, void *buf, int len) usb_device_request_t req; usbd_status err; - usbnet_isowned_core(un); - KASSERT(!usbnet_isdying(un)); + if (usbnet_isdying(un)) + return USBD_IOERROR; DPRINTFN(0x200, ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); @@ -427,8 +422,6 @@ udav_csr_read1(struct usbnet *un, int offset) { uint8_t val = 0; - usbnet_isowned_core(un); - DPRINTFN(0x200, ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); @@ -445,8 +438,8 @@ udav_csr_write1(struct usbnet *un, int offset, unsigned char ch) usb_device_request_t req; usbd_status err; - usbnet_isowned_core(un); - KASSERT(!usbnet_isdying(un)); + if (usbnet_isdying(un)) + return USBD_IOERROR; DPRINTFN(0x200, ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); @@ -478,19 +471,6 @@ udav_uno_init(struct ifnet *ifp) DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); - usbnet_lock_core(un); - - if (usbnet_isdying(un)) { - usbnet_unlock_core(un); - return EIO; - } - - /* Cancel pending I/O and free all TX/RX buffers */ - if (ifp->if_flags & IFF_RUNNING) - usbnet_stop(un, ifp, 1); - - usbnet_busy(un); - memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); @@ -507,9 +487,6 @@ udav_uno_init(struct ifnet *ifp) else UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); - /* Load the multicast filter */ - udav_setiff_locked(un); - /* Enable RX */ UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); @@ -521,26 +498,18 @@ udav_uno_init(struct ifnet *ifp) rc = 0; if (rc != 0) { - usbnet_unbusy(un); - usbnet_unlock_core(un); return rc; } if (usbnet_isdying(un)) - rc = EIO; - else - rc = usbnet_init_rx_tx(un); - - usbnet_unbusy(un); - usbnet_unlock_core(un); + return EIO; - return rc; + return 0; } static void udav_reset(struct usbnet *un) { - usbnet_isowned_core(un); if (usbnet_isdying(un)) return; @@ -553,7 +522,6 @@ udav_reset(struct usbnet *un) static void udav_chip_init(struct usbnet *un) { - usbnet_isowned_core(un); /* Select PHY */ #if 1 @@ -573,6 +541,8 @@ udav_chip_init(struct usbnet *un) UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) break; delay(10); /* XXX */ @@ -586,10 +556,10 @@ udav_chip_init(struct usbnet *un) (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) static void -udav_setiff_locked(struct usbnet *un) +udav_uno_mcast(struct ifnet *ifp) { + struct usbnet * const un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; uint8_t hashes[8]; @@ -597,8 +567,6 @@ udav_setiff_locked(struct usbnet *un) DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return; @@ -609,11 +577,16 @@ udav_setiff_locked(struct usbnet *un) } if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); return; - } else if (ifp->if_flags & IFF_ALLMULTI) { + } else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */ + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); return; @@ -630,7 +603,6 @@ allmulti: while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -638,10 +610,10 @@ allmulti: hashes[h>>3] |= 1 << (h & 0x7); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); /* disable all multicast */ - ifp->if_flags &= ~IFF_ALLMULTI; UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); /* write hash value to the register */ @@ -721,29 +693,6 @@ udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); } -static int -udav_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - udav_setiff_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ static void udav_uno_stop(struct ifnet *ifp, int disable) @@ -768,6 +717,7 @@ udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) printf("%s: %s: dying\n", device_xname(un->un_dev), __func__); #endif + *val = 0; return EINVAL; } @@ -775,6 +725,7 @@ udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) if (phy != 0) { DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", device_xname(un->un_dev), __func__, phy)); + *val = 0; return EINVAL; } diff --git a/sys/dev/usb/if_upl.c b/sys/dev/usb/if_upl.c index fb99702f160e..770c3a244152 100644 --- a/sys/dev/usb/if_upl.c +++ b/sys/dev/usb/if_upl.c @@ -111,10 +111,8 @@ static void upl_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static unsigned upl_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); static int upl_uno_ioctl(struct ifnet *, u_long, void *); -static int upl_uno_init(struct ifnet *); static const struct usbnet_ops upl_ops = { - .uno_init = upl_uno_init, .uno_tx_prepare = upl_uno_tx_prepare, .uno_rx_loop = upl_uno_rx_loop, .uno_ioctl = upl_uno_ioctl, @@ -207,7 +205,7 @@ upl_attach(device_t parent, device_t self, void *aux) return; } - usbnet_attach(un, "upldet"); + usbnet_attach(un); /* Initialize interface info.*/ struct ifnet *ifp = usbnet_ifp(un); @@ -251,22 +249,6 @@ upl_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) return total_len; } -static int -upl_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - if (usbnet_isdying(un)) - rv = EIO; - else - rv = usbnet_init_rx_tx(un); - usbnet_unlock_core(un); - - return rv; -} - static int upl_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) { diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c index ea5b3023dd31..713ad6317569 100644 --- a/sys/dev/usb/if_ure.c +++ b/sys/dev/usb/if_ure.c @@ -86,7 +86,7 @@ static void ure_disable_teredo(struct usbnet *); static void ure_init_fifo(struct usbnet *); static void ure_uno_stop(struct ifnet *, int); -static int ure_uno_ioctl(struct ifnet *, u_long, void *); +static void ure_uno_mcast(struct ifnet *); static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void ure_uno_miibus_statchg(struct ifnet *); @@ -104,7 +104,7 @@ CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, static const struct usbnet_ops ure_ops = { .uno_stop = ure_uno_stop, - .uno_ioctl = ure_uno_ioctl, + .uno_mcast = ure_uno_mcast, .uno_read_reg = ure_uno_mii_read_reg, .uno_write_reg = ure_uno_mii_write_reg, .uno_statchg = ure_uno_miibus_statchg, @@ -137,6 +137,8 @@ ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index, err = usbd_do_request(un->un_udev, &req, buf); if (err) { DPRINTF(("ure_ctl: error %d\n", err)); + if (rw == URE_CTL_READ) + memset(buf, 0, len); return -1; } @@ -277,8 +279,10 @@ static int ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) { - if (un->un_phyno != phy) + if (un->un_phyno != phy) { + *val = 0; return EINVAL; + } /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */ if (reg == RTK_GMEDIASTAT) { @@ -331,17 +335,15 @@ ure_uno_miibus_statchg(struct ifnet *ifp) } static void -ure_rcvfilt_locked(struct usbnet *un) +ure_uno_mcast(struct ifnet *ifp) { + struct usbnet *un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); - struct ifnet *ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; uint32_t mchash[2] = { 0, 0 }; uint32_t h = 0, rxmode; - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return; @@ -391,11 +393,11 @@ ure_reset(struct usbnet *un) { int i; - usbnet_isowned_core(un); - ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & URE_CR_RST)) break; @@ -406,20 +408,11 @@ ure_reset(struct usbnet *un) } static int -ure_init_locked(struct ifnet *ifp) +ure_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; uint8_t eaddr[8]; - usbnet_isowned_core(un); - - if (usbnet_isdying(un)) - return EIO; - - /* Cancel pending I/O. */ - if (ifp->if_flags & IFF_RUNNING) - usbnet_stop(un, ifp, 1); - /* Set MAC address. */ memset(eaddr, 0, sizeof(eaddr)); memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); @@ -445,24 +438,7 @@ ure_init_locked(struct ifnet *ifp) ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & ~URE_RXDY_GATED_EN); - /* Accept multicast frame or run promisc. mode. */ - ure_rcvfilt_locked(un); - - return usbnet_init_rx_tx(un); -} - -static int -ure_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = ure_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; + return 0; } static void @@ -543,6 +519,8 @@ ure_rtl8153_init(struct usbnet *un) URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & URE_AUTOLOAD_DONE) break; @@ -552,6 +530,8 @@ ure_rtl8153_init(struct usbnet *un) URE_PRINTF(un, "timeout waiting for chip autoload\n"); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & URE_PHY_STAT_MASK; if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) @@ -750,6 +730,8 @@ ure_init_fifo(struct usbnet *un) ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & ~URE_MCU_BORW_EN); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & URE_LINK_LIST_READY) break; @@ -761,6 +743,8 @@ ure_init_fifo(struct usbnet *un) ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | URE_RE_INIT_LL); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & URE_LINK_LIST_READY) break; @@ -794,29 +778,6 @@ ure_init_fifo(struct usbnet *un) URE_TXFIFO_THR_NORMAL); } -static int -ure_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - ure_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - static int ure_match(device_t parent, cfdata_t match, void *aux) { @@ -894,7 +855,7 @@ ure_attach(device_t parent, device_t self, void *aux) } /* Set these up now for ure_ctl(). */ - usbnet_attach(un, "uredet"); + usbnet_attach(un); un->un_phyno = 0; @@ -927,7 +888,6 @@ ure_attach(device_t parent, device_t self, void *aux) (un->un_flags != 0) ? "" : "unknown ", ver); - usbnet_lock_core(un); if (un->un_flags & URE_FLAG_8152) ure_rtl8152_init(un); else @@ -940,7 +900,6 @@ ure_attach(device_t parent, device_t self, void *aux) else ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, sizeof(eaddr)); - usbnet_unlock_core(un); if (ETHER_IS_ZERO(eaddr)) { maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); machi = cprng_strong32() & 0xffff; diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c index 764b9c654682..56d6d350e0ca 100644 --- a/sys/dev/usb/if_url.c +++ b/sys/dev/usb/if_url.c @@ -77,11 +77,10 @@ static unsigned url_uno_tx_prepare(struct usbnet *, struct mbuf *, static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); -static int url_uno_ioctl(struct ifnet *, u_long, void *); static void url_uno_stop(struct ifnet *, int); static void url_uno_mii_statchg(struct ifnet *); static int url_uno_init(struct ifnet *); -static void url_rcvfilt_locked(struct usbnet *); +static void url_uno_mcast(struct ifnet *); static void url_reset(struct usbnet *); static int url_csr_read_1(struct usbnet *, int); @@ -93,7 +92,7 @@ static int url_mem(struct usbnet *, int, int, void *, int); static const struct usbnet_ops url_ops = { .uno_stop = url_uno_stop, - .uno_ioctl = url_uno_ioctl, + .uno_mcast = url_uno_mcast, .uno_read_reg = url_uno_mii_read_reg, .uno_write_reg = url_uno_mii_write_reg, .uno_statchg = url_uno_mii_statchg, @@ -241,10 +240,7 @@ url_attach(device_t parent, device_t self, void *aux) } /* Set these up now for url_mem(). */ - usbnet_attach(un, "urldet"); - - usbnet_lock_core(un); - usbnet_busy(un); + usbnet_attach(un); /* reset the adapter */ url_reset(un); @@ -252,22 +248,14 @@ url_attach(device_t parent, device_t self, void *aux) /* Get Ethernet Address */ err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr, ETHER_ADDR_LEN); - usbnet_unbusy(un); - usbnet_unlock_core(un); if (err) { aprint_error_dev(self, "read MAC address failed\n"); - goto bad; + return; } /* initialize interface information */ usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, 0, &unm); - - return; - - bad: - usbnet_set_dying(un, true); - return; } /* read/write memory */ @@ -277,13 +265,14 @@ url_mem(struct usbnet *un, int cmd, int offset, void *buf, int len) usb_device_request_t req; usbd_status err; - usbnet_isowned_core(un); - DPRINTFN(0x200, ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); - if (usbnet_isdying(un)) + if (usbnet_isdying(un)) { + if (cmd == URL_CMD_READMEM) + memset(buf, 0, len); return 0; + } if (cmd == URL_CMD_READMEM) req.bmRequestType = UT_READ_VENDOR_DEVICE; @@ -300,6 +289,8 @@ url_mem(struct usbnet *un, int cmd, int offset, void *buf, int len) device_xname(un->un_dev), cmd == URL_CMD_READMEM ? "read" : "write", offset, err)); + if (cmd == URL_CMD_READMEM) + memset(buf, 0, len); } return err; @@ -371,7 +362,7 @@ url_csr_write_4(struct usbnet *un, int reg, int aval) } static int -url_init_locked(struct ifnet *ifp) +url_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; const u_char *eaddr; @@ -379,13 +370,7 @@ url_init_locked(struct ifnet *ifp) DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); - usbnet_isowned_core(un); - - if (usbnet_isdying(un)) - return EIO; - - /* Cancel pending I/O and free all TX/RX buffers */ - usbnet_stop(un, ifp, 1); + url_reset(un); eaddr = CLLADDR(ifp->if_sadl); for (i = 0; i < ETHER_ADDR_LEN; i++) @@ -400,27 +385,10 @@ url_init_locked(struct ifnet *ifp) /* Init receive control register */ URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB); - /* Accept multicast frame or run promisc. mode */ - url_rcvfilt_locked(un); - /* Enable RX and TX */ URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE); - return usbnet_init_rx_tx(un); -} - -static int -url_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = url_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; + return 0; } static void @@ -436,6 +404,8 @@ url_reset(struct usbnet *un) URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); for (i = 0; i < URL_TX_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) break; delay(10); /* XXX */ @@ -445,9 +415,9 @@ url_reset(struct usbnet *un) } static void -url_rcvfilt_locked(struct usbnet *un) +url_uno_mcast(struct ifnet *ifp) { - struct ifnet * const ifp = usbnet_ifp(un); + struct usbnet * const un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -456,8 +426,6 @@ url_rcvfilt_locked(struct usbnet *un) DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); - usbnet_isowned_core(un); - if (usbnet_isdying(un)) return; @@ -565,29 +533,6 @@ static void url_intr(void) } #endif -static int -url_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - url_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ static void url_uno_stop(struct ifnet *ifp, int disable) @@ -612,6 +557,7 @@ url_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) if (phy != 0) { DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", device_xname(un->un_dev), __func__, phy)); + *val = 0; return EINVAL; } diff --git a/sys/dev/usb/if_urndis.c b/sys/dev/usb/if_urndis.c index 381207450d72..ac70280bff8d 100644 --- a/sys/dev/usb/if_urndis.c +++ b/sys/dev/usb/if_urndis.c @@ -72,8 +72,6 @@ static void urndis_uno_rx_loop(struct usbnet *, struct usbnet_chain *, static unsigned urndis_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); -static int urndis_init_un(struct ifnet *, struct usbnet *); - static uint32_t urndis_ctrl_handle_init(struct usbnet *, const struct rndis_comp_hdr *); static uint32_t urndis_ctrl_handle_query(struct usbnet *, @@ -855,36 +853,16 @@ urndis_watchdog(struct ifnet *ifp) #endif static int -urndis_init_un(struct ifnet *ifp, struct usbnet *un) +urndis_uno_init(struct ifnet *ifp) { - int err; + struct usbnet *un = ifp->if_softc; - if (ifp->if_flags & IFF_RUNNING) - return 0; + KASSERT(IFNET_LOCKED(ifp)); - err = urndis_ctrl_init(un); - if (err != RNDIS_STATUS_SUCCESS) + if (urndis_ctrl_init(un) != RNDIS_STATUS_SUCCESS) return EIO; - usbnet_lock_core(un); - if (usbnet_isdying(un)) - err = EIO; - else { - usbnet_stop(un, ifp, 1); - err = usbnet_init_rx_tx(un); - usbnet_set_link(un, err == 0); - } - usbnet_unlock_core(un); - - return err; -} - -static int -urndis_uno_init(struct ifnet *ifp) -{ - struct usbnet *un = ifp->if_softc; - - return urndis_init_un(ifp, un); + return 0; } static int @@ -1048,18 +1026,18 @@ urndis_attach(device_t parent, device_t self, void *aux) ifp->if_watchdog = urndis_watchdog; #endif - usbnet_attach(un, "urndisdet"); + usbnet_attach(un); - struct ifnet *ifp = usbnet_ifp(un); - urndis_init_un(ifp, un); + if (urndis_ctrl_init(un) != RNDIS_STATUS_SUCCESS) { + aprint_error("%s: unable to initialize hardware\n", + DEVNAME(un)); + return; + } if (urndis_ctrl_query(un, OID_802_3_PERMANENT_ADDRESS, NULL, 0, &buf, &bufsz) != RNDIS_STATUS_SUCCESS) { aprint_error("%s: unable to get hardware address\n", DEVNAME(un)); - usbnet_lock_core(un); - usbnet_stop(un, ifp, 1); - usbnet_unlock_core(un); return; } @@ -1070,9 +1048,6 @@ urndis_attach(device_t parent, device_t self, void *aux) aprint_error("%s: invalid address\n", DEVNAME(un)); if (buf && bufsz) kmem_free(buf, bufsz); - usbnet_lock_core(un); - usbnet_stop(un, ifp, 1); - usbnet_unlock_core(un); return; } @@ -1083,17 +1058,9 @@ urndis_attach(device_t parent, device_t self, void *aux) if (urndis_ctrl_set(un, OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter)) != RNDIS_STATUS_SUCCESS) { aprint_error("%s: unable to set data filters\n", DEVNAME(un)); - usbnet_lock_core(un); - usbnet_stop(un, ifp, 1); - usbnet_unlock_core(un); return; } - /* Turn off again now it has been identified. */ - usbnet_lock_core(un); - usbnet_stop(un, ifp, 1); - usbnet_unlock_core(un); - usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, 0, NULL); } diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c index 1712d2f687f0..1f57e11ea39e 100644 --- a/sys/dev/usb/usbnet.c +++ b/sys/dev/usb/usbnet.c @@ -56,17 +56,19 @@ struct usbnet_private { * and the MII / media data. * - unp_rxlock protects the rx path and its data * - unp_txlock protects the tx path and its data - * - unp_detachcv handles detach vs open references * * the lock ordering is: * ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock + * -> unp_mcastlock * - ifnet lock is not needed for unp_core_lock, but if ifnet lock is * involved, it must be taken first */ kmutex_t unp_core_lock; kmutex_t unp_rxlock; kmutex_t unp_txlock; - kcondvar_t unp_detachcv; + + kmutex_t unp_mcastlock; + bool unp_mcastactive; struct usbnet_cdata unp_cdata; @@ -76,12 +78,12 @@ struct usbnet_private { struct callout unp_stat_ch; struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; - bool unp_dying; + volatile bool unp_dying; bool unp_stopping; bool unp_attached; + bool unp_ifp_attached; bool unp_link; - int unp_refcnt; int unp_timer; unsigned short unp_if_flags; unsigned unp_number; @@ -97,6 +99,21 @@ struct usbnet_private { volatile unsigned usbnet_number; +static void usbnet_isowned_rx(struct usbnet *); +static void usbnet_isowned_tx(struct usbnet *); + +static kmutex_t * +usbnet_mutex_core(struct usbnet *un) +{ + return &un->un_pri->unp_core_lock; +} + +static __inline__ void +usbnet_isowned_core(struct usbnet *un) +{ + KASSERT(mutex_owned(usbnet_mutex_core(un))); +} + static int usbnet_modcmd(modcmd_t, void *); #ifdef USB_DEBUG @@ -149,6 +166,8 @@ fail: static void uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) { + KASSERTMSG(!un->un_pri->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); usbnet_isowned_core(un); if (un->un_ops->uno_stop) (*un->un_ops->uno_stop)(ifp, disable); @@ -157,11 +176,11 @@ uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) static int uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) { - /* - * There are cases where IFNET_LOCK will not be held when we - * are called (e.g. add/delete multicast address), so we can't - * assert it. - */ + + KASSERTMSG(cmd != SIOCADDMULTI, "%s", ifp->if_xname); + KASSERTMSG(cmd != SIOCDELMULTI, "%s", ifp->if_xname); + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + if (un->un_ops->uno_ioctl) return (*un->un_ops->uno_ioctl)(ifp, cmd, data); return 0; @@ -170,15 +189,23 @@ uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) static int uno_override_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) { - /* See above. */ + + switch (cmd) { + case SIOCADDMULTI: + case SIOCDELMULTI: + break; + default: + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + } + return (*un->un_ops->uno_override_ioctl)(ifp, cmd, data); } static int uno_init(struct usbnet *un, struct ifnet *ifp) { - KASSERT(IFNET_LOCKED(ifp)); - return (*un->un_ops->uno_init)(ifp); + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + return un->un_ops->uno_init ? (*un->un_ops->uno_init)(ifp) : 0; } static int @@ -333,7 +360,6 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) struct usbnet_chain * const c = priv; struct usbnet * const un = c->unc_un; struct usbnet_private * const unp = un->un_pri; - struct ifnet * const ifp = usbnet_ifp(un); uint32_t total_len; USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", @@ -341,9 +367,9 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) mutex_enter(&unp->unp_rxlock); - if (unp->unp_dying || unp->unp_stopping || + if (usbnet_isdying(un) || unp->unp_stopping || status == USBD_INVAL || status == USBD_NOT_STARTED || - status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) + status == USBD_CANCELLED) goto out; if (status != USBD_NORMAL_COMPLETION) { @@ -368,7 +394,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) usbnet_isowned_rx(un); done: - if (unp->unp_dying || unp->unp_stopping) + if (usbnet_isdying(un) || unp->unp_stopping) goto out; mutex_exit(&unp->unp_rxlock); @@ -397,7 +423,7 @@ usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) unp->unp_number, status, (uintptr_t)xfer, 0); mutex_enter(&unp->unp_txlock); - if (unp->unp_stopping || unp->unp_dying) { + if (unp->unp_stopping || usbnet_isdying(un)) { mutex_exit(&unp->unp_txlock); return; } @@ -440,14 +466,13 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) struct usbnet * const un = priv; struct usbnet_private * const unp = un->un_pri; struct usbnet_intr * const uni = un->un_intr; - struct ifnet * const ifp = usbnet_ifp(un); - if (uni == NULL || unp->unp_dying || unp->unp_stopping || + if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping || status == USBD_INVAL || status == USBD_NOT_STARTED || - status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) { + status == USBD_CANCELLED) { USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx", unp->unp_number, (uintptr_t)uni, - (unp->unp_dying << 8) | unp->unp_stopping, status); + (usbnet_isdying(un) << 8) | unp->unp_stopping, status); return; } @@ -809,7 +834,7 @@ usbnet_ep_stop_pipes(struct usbnet * const un) return err; } -int +static int usbnet_init_rx_tx(struct usbnet * const un) { USBNETHIST_FUNC(); USBNETHIST_CALLED(); @@ -818,14 +843,15 @@ usbnet_init_rx_tx(struct usbnet * const un) usbd_status err; int error = 0; + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); + usbnet_isowned_core(un); - if (unp->unp_dying) { + if (usbnet_isdying(un)) { return EIO; } - usbnet_busy(un); - /* Open RX and TX pipes. */ err = usbnet_ep_open_pipes(un); if (err) { @@ -849,16 +875,26 @@ usbnet_init_rx_tx(struct usbnet * const un) goto out; } - /* Start up the receive pipe(s). */ - usbnet_rx_start_pipes(un); - /* Indicate we are up and running. */ -#if 0 - /* XXX if_mcast_op() can call this without ifnet locked */ - KASSERT(ifp->if_softc == NULL || IFNET_LOCKED(ifp)); -#endif + /* XXX urndis calls usbnet_init_rx_tx before usbnet_attach_ifp. */ + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); ifp->if_flags |= IFF_RUNNING; + /* + * If the hardware has a multicast filter, program it and then + * allow updates to it while we're running. + */ + if (un->un_ops->uno_mcast) { + mutex_enter(&unp->unp_mcastlock); + (*un->un_ops->uno_mcast)(ifp); + unp->unp_mcastactive = true; + mutex_exit(&unp->unp_mcastlock); + } + + /* Start up the receive pipe(s). */ + usbnet_rx_start_pipes(un); + callout_schedule(&unp->unp_stat_ch, hz); out: @@ -867,93 +903,70 @@ out: usbnet_tx_list_fini(un); usbnet_ep_close_pipes(un); } - usbnet_unbusy(un); - - usbnet_isowned_core(un); - return error; -} - -void -usbnet_busy(struct usbnet *un) -{ - struct usbnet_private * const unp = un->un_pri; - - usbnet_isowned_core(un); - - unp->unp_refcnt++; -} - -void -usbnet_unbusy(struct usbnet *un) -{ - struct usbnet_private * const unp = un->un_pri; + /* + * For devices without any media autodetection, treat success + * here as an active link. + */ + if (un->un_ops->uno_statchg == NULL) + usbnet_set_link(un, error == 0); usbnet_isowned_core(un); - if (--unp->unp_refcnt < 0) - cv_broadcast(&unp->unp_detachcv); + return error; } /* MII management. */ -int +static int usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val) { USBNETHIST_FUNC(); struct usbnet * const un = device_private(dev); - struct usbnet_private * const unp = un->un_pri; int err; /* MII layer ensures core_lock is held. */ usbnet_isowned_core(un); - if (unp->unp_dying) { + if (usbnet_isdying(un)) { return EIO; } - usbnet_busy(un); err = uno_read_reg(un, phy, reg, val); - usbnet_unbusy(un); - if (err) { USBNETHIST_CALLARGS("%jd: read PHY failed: %jd", - unp->unp_number, err, 0, 0); + un->un_pri->unp_number, err, 0, 0); return err; } return 0; } -int +static int usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val) { USBNETHIST_FUNC(); struct usbnet * const un = device_private(dev); - struct usbnet_private * const unp = un->un_pri; int err; /* MII layer ensures core_lock is held. */ usbnet_isowned_core(un); - if (unp->unp_dying) { + if (usbnet_isdying(un)) { return EIO; } - usbnet_busy(un); err = uno_write_reg(un, phy, reg, val); - usbnet_unbusy(un); - if (err) { USBNETHIST_CALLARGS("%jd: write PHY failed: %jd", - unp->unp_number, err, 0, 0); + un->un_pri->unp_number, err, 0, 0); return err; } return 0; } -void +static void usbnet_mii_statchg(struct ifnet *ifp) { USBNETHIST_FUNC(); USBNETHIST_CALLED(); @@ -962,9 +975,7 @@ usbnet_mii_statchg(struct ifnet *ifp) /* MII layer ensures core_lock is held. */ usbnet_isowned_core(un); - usbnet_busy(un); uno_mii_statchg(un, ifp); - usbnet_unbusy(un); } static int @@ -978,7 +989,10 @@ usbnet_media_upd(struct ifnet *ifp) /* ifmedia layer ensures core_lock is held. */ usbnet_isowned_core(un); - if (unp->unp_dying) + /* ifmedia changes only with IFNET_LOCK held. */ + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + + if (usbnet_isdying(un)) return EIO; unp->unp_link = false; @@ -1004,7 +1018,7 @@ usbnet_ifflags_cb(struct ethercom *ec) struct usbnet_private * const unp = un->un_pri; int rv = 0; - mutex_enter(&unp->unp_core_lock); + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); const u_short changed = ifp->if_flags ^ unp->unp_if_flags; if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) { @@ -1015,8 +1029,6 @@ usbnet_ifflags_cb(struct ethercom *ec) rv = ENETRESET; } - mutex_exit(&unp->unp_core_lock); - return rv; } @@ -1035,8 +1047,30 @@ usbnet_if_ioctl(struct ifnet *ifp, u_long cmd, void *data) return uno_override_ioctl(un, ifp, cmd, data); error = ether_ioctl(ifp, cmd, data); - if (error == ENETRESET) - error = uno_ioctl(un, ifp, cmd, data); + if (error == ENETRESET) { + switch (cmd) { + case SIOCADDMULTI: + case SIOCDELMULTI: + /* + * If there's a hardware multicast filter, and + * it has been programmed by usbnet_init_rx_tx + * and is active, update it now. Otherwise, + * drop the update on the floor -- it will be + * observed by usbnet_init_rx_tx next time we + * bring the interface up. + */ + if (un->un_ops->uno_mcast) { + mutex_enter(&unp->unp_mcastlock); + if (unp->unp_mcastactive) + (*un->un_ops->uno_mcast)(ifp); + mutex_exit(&unp->unp_mcastlock); + } + error = 0; + break; + default: + error = uno_ioctl(un, ifp, cmd, data); + } + } return error; } @@ -1050,39 +1084,48 @@ usbnet_if_ioctl(struct ifnet *ifp, u_long cmd, void *data) * - free RX and TX resources * - close pipes * - * usbnet_stop() is exported for drivers to use, expects lock held. - * * usbnet_if_stop() is for the if_stop handler. */ -void +static void usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable) { struct usbnet_private * const unp = un->un_pri; USBNETHIST_FUNC(); USBNETHIST_CALLED(); + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); usbnet_isowned_core(un); - usbnet_busy(un); + /* + * For drivers with hardware multicast filter update callbacks: + * Prevent concurrent access to the hardware registers by + * multicast filter updates, which happens without IFNET_LOCK + * or the usbnet core lock. + */ + if (un->un_ops->uno_mcast) { + mutex_enter(&unp->unp_mcastlock); + unp->unp_mcastactive = false; + mutex_exit(&unp->unp_mcastlock); + } + /* + * Prevent new activity (rescheduling ticks, xfers, &c.) and + * clear the watchdog timer. + */ mutex_enter(&unp->unp_rxlock); mutex_enter(&unp->unp_txlock); unp->unp_stopping = true; + unp->unp_timer = 0; mutex_exit(&unp->unp_txlock); mutex_exit(&unp->unp_rxlock); - uno_stop(un, ifp, disable); - /* - * XXXSMP Would like to - * KASSERT(IFNET_LOCKED(ifp)) - * here but the locking order is: - * ifnet -> core_lock -> rxlock -> txlock - * and core_lock is already held. + * Stop the timer first, then the task -- if the timer was + * already firing, we stop the task or wait for it complete + * only after if last fired. Setting unp_stopping prevents the + * timer task from being scheduled again. */ - ifp->if_flags &= ~IFF_RUNNING; - unp->unp_timer = 0; - callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock); usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, &unp->unp_core_lock); @@ -1090,6 +1133,19 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable) /* Stop transfers. */ usbnet_ep_stop_pipes(un); + /* + * Now that the software is quiescent, ask the driver to stop + * the hardware. The driver's uno_stop routine now has + * exclusive access to any registers that might previously have + * been used by to ifmedia, mii, or ioctl callbacks. + * + * Don't bother if the device is being detached, though -- if + * it's been unplugged then there's no point in trying to touch + * the registers. + */ + if (!usbnet_isdying(un)) + uno_stop(un, ifp, disable); + /* Free RX/TX resources. */ usbnet_rx_list_fini(un); usbnet_tx_list_fini(un); @@ -1097,7 +1153,10 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable) /* Close pipes. */ usbnet_ep_close_pipes(un); - usbnet_unbusy(un); + /* Everything is quesced now. */ + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); + ifp->if_flags &= ~IFF_RUNNING; } static void @@ -1106,6 +1165,18 @@ usbnet_if_stop(struct ifnet *ifp, int disable) struct usbnet * const un = ifp->if_softc; struct usbnet_private * const unp = un->un_pri; + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + + /* + * If we're already stopped, nothing to do. + * + * XXX This should be an assertion, but it may require some + * analysis -- and possibly some tweaking -- of sys/net to + * ensure. + */ + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + mutex_enter(&unp->unp_core_lock); usbnet_stop(un, ifp, disable); mutex_exit(&unp->unp_core_lock); @@ -1126,10 +1197,8 @@ usbnet_tick(void *arg) USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0); - if (unp != NULL && !unp->unp_stopping && !unp->unp_dying) { - /* Perform periodic stuff in process context */ - usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); - } + /* Perform periodic stuff in process context */ + usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); } static void @@ -1164,27 +1233,15 @@ usbnet_tick_task(void *arg) USBNETHIST_FUNC(); struct usbnet * const un = arg; struct usbnet_private * const unp = un->un_pri; - - if (unp == NULL) - return; - - USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0); - - mutex_enter(&unp->unp_core_lock); - if (unp->unp_stopping || unp->unp_dying) { - mutex_exit(&unp->unp_core_lock); - return; - } - struct ifnet * const ifp = usbnet_ifp(un); struct mii_data * const mii = usbnet_mii(un); - KASSERT(ifp != NULL); /* embedded member */ - - usbnet_busy(un); - mutex_exit(&unp->unp_core_lock); + USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0); - if (unp->unp_timer != 0 && --unp->unp_timer == 0) + mutex_enter(&unp->unp_txlock); + const bool timeout = unp->unp_timer != 0 && --unp->unp_timer == 0; + mutex_exit(&unp->unp_txlock); + if (timeout) usbnet_watchdog(ifp); DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0); @@ -1200,8 +1257,7 @@ usbnet_tick_task(void *arg) uno_tick(un); mutex_enter(&unp->unp_core_lock); - usbnet_unbusy(un); - if (!unp->unp_stopping && !unp->unp_dying) + if (!unp->unp_stopping && !usbnet_isdying(un)) callout_schedule(&unp->unp_stat_ch, hz); mutex_exit(&unp->unp_core_lock); } @@ -1211,8 +1267,37 @@ usbnet_if_init(struct ifnet *ifp) { USBNETHIST_FUNC(); USBNETHIST_CALLED(); struct usbnet * const un = ifp->if_softc; + int error; + + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + + /* + * Prevent anyone from bringing the interface back up once + * we're detaching. + */ + if (usbnet_isdying(un)) + return EIO; + + /* + * If we're already running, nothing to do. + * + * XXX This should be an assertion, but it may require some + * analysis -- and possibly some tweaking -- of sys/net to + * ensure. + */ + if (ifp->if_flags & IFF_RUNNING) + return 0; + + mutex_enter(&un->un_pri->unp_core_lock); + error = uno_init(un, ifp); + if (error) + goto out; + error = usbnet_init_rx_tx(un); + if (error) + goto out; +out: mutex_exit(&un->un_pri->unp_core_lock); - return uno_init(un, ifp); + return error; } @@ -1224,12 +1309,6 @@ usbnet_set_link(struct usbnet *un, bool link) un->un_pri->unp_link = link; } -void -usbnet_set_dying(struct usbnet *un, bool link) -{ - un->un_pri->unp_dying = link; -} - struct ifnet * usbnet_ifp(struct usbnet *un) { @@ -1269,64 +1348,22 @@ usbnet_havelink(struct usbnet *un) bool usbnet_isdying(struct usbnet *un) { - return un->un_pri == NULL || un->un_pri->unp_dying; + return atomic_load_relaxed(&un->un_pri->unp_dying); } /* Locking. */ -void -usbnet_lock_core(struct usbnet *un) -{ - mutex_enter(&un->un_pri->unp_core_lock); -} - -void -usbnet_unlock_core(struct usbnet *un) -{ - mutex_exit(&un->un_pri->unp_core_lock); -} - -kmutex_t * -usbnet_mutex_core(struct usbnet *un) -{ - return &un->un_pri->unp_core_lock; -} - -void -usbnet_lock_rx(struct usbnet *un) -{ - mutex_enter(&un->un_pri->unp_rxlock); -} - -void -usbnet_unlock_rx(struct usbnet *un) -{ - mutex_exit(&un->un_pri->unp_rxlock); -} - -kmutex_t * -usbnet_mutex_rx(struct usbnet *un) -{ - return &un->un_pri->unp_rxlock; -} - -void -usbnet_lock_tx(struct usbnet *un) -{ - mutex_enter(&un->un_pri->unp_txlock); -} - -void -usbnet_unlock_tx(struct usbnet *un) +static void +usbnet_isowned_rx(struct usbnet *un) { - mutex_exit(&un->un_pri->unp_txlock); + KASSERT(mutex_owned(&un->un_pri->unp_rxlock)); } -kmutex_t * -usbnet_mutex_tx(struct usbnet *un) +static void +usbnet_isowned_tx(struct usbnet *un) { - return &un->un_pri->unp_txlock; + KASSERT(mutex_owned(&un->un_pri->unp_txlock)); } /* Autoconf management. */ @@ -1353,8 +1390,7 @@ usbnet_empty_eaddr(struct usbnet * const un) */ void -usbnet_attach(struct usbnet *un, - const char *detname) /* detach cv name */ +usbnet_attach(struct usbnet *un) { USBNETHIST_FUNC(); USBNETHIST_CALLED(); @@ -1373,14 +1409,15 @@ usbnet_attach(struct usbnet *un, un->un_pri = kmem_zalloc(sizeof(*un->un_pri), KM_SLEEP); struct usbnet_private * const unp = un->un_pri; - usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, USB_TASKQ_MPSAFE); + usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, + USB_TASKQ_MPSAFE); callout_init(&unp->unp_stat_ch, CALLOUT_MPSAFE); callout_setfunc(&unp->unp_stat_ch, usbnet_tick, un); mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); mutex_init(&unp->unp_core_lock, MUTEX_DEFAULT, IPL_NONE); - cv_init(&unp->unp_detachcv, detname); + mutex_init(&unp->unp_mcastlock, MUTEX_DEFAULT, IPL_SOFTCLOCK); rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev), RND_TYPE_NET, RND_FLAG_DEFAULT); @@ -1435,7 +1472,9 @@ usbnet_attach_ifp(struct usbnet *un, struct ifnet * const ifp = usbnet_ifp(un); KASSERT(unp->unp_attached); + KASSERT(!unp->unp_ifp_attached); + ifp->if_softc = un; strlcpy(ifp->if_xname, device_xname(un->un_dev), IFNAMSIZ); ifp->if_flags = if_flags; ifp->if_extflags = IFEF_MPSAFE | if_extflags; @@ -1454,6 +1493,7 @@ usbnet_attach_ifp(struct usbnet *un, if (ifp->_if_input == NULL) ifp->if_percpuq = if_percpuq_create(ifp); if_register(ifp); + unp->unp_ifp_attached = true; /* * If ethernet address is all zero, skip ether_ifattach() and @@ -1471,7 +1511,6 @@ usbnet_attach_ifp(struct usbnet *un, /* Now ready, and attached. */ IFQ_SET_READY(&ifp->if_snd); - ifp->if_softc = un; usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, un->un_udev, un->un_dev); @@ -1493,39 +1532,39 @@ usbnet_detach(device_t self, int flags) struct ifnet * const ifp = usbnet_ifp(un); struct mii_data * const mii = usbnet_mii(un); - mutex_enter(&unp->unp_core_lock); - unp->unp_dying = true; - mutex_exit(&unp->unp_core_lock); + /* + * Prevent new activity. After we stop the interface, it + * cannot be brought back up. + */ + atomic_store_relaxed(&unp->unp_dying, true); - if (ifp->if_flags & IFF_RUNNING) { + /* + * If we're still running on the network, stop and wait for all + * asynchronous activity to finish. + * + * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but + * no activity is possible, so just skip this part. + */ + if (unp->unp_ifp_attached) { IFNET_LOCK(ifp); - usbnet_if_stop(ifp, 1); + if (ifp->if_flags & IFF_RUNNING) { + usbnet_if_stop(ifp, 1); + } IFNET_UNLOCK(ifp); } - callout_halt(&unp->unp_stat_ch, NULL); - usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, - NULL); - - mutex_enter(&unp->unp_core_lock); - unp->unp_refcnt--; - while (unp->unp_refcnt >= 0) { - /* Wait for processes to go away */ - cv_wait(&unp->unp_detachcv, &unp->unp_core_lock); - } - mutex_exit(&unp->unp_core_lock); - - usbnet_rx_list_free(un); - usbnet_tx_list_free(un); - - callout_destroy(&unp->unp_stat_ch); - rnd_detach_source(&unp->unp_rndsrc); + /* + * The callout and tick task can't be scheduled anew at this + * point, and usbnet_if_stop has waited for them to complete. + */ + KASSERT(!callout_pending(&unp->unp_stat_ch)); + KASSERT(!usb_task_pending(un->un_udev, &unp->unp_ticktask)); if (mii) { mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY); ifmedia_fini(&mii->mii_media); } - if (ifp->if_softc) { + if (unp->unp_ifp_attached) { if (!usbnet_empty_eaddr(un)) ether_ifdetach(ifp); else @@ -1534,14 +1573,28 @@ usbnet_detach(device_t self, int flags) } usbnet_ec(un)->ec_mii = NULL; - cv_destroy(&unp->unp_detachcv); + usbnet_rx_list_free(un); + usbnet_tx_list_free(un); + + rnd_detach_source(&unp->unp_rndsrc); + + mutex_destroy(&unp->unp_mcastlock); mutex_destroy(&unp->unp_core_lock); mutex_destroy(&unp->unp_rxlock); mutex_destroy(&unp->unp_txlock); + callout_destroy(&unp->unp_stat_ch); + pmf_device_deregister(un->un_dev); - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, un->un_dev); + /* + * Notify userland that we're going away, if we arrived in the + * first place. + */ + if (unp->unp_ifp_attached) { + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, + un->un_dev); + } kmem_free(unp, sizeof(*unp)); un->un_pri = NULL; @@ -1561,9 +1614,7 @@ usbnet_activate(device_t self, devact_t act) case DVACT_DEACTIVATE: if_deactivate(ifp); - mutex_enter(&unp->unp_core_lock); - unp->unp_dying = true; - mutex_exit(&unp->unp_core_lock); + atomic_store_relaxed(&unp->unp_dying, true); mutex_enter(&unp->unp_rxlock); mutex_enter(&unp->unp_txlock); diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h index 15e9dfc7b351..70f600b038f7 100644 --- a/sys/dev/usb/usbnet.h +++ b/sys/dev/usb/usbnet.h @@ -58,19 +58,12 @@ * cases), but provides a normal handler with callback to handle * ENETRESET conditions that should be sufficient for most users * - start uses usbnet transmit prepare callback (uno_tx_prepare) - * - interface init and stop have helper functions - * - device specific init should use usbnet_init_rx_tx() to open pipes - * to the device and setup the rx/tx chains for use after any device - * specific setup - * - usbnet_stop() must be called with the un_lock held, and will - * call the device-specific usbnet stop callback, which enables the - * standard init calls stop idiom. * - interrupt handling: - * - for rx, usbnet_init_rx_tx() will enable the receive pipes and + * - for rx, usbnet will enable the receive pipes and * call the rx_loop callback to handle device specific processing of * packets, which can use usbnet_enqueue() to provide data to the * higher layers - * - for tx, usbnet_start (if_start) will pull entries out of the + * - for tx, usbnet will pull entries out of the * transmit queue and use the transmit prepare callback (uno_tx_prepare) * for the given mbuf. the usb callback will use usbnet_txeof() for * the transmit completion function (internal to usbnet) @@ -131,6 +124,8 @@ enum usbnet_ep { typedef void (*usbnet_stop_cb)(struct ifnet *, int); /* Interface ioctl callback. */ typedef int (*usbnet_ioctl_cb)(struct ifnet *, u_long, void *); +/* Reprogram multicast filters callback. */ +typedef void (*usbnet_mcast_cb)(struct ifnet *); /* Initialise device callback. */ typedef int (*usbnet_init_cb)(struct ifnet *); @@ -170,16 +165,16 @@ typedef void (*usbnet_intr_cb)(struct usbnet *, usbd_status); * Note that when CORE_LOCK is held, IFNET_LOCK may or may not also * be held. * - * Note that the IFNET_LOCK **may not be held** for some ioctl - * operations (add/delete multicast addresses, for example). - * - * Busy reference counts are maintained across calls to: uno_stop, - * uno_read_reg, uno_write_reg, uno_statchg, and uno_tick. + * Note that the IFNET_LOCK **may not be held** for the ioctl commands + * SIOCADDMULTI/SIOCDELMULTI. These commands are only passed + * explicitly to uno_override_ioctl; for all other devices, they are + * handled by uno_mcast (also without IFNET_LOCK). */ struct usbnet_ops { usbnet_stop_cb uno_stop; /* C */ - usbnet_ioctl_cb uno_ioctl; /* I (maybe) */ - usbnet_ioctl_cb uno_override_ioctl; /* I (maybe) */ + usbnet_ioctl_cb uno_ioctl; /* I */ + usbnet_ioctl_cb uno_override_ioctl; /* I (except mcast) */ + usbnet_mcast_cb uno_mcast; /* I */ usbnet_init_cb uno_init; /* I */ usbnet_mii_read_reg_cb uno_read_reg; /* C */ usbnet_mii_write_reg_cb uno_write_reg; /* C */ @@ -259,11 +254,8 @@ struct usbnet { /* * This section should be filled in before calling * usbnet_attach_ifp(). - * - * XXX This should be of type "uByte". enum usbnet_ep - * is the index. Fix this in a kernel version bump. */ - enum usbnet_ep un_ed[USBNET_ENDPT_MAX]; + uByte un_ed[USBNET_ENDPT_MAX]; /* MII specific. Not used without MII. */ int un_phyno; @@ -284,7 +276,6 @@ struct usbnet { /* Various accessors. */ void usbnet_set_link(struct usbnet *, bool); -void usbnet_set_dying(struct usbnet *, bool); struct ifnet *usbnet_ifp(struct usbnet *); struct ethercom *usbnet_ec(struct usbnet *); @@ -295,60 +286,27 @@ void *usbnet_softc(struct usbnet *); bool usbnet_havelink(struct usbnet *); bool usbnet_isdying(struct usbnet *); - -/* - * Locking. Note that the isowned() are implemented here so that - * empty-KASSERT() causes them to be elided for non-DIAG builds. - */ -void usbnet_lock_core(struct usbnet *); -void usbnet_unlock_core(struct usbnet *); -kmutex_t *usbnet_mutex_core(struct usbnet *); -static __inline__ void -usbnet_isowned_core(struct usbnet *un) -{ - KASSERT(mutex_owned(usbnet_mutex_core(un))); -} - -void usbnet_busy(struct usbnet *); -void usbnet_unbusy(struct usbnet *); - -void usbnet_lock_rx(struct usbnet *); -void usbnet_unlock_rx(struct usbnet *); -kmutex_t *usbnet_mutex_rx(struct usbnet *); -static __inline__ void -usbnet_isowned_rx(struct usbnet *un) -{ - KASSERT(mutex_owned(usbnet_mutex_rx(un))); -} - -void usbnet_lock_tx(struct usbnet *); -void usbnet_unlock_tx(struct usbnet *); -kmutex_t *usbnet_mutex_tx(struct usbnet *); -static __inline__ void -usbnet_isowned_tx(struct usbnet *un) -{ - KASSERT(mutex_owned(usbnet_mutex_tx(un))); -} - /* * Endpoint / rx/tx chain management: * - * usbnet_attach() initialises usbnet and allocates rx and tx chains - * usbnet_init_rx_tx() open pipes, initialises the rx/tx chains for use - * usbnet_stop() stops pipes, cleans (not frees) rx/tx chains, locked - * version assumes un_lock is held + * 1. usbnet_attach() initialises usbnet and allocates rx and tx chains + * + * 2. On if_init, usbnet: + * - calls uno_init to initialize hardware + * - open pipes + * - initialises the rx/tx chains for use + * - calls uno_mcast to program hardware multicast filter + * + * 3. On if_stop, usbnet: + * - stops pipes + * - calls uno_stop to stop hardware (unless we're detaching anyway) + * - cleans (not frees) rx/tx chains + * - closes pipes + * * usbnet_detach() frees the rx/tx chains * * Setup un_ed[] with valid end points before calling usbnet_attach(). - * Call usbnet_init_rx_tx() to initialise pipes, which will be open - * upon success. */ -int usbnet_init_rx_tx(struct usbnet * const); - -/* MII. */ -int usbnet_mii_readreg(device_t, int, int, uint16_t *); -int usbnet_mii_writereg(device_t, int, int, uint16_t); -void usbnet_mii_statchg(struct ifnet *); /* interrupt handling */ void usbnet_enqueue(struct usbnet * const, uint8_t *, size_t, int, @@ -356,15 +314,12 @@ void usbnet_enqueue(struct usbnet * const, uint8_t *, size_t, int, void usbnet_input(struct usbnet * const, uint8_t *, size_t); /* autoconf */ -void usbnet_attach(struct usbnet *un, const char *); +void usbnet_attach(struct usbnet *); void usbnet_attach_ifp(struct usbnet *, unsigned, unsigned, const struct usbnet_mii *); int usbnet_detach(device_t, int); int usbnet_activate(device_t, devact_t); -/* stop backend */ -void usbnet_stop(struct usbnet *, struct ifnet *, int); - /* module hook up */ #ifdef _MODULE