summaryrefslogtreecommitdiffstats
path: root/sys/dev/ipw
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2009-05-02 15:14:18 +0000
committerthompsa <thompsa@FreeBSD.org>2009-05-02 15:14:18 +0000
commited7c3176b96444dc82c6a07114013192611024f3 (patch)
tree46c2c9933cb1753f24ffd7c0096b2ba9074180d2 /sys/dev/ipw
parentb704e6092a4076e74c276c0d531447a8cb3bf6a6 (diff)
downloadFreeBSD-src-ed7c3176b96444dc82c6a07114013192611024f3.zip
FreeBSD-src-ed7c3176b96444dc82c6a07114013192611024f3.tar.gz
Create a taskqueue for each wireless interface which provides a serialised
sleepable context for net80211 driver callbacks. This removes the need for USB and firmware based drivers to roll their own code to defer the chip programming for state changes, scan requests, channel changes and mcast/promisc updates. When a driver callback completes the hardware state is now guaranteed to have been updated and is in sync with net80211 layer. This nukes around 1300 lines of code from the wireless device drivers making them more readable and less race prone. The net80211 layer has been updated as follows - all state/channel changes are serialised on the taskqueue. - ieee80211_new_state() always queues and can now be called from any context - scanning runs from a single taskq function and executes to completion. driver callbacks are synchronous so the channel, phy mode and rx filters are guaranteed to be set in hardware before probe request frames are transmitted. Help and contributions from Sam Leffler. Reviewed by: sam
Diffstat (limited to 'sys/dev/ipw')
-rw-r--r--sys/dev/ipw/if_ipw.c138
-rw-r--r--sys/dev/ipw/if_ipwvar.h8
2 files changed, 38 insertions, 108 deletions
diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c
index 5463f0a..9d67724 100644
--- a/sys/dev/ipw/if_ipw.c
+++ b/sys/dev/ipw/if_ipw.c
@@ -118,10 +118,6 @@ static void ipw_media_status(struct ifnet *, struct ifmediareq *);
static int ipw_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t);
static void ipw_rx_cmd_intr(struct ipw_softc *, struct ipw_soft_buf *);
-static void ipw_assocsuccess(void *, int);
-static void ipw_assocfailed(void *, int);
-static void ipw_scandone(void *, int);
-static void ipw_bmiss(void *, int);
static void ipw_rx_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
static void ipw_rx_data_intr(struct ipw_softc *, struct ipw_status *,
struct ipw_soft_bd *, struct ipw_soft_buf *);
@@ -147,8 +143,8 @@ static int ipw_reset(struct ipw_softc *);
static int ipw_load_ucode(struct ipw_softc *, const char *, int);
static int ipw_load_firmware(struct ipw_softc *, const char *, int);
static int ipw_config(struct ipw_softc *);
-static void ipw_assoc_task(void *, int);
-static void ipw_disassoc_task(void *, int);
+static void ipw_assoc(struct ieee80211com *, struct ieee80211vap *);
+static void ipw_disassoc(struct ieee80211com *, struct ieee80211vap *);
static void ipw_init_task(void *, int);
static void ipw_init(void *);
static void ipw_init_locked(struct ipw_softc *);
@@ -166,7 +162,6 @@ static void ipw_read_mem_1(struct ipw_softc *, bus_size_t, uint8_t *,
#endif
static void ipw_write_mem_1(struct ipw_softc *, bus_size_t,
const uint8_t *, bus_size_t);
-static void ipw_scan_task(void *, int);
static int ipw_scan(struct ipw_softc *);
static void ipw_scan_start(struct ieee80211com *);
static void ipw_scan_end(struct ieee80211com *);
@@ -239,8 +234,6 @@ ipw_attach(device_t dev)
MTX_DEF | MTX_RECURSE);
TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc);
- TASK_INIT(&sc->sc_scan_task, 0, ipw_scan_task, sc);
- TASK_INIT(&sc->sc_bmiss_task, 0, ipw_bmiss, sc);
callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0);
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
@@ -417,9 +410,7 @@ ipw_detach(device_t dev)
ieee80211_ifdetach(ic);
callout_drain(&sc->sc_wdtimer);
- taskqueue_drain(taskqueue_swi, &sc->sc_init_task);
- taskqueue_drain(taskqueue_swi, &sc->sc_scan_task);
- taskqueue_drain(taskqueue_swi, &sc->sc_bmiss_task);
+ ieee80211_draintask(ic, &sc->sc_init_task);
ipw_release(sc);
@@ -511,12 +502,6 @@ ipw_vap_create(struct ieee80211com *ic,
return NULL;
vap = &ivp->vap;
- TASK_INIT(&ivp->assoc_task, 0, ipw_assoc_task, vap);
- TASK_INIT(&ivp->disassoc_task, 0, ipw_disassoc_task, vap);
- TASK_INIT(&ivp->assoc_success_task, 0, ipw_assocsuccess, vap);
- TASK_INIT(&ivp->assoc_failed_task, 0, ipw_assocfailed, vap);
- TASK_INIT(&ivp->scandone_task, 0, ipw_scandone, vap);
-
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
/* override with driver methods */
ivp->newstate = vap->iv_newstate;
@@ -894,11 +879,15 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
struct ieee80211com *ic = vap->iv_ic;
struct ifnet *ifp = ic->ic_ifp;
struct ipw_softc *sc = ifp->if_softc;
+ enum ieee80211_state ostate;
DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__,
ieee80211_state_name[vap->iv_state],
ieee80211_state_name[nstate], sc->flags));
+ ostate = vap->iv_state;
+ IEEE80211_UNLOCK(ic);
+
switch (nstate) {
case IEEE80211_S_RUN:
if (ic->ic_opmode == IEEE80211_M_IBSS) {
@@ -910,39 +899,33 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* AUTH -> RUN transition and we want to do nothing.
* This is all totally bogus and needs to be redone.
*/
- if (vap->iv_state == IEEE80211_S_SCAN) {
- taskqueue_enqueue(taskqueue_swi,
- &IPW_VAP(vap)->assoc_task);
- return EINPROGRESS;
- }
+ if (ostate == IEEE80211_S_SCAN)
+ ipw_assoc(ic, vap);
}
break;
case IEEE80211_S_INIT:
if (sc->flags & IPW_FLAG_ASSOCIATED)
- taskqueue_enqueue(taskqueue_swi,
- &IPW_VAP(vap)->disassoc_task);
+ ipw_disassoc(ic, vap);
break;
case IEEE80211_S_AUTH:
- taskqueue_enqueue(taskqueue_swi, &IPW_VAP(vap)->assoc_task);
- return EINPROGRESS;
+ ipw_assoc(ic, vap);
+ break;
case IEEE80211_S_ASSOC:
/*
* If we are not transitioning from AUTH the resend the
* association request.
*/
- if (vap->iv_state != IEEE80211_S_AUTH) {
- taskqueue_enqueue(taskqueue_swi,
- &IPW_VAP(vap)->assoc_task);
- return EINPROGRESS;
- }
+ if (ostate != IEEE80211_S_AUTH)
+ ipw_assoc(ic, vap);
break;
default:
break;
}
+ IEEE80211_LOCK(ic);
return ivp->newstate(vap, nstate, arg);
}
@@ -1020,38 +1003,6 @@ ipw_rx_cmd_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
}
static void
-ipw_assocsuccess(void *arg, int npending)
-{
- struct ieee80211vap *vap = arg;
-
- ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
-}
-
-static void
-ipw_assocfailed(void *arg, int npending)
-{
- struct ieee80211vap *vap = arg;
-
- ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
-}
-
-static void
-ipw_scandone(void *arg, int npending)
-{
- struct ieee80211vap *vap = arg;
-
- ieee80211_scan_done(vap);
-}
-
-static void
-ipw_bmiss(void *arg, int npending)
-{
- struct ieee80211com *ic = arg;
-
- ieee80211_beacon_miss(ic);
-}
-
-static void
ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
{
#define IEEESTATE(vap) ieee80211_state_name[vap->iv_state]
@@ -1076,8 +1027,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
}
sc->flags &= ~IPW_FLAG_ASSOCIATING;
sc->flags |= IPW_FLAG_ASSOCIATED;
- taskqueue_enqueue(taskqueue_swi,
- &IPW_VAP(vap)->assoc_success_task);
+ ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
break;
case IPW_STATE_SCANNING:
@@ -1091,7 +1041,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
*/
if (sc->flags & IPW_FLAG_ASSOCIATED) {
/* XXX probably need to issue disassoc to fw */
- taskqueue_enqueue(taskqueue_swi, &sc->sc_bmiss_task);
+ ieee80211_beacon_miss(ic);
}
break;
@@ -1110,8 +1060,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
break;
}
if (sc->flags & IPW_FLAG_SCANNING) {
- taskqueue_enqueue(taskqueue_swi,
- &IPW_VAP(vap)->scandone_task);
+ ieee80211_scan_done(vap);
sc->flags &= ~IPW_FLAG_SCANNING;
sc->sc_scan_timer = 0;
}
@@ -1122,8 +1071,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
IEEESTATE(vap), sc->flags));
sc->flags &= ~(IPW_FLAG_ASSOCIATING | IPW_FLAG_ASSOCIATED);
if (vap->iv_state == IEEE80211_S_RUN)
- taskqueue_enqueue(taskqueue_swi,
- &IPW_VAP(vap)->assoc_failed_task);
+ ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
break;
case IPW_STATE_DISABLED:
@@ -1432,6 +1380,16 @@ ipw_tx_intr(struct ipw_softc *sc)
}
static void
+ipw_fatal_error_intr(struct ipw_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ device_printf(sc->sc_dev, "firmware error\n");
+ ieee80211_runtask(ic, &sc->sc_init_task);
+}
+
+static void
ipw_intr(void *arg)
{
struct ipw_softc *sc = arg;
@@ -1440,10 +1398,9 @@ ipw_intr(void *arg)
IPW_LOCK(sc);
- if ((r = CSR_READ_4(sc, IPW_CSR_INTR)) == 0 || r == 0xffffffff) {
- IPW_UNLOCK(sc);
- return;
- }
+ r = CSR_READ_4(sc, IPW_CSR_INTR);
+ if (r == 0 || r == 0xffffffff)
+ goto done;
/* disable interrupts */
CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
@@ -1452,9 +1409,8 @@ ipw_intr(void *arg)
CSR_WRITE_4(sc, IPW_CSR_INTR, r);
if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) {
- device_printf(sc->sc_dev, "firmware error\n");
- taskqueue_enqueue(taskqueue_swi, &sc->sc_init_task);
- r = 0; /* don't process more interrupts */
+ ipw_fatal_error_intr(sc);
+ goto done;
}
if (r & IPW_INTR_FW_INIT_DONE)
@@ -1468,7 +1424,7 @@ ipw_intr(void *arg)
/* re-enable interrupts */
CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK);
-
+done:
IPW_UNLOCK(sc);
}
@@ -2181,20 +2137,6 @@ ipw_setscanopts(struct ipw_softc *sc, uint32_t chanmask, uint32_t flags)
return ipw_cmd(sc, IPW_CMD_SET_SCAN_OPTIONS, &opts, sizeof(opts));
}
-/*
- * Handler for sc_scan_task. This is a simple wrapper around ipw_scan().
- */
-static void
-ipw_scan_task(void *context, int pending)
-{
- struct ipw_softc *sc = context;
- IPW_LOCK_DECL;
-
- IPW_LOCK(sc);
- ipw_scan(sc);
- IPW_UNLOCK(sc);
-}
-
static int
ipw_scan(struct ipw_softc *sc)
{
@@ -2258,11 +2200,9 @@ ipw_setchannel(struct ipw_softc *sc, struct ieee80211_channel *chan)
}
static void
-ipw_assoc_task(void *context, int pending)
+ipw_assoc(struct ieee80211com *ic, struct ieee80211vap *vap)
{
- struct ieee80211vap *vap = context;
struct ifnet *ifp = vap->iv_ic->ic_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211_node *ni = vap->iv_bss;
struct ipw_security security;
@@ -2353,9 +2293,8 @@ done:
}
static void
-ipw_disassoc_task(void *context, int pending)
+ipw_disassoc(struct ieee80211com *ic, struct ieee80211vap *vap)
{
- struct ieee80211vap *vap = context;
struct ifnet *ifp = vap->iv_ic->ic_ifp;
struct ieee80211_node *ni = vap->iv_bss;
struct ipw_softc *sc = ifp->if_softc;
@@ -2729,8 +2668,7 @@ ipw_scan_start(struct ieee80211com *ic)
IPW_LOCK_DECL;
IPW_LOCK(sc);
- if (!(sc->flags & IPW_FLAG_SCANNING))
- taskqueue_enqueue(taskqueue_swi, &sc->sc_scan_task);
+ ipw_scan(sc);
IPW_UNLOCK(sc);
}
diff --git a/sys/dev/ipw/if_ipwvar.h b/sys/dev/ipw/if_ipwvar.h
index de35019..24fb8e8 100644
--- a/sys/dev/ipw/if_ipwvar.h
+++ b/sys/dev/ipw/if_ipwvar.h
@@ -78,11 +78,6 @@ struct ipw_tx_radiotap_header {
struct ipw_vap {
struct ieee80211vap vap;
- struct task assoc_task;
- struct task disassoc_task;
- struct task assoc_success_task;
- struct task assoc_failed_task;
- struct task scandone_task;
int (*newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -95,9 +90,6 @@ struct ipw_softc {
struct mtx sc_mtx;
struct task sc_init_task;
- struct task sc_scan_task;
- struct task sc_chan_task;
- struct task sc_bmiss_task;
struct callout sc_wdtimer; /* watchdog timer */
uint32_t flags;
OpenPOWER on IntegriCloud