urtwn driver fixes - missing include, free node references, shut down xfers first

* include opt_wlan.h like a good little wlan driver;
* add a function to free the mbufq /and/ the node references on it, or we will leak
  said node references;
* free the mbufq upon NIC shutdown otherwise we may end up with a full list that
  we never begin transmit work on, and thus never drain it;
* .. which frees it upon NIC detach too;
* ensure urtwn_start() gets called after the completion of frame TX even if the
  pending queue is empty, otherwise transmit will stall.  It's highly unlikely that
  the usb tx queue would be empty whilst the incoming send queue is full, but hey,
  who knows.

This passes some iperf testing with and without the NIC being actively removed during
said active iperf test.

Tested:

* urtwn0: MAC/BB RTL8188EU, RF 6052 1T1R ; STA mode
This commit is contained in:
Adrian Chadd 2015-09-29 05:03:24 +00:00
parent 024223535f
commit 24c2763fb1

View File

@ -24,6 +24,8 @@ __FBSDID("$FreeBSD$");
* Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU.
*/
#include "opt_wlan.h"
#include <sys/param.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
@ -169,6 +171,7 @@ static device_detach_t urtwn_detach;
static usb_callback_t urtwn_bulk_tx_callback;
static usb_callback_t urtwn_bulk_rx_callback;
static void urtwn_drain_mbufq(struct urtwn_softc *sc);
static usb_error_t urtwn_do_request(struct urtwn_softc *,
struct usb_device_request *, void *);
static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *,
@ -467,6 +470,20 @@ detach:
return (ENXIO); /* failure */
}
static void
urtwn_drain_mbufq(struct urtwn_softc *sc)
{
struct mbuf *m;
struct ieee80211_node *ni;
URTWN_ASSERT_LOCKED(sc);
while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
m->m_pkthdr.rcvif = NULL;
ieee80211_free_node(ni);
m_freem(m);
}
}
static int
urtwn_detach(device_t self)
{
@ -482,6 +499,9 @@ urtwn_detach(device_t self)
callout_drain(&sc->sc_watchdog_ch);
/* stop all USB transfers */
usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
/* Prevent further allocations from RX/TX data lists. */
URTWN_LOCK(sc);
STAILQ_INIT(&sc->sc_tx_active);
@ -502,10 +522,7 @@ urtwn_detach(device_t self)
urtwn_free_rx_list(sc);
URTWN_UNLOCK(sc);
/* stop all USB transfers */
usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
ieee80211_ifdetach(ic);
mbufq_drain(&sc->sc_snd);
mtx_destroy(&sc->sc_mtx);
return (0);
@ -879,13 +896,12 @@ tr_setup:
data = STAILQ_FIRST(&sc->sc_tx_pending);
if (data == NULL) {
DPRINTF("%s: empty pending queue\n", __func__);
return;
goto finish;
}
STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
usbd_transfer_submit(xfer);
urtwn_start(sc);
break;
default:
data = STAILQ_FIRST(&sc->sc_tx_active);
@ -903,6 +919,9 @@ tr_setup:
}
break;
}
finish:
/* Kick-start more transmit */
urtwn_start(sc);
}
static struct urtwn_data *
@ -1778,7 +1797,6 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni,
device_printf(sc->sc_dev,
"ieee80211_crypto_encap returns NULL.\n");
/* XXX we don't expect the fragmented frames */
m_freem(m0);
return (ENOBUFS);
}
@ -1931,6 +1949,7 @@ urtwn_start(struct urtwn_softc *sc)
if_inc_counter(ni->ni_vap->iv_ifp,
IFCOUNTER_OERRORS, 1);
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
m_freem(m);
ieee80211_free_node(ni);
break;
}
@ -3417,6 +3436,8 @@ urtwn_stop(struct urtwn_softc *sc)
sc->sc_flags &= ~URTWN_RUNNING;
callout_stop(&sc->sc_watchdog_ch);
urtwn_abort_xfers(sc);
urtwn_drain_mbufq(sc);
}
static void
@ -3455,14 +3476,15 @@ urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
}
if (urtwn_tx_start(sc, ni, m, bf) != 0) {
m_freem(m);
ieee80211_free_node(ni);
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
URTWN_UNLOCK(sc);
return (EIO);
}
sc->sc_txtimer = 5;
URTWN_UNLOCK(sc);
sc->sc_txtimer = 5;
return (0);
}