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" <[email protected]> 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;
};