diff options
author | avos <avos@FreeBSD.org> | 2016-02-29 20:53:27 +0000 |
---|---|---|
committer | avos <avos@FreeBSD.org> | 2016-02-29 20:53:27 +0000 |
commit | a293ba5e900abb83fab328baae416236a5810892 (patch) | |
tree | aee5ccaa7c08b861c19e39465944a14358a2efb4 | |
parent | 61cdf21180ea3ae036ba2de85df6e101f7bc44bb (diff) | |
download | FreeBSD-src-a293ba5e900abb83fab328baae416236a5810892.zip FreeBSD-src-a293ba5e900abb83fab328baae416236a5810892.tar.gz |
net80211: split scan_task() (#3) (into scan_start() and
scan_curchan_task() functions)
(This part should fix the problem, described in
https://lists.freebsd.org/pipermail/freebsd-wireless/2016-January/006420.html)
- Rename ss_scan_task into ss_scan_start (better describes it's
current purpose)
- Utilize taskqueue_*_timeout() functions instead of current mechanism:
* reschedule scan_curchan_task() via taskqueue_enqueue_timeout()
for every 'maxdwell' msecs (will replace infinite loop + sleeping
for 'maxdwell' period via cv_wait());
* rerun the task immediately when an external event occurs
(instead of waking it up via cv_signal())
Also, use mtx_sleep() to wait for null frame transmission
(allows to drop conditional variable).
Tested with:
* Intel 3945BG, STA mode;
* RTL8188EU, STA mode.
Approved by: adrian (mentor)
Differential Revision: https://reviews.freebsd.org/D5145
-rw-r--r-- | sys/net80211/ieee80211_scan_sw.c | 203 |
1 files changed, 111 insertions, 92 deletions
diff --git a/sys/net80211/ieee80211_scan_sw.c b/sys/net80211/ieee80211_scan_sw.c index 0b92a8e..2f35f15 100644 --- a/sys/net80211/ieee80211_scan_sw.c +++ b/sys/net80211/ieee80211_scan_sw.c @@ -59,12 +59,12 @@ struct scan_state { #define ISCAN_DISCARD 0x0002 /* discard rx'd frames */ #define ISCAN_CANCEL 0x0004 /* cancel current scan */ #define ISCAN_ABORT 0x0008 /* end the scan immediately */ +#define ISCAN_RUNNING 0x0010 /* scan was started */ unsigned long ss_chanmindwell; /* min dwell on curchan */ unsigned long ss_scanend; /* time scan must stop */ u_int ss_duration; /* duration for next scan */ - struct task ss_scan_task; /* scan execution */ - struct cv ss_scan_cv; /* scan signal */ - struct callout ss_scan_timer; /* scan timer */ + struct task ss_scan_start; /* scan start */ + struct timeout_task ss_scan_curchan; /* scan execution */ }; #define SCAN_PRIVATE(ss) ((struct scan_state *) ss) @@ -99,7 +99,8 @@ struct scan_state { static void scan_curchan(struct ieee80211_scan_state *, unsigned long); static void scan_mindwell(struct ieee80211_scan_state *); static void scan_signal(void *); -static void scan_task(void *, int); +static void scan_start(void *, int); +static void scan_curchan_task(void *, int); static void scan_end(struct ieee80211_scan_state *, int); static void scan_done(struct ieee80211_scan_state *, int); @@ -115,8 +116,9 @@ ieee80211_swscan_detach(struct ieee80211com *ic) SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; scan_signal(ss); IEEE80211_UNLOCK(ic); - ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); - callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer); + ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_start); + taskqueue_drain_timeout(ic->ic_tq, + &SCAN_PRIVATE(ss)->ss_scan_curchan); KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scan still running")); @@ -238,7 +240,7 @@ ieee80211_swscan_start_scan_locked(const struct ieee80211_scanner *scan, ic->ic_flags |= IEEE80211_F_SCAN; /* Start scan task */ - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_start); } return 1; } else { @@ -413,7 +415,8 @@ ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan, ss->ss_maxdwell = duration; ic->ic_flags |= IEEE80211_F_SCAN; ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + ieee80211_runtask(ic, + &SCAN_PRIVATE(ss)->ss_scan_start); } else { /* XXX msg+stat */ } @@ -560,8 +563,8 @@ scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) IEEE80211_LOCK(vap->iv_ic); if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) ieee80211_probe_curchan(vap, 0); - callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, - maxdwell, scan_signal, ss); + taskqueue_enqueue_timeout(vap->iv_ic->ic_tq, + &SCAN_PRIVATE(ss)->ss_scan_curchan, maxdwell); IEEE80211_UNLOCK(vap->iv_ic); } @@ -569,9 +572,16 @@ static void scan_signal(void *arg) { struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; + struct scan_state *ss_priv = SCAN_PRIVATE(ss); + struct timeout_task *scan_task = &ss_priv->ss_scan_curchan; + struct ieee80211com *ic = ss->ss_ic; + + IEEE80211_LOCK_ASSERT(ic); - IEEE80211_LOCK_ASSERT(ss->ss_ic); - cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv); + if (ss_priv->ss_iflags & ISCAN_RUNNING) { + if (taskqueue_cancel_timeout(ic->ic_tq, scan_task, NULL) == 0) + taskqueue_enqueue_timeout(ic->ic_tq, scan_task, 0); + } } /* @@ -591,16 +601,13 @@ scan_mindwell(struct ieee80211_scan_state *ss) } static void -scan_task(void *arg, int pending) +scan_start(void *arg, int pending) { #define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD) struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; struct scan_state *ss_priv = SCAN_PRIVATE(ss); struct ieee80211vap *vap = ss->ss_vap; struct ieee80211com *ic = ss->ss_ic; - struct ieee80211_channel *chan; - unsigned long maxdwell; - int scandone = 0; IEEE80211_LOCK(ic); if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 || @@ -627,8 +634,8 @@ scan_task(void *arg, int pending) * to go out. * XXX Should use M_TXCB mechanism to eliminate this. */ - cv_timedwait(&ss_priv->ss_scan_cv, - IEEE80211_LOCK_OBJ(ic), msecs_to_ticks(1)); + mtx_sleep(vap, IEEE80211_LOCK_OBJ(ic), PCATCH, + "sta_ps", msecs_to_ticks(1)); if (ss_priv->ss_iflags & ISCAN_ABORT) { scan_done(ss, 0); return; @@ -641,90 +648,102 @@ scan_task(void *arg, int pending) /* XXX scan state can change! Re-validate scan state! */ IEEE80211_UNLOCK(ic); + ic->ic_scan_start(ic); /* notify driver */ - IEEE80211_LOCK(ic); - for (;;) { + scan_curchan_task(ss, 0); +} - scandone = (ss->ss_next >= ss->ss_last) || - (ss_priv->ss_iflags & ISCAN_CANCEL) != 0; +static void +scan_curchan_task(void *arg, int pending) +{ + struct ieee80211_scan_state *ss = arg; + struct scan_state *ss_priv = SCAN_PRIVATE(ss); + struct ieee80211vap *vap = ss->ss_vap; + struct ieee80211com *ic = ss->ss_ic; + struct ieee80211_channel *chan; + unsigned long maxdwell; + int scandone; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: loop start; scandone=%d\n", - __func__, - scandone); + IEEE80211_LOCK(ic); +end: + scandone = (ss->ss_next >= ss->ss_last) || + (ss_priv->ss_iflags & ISCAN_CANCEL) != 0; - if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) || - (ss_priv->ss_iflags & ISCAN_ABORT) || - time_after(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) { - scan_end(ss, scandone); - return; - } + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: loop start; scandone=%d\n", + __func__, + scandone); - chan = ss->ss_chans[ss->ss_next++]; + if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) || + (ss_priv->ss_iflags & ISCAN_ABORT) || + time_after(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) { + ss_priv->ss_iflags &= ~ISCAN_RUNNING; + scan_end(ss, scandone); + return; + } else + ss_priv->ss_iflags |= ISCAN_RUNNING; - /* - * Watch for truncation due to the scan end time. - */ - if (time_after(ticks + ss->ss_maxdwell, ss_priv->ss_scanend)) - maxdwell = ss_priv->ss_scanend - ticks; - else - maxdwell = ss->ss_maxdwell; + chan = ss->ss_chans[ss->ss_next++]; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n", - __func__, - ieee80211_chan2ieee(ic, ic->ic_curchan), - ieee80211_channel_type_char(ic->ic_curchan), - ieee80211_chan2ieee(ic, chan), - ieee80211_channel_type_char(chan), - (ss->ss_flags & IEEE80211_SCAN_ACTIVE) && - (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ? - "active" : "passive", - ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell)); + /* + * Watch for truncation due to the scan end time. + */ + if (time_after(ticks + ss->ss_maxdwell, ss_priv->ss_scanend)) + maxdwell = ss_priv->ss_scanend - ticks; + else + maxdwell = ss->ss_maxdwell; - /* - * Potentially change channel and phy mode. - */ - ic->ic_curchan = chan; - ic->ic_rt = ieee80211_get_ratetable(chan); - IEEE80211_UNLOCK(ic); - /* - * Perform the channel change and scan unlocked so the driver - * may sleep. Once set_channel returns the hardware has - * completed the channel change. - */ - ic->ic_set_channel(ic); - ieee80211_radiotap_chan_change(ic); + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n", + __func__, + ieee80211_chan2ieee(ic, ic->ic_curchan), + ieee80211_channel_type_char(ic->ic_curchan), + ieee80211_chan2ieee(ic, chan), + ieee80211_channel_type_char(chan), + (ss->ss_flags & IEEE80211_SCAN_ACTIVE) && + (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ? + "active" : "passive", + ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell)); - /* - * Scan curchan. Drivers for "intelligent hardware" - * override ic_scan_curchan to tell the device to do - * the work. Otherwise we manage the work outselves; - * sending a probe request (as needed), and arming the - * timeout to switch channels after maxdwell ticks. - * - * scan_curchan should only pause for the time required to - * prepare/initiate the hardware for the scan (if at all), the - * below condvar is used to sleep for the channels dwell time - * and allows it to be signalled for abort. - */ - ic->ic_scan_curchan(ss, maxdwell); - IEEE80211_LOCK(ic); + /* + * Potentially change channel and phy mode. + */ + ic->ic_curchan = chan; + ic->ic_rt = ieee80211_get_ratetable(chan); + IEEE80211_UNLOCK(ic); + /* + * Perform the channel change and scan unlocked so the driver + * may sleep. Once set_channel returns the hardware has + * completed the channel change. + */ + ic->ic_set_channel(ic); + ieee80211_radiotap_chan_change(ic); + + /* + * Scan curchan. Drivers for "intelligent hardware" + * override ic_scan_curchan to tell the device to do + * the work. Otherwise we manage the work ourselves; + * sending a probe request (as needed), and arming the + * timeout to switch channels after maxdwell ticks. + * + * scan_curchan should only pause for the time required to + * prepare/initiate the hardware for the scan (if at all). + */ + ic->ic_scan_curchan(ss, maxdwell); + IEEE80211_LOCK(ic); - /* XXX scan state can change! Re-validate scan state! */ + /* XXX scan state can change! Re-validate scan state! */ - ss_priv->ss_chanmindwell = ticks + ss->ss_mindwell; - /* clear mindwell lock and initial channel change flush */ - ss_priv->ss_iflags &= ~ISCAN_REP; + ss_priv->ss_chanmindwell = ticks + ss->ss_mindwell; + /* clear mindwell lock and initial channel change flush */ + ss_priv->ss_iflags &= ~ISCAN_REP; - if (ss_priv->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT)) - continue; + if (ss_priv->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT)) + goto end; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: waiting\n", __func__); - /* Wait to be signalled to scan the next channel */ - cv_wait(&ss_priv->ss_scan_cv, IEEE80211_LOCK_OBJ(ic)); - } + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: waiting\n", __func__); + IEEE80211_UNLOCK(ic); } static void @@ -803,7 +822,7 @@ scan_end(struct ieee80211_scan_state *ss, int scandone) vap->iv_stats.is_scan_passive++; ss->ss_ops->scan_restart(ss, vap); /* XXX? */ - ieee80211_runtask(ic, &ss_priv->ss_scan_task); + ieee80211_runtask(ic, &ss_priv->ss_scan_start); IEEE80211_UNLOCK(ic); return; } @@ -960,9 +979,9 @@ ieee80211_swscan_attach(struct ieee80211com *ic) ic->ic_scan = NULL; return; } - callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0); - cv_init(&ss->ss_scan_cv, "scan"); - TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss); + TASK_INIT(&ss->ss_scan_start, 0, scan_start, ss); + TIMEOUT_TASK_INIT(ic->ic_tq, &ss->ss_scan_curchan, 0, + scan_curchan_task, ss); ic->ic_scan = &ss->base; ss->base.ss_ic = ic; |