* Clean up a few snafus and adjust the names for some procedures.
* Flesh out README.DRAGONFLY
wlan_global_serializer. Normally all wireless base drivers also
use this serializer to avoid deadlocks.
-modevent ieee80211_dragonfly.h
- search for DECLARE_MODULE
+STEP 1:
-sysctl search for SYSCTL_HANDLER_ARGS
+ When porting a new wireless low level device be sure to remove all
+ *LOCK* (upper case) macro calls because the whole point of this is
+ to redo the locking with our own.
-eventhandler search for EVENTHANDLER_REGISTER
+STEP 2:
-taskq search for TASK_INIT
+ All border crossings (module loader, sysctl, eventhandlers, tasks,
+ callouts, ifnet, devmethod, and interrupt handlers) must be properly
+ wrapped with wlan_serialize_enter() and wlan_serialize_exit(). Pay
+ careful attention to any early return()s that might break your locks.
-callout search for callout_reset
- search for callout_stop to deal with
- potential deadlock issues
+modevent search for DECLARE_MODULE and MOD_LOAD and friends.
+
+sysctl search for SYSCTL_HANDLER_ARGS.
+
+ Generally speaking sysctls should be rewritten to use
+ a flow-through model (see ath for an example) as most
+ of them currently use a badly designed early-termination
+ model.
+
+eventhandler search for EVENTHANDLER_REGISTER.
+
+taskq search for TASK_INIT.
+
+ All taskq callback procedures should be renamed to
+ "<blah>_task".
+
+callout search for callout_reset.
+
+ search for callout_stop to deal with potential deadlock
+ issues.
+
+ All callout callback procedures should be renamed to
+ "<blah>_callout"
ifnet wlan/ieee80211.c
- Set if_serializer to &wlan_global_serializer. There are
- a few places where if_ioctl is set to NULL and then later
- restored. It is unclear why this is being done.
+ This is handled by ieee80211_ifattach() where we set
+ the serializer to &wlan_global_serializer when we
+ call ether_ifattach(). The low level drivers should
+ just be calling ieee80211_ifattach() so no additional
+ work should be needed here.
-ifnet, interrupt, devmethod, copyin/copyout
+devmethod Search for DEVMETHOD (low level drivers). Typically
+ this is in the *_pci.c file. The attach function might
+ present an issue where you may wish to release the
+ serializer across the main DMA area allocations.
+ see ath.
-ieee80211_ioctl()
+interrupt Search for bus_setup_intr().
+
+ Typically we pass the &wlan_global_serializer to
+ bus_setup_intr(). The interrupt callback is thus
+ serialized automatically.
+ieee80211_ioctl()
This is called directly from the wlan's ifp->if_ioctl and
also from various wireless drivers. This function expects
the serializer to already be acquired.
The kernel will acquire if_serializer when making
ifp->if_ioctl() calls.
+
+Low level device drivers
+ Don't forget that low level device drivers such as ath
+ have callouts, taskq, sysctl, and other elements also!
+
+ Look for old calls to ifnet_serialize*() and remove,
+ in addition to the various LOCK macros.
*/
extern struct lwkt_serialize wlan_global_serializer;
-void wlan_serialize_enter(void);
-void wlan_serialize_exit(void);
+#define wlan_serialize_enter() _wlan_serialize_enter(__FUNCTION__)
+#define wlan_serialize_exit() _wlan_serialize_exit(__FUNCTION__)
+void _wlan_serialize_enter(const char *funcname);
+void _wlan_serialize_exit(const char *funcname);
int wlan_serialize_sleep(void *ident, int flags, const char *wmesg, int timo);
static __inline void
error = 0; \
break; \
case MOD_UNLOAD: \
+ error = 0; \
if (nrefs) { \
kprintf("wlan_##name: still in use (%u " \
"dynamic refs)\n", \
nrefs); \
- return EBUSY; \
- } \
- if (type == MOD_UNLOAD) { \
+ error = EBUSY; \
+ } else if (type == MOD_UNLOAD) { \
SET_FOREACH(iter, policy##_set) { \
f = (void*) *iter; \
f(type); \
} \
} \
- error = 0; \
break; \
default: \
error = EINVAL; \
static void \
name##_modevent(int type) \
{ \
- wlan_serialize_enter(); \
+ /* wlan already serialized! */ \
if (type == MOD_LOAD) \
ieee80211_crypto_register(&name); \
else \
ieee80211_crypto_unregister(&name); \
- wlan_serialize_exit(); \
} \
TEXT_SET(crypto##_set, name##_modevent)
static void \
name##_modevent(int type) \
{ \
- wlan_serialize_enter(); \
+ /* wlan already serialized! */ \
if (type == MOD_LOAD) \
ieee80211_scanner_register(alg, &v); \
else \
ieee80211_scanner_unregister(alg, &v); \
- wlan_serialize_exit(); \
} \
TEXT_SET(scanner_set, name##_modevent); \
static void \
alg##_modevent(int type) \
{ \
- wlan_serialize_enter(); \
+ /* wlan already serialized! */ \
if (type == MOD_LOAD) \
ieee80211_aclator_register(&alg); \
else \
ieee80211_aclator_unregister(&alg); \
- wlan_serialize_exit(); \
} \
TEXT_SET(acl_set, alg##_modevent); \
static void \
name##_modevent(int type) \
{ \
- wlan_serialize_enter(); \
+ /* wlan already serialized! */ \
if (type == MOD_LOAD) \
ieee80211_authenticator_register(alg, &v); \
else \
ieee80211_authenticator_unregister(alg); \
- wlan_serialize_exit(); \
} \
TEXT_SET(auth_set, name##_modevent)
static void \
alg##_modevent(int type) \
{ \
- wlan_serialize_enter(); \
+ /* wlan already serialized! */ \
if (type == MOD_LOAD) \
ieee80211_ratectl_register(alg, &v); \
else \
ieee80211_ratectl_unregister(alg); \
- wlan_serialize_exit(); \
} \
TEXT_SET(ratectl##_set, alg##_modevent)
return ENOMEM;
}
if_initname(ifp, name, unit);
- ifp->if_serializer = &wlan_global_serializer;
ifp->if_softc = vap; /* back pointer */
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
ifp->if_start = ieee80211_start;
if (maxrate)
ifp->if_baudrate = IF_Mbps(maxrate);
- ether_ifattach(ifp, vap->iv_myaddr, NULL);
+ ether_ifattach(ifp, vap->iv_myaddr, &wlan_global_serializer);
if (vap->iv_opmode == IEEE80211_M_MONITOR) {
/* NB: disallow transmit */
#ifdef __FreeBSD__
/*
* Flush any deferred vap tasks.
*/
+ wlan_assert_serialized();
+ wlan_serialize_exit(); /* exit to block */
ieee80211_draintask(ic, &vap->iv_nstate_task);
ieee80211_draintask(ic, &vap->iv_swbmiss_task);
+ wlan_serialize_enter(); /* then reenter */
#ifdef __FreeBSD__
/* XXX band-aid until ifnet handles this for us */
ic->ic_vap_delete(vap);
}
+const char *wlan_last_enter_func;
+const char *wlan_last_exit_func;
/*
* These serializer functions are used by wlan and all drivers.
*/
void
-wlan_serialize_enter(void)
+_wlan_serialize_enter(const char *funcname)
{
lwkt_serialize_enter(&wlan_global_serializer);
+ wlan_last_enter_func = funcname;
}
void
-wlan_serialize_exit(void)
+_wlan_serialize_exit(const char *funcname)
{
lwkt_serialize_exit(&wlan_global_serializer);
+ wlan_last_exit_func = funcname;
}
int
static eventhandler_tag wlan_ifllevent;
static void
-bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
+bpf_track_event(void *arg, struct ifnet *ifp, int dlt, int attach)
{
/* NB: identify vap's by if_start */
}
static void
-wlan_iflladdr(void *arg __unused, struct ifnet *ifp)
+wlan_iflladdr_event(void *arg __unused, struct ifnet *ifp)
{
struct ieee80211com *ic = ifp->if_l2com;
struct ieee80211vap *vap, *next;
if (bootverbose)
kprintf("wlan: <802.11 Link Layer>\n");
wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
- bpf_track, 0,
+ bpf_track_event, 0,
EVENTHANDLER_PRI_ANY);
if (wlan_bpfevent == NULL) {
error = ENOMEM;
break;
}
wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
- wlan_iflladdr, NULL,
+ wlan_iflladdr_event, NULL,
EVENTHANDLER_PRI_ANY);
if (wlan_ifllevent == NULL) {
EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
return 0;
}
-#ifdef IEEE80211_DEBUG
+/*
+ * Modules may be compiled with debugging even if wlan isn't
+ */
+/*#ifdef IEEE80211_DEBUG*/
+#if 1
/*
* Debugging support.
*/
void
ieee80211_waitfor_parent(struct ieee80211com *ic)
{
- wlan_serialize_exit();
+ print_backtrace(-1);
+ wlan_assert_serialized();
+ wlan_serialize_exit(); /* exit to block */
taskqueue_block(ic->ic_tq);
ieee80211_draintask(ic, &ic->ic_parent_task);
ieee80211_draintask(ic, &ic->ic_mcast_task);
ieee80211_draintask(ic, &ic->ic_chan_task);
ieee80211_draintask(ic, &ic->ic_bmiss_task);
taskqueue_unblock(ic->ic_tq);
- wlan_serialize_enter();
+ wlan_serialize_enter(); /* then re-enter */
}
/*
ss->ss_ops->scan_restart(ss, vap); /* XXX? */
ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
- return;
+ goto done2;
}
/* past here, scandone is ``true'' if not in bg mode */
}
SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT);
ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
+done2:
wlan_serialize_exit();
#undef ISCAN_REP
}