Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH 0/4] ath10k: cleanups
From: Kalle Valo @ 2013-08-12 14:30 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, linux-wireless
In-Reply-To: <1375949650-9699-1-git-send-email-michal.kazior@tieto.com>

Michal Kazior <michal.kazior@tieto.com> writes:

> This patchset contains a few non-functional clean
> ups.
>
> Michal Kazior (4):
>   ath10k: clean up monitor start code
>   ath10k: use sizeof(*var) in kmalloc
>   ath10k: clean up PCI completion states
>   ath10k: print errcode when CE ring setup fails

Thanks, all four applied.

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH 2/4] ath10k: use sizeof(*var) in kmalloc
From: Kalle Valo @ 2013-08-12 14:26 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, linux-wireless
In-Reply-To: <1375949650-9699-3-git-send-email-michal.kazior@tieto.com>

Michal Kazior <michal.kazior@tieto.com> writes:

> This fixes checkpatch warning from the latest
> 3.11-rc kernel tree.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
>  drivers/net/wireless/ath/ath10k/pci.c |    3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
> index d95439b..1814af1 100644
> --- a/drivers/net/wireless/ath/ath10k/pci.c
> +++ b/drivers/net/wireless/ath/ath10k/pci.c
> @@ -803,8 +803,7 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
>  			continue;
>  
>  		for (i = 0; i < completions; i++) {
> -			compl = kmalloc(sizeof(struct ath10k_pci_compl),
> -					GFP_KERNEL);
> +			compl = kmalloc(sizeof(*compl), GFP_KERNEL);
>  			if (!compl) {
>  				ath10k_warn("No memory for completion state\n");
>  				ath10k_pci_stop_ce(ar);

Just out of curiosity, what's the warning? kmalloc() should be called
with sizeof(*foo) style?

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH 1/2] ath10k: Remove qca98xx hw1.0 support
From: Kalle Valo @ 2013-08-12 14:21 UTC (permalink / raw)
  To: Bartosz Markowski; +Cc: ath10k, linux-wireless
In-Reply-To: <1375881466-30090-1-git-send-email-bartosz.markowski@tieto.com>

Bartosz Markowski <bartosz.markowski@tieto.com> writes:

> Since the firmware support is no longer available for hw1.0,
> drop all code (especially workarounds) for those units.
>
> Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>

Thanks, both applied.

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH v2] ath10k: setup peer UAPSD flag correctly
From: Kalle Valo @ 2013-08-12 14:17 UTC (permalink / raw)
  To: Janusz Dziedzic; +Cc: ath10k, linux-wireless
In-Reply-To: <1375870249-29316-1-git-send-email-janusz.dziedzic@tieto.com>

Janusz Dziedzic <janusz.dziedzic@tieto.com> writes:

> Setup UAPSD peer/peer rate flags correctly.
> WMI_RC_UAPSD_FLAG is a peer rate capabilities flag
> and should not be set as a peer flag.
> Found during code review, doesn't fix a known
> issues.
>
> Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>

Thanks, applied.

-- 
Kalle Valo

^ permalink raw reply

* Pull request: ath 20130812
From: Kalle Valo @ 2013-08-12 14:14 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, ath6kl-devel, ath10k

Hi John,

here's a small pull request for ath10k and ath6kl. The changes are:

New features in ath10k are rx/tx checsumming in hw and survey scan
implemented by Michal. Also he made fixes to different areas of the
driver, most notable being fixing the case when using two streams and
reducing the number of interface combinations to avoid firmware crashes.
Bartosz did a clean related to how we handle SoC power save in PCI
layer.

For ath6kl Mohammed and Vasanth sent each a patch to fix two infrequent
crashes.

The following changes since commit 424121c365aed6ec93bbc8b515548df79c5af61c:

  ath10k: fix rts/fragmentation threshold setup (2013-07-30 18:01:21 +0300)

are available in the git repository at:

  git://github.com/kvalo/ath.git for-linville

for you to fetch changes up to 9d0e2f0772d394060bf3b17cd1f3a35574365103:

  ath6kl: Fix invalid pointer access on fuzz testing with AP mode (2013-08-07 10:58:59 +0300)

----------------------------------------------------------------
Bartosz Markowski (1):
      ath10k: add SoC power save option to PCI features map

Michal Kazior (11):
      ath10k: improve tx throughput on slow machines
      ath10k: detect the number of spatial streams supported by hw
      ath10k: implement rx checksum offloading
      ath10k: implement tx checksum offloading
      ath10k: implement get_survey()
      ath10k: prevent using invalid ringbuffer indexes
      ath10k: make sure to use passive scan when n_ssids is 0
      ath10k: advertise more conservative intf combinations
      ath10k: zero arvif memory on add_interface()
      ath10k: fix failpath in MSI-X setup
      ath10k: fix device teardown

Mohammed Shafi Shajakhan (1):
      ath6kl: Fix invalid pointer access on fuzz testing with AP mode

Vasanthakumar Thiagarajan (1):
      ath6kl: Fix race in heart beat polling

 drivers/net/wireless/ath/ath10k/ce.c     |    5 ++
 drivers/net/wireless/ath/ath10k/core.h   |    8 +++
 drivers/net/wireless/ath/ath10k/htt_rx.c |   40 ++++++++++++++
 drivers/net/wireless/ath/ath10k/htt_tx.c |    2 +
 drivers/net/wireless/ath/ath10k/mac.c    |   79 +++++++++++++++++++++------
 drivers/net/wireless/ath/ath10k/pci.c    |   70 +++++++++++++++++-------
 drivers/net/wireless/ath/ath10k/pci.h    |   11 ++--
 drivers/net/wireless/ath/ath10k/wmi.c    |   87 ++++++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath10k/wmi.h    |    5 ++
 drivers/net/wireless/ath/ath6kl/init.c   |    3 ++
 drivers/net/wireless/ath/ath6kl/main.c   |    3 ++
 11 files changed, 270 insertions(+), 43 deletions(-)

^ permalink raw reply

* Re: [PATCH] iwlwifi: mvm: make debugfs write() operations write up to count bytes
From: Djalal Harouni @ 2013-08-12 12:33 UTC (permalink / raw)
  To: Berg, Johannes
  Cc: Grumbach, Emmanuel, Intel Linux Wireless, John W. Linville,
	linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org
In-Reply-To: <1DC40B07CD6EC041A66726C271A73AE61AA5E38C@IRSMSX102.ger.corp.intel.com>

On Mon, Aug 12, 2013 at 08:19:12AM +0000, Berg, Johannes wrote:
> > Some debugfs write() operations of the MVM Firmware will ignore the count
> > argument, and will copy more bytes than what was specified.
> > Fix this by getting the right count of bytes.
> > 
> > This will also honor restrictions put on the number of bytes to write.
> 
> That makes some sense.
And avoid strncmp() on garbage data.

> > To be consitant this patch also switches the initializer from 'char buf[x] = {}' to
> > the explicit memset() as it is done in other places of the same file.
> 
> I'd rather this (a) be done in a separate patch, and (b) the other way around, switch everything to C99.
Ok

> > Cc: stable@vger.kernel.org
> 
> That doesn't really make sense for the debugfs interface.
Ok

> > +	memset(buf, 0, sizeof(buf));
> > +	if (count > sizeof(buf) - 1)
> > +		count = sizeof(buf) - 1;
> 
> Why -1? And why not use min()/min_t()?
Yes -1 to be sure that the processed string is null terminated

Ok will use min_t 


Will send a second version, Thanks!

> johannes
> -- 
> 
> Intel GmbH
> Dornacher Strasse 1
> 85622 Feldkirchen/Muenchen, Deutschland
> Sitz der Gesellschaft: Feldkirchen bei Muenchen
> Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
> Registergericht: Muenchen HRB 47456
> Ust.-IdNr./VAT Registration No.: DE129385895
> Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052
> 

-- 
Djalal Harouni
http://opendz.org

^ permalink raw reply

* Re: [PATCH 28/30] iwlwifi: mvm: Change beacon abort escape time value
From: Arik Nemtsov @ 2013-08-12 12:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Alexander Bondar
In-Reply-To: <1374827327-3464-29-git-send-email-johannes@sipsolutions.net>

On Fri, Jul 26, 2013 at 11:28 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> From: Alexander Bondar <alexander.bondar@intel.com>
>
> Set beacon abort escape timer values - 6 beacons in D0 state,
> 9 beacons in D3 and D0i3.
>
> Signed-off-by: Alexander Bondar <alexander.bondar@intel.com>
> Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---
>  drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 3 ++-
>  drivers/net/wireless/iwlwifi/mvm/power.c        | 3 +++
>  2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
> index 149347d..060e630 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
> +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
> @@ -285,7 +285,8 @@ struct iwl_beacon_filter_cmd {
>  #define IWL_BF_ESCAPE_TIMER_MAX 1024
>  #define IWL_BF_ESCAPE_TIMER_MIN 0
>
> -#define IWL_BA_ESCAPE_TIMER_DEFAULT 3
> +#define IWL_BA_ESCAPE_TIMER_DEFAULT 6
> +#define IWL_BA_ESCAPE_TIMER_D3 6

Did you mean 9 here?
(Sorry for the late review)

^ permalink raw reply

* Re: [PATCH 1/2] cfg80211: add wdev to testmode cmd
From: Johannes Berg @ 2013-08-12 12:11 UTC (permalink / raw)
  To: linux-wireless; +Cc: David Spinadel
In-Reply-To: <1375780347-1062-1-git-send-email-johannes@sipsolutions.net>

On Tue, 2013-08-06 at 11:12 +0200, Johannes Berg wrote:
> From: David Spinadel <david.spinadel@intel.com>
> 
> To allow drivers to implement per-interface testmode operations
> more easily, pass a wdev pointer if any identification for one
> was given from userspace. Clean up the code a bit while at it.

Applied both.

johannes


^ permalink raw reply

* Re: [PATCH] mac80211: add control port protocol TX control flag
From: Johannes Berg @ 2013-08-12 12:09 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1375783056-2665-1-git-send-email-johannes@sipsolutions.net>

On Tue, 2013-08-06 at 11:57 +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> A lot of drivers check the frame protocol for ETH_P_PAE,
> for various reasons (like making those more reliable).
> Add a new flags bitmap to the TX control info and a new
> flag indicating the control port protocol is in use to
> let all drivers also apply such logic to other control
> port protocols, should they be configured.

Applied (with fix for the problem Eliad pointed out, and the change-id
removed)

johannes


^ permalink raw reply

* Re: [PATCH] nl80211: clean up CQM settings code
From: Johannes Berg @ 2013-08-12 12:07 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1375791102-5505-1-git-send-email-johannes@sipsolutions.net>

On Tue, 2013-08-06 at 14:11 +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> Clean up the CQM settings code a bit and while at it
> enforce that when setting the threshold to 0 (disable)
> the hysteresis is also set to 0 to avoid confusion.
> As we haven't enforce it, simply override userspace.

Applied.

johannes


^ permalink raw reply

* [PATCH] mac80211: add APIs to allow keeping connections after WoWLAN
From: Johannes Berg @ 2013-08-12 12:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

In order to be able to (securely) keep connections alive after
the system was suspended for WoWLAN, we need some additional
APIs. We already have API (ieee80211_gtk_rekey_notify) to tell
wpa_supplicant about the new replay counter if GTK rekeying
was done by the device while the host was asleep, but that's
not sufficient.

If GTK rekeying wasn't done, we need to tell the host about
sequence counters for the GTK (and PTK regardless of rekeying)
that was used while asleep, add ieee80211_set_key_rx_seq() for
that.

If GTK rekeying was done, then we need to be able to disable
the old keys (with ieee80211_remove_key()) and allocate the
new GTK key(s) in mac80211 (with ieee80211_gtk_rekey_add()).

If protocol offload (e.g. ARP) is implemented, then also the
TX sequence counter for the PTK must be updated, using the new
ieee80211_set_key_tx_seq() function.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/mac80211.h |  83 ++++++++++++++++++++++++++
 net/mac80211/key.c     | 154 ++++++++++++++++++++++++++++++++++++++++++++++---
 net/mac80211/util.c    |   2 +-
 3 files changed, 231 insertions(+), 8 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index df93c77..e3e3037 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3688,6 +3688,89 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
 			      int tid, struct ieee80211_key_seq *seq);
 
 /**
+ * ieee80211_set_key_tx_seq - set key TX sequence counter
+ *
+ * @keyconf: the parameter passed with the set key
+ * @seq: new sequence data
+ *
+ * This function allows a driver to set the current TX IV/PNs for the
+ * given key. This is useful when resuming from WoWLAN sleep and the
+ * device may have transmitted frames using the PTK, e.g. replies to
+ * ARP requests.
+ *
+ * Note that this function may only be called when no TX processing
+ * can be done concurrently.
+ */
+void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
+			      struct ieee80211_key_seq *seq);
+
+/**
+ * ieee80211_set_key_rx_seq - set key RX sequence counter
+ *
+ * @keyconf: the parameter passed with the set key
+ * @tid: The TID, or -1 for the management frame value (CCMP only);
+ *	the value on TID 0 is also used for non-QoS frames. For
+ *	CMAC, only TID 0 is valid.
+ * @seq: new sequence data
+ *
+ * This function allows a driver to set the current RX IV/PNs for the
+ * given key. This is useful when resuming from WoWLAN sleep and GTK
+ * rekey may have been done while suspended. It should not be called
+ * if IV checking is done by the device and not by mac80211.
+ *
+ * Note that this function may only be called when no RX processing
+ * can be done concurrently.
+ */
+void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
+			      int tid, struct ieee80211_key_seq *seq);
+
+/**
+ * ieee80211_remove_key - remove the given key
+ * @keyconf: the parameter passed with the set key
+ *
+ * Remove the given key. If the key was uploaded to the hardware at the
+ * time this function is called, it is not deleted in the hardware but
+ * instead assumed to have been removed already.
+ *
+ * Note that due to locking considerations this function can (currently)
+ * only be called during key iteration (ieee80211_iter_keys().)
+ */
+void ieee80211_remove_key(struct ieee80211_key_conf *keyconf);
+
+/**
+ * ieee80211_gtk_rekey_add - add a GTK key from rekeying during WoWLAN
+ * @vif: the virtual interface to add the key on
+ * @keyconf: new key data
+ *
+ * When GTK rekeying was done while the system was suspended, (a) new
+ * key(s) will be available. These will be needed by mac80211 for proper
+ * RX processing, so this function allows setting them.
+ *
+ * The function returns the newly allocated key structure, which will
+ * have similar contents to the passed key configuration but point to
+ * mac80211-owned memory. In case of errors, the function returns an
+ * ERR_PTR(), use IS_ERR() etc.
+ *
+ * Note that this function assumes the key isn't added to hardware
+ * acceleration, so no TX will be done with the key. Since it's a GTK
+ * on managed (station) networks, this is true anyway. If the driver
+ * calls this function from the resume callback and subsequently uses
+ * the return code 1 to reconfigure the device, this key will be part
+ * of the reconfiguration.
+ *
+ * Note that the driver should also call ieee80211_set_key_rx_seq()
+ * for the new key for each TID to set up sequence counters properly.
+ *
+ * IMPORTANT: If this replaces a key that is present in the hardware,
+ * then it will attempt to remove it during this call. In many cases
+ * this isn't what you want, so call ieee80211_remove_key() first for
+ * the key that's being replaced.
+ */
+struct ieee80211_key_conf *
+ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
+			struct ieee80211_key_conf *keyconf);
+
+/**
  * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
  * @vif: virtual interface the rekeying was done on
  * @bssid: The BSSID of the AP, for checking association
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index e39cc91..620677e 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -93,6 +93,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
 	might_sleep();
 
+	if (key->flags & KEY_FLAG_TAINTED)
+		return -EINVAL;
+
 	if (!key->local->ops->set_key)
 		goto out_unsupported;
 
@@ -455,6 +458,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
 		       struct ieee80211_sub_if_data *sdata,
 		       struct sta_info *sta)
 {
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_key *old_key;
 	int idx, ret;
 	bool pairwise;
@@ -484,10 +488,13 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
 	ieee80211_debugfs_key_add(key);
 
-	ret = ieee80211_key_enable_hw_accel(key);
-
-	if (ret)
-		ieee80211_key_free(key, true);
+	if (!local->wowlan) {
+		ret = ieee80211_key_enable_hw_accel(key);
+		if (ret)
+			ieee80211_key_free(key, true);
+	} else {
+		ret = 0;
+	}
 
 	mutex_unlock(&sdata->local->key_mtx);
 
@@ -540,7 +547,7 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
 			 void *iter_data)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_key *key;
+	struct ieee80211_key *key, *tmp;
 	struct ieee80211_sub_if_data *sdata;
 
 	ASSERT_RTNL();
@@ -548,13 +555,14 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
 	mutex_lock(&local->key_mtx);
 	if (vif) {
 		sdata = vif_to_sdata(vif);
-		list_for_each_entry(key, &sdata->key_list, list)
+		list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
 			iter(hw, &sdata->vif,
 			     key->sta ? &key->sta->sta : NULL,
 			     &key->conf, iter_data);
 	} else {
 		list_for_each_entry(sdata, &local->interfaces, list)
-			list_for_each_entry(key, &sdata->key_list, list)
+			list_for_each_entry_safe(key, tmp,
+						 &sdata->key_list, list)
 				iter(hw, &sdata->vif,
 				     key->sta ? &key->sta->sta : NULL,
 				     &key->conf, iter_data);
@@ -751,3 +759,135 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
 	}
 }
 EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
+
+void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
+			      struct ieee80211_key_seq *seq)
+{
+	struct ieee80211_key *key;
+	u64 pn64;
+
+	key = container_of(keyconf, struct ieee80211_key, conf);
+
+	switch (key->conf.cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		key->u.tkip.tx.iv32 = seq->tkip.iv32;
+		key->u.tkip.tx.iv16 = seq->tkip.iv16;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		pn64 = (u64)seq->ccmp.pn[5] |
+		       ((u64)seq->ccmp.pn[4] << 8) |
+		       ((u64)seq->ccmp.pn[3] << 16) |
+		       ((u64)seq->ccmp.pn[2] << 24) |
+		       ((u64)seq->ccmp.pn[1] << 32) |
+		       ((u64)seq->ccmp.pn[0] << 40);
+		atomic64_set(&key->u.ccmp.tx_pn, pn64);
+		break;
+	case WLAN_CIPHER_SUITE_AES_CMAC:
+		pn64 = (u64)seq->aes_cmac.pn[5] |
+		       ((u64)seq->aes_cmac.pn[4] << 8) |
+		       ((u64)seq->aes_cmac.pn[3] << 16) |
+		       ((u64)seq->aes_cmac.pn[2] << 24) |
+		       ((u64)seq->aes_cmac.pn[1] << 32) |
+		       ((u64)seq->aes_cmac.pn[0] << 40);
+		atomic64_set(&key->u.aes_cmac.tx_pn, pn64);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(ieee80211_set_key_tx_seq);
+
+void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
+			      int tid, struct ieee80211_key_seq *seq)
+{
+	struct ieee80211_key *key;
+	u8 *pn;
+
+	key = container_of(keyconf, struct ieee80211_key, conf);
+
+	switch (key->conf.cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS))
+			return;
+		key->u.tkip.rx[tid].iv32 = seq->tkip.iv32;
+		key->u.tkip.rx[tid].iv16 = seq->tkip.iv16;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
+			return;
+		if (tid < 0)
+			pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS];
+		else
+			pn = key->u.ccmp.rx_pn[tid];
+		memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN);
+		break;
+	case WLAN_CIPHER_SUITE_AES_CMAC:
+		if (WARN_ON(tid != 0))
+			return;
+		pn = key->u.aes_cmac.rx_pn;
+		memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq);
+
+void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
+{
+	struct ieee80211_key *key;
+
+	key = container_of(keyconf, struct ieee80211_key, conf);
+
+	assert_key_lock(key->local);
+
+	/*
+	 * if key was uploaded, we assume the driver will/has remove(d)
+	 * it, so adjust bookkeeping accordingly
+	 */
+	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
+		key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+		if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+		      (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+		      (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+			increment_tailroom_need_count(key->sdata);
+	}
+
+	ieee80211_key_free(key, false);
+}
+EXPORT_SYMBOL_GPL(ieee80211_remove_key);
+
+struct ieee80211_key_conf *
+ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
+			struct ieee80211_key_conf *keyconf)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_key *key;
+	int err;
+
+	if (WARN_ON(!local->wowlan))
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+		return ERR_PTR(-EINVAL);
+
+	key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
+				  keyconf->keylen, keyconf->key,
+				  0, NULL);
+	if (IS_ERR(key))
+		return ERR_PTR(PTR_ERR(key));
+
+	if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
+		key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
+
+	err = ieee80211_key_link(key, sdata, NULL);
+	if (err)
+		return ERR_PTR(err);
+
+	return &key->conf;
+}
+EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d23c5a7..e1b34a1 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1453,8 +1453,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 		local->resuming = true;
 
 	if (local->wowlan) {
-		local->wowlan = false;
 		res = drv_resume(local);
+		local->wowlan = false;
 		if (res < 0) {
 			local->resuming = false;
 			return res;
-- 
1.8.0


^ permalink raw reply related

* Re: brcsmac kernel panic
From: Arend van Spriel @ 2013-08-12 10:38 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: linux-wireless, linux-kernel
In-Reply-To: <5207BA00.3030709@monom.org>

[-- Attachment #1: Type: text/plain, Size: 798 bytes --]

On 08/11/2013 06:21 PM, Daniel Wagner wrote:
> Hi,
>
> I just updated my laptop (MacBook Air 2012) from 3.11-rc3+ to 3.11-rc4+
> and since then brcsmac crashes short after enabling it. Unfortunately, I
> did also change some config flags in the area of cpufreq (enabling
> p-state driver) so the configuration is not exactly the same. Before I
> try to figure out what I have changed, I am posting the picture of the
> crash. Maybe it is something obvious.
>
> v3.11-rc4-197-gd92581f
> http://www.monom.org/misc/brcmsmac/v3.11-rc4.config
> http://www.monom.org/misc/brcmsmac/IMAG0064.jpg

Thanks, Daniel

I was looking at this issue two weeks ago and just got back from my 
vacation. Can you apply the patch and send me a kernel log?

Sharing pictures, huh. What about this one :-p

Regards,
Arend

[-- Attachment #2: barcelona-2012.jpg --]
[-- Type: image/jpeg, Size: 82908 bytes --]

[-- Attachment #3: 0001-brcmsmac-avoid-kernel-panic-due-to-divide-by-zero-er.patch --]
[-- Type: text/plain, Size: 1447 bytes --]

>From aeca211f0bb6186eefb7f3a6ad98115e2256e53a Mon Sep 17 00:00:00 2001
From: Arend van Spriel <arend@broadcom.com>
Date: Mon, 12 Aug 2013 12:34:45 +0200
Subject: [PATCH] brcmsmac: avoid kernel panic due to divide-by-zero error

The patch avoid the kernel panic and adds a few error log messages.

Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/net/wireless/brcm80211/brcmsmac/main.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 9fd6f2f..ea92ea2 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -630,10 +630,21 @@ static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
 		dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
 		if (preamble_type == BRCMS_MM_PREAMBLE)
 			dur += PREN_MM_EXT;
+
+		if (mcs > BRCMS_MAXMCS) {
+			brcms_err(wlc->hw->d11core, "wl%d: invalid mcs: %u\n",
+				  wlc->pub->unit, mcs);
+			mcs = 0;
+		}
 		/* 1000Ndbps = kbps * 4 */
 		kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
 				   rspec_issgi(ratespec)) * 4;
 
+		if (kNdps == 0) {
+			brcms_err(wlc->hw->d11core, "wl%d: invalid zero rate: rspec=0x%x\n",
+				  wlc->pub->unit, ratespec);
+			kNdps = 6500 * 4;
+		}
 		if (rspec_stc(ratespec) == 0)
 			nsyms =
 			    CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
-- 
1.7.10.4


^ permalink raw reply related

* Re: [PATCH 12/12] brcmsmac: support 4313iPA
From: David Herrmann @ 2013-08-12 10:22 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: Jonas Gorski, John W. Linville, linux-wireless, Piotr Haber
In-Reply-To: <5208B47B.6090903@broadcom.com>

Hi

On Mon, Aug 12, 2013 at 12:10 PM, Arend van Spriel <arend@broadcom.com> wrote:
> On 08/11/2013 02:48 PM, Jonas Gorski wrote:
>>
>> Hi,
>>
>> On Sat, Aug 10, 2013 at 12:27 PM, Arend van Spriel <arend@broadcom.com>
>> wrote:
>>>
>>> From: Piotr Haber <phaber@broadcom.com>
>>>
>>> Add support for 4313 iPA variant.
>>> It is a variant of already supported 4313 ePA,
>>> so this patch adds the required PHY changes to
>>> support it properly including an updated switch
>>> control table for BT-combo card variants.
>>
>>
>> Okay, I'll bite. Since this patch was already reverted once, it
>> warrants some additional scrutiny.
>
>
> That's the right attitude ;-) The revert made us cautious as well before
> sending out this patch, but thanks for making the effort.
>
>
>> First of all, the patch is quite large, and I wonder if it couldn't be
>> split into smaller patches, especially as it looks like there are
>> additional fixes/changes merged in it.
>
>
> It indeed seems rather large. The original work from Piotr were two patches
> that I squashed. I will break up this patch in more individual patches.
>
> John,
>
> Can you drop this patch from the series?
>
>
>> Detailed comments below ...
>>
>>> Tested-by: Maximilian Engelhardt <maxi@daemonizer.de>
>>> Tested-by: David Costa <david@zarel.net>
>>> Reviewed-by: Arend Van Spriel <arend@broadcom.com>
>>> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
>>> Signed-off-by: Piotr Haber <phaber@broadcom.com>
>>> Signed-off-by: Arend van Spriel <arend@broadcom.com>
>>> ---
>>
>>
>> This is obviously a V2 (or V(n+1) where n was the reverted version),
>> so there should be something describing the changes to the reverted
>> version. Why should we trust it now to not break things again? (Yes, I
>> see those Tested-bys ;-)
>
>
> This is a gray area. The original patch was taken into the tree so I
> considered this to be a new patch.
>
> We tested with a number of 4313 variants having some extra shipped that we
> did not have at the time of the original patch. I looked up the revert patch
> and noticed it is tagged with Reported-by. So I will ask David Herrmann to
> test V(n+2) before sending it (if you don't mind n will be 0).

If you add me to CC for the patch I will happily test it. But for now
I have no idea which patches I should try so I will wait for the next
revision, I guess?

Thanks for letting me know!
David

^ permalink raw reply

* Re: [PATCH 12/12] brcmsmac: support 4313iPA
From: Arend van Spriel @ 2013-08-12 10:10 UTC (permalink / raw)
  To: Jonas Gorski, John W. Linville
  Cc: linux-wireless, Piotr Haber, David Herrmann
In-Reply-To: <CAOiHx==iBf19ym=Q3HFOdKv_u-6tvz0uq_U61ziVfKS7LuWG5w@mail.gmail.com>

On 08/11/2013 02:48 PM, Jonas Gorski wrote:
> Hi,
>
> On Sat, Aug 10, 2013 at 12:27 PM, Arend van Spriel <arend@broadcom.com> wrote:
>> From: Piotr Haber <phaber@broadcom.com>
>>
>> Add support for 4313 iPA variant.
>> It is a variant of already supported 4313 ePA,
>> so this patch adds the required PHY changes to
>> support it properly including an updated switch
>> control table for BT-combo card variants.
>
> Okay, I'll bite. Since this patch was already reverted once, it
> warrants some additional scrutiny.

That's the right attitude ;-) The revert made us cautious as well before 
sending out this patch, but thanks for making the effort.

> First of all, the patch is quite large, and I wonder if it couldn't be
> split into smaller patches, especially as it looks like there are
> additional fixes/changes merged in it.

It indeed seems rather large. The original work from Piotr were two 
patches that I squashed. I will break up this patch in more individual 
patches.

John,

Can you drop this patch from the series?

> Detailed comments below ...
>
>> Tested-by: Maximilian Engelhardt <maxi@daemonizer.de>
>> Tested-by: David Costa <david@zarel.net>
>> Reviewed-by: Arend Van Spriel <arend@broadcom.com>
>> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
>> Signed-off-by: Piotr Haber <phaber@broadcom.com>
>> Signed-off-by: Arend van Spriel <arend@broadcom.com>
>> ---
>
> This is obviously a V2 (or V(n+1) where n was the reverted version),
> so there should be something describing the changes to the reverted
> version. Why should we trust it now to not break things again? (Yes, I
> see those Tested-bys ;-)

This is a gray area. The original patch was taken into the tree so I 
considered this to be a new patch.

We tested with a number of 4313 variants having some extra shipped that 
we did not have at the time of the original patch. I looked up the 
revert patch and noticed it is tagged with Reported-by. So I will ask 
David Herrmann to test V(n+2) before sending it (if you don't mind n 
will be 0).

>>   .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c  | 399 +++++++++++++--------
>>   .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c   | 289 +++++++++------
>>   .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h   |   1 +
>>   3 files changed, 436 insertions(+), 253 deletions(-)
>>
>> diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
>> index 3d6b16c..b8ddaad 100644
>> --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
>> +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
>> @@ -1137,8 +1137,9 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
>>          gain0_15 = ((biq1 & 0xf) << 12) |
>>                     ((tia & 0xf) << 8) |
>>                     ((lna2 & 0x3) << 6) |
>> -                  ((lna2 &
>> -                    0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
>> +                  ((lna2 & 0x3) << 4) |
>> +                  ((lna1 & 0x3) << 2) |
>> +                  ((lna1 & 0x3) << 0);
>
> Unrelated style change.

I will put this in a separate patch.

>>
>>          mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
>>          mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
>> @@ -1328,6 +1329,43 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
>>          return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
>>   }
>>
>> +static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
>> +                                     u16 tia_gain, u16 lna2_gain)
>> +{
>> +       u32 i_thresh_l, q_thresh_l;
>> +       u32 i_thresh_h, q_thresh_h;
>> +       struct lcnphy_iq_est iq_est_h, iq_est_l;
>> +
>> +       wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
>> +                                              lna2_gain, 0);
>> +
>> +       wlc_lcnphy_rx_gain_override_enable(pi, true);
>> +       wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
>> +       udelay(500);
>> +       write_radio_reg(pi, RADIO_2064_REG112, 0);
>> +       if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
>> +               return false;
>> +
>> +       wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
>> +       udelay(500);
>> +       write_radio_reg(pi, RADIO_2064_REG112, 0);
>> +       if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
>> +               return false;
>> +
>> +       i_thresh_l = (iq_est_l.i_pwr << 1);
>> +       i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
>> +
>> +       q_thresh_l = (iq_est_l.q_pwr << 1);
>> +       q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
>
> So X_thresh_l == iq_est_l.X_pwr * 2 and X_thresh_h == iq_est_l.X_pwr *
> 5? Why not trust the compiler to use optimize it? It would be a bit
> more readable.

This is a bit personal. A C programmer is probably as familiar with 
bitwise operators as with arithmetic. Anyways, my main reason for having 
it this way is maintainability as it closely resembles the internal 
driver code base. So I tend to leave it as is.

>> +       if ((iq_est_h.i_pwr > i_thresh_l) &&
>> +           (iq_est_h.i_pwr < i_thresh_h) &&
>> +           (iq_est_h.q_pwr > q_thresh_l) &&
>> +           (iq_est_h.q_pwr < q_thresh_h))
>> +               return true;
>> +
>> +       return false;
>> +}
>> +
>>   static bool
>>   wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
>>                       const struct lcnphy_rx_iqcomp *iqcomp,
>> @@ -1342,8 +1380,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
>>              RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
>>              rfoverride3_old, rfoverride3val_old, rfoverride4_old,
>>              rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
>> -       int tia_gain;
>> -       u32 received_power, rx_pwr_threshold;
>> +       int tia_gain, lna2_gain, biq1_gain;
>> +       bool set_gain;
>>          u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
>>          u16 values_to_save[11];
>>          s16 *ptr;
>> @@ -1368,126 +1406,134 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
>>                  goto cal_done;
>>          }
>>
>> -       if (module == 1) {
>> +       WARN_ON(module != 1);
>> +       tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
>> +       wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
>>
>> -               tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
>> -               wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
>
> This indentation change makes it a bit harder to review, but luckily
> there is git show -b ...

I will do the indentation change with a separate patch.

>> +       for (i = 0; i < 11; i++)
>> +               values_to_save[i] =
>> +                       read_radio_reg(pi, rxiq_cal_rf_reg[i]);
>> +       Core1TxControl_old = read_phy_reg(pi, 0x631);
>> +
>> +       or_phy_reg(pi, 0x631, 0x0015);
>> +
>> +       RFOverride0_old = read_phy_reg(pi, 0x44c);
>> +       RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
>> +       rfoverride2_old = read_phy_reg(pi, 0x4b0);
>> +       rfoverride2val_old = read_phy_reg(pi, 0x4b1);
>> +       rfoverride3_old = read_phy_reg(pi, 0x4f9);
>> +       rfoverride3val_old = read_phy_reg(pi, 0x4fa);
>> +       rfoverride4_old = read_phy_reg(pi, 0x938);
>> +       rfoverride4val_old = read_phy_reg(pi, 0x939);
>> +       afectrlovr_old = read_phy_reg(pi, 0x43b);
>> +       afectrlovrval_old = read_phy_reg(pi, 0x43c);
>> +       old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
>> +       old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
>>
>> -               for (i = 0; i < 11; i++)
>> -                       values_to_save[i] =
>> -                               read_radio_reg(pi, rxiq_cal_rf_reg[i]);
>> -               Core1TxControl_old = read_phy_reg(pi, 0x631);
>> -
>> -               or_phy_reg(pi, 0x631, 0x0015);
>> -
>> -               RFOverride0_old = read_phy_reg(pi, 0x44c);
>> -               RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
>> -               rfoverride2_old = read_phy_reg(pi, 0x4b0);
>> -               rfoverride2val_old = read_phy_reg(pi, 0x4b1);
>> -               rfoverride3_old = read_phy_reg(pi, 0x4f9);
>> -               rfoverride3val_old = read_phy_reg(pi, 0x4fa);
>> -               rfoverride4_old = read_phy_reg(pi, 0x938);
>> -               rfoverride4val_old = read_phy_reg(pi, 0x939);
>> -               afectrlovr_old = read_phy_reg(pi, 0x43b);
>> -               afectrlovrval_old = read_phy_reg(pi, 0x43c);
>> -               old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
>> -               old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
>> -
>> -               tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
>> -               if (tx_gain_override_old) {
>> -                       wlc_lcnphy_get_tx_gain(pi, &old_gains);
>> -                       tx_gain_index_old = pi_lcn->lcnphy_current_index;
>> -               }
>> +       tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
>> +       if (tx_gain_override_old) {
>> +               wlc_lcnphy_get_tx_gain(pi, &old_gains);
>> +               tx_gain_index_old = pi_lcn->lcnphy_current_index;
>> +       }
>>
>> -               wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
>> +       wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
>>
>> -               mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
>> -               mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
>> +       mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
>> +       mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
>>
>> -               mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
>> -               mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
>> +       mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
>> +       mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
>>
>> -               write_radio_reg(pi, RADIO_2064_REG116, 0x06);
>> -               write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
>> -               write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
>> -               write_radio_reg(pi, RADIO_2064_REG098, 0x03);
>> -               write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
>> -               mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
>> -               write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
>> -               write_radio_reg(pi, RADIO_2064_REG114, 0x01);
>> -               write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
>> -               write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
>> -
>> -               mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
>> -               mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
>> -               mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
>> -               mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
>> -               mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
>> -               mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
>> -               mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
>> -               mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
>> -               mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
>> -               mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
>> -
>> -               mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
>> -               mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
>> -
>> -               wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
>> -               write_phy_reg(pi, 0x6da, 0xffff);
>> -               or_phy_reg(pi, 0x6db, 0x3);
>> -               wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
>> -               wlc_lcnphy_rx_gain_override_enable(pi, true);
>> -
>> -               tia_gain = 8;
>> -               rx_pwr_threshold = 950;
>> -               while (tia_gain > 0) {
>> -                       tia_gain -= 1;
>> -                       wlc_lcnphy_set_rx_gain_by_distribution(pi,
>> -                                                              0, 0, 2, 2,
>> -                                                              (u16)
>> -                                                              tia_gain, 1, 0);
>> -                       udelay(500);
>> +       write_radio_reg(pi, RADIO_2064_REG116, 0x06);
>> +       write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
>> +       write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
>> +       write_radio_reg(pi, RADIO_2064_REG098, 0x03);
>> +       write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
>> +       mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
>> +       write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
>> +       write_radio_reg(pi, RADIO_2064_REG114, 0x01);
>> +       write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
>> +       write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
>> +
>> +       mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
>> +       mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
>> +       mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
>> +       mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
>> +       mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
>> +       mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
>> +       mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
>> +       mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
>> +       mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
>> +       mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
>>
>> -                       received_power =
>> -                               wlc_lcnphy_measure_digital_power(pi, 2000);
>> -                       if (received_power < rx_pwr_threshold)
>> -                               break;
>> +       mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
>> +       mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
>> +
>> +       write_phy_reg(pi, 0x6da, 0xffff);
>> +       or_phy_reg(pi, 0x6db, 0x3);
>> +
>> +       wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
>> +       set_gain = false;
>> +
>> +       lna2_gain = 3;
>> +       while ((lna2_gain >= 0) && !set_gain) {
>> +               tia_gain = 4;
>> +
>> +               while ((tia_gain >= 0) && !set_gain) {
>> +                       biq1_gain = 6;
>> +
>> +                       while ((biq1_gain >= 0) && !set_gain) {
>> +                               set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
>> +                                                                    (u16)
>> +                                                                    biq1_gain,
>> +                                                                    (u16)
>> +                                                                    tia_gain,
>> +                                                                    (u16)
>> +                                                                    lna2_gain);
>> +                               biq1_gain -= 1;
>> +                       }
>> +                       tia_gain -= 1;
>>                  }
>> -               result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
>> +               lna2_gain -= 1;
>> +       }
>
> This looks like it could be made more readable using for loops and a goto:
>
> 	for (lna_gain = 3; lna_gain >= 0; lna_gain--) {
> 		for (tia_gain = 4; tia_gain >= 0; tia_gain--) {
> 			for (big1_gain = 6; big1_gain >= 0; big1_gain--) {
> 				set_gain = wlc_lcnphy_rx_iq_cal_gain(...);
> 				if (set_gain)
> 					goto found;
> 			}
> 		}
> 	}
> found:
> 	...

That is a sensible change. Will do.

>>
>> -               wlc_lcnphy_stop_tx_tone(pi);
>> +       if (set_gain)
>> +               result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
>> +       else
>> +               result = false;
>>
>> -               write_phy_reg(pi, 0x631, Core1TxControl_old);
>> +       wlc_lcnphy_stop_tx_tone(pi);
>>
>> -               write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
>> -               write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
>> -               write_phy_reg(pi, 0x4b0, rfoverride2_old);
>> -               write_phy_reg(pi, 0x4b1, rfoverride2val_old);
>> -               write_phy_reg(pi, 0x4f9, rfoverride3_old);
>> -               write_phy_reg(pi, 0x4fa, rfoverride3val_old);
>> -               write_phy_reg(pi, 0x938, rfoverride4_old);
>> -               write_phy_reg(pi, 0x939, rfoverride4val_old);
>> -               write_phy_reg(pi, 0x43b, afectrlovr_old);
>> -               write_phy_reg(pi, 0x43c, afectrlovrval_old);
>> -               write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
>> -               write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
>> +       write_phy_reg(pi, 0x631, Core1TxControl_old);
>> +
>> +       write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
>> +       write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
>> +       write_phy_reg(pi, 0x4b0, rfoverride2_old);
>> +       write_phy_reg(pi, 0x4b1, rfoverride2val_old);
>> +       write_phy_reg(pi, 0x4f9, rfoverride3_old);
>> +       write_phy_reg(pi, 0x4fa, rfoverride3val_old);
>> +       write_phy_reg(pi, 0x938, rfoverride4_old);
>> +       write_phy_reg(pi, 0x939, rfoverride4val_old);
>> +       write_phy_reg(pi, 0x43b, afectrlovr_old);
>> +       write_phy_reg(pi, 0x43c, afectrlovrval_old);
>> +       write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
>> +       write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
>>
>> -               wlc_lcnphy_clear_trsw_override(pi);
>> +       wlc_lcnphy_clear_trsw_override(pi);
>>
>> -               mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
>> +       mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
>>
>> -               for (i = 0; i < 11; i++)
>> -                       write_radio_reg(pi, rxiq_cal_rf_reg[i],
>> -                                       values_to_save[i]);
>> +       for (i = 0; i < 11; i++)
>> +               write_radio_reg(pi, rxiq_cal_rf_reg[i],
>> +                               values_to_save[i]);
>>
>> -               if (tx_gain_override_old)
>> -                       wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
>> -               else
>> -                       wlc_lcnphy_disable_tx_gain_override(pi);
>> +       if (tx_gain_override_old)
>> +               wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
>> +       else
>> +               wlc_lcnphy_disable_tx_gain_override(pi);
>>
>> -               wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
>> -               wlc_lcnphy_rx_gain_override_enable(pi, false);
>> -       }
>> +       wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
>> +       wlc_lcnphy_rx_gain_override_enable(pi, false);
>>
>>   cal_done:
>>          kfree(ptr);
>> @@ -1789,6 +1835,17 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
>>                  write_radio_reg(pi, RADIO_2064_REG038, 3);
>>                  write_radio_reg(pi, RADIO_2064_REG091, 7);
>>          }
>> +
>> +       if (!(pi->sh->boardflags & BFL_FEM)) {
>> +               u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc,
>> +                       0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0};
>> +
>> +               write_radio_reg(pi, RADIO_2064_REG02A, 0xf);
>> +               write_radio_reg(pi, RADIO_2064_REG091, 0x3);
>> +               write_radio_reg(pi, RADIO_2064_REG038, 0x3);
>> +
>> +               write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);
>> +       }
>>   }
>>
>>   static int
>> @@ -1983,6 +2040,16 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
>>                  } else {
>>                          mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
>>                          mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
>> +                       mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);
>> +                       mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);
>> +                       mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);
>> +                       mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);
>> +                       mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
>> +                       mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);
>> +                       mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);
>> +                       mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);
>> +                       mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);
>> +                       mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);
>
> What does this do? This seems to be applied regardless of iPA or ePA,
> so I looks like it fixes something? Or is this needed for iPA and
> harmless for ePA?

When reviewing this patch that was one of my comments as well. It was 
added because the iPA changes were ported from a more recent branch of 
our internal driver.

What changed is the TSSI algorithm for both ePA and iPA. I will try to 
create a separate patch for that for ePA. Most of the comments below are 
related to this.

>>                  }
>>          } else {
>>                  mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
>> @@ -2069,12 +2136,14 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
>>                      (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
>>
>>          mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
>> +       mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));
>
> Same here.
>
>>   }
>>
>>   static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
>>   {
>>          struct phytbl_info tab;
>>          u32 rfseq, ind;
>> +       u8 tssi_sel;
>>
>>          tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
>>          tab.tbl_width = 32;
>> @@ -2096,7 +2165,13 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
>>
>>          mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
>>
>> -       wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
>> +       if (pi->sh->boardflags & BFL_FEM) {
>> +               tssi_sel = 0x1;
>> +               wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
>> +       } else {
>> +               tssi_sel = 0xe;
>> +               wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA);
>> +       }
>
> Doesn't this change change tssi_sel from 0xe to 0x1 for (already
> supported) ePA cards, and sets it to the old value 0xe for iPA ones? I
> would have expected 0xe for BFL_FEM /ePA and 0x1 for iPA ... .
>
>>          mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
>>
>>          mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
>> @@ -2132,9 +2207,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
>>          mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
>>
>>          if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
>> -               mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
>> +               mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);
>>                  mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
>>          } else {
>> +               mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);
>
> Okay, this one is new also for the ePA case, so I wonder why this
> wasn't needed before?
>
>>                  mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
>>                  mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
>>          }
>> @@ -2181,6 +2257,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
>>
>>          mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
>>
>> +       mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);
>> +       mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
>> +       mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
>> +
>
> Same for these three writes.
>
>>          wlc_lcnphy_pwrctrl_rssiparams(pi);
>>   }
>>
>> @@ -2799,6 +2879,8 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
>>                  read_radio_reg(pi, RADIO_2064_REG007) & 1;
>>          u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
>>          u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
>> +       u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);
>> +
>
> These changes also look at a first glance unrelated to iPA, as well as ...
>
>>          idleTssi = read_phy_reg(pi, 0x4ab);
>>          suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
>>                           MCTL_EN_MAC));
>> @@ -2816,6 +2898,12 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
>>          mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
>>          mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
>>          wlc_lcnphy_tssi_setup(pi);
>> +
>> +       mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));
>> +       mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));
>> +
>> +       wlc_lcnphy_set_bbmult(pi, 0x0);
>> +
>
> These ones.
>
>>          wlc_phy_do_dummy_tx(pi, true, OFF);
>>          idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
>>                      >> 0);
>> @@ -2837,6 +2925,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
>>
>>          mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
>>
>> +       wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);
>>          wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
>>          wlc_lcnphy_set_tx_gain(pi, &old_gains);
>>          wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
>> @@ -3050,6 +3139,11 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
>>                          wlc_lcnphy_write_table(pi, &tab);
>>                          tab.tbl_offset++;
>>                  }
>> +               mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);
>> +               mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);
>> +               mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);
>> +               mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);
>> +               mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);
>>
>>                  mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
>>
>> @@ -3851,7 +3945,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
>>          target_gains.pad_gain = 21;
>>          target_gains.dac_gain = 0;
>>          wlc_lcnphy_set_tx_gain(pi, &target_gains);
>> -       wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
>>
>>          if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
>>
>> @@ -3862,6 +3955,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
>>                                          lcnphy_recal ? LCNPHY_CAL_RECAL :
>>                                          LCNPHY_CAL_FULL), false);
>>          } else {
>> +               wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
>>                  wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
>>          }
>>
>> @@ -4286,17 +4380,22 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
>>          if (CHSPEC_IS5G(pi->radio_chanspec))
>>                  pa_gain = 0x70;
>>          else
>> -               pa_gain = 0x70;
>> +               pa_gain = 0x60;
>
> You are reducing the value for !BFL_FEM, I assume this is a fix for something?

Your guess is as good as mine. Internally, we get phy code deliveries 
from system engineering team and unfortunately the changelog is pretty 
high-level.

>>
>>          if (pi->sh->boardflags & BFL_FEM)
>>                  pa_gain = 0x10;
>> +
>
> Unnecessary whitespace change.

Probably, Whitespace jEdit plugin did that for me. Sorry about that.

>>          tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
>>          tab.tbl_width = 32;
>>          tab.tbl_len = 1;
>>          tab.tbl_ptr = &val;
>>
>>          for (j = 0; j < 128; j++) {
>> -               gm_gain = gain_table[j].gm;
>> +               if (pi->sh->boardflags & BFL_FEM)
>> +                       gm_gain = gain_table[j].gm;
>> +               else
>> +                       gm_gain = 15;
>> +
>>                  val = (((u32) pa_gain << 24) |
>>                         (gain_table[j].pad << 16) |
>>                         (gain_table[j].pga << 8) | gm_gain);
>> @@ -4507,7 +4606,10 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)
>>
>>          write_phy_reg(pi, 0x4ea, 0x4688);
>>
>> -       mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
>> +       if (pi->sh->boardflags & BFL_FEM)
>> +               mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
>> +       else
>> +               mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
>>
>>          mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
>>
>> @@ -4518,6 +4620,13 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)
>>          wlc_lcnphy_rcal(pi);
>>
>>          wlc_lcnphy_rc_cal(pi);
>> +
>> +       if (!(pi->sh->boardflags & BFL_FEM)) {
>> +               write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
>> +               write_radio_reg(pi, RADIO_2064_REG033, 0x19);
>> +               write_radio_reg(pi, RADIO_2064_REG039, 0xe);
>> +       }
>> +
>>   }
>>
>>   static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
>> @@ -4530,6 +4639,7 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
>>          uint idx;
>>          u8 phybw40;
>>          struct phytbl_info tab;
>> +       const struct phytbl_info *tb;
>>          u32 val;
>>
>>          phybw40 = CHSPEC_IS40(pi->radio_chanspec);
>> @@ -4547,22 +4657,20 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
>>                  wlc_lcnphy_write_table(pi, &tab);
>>          }
>>
>> -       tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
>> -       tab.tbl_width = 16;
>> -       tab.tbl_ptr = &val;
>> -       tab.tbl_len = 1;
>> -
>> -       val = 114;
>> -       tab.tbl_offset = 0;
>> -       wlc_lcnphy_write_table(pi, &tab);
>> +       if (!(pi->sh->boardflags & BFL_FEM)) {
>> +               tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
>> +               tab.tbl_width = 16;
>> +               tab.tbl_ptr = &val;
>> +               tab.tbl_len = 1;
>>
>> -       val = 130;
>> -       tab.tbl_offset = 1;
>> -       wlc_lcnphy_write_table(pi, &tab);
>> +               val = 150;
>> +               tab.tbl_offset = 0;
>> +               wlc_lcnphy_write_table(pi, &tab);
>>
>> -       val = 6;
>> -       tab.tbl_offset = 8;
>> -       wlc_lcnphy_write_table(pi, &tab);
>> +               val = 220;
>> +               tab.tbl_offset = 1;
>> +               wlc_lcnphy_write_table(pi, &tab);
>> +       }
>
> So this isn't needed anymore for ePA cards?

Suspicious. I will look into this one.

>>
>>          if (CHSPEC_IS2G(pi->radio_chanspec)) {
>>                  if (pi->sh->boardflags & BFL_FEM)
>> @@ -4576,7 +4684,6 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
>>          }
>>
>>          if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
>> -               const struct phytbl_info *tb;
>>                  int l;
>>
>>                  if (CHSPEC_IS2G(pi->radio_chanspec)) {
>> @@ -4597,21 +4704,22 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
>>                          wlc_lcnphy_write_table(pi, &tb[idx]);
>>          }
>>
>> -       if ((pi->sh->boardflags & BFL_FEM)
>> -           && !(pi->sh->boardflags & BFL_FEM_BT))
>> -               wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
>> -       else if (pi->sh->boardflags & BFL_FEM_BT) {
>> -               if (pi->sh->boardrev < 0x1250)
>> -                       wlc_lcnphy_write_table(
>> -                               pi,
>> -                               &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
>> +       if (pi->sh->boardflags & BFL_FEM) {
>> +               if (pi->sh->boardflags & BFL_FEM_BT) {
>> +                       if (pi->sh->boardrev < 0x1250)
>> +                               tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
>> +                       else
>> +                               tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
>> +               } else {
>> +                       tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;
>> +               }
>> +       } else {
>> +               if (pi->sh->boardflags & BFL_FEM_BT)
>> +                       tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;
>>                  else
>> -                       wlc_lcnphy_write_table(
>> -                               pi,
>> -                               &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
>> -       } else
>> -               wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
>> -
>> +                       tb = &dot11lcn_sw_ctrl_tbl_info_4313;
>> +       }
>> +       wlc_lcnphy_write_table(pi, tb);
>>          wlc_lcnphy_load_rfpower(pi);
>>
>>          wlc_lcnphy_clear_papd_comptable(pi);
>> @@ -4955,6 +5063,8 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
>>                  wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
>>
>>          mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
>> +       if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
>> +               wlc_lcnphy_tssi_setup(pi);
>>   }
>>
>>   void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
>> @@ -4993,8 +5103,7 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
>>          if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
>>                  return false;
>>
>> -       if ((pi->sh->boardflags & BFL_FEM) &&
>> -           (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
>> +       if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
>>                  if (pi_lcn->lcnphy_tempsense_option == 3) {
>>                          pi->hwpwrctrl = true;
>>                          pi->hwpwrctrl_capable = true;
>> diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
>> index 622c01c..9fb0ca2 100644
>> --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
>> +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
>> @@ -2058,6 +2058,73 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
>>          0x0005,
>>   };
>>
>> +static const u16 dot11lcn_sw_ctrl_tbl_4313_ipa_rev0_combo[] = {
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +       0x0005,
>> +       0x0006,
>> +       0x0009,
>> +       0x000a,
>> +};
>> +
>>   static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
>>          0x0004,
>>          0x0004,
>> @@ -2834,6 +2901,12 @@ const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313 = {
>>          sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0[0]), 15, 0, 16
>>   };
>>
>> +const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa = {
>> +       &dot11lcn_sw_ctrl_tbl_4313_ipa_rev0_combo,
>> +       sizeof(dot11lcn_sw_ctrl_tbl_4313_ipa_rev0_combo) /
>> +       sizeof(dot11lcn_sw_ctrl_tbl_4313_ipa_rev0_combo[0]), 15, 0, 16
>
> Not necessarily in this patch but maybe in a follow up cleanup patch:
> ARRAY_SIZE() please?

As I am reworking the patch, I will incorporate this comment as well.

>
>
> I guess that's it from me.

Thanks again,
Arend



^ permalink raw reply

* [RFC 15/15] ath9k: Remove unused function argument
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a00e1b6..49e9cce 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -885,7 +885,6 @@ static int ath9k_process_rate(struct ath_common *common,
 
 static void ath9k_process_rssi(struct ath_common *common,
 			       struct ieee80211_hw *hw,
-			       struct ieee80211_hdr *hdr,
 			       struct ath_rx_status *rx_stats)
 {
 	struct ath_softc *sc = hw->priv;
@@ -1150,7 +1149,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 		ath_start_rx_poll(sc, 3);
 	}
 
-	ath9k_process_rssi(common, hw, hdr, rx_stats);
+	ath9k_process_rssi(common, hw, rx_stats);
 
 	rx_status->band = hw->conf.chandef.chan->band;
 	rx_status->freq = hw->conf.chandef.chan->center_freq;
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 14/15] ath9k: Fix error condition for corrupt descriptors
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

In case a descriptor has the "done" bit clear and the
next descriptor has it set, we drop both of them. If
the packet that is received after these two packets
is dropped for some reason, "discard_next" will not cleared.
Fix this.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 0965bf6..a00e1b6 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1068,6 +1068,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ieee80211_hdr *hdr;
 	bool discard_current = sc->rx.discard_next;
+	int ret = 0;
 
 	/*
 	 * Discard corrupt descriptors which are marked in
@@ -1106,8 +1107,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	 * This is different from the other corrupt descriptor
 	 * condition handled above.
 	 */
-	if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
-		return -EINVAL;
+	if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
+		ret = -EINVAL;
+		goto exit;
+	}
 
 	hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
 
@@ -1123,18 +1126,23 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 		if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
 			RX_STAT_INC(rx_spectral);
 
-		return -EINVAL;
+		ret = -EINVAL;
+		goto exit;
 	}
 
 	/*
 	 * everything but the rate is checked here, the rate check is done
 	 * separately to avoid doing two lookups for a rate for each frame.
 	 */
-	if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
-		return -EINVAL;
+	if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) {
+		ret = -EINVAL;
+		goto exit;
+	}
 
-	if (ath9k_process_rate(common, hw, rx_stats, rx_status))
-		return -EINVAL;
+	if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
+		ret = -EINVAL;
+		goto exit;
+	}
 
 	rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr);
 	if (rx_stats->is_mybeacon) {
@@ -1152,15 +1160,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	if (rx_stats->rs_moreaggr)
 		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
 
-	sc->rx.discard_next = false;
-
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	if (ieee80211_is_data_present(hdr->frame_control) &&
 	    !ieee80211_is_qos_nullfunc(hdr->frame_control))
 		sc->rx.num_pkts++;
 #endif
 
-	return 0;
+exit:
+	sc->rx.discard_next = false;
+	return ret;
 }
 
 static void ath9k_rx_skb_postprocess(struct ath_common *common,
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 13/15] ath9k: Handle corrupt descriptors properly
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

The MIC/PHYERR/CRC error bits are valid only for
the last desc. for chained packets. Check this early
in the preprocess() routine and bail out.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 7f327e9..0965bf6 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1099,6 +1099,16 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	if (rx_stats->rs_more)
 		return 0;
 
+	/*
+	 * Return immediately if the RX descriptor has been marked
+	 * as corrupt based on the various error bits.
+	 *
+	 * This is different from the other corrupt descriptor
+	 * condition handled above.
+	 */
+	if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
+		return -EINVAL;
+
 	hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
 
 	ath9k_process_tsf(rx_stats, rx_status, tsf);
@@ -1335,8 +1345,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 			sc->rx.frag = skb;
 			goto requeue;
 		}
-		if (rs.rs_status & ATH9K_RXERR_CORRUPT_DESC)
-			goto requeue_drop_frag;
 
 		if (sc->rx.frag) {
 			int space = skb->len - skb_tailroom(hdr_skb);
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 12/15] ath9k: Move the RX poll check to preprocess()
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 44f5a2b..7f327e9 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1127,6 +1127,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 		return -EINVAL;
 
 	rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr);
+	if (rx_stats->is_mybeacon) {
+		sc->hw_busy_count = 0;
+		ath_start_rx_poll(sc, 3);
+	}
+
 	ath9k_process_rssi(common, hw, hdr, rx_stats);
 
 	rx_status->band = hw->conf.chandef.chan->band;
@@ -1277,10 +1282,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		if (retval)
 			goto requeue_drop_frag;
 
-		if (rs.is_mybeacon) {
-			sc->hw_busy_count = 0;
-			ath_start_rx_poll(sc, 3);
-		}
 		/* Ensure we always have an skb to requeue once we are done
 		 * processing the current buffer's skb */
 		requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 11/15] ath9k: Fix RX beacon processing
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

Make sure that chained descriptors are handled correctly
before the packet is parsed to determine if it is a beacon.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 47 ++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 26 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 823b411..44f5a2b 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1037,13 +1037,28 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 #endif
 }
 
+static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (ieee80211_is_beacon(hdr->frame_control)) {
+		RX_STAT_INC(rx_beacons);
+		if (!is_zero_ether_addr(common->curbssid) &&
+		    ether_addr_equal(hdr->addr3, common->curbssid))
+			return true;
+	}
+
+	return false;
+}
+
 /*
  * For Decrypt or Demic errors, we only mark packet status here and always push
  * up the frame up to let mac80211 handle the actual error case, be it no
  * decryption key or real decryption error. This let us keep statistics there.
  */
 static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
-				   struct ieee80211_hdr *hdr,
+				   struct sk_buff *skb,
 				   struct ath_rx_status *rx_stats,
 				   struct ieee80211_rx_status *rx_status,
 				   bool *decrypt_error, u64 tsf)
@@ -1051,6 +1066,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	struct ieee80211_hw *hw = sc->hw;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ieee80211_hdr *hdr;
 	bool discard_current = sc->rx.discard_next;
 
 	/*
@@ -1083,6 +1099,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	if (rx_stats->rs_more)
 		return 0;
 
+	hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
+
 	ath9k_process_tsf(rx_stats, rx_status, tsf);
 	ath_debug_stat_rx(sc, rx_stats);
 
@@ -1108,6 +1126,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	if (ath9k_process_rate(common, hw, rx_stats, rx_status))
 		return -EINVAL;
 
+	rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr);
 	ath9k_process_rssi(common, hw, hdr, rx_stats);
 
 	rx_status->band = hw->conf.chandef.chan->band;
@@ -1198,24 +1217,6 @@ static void ath9k_apply_ampdu_details(struct ath_softc *sc,
 	}
 }
 
-static bool ath9k_is_mybeacon(struct ath_softc *sc, struct sk_buff *skb)
-{
-	struct ath_hw *ah = sc->sc_ah;
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ieee80211_hdr *hdr;
-
-	hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
-
-	if (ieee80211_is_beacon(hdr->frame_control)) {
-		RX_STAT_INC(rx_beacons);
-		if (!is_zero_ether_addr(common->curbssid) &&
-		    ether_addr_equal(hdr->addr3, common->curbssid))
-			return true;
-	}
-
-	return false;
-}
-
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
 	struct ath_buf *bf;
@@ -1225,7 +1226,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 	struct ath9k_hw_capabilities *pCap = &ah->caps;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_hdr *hdr;
 	int retval;
 	struct ath_rx_status rs;
 	enum ath9k_rx_qtype qtype;
@@ -1269,15 +1269,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		else
 			hdr_skb = skb;
 
-		rs.is_mybeacon = ath9k_is_mybeacon(sc, hdr_skb);
-
-		hdr = (struct ieee80211_hdr *) (hdr_skb->data +
-						ah->caps.rx_status_len);
-
 		rxs = IEEE80211_SKB_RXCB(hdr_skb);
 		memset(rxs, 0, sizeof(struct ieee80211_rx_status));
 
-		retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs,
+		retval = ath9k_rx_skb_preprocess(sc, hdr_skb, &rs, rxs,
 						 &decrypt_error, tsf);
 		if (retval)
 			goto requeue_drop_frag;
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 10/15] ath9k: Fix RX packet counter
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

Handle chained descriptors and increment the RX counter
only for valid packets. Since this is used only by MCI,
use CONFIG_ATH9K_BTCOEX_SUPPORT.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 2d0017c..823b411 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1119,6 +1119,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
 
 	sc->rx.discard_next = false;
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+	if (ieee80211_is_data_present(hdr->frame_control) &&
+	    !ieee80211_is_qos_nullfunc(hdr->frame_control))
+		sc->rx.num_pkts++;
+#endif
+
 	return 0;
 }
 
@@ -1267,10 +1274,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		hdr = (struct ieee80211_hdr *) (hdr_skb->data +
 						ah->caps.rx_status_len);
 
-		if (ieee80211_is_data_present(hdr->frame_control) &&
-		    !ieee80211_is_qos_nullfunc(hdr->frame_control))
-			sc->rx.num_pkts++;
-
 		rxs = IEEE80211_SKB_RXCB(hdr_skb);
 		memset(rxs, 0, sizeof(struct ieee80211_rx_status));
 
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 09/15] ath9k: Fix RX debug statistics
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

The various error bits that ath_debug_stat_rx()
checks are valid only for the last descriptor for
a chained packet, handle this correctly.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index e18adde..2d0017c 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1084,6 +1084,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 		return 0;
 
 	ath9k_process_tsf(rx_stats, rx_status, tsf);
+	ath_debug_stat_rx(sc, rx_stats);
 
 	/*
 	 * Process PHY errors and return so that the packet
@@ -1270,8 +1271,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		    !ieee80211_is_qos_nullfunc(hdr->frame_control))
 			sc->rx.num_pkts++;
 
-		ath_debug_stat_rx(sc, &rs);
-
 		rxs = IEEE80211_SKB_RXCB(hdr_skb);
 		memset(rxs, 0, sizeof(struct ieee80211_rx_status));
 
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 08/15] ath9k: Fix PHY error processing
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

Parse the PHY error details only for the last fragment
in case descriptors are chained.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 51e7d16..e18adde 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -803,8 +803,6 @@ static bool ath9k_rx_accept(struct ath_common *common,
 			rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
 			mic_error = false;
 		}
-		if (rx_stats->rs_status & ATH9K_RXERR_PHY)
-			return false;
 
 		if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) ||
 		    (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) {
@@ -1088,6 +1086,18 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	ath9k_process_tsf(rx_stats, rx_status, tsf);
 
 	/*
+	 * Process PHY errors and return so that the packet
+	 * can be dropped.
+	 */
+	if (rx_stats->rs_status & ATH9K_RXERR_PHY) {
+		ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime);
+		if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
+			RX_STAT_INC(rx_spectral);
+
+		return -EINVAL;
+	}
+
+	/*
 	 * everything but the rate is checked here, the rate check is done
 	 * separately to avoid doing two lookups for a rate for each frame.
 	 */
@@ -1265,15 +1275,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		rxs = IEEE80211_SKB_RXCB(hdr_skb);
 		memset(rxs, 0, sizeof(struct ieee80211_rx_status));
 
-		if (rs.rs_status & ATH9K_RXERR_PHY) {
-			ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime);
-
-			if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) {
-				RX_STAT_INC(rx_spectral);
-				goto requeue_drop_frag;
-			}
-		}
-
 		retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs,
 						 &decrypt_error, tsf);
 		if (retval)
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 07/15] ath9k: Reorder some functions
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 220 +++++++++++++++++-----------------
 1 file changed, 110 insertions(+), 110 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 9fabd5f..51e7d16 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -929,6 +929,116 @@ static void ath9k_process_tsf(struct ath_rx_status *rs,
 		rxs->mactime += 0x100000000ULL;
 }
 
+#ifdef CONFIG_ATH9K_DEBUGFS
+static s8 fix_rssi_inv_only(u8 rssi_val)
+{
+	if (rssi_val == 128)
+		rssi_val = 0;
+	return (s8) rssi_val;
+}
+#endif
+
+/* returns 1 if this was a spectral frame, even if not handled. */
+static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
+			   struct ath_rx_status *rs, u64 tsf)
+{
+#ifdef CONFIG_ATH9K_DEBUGFS
+	struct ath_hw *ah = sc->sc_ah;
+	u8 bins[SPECTRAL_HT20_NUM_BINS];
+	u8 *vdata = (u8 *)hdr;
+	struct fft_sample_ht20 fft_sample;
+	struct ath_radar_info *radar_info;
+	struct ath_ht20_mag_info *mag_info;
+	int len = rs->rs_datalen;
+	int dc_pos;
+	u16 length, max_magnitude;
+
+	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
+	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
+	 * yet, but this is supposed to be possible as well.
+	 */
+	if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
+	    rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
+	    rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
+		return 0;
+
+	/* check if spectral scan bit is set. This does not have to be checked
+	 * if received through a SPECTRAL phy error, but shouldn't hurt.
+	 */
+	radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
+	if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
+		return 0;
+
+	/* Variation in the data length is possible and will be fixed later.
+	 * Note that we only support HT20 for now.
+	 *
+	 * TODO: add HT20_40 support as well.
+	 */
+	if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
+	    (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
+		return 1;
+
+	fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
+	length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
+	fft_sample.tlv.length = __cpu_to_be16(length);
+
+	fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
+	fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
+	fft_sample.noise = ah->noise;
+
+	switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
+	case 0:
+		/* length correct, nothing to do. */
+		memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
+		break;
+	case -1:
+		/* first byte missing, duplicate it. */
+		memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
+		bins[0] = vdata[0];
+		break;
+	case 2:
+		/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
+		memcpy(bins, vdata, 30);
+		bins[30] = vdata[31];
+		memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
+		break;
+	case 1:
+		/* MAC added 2 extra bytes AND first byte is missing. */
+		bins[0] = vdata[0];
+		memcpy(&bins[0], vdata, 30);
+		bins[31] = vdata[31];
+		memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
+		break;
+	default:
+		return 1;
+	}
+
+	/* DC value (value in the middle) is the blind spot of the spectral
+	 * sample and invalid, interpolate it.
+	 */
+	dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+	bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
+
+	/* mag data is at the end of the frame, in front of radar_info */
+	mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
+
+	/* copy raw bins without scaling them */
+	memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS);
+	fft_sample.max_exp = mag_info->max_exp & 0xf;
+
+	max_magnitude = spectral_max_magnitude(mag_info->all_bins);
+	fft_sample.max_magnitude = __cpu_to_be16(max_magnitude);
+	fft_sample.max_index = spectral_max_index(mag_info->all_bins);
+	fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
+	fft_sample.tsf = __cpu_to_be64(tsf);
+
+	ath_debug_send_fft_sample(sc, &fft_sample.tlv);
+	return 1;
+#else
+	return 0;
+#endif
+}
+
 /*
  * For Decrypt or Demic errors, we only mark packet status here and always push
  * up the frame up to let mac80211 handle the actual error case, be it no
@@ -1052,116 +1162,6 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
 		rxs->flag &= ~RX_FLAG_DECRYPTED;
 }
 
-#ifdef CONFIG_ATH9K_DEBUGFS
-static s8 fix_rssi_inv_only(u8 rssi_val)
-{
-	if (rssi_val == 128)
-		rssi_val = 0;
-	return (s8) rssi_val;
-}
-#endif
-
-/* returns 1 if this was a spectral frame, even if not handled. */
-static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
-			   struct ath_rx_status *rs, u64 tsf)
-{
-#ifdef CONFIG_ATH9K_DEBUGFS
-	struct ath_hw *ah = sc->sc_ah;
-	u8 bins[SPECTRAL_HT20_NUM_BINS];
-	u8 *vdata = (u8 *)hdr;
-	struct fft_sample_ht20 fft_sample;
-	struct ath_radar_info *radar_info;
-	struct ath_ht20_mag_info *mag_info;
-	int len = rs->rs_datalen;
-	int dc_pos;
-	u16 length, max_magnitude;
-
-	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
-	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
-	 * yet, but this is supposed to be possible as well.
-	 */
-	if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
-	    rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
-	    rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
-		return 0;
-
-	/* check if spectral scan bit is set. This does not have to be checked
-	 * if received through a SPECTRAL phy error, but shouldn't hurt.
-	 */
-	radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
-	if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
-		return 0;
-
-	/* Variation in the data length is possible and will be fixed later.
-	 * Note that we only support HT20 for now.
-	 *
-	 * TODO: add HT20_40 support as well.
-	 */
-	if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
-	    (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
-		return 1;
-
-	fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
-	length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
-	fft_sample.tlv.length = __cpu_to_be16(length);
-
-	fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
-	fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
-	fft_sample.noise = ah->noise;
-
-	switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
-	case 0:
-		/* length correct, nothing to do. */
-		memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
-		break;
-	case -1:
-		/* first byte missing, duplicate it. */
-		memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
-		bins[0] = vdata[0];
-		break;
-	case 2:
-		/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
-		memcpy(bins, vdata, 30);
-		bins[30] = vdata[31];
-		memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
-		break;
-	case 1:
-		/* MAC added 2 extra bytes AND first byte is missing. */
-		bins[0] = vdata[0];
-		memcpy(&bins[0], vdata, 30);
-		bins[31] = vdata[31];
-		memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
-		break;
-	default:
-		return 1;
-	}
-
-	/* DC value (value in the middle) is the blind spot of the spectral
-	 * sample and invalid, interpolate it.
-	 */
-	dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
-	bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
-
-	/* mag data is at the end of the frame, in front of radar_info */
-	mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
-
-	/* copy raw bins without scaling them */
-	memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS);
-	fft_sample.max_exp = mag_info->max_exp & 0xf;
-
-	max_magnitude = spectral_max_magnitude(mag_info->all_bins);
-	fft_sample.max_magnitude = __cpu_to_be16(max_magnitude);
-	fft_sample.max_index = spectral_max_index(mag_info->all_bins);
-	fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
-	fft_sample.tsf = __cpu_to_be64(tsf);
-
-	ath_debug_send_fft_sample(sc, &fft_sample.tlv);
-	return 1;
-#else
-	return 0;
-#endif
-}
-
 static void ath9k_apply_ampdu_details(struct ath_softc *sc,
 	struct ath_rx_status *rs, struct ieee80211_rx_status *rxs)
 {
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 06/15] ath9k: Fix TSF processing
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

There is no need to calculate the mactime for chained
descriptor packets, so make sure that this is done
only for the last fragment of valid packets.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index b04a971..9fabd5f 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -913,6 +913,22 @@ static void ath9k_process_rssi(struct ath_common *common,
 	ah->stats.avgbrssi = rssi;
 }
 
+static void ath9k_process_tsf(struct ath_rx_status *rs,
+			      struct ieee80211_rx_status *rxs,
+			      u64 tsf)
+{
+	u32 tsf_lower = tsf & 0xffffffff;
+
+	rxs->mactime = (tsf & ~0xffffffffULL) | rs->rs_tstamp;
+	if (rs->rs_tstamp > tsf_lower &&
+	    unlikely(rs->rs_tstamp - tsf_lower > 0x10000000))
+		rxs->mactime -= 0x100000000ULL;
+
+	if (rs->rs_tstamp < tsf_lower &&
+	    unlikely(tsf_lower - rs->rs_tstamp > 0x10000000))
+		rxs->mactime += 0x100000000ULL;
+}
+
 /*
  * For Decrypt or Demic errors, we only mark packet status here and always push
  * up the frame up to let mac80211 handle the actual error case, be it no
@@ -922,7 +938,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 				   struct ieee80211_hdr *hdr,
 				   struct ath_rx_status *rx_stats,
 				   struct ieee80211_rx_status *rx_status,
-				   bool *decrypt_error)
+				   bool *decrypt_error, u64 tsf)
 {
 	struct ieee80211_hw *hw = sc->hw;
 	struct ath_hw *ah = sc->sc_ah;
@@ -959,6 +975,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	if (rx_stats->rs_more)
 		return 0;
 
+	ath9k_process_tsf(rx_stats, rx_status, tsf);
+
 	/*
 	 * everything but the rate is checked here, the rate check is done
 	 * separately to avoid doing two lookups for a rate for each frame.
@@ -1196,7 +1214,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
 	int dma_type;
 	u64 tsf = 0;
-	u32 tsf_lower = 0;
 	unsigned long flags;
 	dma_addr_t new_buf_addr;
 
@@ -1208,7 +1225,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 	qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
 
 	tsf = ath9k_hw_gettsf64(ah);
-	tsf_lower = tsf & 0xffffffff;
 
 	do {
 		bool decrypt_error = false;
@@ -1249,15 +1265,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		rxs = IEEE80211_SKB_RXCB(hdr_skb);
 		memset(rxs, 0, sizeof(struct ieee80211_rx_status));
 
-		rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
-		if (rs.rs_tstamp > tsf_lower &&
-		    unlikely(rs.rs_tstamp - tsf_lower > 0x10000000))
-			rxs->mactime -= 0x100000000ULL;
-
-		if (rs.rs_tstamp < tsf_lower &&
-		    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
-			rxs->mactime += 0x100000000ULL;
-
 		if (rs.rs_status & ATH9K_RXERR_PHY) {
 			ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime);
 
@@ -1268,7 +1275,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		}
 
 		retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs,
-						 &decrypt_error);
+						 &decrypt_error, tsf);
 		if (retval)
 			goto requeue_drop_frag;
 
-- 
1.8.3.4


^ permalink raw reply related

* [RFC 05/15] ath9k: Fix RX crypto processing
From: Sujith Manoharan @ 2013-08-12  9:41 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1376300502-2741-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha@qca.qualcomm.com>

The keymiss events are valid only in the last descriptor
of a packet. Fix this by making sure that we return
early in case of chained descriptors.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath9k/recv.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index f8cc2b3..b04a971 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -785,10 +785,6 @@ static bool ath9k_rx_accept(struct ath_common *common,
 	    !test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
 		rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
 
-	/* Only use error bits from the last fragment */
-	if (rx_stats->rs_more)
-		return true;
-
 	mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) &&
 		!ieee80211_has_morefrags(fc) &&
 		!(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
@@ -959,6 +955,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 		return -EINVAL;
 	}
 
+	/* Only use status info from the last fragment */
+	if (rx_stats->rs_more)
+		return 0;
+
 	/*
 	 * everything but the rate is checked here, the rate check is done
 	 * separately to avoid doing two lookups for a rate for each frame.
@@ -966,10 +966,6 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 	if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
 		return -EINVAL;
 
-	/* Only use status info from the last fragment */
-	if (rx_stats->rs_more)
-		return 0;
-
 	if (ath9k_process_rate(common, hw, rx_stats, rx_status))
 		return -EINVAL;
 
-- 
1.8.3.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox