On Fri, Feb 27, 2015 at 02:43:42PM -0430, Halim Srama wrote: > After a couple of hours without using the PC the dongle went of. and trying > to restart the interface generates de same problems I reported earlier. > On Feb 27, 2015 12:46 PM, "Henrique Lengler" <henriquel...@opmbx.org> wrote: > > > On Fri, Feb 27, 2015 at 05:25:49PM +0100, Stefan Sperling wrote: > > > On Fri, Feb 27, 2015 at 11:42:32AM -0430, Halim Srama wrote: > > > > With the previous -current athn0 used to trigger the ehci_idone. It's a > > > > TP-LINK TL-WN722N. > > > > > > Thanks, those are easy to find and cheap. I'll pick one up ASAP. > > > > As I said, I have this problem, and I use the same card. > > -- > > Regards > > > > Henrique Lengler
This driver is quite buggy. It works much better for me with this diff. Please test. I got some help from mpi@, thanks much! hostap mode doesn't work for me. I doubt it ever did and I doubt this driver has ever been stable enough for anyone to seriously try hostap. Index: if_athn_usb.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_athn_usb.c,v retrieving revision 1.26 diff -u -p -r1.26 if_athn_usb.c --- if_athn_usb.c 10 Feb 2015 23:25:46 -0000 1.26 +++ if_athn_usb.c 1 Mar 2015 10:52:25 -0000 @@ -126,6 +126,7 @@ uint32_t athn_usb_read(struct athn_softc void athn_usb_write(struct athn_softc *, uint32_t, uint32_t); void athn_usb_write_barrier(struct athn_softc *); int athn_usb_media_change(struct ifnet *); +void athn_usb_next_scan(void *); int athn_usb_newstate(struct ieee80211com *, enum ieee80211_state, int); void athn_usb_newstate_cb(struct athn_usb_softc *, void *); @@ -291,6 +292,8 @@ athn_usb_detach(struct device *self, int /* Wait for all async commands to complete. */ athn_usb_wait_async(usc); + usbd_ref_wait(usc->sc_udev); + /* Abort and close Tx/Rx pipes. */ athn_usb_close_pipes(usc); @@ -348,10 +351,7 @@ athn_usb_attachhook(void *xsc) #endif ic->ic_newstate = athn_usb_newstate; ic->ic_media.ifm_change = athn_usb_media_change; - - /* Firmware cannot handle more than 8 STAs. */ - if (ic->ic_max_nnodes > AR_USB_MAX_STA) - ic->ic_max_nnodes = AR_USB_MAX_STA; + timeout_set(&sc->scan_to, athn_usb_next_scan, usc); ops->rx_enable = athn_usb_rx_enable; splx(s); @@ -436,18 +436,28 @@ athn_usb_open_pipes(struct athn_usb_soft void athn_usb_close_pipes(struct athn_usb_softc *usc) { - if (usc->tx_data_pipe != NULL) + if (usc->tx_data_pipe != NULL) { usbd_close_pipe(usc->tx_data_pipe); - if (usc->rx_data_pipe != NULL) + usc->tx_data_pipe = NULL; + } + if (usc->rx_data_pipe != NULL) { usbd_close_pipe(usc->rx_data_pipe); - if (usc->tx_intr_pipe != NULL) + usc->rx_data_pipe = NULL; + } + if (usc->tx_intr_pipe != NULL) { + usbd_abort_pipe(usc->rx_intr_pipe); usbd_close_pipe(usc->tx_intr_pipe); + usc->tx_intr_pipe = NULL; + } if (usc->rx_intr_pipe != NULL) { usbd_abort_pipe(usc->rx_intr_pipe); usbd_close_pipe(usc->rx_intr_pipe); + usc->rx_intr_pipe = NULL; } - if (usc->ibuf != NULL) + if (usc->ibuf != NULL) { free(usc->ibuf, M_USBDEV, 0); + usc->ibuf = NULL; + } } int @@ -590,7 +600,6 @@ athn_usb_task(void *arg) ring->queued--; ring->next = (ring->next + 1) % ATHN_USB_HOST_CMD_RING_COUNT; } - wakeup(ring); splx(s); } @@ -602,8 +611,11 @@ athn_usb_do_async(struct athn_usb_softc struct athn_usb_host_cmd *cmd; int s; - if (ring->queued) + if (ring->queued == ATHN_USB_HOST_CMD_RING_COUNT) { + printf("%s: host cmd queue overrun\n", usc->usb_dev.dv_xname); return; /* XXX */ + } + s = splusb(); cmd = &ring->cmd[ring->cur]; cmd->cb = cb; @@ -621,8 +633,7 @@ void athn_usb_wait_async(struct athn_usb_softc *usc) { /* Wait for all queued asynchronous commands to complete. */ - while (usc->cmdq.queued > 0) - tsleep(&usc->cmdq, 0, "cmdq", 0); + usb_wait_task(usc->sc_udev, &usc->sc_task); } int @@ -852,6 +863,9 @@ athn_usb_wmi_xcmd(struct athn_usb_softc struct ar_wmi_cmd_hdr *wmi; int s, error; + if (usbd_is_dying(usc->sc_udev)) + return ENXIO; + htc = (struct ar_htc_frame_hdr *)data->buf; memset(htc, 0, sizeof(*htc)); htc->endpoint_id = usc->ep_ctrl; @@ -877,12 +891,29 @@ athn_usb_wmi_xcmd(struct athn_usb_softc } usc->obuf = obuf; usc->wait_cmd_id = cmd_id; - /* Wait for WMI command to complete. */ - error = tsleep(&usc->wait_cmd_id, 0, "athnwmi", hz); + /* + * Wait for WMI command to complete. In case it does not complete + * wait until USB transfer timeout to avoid racing the transfer. + */ + error = tsleep(&usc->wait_cmd_id, 0, "athnwmi", ATHN_USB_CMD_TIMEOUT); usc->wait_cmd_id = 0; - /* Most of the time this would have complete already. */ - while (__predict_false(!usc->wmi_done)) - tsleep(&usc->wmi_done, 0, "athnwmi", 0); + if (error) { + if (error == EWOULDBLOCK) { + printf("%s: firmware command 0x%x timed out)\n", + usc->usb_dev.dv_xname, cmd_id); + error = ETIMEDOUT; + } + splx(s); + return (error); + } + /* Most of the time the transfer will have completed already. */ + if (__predict_false(!usc->wmi_done) && !usbd_is_dying(usc->sc_udev)) { + /* Wait a little bit for the USB transfer to finish. */ + error = tsleep(&usc->wmi_done, 0, "athnwmd", + ATHN_USB_CMD_TIMEOUT); + if (error == EWOULDBLOCK) + error = ETIMEDOUT; + } splx(s); return (error); } @@ -956,8 +987,12 @@ athn_usb_write_barrier(struct athn_softc int athn_usb_media_change(struct ifnet *ifp) { + struct athn_usb_softc *usc = (struct athn_usb_softc *)ifp->if_softc; int error; + if (usbd_is_dying(usc->sc_udev)) + return ENXIO; + error = ieee80211_media_change(ifp); if (error != ENETRESET) return (error); @@ -970,6 +1005,27 @@ athn_usb_media_change(struct ifnet *ifp) return (error); } +void +athn_usb_next_scan(void *arg) +{ + struct athn_usb_softc *usc = arg; + struct athn_softc *sc = &usc->sc_sc; + struct ieee80211com *ic = &sc->sc_ic; + int s; + + if (usbd_is_dying(usc->sc_udev)) + return; + + usbd_ref_incr(usc->sc_udev); + + s = splnet(); + if (ic->ic_state == IEEE80211_S_SCAN) + ieee80211_next_scan(&ic->ic_if); + splx(s); + + usbd_ref_decr(usc->sc_udev); +} + int athn_usb_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) @@ -992,7 +1048,9 @@ athn_usb_newstate_cb(struct athn_usb_sof struct ieee80211com *ic = &sc->sc_ic; enum ieee80211_state ostate; uint32_t reg, imask; +#ifndef IEEE80211_STA_ONLY uint8_t sta_index; +#endif int s, error; timeout_del(&sc->calib_to); @@ -1002,9 +1060,19 @@ athn_usb_newstate_cb(struct athn_usb_sof DPRINTF(("newstate %d -> %d\n", ostate, cmd->state)); if (ostate == IEEE80211_S_RUN) { - sta_index = ((struct athn_node *)ic->ic_bss)->sta_index; - (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE, - &sta_index, sizeof(sta_index), NULL); +#ifndef IEEE80211_STA_ONLY + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + /* XXX really needed? */ + sta_index = ((struct athn_node *)ic->ic_bss)->sta_index; + (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE, + &sta_index, sizeof(sta_index), NULL); + } +#endif + reg = AR_READ(sc, AR_RX_FILTER); + reg = (reg & ~AR_RX_FILTER_MYBEACON) | + AR_RX_FILTER_BEACON; + AR_WRITE(sc, AR_RX_FILTER, reg); + AR_WRITE_BARRIER(sc); } switch (cmd->state) { case IEEE80211_S_INIT: @@ -1014,7 +1082,8 @@ athn_usb_newstate_cb(struct athn_usb_sof /* Make the LED blink while scanning. */ athn_set_led(sc, !sc->led_state); (void)athn_usb_switch_chan(sc, ic->ic_bss->ni_chan, NULL); - timeout_add_msec(&sc->scan_to, 200); + if (!usbd_is_dying(usc->sc_udev)) + timeout_add_msec(&sc->scan_to, 200); break; case IEEE80211_S_AUTH: athn_set_led(sc, 0); @@ -1028,8 +1097,13 @@ athn_usb_newstate_cb(struct athn_usb_sof if (ic->ic_opmode == IEEE80211_M_MONITOR) break; - /* Create node entry for our BSS. */ - error = athn_usb_create_node(usc, ic->ic_bss); +#ifndef IEEE80211_STA_ONLY + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + /* Create node entry for our BSS */ + /* XXX really needed? breaks station mode on down/up */ + error = athn_usb_create_node(usc, ic->ic_bss); + } +#endif athn_set_bss(sc, ic->ic_bss); athn_usb_wmi_cmd(usc, AR_WMI_CMD_DISABLE_INTR); @@ -1109,6 +1183,7 @@ athn_usb_node_leave_cb(struct athn_usb_s (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE, &sta_index, sizeof(sta_index), NULL); + usc->nnodes--; } int @@ -1176,6 +1251,10 @@ athn_usb_create_node(struct athn_usb_sof struct ar_htc_target_rate rate; int error; + /* Firmware cannot handle more than 8 STAs. */ + if (usc->nnodes > AR_USB_MAX_STA) + return ENOBUFS; + an->sta_index = IEEE80211_AID(ni->ni_associd); /* Create node entry on target. */ @@ -1192,6 +1271,7 @@ athn_usb_create_node(struct athn_usb_sof &sta, sizeof(sta), NULL); if (error != 0) return (error); + usc->nnodes++; /* Setup supported rates. */ memset(&rate, 0, sizeof(rate)); @@ -1263,11 +1343,6 @@ athn_usb_switch_chan(struct athn_softc * return (error); } - error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_START_RECV); - if (error != 0) - return (error); - athn_rx_start(sc); - mode = htobe16(IEEE80211_IS_CHAN_2GHZ(c) ? AR_HTC_MODE_11NG : AR_HTC_MODE_11NA); error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_SET_MODE, @@ -1275,6 +1350,11 @@ athn_usb_switch_chan(struct athn_softc * if (error != 0) return (error); + error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_START_RECV); + if (error != 0) + return (error); + athn_rx_start(sc); + /* Re-enable interrupts. */ error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_ENABLE_INTR); return (error); @@ -1518,6 +1598,15 @@ athn_usb_intr(struct usbd_xfer *xfer, vo DPRINTF(("intr status=%d\n", status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(usc->rx_intr_pipe); + else if (status == USBD_IOERROR) { + /* + * The device has gone away. If async commands are + * pending or running ensure the device dies ASAP + * and any blocked processes are woken up. + */ + if (usc->cmdq.queued > 0) + usbd_deactivate(usc->sc_udev); + } return; } usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); @@ -1722,6 +1811,8 @@ athn_usb_rxeof(struct usbd_xfer *xfer, v { struct athn_usb_rx_data *data = priv; struct athn_usb_softc *usc = data->sc; + struct athn_softc *sc = &usc->sc_sc; + struct ifnet *ifp = &sc->sc_ic.ic_if; struct athn_usb_rx_stream *stream = &usc->rx_stream; uint8_t *buf = data->buf; struct ar_stream_hdr *hdr; @@ -1790,6 +1881,10 @@ athn_usb_rxeof(struct usbd_xfer *xfer, v } } else /* Drop frames larger than MCLBYTES. */ m = NULL; + + if (m == NULL) + ifp->if_ierrors++; + /* * NB: m can be NULL, in which case the next pktlen bytes * will be discarded from the Rx stream. @@ -2048,11 +2143,17 @@ int athn_usb_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct athn_softc *sc = ifp->if_softc; + struct athn_usb_softc *usc = (struct athn_usb_softc *)sc; struct ieee80211com *ic = &sc->sc_ic; struct ifaddr *ifa; struct ifreq *ifr; int s, error = 0; + if (usbd_is_dying(usc->sc_udev)) + return ENXIO; + + usbd_ref_incr(usc->sc_udev); + s = splnet(); switch (cmd) { @@ -2105,6 +2206,9 @@ athn_usb_ioctl(struct ifnet *ifp, u_long } } splx(s); + + usbd_ref_decr(usc->sc_udev); + return (error); } @@ -2214,8 +2318,12 @@ athn_usb_init(struct ifnet *ifp) DPRINTF(("creating default node\n")); error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_CREATE, &sta, sizeof(sta), NULL); - if (error != 0) + if (error != 0) { + printf("%s: could not add default node (error %d)\n", + usc->usb_dev.dv_xname, error); goto fail; + } + usc->nnodes++; /* Update target capabilities. */ memset(&hic, 0, sizeof(hic)); @@ -2298,6 +2406,7 @@ athn_usb_stop(struct ifnet *ifp) sta_index = 0; (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE, &sta_index, sizeof(sta_index), NULL); + usc->nnodes--; (void)athn_usb_wmi_cmd(usc, AR_WMI_CMD_DISABLE_INTR); (void)athn_usb_wmi_cmd(usc, AR_WMI_CMD_DRAIN_TXQ_ALL); Index: if_athn_usb.h =================================================================== RCS file: /cvs/src/sys/dev/usb/if_athn_usb.h,v retrieving revision 1.4 diff -u -p -r1.4 if_athn_usb.h --- if_athn_usb.h 15 Apr 2013 09:23:01 -0000 1.4 +++ if_athn_usb.h 1 Mar 2015 02:32:35 -0000 @@ -458,4 +458,7 @@ struct athn_usb_softc { uint8_t ep_uapsd; uint8_t ep_mgmt; uint8_t ep_data[EDCA_NUM_AC]; + + /* Firmware cannot handle more than 8 STAs. */ + uint8_t nnodes; };