svn commit: r296232 - head/sys/net80211

Andriy Voskoboinyk avos at FreeBSD.org
Mon Feb 29 20:53:29 UTC 2016


Author: avos
Date: Mon Feb 29 20:53:27 2016
New Revision: 296232
URL: https://svnweb.freebsd.org/changeset/base/296232

Log:
  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

Modified:
  head/sys/net80211/ieee80211_scan_sw.c

Modified: head/sys/net80211/ieee80211_scan_sw.c
==============================================================================
--- head/sys/net80211/ieee80211_scan_sw.c	Mon Feb 29 20:47:07 2016	(r296231)
+++ head/sys/net80211/ieee80211_scan_sw.c	Mon Feb 29 20:53:27 2016	(r296232)
@@ -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 ieee80211
 		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
 			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 ie
 			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
 	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_stat
 }
 
 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 */
+
+	scan_curchan_task(ss, 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_LOCK(ic);
+end:
+	scandone = (ss->ss_next >= ss->ss_last) ||
+	    (ss_priv->ss_iflags & ISCAN_CANCEL) != 0;
 
-	for (;;) {
+	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+	    "%s: loop start; scandone=%d\n",
+	    __func__,
+	    scandone);
 
-		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)) {
+		ss_priv->ss_iflags &= ~ISCAN_RUNNING;
+		scan_end(ss, scandone);
+		return;
+	} else
+		ss_priv->ss_iflags |= ISCAN_RUNNING;
 
-		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)) {
-			scan_end(ss, scandone);
-			return;
-		}
+	/*
+	 * 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 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);
 
-		/*
-		 * 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);
+	/* XXX scan state can change! Re-validate scan state! */
 
-		/*
-		 * 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);
+	ss_priv->ss_chanmindwell = ticks + ss->ss_mindwell;
+	/* clear mindwell lock and initial channel change flush */
+	ss_priv->ss_iflags &= ~ISCAN_REP;
 
-		/* XXX scan state can change! Re-validate scan state! */
+	if (ss_priv->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT))
+		goto end;
 
-		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;
-
-		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
 			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 ieee80211
 		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;


More information about the svn-src-head mailing list