From nobody@FreeBSD.org  Tue Mar 20 23:58:28 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 96FFF1065677
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 20 Mar 2012 23:58:28 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 824158FC1F
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 20 Mar 2012 23:58:28 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q2KNwSJE046093
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 20 Mar 2012 23:58:28 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id q2KNwSnA046092;
	Tue, 20 Mar 2012 23:58:28 GMT
	(envelope-from nobody)
Message-Id: <201203202358.q2KNwSnA046092@red.freebsd.org>
Date: Tue, 20 Mar 2012 23:58:28 GMT
From: Adrian Chadd <adrian@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [net80211] [ath] initial switch to HT40 isn't causing a hardware channel change call
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         166286
>Category:       kern
>Synopsis:       [net80211] [ath] initial switch to HT40 isn't causing a hardware channel change call
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-wireless
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Mar 21 00:00:28 UTC 2012
>Closed-Date:    
>Last-Modified:  Sun Mar 25 03:20:15 UTC 2012
>Originator:     Adrian Chadd
>Release:        9.0-RELEASE i386, with -HEAD net80211/ath
>Organization:
>Environment:
>Description:

I've been seeing issues with TX failing.

Mar 20 16:45:39 marilyn kernel: wlan0: sta_newstate: AUTH -> ASSOC (0)
Mar 20 16:45:39 marilyn kernel: [101308] ath0: ath_txq_update: Q1 qflags 0xf aifs 3 cwmin 15 cwmax 1023 burstTime 0
Mar 20 16:45:39 marilyn kernel: [101308] ath0: ath_txq_update: Q0 qflags 0xf aifs 7 cwmin 15 cwmax 1023 burstTime 0
Mar 20 16:45:39 marilyn kernel: [101308] ath0: ath_txq_update: Q2 qflags 0xf aifs 2 cwmin 7 cwmax 15 burstTime 3008
Mar 20 16:45:39 marilyn kernel: [101308] ath0: ath_txq_update: Q3 qflags 0xf aifs 2 cwmin 3 cwmax 7 burstTime 1504
Mar 20 16:45:39 marilyn kernel: wlan0: [00:24:6c:04:f0:79] switch station to HT20 channel 5200/0x210140
Mar 20 16:45:39 marilyn kernel: [101308] ath0: ath_setslottime: chan 5200 MHz flags 0x200140 short slot, 9 usec
Mar 20 16:45:39 marilyn kernel: wlan0: [00:24:6c:04:f0:79] assoc success at aid 3: short preamble, short slot time, QoS, HT20 (+AMPDU)
Mar 20 16:45:39 marilyn kernel: wlan0: ieee80211_new_state_locked: ASSOC -> RUN (nrunning 0 nscanning 0)
Mar 20 16:45:39 marilyn kernel: wlan0: ieee80211_newstate_cb: ASSOC -> RUN arg 16
Mar 20 16:45:39 marilyn kernel: wlan0: sta_newstate: ASSOC -> RUN (16)
Mar 20 16:45:39 marilyn kernel: wlan0: link state changed to UP
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_chan_set: 40 (5200 MHz, flags 0x210140)
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_stoprecv: rx queue 0x384100c0, link 0xe9a20060
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_stoptxdma: tx queue [9] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [0] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [1] 0xe92e3c0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [2] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [3] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [8] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_stoptxdma: tx queue [9] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [0] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [1] 0xe92e3c0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [2] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [3] 0, link 0
Mar 20 16:45:39 marilyn kernel: [101309] ath0: ath_tx_stopdma: tx queue [8] 0, link 0
Mar 20 16:45:39 marilyn kernel: ar5416Set11nRegs: chan isht40=0, isht40d=0, isht40u=0, phymode=0x3c0, macmode=0
Mar 20 16:45:39 marilyn kernel: ar5416PerCalibrationN: NF calibration didn't finish; delaying CCA
Mar 20 16:45:39 marilyn kernel: wlan0: [00:24:6c:04:f0:79] switch station to HT40 channel 5200/0x240140

>How-To-Repeat:
This may be AP specific/dependent. I've not seen this when associating to many work (atheros) or home (freebsd) APs. But this particular one, for whatever reason, is exhibiting this issue.

This is on an open access point, rather than one protected by WEP/WPA.

# ifconfig wlan0 create wlandev ath0 ssid <SSID> -bgscan up

It then shows up in ifconfig as a ht40- AP.

xmit debugging (sysctl dev.ath.0.debug=0x3) shows that the frames are being TXed with the HT2040 bit set to 1, thus the frame is trying to go out in 40MHz mode. However, the hardware is configured for 20MHz operation:

* AR_PHY_TURBO doesn't have AR_PHY_FC_DYN2040_EN set;
* AR_2040_MODE is 0, so the pri/ext RX_CLEAR line isn't being programmed in.

Thus any TX will fail, as the rate control code currently transmits _only_ 40MHz frames at this point. Legacy frames will succeed however as they are always transmitted at 20MHz.

A manual scan fixes the issue. A background scan also fixes the issue and likely hid this brokenness in the past as once the background scan completes, the hardware is re-initialised into 40MHz mode.

>Fix:
I'm not sure yet. I need to add some thread debugging to net80211 to see which thread(s) are doing the HT update. It may be one SMP race where the HT40 IE is parsed in another thread and the channel change completes before the IE is parsed and updated.

In any case, I do think it's a net80211 issue, as it likely is missing a call to ic_chan_set() after the operational mode change.


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-wireless 
Responsible-Changed-By: adrian 
Responsible-Changed-When: Wed Mar 21 00:13:04 UTC 2012 
Responsible-Changed-Why:  
assign to maintainer. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=166286 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/166286: commit references a PR
Date: Sun, 25 Mar 2012 03:12:08 +0000 (UTC)

 Author: adrian
 Date: Sun Mar 25 03:11:57 2012
 New Revision: 233452
 URL: http://svn.freebsd.org/changeset/base/233452
 
 Log:
   Create a new task to handle 802.11n channel width changes.
   
   Currently, a channel width change updates the 802.11n HT info data in
   net80211 but it doesn't trigger any device changes.  So the device
   driver may decide that HT40 frames can be transmitted but the last
   device channel set only had HT20 set.
   
   Now, a task is scheduled so a hardware reset or change isn't done
   during any active ongoing RX. It also means that it's serialised
   with the other task operations (eg channel change.)
   
   This isn't the final incantation of this work, see below.
   
   For now, any unmodified drivers will simply receive a channel
   change log entry.  A subsequent patch to ath(4) will introduce
   some basic channel change handling (by resetting the NIC.)
   Other NICs may need to update their rate control information.
   
   TODO:
   
   * There's still a small window at the present moment where the
     channel width has been updated but the task hasn't been fired.
     The final version of this should likely pass in a channel width
     field to the driver and let the driver atomically do whatever
     it needs to before changing the channel.
   
   PR:		kern/166286
 
 Modified:
   head/sys/net80211/ieee80211.c
   head/sys/net80211/ieee80211_ht.c
   head/sys/net80211/ieee80211_ht.h
   head/sys/net80211/ieee80211_node.c
   head/sys/net80211/ieee80211_node.h
   head/sys/net80211/ieee80211_proto.c
   head/sys/net80211/ieee80211_sta.c
   head/sys/net80211/ieee80211_var.h
 
 Modified: head/sys/net80211/ieee80211.c
 ==============================================================================
 --- head/sys/net80211/ieee80211.c	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211.c	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -256,6 +256,13 @@ null_input(struct ifnet *ifp, struct mbu
  	m_freem(m);
  }
  
 +static void
 +null_update_chw(struct ieee80211com *ic)
 +{
 +
 +	if_printf(ic->ic_ifp, "%s: need callback\n", __func__);
 +}
 +
  /*
   * Attach/setup the common net80211 state.  Called by
   * the driver on attach to prior to creating any vap's.
 @@ -287,6 +294,7 @@ ieee80211_ifattach(struct ieee80211com *
  
  	ic->ic_update_mcast = null_update_mcast;
  	ic->ic_update_promisc = null_update_promisc;
 +	ic->ic_update_chw = null_update_chw;
  
  	ic->ic_hash_key = arc4random();
  	ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
 
 Modified: head/sys/net80211/ieee80211_ht.c
 ==============================================================================
 --- head/sys/net80211/ieee80211_ht.c	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211_ht.c	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -1428,12 +1428,13 @@ ieee80211_parse_htinfo(struct ieee80211_
   * required channel change is done (e.g. in sta mode when
   * parsing the contents of a beacon frame).
   */
 -static void
 +static int
  htinfo_update_chw(struct ieee80211_node *ni, int htflags)
  {
  	struct ieee80211com *ic = ni->ni_ic;
  	struct ieee80211_channel *c;
  	int chanflags;
 +	int ret = 0;
  
  	chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
  	if (chanflags != ni->ni_chan->ic_flags) {
 @@ -1460,11 +1461,13 @@ htinfo_update_chw(struct ieee80211_node 
  			    IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
  			    c->ic_freq, c->ic_flags);
  			ni->ni_chan = c;
 +			ret = 1;
  		}
  		/* NB: caller responsible for forcing any channel change */
  	}
  	/* update node's tx channel width */
  	ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
 +	return (ret);
  }
  
  /*
 @@ -1515,13 +1518,14 @@ htcap_update_shortgi(struct ieee80211_no
   * Parse and update HT-related state extracted from
   * the HT cap and info ie's.
   */
 -void
 +int
  ieee80211_ht_updateparams(struct ieee80211_node *ni,
  	const uint8_t *htcapie, const uint8_t *htinfoie)
  {
  	struct ieee80211vap *vap = ni->ni_vap;
  	const struct ieee80211_ie_htinfo *htinfo;
  	int htflags;
 +	int ret = 0;
  
  	ieee80211_parse_htcap(ni, htcapie);
  	if (vap->iv_htcaps & IEEE80211_HTCAP_SMPS)
 @@ -1543,13 +1547,16 @@ ieee80211_ht_updateparams(struct ieee802
  		else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
  			htflags = IEEE80211_CHAN_HT40D;
  	}
 -	htinfo_update_chw(ni, htflags);
 +	if (htinfo_update_chw(ni, htflags))
 +		ret = 1;
  
  	if ((htinfo->hi_byte1 & IEEE80211_HTINFO_RIFSMODE_PERM) &&
  	    (vap->iv_flags_ht & IEEE80211_FHT_RIFS))
  		ni->ni_flags |= IEEE80211_NODE_RIFS;
  	else
  		ni->ni_flags &= ~IEEE80211_NODE_RIFS;
 +
 +	return (ret);
  }
  
  /*
 @@ -1578,7 +1585,7 @@ ieee80211_ht_updatehtcap(struct ieee8021
  		else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
  			htflags = IEEE80211_CHAN_HT40D;
  	}
 -	htinfo_update_chw(ni, htflags);
 +	(void) htinfo_update_chw(ni, htflags);
  }
  
  /*
 
 Modified: head/sys/net80211/ieee80211_ht.h
 ==============================================================================
 --- head/sys/net80211/ieee80211_ht.h	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211_ht.h	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -184,7 +184,7 @@ void	ieee80211_htprot_update(struct ieee
  void	ieee80211_ht_timeout(struct ieee80211com *);
  void	ieee80211_parse_htcap(struct ieee80211_node *, const uint8_t *);
  void	ieee80211_parse_htinfo(struct ieee80211_node *, const uint8_t *);
 -void	ieee80211_ht_updateparams(struct ieee80211_node *, const uint8_t *,
 +int	ieee80211_ht_updateparams(struct ieee80211_node *, const uint8_t *,
  		const uint8_t *);
  void	ieee80211_ht_updatehtcap(struct ieee80211_node *, const uint8_t *);
  int	ieee80211_ampdu_request(struct ieee80211_node *,
 
 Modified: head/sys/net80211/ieee80211_node.c
 ==============================================================================
 --- head/sys/net80211/ieee80211_node.c	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211_node.c	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -685,6 +685,14 @@ ieee80211_setcurchan(struct ieee80211com
  	ieee80211_runtask(ic, &ic->ic_chan_task);
  }
  
 +void
 +ieee80211_update_chw(struct ieee80211com *ic)
 +{
 +
 +	ieee80211_setupcurchan(ic, ic->ic_curchan);
 +	ieee80211_runtask(ic, &ic->ic_chw_task);
 +}
 +
  /*
   * Join the specified IBSS/BSS network.  The node is assumed to
   * be passed in with a held reference.
 
 Modified: head/sys/net80211/ieee80211_node.h
 ==============================================================================
 --- head/sys/net80211/ieee80211_node.h	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211_node.h	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -324,6 +324,7 @@ void	ieee80211_sync_curchan(struct ieee8
  void	ieee80211_setupcurchan(struct ieee80211com *,
  	    struct ieee80211_channel *);
  void	ieee80211_setcurchan(struct ieee80211com *, struct ieee80211_channel *);
 +void	ieee80211_update_chw(struct ieee80211com *);
  int	ieee80211_ibss_merge(struct ieee80211_node *);
  struct ieee80211_scan_entry;
  int	ieee80211_sta_join(struct ieee80211vap *, struct ieee80211_channel *,
 
 Modified: head/sys/net80211/ieee80211_proto.c
 ==============================================================================
 --- head/sys/net80211/ieee80211_proto.c	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211_proto.c	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -105,6 +105,7 @@ static void parent_updown(void *, int);
  static void update_mcast(void *, int);
  static void update_promisc(void *, int);
  static void update_channel(void *, int);
 +static void update_chw(void *, int);
  static void ieee80211_newstate_cb(void *, int);
  static int ieee80211_new_state_locked(struct ieee80211vap *,
  	enum ieee80211_state, int);
 @@ -144,6 +145,7 @@ ieee80211_proto_attach(struct ieee80211c
  	TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic);
  	TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic);
  	TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss, ic);
 +	TASK_INIT(&ic->ic_chw_task, 0, update_chw, ic);
  
  	ic->ic_wme.wme_hipri_switch_hysteresis =
  		AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
 @@ -1147,6 +1149,17 @@ update_channel(void *arg, int npending)
  	ieee80211_radiotap_chan_change(ic);
  }
  
 +static void
 +update_chw(void *arg, int npending)
 +{
 +	struct ieee80211com *ic = arg;
 +
 +	/*
 +	 * XXX should we defer the channel width _config_ update until now?
 +	 */
 +	ic->ic_update_chw(ic);
 +}
 +
  /*
   * Block until the parent is in a known state.  This is
   * used after any operations that dispatch a task (e.g.
 @@ -1161,6 +1174,7 @@ ieee80211_waitfor_parent(struct ieee8021
  	ieee80211_draintask(ic, &ic->ic_promisc_task);
  	ieee80211_draintask(ic, &ic->ic_chan_task);
  	ieee80211_draintask(ic, &ic->ic_bmiss_task);
 +	ieee80211_draintask(ic, &ic->ic_chw_task);
  	taskqueue_unblock(ic->ic_tq);
  }
  
 
 Modified: head/sys/net80211/ieee80211_sta.c
 ==============================================================================
 --- head/sys/net80211/ieee80211_sta.c	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211_sta.c	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -1285,6 +1285,7 @@ sta_recv_mgmt(struct ieee80211_node *ni,
  	uint8_t *frm, *efrm;
  	uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
  	uint8_t rate;
 +	int ht_state_change = 0;
  
  	wh = mtod(m0, struct ieee80211_frame *);
  	frm = (uint8_t *)&wh[1];
 @@ -1372,9 +1373,10 @@ sta_recv_mgmt(struct ieee80211_node *ni,
  #endif
  			if (scan.htcap != NULL && scan.htinfo != NULL &&
  			    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
 -				ieee80211_ht_updateparams(ni,
 -				    scan.htcap, scan.htinfo);
  				/* XXX state changes? */
 +				if (ieee80211_ht_updateparams(ni,
 +				    scan.htcap, scan.htinfo))
 +					ht_state_change = 1;
  			}
  			if (scan.quiet)
  				ic->ic_set_quiet(ni, scan.quiet);
 @@ -1441,6 +1443,13 @@ sta_recv_mgmt(struct ieee80211_node *ni,
  #endif
  				ieee80211_bg_scan(vap, 0);
  			}
 +
 +			/*
 +			 * If we've had a channel width change (eg HT20<->HT40)
 +			 * then schedule a delayed driver notification.
 +			 */
 +			if (ht_state_change)
 +				ieee80211_update_chw(ic);
  			return;
  		}
  		/*
 
 Modified: head/sys/net80211/ieee80211_var.h
 ==============================================================================
 --- head/sys/net80211/ieee80211_var.h	Sun Mar 25 02:22:32 2012	(r233451)
 +++ head/sys/net80211/ieee80211_var.h	Sun Mar 25 03:11:57 2012	(r233452)
 @@ -130,6 +130,7 @@ struct ieee80211com {
  	struct task		ic_mcast_task;	/* deferred mcast update */
  	struct task		ic_chan_task;	/* deferred channel change */
  	struct task		ic_bmiss_task;	/* deferred beacon miss hndlr */
 +	struct task		ic_chw_task;	/* deferred HT CHW update */
  
  	uint32_t		ic_flags;	/* state flags */
  	uint32_t		ic_flags_ext;	/* extended state flags */
 @@ -322,6 +323,10 @@ struct ieee80211com {
  				    int batimeout, int baseqctl);
  	void			(*ic_ampdu_rx_stop)(struct ieee80211_node *,
  				    struct ieee80211_rx_ampdu *);
 +
 +	/* The channel width has changed (20<->2040) */
 +	void			(*ic_update_chw)(struct ieee80211com *);
 +
  	uint64_t		ic_spare[7];
  };
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/166286: commit references a PR
Date: Sun, 25 Mar 2012 03:14:39 +0000 (UTC)

 Author: adrian
 Date: Sun Mar 25 03:14:31 2012
 New Revision: 233453
 URL: http://svn.freebsd.org/changeset/base/233453
 
 Log:
   Add the new channel width change field to the ath(4) driver.
   
   This is not entirely correct as it simply resets the channel, flushing
   whatever is in the TX/RX queue.  This can and will break aggregation
   BAW tracking.  But the alternative (HT40 frames being sent with the hardware
   in HT20 mode) is even worse.
   
   There's still a small window between the htinfo being received (and the ni_chw
   field being updated) which could cause problems.  I'll look at fleshing this
   out in follow-up commits.
   
   PR:		kern/166286
 
 Modified:
   head/sys/dev/ath/if_ath.c
 
 Modified: head/sys/dev/ath/if_ath.c
 ==============================================================================
 --- head/sys/dev/ath/if_ath.c	Sun Mar 25 03:11:57 2012	(r233452)
 +++ head/sys/dev/ath/if_ath.c	Sun Mar 25 03:14:31 2012	(r233453)
 @@ -199,6 +199,7 @@ static void	ath_chan_change(struct ath_s
  static void	ath_scan_start(struct ieee80211com *);
  static void	ath_scan_end(struct ieee80211com *);
  static void	ath_set_channel(struct ieee80211com *);
 +static void	ath_update_chw(struct ieee80211com *);
  static void	ath_calibrate(void *);
  static int	ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
  static void	ath_setup_stationkey(struct ieee80211_node *);
 @@ -794,6 +795,7 @@ ath_attach(u_int16_t devid, struct ath_s
  	ic->ic_scan_start = ath_scan_start;
  	ic->ic_scan_end = ath_scan_end;
  	ic->ic_set_channel = ath_set_channel;
 +	ic->ic_update_chw = ath_update_chw;
  
  	/* 802.11n specific - but just override anyway */
  	sc->sc_addba_request = ic->ic_addba_request;
 @@ -5717,6 +5719,31 @@ ath_scan_end(struct ieee80211com *ic)
  		 sc->sc_curaid);
  }
  
 +/*
 + * For now, just do a channel change.
 + *
 + * Later, we'll go through the hard slog of suspending tx/rx, changing rate
 + * control state and resetting the hardware without dropping frames out
 + * of the queue.
 + *
 + * The unfortunate trouble here is making absolutely sure that the
 + * channel width change has propagated enough so the hardware
 + * absolutely isn't handed bogus frames for it's current operating
 + * mode. (Eg, 40MHz frames in 20MHz mode.) Since TX and RX can and
 + * does occur in parallel, we need to make certain we've blocked
 + * any further ongoing TX (and RX, that can cause raw TX)
 + * before we do this.
 + */
 +static void
 +ath_update_chw(struct ieee80211com *ic)
 +{
 +	struct ifnet *ifp = ic->ic_ifp;
 +	struct ath_softc *sc = ifp->if_softc;
 +
 +	DPRINTF(sc, ATH_DEBUG_STATE, "%s: called\n", __func__);
 +	ath_set_channel(ic);
 +}
 +
  static void
  ath_set_channel(struct ieee80211com *ic)
  {
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
