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;
 };

Reply via email to