Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 0/5 V2] Updates to match latest Realtek version and new PM framework
From: Larry Finger @ 2011-10-12  2:28 UTC (permalink / raw)
  To: linville; +Cc: Larry Finger, linux-wireless

The latest Realtek driver for rtl8192ce, rtl8192se, and rtl8192de incorporates
some changes. With these patches, the changes are added to the mainline
drivers. In addition, the drivers are changed to the new PM framework.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---

John,

V1 of these patches had been applied to git://git.infradead.org/users/linville/wireless-testing.git.

I had committed them to my local tree and let git generate the patches. For V2, I switched to
git://git.infradead.org/users/linville/wireless-next.git. A pull on the new tree got the objects
from the for-davem branch, but master was unchanged. I reverted all 5 from my tree, imported the
patches with quilt and cleaned them up. They all apply cleanly with no warnings and no fuzz.

If I understood your mail message correctly, patches 1, 2, 3, and 5 have already been applied,
but I'm sending a new version just in case. Patches 4 and 5 can be applied in any order - thus
4 will work by itself.

Sorry for any problems.

Larry
---

Chaoming Li (4):
  rtlwifi: Update to new Realtek version - Part I
  rtlwifi: rtl8192ce: Add new chip revisions
  rtlwifi: rtl8192se: Updates from latest Realtek driver version - Part
    II
  rtlwifi: rtl8192de: Updates from latest Reaktek driver - Part III

Larry Finger (1):
  rtlwifi: Change PCI drivers to use the new PM framework

 drivers/net/wireless/rtlwifi/base.c          |    6 +-
 drivers/net/wireless/rtlwifi/pci.c           |   19 +---
 drivers/net/wireless/rtlwifi/pci.h           |    4 +-
 drivers/net/wireless/rtlwifi/rtl8192ce/def.h |   14 +++
 drivers/net/wireless/rtlwifi/rtl8192ce/sw.c  |   30 +++++--
 drivers/net/wireless/rtlwifi/rtl8192cu/def.h |    4 -
 drivers/net/wireless/rtlwifi/rtl8192de/def.h |  124 ++++++++++++++++----------
 drivers/net/wireless/rtlwifi/rtl8192de/hw.c  |   19 ++---
 drivers/net/wireless/rtlwifi/rtl8192de/sw.c  |   16 ++--
 drivers/net/wireless/rtlwifi/rtl8192se/hw.c  |   22 +++---
 drivers/net/wireless/rtlwifi/rtl8192se/reg.h |    1 +
 drivers/net/wireless/rtlwifi/rtl8192se/sw.c  |   17 +++--
 drivers/net/wireless/rtlwifi/rtl8192se/trx.c |   53 +++++++-----
 drivers/net/wireless/rtlwifi/wifi.h          |    1 +
 14 files changed, 196 insertions(+), 134 deletions(-)

-- 
1.7.6.4


^ permalink raw reply

* Re: [PATCH 4/5] rtlwifi: rtl8192se: Updates from latest Realtek driver version - Part II
From: Larry Finger @ 2011-10-12  1:52 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, Chaoming Li
In-Reply-To: <20111011201615.GK6558@tuxdriver.com>

On 10/11/2011 03:16 PM, John W. Linville wrote:
> On Fri, Oct 07, 2011 at 11:43:21AM -0500, Larry Finger wrote:
>> From: Chaoming Li<chaoming_li@realsil.com.cn>
>>
>> This patch incorporate the differences between the 06/20/2011 and
>> 08/16/2011 Realtek releases of the rtl8192se driver.
>>
>> The changes include:
>>
>> 1. Fixing some typos in register usage.
>> 2. A change in the handling of decryption status for 802.11w packets.
>>
>> Signed-off-by: Chaoming Li<chaoming_li@realsil.com.cn>
>> Signed-off-by: Larry Finger<Larry.Finger@lwfinger.net>
>
> This patch doesn't apply (at least on wireless-next), and several of
> the others required fixups as well.  What tree did you base this upon?

I thought it was wireless-next, but with all the disruptions lately, I may have 
messed up. I'll check it out and send you a new one.

Larry


^ permalink raw reply

* [RFC 07/07] mac80211: Do not call release_buffered_frames if not available.
From: Dmitry Tarnyagin @ 2011-10-12  1:02 UTC (permalink / raw)
  To: linux-wireless.vger.kernel.org; +Cc: Bartosz MARKOWSKI, Janusz DZIEDZIC

From: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
Date: Wed, 5 Oct 2011 13:20:04 +0200

A new .release_buffered_frames callback was introduced recently.
Check for the callback presence was missing in the mac80211 code,
and PM state could get broken in some cases.

Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
---
  net/mac80211/sta_info.c |    4 +++-
  1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 58b1c2b..ff30fe3 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1262,7 +1262,9 @@ ieee80211_sta_ps_deliver_response(struct sta_info  
*sta,
  		tids = ieee80211_tids_for_ac(ac);

  		if (!found) {
-			driver_release_tids = sta->driver_buffered_tids & tids;
+			if (local->ops->release_buffered_frames)
+				driver_release_tids =
+					sta->driver_buffered_tids & tids;
  			if (driver_release_tids) {
  				found = true;
  			} else {
-- 
1.7.1

^ permalink raw reply related

* [RFC 06/07] compat-wireless: UAPSD configuration in STA mode
From: Dmitry Tarnyagin @ 2011-10-12  1:02 UTC (permalink / raw)
  To: linux-wireless.vger.kernel.org; +Cc: Bartosz MARKOWSKI, Janusz DZIEDZIC

From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Date: Wed, 3 Aug 2011 09:46:05 +0200

This patch adds UAPSD queues configuration as a param to assoc request.
With the patch it's possible to configure UAPSD from user space.

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
---
  include/linux/nl80211.h |    2 ++
  include/net/cfg80211.h  |    1 +
  net/mac80211/main.c     |    3 ++-
  net/mac80211/mlme.c     |    2 ++
  net/wireless/core.h     |    6 ++++--
  net/wireless/mlme.c     |   10 +++++++---
  net/wireless/nl80211.c  |    7 ++++++-
  net/wireless/sme.c      |    2 +-
  8 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index a9bee60..74c5458 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1349,6 +1349,8 @@ enum nl80211_attrs {
  	NL80211_ATTR_P2P_PS_LEGACY_PS,
  	NL80211_ATTR_P2P_PS_OPP_PS,
  	NL80211_ATTR_P2P_PS_CTWINDOW,
+	NL80211_ATTR_UAPSD,
+
  	/* add attributes here, update the policy in nl80211.c */

  	__NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index c08e475..228194f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1050,6 +1050,7 @@ struct cfg80211_assoc_request {
  	size_t ie_len;
  	struct cfg80211_crypto_settings crypto;
  	bool use_mfp;
+	int uapsd;
  };

  /**
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index b9b9765..5f99907 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -630,7 +630,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t  
priv_data_len,
  	local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
  	local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
  	local->user_power_level = -1;
-	local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
+	/* Disable all UAPSD AC by default */
+	local->uapsd_queues = 0;
  	local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;

  	INIT_LIST_HEAD(&local->interfaces);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index dde286a..5116ee1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2754,6 +2754,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data  
*sdata,

  	if (bss->wmm_used && bss->uapsd_supported &&
  	    (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
+		if (req->uapsd != -1)
+			sdata->local->uapsd_queues = req->uapsd;
  		wk->assoc.uapsd_used = true;
  		ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
  	} else {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b9ec306..71763ae 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -339,13 +339,15 @@ int __cfg80211_mlme_assoc(struct  
cfg80211_registered_device *rdev,
  			  const u8 *bssid, const u8 *prev_bssid,
  			  const u8 *ssid, int ssid_len,
  			  const u8 *ie, int ie_len, bool use_mfp,
-			  struct cfg80211_crypto_settings *crypt);
+			  struct cfg80211_crypto_settings *crypt,
+			  int uapsd);
  int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
  			struct net_device *dev, struct ieee80211_channel *chan,
  			const u8 *bssid, const u8 *prev_bssid,
  			const u8 *ssid, int ssid_len,
  			const u8 *ie, int ie_len, bool use_mfp,
-			struct cfg80211_crypto_settings *crypt);
+			struct cfg80211_crypto_settings *crypt,
+			int uapsd);
  int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
  			   struct net_device *dev, const u8 *bssid,
  			   const u8 *ie, int ie_len, u16 reason,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 4194b3e..3a03fd2 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -507,7 +507,8 @@ int __cfg80211_mlme_assoc(struct  
cfg80211_registered_device *rdev,
  			  const u8 *bssid, const u8 *prev_bssid,
  			  const u8 *ssid, int ssid_len,
  			  const u8 *ie, int ie_len, bool use_mfp,
-			  struct cfg80211_crypto_settings *crypt)
+			  struct cfg80211_crypto_settings *crypt,
+			  int uapsd)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  	struct cfg80211_assoc_request req;
@@ -537,6 +538,7 @@ int __cfg80211_mlme_assoc(struct  
cfg80211_registered_device *rdev,
  	memcpy(&req.crypto, crypt, sizeof(req.crypto));
  	req.use_mfp = use_mfp;
  	req.prev_bssid = prev_bssid;
+	req.uapsd = uapsd;
  	req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
  				   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
  	if (!req.bss) {
@@ -574,14 +576,16 @@ int cfg80211_mlme_assoc(struct  
cfg80211_registered_device *rdev,
  			const u8 *bssid, const u8 *prev_bssid,
  			const u8 *ssid, int ssid_len,
  			const u8 *ie, int ie_len, bool use_mfp,
-			struct cfg80211_crypto_settings *crypt)
+			struct cfg80211_crypto_settings *crypt,
+			int uapsd)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  	int err;

  	wdev_lock(wdev);
  	err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
-				    ssid, ssid_len, ie, ie_len, use_mfp, crypt);
+				    ssid, ssid_len, ie, ie_len, use_mfp,
+				    crypt, uapsd);
  	wdev_unlock(wdev);

  	return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 683f56e..0e5c8a8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -206,6 +206,7 @@ static const struct nla_policy  
nl80211_policy[NL80211_ATTR_MAX+1] = {
  	[NL80211_ATTR_P2P_PS_LEGACY_PS] = { .type = NLA_U32 },
  	[NL80211_ATTR_P2P_PS_OPP_PS] = { .type = NLA_U32 },
  	[NL80211_ATTR_P2P_PS_CTWINDOW] = { .type = NLA_U32 },
+	[NL80211_ATTR_UAPSD] = { .type = NLA_U32 },
  };

  /* policy for the key attributes */
@@ -4362,6 +4363,7 @@ static int nl80211_associate(struct sk_buff *skb,  
struct genl_info *info)
  	const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
  	int err, ssid_len, ie_len = 0;
  	bool use_mfp = false;
+	int uapsd = -1;

  	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
  		return -EINVAL;
@@ -4405,11 +4407,14 @@ static int nl80211_associate(struct sk_buff *skb,  
struct genl_info *info)
  	if (info->attrs[NL80211_ATTR_PREV_BSSID])
  		prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);

+	if (info->attrs[NL80211_ATTR_UAPSD])
+		uapsd = nla_get_u32(info->attrs[NL80211_ATTR_UAPSD]);
+
  	err = nl80211_crypto_settings(rdev, info, &crypto, 1);
  	if (!err)
  		err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
  					  ssid, ssid_len, ie, ie_len, use_mfp,
-					  &crypto);
+					  &crypto, uapsd);

  	return err;
  }
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 0acfdc9..daef93c 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -190,7 +190,7 @@ static int cfg80211_conn_do_work(struct wireless_dev  
*wdev)
  					    prev_bssid,
  					    params->ssid, params->ssid_len,
  					    params->ie, params->ie_len,
-					    false, &params->crypto);
+					    false, &params->crypto, -1);
  		if (err)
  			__cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
  					       NULL, 0,
-- 
1.7.1

^ permalink raw reply related

* [RFC 05/07] mac80211: Purge cfg80211 beacon cache before authentication.
From: Dmitry Tarnyagin @ 2011-10-12  1:02 UTC (permalink / raw)
  To: linux-wireless.vger.kernel.org; +Cc: Bartosz MARKOWSKI, Janusz DZIEDZIC

From: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
Date: Wed, 10 Aug 2011 19:15:13 +0200

cw1200 device requires SSID to be available at AUTH stage.
cfg80211 beacon cache is designed to handle multi-SSID BSSes, so
bss struct returned by cfg80211_get_bss() has random SSID if BSS
just changed SSID before authentication (typical for p2p).

As a workaround cfg80211 beacon cache is purged to make sure
target BSS is searchable in rb-tree at the AUTH stage.

Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
---
  net/mac80211/ieee80211_i.h |    1 +
  net/mac80211/mlme.c        |    1 +
  net/mac80211/work.c        |   22 ++++++++++++++++++++++
  3 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 453bdb8..3dbaeb7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -325,6 +325,7 @@ struct ieee80211_work {
  			u8 key_len, key_idx;
  			bool privacy;
  			bool synced;
+			struct cfg80211_bss *bss;
  		} probe_auth;
  		struct {
  			struct cfg80211_bss *bss;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8c13619..dde286a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2562,6 +2562,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data  
*sdata,

  	wk->probe_auth.algorithm = auth_alg;
  	wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY;
+	wk->probe_auth.bss = req->bss;

  	/* if we already have a probe, don't probe again */
  	if (req->bss->proberesp_ies)
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 8a93de7..4acf7ca 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -488,6 +488,28 @@ ieee80211_authenticate(struct ieee80211_work *wk)
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	struct ieee80211_local *local = sdata->local;

+	/* At least one device requires SSID to be available at AUTH stage.
+	 * cfg80211 beacon cache is designed to handle multi-SSID BSSes, so
+	 * bss struct returned by cfg80211_get_bss() has random SSID if BSS
+	 * just changed SSID before authentication (it's typical for p2p).
+	 * As a workaround cfg80211 beacon cache is purged to make sure target
+	 * BSS is searchable in rb-tree at the AUTH stage.
+	 */
+	struct cfg80211_bss *bss;
+	while (true) {
+		bss = cfg80211_get_bss(local->hw.wiphy,
+				wk->probe_auth.bss->channel,
+				wk->probe_auth.bss->bssid,
+				NULL, 0, 0, 0);
+		if (WARN_ON(!bss))
+			break;
+		if (bss == wk->probe_auth.bss) {
+			cfg80211_put_bss(bss);
+			break;
+		}
+		cfg80211_unlink_bss(local->hw.wiphy, bss);
+	}
+
  	if (!wk->probe_auth.synced) {
  		int ret = drv_tx_sync(local, sdata, wk->filter_ta,
  				      IEEE80211_TX_SYNC_AUTH);
-- 
1.7.1

^ permalink raw reply related

* [RFC 04/07] compat-wireless: p2p power save support
From: Dmitry Tarnyagin @ 2011-10-12  1:02 UTC (permalink / raw)
  To: linux-wireless.vger.kernel.org; +Cc: Bartosz MARKOWSKI, Janusz DZIEDZIC

From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Date: Thu, 4 Aug 2011 11:42:16 +0200

P2P power save support:
  - Opportunistic Power Save
  - Notice Of Absence

Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
---
  include/linux/nl80211.h    |   12 +++++
  include/net/cfg80211.h     |   34 +++++++++++++
  include/net/mac80211.h     |    3 +
  net/mac80211/cfg.c         |   24 +++++++++
  net/mac80211/ieee80211_i.h |    3 +
  net/mac80211/mlme.c        |  114  
++++++++++++++++++++++++++++++++++++++++++
  net/wireless/nl80211.c     |  119  
++++++++++++++++++++++++++++++++++++++++++++
  net/wireless/util.c        |    9 +++
  8 files changed, 318 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 44911f6..a9bee60 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -638,6 +638,10 @@ enum nl80211_commands {
  	NL80211_CMD_TDLS_OPER,
  	NL80211_CMD_TDLS_MGMT,

+	NL80211_CMD_GET_NOA,
+	NL80211_CMD_SET_NOA,
+	NL80211_CMD_SET_P2P_POWER_SAVE,
+
  	/* add new commands above here */

  	/* used to define NL80211_CMD_MAX below */
@@ -1337,6 +1341,14 @@ enum nl80211_attrs {
  	NL80211_ATTR_TDLS_SUPPORT,
  	NL80211_ATTR_TDLS_EXTERNAL_SETUP,

+	NL80211_ATTR_P2P_PS_NOA,
+	NL80211_ATTR_P2P_PS_NOA_COUNT,
+	NL80211_ATTR_P2P_PS_NOA_START,
+	NL80211_ATTR_P2P_PS_NOA_DURATION,
+	NL80211_ATTR_P2P_PS_NOA_INTERVAL,
+	NL80211_ATTR_P2P_PS_LEGACY_PS,
+	NL80211_ATTR_P2P_PS_OPP_PS,
+	NL80211_ATTR_P2P_PS_CTWINDOW,
  	/* add attributes here, update the policy in nl80211.c */

  	__NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d2a9c21..c08e475 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1253,6 +1253,33 @@ struct cfg80211_gtk_rekey_data {
  	u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
  };

+/*
+ * struct cfg80211_p2p_ps - p2p power save params
+ *
+ * This structure ...
+ *
+ * @legacy_ps: 0=disable, 1=enable, 2=maximum_ps, -1=no change
+ * @opp_ps: 0=disable, 1=enable, -1=no change
+ * @ctwidnow: 0... - change in ms, -1=no change
+ * @count: 0..255 - count
+ * @start: Start time in ms from next TBTT
+ * @duration: Duration in ms
+ * @interval: interval in ms
+ */
+struct cfg80211_p2p_ps {
+	int	legacy_ps;
+
+	/* Opportunistic Power Save */
+	int	opp_ps;
+	int	ctwindow;
+
+	/* Notice of Absence */
+	u8	count;
+	int	start;
+	int	duration;
+	int	interval;
+};
+
  /**
   * struct cfg80211_ops - backend description for wireless configuration
   *
@@ -1625,6 +1652,9 @@ struct cfg80211_ops {
  			     u16 status_code, const u8 *buf, size_t len);
  	int	(*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
  			     u8 *peer, enum nl80211_tdls_operation oper);
+	int	(*set_p2p_power_mgmt)(struct wiphy *wiphy,
+				      struct net_device *dev,
+				      struct cfg80211_p2p_ps *ps);
  };

  /*
@@ -2188,6 +2218,8 @@ struct wireless_dev {
  	bool ps;
  	int ps_timeout;

+	struct cfg80211_p2p_ps	p2p_ps;
+
  	int beacon_interval;

  #ifdef CONFIG_CFG80211_WEXT
@@ -2376,6 +2408,7 @@ struct ieee802_11_elems {
  	u8 *ext_supp_rates;
  	u8 *wmm_info;
  	u8 *wmm_param;
+	u8 *p2p_ie;
  	struct ieee80211_ht_cap *ht_cap_elem;
  	struct ieee80211_ht_info *ht_info_elem;
  	struct ieee80211_meshconf_ie *mesh_config;
@@ -2406,6 +2439,7 @@ struct ieee802_11_elems {
  	u8 ext_supp_rates_len;
  	u8 wmm_info_len;
  	u8 wmm_param_len;
+	u8 p2p_ie_len;
  	u8 mesh_id_len;
  	u8 peering_len;
  	u8 preq_len;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 604464e..7a02a57 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -760,6 +760,7 @@ enum ieee80211_conf_changed {
  	IEEE80211_CONF_CHANGE_CHANNEL		= BIT(6),
  	IEEE80211_CONF_CHANGE_RETRY_LIMITS	= BIT(7),
  	IEEE80211_CONF_CHANGE_IDLE		= BIT(8),
+	IEEE80211_CONF_CHANGE_P2P_PS		= BIT(9),
  };

  /**
@@ -830,6 +831,7 @@ struct ieee80211_conf {
  	struct ieee80211_channel *channel;
  	enum nl80211_channel_type channel_type;
  	enum ieee80211_smps_mode smps_mode;
+	struct cfg80211_p2p_ps p2p_ps;
  };

  /**
@@ -1165,6 +1167,7 @@ enum ieee80211_hw_flags {
  	IEEE80211_HW_TX_AMPDU_SETUP_IN_HW		= 1<<23,
  	IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS		= 1<<24,
  	IEEE80211_HW_SUPPORTS_CQM_TX_FAIL		= 1<<25,
+	IEEE80211_HW_SUPPORTS_P2P_PS			= 1<<26,
  };

  /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index da96781..1f8541c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1722,6 +1722,29 @@ static int ieee80211_set_power_mgmt(struct wiphy  
*wiphy, struct net_device *dev,
  	return 0;
  }

+static int ieee80211_set_p2p_power_mgmt(struct wiphy *wiphy,
+					struct net_device *dev,
+					struct cfg80211_p2p_ps *p2p_ps)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_conf *conf = &local->hw.conf;
+
+	if (!(sdata->vif.type == NL80211_IFTYPE_P2P_CLIENT ||
+	    sdata->vif.type == NL80211_IFTYPE_P2P_GO ||
+	    sdata->vif.type == NL80211_IFTYPE_STATION ||
+	    sdata->vif.type == NL80211_IFTYPE_AP))
+		return -EOPNOTSUPP;
+
+	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_P2P_PS))
+		return -EOPNOTSUPP;
+
+	conf->p2p_ps = *p2p_ps;
+	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_P2P_PS);
+
+	return 0;
+}
+
  static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
  					 struct net_device *dev,
  					 s32 rssi_thold, u32 rssi_hyst)
@@ -2589,4 +2612,5 @@ struct cfg80211_ops mac80211_config_ops = {
  	.set_rekey_data = ieee80211_set_rekey_data,
  	.tdls_oper = ieee80211_tdls_oper,
  	.tdls_mgmt = ieee80211_tdls_mgmt,
+	.set_p2p_power_mgmt = ieee80211_set_p2p_power_mgmt,
  };
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1eaa7b3..453bdb8 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -409,6 +409,9 @@ struct ieee80211_if_managed {

  	int wmm_last_param_set;

+	char	p2p_last_ie[255];
+	u8	p2p_last_ie_len;
+
  	u8 use_4addr;

  	/* Signal strength from the last Beacon frame in the current BSS. */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c3e2d3c..8c13619 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -851,6 +851,117 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
  	ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
  }

+#define MAX_P2P_NOA_DESC 4
+/* TODO: check if not defined already */
+struct noa_desc {
+	u8	count;
+	__le32	duration;
+	__le32	interval;
+	__le32	start;
+} __packed;
+
+struct noa_attr {
+	u8	index;
+	u8	oppPsCTWindow;
+	struct noa_desc dsc[MAX_P2P_NOA_DESC];
+} __packed;
+
+struct p2p_attr {
+	u8	type;
+	__le16	len;
+	u8	data[0];
+} __packed;
+
+static void ieee80211_sta_p2p_noa_check(struct ieee80211_local *local,
+					struct ieee80211_sub_if_data *sdata,
+					u8 *p2p_ie, size_t p2p_ie_len)
+{
+	struct ieee80211_conf *conf = &local->hw.conf;
+	struct cfg80211_p2p_ps p2p_ps = {0};
+	struct p2p_attr *attr;
+	struct noa_attr *noa_attr = NULL;
+	u8 *ptr, idx;
+	u16 len = 0, noa_len = 0;
+	int i;
+
+	if (!p2p_ie)
+		goto out;
+
+	/* Find Noa attr */
+	ptr = p2p_ie + 4;
+	for (i = 0; i < p2p_ie_len; i++) {
+		attr = (struct p2p_attr *) &ptr[i];
+		len = __le32_to_cpu(attr->len);
+
+		switch (attr->type) {
+		case 0x0C:
+			noa_attr = (struct noa_attr *) &attr->data[0];
+			noa_len = len;
+			break;
+		default:
+			break;
+		}
+		if (noa_attr)
+			break;
+		i = i + len + 2;
+	}
+
+	if (!noa_attr)
+		goto out;
+
+	/* Get NOA settings */
+	idx = noa_attr->index;
+	p2p_ps.opp_ps = !!(noa_attr->oppPsCTWindow & BIT(7));
+	p2p_ps.ctwindow = (noa_attr->oppPsCTWindow & (~BIT(7)));
+
+	if (idx > 0 &&
+	    noa_len >= (idx*sizeof(struct noa_desc) + 2)) {
+		p2p_ps.count = noa_attr->dsc[idx-1].count;
+		p2p_ps.start = __le32_to_cpu(noa_attr->dsc[idx-1].start);
+		p2p_ps.duration = __le32_to_cpu(noa_attr->dsc[idx-1].duration);
+		p2p_ps.interval = __le32_to_cpu(noa_attr->dsc[idx-1].interval);
+	}
+
+out:
+	/* Notify driver if change is required */
+	if (memcmp(&conf->p2p_ps, &p2p_ps, sizeof(p2p_ps))) {
+		conf->p2p_ps = p2p_ps;
+		if (local->hw.flags & IEEE80211_HW_SUPPORTS_P2P_PS)
+			ieee80211_hw_config(local,
+					IEEE80211_CONF_CHANGE_P2P_PS);
+	}
+}
+
+
+/* P2P */
+static void ieee80211_sta_p2p_params(struct ieee80211_local *local,
+				     struct ieee80211_sub_if_data *sdata,
+				     u8 *p2p_ie, size_t p2p_ie_len)
+{
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+	if (!p2p_ie) {
+		if (ifmgd->p2p_last_ie_len) {
+			memset(ifmgd->p2p_last_ie, 0x00,
+			       sizeof(ifmgd->p2p_last_ie));
+			ifmgd->p2p_last_ie_len = 0;
+			ieee80211_sta_p2p_noa_check(local, sdata, p2p_ie,
+						    p2p_ie_len);
+			return;
+		}
+	}
+
+	if (p2p_ie_len != ifmgd->p2p_last_ie_len ||
+	    memcmp(p2p_ie, ifmgd->p2p_last_ie, p2p_ie_len)) {
+		/* BSS_CHANGED_P2P_PS */
+		ieee80211_sta_p2p_noa_check(local, sdata, p2p_ie,
+					    p2p_ie_len);
+	}
+
+	memcpy(ifmgd->p2p_last_ie, p2p_ie, p2p_ie_len);
+	ifmgd->p2p_last_ie_len = p2p_ie_len;
+}
+
  /* MLME */
  static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
  				     struct ieee80211_sub_if_data *sdata,
@@ -1884,6 +1995,9 @@ static void ieee80211_rx_mgmt_beacon(struct  
ieee80211_sub_if_data *sdata,

  		ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
  					 elems.wmm_param_len);
+
+		ieee80211_sta_p2p_params(local, sdata, elems.p2p_ie,
+					 elems.p2p_ie_len);
  	}

  	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8af66b2..683f56e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -197,6 +197,15 @@ static const struct nla_policy  
nl80211_policy[NL80211_ATTR_MAX+1] = {
  	[NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
  	[NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
  	[NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
+	[NL80211_ATTR_P2P_PS_NOA] = { .type = NLA_BINARY,
+				      .len = 32 },
+	[NL80211_ATTR_P2P_PS_NOA_COUNT] = { .type = NLA_U8 },
+	[NL80211_ATTR_P2P_PS_NOA_START] = { .type = NLA_U32},
+	[NL80211_ATTR_P2P_PS_NOA_DURATION] = { .type = NLA_U32 },
+	[NL80211_ATTR_P2P_PS_NOA_INTERVAL] = { .type = NLA_U32 },
+	[NL80211_ATTR_P2P_PS_LEGACY_PS] = { .type = NLA_U32 },
+	[NL80211_ATTR_P2P_PS_OPP_PS] = { .type = NLA_U32 },
+	[NL80211_ATTR_P2P_PS_CTWINDOW] = { .type = NLA_U32 },
  };

  /* policy for the key attributes */
@@ -5888,6 +5897,92 @@ static int nl80211_set_rekey_data(struct sk_buff  
*skb, struct genl_info *info)
  	return err;
  }

+static int nl80211_get_noa(struct sk_buff *skb, struct genl_info *info)
+{
+	/* TODO: implementation needed. Currently wpa_supplicant don't
+	 * support this. */
+	return -1;
+}
+
+static int nl80211_set_noa(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_p2p_ps p2p_ps;
+	int ret = 0;
+
+	if (!rdev->ops->set_p2p_power_mgmt)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_P2P_PS_NOA_COUNT] ||
+	    !info->attrs[NL80211_ATTR_P2P_PS_NOA_START] ||
+	    !info->attrs[NL80211_ATTR_P2P_PS_NOA_DURATION] ||
+	    !info->attrs[NL80211_ATTR_P2P_PS_NOA_INTERVAL])
+		return -EINVAL;
+
+	p2p_ps = wdev->p2p_ps;
+	p2p_ps.count = nla_get_u8(info->attrs[NL80211_ATTR_P2P_PS_NOA_COUNT]);
+	p2p_ps.start = nla_get_u32(info->attrs[NL80211_ATTR_P2P_PS_NOA_START]);
+	p2p_ps.duration = nla_get_u32(
+				info->attrs[NL80211_ATTR_P2P_PS_NOA_DURATION]);
+	p2p_ps.interval = nla_get_u32(
+				info->attrs[NL80211_ATTR_P2P_PS_NOA_INTERVAL]);
+	p2p_ps.legacy_ps = -1;
+	p2p_ps.opp_ps = -1;
+	p2p_ps.ctwindow = -1;
+
+
+	ret = rdev->ops->set_p2p_power_mgmt(wdev->wiphy, dev, &p2p_ps);
+
+	wdev->p2p_ps.count = p2p_ps.count;
+	wdev->p2p_ps.start = p2p_ps.start;
+	wdev->p2p_ps.duration = p2p_ps.duration;
+	wdev->p2p_ps.interval = p2p_ps.interval;
+
+	return ret;
+}
+
+static int nl80211_set_p2p_power_save(struct sk_buff *skb,
+				      struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int ret = 0;
+
+	struct cfg80211_p2p_ps p2p_ps = {0};
+	int legacy_ps, opp_ps, ctwindow;
+
+	if (!rdev->ops->set_p2p_power_mgmt)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_P2P_PS_LEGACY_PS] ||
+	    !info->attrs[NL80211_ATTR_P2P_PS_OPP_PS] ||
+	    !info->attrs[NL80211_ATTR_P2P_PS_CTWINDOW])
+		return -EINVAL;
+
+	p2p_ps = wdev->p2p_ps;
+
+	p2p_ps.legacy_ps = nla_get_u32(
+				info->attrs[NL80211_ATTR_P2P_PS_LEGACY_PS]);
+	p2p_ps.opp_ps = nla_get_u32(info->attrs[NL80211_ATTR_P2P_PS_OPP_PS]);
+	p2p_ps.ctwindow = nla_get_u32(
+				info->attrs[NL80211_ATTR_P2P_PS_CTWINDOW]);
+
+
+	ret = rdev->ops->set_p2p_power_mgmt(wdev->wiphy, dev, &p2p_ps);
+
+	if (p2p_ps.legacy_ps != -1)
+		wdev->p2p_ps.legacy_ps = p2p_ps.legacy_ps;
+	if (p2p_ps.opp_ps != -1)
+		wdev->p2p_ps.opp_ps = p2p_ps.opp_ps;
+	if (p2p_ps.ctwindow != -1)
+		wdev->p2p_ps.ctwindow = p2p_ps.ctwindow;
+
+	return ret;
+}
+
  #define NL80211_FLAG_NEED_WIPHY		0x01
  #define NL80211_FLAG_NEED_NETDEV	0x02
  #define NL80211_FLAG_NEED_RTNL		0x04
@@ -6443,6 +6538,30 @@ static struct genl_ops nl80211_ops[] = {
  		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
  				  NL80211_FLAG_NEED_RTNL,
  	},
+	{
+		.cmd = NL80211_CMD_GET_NOA,
+		.doit = nl80211_get_noa,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_SET_NOA,
+		.doit = nl80211_set_noa,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_SET_P2P_POWER_SAVE,
+		.doit = nl80211_set_p2p_power_save,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+				  NL80211_FLAG_NEED_RTNL,
+	},
  };

  static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --git a/net/wireless/util.c b/net/wireless/util.c
index e0bd192..50180dc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1142,6 +1142,15 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t  
len,
  					}
  				}
  			}
+			if (elen >= 4 && pos[0] == 0x50 && pos[1] == 0x6F &&
+			    pos[2] == 0x9A) {
+				/* P2P OUI (50:6F:9A) */
+				if (calc_crc)
+					crc = crc32_be(crc, pos - 2, elen + 2);
+
+				elems->p2p_ie = pos;
+				elems->p2p_ie_len = elen;
+			}
  			break;
  		case WLAN_EID_RSN:
  			elems->rsn = pos;
-- 
1.7.1

^ permalink raw reply related

* [RFC 03/07] compat-wireless: Enable changing regulatory domain
From: Dmitry Tarnyagin @ 2011-10-12  1:02 UTC (permalink / raw)
  To: linux-wireless.vger.kernel.org
  Cc: Bartosz MARKOWSKI, Janusz DZIEDZIC, Johan Lilje

From: Johan Lilje <johan.lilje@stericsson.com>
Date: Tue, 2 Aug 2011 09:21:49 +0200

If compat-wireless code is compiled into the kernel,
first request regulatory hint fails to return since
userspace is not ready yet.
Added timeout mechanism to remove old pending requests.

Signed-off-by: Johan Lilje <johan.lilje@stericsson.com>
---
  include/net/regulatory.h |    3 +++
  net/wireless/reg.c       |   26 +++++++++++++++++++++++---
  2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index eb7d3c2..98dda7b 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -61,6 +61,8 @@ enum environment_cap {
   * 	country IE
   * @country_ie_env: lets us know if the AP is telling us we are outdoor,
   * 	indoor, or if it doesn't matter
+ * @timestamp: stores the time when this request calls crda, to enable
+ *	timeout mechanism.
   * @list: used to insert into the reg_requests_list linked list
   */
  struct regulatory_request {
@@ -70,6 +72,7 @@ struct regulatory_request {
  	bool intersect;
  	bool processed;
  	enum environment_cap country_ie_env;
+	struct timespec timestamp;
  	struct list_head list;
  };

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 6acba9d..1fbd36a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -35,6 +35,7 @@

  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

+#include <linux/time.h>
  #include <linux/kernel.h>
  #include <linux/export.h>
  #include <linux/slab.h>
@@ -1433,6 +1434,9 @@ new_request:
  		return r;
  	}

+	/* Get timestamp */
+	getnstimeofday(&(last_request->timestamp));
+
  	return call_crda(last_request->alpha2);
  }

@@ -1479,15 +1483,31 @@ static void reg_process_hint(struct  
regulatory_request *reg_request)
  static void reg_process_pending_hints(void)
  {
  	struct regulatory_request *reg_request;
+	struct timespec time_diff;
+	struct timespec timestamp_now;

  	mutex_lock(&cfg80211_mutex);
  	mutex_lock(&reg_mutex);

  	/* When last_request->processed becomes true this will be rescheduled */
  	if (last_request && !last_request->processed) {
-		REG_DBG_PRINT("Pending regulatory request, waiting "
-			      "for it to be processed...\n");
-		goto out;
+		/* Get time since last request */
+		if (last_request->timestamp.tv_nsec) {
+			getnstimeofday(&timestamp_now);
+			time_diff = timespec_sub(timestamp_now,
+						 last_request->timestamp);
+		}
+
+		/* Previous call to CRDA did not return within 2 seconds */
+		if (time_diff.tv_sec > 2) {
+			REG_DBG_PRINT("Regulatory request timeout, "
+				      "removing pending hint\n");
+			reg_set_request_processed();
+		} else {
+			REG_DBG_PRINT("Pending regulatory request, waiting "
+				      "for it to be processed...\n");
+			goto out;
+		}
  	}

  	spin_lock(&reg_requests_lock);
-- 
1.7.1

^ permalink raw reply related

* [RFC 02/07] compat-wireless: Connection quality monitor extensions
From: Dmitry Tarnyagin @ 2011-10-12  1:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Bartosz MARKOWSKI, Janusz DZIEDZIC

From: Bartosz Markowski <bartosz.markowski@tieto.com>
Date: Tue, 12 Jul 2011 13:29:03 +0200
Subject: [PATCH 2/7] compat-wireless: CQM STE extensions

added:
* beacon miss threshold - This value specifies the threshold
   for the BEACON loss level
* tx fail - This value specifies the threshold for the TX loss level

Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>
---
  include/linux/compat-3.0.h |    2 +
  include/linux/nl80211.h    |   16 +++++
  include/net/cfg80211.h     |   34 ++++++++++
  include/net/mac80211.h     |   41 ++++++++++++
  net/mac80211/cfg.c         |   54 ++++++++++++++++
  net/mac80211/mlme.c        |   23 ++++++-
  net/wireless/mlme.c        |   25 +++++++
  net/wireless/nl80211.c     |  152  
+++++++++++++++++++++++++++++++++++++++++++-
  net/wireless/nl80211.h     |    9 +++
  9 files changed, 353 insertions(+), 3 deletions(-)

diff --git a/include/linux/compat-3.0.h b/include/linux/compat-3.0.h
index 8c8720e..961a3a6 100644
--- a/include/linux/compat-3.0.h
+++ b/include/linux/compat-3.0.h
@@ -59,6 +59,7 @@ int __must_check kstrtos16_from_user(const char __user  
*s, size_t count, unsigne
  int __must_check kstrtou8_from_user(const char __user *s, size_t count,  
unsigned int base, u8 *res);
  int __must_check kstrtos8_from_user(const char __user *s, size_t count,  
unsigned int base, s8 *res);

+/*
  static inline int __must_check kstrtou64_from_user(const char __user *s,  
size_t count, unsigned int base, u64 *res)
  {
  	return kstrtoull_from_user(s, count, base, res);
@@ -78,6 +79,7 @@ static inline int __must_check kstrtos32_from_user(const  
char __user *s, size_t
  {
  	return kstrtoint_from_user(s, count, base, res);
  }
+*/

  #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) */

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index be125a5..44911f6 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -2311,6 +2311,14 @@ enum nl80211_ps_state {
   * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
   * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
   *	consecutive packets were not acknowledged by the peer
+ * @NL80211_ATTR_CQM_BEACON_MISS_THOLD: BEACON threshold. This value  
specifies
+ *	the threshold for the BEACON loss level at which an event will be
+ *	sent. Zero to disable.
+ * @NL80211_ATTR_CQM_BEACON_MISS_THOLD_EVENT: BEACON miss event
+ * @NL80211_ATTR_CQM_TX_FAIL_THOLD: TX threshold. This value specifies the
+ *	the threshold for the TX loss level at which an event will be
+ *	sent. Zero to disable.
+ * @NL80211_ATTR_CQM_TX_FAIL_THOLD_EVENT: TX threshold event
   * @__NL80211_ATTR_CQM_AFTER_LAST: internal
   * @NL80211_ATTR_CQM_MAX: highest key attribute
   */
@@ -2321,6 +2329,14 @@ enum nl80211_attr_cqm {
  	NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
  	NL80211_ATTR_CQM_PKT_LOSS_EVENT,

+	/* Beacon Threshold */
+	NL80211_ATTR_CQM_BEACON_MISS_THOLD,
+	NL80211_ATTR_CQM_BEACON_MISS_THOLD_EVENT,
+
+	/* Tx Threshold */
+	NL80211_ATTR_CQM_TX_FAIL_THOLD,
+	NL80211_ATTR_CQM_TX_FAIL_THOLD_EVENT,
+
  	/* keep last */
  	__NL80211_ATTR_CQM_AFTER_LAST,
  	NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7fcb671..d2a9c21 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1403,6 +1403,9 @@ struct cfg80211_gtk_rekey_data {
   * @set_power_mgmt: Configure WLAN power management. A timeout value of -1
   *	allows the driver to adjust the dynamic ps timeout value.
   * @set_cqm_rssi_config: Configure connection quality monitor RSSI  
threshold.
+ * @set_cqm_beacon_miss_config: Configure connection quality monitor  
BEACON
+ *	threshold
+ * @set_cqm_tx_fail_config: Configure connection quality monitor TX  
threshold.
   * @sched_scan_start: Tell the driver to start a scheduled scan.
   * @sched_scan_stop: Tell the driver to stop an ongoing scheduled
   *	scan.  The driver_initiated flag specifies whether the driver
@@ -1590,6 +1593,14 @@ struct cfg80211_ops {
  				       struct net_device *dev,
  				       s32 rssi_thold, u32 rssi_hyst);

+	int     (*set_cqm_beacon_miss_config)(struct wiphy *wiphy,
+				       struct net_device *dev,
+				       u32 beacon_thold);
+
+	int     (*set_cqm_tx_fail_config)(struct wiphy *wiphy,
+				       struct net_device *dev,
+				       u32 tx_thold);
+
  	void	(*mgmt_frame_register)(struct wiphy *wiphy,
  				       struct net_device *dev,
  				       u16 frame_type, bool reg);
@@ -3185,6 +3196,29 @@ void cfg80211_gtk_rekey_notify(struct net_device  
*dev, const u8 *bssid,
  void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
  				     const u8 *bssid, bool preauth, gfp_t gfp);

+/*
+ * cfg80211_cqm_beacon_miss_notify - connection quality monitoring beacon
+ *	miss event
+ * @dev: network device
+ * @gfp: context flags
+ *
+ * This function is called when a configured connection quality monitoring
+ * beacon threshold reached event occurs.
+ */
+void cfg80211_cqm_beacon_miss_notify(struct net_device *dev,
+				     gfp_t gfp);
+
+/**
+ * cfg80211_cqm_tx_fail_notify - connection quality monitoring tx failure  
event
+ * @dev: network device
+ * @gfp: context flags
+ *
+ * This function is called when a configured connection quality monitoring
+ * tx threshold reached event occurs.
+ */
+void cfg80211_cqm_tx_fail_notify(struct net_device *dev,
+				 gfp_t gfp);
+
  /* Logging, debugging and troubleshooting/diagnostic helpers. */

  /* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e9d5745..604464e 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -244,6 +244,10 @@ enum ieee80211_rssi_event {
   * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero  
value
   *	implies disabled
   * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ * @cqm_beacon_miss_thold: Connection quality monitor beacon threshold, a  
zero
+ *	value implies disabled
+ * @cqm_tx_fail_thold: Connection quality monitor tx threshold, a zero  
value
+ *	implies disabled
   * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
   *	may filter ARP queries targeted for other addresses than listed here.
   *	The driver must allow ARP queries targeted for all address listed here
@@ -280,6 +284,8 @@ struct ieee80211_bss_conf {
  	u16 ht_operation_mode;
  	s32 cqm_rssi_thold;
  	u32 cqm_rssi_hyst;
+	u32 cqm_beacon_miss_thold;
+	u32 cqm_tx_fail_thold;
  	enum nl80211_channel_type channel_type;
  	__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
  	u8 arp_addr_cnt;
@@ -1126,6 +1132,11 @@ enum sta_notify_cmd {
   * @IEEE80211_HW_TX_AMPDU_SETUP_IN_HW: The device handles TX A-MPDU  
session
   *	setup strictly in HW. mac80211 should not attempt to do this in
   *	software.
+ * @IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS
+ *      Connection quality monitoring - beacon miss.
+ *
+ * @IEEE80211_HW_SUPPORTS_CQM_TX_FAIL
+ *      Connection quality monitoring - tx failure.
   */
  enum ieee80211_hw_flags {
  	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1152,6 +1163,8 @@ enum ieee80211_hw_flags {
  	IEEE80211_HW_SUPPORTS_PER_STA_GTK		= 1<<21,
  	IEEE80211_HW_AP_LINK_PS				= 1<<22,
  	IEEE80211_HW_TX_AMPDU_SETUP_IN_HW		= 1<<23,
+	IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS		= 1<<24,
+	IEEE80211_HW_SUPPORTS_CQM_TX_FAIL		= 1<<25,
  };

  /**
@@ -3376,6 +3389,34 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif  
*vif,
   */
  unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif);

+/*
+ * ieee80211_cqm_beacon_miss_notify - inform a configured connection  
quality
+ *	monitoring beacon miss threshold triggered
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @gfp: context flag
+ *
+ * When the %IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS is set, and a  
connection
+ * quality monitoring is configured with an beacon miss threshold, the  
driver
+ * will inform whenever the desired amount of consecutive beacons is  
missed.
+ */
+void ieee80211_cqm_beacon_miss_notify(struct ieee80211_vif *vif,
+				      gfp_t gfp);
+
+/**
+ * ieee80211_cqm_tx_fail_notify - inform a configured connection quality
+ *	monitoring beacon miss threshold triggered
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @gfp: context flag
+ *
+ * When the %IEEE80211_HW_SUPPORTS_CQM_TX_FAIL is set, and a connection
+ * quality monitoring is configured with an tx failure threshold, the  
driver
+ * whenever the desired amount of consecutive TX attempts is failed.
+ */
+void ieee80211_cqm_tx_fail_notify(struct ieee80211_vif *vif,
+				  gfp_t gfp);
+
  /**
   * ieee80211_chswitch_done - Complete channel switch process
   * @vif: &struct ieee80211_vif pointer from the add_interface callback.
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 55ee5a3..da96781 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1751,6 +1751,58 @@ static int ieee80211_set_cqm_rssi_config(struct  
wiphy *wiphy,
  	return 0;
  }

+static int ieee80211_set_cqm_beacon_miss_config(struct wiphy *wiphy,
+						struct net_device *dev,
+						u32 beacon_thold)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_vif *vif = &sdata->vif;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+	if (beacon_thold == bss_conf->cqm_beacon_miss_thold)
+		return 0;
+
+	bss_conf->cqm_beacon_miss_thold = beacon_thold;
+
+	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS)) {
+		if (sdata->vif.type != NL80211_IFTYPE_STATION)
+			return -EOPNOTSUPP;
+		return 0;
+	}
+
+	if (sdata->u.mgd.associated)
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
+
+	return 0;
+}
+
+static int ieee80211_set_cqm_tx_fail_config(struct wiphy *wiphy,
+					    struct net_device *dev,
+					    u32 tx_thold)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_vif *vif = &sdata->vif;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+	if (tx_thold == bss_conf->cqm_tx_fail_thold)
+		return 0;
+
+	bss_conf->cqm_tx_fail_thold = tx_thold;
+
+	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_TX_FAIL)) {
+		if (sdata->vif.type != NL80211_IFTYPE_STATION)
+			return -EOPNOTSUPP;
+		return 0;
+	}
+
+	if (sdata->u.mgd.associated)
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
+
+	return 0;
+}
+
  static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
  				      struct net_device *dev,
  				      const u8 *addr,
@@ -2527,6 +2579,8 @@ struct cfg80211_ops mac80211_config_ops = {
  	.mgmt_tx = ieee80211_mgmt_tx,
  	.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
  	.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
+	.set_cqm_beacon_miss_config = ieee80211_set_cqm_beacon_miss_config,
+	.set_cqm_tx_fail_config = ieee80211_set_cqm_tx_fail_config,
  	.mgmt_frame_register = ieee80211_mgmt_frame_register,
  	.set_antenna = ieee80211_set_antenna,
  	.get_antenna = ieee80211_get_antenna,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 96f9fae..c3e2d3c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2174,7 +2174,10 @@ void ieee80211_sta_work(struct  
ieee80211_sub_if_data *sdata)
  				    ifmgd->probe_send_count, max_tries);
  #endif
  			ieee80211_mgd_probe_ap_send(sdata);
-		} else {
+		} else if (!(local->hw.flags &
+				IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS) &&
+			   !(local->hw.flags &
+				IEEE80211_HW_SUPPORTS_CQM_TX_FAIL)) {
  			/*
  			 * We actually lost the connection ... or did we?
  			 * Let's make sure!
@@ -2811,3 +2814,21 @@ unsigned char ieee80211_get_operstate(struct  
ieee80211_vif *vif)
  	return sdata->dev->operstate;
  }
  EXPORT_SYMBOL(ieee80211_get_operstate);
+
+void ieee80211_cqm_beacon_miss_notify(struct ieee80211_vif *vif,
+				      gfp_t gfp)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+	cfg80211_cqm_beacon_miss_notify(sdata->dev, gfp);
+}
+EXPORT_SYMBOL(ieee80211_cqm_beacon_miss_notify);
+
+void ieee80211_cqm_tx_fail_notify(struct ieee80211_vif *vif,
+				      gfp_t gfp)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+	cfg80211_cqm_tx_fail_notify(sdata->dev, gfp);
+}
+EXPORT_SYMBOL(ieee80211_cqm_tx_fail_notify);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 21fc970..4194b3e 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -1097,6 +1097,7 @@ void cfg80211_gtk_rekey_notify(struct net_device  
*dev, const u8 *bssid,
  }
  EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);

+
  void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
  				     const u8 *bssid, bool preauth, gfp_t gfp)
  {
@@ -1107,3 +1108,27 @@ void cfg80211_pmksa_candidate_notify(struct  
net_device *dev, int index,
  	nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
  }
  EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+
+void cfg80211_cqm_beacon_miss_notify(struct net_device *dev,
+				     gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	/* Indicate roaming trigger event to user space */
+	nl80211_send_cqm_beacon_miss_notify(rdev, dev, gfp);
+}
+EXPORT_SYMBOL(cfg80211_cqm_beacon_miss_notify);
+
+void cfg80211_cqm_tx_fail_notify(struct net_device *dev,
+				 gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	/* Indicate roaming trigger event to user space */
+	nl80211_send_cqm_tx_fail_notify(rdev, dev, gfp);
+}
+EXPORT_SYMBOL(cfg80211_cqm_tx_fail_notify);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4b7c1d4..8af66b2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5454,6 +5454,10 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1]  
__read_mostly = {
  	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
  	[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
  	[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_BEACON_MISS_THOLD] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_BEACON_MISS_THOLD_EVENT] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_TX_FAIL_THOLD] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_TX_FAIL_THOLD_EVENT] = { .type = NLA_U32 },
  };

  static int nl80211_set_cqm_rssi(struct genl_info *info,
@@ -5479,6 +5483,45 @@ static int nl80211_set_cqm_rssi(struct genl_info  
*info,
  					      threshold, hysteresis);
  }

+static int nl80211_set_cqm_beacon_miss(struct genl_info *info,
+				       u32 threshold)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct wireless_dev *wdev;
+	struct net_device *dev = info->user_ptr[1];
+
+	wdev = dev->ieee80211_ptr;
+
+	if (!rdev->ops->set_cqm_beacon_miss_config)
+		return -EOPNOTSUPP;
+
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+		return -EOPNOTSUPP;
+
+	return rdev->ops->set_cqm_beacon_miss_config(wdev->wiphy,
+			dev, threshold);
+}
+
+static int nl80211_set_cqm_tx_fail(struct genl_info *info,
+				   u32 threshold)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct wireless_dev *wdev;
+	struct net_device *dev = info->user_ptr[1];
+
+	wdev = dev->ieee80211_ptr;
+
+	if (!rdev->ops->set_cqm_tx_fail_config)
+		return -EOPNOTSUPP;
+
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+		return -EOPNOTSUPP;
+
+	return rdev->ops->set_cqm_tx_fail_config(wdev->wiphy, dev, threshold);
+}
+
  static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
  {
  	struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
@@ -5503,8 +5546,25 @@ static int nl80211_set_cqm(struct sk_buff *skb,  
struct genl_info *info)
  		threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
  		hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
  		err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
-	} else
-		err = -EINVAL;
+		if (err)
+			goto out;
+	}
+
+	if (attrs[NL80211_ATTR_CQM_BEACON_MISS_THOLD]) {
+		u32 thold;
+		thold = nla_get_u32(attrs[NL80211_ATTR_CQM_BEACON_MISS_THOLD]);
+		err = nl80211_set_cqm_beacon_miss(info, thold);
+		if (err)
+			goto out;
+	}
+
+	if (attrs[NL80211_ATTR_CQM_TX_FAIL_THOLD]) {
+		u32 thold;
+		thold = nla_get_u32(attrs[NL80211_ATTR_CQM_TX_FAIL_THOLD]);
+		err = nl80211_set_cqm_tx_fail(info, thold);
+		if (err)
+			goto out;
+	}

  out:
  	return err;
@@ -7463,6 +7523,94 @@ nl80211_send_cqm_pktloss_notify(struct  
cfg80211_registered_device *rdev,
  	nlmsg_free(msg);
  }

+void
+nl80211_send_cqm_beacon_miss_notify(struct cfg80211_registered_device  
*rdev,
+				    struct net_device *netdev,
+				    gfp_t gfp)
+{
+	struct sk_buff *msg;
+	struct nlattr *pinfoattr;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+	pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
+	if (!pinfoattr)
+		goto nla_put_failure;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_BEACON_MISS_THOLD_EVENT, 0);
+
+	nla_nest_end(msg, pinfoattr);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, gfp);
+	return;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
+void
+nl80211_send_cqm_tx_fail_notify(struct cfg80211_registered_device *rdev,
+				struct net_device *netdev,
+				gfp_t gfp)
+{
+	struct sk_buff *msg;
+	struct nlattr *pinfoattr;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+	pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
+	if (!pinfoattr)
+		goto nla_put_failure;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_TX_FAIL_THOLD_EVENT, 0);
+
+	nla_nest_end(msg, pinfoattr);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, gfp);
+	return;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
  static int nl80211_netlink_notify(struct notifier_block * nb,
  				  unsigned long state,
  				  void *_notify)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index f24a1fb..920e19a 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -108,6 +108,15 @@ void
  nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
  				struct net_device *netdev, const u8 *peer,
  				u32 num_packets, gfp_t gfp);
+void
+nl80211_send_cqm_beacon_miss_notify(struct cfg80211_registered_device  
*rdev,
+			       struct net_device *netdev,
+			       gfp_t gfp);
+
+void
+nl80211_send_cqm_tx_fail_notify(struct cfg80211_registered_device *rdev,
+			   struct net_device *netdev,
+			   gfp_t gfp);

  void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
  			      struct net_device *netdev, const u8 *bssid,
-- 
1.7.1

^ permalink raw reply related

* [RFC 01/07] wireless-next: WAPI support for hardware-accelerated drivers
From: Dmitry Tarnyagin @ 2011-10-12  1:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: Bartosz MARKOWSKI, Janusz DZIEDZIC

From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Date: Wed, 1 Jun 2011 14:40:13 +0200

This commit implements WAPI support for hardware-accelerated devices.

Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
---
  include/linux/ieee80211.h  |    3 ++
  include/linux/nl80211.h    |    5 ++-
  include/linux/wireless.h   |    6 ++++
  net/mac80211/Makefile      |    1 +
  net/mac80211/ieee80211_i.h |    2 +-
  net/mac80211/key.c         |    4 ++
  net/mac80211/key.h         |    2 +
  net/mac80211/main.c        |    1 +
  net/mac80211/rx.c          |    4 ++
  net/mac80211/tx.c          |    6 ++++
  net/mac80211/wapi.c        |   71  
++++++++++++++++++++++++++++++++++++++++++++
  net/mac80211/wapi.h        |   27 ++++++++++++++++
  net/wireless/nl80211.c     |    7 ++--
  net/wireless/util.c        |    8 +++++
  net/wireless/wext-compat.c |   39 +++++++++++++++++++++--
  15 files changed, 176 insertions(+), 10 deletions(-)
  create mode 100644 net/mac80211/wapi.c
  create mode 100644 net/mac80211/wapi.h

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 48363c3..bf86b0d 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1395,6 +1395,7 @@ enum ieee80211_key_len {
  	WLAN_KEY_LEN_CCMP = 16,
  	WLAN_KEY_LEN_TKIP = 32,
  	WLAN_KEY_LEN_AES_CMAC = 16,
+	WLAN_KEY_LEN_SMS4 = 32,
  };

  /* Public action codes */
@@ -1551,12 +1552,14 @@ enum ieee80211_sa_query_action {
  #define WLAN_CIPHER_SUITE_CCMP		0x000FAC04
  #define WLAN_CIPHER_SUITE_WEP104	0x000FAC05
  #define WLAN_CIPHER_SUITE_AES_CMAC	0x000FAC06
+#define WLAN_CIPHER_SUITE_SMS4		0x000FAC07

  /* AKM suite selectors */
  #define WLAN_AKM_SUITE_8021X		0x000FAC01
  #define WLAN_AKM_SUITE_PSK		0x000FAC02
  #define WLAN_AKM_SUITE_SAE			0x000FAC08
  #define WLAN_AKM_SUITE_FT_OVER_SAE	0x000FAC09
+#define WLAN_AKM_SUITE_WAPI_PSK		0x000FAC03

  #define WLAN_MAX_KEY_LEN		32

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 9d797f2..be125a5 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1379,8 +1379,8 @@ enum nl80211_attrs {
  #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY	24
  #define NL80211_HT_CAPABILITY_LEN		26

-#define NL80211_MAX_NR_CIPHER_SUITES		5
-#define NL80211_MAX_NR_AKM_SUITES		2
+#define NL80211_MAX_NR_CIPHER_SUITES		6
+#define NL80211_MAX_NR_AKM_SUITES		3

  /**
   * enum nl80211_iftype - (virtual) interface types
@@ -2207,6 +2207,7 @@ enum nl80211_mfp {
  enum nl80211_wpa_versions {
  	NL80211_WPA_VERSION_1 = 1 << 0,
  	NL80211_WPA_VERSION_2 = 1 << 1,
+	NL80211_WAPI_VERSION_1 = 1 << 2,
  };

  /**
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 4395b28..f3e2375 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -586,6 +586,7 @@
  #define IW_AUTH_WPA_VERSION_DISABLED	0x00000001
  #define IW_AUTH_WPA_VERSION_WPA		0x00000002
  #define IW_AUTH_WPA_VERSION_WPA2	0x00000004
+#define IW_AUTH_WPA_VERSION_WAPI	0x00000008

  /* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and  
IW_AUTH_CIPHER_GROUP_MGMT
   * values (bit field) */
@@ -595,10 +596,12 @@
  #define IW_AUTH_CIPHER_CCMP	0x00000008
  #define IW_AUTH_CIPHER_WEP104	0x00000010
  #define IW_AUTH_CIPHER_AES_CMAC	0x00000020
+#define IW_AUTH_CIPHER_SMS4	0x00000040

  /* IW_AUTH_KEY_MGMT values (bit field) */
  #define IW_AUTH_KEY_MGMT_802_1X	1
  #define IW_AUTH_KEY_MGMT_PSK	2
+#define IW_AUTH_KEY_MGMT_WAPI_PSK	4

  /* IW_AUTH_80211_AUTH_ALG values (bit field) */
  #define IW_AUTH_ALG_OPEN_SYSTEM	0x00000001
@@ -624,6 +627,7 @@
  #define IW_ENCODE_ALG_CCMP	3
  #define IW_ENCODE_ALG_PMK	4
  #define IW_ENCODE_ALG_AES_CMAC	5
+#define IW_ENCODE_ALG_SMS4	6
  /* struct iw_encode_ext ->ext_flags */
  #define IW_ENCODE_EXT_TX_SEQ_VALID	0x00000001
  #define IW_ENCODE_EXT_RX_SEQ_VALID	0x00000002
@@ -644,6 +648,8 @@
  #define IW_ENC_CAPA_CIPHER_TKIP	0x00000004
  #define IW_ENC_CAPA_CIPHER_CCMP	0x00000008
  #define IW_ENC_CAPA_4WAY_HANDSHAKE	0x00000010
+#define IW_ENC_CAPA_WAPI		0x00000020
+#define IW_ENC_CAPA_CIPHER_SMS4		0x00000040

  /* Event capability macros - in (struct iw_range *)->event_capa
   * Because we have more than 32 possible events, we use an array of
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index fdb54e6..ed3dd35 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -6,6 +6,7 @@ mac80211-y := \
  	sta_info.o \
  	wep.o \
  	wpa.o \
+	wapi.o \
  	scan.o offchannel.o \
  	ht.o agg-tx.o agg-rx.o \
  	ibss.o \
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 46fbf7f..1eaa7b3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -42,7 +42,7 @@ struct ieee80211_local;
  #define TOTAL_MAX_TX_BUFFER 512

  /* Required encryption head and tailroom */
-#define IEEE80211_ENCRYPT_HEADROOM 8
+#define IEEE80211_ENCRYPT_HEADROOM 20
  #define IEEE80211_ENCRYPT_TAILROOM 18

  /* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index e8ff846..91f0141 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -413,6 +413,10 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher,  
int idx, size_t key_len,
  			return ERR_PTR(err);
  		}
  		break;
+	case WLAN_CIPHER_SUITE_SMS4:
+		key->conf.iv_len = WAPI_IV_LEN;
+		key->conf.icv_len = WAPI_ICV_LEN;
+		break;
  	}
  	memcpy(key->conf.key, key_data, key_len);
  	INIT_LIST_HEAD(&key->list);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 7d4e31f..455f1fe 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -29,6 +29,8 @@
  #define TKIP_IV_LEN		8
  #define TKIP_ICV_LEN		4
  #define CMAC_PN_LEN		6
+#define WAPI_IV_LEN		18
+#define WAPI_ICV_LEN		16

  #define NUM_RX_DATA_QUEUES	16

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 163226e..b9b9765 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -716,6 +716,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
  		WLAN_CIPHER_SUITE_WEP104,
  		WLAN_CIPHER_SUITE_TKIP,
  		WLAN_CIPHER_SUITE_CCMP,
+		WLAN_CIPHER_SUITE_SMS4,

  		/* keep last -- depends on hw flags! */
  		WLAN_CIPHER_SUITE_AES_CMAC
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8bd8683..6cc9800 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -28,6 +28,7 @@
  #include "wpa.h"
  #include "tkip.h"
  #include "wme.h"
+#include "wapi.h"

  /*
   * monitor mode reception
@@ -1058,6 +1059,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
  	case WLAN_CIPHER_SUITE_AES_CMAC:
  		result = ieee80211_crypto_aes_cmac_decrypt(rx);
  		break;
+	case WLAN_CIPHER_SUITE_SMS4:
+		result = ieee80211_crypto_wapi_decrypt(rx);
+		break;
  	default:
  		/*
  		 * We can reach here only with HW-only algorithms
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e2cdd6e..64ca6c1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -31,6 +31,7 @@
  #include "mesh.h"
  #include "wep.h"
  #include "wpa.h"
+#include "wapi.h"
  #include "wme.h"
  #include "rate.h"

@@ -592,6 +593,11 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data  
*tx)
  			if (!ieee80211_is_mgmt(hdr->frame_control))
  				tx->key = NULL;
  			break;
+
+		case WLAN_CIPHER_SUITE_SMS4:
+			if (tx->ethertype == ETH_P_WAPI)
+				tx->key = NULL;
+			break;
  		}

  		if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED))
diff --git a/net/mac80211/wapi.c b/net/mac80211/wapi.c
new file mode 100644
index 0000000..4780808
--- /dev/null
+++ b/net/mac80211/wapi.c
@@ -0,0 +1,71 @@
+/*
+ * Software WAPI encryption implementation
+ * Copyright (c) 2011, ST-Ericsson
+ * Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/crc32.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wapi.h"
+
+
+static int ieee80211_wapi_decrypt(struct ieee80211_local *local,
+				  struct sk_buff *skb,
+				  struct ieee80211_key *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	int data_len;
+
+	if (!(status->flag & RX_FLAG_DECRYPTED)) {
+		/* TODO - SMS4 decryption for firmware without
+		 * SMS4 support */
+		return RX_DROP_UNUSABLE;
+	}
+
+
+	data_len = skb->len - hdrlen - WAPI_IV_LEN - WAPI_ICV_LEN;
+	if (data_len < 0)
+		return RX_DROP_UNUSABLE;
+
+	/* Trim ICV */
+	skb_trim(skb, skb->len - WAPI_ICV_LEN);
+
+	/* Remove IV */
+	memmove(skb->data + WAPI_IV_LEN, skb->data, hdrlen);
+	skb_pull(skb, WAPI_IV_LEN);
+
+	return RX_CONTINUE;
+}
+
+ieee80211_rx_result
+ieee80211_crypto_wapi_decrypt(struct ieee80211_rx_data *rx)
+{
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+	if (!ieee80211_is_data(hdr->frame_control))
+		return RX_CONTINUE;
+
+	if (ieee80211_wapi_decrypt(rx->local, rx->skb, rx->key))
+		return RX_DROP_UNUSABLE;
+
+	return RX_CONTINUE;
+}
diff --git a/net/mac80211/wapi.h b/net/mac80211/wapi.h
new file mode 100644
index 0000000..f06eee0
--- /dev/null
+++ b/net/mac80211/wapi.h
@@ -0,0 +1,27 @@
+/*
+ * Software WAPI encryption implementation
+ * Copyright (c) 2011, ST-Ericsson
+ * Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef WAPI_H
+#define WAPI_H
+
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include "ieee80211_i.h"
+#include "key.h"
+
+#ifndef ETH_P_WAPI
+#define ETH_P_WAPI     0x88B4
+#endif
+
+
+ieee80211_rx_result
+ieee80211_crypto_wapi_decrypt(struct ieee80211_rx_data *rx);
+
+#endif /* WAPI_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fe059b1..4b7c1d4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -98,7 +98,7 @@ static const struct nla_policy  
nl80211_policy[NL80211_ATTR_MAX+1] = {
  	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
  	[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
  	[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
-	[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+	[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
  	[NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },

  	[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
@@ -204,7 +204,7 @@ static const struct nla_policy  
nl80211_key_policy[NL80211_KEY_MAX + 1] = {
  	[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
  	[NL80211_KEY_IDX] = { .type = NLA_U8 },
  	[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
-	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
  	[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
  	[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
  	[NL80211_KEY_TYPE] = { .type = NLA_U32 },
@@ -4167,7 +4167,8 @@ static bool nl80211_valid_auth_type(enum  
nl80211_auth_type auth_type)
  static bool nl80211_valid_wpa_versions(u32 wpa_versions)
  {
  	return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
-				  NL80211_WPA_VERSION_2));
+				  NL80211_WPA_VERSION_2 |
+				  NL80211_WAPI_VERSION_1));
  }

  static int nl80211_authenticate(struct sk_buff *skb, struct genl_info  
*info)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index f5bd881..e0bd192 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -208,6 +208,10 @@ int cfg80211_validate_key_settings(struct  
cfg80211_registered_device *rdev,
  		if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
  			return -EINVAL;
  		break;
+	case WLAN_CIPHER_SUITE_SMS4:
+		if (params->key_len != WLAN_KEY_LEN_SMS4)
+			return -EINVAL;
+		break;
  	default:
  		/*
  		 * We don't know anything about this algorithm,
@@ -231,6 +235,10 @@ int cfg80211_validate_key_settings(struct  
cfg80211_registered_device *rdev,
  			if (params->seq_len != 6)
  				return -EINVAL;
  			break;
+		case WLAN_CIPHER_SUITE_SMS4:
+			if (params->seq_len != 16)
+				return -EINVAL;
+			break;
  		}
  	}

diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 2aaca82..f63c7c4 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -216,6 +216,11 @@ int cfg80211_wext_giwrange(struct net_device *dev,
  			range->encoding_size[range->num_encoding_sizes++] =
  				WLAN_KEY_LEN_WEP104;
  			break;
+
+		case WLAN_CIPHER_SUITE_SMS4:
+			range->enc_capa |= (IW_ENC_CAPA_CIPHER_SMS4 |
+					    IW_ENC_CAPA_WAPI);
+			break;
  		}
  	}

@@ -699,6 +704,9 @@ static int cfg80211_wext_siwencodeext(struct  
net_device *dev,
  	case IW_ENCODE_ALG_AES_CMAC:
  		cipher = WLAN_CIPHER_SUITE_AES_CMAC;
  		break;
+	case IW_ENCODE_ALG_SMS4:
+		cipher = WLAN_CIPHER_SUITE_SMS4;
+		break;
  	default:
  		return -EOPNOTSUPP;
  	}
@@ -953,17 +961,21 @@ static int cfg80211_set_wpa_version(struct  
wireless_dev *wdev, u32 wpa_versions)
  {
  	if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
  			     IW_AUTH_WPA_VERSION_WPA2|
+			     IW_AUTH_WPA_VERSION_WAPI|
  		             IW_AUTH_WPA_VERSION_DISABLED))
  		return -EINVAL;

  	if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) &&
  	    (wpa_versions & (IW_AUTH_WPA_VERSION_WPA|
-			     IW_AUTH_WPA_VERSION_WPA2)))
+			     IW_AUTH_WPA_VERSION_WPA2|
+			     IW_AUTH_WPA_VERSION_WAPI)))
  		return -EINVAL;

  	if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED)
  		wdev->wext.connect.crypto.wpa_versions &=
-			~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2);
+			~(NL80211_WPA_VERSION_1|
+			  NL80211_WPA_VERSION_2|
+			  NL80211_WAPI_VERSION_1);

  	if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
  		wdev->wext.connect.crypto.wpa_versions |=
@@ -973,6 +985,10 @@ static int cfg80211_set_wpa_version(struct  
wireless_dev *wdev, u32 wpa_versions)
  		wdev->wext.connect.crypto.wpa_versions |=
  			NL80211_WPA_VERSION_2;

+	if (wpa_versions & IW_AUTH_WPA_VERSION_WAPI)
+		wdev->wext.connect.crypto.wpa_versions |=
+			NL80211_WAPI_VERSION_1;
+
  	return 0;
  }

@@ -995,6 +1011,9 @@ static int cfg80211_set_cipher_group(struct  
wireless_dev *wdev, u32 cipher)
  			WLAN_CIPHER_SUITE_AES_CMAC;
  	else if (cipher & IW_AUTH_CIPHER_NONE)
  		wdev->wext.connect.crypto.cipher_group = 0;
+	else if (cipher & IW_AUTH_CIPHER_SMS4)
+		wdev->wext.connect.crypto.cipher_group =
+			WLAN_CIPHER_SUITE_SMS4;
  	else
  		return -EINVAL;

@@ -1031,7 +1050,12 @@ static int cfg80211_set_cipher_pairwise(struct  
wireless_dev *wdev, u32 cipher)
  		nr_ciphers++;
  	}

-	BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5);
+	if (cipher & IW_AUTH_CIPHER_SMS4) {
+		ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_SMS4;
+		nr_ciphers++;
+	}
+
+	BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 6);

  	wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers;

@@ -1044,7 +1068,8 @@ static int cfg80211_set_key_mgt(struct wireless_dev  
*wdev, u32 key_mgt)
  	int nr_akm_suites = 0;

  	if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X |
-			IW_AUTH_KEY_MGMT_PSK))
+			IW_AUTH_KEY_MGMT_PSK |
+			IW_AUTH_KEY_MGMT_WAPI_PSK))
  		return -EINVAL;

  	if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
@@ -1059,6 +1084,12 @@ static int cfg80211_set_key_mgt(struct wireless_dev  
*wdev, u32 key_mgt)
  		nr_akm_suites++;
  	}

+	if (key_mgt & IW_AUTH_KEY_MGMT_WAPI_PSK) {
+		wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
+			WLAN_AKM_SUITE_WAPI_PSK;
+		nr_akm_suites++;
+	}
+
  	wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites;

  	return 0;
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2] mwifiex: add support for Marvell pcie8766 chipset
From: Bing Zhao @ 2011-10-12  0:41 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Amitkumar Karwar, Kiran Divekar, Yogesh Powar,
	Frank Huang, Bing Zhao

From: Amitkumar Karwar <akarwar@marvell.com>

This patch supports 88W8766P chipset with a PCIe interface.

The corresponding firmware image file is located at:
"mrvl/pcie8766_uapsta.bin"

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Ramesh Radhakrishnan <rramesh@marvell.com>
Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Frank Huang <frankh@marvell.com>
---
v2: fix warning "Section mismatch in reference from the variable...",
    found by John Linville

 drivers/net/wireless/mwifiex/11n_aggr.c    |    3 +-
 drivers/net/wireless/mwifiex/Kconfig       |   11 +
 drivers/net/wireless/mwifiex/Makefile      |    3 +
 drivers/net/wireless/mwifiex/cmdevt.c      |   11 +-
 drivers/net/wireless/mwifiex/fw.h          |   30 +-
 drivers/net/wireless/mwifiex/init.c        |   17 +-
 drivers/net/wireless/mwifiex/main.c        |    4 +-
 drivers/net/wireless/mwifiex/main.h        |   20 +-
 drivers/net/wireless/mwifiex/pcie.c        | 1948 ++++++++++++++++++++++++++++
 drivers/net/wireless/mwifiex/pcie.h        |  148 +++
 drivers/net/wireless/mwifiex/sdio.c        |   19 +-
 drivers/net/wireless/mwifiex/sdio.h        |   24 +-
 drivers/net/wireless/mwifiex/sta_cmd.c     |   64 +
 drivers/net/wireless/mwifiex/sta_cmdresp.c |    2 +
 drivers/net/wireless/mwifiex/sta_tx.c      |    2 +-
 drivers/net/wireless/mwifiex/txrx.c        |    2 +-
 drivers/net/wireless/mwifiex/util.h        |    9 +-
 drivers/net/wireless/mwifiex/wmm.c         |    4 +-
 18 files changed, 2284 insertions(+), 37 deletions(-)
 create mode 100644 drivers/net/wireless/mwifiex/pcie.c
 create mode 100644 drivers/net/wireless/mwifiex/pcie.h

diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 9e63d16..079e553 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -246,8 +246,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
 	tx_param.next_pkt_len = 0;
 
 	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
-					     skb_aggr->data,
-					     skb_aggr->len, &tx_param);
+					   skb_aggr, &tx_param);
 	switch (ret) {
 	case -EBUSY:
 		spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index 8696292..8f2797a 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -19,3 +19,14 @@ config MWIFIEX_SDIO
 
 	  If you choose to build it as a module, it will be called
 	  mwifiex_sdio.
+
+config MWIFIEX_PCIE
+	tristate "Marvell WiFi-Ex Driver for PCIE 8766"
+	depends on MWIFIEX && PCI
+	select FW_LOADER
+	---help---
+	  This adds support for wireless adapters based on Marvell
+	  8766 chipset with PCIe interface.
+
+	  If you choose to build it as a module, it will be called
+	  mwifiex_pcie.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 42cb733..b0257ad 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -39,3 +39,6 @@ obj-$(CONFIG_MWIFIEX) += mwifiex.o
 
 mwifiex_sdio-y += sdio.o
 obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o
+
+mwifiex_pcie-y += pcie.o
+obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index d12e25d..508de7f 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -94,7 +94,7 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
 		skb_trim(cmd_node->cmd_skb, 0);
 
 	if (cmd_node->resp_skb) {
-		dev_kfree_skb_any(cmd_node->resp_skb);
+		adapter->if_ops.cmdrsp_complete(adapter, cmd_node->resp_skb);
 		cmd_node->resp_skb = NULL;
 	}
 }
@@ -176,8 +176,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
 	skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
 
 	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
-					     cmd_node->cmd_skb->data,
-					     cmd_node->cmd_skb->len, NULL);
+					   cmd_node->cmd_skb, NULL);
 
 	skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN);
 
@@ -238,8 +237,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
 
 	skb_push(adapter->sleep_cfm, INTF_HEADER_LEN);
 	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
-					     adapter->sleep_cfm->data,
-					     adapter->sleep_cfm->len, NULL);
+					   adapter->sleep_cfm, NULL);
 	skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN);
 
 	if (ret == -1) {
@@ -402,8 +400,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
 
 	adapter->event_cause = 0;
 	adapter->event_skb = NULL;
-
-	dev_kfree_skb_any(skb);
+	adapter->if_ops.event_complete(adapter, skb);
 
 	return ret;
 }
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index f23ec72..71c61b7 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -84,7 +84,8 @@ enum KEY_TYPE_ID {
 
 #define MAX_FIRMWARE_POLL_TRIES			100
 
-#define FIRMWARE_READY				0xfedc
+#define FIRMWARE_READY_SDIO				0xfedc
+#define FIRMWARE_READY_PCIE				0xfedcba00
 
 enum MWIFIEX_802_11_PRIVACY_FILTER {
 	MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL,
@@ -221,7 +222,7 @@ enum MWIFIEX_802_11_WEP_STATUS {
 #define HostCmd_CMD_802_11_HS_CFG_ENH                 0x00e5
 #define HostCmd_CMD_CAU_REG_ACCESS                    0x00ed
 #define HostCmd_CMD_SET_BSS_MODE                      0x00f7
-
+#define HostCmd_CMD_PCIE_DESC_DETAILS                 0x00fa
 
 enum ENH_PS_MODES {
 	EN_PS = 1,
@@ -1137,6 +1138,30 @@ struct host_cmd_ds_set_bss_mode {
 	u8 con_type;
 } __packed;
 
+struct host_cmd_ds_pcie_details {
+	/* TX buffer descriptor ring address */
+	u32 txbd_addr_lo;
+	u32 txbd_addr_hi;
+	/* TX buffer descriptor ring count */
+	u32 txbd_count;
+
+	/* RX buffer descriptor ring address */
+	u32 rxbd_addr_lo;
+	u32 rxbd_addr_hi;
+	/* RX buffer descriptor ring count */
+	u32 rxbd_count;
+
+	/* Event buffer descriptor ring address */
+	u32 evtbd_addr_lo;
+	u32 evtbd_addr_hi;
+	/* Event buffer descriptor ring count */
+	u32 evtbd_count;
+
+	/* Sleep cookie buffer physical address */
+	u32 sleep_cookie_addr_lo;
+	u32 sleep_cookie_addr_hi;
+} __packed;
+
 struct host_cmd_ds_command {
 	__le16 command;
 	__le16 size;
@@ -1184,6 +1209,7 @@ struct host_cmd_ds_command {
 		struct host_cmd_ds_rf_reg_access rf_reg;
 		struct host_cmd_ds_pmic_reg_access pmic_reg;
 		struct host_cmd_ds_set_bss_mode bss_mode;
+		struct host_cmd_ds_pcie_details pcie_host_spec;
 		struct host_cmd_ds_802_11_eeprom_access eeprom;
 	} params;
 } __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index e1076b4..0ce72fc 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -191,7 +191,12 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
 						(adapter->sleep_cfm->data);
 
 	adapter->cmd_sent = false;
-	adapter->data_sent = true;
+
+	if (adapter->iface_type == MWIFIEX_PCIE)
+		adapter->data_sent = false;
+	else
+		adapter->data_sent = true;
+
 	adapter->cmd_resp_received = false;
 	adapter->event_received = false;
 	adapter->data_received = false;
@@ -581,11 +586,13 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
 int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
 		    struct mwifiex_fw_image *pmfw)
 {
-	int ret, winner;
+	int ret;
 	u32 poll_num = 1;
 
+	adapter->winner = 0;
+
 	/* Check if firmware is already running */
-	ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
+	ret = adapter->if_ops.check_fw_status(adapter, poll_num);
 	if (!ret) {
 		dev_notice(adapter->dev,
 				"WLAN FW already running! Skip FW download\n");
@@ -594,7 +601,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
 	poll_num = MAX_FIRMWARE_POLL_TRIES;
 
 	/* Check if we are the winner for downloading FW */
-	if (!winner) {
+	if (!adapter->winner) {
 		dev_notice(adapter->dev,
 				"Other interface already running!"
 				" Skip FW download\n");
@@ -612,7 +619,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
 
 poll_fw:
 	/* Check if the firmware is downloaded successfully or not */
-	ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
+	ret = adapter->if_ops.check_fw_status(adapter, poll_num);
 	if (ret) {
 		dev_err(adapter->dev, "FW failed to be active in time\n");
 		return -1;
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 277ea84..849144d 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -661,7 +661,7 @@ mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
  */
 int
 mwifiex_add_card(void *card, struct semaphore *sem,
-		 struct mwifiex_if_ops *if_ops)
+		 struct mwifiex_if_ops *if_ops, u8 iface_type)
 {
 	struct mwifiex_adapter *adapter;
 	char fmt[64];
@@ -675,6 +675,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
 		goto err_init_sw;
 	}
 
+	adapter->iface_type = iface_type;
+
 	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
 	adapter->surprise_removed = false;
 	init_waitqueue_head(&adapter->init_wait_q);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 907ab74..ec45607 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -37,6 +37,7 @@
 #include "ioctl.h"
 #include "util.h"
 #include "fw.h"
+#include "pcie.h"
 
 extern const char driver_version[];
 
@@ -107,6 +108,8 @@ enum {
 
 #define MAX_FREQUENCY_BAND_BG   2484
 
+#define MWIFIEX_EVENT_HEADER_LEN           4
+
 struct mwifiex_dbg {
 	u32 num_cmd_host_to_card_failure;
 	u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -156,6 +159,11 @@ enum MWIFIEX_PS_STATE {
 	PS_STATE_SLEEP
 };
 
+enum mwifiex_iface_type {
+	MWIFIEX_SDIO,
+	MWIFIEX_PCIE,
+};
+
 struct mwifiex_add_ba_param {
 	u32 tx_win_size;
 	u32 rx_win_size;
@@ -517,27 +525,31 @@ struct cmd_ctrl_node {
 struct mwifiex_if_ops {
 	int (*init_if) (struct mwifiex_adapter *);
 	void (*cleanup_if) (struct mwifiex_adapter *);
-	int (*check_fw_status) (struct mwifiex_adapter *, u32, int *);
+	int (*check_fw_status) (struct mwifiex_adapter *, u32);
 	int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
 	int (*register_dev) (struct mwifiex_adapter *);
 	void (*unregister_dev) (struct mwifiex_adapter *);
 	int (*enable_int) (struct mwifiex_adapter *);
 	int (*process_int_status) (struct mwifiex_adapter *);
-	int (*host_to_card) (struct mwifiex_adapter *, u8,
-			     u8 *payload, u32 pkt_len,
+	int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *,
 			     struct mwifiex_tx_param *);
 	int (*wakeup) (struct mwifiex_adapter *);
 	int (*wakeup_complete) (struct mwifiex_adapter *);
 
+	/* Interface specific functions */
 	void (*update_mp_end_port) (struct mwifiex_adapter *, u16);
 	void (*cleanup_mpa_buf) (struct mwifiex_adapter *);
+	int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *);
+	int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
 };
 
 struct mwifiex_adapter {
+	u8 iface_type;
 	struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
 	u8 priv_num;
 	const struct firmware *firmware;
 	char fw_name[32];
+	int winner;
 	struct device *dev;
 	bool surprise_removed;
 	u32 fw_release_number;
@@ -872,7 +884,7 @@ struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter
 						*adapter, u8 bss_index);
 int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
 			     u32 func_init_shutdown);
-int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *);
+int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
 int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
 
 void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
new file mode 100644
index 0000000..d34acf0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -0,0 +1,1948 @@
+/*
+ * Marvell Wireless LAN device driver: PCIE specific handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/firmware.h>
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "pcie.h"
+
+#define PCIE_VERSION	"1.0"
+#define DRV_NAME        "Marvell mwifiex PCIe"
+
+static u8 user_rmmod;
+
+static struct mwifiex_if_ops pcie_ops;
+
+static struct semaphore add_remove_card_sem;
+static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
+static int mwifiex_pcie_resume(struct pci_dev *pdev);
+
+/*
+ * This function is called after skb allocation to update
+ * "skb->cb" with physical address of data pointer.
+ */
+static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb)
+{
+	phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+
+	*buf_pa = (phys_addr_t)virt_to_phys(skb->data);
+
+	return buf_pa;
+}
+
+/*
+ * This function reads sleep cookie and checks if FW is ready
+ */
+static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
+{
+	u32 *cookie_addr;
+	struct pcie_service_card *card = adapter->card;
+
+	if (card->sleep_cookie) {
+		cookie_addr = (u32 *)card->sleep_cookie->data;
+		dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
+			*cookie_addr);
+		if (*cookie_addr == FW_AWAKE_COOKIE)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * This function probes an mwifiex device and registers it. It allocates
+ * the card structure, enables PCIE function number and initiates the
+ * device registration and initialization procedure by adding a logical
+ * interface.
+ */
+static int mwifiex_pcie_probe(struct pci_dev *pdev,
+					const struct pci_device_id *ent)
+{
+	struct pcie_service_card *card;
+
+	pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
+				pdev->vendor, pdev->device, pdev->revision);
+
+	card = kzalloc(sizeof(struct pcie_service_card), GFP_KERNEL);
+	if (!card) {
+		pr_err("%s: failed to alloc memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	card->dev = pdev;
+
+	if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
+			     MWIFIEX_PCIE)) {
+		pr_err("%s failed\n", __func__);
+		kfree(card);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function removes the interface and frees up the card structure.
+ */
+static void mwifiex_pcie_remove(struct pci_dev *pdev)
+{
+	struct pcie_service_card *card;
+	struct mwifiex_adapter *adapter;
+	int i;
+
+	card = pci_get_drvdata(pdev);
+	if (!card)
+		return;
+
+	adapter = card->adapter;
+	if (!adapter || !adapter->priv_num)
+		return;
+
+	if (user_rmmod) {
+#ifdef CONFIG_PM
+		if (adapter->is_suspended)
+			mwifiex_pcie_resume(pdev);
+#endif
+
+		for (i = 0; i < adapter->priv_num; i++)
+			if ((GET_BSS_ROLE(adapter->priv[i]) ==
+						MWIFIEX_BSS_ROLE_STA) &&
+					adapter->priv[i]->media_connected)
+				mwifiex_deauthenticate(adapter->priv[i], NULL);
+
+		mwifiex_disable_auto_ds(mwifiex_get_priv(adapter,
+						 MWIFIEX_BSS_ROLE_ANY));
+
+		mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
+						MWIFIEX_BSS_ROLE_ANY),
+					 MWIFIEX_FUNC_SHUTDOWN);
+	}
+
+	mwifiex_remove_card(card->adapter, &add_remove_card_sem);
+	kfree(card);
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct mwifiex_adapter *adapter;
+	struct pcie_service_card *card;
+	int hs_actived, i;
+
+	if (pdev) {
+		card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+		if (!card || card->adapter) {
+			pr_err("Card or adapter structure is not valid\n");
+			return 0;
+		}
+	} else {
+		pr_err("PCIE device is not specified\n");
+		return 0;
+	}
+
+	adapter = card->adapter;
+
+	hs_actived = mwifiex_enable_hs(adapter);
+
+	/* Indicate device suspended */
+	adapter->is_suspended = true;
+
+	for (i = 0; i < adapter->priv_num; i++)
+		netif_carrier_off(adapter->priv[i]->netdev);
+
+	return 0;
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_pcie_resume(struct pci_dev *pdev)
+{
+	struct mwifiex_adapter *adapter;
+	struct pcie_service_card *card;
+	int i;
+
+	if (pdev) {
+		card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+		if (!card || !card->adapter) {
+			pr_err("Card or adapter structure is not valid\n");
+			return 0;
+		}
+	} else {
+		pr_err("PCIE device is not specified\n");
+		return 0;
+	}
+
+	adapter = card->adapter;
+
+	if (!adapter->is_suspended) {
+		dev_warn(adapter->dev, "Device already resumed\n");
+		return 0;
+	}
+
+	adapter->is_suspended = false;
+
+	for (i = 0; i < adapter->priv_num; i++)
+		if (adapter->priv[i]->media_connected)
+			netif_carrier_on(adapter->priv[i]->netdev);
+
+	mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+			      MWIFIEX_ASYNC_CMD);
+
+	return 0;
+}
+
+#define PCIE_VENDOR_ID_MARVELL              (0x11ab)
+#define PCIE_DEVICE_ID_MARVELL_88W8766P		(0x2b30)
+
+static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
+	{
+		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(pci, mwifiex_ids);
+
+/* PCI Device Driver */
+static struct pci_driver __refdata mwifiex_pcie = {
+	.name     = "mwifiex_pcie",
+	.id_table = mwifiex_ids,
+	.probe    = mwifiex_pcie_probe,
+	.remove   = mwifiex_pcie_remove,
+#ifdef CONFIG_PM
+	/* Power Management Hooks */
+	.suspend  = mwifiex_pcie_suspend,
+	.resume   = mwifiex_pcie_resume,
+#endif
+};
+
+/*
+ * This function writes data into PCIE card register.
+ */
+static int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data)
+{
+	struct pcie_service_card *card = adapter->card;
+
+	iowrite32(data, card->pci_mmap1 + reg);
+
+	return 0;
+}
+
+/*
+ * This function reads data from PCIE card register.
+ */
+static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
+{
+	struct pcie_service_card *card = adapter->card;
+
+	*data = ioread32(card->pci_mmap1 + reg);
+
+	return 0;
+}
+
+/*
+ * This function wakes up the card.
+ *
+ * A host power up command is written to the card configuration
+ * register to wake up the card.
+ */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+	int i = 0;
+
+	while (mwifiex_pcie_ok_to_access_hw(adapter)) {
+		i++;
+		udelay(10);
+		/* 50ms max wait */
+		if (i == 50000)
+			break;
+	}
+
+	dev_dbg(adapter->dev, "event: Wakeup device...\n");
+
+	/* Enable interrupts or any chip access will wakeup device */
+	if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, HOST_INTR_MASK)) {
+		dev_warn(adapter->dev, "Enable host interrupt failed\n");
+		return -1;
+	}
+
+	dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+	adapter->ps_state = PS_STATE_AWAKE;
+
+	return 0;
+}
+
+/*
+ * This function is called after the card has woken up.
+ *
+ * The card configuration register is reset.
+ */
+static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
+{
+	dev_dbg(adapter->dev, "cmd: Wakeup device completed\n");
+
+	return 0;
+}
+
+/*
+ * This function disables the host interrupt.
+ *
+ * The host interrupt mask is read, the disable bit is reset and
+ * written back to the card host interrupt mask register.
+ */
+static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
+{
+	if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
+				      0x00000000)) {
+			dev_warn(adapter->dev, "Disable host interrupt failed\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function enables the host interrupt.
+ *
+ * The host interrupt enable mask is written to the card
+ * host interrupt mask register.
+ */
+static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
+{
+	if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+		/* Simply write the mask to the register */
+		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
+				      HOST_INTR_MASK)) {
+			dev_warn(adapter->dev, "Enable host interrupt failed\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for TX
+ */
+static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct sk_buff *skb;
+	int i;
+	phys_addr_t *buf_pa;
+
+	/*
+	 * driver maintaines the write pointer and firmware maintaines the read
+	 * pointer. The write pointer starts at 0 (zero) while the read pointer
+	 * starts at zero with rollover bit set
+	 */
+	card->txbd_wrptr = 0;
+	card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+	/* allocate shared memory for the BD ring and divide the same in to
+	   several descriptors */
+	card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+				MWIFIEX_MAX_TXRX_BD;
+	dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
+				card->txbd_ring_size);
+	card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
+	if (!card->txbd_ring_vbase) {
+		dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n");
+		kfree(card->txbd_ring_vbase);
+		return -1;
+	}
+	card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
+
+	dev_dbg(adapter->dev, "info: txbd_ring - base: %p, pbase: %#x:%x,"
+			"len: %x\n", card->txbd_ring_vbase,
+			(u32)card->txbd_ring_pbase,
+			(u32)((u64)card->txbd_ring_pbase >> 32),
+			card->txbd_ring_size);
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+				(card->txbd_ring_vbase +
+				(sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+		/* Allocate buffer here so that firmware can DMA data from it */
+		skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+		if (!skb) {
+			dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n");
+			kfree(card->txbd_ring_vbase);
+			return -ENOMEM;
+		}
+		buf_pa = mwifiex_update_sk_buff_pa(skb);
+
+		skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
+		dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, "
+				"buf_base: %p, buf_pbase: %#x:%x, "
+				"buf_len: %#x\n", skb, skb->data,
+				(u32)*buf_pa, (u32)(((u64)*buf_pa >> 32)),
+				skb->len);
+
+		card->tx_buf_list[i] = skb;
+		card->txbd_ring[i]->paddr = *buf_pa;
+		card->txbd_ring[i]->len = (u16)skb->len;
+		card->txbd_ring[i]->flags = 0;
+	}
+
+	return 0;
+}
+
+static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		if (card->tx_buf_list[i])
+			dev_kfree_skb_any(card->tx_buf_list[i]);
+		card->tx_buf_list[i] = NULL;
+		card->txbd_ring[i]->paddr = 0;
+		card->txbd_ring[i]->len = 0;
+		card->txbd_ring[i]->flags = 0;
+		card->txbd_ring[i] = NULL;
+	}
+
+	kfree(card->txbd_ring_vbase);
+	card->txbd_ring_size = 0;
+	card->txbd_wrptr = 0;
+	card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->txbd_ring_vbase = NULL;
+
+	return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for RX
+ */
+static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct sk_buff *skb;
+	int i;
+	phys_addr_t *buf_pa;
+
+	/*
+	 * driver maintaines the read pointer and firmware maintaines the write
+	 * pointer. The write pointer starts at 0 (zero) while the read pointer
+	 * starts at zero with rollover bit set
+	 */
+	card->rxbd_wrptr = 0;
+	card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+	card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+				MWIFIEX_MAX_TXRX_BD;
+	dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
+				card->rxbd_ring_size);
+	card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL);
+	if (!card->rxbd_ring_vbase) {
+		dev_err(adapter->dev, "Unable to allocate buffer for "
+				"rxbd_ring.\n");
+		return -1;
+	}
+	card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase);
+
+	dev_dbg(adapter->dev, "info: rxbd_ring - base: %p, pbase: %#x:%x,"
+			"len: %#x\n", card->rxbd_ring_vbase,
+			(u32)card->rxbd_ring_pbase,
+			(u32)((u64)card->rxbd_ring_pbase >> 32),
+			card->rxbd_ring_size);
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+				(card->rxbd_ring_vbase +
+				(sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+		/* Allocate skb here so that firmware can DMA data from it */
+		skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+		if (!skb) {
+			dev_err(adapter->dev, "Unable to allocate skb for RX ring.\n");
+			kfree(card->rxbd_ring_vbase);
+			return -ENOMEM;
+		}
+		buf_pa = mwifiex_update_sk_buff_pa(skb);
+		skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
+
+		dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
+				"buf_base: %p, buf_pbase: %#x:%x, "
+				"buf_len: %#x\n", skb, skb->data,
+				(u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+				skb->len);
+
+		card->rx_buf_list[i] = skb;
+		card->rxbd_ring[i]->paddr = *buf_pa;
+		card->rxbd_ring[i]->len = (u16)skb->len;
+		card->rxbd_ring[i]->flags = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * This function deletes Buffer descriptor ring for RX
+ */
+static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		if (card->rx_buf_list[i])
+			dev_kfree_skb_any(card->rx_buf_list[i]);
+		card->rx_buf_list[i] = NULL;
+		card->rxbd_ring[i]->paddr = 0;
+		card->rxbd_ring[i]->len = 0;
+		card->rxbd_ring[i]->flags = 0;
+		card->rxbd_ring[i] = NULL;
+	}
+
+	kfree(card->rxbd_ring_vbase);
+	card->rxbd_ring_size = 0;
+	card->rxbd_wrptr = 0;
+	card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->rxbd_ring_vbase = NULL;
+
+	return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for Events
+ */
+static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct sk_buff *skb;
+	int i;
+	phys_addr_t *buf_pa;
+
+	/*
+	 * driver maintaines the read pointer and firmware maintaines the write
+	 * pointer. The write pointer starts at 0 (zero) while the read pointer
+	 * starts at zero with rollover bit set
+	 */
+	card->evtbd_wrptr = 0;
+	card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+	card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+				MWIFIEX_MAX_EVT_BD;
+	dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
+				card->evtbd_ring_size);
+	card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL);
+	if (!card->evtbd_ring_vbase) {
+		dev_err(adapter->dev, "Unable to allocate buffer. "
+				"Terminating download\n");
+		return -1;
+	}
+	card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase);
+
+	dev_dbg(adapter->dev, "info: CMDRSP/EVT bd_ring - base: %p, "
+		       "pbase: %#x:%x, len: %#x\n", card->evtbd_ring_vbase,
+		       (u32)card->evtbd_ring_pbase,
+		       (u32)((u64)card->evtbd_ring_pbase >> 32),
+		       card->evtbd_ring_size);
+
+	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+		card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+				(card->evtbd_ring_vbase +
+				(sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+		/* Allocate skb here so that firmware can DMA data from it */
+		skb = dev_alloc_skb(MAX_EVENT_SIZE);
+		if (!skb) {
+			dev_err(adapter->dev, "Unable to allocate skb for EVENT buf.\n");
+			kfree(card->evtbd_ring_vbase);
+			return -ENOMEM;
+		}
+		buf_pa = mwifiex_update_sk_buff_pa(skb);
+		skb_put(skb, MAX_EVENT_SIZE);
+
+		dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
+			       "buf_base: %p, buf_pbase: %#x:%x, "
+			       "buf_len: %#x\n", skb, skb->data,
+			       (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+			       skb->len);
+
+		card->evt_buf_list[i] = skb;
+		card->evtbd_ring[i]->paddr = *buf_pa;
+		card->evtbd_ring[i]->len = (u16)skb->len;
+		card->evtbd_ring[i]->flags = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * This function deletes Buffer descriptor ring for Events
+ */
+static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+		if (card->evt_buf_list[i])
+			dev_kfree_skb_any(card->evt_buf_list[i]);
+		card->evt_buf_list[i] = NULL;
+		card->evtbd_ring[i]->paddr = 0;
+		card->evtbd_ring[i]->len = 0;
+		card->evtbd_ring[i]->flags = 0;
+		card->evtbd_ring[i] = NULL;
+	}
+
+	kfree(card->evtbd_ring_vbase);
+	card->evtbd_wrptr = 0;
+	card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->evtbd_ring_size = 0;
+	card->evtbd_ring_vbase = NULL;
+
+	return 0;
+}
+
+/*
+ * This function allocates a buffer for CMDRSP
+ */
+static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct sk_buff *skb;
+
+	/* Allocate memory for receiving command response data */
+	skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
+	if (!skb) {
+		dev_err(adapter->dev, "Unable to allocate skb for command "
+				      "response data.\n");
+		return -ENOMEM;
+	}
+	mwifiex_update_sk_buff_pa(skb);
+	skb_put(skb, MWIFIEX_UPLD_SIZE);
+	card->cmdrsp_buf = skb;
+
+	skb = NULL;
+	/* Allocate memory for sending command to firmware */
+	skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
+	if (!skb) {
+		dev_err(adapter->dev, "Unable to allocate skb for command "
+				      "data.\n");
+		return -ENOMEM;
+	}
+	mwifiex_update_sk_buff_pa(skb);
+	skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER);
+	card->cmd_buf = skb;
+
+	return 0;
+}
+
+/*
+ * This function deletes a buffer for CMDRSP
+ */
+static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card;
+
+	if (!adapter)
+		return 0;
+
+	card = adapter->card;
+
+	if (card && card->cmdrsp_buf)
+		dev_kfree_skb_any(card->cmdrsp_buf);
+
+	if (card && card->cmd_buf)
+		dev_kfree_skb_any(card->cmd_buf);
+
+	return 0;
+}
+
+/*
+ * This function allocates a buffer for sleep cookie
+ */
+static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
+{
+	struct sk_buff *skb;
+	struct pcie_service_card *card = adapter->card;
+
+	/* Allocate memory for sleep cookie */
+	skb = dev_alloc_skb(sizeof(u32));
+	if (!skb) {
+		dev_err(adapter->dev, "Unable to allocate skb for sleep "
+				      "cookie!\n");
+		return -ENOMEM;
+	}
+	mwifiex_update_sk_buff_pa(skb);
+	skb_put(skb, sizeof(u32));
+
+	/* Init val of Sleep Cookie */
+	*(u32 *)skb->data = FW_AWAKE_COOKIE;
+
+	dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
+				*((u32 *)skb->data));
+
+	/* Save the sleep cookie */
+	card->sleep_cookie = skb;
+
+	return 0;
+}
+
+/*
+ * This function deletes buffer for sleep cookie
+ */
+static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card;
+
+	if (!adapter)
+		return 0;
+
+	card = adapter->card;
+
+	if (card && card->sleep_cookie) {
+		dev_kfree_skb_any(card->sleep_cookie);
+		card->sleep_cookie = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * This function sends data buffer to device
+ */
+static int
+mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+	struct pcie_service_card *card = adapter->card;
+	u32 wrindx, rdptr;
+	phys_addr_t *buf_pa;
+	__le16 *tmp;
+
+	if (!mwifiex_pcie_ok_to_access_hw(adapter))
+		mwifiex_pm_wakeup_card(adapter);
+
+	/* Read the TX ring read pointer set by firmware */
+	if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+		dev_err(adapter->dev, "SEND DATA: failed to read "
+				      "REG_TXBD_RDPTR\n");
+		return -1;
+	}
+
+	wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+
+	dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
+				card->txbd_wrptr);
+	if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
+			(rdptr & MWIFIEX_TXBD_MASK)) ||
+	    ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+			(rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+		struct sk_buff *skb_data;
+		u8 *payload;
+
+		adapter->data_sent = true;
+		skb_data = card->tx_buf_list[wrindx];
+		memcpy(skb_data->data, skb->data, skb->len);
+		payload = skb_data->data;
+		tmp = (__le16 *)&payload[0];
+		*tmp = cpu_to_le16((u16)skb->len);
+		tmp = (__le16 *)&payload[2];
+		*tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
+		skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
+		skb_trim(skb_data, skb->len);
+		buf_pa = MWIFIEX_SKB_PACB(skb_data);
+		card->txbd_ring[wrindx]->paddr = *buf_pa;
+		card->txbd_ring[wrindx]->len = (u16)skb_data->len;
+		card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+						MWIFIEX_BD_FLAG_LAST_DESC;
+
+		if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
+							MWIFIEX_MAX_TXRX_BD)
+			card->txbd_wrptr = ((card->txbd_wrptr &
+						MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+						MWIFIEX_BD_FLAG_ROLLOVER_IND);
+
+		/* Write the TX ring write pointer in to REG_TXBD_WRPTR */
+		if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR,
+							card->txbd_wrptr)) {
+			dev_err(adapter->dev, "SEND DATA: failed to write "
+					      "REG_TXBD_WRPTR\n");
+			return 0;
+		}
+
+		/* Send the TX ready interrupt */
+		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+				      CPU_INTR_DNLD_RDY)) {
+			dev_err(adapter->dev, "SEND DATA: failed to assert "
+					      "door-bell interrupt.\n");
+			return -1;
+		}
+		dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
+				      "%#x> and sent packet to firmware "
+				      "successfully\n", rdptr,
+				      card->txbd_wrptr);
+	} else {
+		dev_dbg(adapter->dev, "info: TX Ring full, can't send anymore "
+				      "packets to firmware\n");
+		adapter->data_sent = true;
+		/* Send the TX ready interrupt */
+		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+				      CPU_INTR_DNLD_RDY))
+			dev_err(adapter->dev, "SEND DATA: failed to assert "
+					      "door-bell interrupt\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles received buffer ring and
+ * dispatches packets to upper
+ */
+static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	u32 wrptr, rd_index;
+	int ret = 0;
+	struct sk_buff *skb_tmp = NULL;
+
+	/* Read the RX ring Write pointer set by firmware */
+	if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+		dev_err(adapter->dev, "RECV DATA: failed to read "
+				      "REG_TXBD_RDPTR\n");
+		ret = -1;
+		goto done;
+	}
+
+	while (((wrptr & MWIFIEX_RXBD_MASK) !=
+		(card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
+	       ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
+		(card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+		struct sk_buff *skb_data;
+		u16 rx_len;
+
+		rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
+		skb_data = card->rx_buf_list[rd_index];
+
+		/* Get data length from interface header -
+		   first byte is len, second byte is type */
+		rx_len = *((u16 *)skb_data->data);
+		dev_dbg(adapter->dev, "info: RECV DATA: Rd=%#x, Wr=%#x, "
+				"Len=%d\n", card->rxbd_rdptr, wrptr, rx_len);
+		skb_tmp = dev_alloc_skb(rx_len);
+		if (!skb_tmp) {
+			dev_dbg(adapter->dev, "info: Failed to alloc skb "
+					      "for RX\n");
+			ret = -EBUSY;
+			goto done;
+		}
+
+		skb_put(skb_tmp, rx_len);
+
+		memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
+		if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
+							MWIFIEX_MAX_TXRX_BD) {
+			card->rxbd_rdptr = ((card->rxbd_rdptr &
+					     MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+					    MWIFIEX_BD_FLAG_ROLLOVER_IND);
+		}
+		dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
+				card->rxbd_rdptr, wrptr);
+
+		/* Write the RX ring read pointer in to REG_RXBD_RDPTR */
+		if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR,
+				      card->rxbd_rdptr)) {
+			dev_err(adapter->dev, "RECV DATA: failed to "
+					      "write REG_RXBD_RDPTR\n");
+			ret = -1;
+			goto done;
+		}
+
+		/* Read the RX ring Write pointer set by firmware */
+		if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+			dev_err(adapter->dev, "RECV DATA: failed to read "
+					      "REG_TXBD_RDPTR\n");
+			ret = -1;
+			goto done;
+		}
+		dev_dbg(adapter->dev, "info: RECV DATA: Received packet from "
+				      "firmware successfully\n");
+		mwifiex_handle_rx_packet(adapter, skb_tmp);
+	}
+
+done:
+	if (ret && skb_tmp)
+		dev_kfree_skb_any(skb_tmp);
+	return ret;
+}
+
+/*
+ * This function downloads the boot command to device
+ */
+static int
+mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+	phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+
+	if (!(skb->data && skb->len && *buf_pa)) {
+		dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x:%x, "
+				"%x>\n", __func__, skb->data, skb->len,
+				(u32)*buf_pa, (u32)((u64)*buf_pa >> 32));
+		return -1;
+	}
+
+	/* Write the lower 32bits of the physical address to scratch
+	 * register 0 */
+	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) {
+		dev_err(adapter->dev, "%s: failed to write download command "
+				      "to boot code.\n", __func__);
+		return -1;
+	}
+
+	/* Write the upper 32bits of the physical address to scratch
+	 * register 1 */
+	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
+			      (u32)((u64)*buf_pa >> 32))) {
+		dev_err(adapter->dev, "%s: failed to write download command "
+				      "to boot code.\n", __func__);
+		return -1;
+	}
+
+	/* Write the command length to scratch register 2 */
+	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) {
+		dev_err(adapter->dev, "%s: failed to write command length to "
+				      "scratch register 2\n", __func__);
+		return -1;
+	}
+
+	/* Ring the door bell */
+	if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+			      CPU_INTR_DOOR_BELL)) {
+		dev_err(adapter->dev, "%s: failed to assert door-bell "
+				      "interrupt.\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function downloads commands to the device
+ */
+static int
+mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+	struct pcie_service_card *card = adapter->card;
+	int ret = 0;
+	phys_addr_t *cmd_buf_pa;
+	phys_addr_t *cmdrsp_buf_pa;
+
+	if (!(skb->data && skb->len)) {
+		dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
+				      __func__, skb->data, skb->len);
+		return -1;
+	}
+
+	/* Make sure a command response buffer is available */
+	if (!card->cmdrsp_buf) {
+		dev_err(adapter->dev, "No response buffer available, send "
+				      "command failed\n");
+		return -EBUSY;
+	}
+
+	/* Make sure a command buffer is available */
+	if (!card->cmd_buf) {
+		dev_err(adapter->dev, "Command buffer not available\n");
+		return -EBUSY;
+	}
+
+	adapter->cmd_sent = true;
+	/* Copy the given skb in to DMA accessable shared buffer */
+	skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len);
+	skb_trim(card->cmd_buf, skb->len);
+	memcpy(card->cmd_buf->data, skb->data, skb->len);
+
+	/* To send a command, the driver will:
+		1. Write the 64bit physical address of the data buffer to
+		   SCRATCH1 + SCRATCH0
+		2. Ring the door bell (i.e. set the door bell interrupt)
+
+		In response to door bell interrupt, the firmware will perform
+		the DMA of the command packet (first header to obtain the total
+		length and then rest of the command).
+	*/
+
+	if (card->cmdrsp_buf) {
+		cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf);
+		/* Write the lower 32bits of the cmdrsp buffer physical
+		   address */
+		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
+					(u32)*cmdrsp_buf_pa)) {
+			dev_err(adapter->dev, "Failed to write download command to boot code.\n");
+			ret = -1;
+			goto done;
+		}
+		/* Write the upper 32bits of the cmdrsp buffer physical
+		   address */
+		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
+					(u32)((u64)*cmdrsp_buf_pa >> 32))) {
+			dev_err(adapter->dev, "Failed to write download command"
+					      " to boot code.\n");
+			ret = -1;
+			goto done;
+		}
+	}
+
+	cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf);
+	/* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
+	if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO,
+				(u32)*cmd_buf_pa)) {
+		dev_err(adapter->dev, "Failed to write download command "
+				      "to boot code.\n");
+		ret = -1;
+		goto done;
+	}
+	/* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
+	if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
+				(u32)((u64)*cmd_buf_pa >> 32))) {
+		dev_err(adapter->dev, "Failed to write download command "
+				      "to boot code.\n");
+		ret = -1;
+		goto done;
+	}
+
+	/* Write the command length to REG_CMD_SIZE */
+	if (mwifiex_write_reg(adapter, REG_CMD_SIZE,
+				card->cmd_buf->len)) {
+		dev_err(adapter->dev, "Failed to write command length to "
+				      "REG_CMD_SIZE\n");
+		ret = -1;
+		goto done;
+	}
+
+	/* Ring the door bell */
+	if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+			      CPU_INTR_DOOR_BELL)) {
+		dev_err(adapter->dev, "Failed to assert door-bell "
+				      "interrupt.\n");
+		ret = -1;
+		goto done;
+	}
+
+done:
+	if (ret)
+		adapter->cmd_sent = false;
+
+	return 0;
+}
+
+/*
+ * This function handles command complete interrupt
+ */
+static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	int count = 0;
+
+	dev_dbg(adapter->dev, "info: Rx CMD Response\n");
+
+	if (!adapter->curr_cmd) {
+		skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN);
+		if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
+			mwifiex_process_sleep_confirm_resp(adapter,
+					card->cmdrsp_buf->data,
+					card->cmdrsp_buf->len);
+			while (mwifiex_pcie_ok_to_access_hw(adapter) &&
+							(count++ < 10))
+				udelay(50);
+		} else {
+			dev_err(adapter->dev, "There is no command but "
+					      "got cmdrsp\n");
+		}
+		memcpy(adapter->upld_buf, card->cmdrsp_buf->data,
+		       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER,
+			     card->cmdrsp_buf->len));
+		skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+	} else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+		skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN);
+		adapter->curr_cmd->resp_skb = card->cmdrsp_buf;
+		adapter->cmd_resp_received = true;
+		/* Take the pointer and set it to CMD node and will
+		   return in the response complete callback */
+		card->cmdrsp_buf = NULL;
+
+		/* Clear the cmd-rsp buffer address in scratch registers. This
+		   will prevent firmware from writing to the same response
+		   buffer again. */
+		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) {
+			dev_err(adapter->dev, "cmd_done: failed to clear "
+					      "cmd_rsp address.\n");
+			return -1;
+		}
+		/* Write the upper 32bits of the cmdrsp buffer physical
+		   address */
+		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) {
+			dev_err(adapter->dev, "cmd_done: failed to clear "
+					      "cmd_rsp address.\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Command Response processing complete handler
+ */
+static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
+					struct sk_buff *skb)
+{
+	struct pcie_service_card *card = adapter->card;
+
+	if (skb) {
+		card->cmdrsp_buf = skb;
+		skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+	}
+
+	return 0;
+}
+
+/*
+ * This function handles firmware event ready interrupt
+ */
+static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
+	u32 wrptr, event;
+
+	if (adapter->event_received) {
+		dev_dbg(adapter->dev, "info: Event being processed, "\
+				"do not process this interrupt just yet\n");
+		return 0;
+	}
+
+	if (rdptr >= MWIFIEX_MAX_EVT_BD) {
+		dev_dbg(adapter->dev, "info: Invalid read pointer...\n");
+		return -1;
+	}
+
+	/* Read the event ring write pointer set by firmware */
+	if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+		dev_err(adapter->dev, "EventReady: failed to read REG_EVTBD_WRPTR\n");
+		return -1;
+	}
+
+	dev_dbg(adapter->dev, "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
+			card->evtbd_rdptr, wrptr);
+	if (((wrptr & MWIFIEX_EVTBD_MASK) !=
+	     (card->evtbd_rdptr & MWIFIEX_EVTBD_MASK)) ||
+	    ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
+	     (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+		struct sk_buff *skb_cmd;
+		__le16 data_len = 0;
+		u16 evt_len;
+
+		dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
+		skb_cmd = card->evt_buf_list[rdptr];
+		/* Take the pointer and set it to event pointer in adapter
+		   and will return back after event handling callback */
+		card->evt_buf_list[rdptr] = NULL;
+		card->evtbd_ring[rdptr]->paddr = 0;
+		card->evtbd_ring[rdptr]->len = 0;
+		card->evtbd_ring[rdptr]->flags = 0;
+
+		event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN];
+		adapter->event_cause = event;
+		/* The first 4bytes will be the event transfer header
+		   len is 2 bytes followed by type which is 2 bytes */
+		memcpy(&data_len, skb_cmd->data, sizeof(__le16));
+		evt_len = le16_to_cpu(data_len);
+
+		skb_pull(skb_cmd, INTF_HEADER_LEN);
+		dev_dbg(adapter->dev, "info: Event length: %d\n", evt_len);
+
+		if ((evt_len > 0) && (evt_len  < MAX_EVENT_SIZE))
+			memcpy(adapter->event_body, skb_cmd->data +
+			       MWIFIEX_EVENT_HEADER_LEN, evt_len -
+			       MWIFIEX_EVENT_HEADER_LEN);
+
+		adapter->event_received = true;
+		adapter->event_skb = skb_cmd;
+
+		/* Do not update the event read pointer here, wait till the
+		   buffer is released. This is just to make things simpler,
+		   we need to find a better method of managing these buffers.
+		*/
+	}
+
+	return 0;
+}
+
+/*
+ * Event processing complete handler
+ */
+static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
+				       struct sk_buff *skb)
+{
+	struct pcie_service_card *card = adapter->card;
+	int ret = 0;
+	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
+	u32 wrptr;
+	phys_addr_t *buf_pa;
+
+	if (!skb)
+		return 0;
+
+	if (rdptr >= MWIFIEX_MAX_EVT_BD)
+		dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
+					rdptr);
+
+	/* Read the event ring write pointer set by firmware */
+	if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+		dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_WRPTR\n");
+		ret = -1;
+		goto done;
+	}
+
+	if (!card->evt_buf_list[rdptr]) {
+		skb_push(skb, INTF_HEADER_LEN);
+		card->evt_buf_list[rdptr] = skb;
+		buf_pa = MWIFIEX_SKB_PACB(skb);
+		card->evtbd_ring[rdptr]->paddr = *buf_pa;
+		card->evtbd_ring[rdptr]->len = (u16)skb->len;
+		card->evtbd_ring[rdptr]->flags = 0;
+		skb = NULL;
+	} else {
+		dev_dbg(adapter->dev, "info: ERROR: Buffer is still valid at "
+				      "index %d, <%p, %p>\n", rdptr,
+				      card->evt_buf_list[rdptr], skb);
+	}
+
+	if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
+		card->evtbd_rdptr = ((card->evtbd_rdptr &
+					MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+					MWIFIEX_BD_FLAG_ROLLOVER_IND);
+	}
+
+	dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
+				card->evtbd_rdptr, wrptr);
+
+	/* Write the event ring read pointer in to REG_EVTBD_RDPTR */
+	if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) {
+		dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_RDPTR\n");
+		ret = -1;
+		goto done;
+	}
+
+done:
+	/* Free the buffer for failure case */
+	if (ret && skb)
+		dev_kfree_skb_any(skb);
+
+	dev_dbg(adapter->dev, "info: Check Events Again\n");
+	ret = mwifiex_pcie_process_event_ready(adapter);
+
+	return ret;
+}
+
+/*
+ * This function downloads the firmware to the card.
+ *
+ * Firmware is downloaded to the card in blocks. Every block download
+ * is tested for CRC errors, and retried a number of times before
+ * returning failure.
+ */
+static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
+				    struct mwifiex_fw_image *fw)
+{
+	int ret;
+	u8 *firmware = fw->fw_buf;
+	u32 firmware_len = fw->fw_len;
+	u32 offset = 0;
+	struct sk_buff *skb;
+	u32 txlen, tx_blocks = 0, tries, len;
+	u32 block_retry_cnt = 0;
+
+	if (!adapter) {
+		pr_err("adapter structure is not valid\n");
+		return -1;
+	}
+
+	if (!firmware || !firmware_len) {
+		dev_err(adapter->dev, "No firmware image found! "
+				      "Terminating download\n");
+		return -1;
+	}
+
+	dev_dbg(adapter->dev, "info: Downloading FW image (%d bytes)\n",
+				firmware_len);
+
+	if (mwifiex_pcie_disable_host_int(adapter)) {
+		dev_err(adapter->dev, "%s: Disabling interrupts"
+				      " failed.\n", __func__);
+		return -1;
+	}
+
+	skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
+	if (!skb) {
+		ret = -ENOMEM;
+		goto done;
+	}
+	mwifiex_update_sk_buff_pa(skb);
+
+	/* Perform firmware data transfer */
+	do {
+		u32 ireg_intr = 0;
+
+		/* More data? */
+		if (offset >= firmware_len)
+			break;
+
+		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+			ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG,
+					       &len);
+			if (ret) {
+				dev_warn(adapter->dev, "Failed reading length from boot code\n");
+				goto done;
+			}
+			if (len)
+				break;
+			udelay(10);
+		}
+
+		if (!len) {
+			break;
+		} else if (len > MWIFIEX_UPLD_SIZE) {
+			pr_err("FW download failure @ %d, invalid length %d\n",
+				offset, len);
+			ret = -1;
+			goto done;
+		}
+
+		txlen = len;
+
+		if (len & BIT(0)) {
+			block_retry_cnt++;
+			if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
+				pr_err("FW download failure @ %d, over max "
+				       "retry count\n", offset);
+				ret = -1;
+				goto done;
+			}
+			dev_err(adapter->dev, "FW CRC error indicated by the "
+					      "helper: len = 0x%04X, txlen = "
+					      "%d\n", len, txlen);
+			len &= ~BIT(0);
+			/* Setting this to 0 to resend from same offset */
+			txlen = 0;
+		} else {
+			block_retry_cnt = 0;
+			/* Set blocksize to transfer - checking for
+			   last block */
+			if (firmware_len - offset < txlen)
+				txlen = firmware_len - offset;
+
+			dev_dbg(adapter->dev, ".");
+
+			tx_blocks =
+				(txlen + MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) /
+				MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD;
+
+			/* Copy payload to buffer */
+			memmove(skb->data, &firmware[offset], txlen);
+		}
+
+		skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
+		skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD);
+
+		/* Send the boot command to device */
+		if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
+			dev_err(adapter->dev, "Failed to send firmware download command\n");
+			ret = -1;
+			goto done;
+		}
+		/* Wait for the command done interrupt */
+		do {
+			if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
+					     &ireg_intr)) {
+				dev_err(adapter->dev, "%s: Failed to read "
+						      "interrupt status during "
+						      "fw dnld.\n", __func__);
+				ret = -1;
+				goto done;
+			}
+		} while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
+			 CPU_INTR_DOOR_BELL);
+		offset += txlen;
+	} while (true);
+
+	dev_dbg(adapter->dev, "info:\nFW download over, size %d bytes\n",
+				offset);
+
+	ret = 0;
+
+done:
+	dev_kfree_skb_any(skb);
+	return ret;
+}
+
+/*
+ * This function checks the firmware status in card.
+ *
+ * The winner interface is also determined by this function.
+ */
+static int
+mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
+{
+	int ret = 0;
+	u32 firmware_stat, winner_status;
+	u32 tries;
+
+	/* Mask spurios interrupts */
+	if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK,
+				HOST_INTR_MASK)) {
+		dev_warn(adapter->dev, "Write register failed\n");
+		return -1;
+	}
+
+	dev_dbg(adapter->dev, "Setting driver ready signature\n");
+	if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) {
+		dev_err(adapter->dev, "Failed to write driver ready signature\n");
+		return -1;
+	}
+
+	/* Wait for firmware initialization event */
+	for (tries = 0; tries < poll_num; tries++) {
+		if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+				     &firmware_stat))
+			ret = -1;
+		else
+			ret = 0;
+		if (ret)
+			continue;
+		if (firmware_stat == FIRMWARE_READY_PCIE) {
+			ret = 0;
+			break;
+		} else {
+			mdelay(100);
+			ret = -1;
+		}
+	}
+
+	if (ret) {
+		if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+				     &winner_status))
+			ret = -1;
+		else if (!winner_status) {
+			dev_err(adapter->dev, "PCI-E is the winner\n");
+			adapter->winner = 1;
+			ret = -1;
+		} else {
+			dev_err(adapter->dev, "PCI-E is not the winner <%#x, %d>, exit download\n",
+					ret, adapter->winner);
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * This function reads the interrupt status from card.
+ */
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+{
+	u32 pcie_ireg;
+	unsigned long flags;
+
+	if (!mwifiex_pcie_ok_to_access_hw(adapter))
+		return;
+
+	if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) {
+		dev_warn(adapter->dev, "Read register failed\n");
+		return;
+	}
+
+	if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+
+		mwifiex_pcie_disable_host_int(adapter);
+
+		/* Clear the pending interrupts */
+		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS,
+				      ~pcie_ireg)) {
+			dev_warn(adapter->dev, "Write register failed\n");
+			return;
+		}
+		spin_lock_irqsave(&adapter->int_lock, flags);
+		adapter->int_status |= pcie_ireg;
+		spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+		if (pcie_ireg & HOST_INTR_CMD_DONE) {
+			if ((adapter->ps_state == PS_STATE_SLEEP_CFM) ||
+			    (adapter->ps_state == PS_STATE_SLEEP)) {
+				mwifiex_pcie_enable_host_int(adapter);
+				if (mwifiex_write_reg(adapter,
+						PCIE_CPU_INT_EVENT,
+						CPU_INTR_SLEEP_CFM_DONE)) {
+					dev_warn(adapter->dev, "Write register"
+							       " failed\n");
+					return;
+
+				}
+			}
+		} else if (!adapter->pps_uapsd_mode &&
+			   adapter->ps_state == PS_STATE_SLEEP) {
+				/* Potentially for PCIe we could get other
+				 * interrupts like shared. Don't change power
+				 * state until cookie is set */
+				if (mwifiex_pcie_ok_to_access_hw(adapter))
+					adapter->ps_state = PS_STATE_AWAKE;
+		}
+	}
+}
+
+/*
+ * Interrupt handler for PCIe root port
+ *
+ * This function reads the interrupt status from firmware and assigns
+ * the main process in workqueue which will handle the interrupt.
+ */
+static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
+{
+	struct pci_dev *pdev = (struct pci_dev *)context;
+	struct pcie_service_card *card;
+	struct mwifiex_adapter *adapter;
+
+	if (!pdev) {
+		pr_debug("info: %s: pdev is NULL\n", (u8 *)pdev);
+		goto exit;
+	}
+
+	card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+	if (!card || !card->adapter) {
+		pr_debug("info: %s: card=%p adapter=%p\n", __func__, card,
+						card ? card->adapter : NULL);
+		goto exit;
+	}
+	adapter = card->adapter;
+
+	if (adapter->surprise_removed)
+		goto exit;
+
+	mwifiex_interrupt_status(adapter);
+	queue_work(adapter->workqueue, &adapter->main_work);
+
+exit:
+	return IRQ_HANDLED;
+}
+
+/*
+ * This function checks the current interrupt status.
+ *
+ * The following interrupts are checked and handled by this function -
+ *      - Data sent
+ *      - Command sent
+ *      - Command received
+ *      - Packets received
+ *      - Events received
+ *
+ * In case of Rx packets received, the packets are uploaded from card to
+ * host and processed accordingly.
+ */
+static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+{
+	int ret;
+	u32 pcie_ireg = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->int_lock, flags);
+	/* Clear out unused interrupts */
+	adapter->int_status &= HOST_INTR_MASK;
+	spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+	while (adapter->int_status & HOST_INTR_MASK) {
+		if (adapter->int_status & HOST_INTR_DNLD_DONE) {
+			adapter->int_status &= ~HOST_INTR_DNLD_DONE;
+			if (adapter->data_sent) {
+				dev_dbg(adapter->dev, "info: DATA sent Interrupt\n");
+				adapter->data_sent = false;
+			}
+		}
+		if (adapter->int_status & HOST_INTR_UPLD_RDY) {
+			adapter->int_status &= ~HOST_INTR_UPLD_RDY;
+			dev_dbg(adapter->dev, "info: Rx DATA\n");
+			ret = mwifiex_pcie_process_recv_data(adapter);
+			if (ret)
+				return ret;
+		}
+		if (adapter->int_status & HOST_INTR_EVENT_RDY) {
+			adapter->int_status &= ~HOST_INTR_EVENT_RDY;
+			dev_dbg(adapter->dev, "info: Rx EVENT\n");
+			ret = mwifiex_pcie_process_event_ready(adapter);
+			if (ret)
+				return ret;
+		}
+
+		if (adapter->int_status & HOST_INTR_CMD_DONE) {
+			adapter->int_status &= ~HOST_INTR_CMD_DONE;
+			if (adapter->cmd_sent) {
+				dev_dbg(adapter->dev, "info: CMD sent Interrupt\n");
+				adapter->cmd_sent = false;
+			}
+			/* Handle command response */
+			ret = mwifiex_pcie_process_cmd_complete(adapter);
+			if (ret)
+				return ret;
+		}
+
+		if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+			if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
+					     &pcie_ireg)) {
+				dev_warn(adapter->dev, "Read register failed\n");
+				return -1;
+			}
+
+			if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+				if (mwifiex_write_reg(adapter,
+					PCIE_HOST_INT_STATUS, ~pcie_ireg)) {
+					dev_warn(adapter->dev, "Write register"
+							       " failed\n");
+					return -1;
+				}
+				adapter->int_status |= pcie_ireg;
+				adapter->int_status &= HOST_INTR_MASK;
+			}
+
+		}
+	}
+	dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
+	       adapter->cmd_sent, adapter->data_sent);
+	mwifiex_pcie_enable_host_int(adapter);
+
+	return 0;
+}
+
+/*
+ * This function downloads data from driver to card.
+ *
+ * Both commands and data packets are transferred to the card by this
+ * function.
+ *
+ * This function adds the PCIE specific header to the front of the buffer
+ * before transferring. The header contains the length of the packet and
+ * the type. The firmware handles the packets based upon this set type.
+ */
+static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
+				     struct sk_buff *skb,
+				     struct mwifiex_tx_param *tx_param)
+{
+	if (!adapter || !skb) {
+		dev_err(adapter->dev, "Invalid parameter in %s <%p, %p>\n",
+				__func__, adapter, skb);
+		return -1;
+	}
+
+	if (type == MWIFIEX_TYPE_DATA)
+		return mwifiex_pcie_send_data(adapter, skb);
+	else if (type == MWIFIEX_TYPE_CMD)
+		return mwifiex_pcie_send_cmd(adapter, skb);
+
+	return 0;
+}
+
+/*
+ * This function initializes the PCI-E host memory space, WCB rings, etc.
+ *
+ * The following initializations steps are followed -
+ *      - Allocate TXBD ring buffers
+ *      - Allocate RXBD ring buffers
+ *      - Allocate event BD ring buffers
+ *      - Allocate command response ring buffer
+ *      - Allocate sleep cookie buffer
+ */
+static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	int ret;
+	struct pci_dev *pdev = card->dev;
+
+	pci_set_drvdata(pdev, card);
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto err_enable_dev;
+
+	pci_set_master(pdev);
+
+	dev_dbg(adapter->dev, "try set_consistent_dma_mask(32)\n");
+	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(adapter->dev, "set_dma_mask(32) failed\n");
+		goto err_set_dma_mask;
+	}
+
+	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(adapter->dev, "set_consistent_dma_mask(64) failed\n");
+		goto err_set_dma_mask;
+	}
+
+	ret = pci_request_region(pdev, 0, DRV_NAME);
+	if (ret) {
+		dev_err(adapter->dev, "req_reg(0) error\n");
+		goto err_req_region0;
+	}
+	card->pci_mmap = pci_iomap(pdev, 0, 0);
+	if (!card->pci_mmap) {
+		dev_err(adapter->dev, "iomap(0) error\n");
+		goto err_iomap0;
+	}
+	ret = pci_request_region(pdev, 2, DRV_NAME);
+	if (ret) {
+		dev_err(adapter->dev, "req_reg(2) error\n");
+		goto err_req_region2;
+	}
+	card->pci_mmap1 = pci_iomap(pdev, 2, 0);
+	if (!card->pci_mmap1) {
+		dev_err(adapter->dev, "iomap(2) error\n");
+		goto err_iomap2;
+	}
+
+	dev_dbg(adapter->dev, "PCI memory map Virt0: %p PCI memory map Virt2: "
+			      "%p\n", card->pci_mmap, card->pci_mmap1);
+
+	card->cmdrsp_buf = NULL;
+	ret = mwifiex_pcie_create_txbd_ring(adapter);
+	if (ret)
+		goto err_cre_txbd;
+	ret = mwifiex_pcie_create_rxbd_ring(adapter);
+	if (ret)
+		goto err_cre_rxbd;
+	ret = mwifiex_pcie_create_evtbd_ring(adapter);
+	if (ret)
+		goto err_cre_evtbd;
+	ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
+	if (ret)
+		goto err_alloc_cmdbuf;
+	ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
+	if (ret)
+		goto err_alloc_cookie;
+
+	return ret;
+
+err_alloc_cookie:
+	mwifiex_pcie_delete_cmdrsp_buf(adapter);
+err_alloc_cmdbuf:
+	mwifiex_pcie_delete_evtbd_ring(adapter);
+err_cre_evtbd:
+	mwifiex_pcie_delete_rxbd_ring(adapter);
+err_cre_rxbd:
+	mwifiex_pcie_delete_txbd_ring(adapter);
+err_cre_txbd:
+	pci_iounmap(pdev, card->pci_mmap1);
+err_iomap2:
+	pci_release_region(pdev, 2);
+err_req_region2:
+	pci_iounmap(pdev, card->pci_mmap);
+err_iomap0:
+	pci_release_region(pdev, 0);
+err_req_region0:
+err_set_dma_mask:
+	pci_disable_device(pdev);
+err_enable_dev:
+	pci_set_drvdata(pdev, NULL);
+	return ret;
+}
+
+/*
+ * This function cleans up the allocated card buffers.
+ *
+ * The following are freed by this function -
+ *      - TXBD ring buffers
+ *      - RXBD ring buffers
+ *      - Event BD ring buffers
+ *      - Command response ring buffer
+ *      - Sleep cookie buffer
+ */
+static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct pci_dev *pdev = card->dev;
+
+	mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+	mwifiex_pcie_delete_cmdrsp_buf(adapter);
+	mwifiex_pcie_delete_evtbd_ring(adapter);
+	mwifiex_pcie_delete_rxbd_ring(adapter);
+	mwifiex_pcie_delete_txbd_ring(adapter);
+	card->cmdrsp_buf = NULL;
+
+	dev_dbg(adapter->dev, "Clearing driver ready signature\n");
+	if (user_rmmod) {
+		if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
+			dev_err(adapter->dev, "Failed to write driver not-ready signature\n");
+	}
+
+	if (pdev) {
+		pci_iounmap(pdev, card->pci_mmap);
+		pci_iounmap(pdev, card->pci_mmap1);
+
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+/*
+ * This function registers the PCIE device.
+ *
+ * PCIE IRQ is claimed, block size is set and driver data is initialized.
+ */
+static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
+{
+	int ret;
+	struct pcie_service_card *card = adapter->card;
+	struct pci_dev *pdev = card->dev;
+
+	/* save adapter pointer in card */
+	card->adapter = adapter;
+
+	ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
+			  "MRVL_PCIE", pdev);
+	if (ret) {
+		pr_err("request_irq failed: ret=%d\n", ret);
+		adapter->card = NULL;
+		return -1;
+	}
+
+	adapter->dev = &pdev->dev;
+	strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
+
+	return 0;
+}
+
+/*
+ * This function unregisters the PCIE device.
+ *
+ * The PCIE IRQ is released, the function is disabled and driver
+ * data is set to null.
+ */
+static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+
+	if (card) {
+		dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
+		free_irq(card->dev->irq, card->dev);
+	}
+}
+
+static struct mwifiex_if_ops pcie_ops = {
+	.init_if =			mwifiex_pcie_init,
+	.cleanup_if =			mwifiex_pcie_cleanup,
+	.check_fw_status =		mwifiex_check_fw_status,
+	.prog_fw =			mwifiex_prog_fw_w_helper,
+	.register_dev =			mwifiex_register_dev,
+	.unregister_dev =		mwifiex_unregister_dev,
+	.enable_int =			mwifiex_pcie_enable_host_int,
+	.process_int_status =		mwifiex_process_int_status,
+	.host_to_card =			mwifiex_pcie_host_to_card,
+	.wakeup =			mwifiex_pm_wakeup_card,
+	.wakeup_complete =		mwifiex_pm_wakeup_card_complete,
+
+	/* PCIE specific */
+	.cmdrsp_complete =		mwifiex_pcie_cmdrsp_complete,
+	.event_complete =		mwifiex_pcie_event_complete,
+	.update_mp_end_port =		NULL,
+	.cleanup_mpa_buf =		NULL,
+};
+
+/*
+ * This function initializes the PCIE driver module.
+ *
+ * This initiates the semaphore and registers the device with
+ * PCIE bus.
+ */
+static int mwifiex_pcie_init_module(void)
+{
+	int ret;
+
+	pr_debug("Marvell 8766 PCIe Driver\n");
+
+	sema_init(&add_remove_card_sem, 1);
+
+	/* Clear the flag in case user removes the card. */
+	user_rmmod = 0;
+
+	ret = pci_register_driver(&mwifiex_pcie);
+	if (ret)
+		pr_err("Driver register failed!\n");
+	else
+		pr_debug("info: Driver registered successfully!\n");
+
+	return ret;
+}
+
+/*
+ * This function cleans up the PCIE driver.
+ *
+ * The following major steps are followed for cleanup -
+ *      - Resume the device if its suspended
+ *      - Disconnect the device if connected
+ *      - Shutdown the firmware
+ *      - Unregister the device from PCIE bus.
+ */
+static void mwifiex_pcie_cleanup_module(void)
+{
+	if (!down_interruptible(&add_remove_card_sem))
+		up(&add_remove_card_sem);
+
+	/* Set the flag as user is removing this module. */
+	user_rmmod = 1;
+
+	pci_unregister_driver(&mwifiex_pcie);
+}
+
+module_init(mwifiex_pcie_init_module);
+module_exit(mwifiex_pcie_cleanup_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
+MODULE_VERSION(PCIE_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin");
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
new file mode 100644
index 0000000..445ff21
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -0,0 +1,148 @@
+/* @file mwifiex_pcie.h
+ *
+ * @brief This file contains definitions for PCI-E interface.
+ * driver.
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef	_MWIFIEX_PCIE_H
+#define	_MWIFIEX_PCIE_H
+
+#include    <linux/pci.h>
+#include    <linux/pcieport_if.h>
+#include    <linux/interrupt.h>
+
+#include    "main.h"
+
+#define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
+
+/* Constants for Buffer Descriptor (BD) rings */
+#define MWIFIEX_MAX_TXRX_BD			0x20
+#define MWIFIEX_TXBD_MASK			0x3F
+#define MWIFIEX_RXBD_MASK			0x3F
+
+#define MWIFIEX_MAX_EVT_BD			0x04
+#define MWIFIEX_EVTBD_MASK			0x07
+
+/* PCIE INTERNAL REGISTERS */
+#define PCIE_SCRATCH_0_REG				0xC10
+#define PCIE_SCRATCH_1_REG				0xC14
+#define PCIE_CPU_INT_EVENT				0xC18
+#define PCIE_CPU_INT_STATUS				0xC1C
+#define PCIE_HOST_INT_STATUS				0xC30
+#define PCIE_HOST_INT_MASK				0xC34
+#define PCIE_HOST_INT_STATUS_MASK			0xC3C
+#define PCIE_SCRATCH_2_REG				0xC40
+#define PCIE_SCRATCH_3_REG				0xC44
+#define PCIE_SCRATCH_4_REG				0xCC0
+#define PCIE_SCRATCH_5_REG				0xCC4
+#define PCIE_SCRATCH_6_REG				0xCC8
+#define PCIE_SCRATCH_7_REG				0xCCC
+#define PCIE_SCRATCH_8_REG				0xCD0
+#define PCIE_SCRATCH_9_REG				0xCD4
+#define PCIE_SCRATCH_10_REG				0xCD8
+#define PCIE_SCRATCH_11_REG				0xCDC
+#define PCIE_SCRATCH_12_REG				0xCE0
+
+#define CPU_INTR_DNLD_RDY				BIT(0)
+#define CPU_INTR_DOOR_BELL				BIT(1)
+#define CPU_INTR_SLEEP_CFM_DONE			BIT(2)
+#define CPU_INTR_RESET					BIT(3)
+
+#define HOST_INTR_DNLD_DONE				BIT(0)
+#define HOST_INTR_UPLD_RDY				BIT(1)
+#define HOST_INTR_CMD_DONE				BIT(2)
+#define HOST_INTR_EVENT_RDY				BIT(3)
+#define HOST_INTR_MASK					(HOST_INTR_DNLD_DONE | \
+							 HOST_INTR_UPLD_RDY  | \
+							 HOST_INTR_CMD_DONE  | \
+							 HOST_INTR_EVENT_RDY)
+
+#define MWIFIEX_BD_FLAG_ROLLOVER_IND			BIT(7)
+#define MWIFIEX_BD_FLAG_FIRST_DESC			BIT(0)
+#define MWIFIEX_BD_FLAG_LAST_DESC			BIT(1)
+#define REG_CMD_ADDR_LO					PCIE_SCRATCH_0_REG
+#define REG_CMD_ADDR_HI					PCIE_SCRATCH_1_REG
+#define REG_CMD_SIZE					PCIE_SCRATCH_2_REG
+
+#define REG_CMDRSP_ADDR_LO				PCIE_SCRATCH_4_REG
+#define REG_CMDRSP_ADDR_HI				PCIE_SCRATCH_5_REG
+
+/* TX buffer description read pointer */
+#define REG_TXBD_RDPTR					PCIE_SCRATCH_6_REG
+/* TX buffer description write pointer */
+#define REG_TXBD_WRPTR					PCIE_SCRATCH_7_REG
+/* RX buffer description read pointer */
+#define REG_RXBD_RDPTR					PCIE_SCRATCH_8_REG
+/* RX buffer description write pointer */
+#define REG_RXBD_WRPTR					PCIE_SCRATCH_9_REG
+/* Event buffer description read pointer */
+#define REG_EVTBD_RDPTR					PCIE_SCRATCH_10_REG
+/* Event buffer description write pointer */
+#define REG_EVTBD_WRPTR					PCIE_SCRATCH_11_REG
+/* Driver ready signature write pointer */
+#define REG_DRV_READY					PCIE_SCRATCH_12_REG
+
+/* Max retry number of command write */
+#define MAX_WRITE_IOMEM_RETRY				2
+/* Define PCIE block size for firmware download */
+#define MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD		256
+/* FW awake cookie after FW ready */
+#define FW_AWAKE_COOKIE						(0xAA55AA55)
+
+struct mwifiex_pcie_buf_desc {
+	u64 paddr;
+	u16 len;
+	u16 flags;
+} __packed;
+
+struct pcie_service_card {
+	struct pci_dev *dev;
+	struct mwifiex_adapter *adapter;
+
+	u32 txbd_wrptr;
+	u32 txbd_rdptr;
+	u32 txbd_ring_size;
+	u8 *txbd_ring_vbase;
+	phys_addr_t txbd_ring_pbase;
+	struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD];
+	struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
+
+	u32 rxbd_wrptr;
+	u32 rxbd_rdptr;
+	u32 rxbd_ring_size;
+	u8 *rxbd_ring_vbase;
+	phys_addr_t rxbd_ring_pbase;
+	struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
+	struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
+
+	u32 evtbd_wrptr;
+	u32 evtbd_rdptr;
+	u32 evtbd_ring_size;
+	u8 *evtbd_ring_vbase;
+	phys_addr_t evtbd_ring_pbase;
+	struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD];
+	struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
+
+	struct sk_buff *cmd_buf;
+	struct sk_buff *cmdrsp_buf;
+	struct sk_buff *sleep_cookie;
+	void __iomem *pci_mmap;
+	void __iomem *pci_mmap1;
+};
+
+#endif /* _MWIFIEX_PCIE_H */
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 82098ac..283171b 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -89,7 +89,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
 		return -EIO;
 	}
 
-	if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
+	if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops,
+			     MWIFIEX_SDIO)) {
 		pr_err("%s: add card failed\n", __func__);
 		kfree(card);
 		sdio_claim_host(func);
@@ -830,7 +831,7 @@ done:
  * The winner interface is also determined by this function.
  */
 static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
-				   u32 poll_num, int *winner)
+				   u32 poll_num)
 {
 	int ret = 0;
 	u16 firmware_stat;
@@ -842,7 +843,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
 		ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
 		if (ret)
 			continue;
-		if (firmware_stat == FIRMWARE_READY) {
+		if (firmware_stat == FIRMWARE_READY_SDIO) {
 			ret = 0;
 			break;
 		} else {
@@ -851,15 +852,15 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
 		}
 	}
 
-	if (winner && ret) {
+	if (ret) {
 		if (mwifiex_read_reg
 		    (adapter, CARD_FW_STATUS0_REG, &winner_status))
 			winner_status = 0;
 
 		if (winner_status)
-			*winner = 0;
+			adapter->winner = 0;
 		else
-			*winner = 1;
+			adapter->winner = 1;
 	}
 	return ret;
 }
@@ -1413,7 +1414,7 @@ tx_curr_single:
  * the type. The firmware handles the packets based upon this set type.
  */
 static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
-				     u8 type, u8 *payload, u32 pkt_len,
+				     u8 type, struct sk_buff *skb,
 				     struct mwifiex_tx_param *tx_param)
 {
 	struct sdio_mmc_card *card = adapter->card;
@@ -1421,6 +1422,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
 	u32 buf_block_len;
 	u32 blk_size;
 	u8 port = CTRL_PORT;
+	u8 *payload = (u8 *)skb->data;
+	u32 pkt_len = skb->len;
 
 	/* Allocate buffer and copy payload */
 	blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
@@ -1722,6 +1725,8 @@ static struct mwifiex_if_ops sdio_ops = {
 	/* SDIO specific */
 	.update_mp_end_port = mwifiex_update_mp_end_port,
 	.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
+	.cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
+	.event_complete = mwifiex_sdio_event_complete,
 };
 
 /*
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 524f78f..3f71180 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -169,9 +169,6 @@
 /* Rx unit register */
 #define CARD_RX_UNIT_REG		0x63
 
-/* Event header len w/o 4 bytes of interface header */
-#define MWIFIEX_EVENT_HEADER_LEN           4
-
 /* Max retry number of CMD53 write */
 #define MAX_WRITE_IOMEM_RETRY		2
 
@@ -304,4 +301,25 @@ struct sdio_mmc_card {
 	struct mwifiex_sdio_mpa_tx mpa_tx;
 	struct mwifiex_sdio_mpa_rx mpa_rx;
 };
+
+/*
+ * .cmdrsp_complete handler
+ */
+static inline int mwifiex_sdio_cmdrsp_complete(struct mwifiex_adapter *adapter,
+					       struct sk_buff *skb)
+{
+	dev_kfree_skb_any(skb);
+	return 0;
+}
+
+/*
+ * .event_complete handler
+ */
+static inline int mwifiex_sdio_event_complete(struct mwifiex_adapter *adapter,
+					      struct sk_buff *skb)
+{
+	dev_kfree_skb_any(skb);
+	return 0;
+}
+
 #endif /* _MWIFIEX_SDIO_H */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index c54ee28..ea6518d 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -902,6 +902,59 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
 }
 
 /*
+ * This function prepares command to set PCI-Express
+ * host buffer configuration
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Setting host buffer configuration
+ *      - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
+				   struct host_cmd_ds_command *cmd, u16 action)
+{
+	struct host_cmd_ds_pcie_details *host_spec =
+					&cmd->params.pcie_host_spec;
+	struct pcie_service_card *card = priv->adapter->card;
+	phys_addr_t *buf_pa;
+
+	cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
+	cmd->size = cpu_to_le16(sizeof(struct
+					host_cmd_ds_pcie_details) + S_DS_GEN);
+	cmd->result = 0;
+
+	memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details));
+
+	if (action == HostCmd_ACT_GEN_SET) {
+		/* Send the ring base addresses and count to firmware */
+		host_spec->txbd_addr_lo = (u32)(card->txbd_ring_pbase);
+		host_spec->txbd_addr_hi =
+				(u32)(((u64)card->txbd_ring_pbase)>>32);
+		host_spec->txbd_count = MWIFIEX_MAX_TXRX_BD;
+		host_spec->rxbd_addr_lo = (u32)(card->rxbd_ring_pbase);
+		host_spec->rxbd_addr_hi =
+				(u32)(((u64)card->rxbd_ring_pbase)>>32);
+		host_spec->rxbd_count = MWIFIEX_MAX_TXRX_BD;
+		host_spec->evtbd_addr_lo =
+				(u32)(card->evtbd_ring_pbase);
+		host_spec->evtbd_addr_hi =
+				(u32)(((u64)card->evtbd_ring_pbase)>>32);
+		host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD;
+		if (card->sleep_cookie) {
+			buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie);
+			host_spec->sleep_cookie_addr_lo = (u32) *buf_pa;
+			host_spec->sleep_cookie_addr_hi =
+						(u32) (((u64)*buf_pa) >> 32);
+			dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: "
+				 "0x%x\n", host_spec->sleep_cookie_addr_lo);
+		}
+	}
+
+	return 0;
+}
+
+/*
  * This function prepares the commands before sending them to the firmware.
  *
  * This is a generic function which calls specific command preparation
@@ -1079,6 +1132,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
 				host_cmd_ds_set_bss_mode) + S_DS_GEN);
 		ret = 0;
 		break;
+	case HostCmd_CMD_PCIE_DESC_DETAILS:
+		ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action);
+		break;
 	default:
 		dev_err(priv->adapter->dev,
 			"PREP_CMD: unknown cmd- %#x\n", cmd_no);
@@ -1095,6 +1151,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
  * working state.
  *
  * The following commands are issued sequentially -
+ *      - Set PCI-Express host buffer configuration (PCIE only)
  *      - Function init (for first interface only)
  *      - Read MAC address (for first interface only)
  *      - Reconfigure Tx buffer size (for first interface only)
@@ -1116,6 +1173,13 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
 	struct mwifiex_ds_11n_tx_cfg tx_cfg;
 
 	if (first_sta) {
+		if (priv->adapter->iface_type == MWIFIEX_PCIE) {
+			ret = mwifiex_send_cmd_async(priv,
+					HostCmd_CMD_PCIE_DESC_DETAILS,
+					HostCmd_ACT_GEN_SET, 0, NULL);
+			if (ret)
+				return -1;
+		}
 
 		ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
 					     HostCmd_ACT_GEN_SET, 0, NULL);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 6804239..7a16b0c 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -952,6 +952,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
 	case HostCmd_CMD_11N_CFG:
 		ret = mwifiex_ret_11n_cfg(resp, data_buf);
 		break;
+	case HostCmd_CMD_PCIE_DESC_DETAILS:
+		break;
 	default:
 		dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
 		       resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 1822bfa..d97facd 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -151,7 +151,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
 	skb_push(skb, INTF_HEADER_LEN);
 
 	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
-					     skb->data, skb->len, NULL);
+					   skb, NULL);
 	switch (ret) {
 	case -EBUSY:
 		adapter->data_sent = true;
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 5d95c4b..4c3421e 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -78,7 +78,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
 				(struct txpd *) (head_ptr + INTF_HEADER_LEN);
 
 		ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
-					     skb->data, skb->len, tx_param);
+						   skb, tx_param);
 	}
 
 	switch (ret) {
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
index 9506afc..f6d36b9 100644
--- a/drivers/net/wireless/mwifiex/util.h
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -22,11 +22,16 @@
 
 static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
 {
-	return (struct mwifiex_rxinfo *)skb->cb;
+	return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t));
 }
 
 static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
 {
-	return (struct mwifiex_txinfo *)skb->cb;
+	return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t));
+}
+
+static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb)
+{
+	return (phys_addr_t *)skb->cb;
 }
 #endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index eda2447..6c239c3 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -1125,8 +1125,8 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
 	tx_param.next_pkt_len =
 		((skb_next) ? skb_next->len +
 		 sizeof(struct txpd) : 0);
-	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
-					   skb->data, skb->len, &tx_param);
+	ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb,
+					   &tx_param);
 	switch (ret) {
 	case -EBUSY:
 		dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
-- 
1.7.0.2


^ permalink raw reply related

* RE: [PATCH] mwifiex: add support for Marvell pcie8766 chipset
From: Bing Zhao @ 2011-10-11 21:32 UTC (permalink / raw)
  To: John W. Linville, g@tuxdriver.com
  Cc: linux-wireless@vger.kernel.org, Amitkumar Karwar, Kiran Divekar,
	Yogesh Powar, Frank Huang
In-Reply-To: <20111011203936.GL6558@tuxdriver.com>

Hi John,

> -----Original Message-----
> From: John W. Linville [mailto:linville@tuxdriver.com]
> Sent: Tuesday, October 11, 2011 1:40 PM
> To: Bing Zhao; g@tuxdriver.com
> Cc: linux-wireless@vger.kernel.org; Amitkumar Karwar; Kiran Divekar; Yogesh Powar; Frank Huang
> Subject: Re: [PATCH] mwifiex: add support for Marvell pcie8766 chipset
> 
> On Thu, Oct 06, 2011 at 08:30:53PM -0700, Bing Zhao wrote:
> > Hi John,
> >
> > > -----Original Message-----
> > > From: Bing Zhao [mailto:bzhao@marvell.com]
> > > Sent: Monday, October 03, 2011 9:08 PM
> > > To: linux-wireless@vger.kernel.org
> > > Cc: John W. Linville; Amitkumar Karwar; Kiran Divekar; Yogesh Powar; Frank Huang; Bing Zhao
> > > Subject: [PATCH] mwifiex: add support for Marvell pcie8766 chipset
> > >
> > > From: Amitkumar Karwar <akarwar@marvell.com>
> > >
> > > This patch supports 88W8766P chipset with a PCIe interface.
> > >
> > > The corresponding firmware image file is located at:
> > > "mrvl/pcie8766_uapsta.bin"
> > >
> > > Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> > > Signed-off-by: Ramesh Radhakrishnan <rramesh@marvell.com>
> > > Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
> > > Signed-off-by: Kiran Divekar <dkiran@marvell.com>
> > > Signed-off-by: Bing Zhao <bzhao@marvell.com>
> > > Signed-off-by: Frank Huang <frankh@marvell.com>
> >
> > Could you please apply this patch? It doesn't depend on the other patches we are working on.
> >
> > Thanks,
> > Bing
> 
> It generates warnings...

Sorry about the warnings. I will fix them and resend v2 patch.

Thanks,
Bing

> 
>   LD [M]  drivers/net/wireless/mwifiex/mwifiex_pcie.o
> WARNING: drivers/net/wireless/mwifiex/mwifiex_pcie.o(.data+0x18): Section mismatch in reference from
> the variable mwifiex_pcie to the variable .devinit.rodata:mwifiex_ids
> The variable mwifiex_pcie references
> the variable __devinitconst mwifiex_ids
> If the reference is valid then annotate the
> variable with __init* or __refdata (see linux/init.h) or name the variable:
> *driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
> 
> WARNING: drivers/net/wireless/mwifiex/mwifiex_pcie.o(.data+0x20): Section mismatch in reference from
> the variable mwifiex_pcie to the function .devinit.text:mwifiex_pcie_probe()
> The variable mwifiex_pcie references
> the function __devinit mwifiex_pcie_probe()
> If the reference is valid then annotate the
> variable with __init* or __refdata (see linux/init.h) or name the variable:
> *driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
> 
> --
> John W. Linville		Someday the world will need a hero, and you
> linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH] mwifiex: add support for Marvell pcie8766 chipset
From: John W. Linville @ 2011-10-11 20:39 UTC (permalink / raw)
  To: Bing Zhao, g
  Cc: linux-wireless@vger.kernel.org, Amitkumar Karwar, Kiran Divekar,
	Yogesh Powar, Frank Huang
In-Reply-To: <477F20668A386D41ADCC57781B1F704308155977E8@SC-VEXCH1.marvell.com>

On Thu, Oct 06, 2011 at 08:30:53PM -0700, Bing Zhao wrote:
> Hi John,
> 
> > -----Original Message-----
> > From: Bing Zhao [mailto:bzhao@marvell.com]
> > Sent: Monday, October 03, 2011 9:08 PM
> > To: linux-wireless@vger.kernel.org
> > Cc: John W. Linville; Amitkumar Karwar; Kiran Divekar; Yogesh Powar; Frank Huang; Bing Zhao
> > Subject: [PATCH] mwifiex: add support for Marvell pcie8766 chipset
> > 
> > From: Amitkumar Karwar <akarwar@marvell.com>
> > 
> > This patch supports 88W8766P chipset with a PCIe interface.
> > 
> > The corresponding firmware image file is located at:
> > "mrvl/pcie8766_uapsta.bin"
> > 
> > Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> > Signed-off-by: Ramesh Radhakrishnan <rramesh@marvell.com>
> > Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
> > Signed-off-by: Kiran Divekar <dkiran@marvell.com>
> > Signed-off-by: Bing Zhao <bzhao@marvell.com>
> > Signed-off-by: Frank Huang <frankh@marvell.com>
> 
> Could you please apply this patch? It doesn't depend on the other patches we are working on.
> 
> Thanks,
> Bing

It generates warnings...

  LD [M]  drivers/net/wireless/mwifiex/mwifiex_pcie.o
WARNING: drivers/net/wireless/mwifiex/mwifiex_pcie.o(.data+0x18): Section mismatch in reference from the variable mwifiex_pcie to the variable .devinit.rodata:mwifiex_ids
The variable mwifiex_pcie references
the variable __devinitconst mwifiex_ids
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console

WARNING: drivers/net/wireless/mwifiex/mwifiex_pcie.o(.data+0x20): Section mismatch in reference from the variable mwifiex_pcie to the function .devinit.text:mwifiex_pcie_probe()
The variable mwifiex_pcie references
the function __devinit mwifiex_pcie_probe()
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH v2 1/5] ath6kl: Add endpoint_stats debugfs file
From: Joe Perches @ 2011-10-11 20:33 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: kvalo, linux-wireless
In-Reply-To: <20111011185228.GA20806@jouni.qca.qualcomm.com>

On Tue, 2011-10-11 at 21:52 +0300, Jouni Malinen wrote:
> On Tue, Oct 11, 2011 at 09:39:31AM -0700, Joe Perches wrote:
> > > +static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
> > > +					unsigned int buf_len, unsigned int len,
> > > +					int offset, const char *name)
> > Perhaps the function name is wrong.
> > This doesn't print, it fills a buffer.
> Well, it prints the stuff into a buffer just like scnprintf prints
> things.. Feel free to send a patch if you want to try to rename
> *print* functions ;-).

OK, s/print/scnprint/



^ permalink raw reply

* Re: [PATCH 4/5] rtlwifi: rtl8192se: Updates from latest Realtek driver version - Part II
From: John W. Linville @ 2011-10-11 20:16 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, Chaoming Li
In-Reply-To: <1318005802-29057-5-git-send-email-Larry.Finger@lwfinger.net>

On Fri, Oct 07, 2011 at 11:43:21AM -0500, Larry Finger wrote:
> From: Chaoming Li <chaoming_li@realsil.com.cn>
> 
> This patch incorporate the differences between the 06/20/2011 and
> 08/16/2011 Realtek releases of the rtl8192se driver.
> 
> The changes include:
> 
> 1. Fixing some typos in register usage.
> 2. A change in the handling of decryption status for 802.11w packets.
> 
> Signed-off-by: Chaoming Li <chaoming_li@realsil.com.cn>
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>

This patch doesn't apply (at least on wireless-next), and several of
the others required fixups as well.  What tree did you base this upon?

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH] iw: add DFS region parsing support
From: Luis R. Rodriguez @ 2011-10-11 20:25 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1318363042.15357.0.camel@jlt3.sipsolutions.net>

On Tue, Oct 11, 2011 at 12:57 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Tue, 2011-10-11 at 10:59 -0700, Luis R. Rodriguez wrote:
>
>> +     default:
>> +             printf("Uknown");
>
> typo.

Will fix.

> Also, I prefer patches w/o nl80211.h updates.

In my RFC on December the stars aligned differently and you preferred
it together I think.

  Luis

^ permalink raw reply

* Re: pull request: wireless-next 2011-10-11
From: John W. Linville @ 2011-10-11 19:51 UTC (permalink / raw)
  To: David Miller; +Cc: linux-wireless, netdev
In-Reply-To: <20111011.154526.442711861363485253.davem@davemloft.net>

On Tue, Oct 11, 2011 at 03:45:26PM -0400, David Miller wrote:
> From: "John W. Linville" <linville@tuxdriver.com>
> Date: Tue, 11 Oct 2011 15:38:06 -0400
> 
> > On Tue, Oct 11, 2011 at 03:16:16PM -0400, John W. Linville wrote:
> >> commit bfb3780bc9b622422c1f0d3e12371a70863000da
> >> 
> >> Dave,
> >> 
> >> Here is another wireless batch intended for 3.2...  Highlights include a
> >> bluetooth pull with some refactoring, a big pull of ath6kl updates, a
> >> flurry of mac80211 patches from Johannes, and the usual strong ath9k
> >> showing.
> >> 
> >> Please let me know if there are problems!
> > 
> > There was a problem -- a warning in ath6kl.  Sorry about that!
> > 
> > commit 094daf7db7c47861009899ce23f9177d761e20b0
> 
> I made sure I got the most recent changes.

Cool -- sorry for the confusion!

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH] iw: add DFS region parsing support
From: Johannes Berg @ 2011-10-11 19:57 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linville, linux-wireless
In-Reply-To: <1318355944-24708-8-git-send-email-mcgrof@qca.qualcomm.com>

On Tue, 2011-10-11 at 10:59 -0700, Luis R. Rodriguez wrote:

> +	default:
> +		printf("Uknown");

typo. Also, I prefer patches w/o nl80211.h updates.

johannes


^ permalink raw reply

* Re: pull request: wireless-next 2011-10-11
From: David Miller @ 2011-10-11 19:45 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev
In-Reply-To: <20111011193806.GI6558@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 11 Oct 2011 15:38:06 -0400

> On Tue, Oct 11, 2011 at 03:16:16PM -0400, John W. Linville wrote:
>> commit bfb3780bc9b622422c1f0d3e12371a70863000da
>> 
>> Dave,
>> 
>> Here is another wireless batch intended for 3.2...  Highlights include a
>> bluetooth pull with some refactoring, a big pull of ath6kl updates, a
>> flurry of mac80211 patches from Johannes, and the usual strong ath9k
>> showing.
>> 
>> Please let me know if there are problems!
> 
> There was a problem -- a warning in ath6kl.  Sorry about that!
> 
> commit 094daf7db7c47861009899ce23f9177d761e20b0

I made sure I got the most recent changes.

^ permalink raw reply

* Re: pull request: wireless-next 2011-10-11
From: David Miller @ 2011-10-11 19:40 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev
In-Reply-To: <20111011191616.GF6558@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 11 Oct 2011 15:16:16 -0400

> Here is another wireless batch intended for 3.2...  Highlights include a
> bluetooth pull with some refactoring, a big pull of ath6kl updates, a
> flurry of mac80211 patches from Johannes, and the usual strong ath9k
> showing.
> 
> Please let me know if there are problems!

Pulled, thanks John.

^ permalink raw reply

* Re: pull request: wireless-next 2011-10-11
From: John W. Linville @ 2011-10-11 19:38 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev
In-Reply-To: <20111011191616.GF6558@tuxdriver.com>

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

On Tue, Oct 11, 2011 at 03:16:16PM -0400, John W. Linville wrote:
> commit bfb3780bc9b622422c1f0d3e12371a70863000da
> 
> Dave,
> 
> Here is another wireless batch intended for 3.2...  Highlights include a
> bluetooth pull with some refactoring, a big pull of ath6kl updates, a
> flurry of mac80211 patches from Johannes, and the usual strong ath9k
> showing.
> 
> Please let me know if there are problems!

There was a problem -- a warning in ath6kl.  Sorry about that!

commit 094daf7db7c47861009899ce23f9177d761e20b0

Dave,

Here is another wireless batch intended for 3.2...  Highlights include a
bluetooth pull with some refactoring, a big pull of ath6kl updates, a
flurry of mac80211 patches from Johannes, and the usual strong ath9k
showing.

Please let me know if there are problems!

Thanks,

John

P.S.  This version correct a warning due to some merge damage in
ath6kl...

---

The following changes since commit 3ed6f6958c0ac21958285d8648f14d34da4bbcb3:

  ll_temac: convert to SKB paged frag API. (2011-10-10 15:19:13 -0400)

are available in the git repository at:
  git://git.infradead.org/users/linville/wireless-next.git for-davem

Amitkumar Karwar (5):
      mwifiex: remove unnecessary mwifiex_dump_station_info() call
      mwifiex: remove unreachable code
      mwifiex: fix Tx data rate display issue
      mwifiex: correct AMSDU aggregation check
      mwifiex: handle an error path correctly

Anderson Lizardo (1):
      Bluetooth: use recommended LE connection parameters

Andre Guedes (1):
      Bluetooth: hci_le_adv_report_evt code refactoring

Andy Shevchenko (1):
      wireless: at76c50x: use native hex_pack_byte() method

Arik Nemtsov (5):
      nl80211: support sending TDLS commands/frames
      mac80211: standardize adding supported rates IEs
      mac80211: handle TDLS high-level commands and frames
      nl80211/mac80211: allow adding TDLS peers as stations
      mac80211: data path modification for TDLS peers

Daniel Drake (1):
      libertas: detect TX lockups and reset hardware

Don Fry (1):
      iwlagn: rename iwlagn module iwlwifi and alias to iwlagn.

Edward Lu (4):
      ath6kl: Support channel set request for startscan command
      ath6kl: Fix a typo in ath6k context
      ath6kl: Fix default key installation in AP mode
      ath6kl: Do not clear CONNECT bit setting in AP mode for STA disconnect

Eliad Peller (1):
      mac80211: pass vif param to conf_tx() callback

Greg Dietsche (1):
      iwlagn: iwl-agn-rs: remove unnecessary null check for sta and lq_sta

Helmut Schaa (1):
      mac80211: Allow noack flag overwrite for injected frames

Johannes Berg (17):
      cfg80211/mac80211: apply station uAPSD parameters selectively
      mac80211: let drivers inform it about per TID buffered frames
      mac80211: unify TIM bit handling
      mac80211: also expire filtered frames
      mac80211: split PS buffers into ACs
      mac80211: remove return value from add_pending_skbs
      mac80211: clear more-data bit on filtered frames
      mac80211: allow releasing driver-buffered frames
      mac80211: implement uAPSD
      mac80211: send (QoS) Null if no buffered frames
      mac80211: reply only once to each PS-poll
      mac80211: optimise station flags
      mac80211: add missing station flags to debugfs
      mac80211: explicitly notify drivers of frame release
      mac80211: allow out-of-band EOSP notification
      mac80211: document client powersave
      mac80211: dont assign seqno to or aggregate QoS Null frames

John W. Linville (3):
      Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
      Merge branch 'master' of git://github.com/padovan/bluetooth-next
      Merge branch 'master' of git://git.infradead.org/users/linville/wireless-next into for-davem

Jouni Malinen (37):
      ath6kl: Use cfg80211_inform_bss instead of cfg80211_inform_bss_frame
      ath6kl: Add functionality for starting AP mode
      ath6kl: Fix AP mode (Re)AssocReq IE processing
      ath6kl: Delay initial group key setup in AP mode
      ath6kl: Use change_station() to authorize/unauthorize STAs
      ath6kl: Add new WMI commands and events for P2P
      ath6kl: Implement remain_on_channel and cancel_remain_on_channel
      ath6kl: Implement mgmt_tx
      ath6kl: Request P2P capabilities during target init
      ath6kl: Add cfg80211 calls for remain-on-channel events
      ath6kl: Use set_appie command to add Probe Request IEs
      ath6kl: Report received Probe Request frames to cfg80211
      ath6kl: Notify cfg80211 of TX status of mgmt_tx frames
      ath6kl: Report received Action frames to cfg80211
      ath6kl: Advertise supported mgmt_stypes
      ath6kl: Add support for new P2P iftypes in mode changes
      ath6kl: Include P2P IE(s) in GO Probe Response depending on request
      ath6kl: Return error from wmi.c instead of -EIO in ath6kl_cfg80211_scan
      ath6kl: Define __CHECK_ENDIAN__ for sparse
      ath6kl: Do not enable Probe Request reporting by default
      athk6l: Fix channel list processing in scan requests
      ath6kl: Fix WMI message structure for AP_SET_PVB
      ath6kl: Fix AP mode connect event parsing and TIM updates
      ath6kl: Allow AP mode to be configured
      ath6kl: Allow enabling of P2P support
      ath6kl: Fix static WEP configuration in AP mode
      ath6kl: Fix BSS update on roaming
      ath6kl: Remove deprecated WMI_OPT_RX_FRAME_EVENTID processing
      ath6kl: Remove RSSI update for internal node table
      ath6kl: Remove unnecessary node table update on disconnect event
      ath6kl: Replace internal node table with cfg80211 BSS table
      ath6kl: Remove the unused node table implementation
      ath6kl: Remove unnecessary bssinfo event header conversion
      ath6kl: Update BSS information after connection
      ath6kl: Export beacon interval and DTIM period through STA info
      ath6kl: Report PMKSA candidate events through cfg80211
      ath6kl: fix TCP corruption

Kalle Valo (28):
      ath6kl: fix indentation in htc_issued_send()
      ath6kl: implement suspend support
      ath6kl: add testmode support
      ath6kl: fix compilation when NL80211_TESTMODE is disabled
      ath6kl: add firmware log support
      ath6kl: implement support to set firmware log parameters
      ath6kl: cleanup diagnose window read and write functions
      ath6kl: read fwlog from firmware ring buffer
      ath6kl: unify tx function names in htc.c
      ath6kl: unify rx function naming in htc.c
      ath6kl: separate firmware fetch from upload
      ath6kl: fix busy loop in ath6kl_bmi_get_rx_lkahd()
      ath6kl: add support for firmware API 2 format
      ath6kl: refactor firmware load address code
      ath6kl: refactor firmware ext data addr and reserved ram handling size
      ath6kl: read firmware start address from hardware
      ath6kl: read reserved ram size from firmware file
      ath6kl: add firmware capabilities support
      Merge remote branch 'wireless-next/master' into ath6kl-next
      ath6kl: pass only unicast frames for aggregation
      ath6kl: allow firmware to override firmware patch address
      ath6kl: silence "invalid rate" warning
      ath6kl: add prefix parameter to ath6kl_dbg_dump()
      ath6kl: add sdio debug messages
      ath6kl: add debug logs for booting
      ath6kl: improve wmi debug messages
      ath6kl: fix size_t related warnings
      ath6kl: include vmalloc.h in debug.c

Kevin Fang (1):
      ath6kl: Add beginning of AR6004 initialisation support

Larry Finger (2):
      rtlwifi: Remove unused routine _usb_readN_sync
      rtlwifi: Remove unused _usb_nbytes_read_write and _usb_writeN_sync

Lorenzo Bianconi (1):
      mac80211: max_tp_rate2 management of minstrel_ht

Luis R. Rodriguez (1):
      ath9k_htc: add AVM FRITZ!WLAN 11N v2 support

Mat Martineau (3):
      Bluetooth: Linearize skbs for use in BNEP, CMTP, HIDP, and RFCOMM
      Bluetooth: Handle fragmented skbs in bt_sock_stream_recvmsg()
      Bluetooth: Perform L2CAP SDU reassembly without copying data

Mohammed Shafi Shajakhan (4):
      ath9k/ath9k_htc: Fix PS wrappers for RF kill
      ath9k_hw: extend GPIO pin select mask for rfkill
      ath9k_hw: Fix number of GPIO pins for AR9287/9300
      ath9k_hw: set pci_express capability true for AR9480

Oliver Neukum (1):
      btusb: add device entry for Broadcom SoftSailing

Peter Hurley (1):
      Bluetooth: Allow ACL packets over USB in HCI_RAW mode

Raja Mani (2):
      ath6kl: Avoid finding bss presence in cfg80211 scan list
      ath6kl: Check sme state before delivering disconnect event to cfg80211

Rajkumar Manoharan (4):
      ath6kl: Fix compilation error while compiling w/o debug
      ath9k: Remove unnecessary AMPDU check at tx status
      ath9k: Remove redundant my beacon check at ath_rx_ps_beacon
      mac80211: Send nullfunc frames at lower rate during connection monitor

Sam Leffler (1):
      ath6kl: query device tree for firmware board-id

Sangwook Lee (1):
      net:rfkill: add a gpio setup function into GPIO rfkill

Stephen Rothwell (1):
      wireless/ath6kl: use of module_param requires the inclusion of moduleparam.h

Szymon Janc (1):
      Bluetooth: Mark not declared l2cap_core functions as static

Vasanthakumar Thiagarajan (21):
      ath6kl: Release ar->lock right afer updating net_stats in ath6kl_rx()
      ath6kl: Minor cleanup in min_hdr_len computation
      ath6kl: Cleanup ath6kl_wmi_data_hdr_remove()
      ath6kl: Fix bug in computing AMSU subframe padding
      ath6kl: Fix buffer alignment for scatter-gather I/O
      ath6kl: Fix system freeze under heavy data load
      ath6kl: Remove unused meta_v2 from ath6kl_data_tx()
      ath6kl: Add wmi meta data information only it is available
      ath6kl: Avoid rolling back of entire scatter setup in case of failure
      ath6kl: Add initial debugfs changes
      ath6kl: Add debugfs entry to dump target stats
      ath6kl: Add debugfs file entry to dump credit distribution stats
      ath6kl: Add debugfs interface to dump diagnostic registers from firmware
      ath6kl: Fix endianness in requesting chip register read
      ath6kl: Make ath6kl_diag_write32() non-static
      ath6kl: Fix endianness in register write
      ath6kl: Add debugfs support to write a chip register
      ath6kl: Remove auth type fall back in auto authentication mode
      ath6kl: Set the sme_state to disconnected in disconnect() callback
      ath6kl: Fix disconnect event reporting
      ath6kl: Remove unnecessary retrieval of first list entry in ath6kl_htc_tx_setup_scat_list()

Vivek Natarajan (4):
      ath6kl: Add debugfs entry to modify roaming parameters.
      ath6kl: Process regulatory requests from firmware.
      ath6kl: deinitialise wiphy on error
      ath6kl: Indicate the roaming capability of the firmware

Waldemar Rymarkiewicz (1):
      Bluetooth: Fix possible NULL pointer dereference

Yogesh Ashok Powar (1):
      mwifiex: add cfg80211 handlers add/del_virtual_intf

 Documentation/DocBook/80211.tmpl                 |   11 +-
 Documentation/feature-removal-schedule.txt       |    9 +
 drivers/bluetooth/btusb.c                        |    6 +-
 drivers/net/wireless/Makefile                    |    2 +-
 drivers/net/wireless/at76c50x-usb.c              |   18 +-
 drivers/net/wireless/ath/ath5k/mac80211-ops.c    |    2 +-
 drivers/net/wireless/ath/ath6kl/Makefile         |    4 +-
 drivers/net/wireless/ath/ath6kl/bmi.c            |   23 +-
 drivers/net/wireless/ath/ath6kl/bmi.h            |    4 +-
 drivers/net/wireless/ath/ath6kl/cfg80211.c       |  894 ++++++++++++-----
 drivers/net/wireless/ath/ath6kl/common.h         |   83 --
 drivers/net/wireless/ath/ath6kl/core.h           |  145 +++-
 drivers/net/wireless/ath/ath6kl/debug.c          |  784 +++++++++++++++
 drivers/net/wireless/ath/ath6kl/debug.h          |   49 +-
 drivers/net/wireless/ath/ath6kl/hif-ops.h        |    5 +
 drivers/net/wireless/ath/ath6kl/hif.h            |    1 +
 drivers/net/wireless/ath/ath6kl/htc.c            |  271 +++---
 drivers/net/wireless/ath/ath6kl/init.c           |  794 ++++++++++++----
 drivers/net/wireless/ath/ath6kl/main.c           |  448 ++++++---
 drivers/net/wireless/ath/ath6kl/node.c           |  234 -----
 drivers/net/wireless/ath/ath6kl/sdio.c           |   79 ++-
 drivers/net/wireless/ath/ath6kl/target.h         |   41 +-
 drivers/net/wireless/ath/ath6kl/testmode.c       |  167 ++++
 drivers/net/wireless/ath/ath6kl/testmode.h       |   36 +
 drivers/net/wireless/ath/ath6kl/txrx.c           |   61 +-
 drivers/net/wireless/ath/ath6kl/wmi.c            | 1126 +++++++++++++++-------
 drivers/net/wireless/ath/ath6kl/wmi.h            |  350 ++++++-
 drivers/net/wireless/ath/ath9k/ath9k.h           |    3 +-
 drivers/net/wireless/ath/ath9k/eeprom.h          |    7 +-
 drivers/net/wireless/ath/ath9k/gpio.c            |    7 +-
 drivers/net/wireless/ath/ath9k/hif_usb.c         |    1 +
 drivers/net/wireless/ath/ath9k/htc_drv_gpio.c    |   10 +-
 drivers/net/wireless/ath/ath9k/htc_drv_main.c    |    3 +-
 drivers/net/wireless/ath/ath9k/hw.c              |   11 +-
 drivers/net/wireless/ath/ath9k/main.c            |    6 +-
 drivers/net/wireless/ath/ath9k/rc.c              |    6 -
 drivers/net/wireless/ath/ath9k/recv.c            |   23 +-
 drivers/net/wireless/ath/ath9k/xmit.c            |   19 +-
 drivers/net/wireless/ath/carl9170/main.c         |    3 +-
 drivers/net/wireless/b43/main.c                  |    3 +-
 drivers/net/wireless/b43legacy/main.c            |    3 +-
 drivers/net/wireless/iwlegacy/iwl-4965-tx.c      |    2 +-
 drivers/net/wireless/iwlegacy/iwl-core.c         |    3 +-
 drivers/net/wireless/iwlegacy/iwl-core.h         |    3 +-
 drivers/net/wireless/iwlwifi/Kconfig             |   22 +-
 drivers/net/wireless/iwlwifi/Makefile            |   40 +-
 drivers/net/wireless/iwlwifi/iwl-agn-rs.c        |    3 -
 drivers/net/wireless/iwlwifi/iwl-agn-tx.c        |    2 +-
 drivers/net/wireless/iwlwifi/iwl-agn.c           |    1 +
 drivers/net/wireless/iwlwifi/iwl-core.c          |    5 +-
 drivers/net/wireless/iwlwifi/iwl-core.h          |    3 +-
 drivers/net/wireless/iwlwifi/iwl-shared.h        |    2 +-
 drivers/net/wireless/libertas/dev.h              |    1 +
 drivers/net/wireless/libertas/main.c             |   35 +
 drivers/net/wireless/mac80211_hwsim.c            |    3 +-
 drivers/net/wireless/mwifiex/11n_aggr.c          |    2 -
 drivers/net/wireless/mwifiex/11n_aggr.h          |    1 +
 drivers/net/wireless/mwifiex/cfg80211.c          |  176 +++-
 drivers/net/wireless/mwifiex/cfg80211.h          |    3 +-
 drivers/net/wireless/mwifiex/decl.h              |    8 -
 drivers/net/wireless/mwifiex/init.c              |    2 +-
 drivers/net/wireless/mwifiex/main.c              |  266 +----
 drivers/net/wireless/mwifiex/main.h              |   19 +-
 drivers/net/wireless/mwifiex/sta_ioctl.c         |   46 +-
 drivers/net/wireless/mwifiex/wmm.c               |   32 +-
 drivers/net/wireless/mwl8k.c                     |    5 +-
 drivers/net/wireless/p54/main.c                  |    3 +-
 drivers/net/wireless/p54/txrx.c                  |    2 +-
 drivers/net/wireless/rt2x00/rt2400pci.c          |    5 +-
 drivers/net/wireless/rt2x00/rt2800lib.c          |    5 +-
 drivers/net/wireless/rt2x00/rt2800lib.h          |    3 +-
 drivers/net/wireless/rt2x00/rt2x00.h             |    3 +-
 drivers/net/wireless/rt2x00/rt2x00mac.c          |    3 +-
 drivers/net/wireless/rt2x00/rt61pci.c            |    5 +-
 drivers/net/wireless/rt2x00/rt73usb.c            |    5 +-
 drivers/net/wireless/rtl818x/rtl8187/dev.c       |    3 +-
 drivers/net/wireless/rtlwifi/core.c              |    3 +-
 drivers/net/wireless/rtlwifi/usb.c               |   40 -
 drivers/net/wireless/rtlwifi/wifi.h              |    8 +-
 drivers/net/wireless/wl1251/main.c               |    3 +-
 drivers/net/wireless/wl12xx/main.c               |    3 +-
 drivers/staging/brcm80211/brcmsmac/mac80211_if.c |    7 +-
 include/linux/ieee80211.h                        |   85 ++
 include/linux/if_ether.h                         |    1 +
 include/linux/nl80211.h                          |   44 +
 include/linux/rfkill-gpio.h                      |    4 +
 include/net/bluetooth/l2cap.h                    |    3 +-
 include/net/cfg80211.h                           |   29 +
 include/net/ieee80211_radiotap.h                 |    1 +
 include/net/mac80211.h                           |  229 +++++-
 net/bluetooth/af_bluetooth.c                     |   30 +-
 net/bluetooth/bnep/core.c                        |    5 +-
 net/bluetooth/cmtp/core.c                        |    5 +-
 net/bluetooth/hci_conn.c                         |   14 +-
 net/bluetooth/hci_event.c                        |   20 +-
 net/bluetooth/hidp/core.c                        |   10 +-
 net/bluetooth/l2cap_core.c                       |  255 ++----
 net/bluetooth/rfcomm/core.c                      |    5 +-
 net/mac80211/Kconfig                             |   12 +
 net/mac80211/agg-rx.c                            |    2 +-
 net/mac80211/agg-tx.c                            |    2 +-
 net/mac80211/cfg.c                               |  380 +++++++-
 net/mac80211/debugfs_sta.c                       |   37 +-
 net/mac80211/driver-ops.h                        |   33 +-
 net/mac80211/driver-trace.h                      |   77 ++
 net/mac80211/ht.c                                |    2 +-
 net/mac80211/ibss.c                              |    4 +-
 net/mac80211/ieee80211_i.h                       |   16 +-
 net/mac80211/iface.c                             |    4 +-
 net/mac80211/key.c                               |    4 +-
 net/mac80211/main.c                              |   18 +
 net/mac80211/mesh.c                              |   58 --
 net/mac80211/mesh.h                              |    4 -
 net/mac80211/mesh_plink.c                        |   12 +-
 net/mac80211/mlme.c                              |   34 +-
 net/mac80211/pm.c                                |    2 +-
 net/mac80211/rate.c                              |    8 +-
 net/mac80211/rc80211_minstrel_ht.c               |    2 +
 net/mac80211/rx.c                                |  118 ++-
 net/mac80211/sta_info.c                          |  636 ++++++++++---
 net/mac80211/sta_info.h                          |  136 ++--
 net/mac80211/status.c                            |   54 +-
 net/mac80211/tx.c                                |  187 +++--
 net/mac80211/util.c                              |   76 ++-
 net/mac80211/wme.c                               |    4 +-
 net/rfkill/rfkill-gpio.c                         |   11 +
 net/wireless/nl80211.c                           |  109 ++-
 net/wireless/util.c                              |    5 +-
 128 files changed, 6629 insertions(+), 2696 deletions(-)
 delete mode 100644 drivers/net/wireless/ath/ath6kl/node.c
 create mode 100644 drivers/net/wireless/ath/ath6kl/testmode.c
 create mode 100644 drivers/net/wireless/ath/ath6kl/testmode.h

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* pull request: wireless-next 2011-10-11
From: John W. Linville @ 2011-10-11 19:16 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev

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

commit bfb3780bc9b622422c1f0d3e12371a70863000da

Dave,

Here is another wireless batch intended for 3.2...  Highlights include a
bluetooth pull with some refactoring, a big pull of ath6kl updates, a
flurry of mac80211 patches from Johannes, and the usual strong ath9k
showing.

Please let me know if there are problems!

Thanks,

John

---

The following changes since commit 3ed6f6958c0ac21958285d8648f14d34da4bbcb3:

  ll_temac: convert to SKB paged frag API. (2011-10-10 15:19:13 -0400)

are available in the git repository at:
  git://git.infradead.org/users/linville/wireless-next.git for-davem

Amitkumar Karwar (5):
      mwifiex: remove unnecessary mwifiex_dump_station_info() call
      mwifiex: remove unreachable code
      mwifiex: fix Tx data rate display issue
      mwifiex: correct AMSDU aggregation check
      mwifiex: handle an error path correctly

Anderson Lizardo (1):
      Bluetooth: use recommended LE connection parameters

Andre Guedes (1):
      Bluetooth: hci_le_adv_report_evt code refactoring

Andy Shevchenko (1):
      wireless: at76c50x: use native hex_pack_byte() method

Arik Nemtsov (5):
      nl80211: support sending TDLS commands/frames
      mac80211: standardize adding supported rates IEs
      mac80211: handle TDLS high-level commands and frames
      nl80211/mac80211: allow adding TDLS peers as stations
      mac80211: data path modification for TDLS peers

Daniel Drake (1):
      libertas: detect TX lockups and reset hardware

Don Fry (1):
      iwlagn: rename iwlagn module iwlwifi and alias to iwlagn.

Edward Lu (4):
      ath6kl: Support channel set request for startscan command
      ath6kl: Fix a typo in ath6k context
      ath6kl: Fix default key installation in AP mode
      ath6kl: Do not clear CONNECT bit setting in AP mode for STA disconnect

Eliad Peller (1):
      mac80211: pass vif param to conf_tx() callback

Greg Dietsche (1):
      iwlagn: iwl-agn-rs: remove unnecessary null check for sta and lq_sta

Helmut Schaa (1):
      mac80211: Allow noack flag overwrite for injected frames

Johannes Berg (17):
      cfg80211/mac80211: apply station uAPSD parameters selectively
      mac80211: let drivers inform it about per TID buffered frames
      mac80211: unify TIM bit handling
      mac80211: also expire filtered frames
      mac80211: split PS buffers into ACs
      mac80211: remove return value from add_pending_skbs
      mac80211: clear more-data bit on filtered frames
      mac80211: allow releasing driver-buffered frames
      mac80211: implement uAPSD
      mac80211: send (QoS) Null if no buffered frames
      mac80211: reply only once to each PS-poll
      mac80211: optimise station flags
      mac80211: add missing station flags to debugfs
      mac80211: explicitly notify drivers of frame release
      mac80211: allow out-of-band EOSP notification
      mac80211: document client powersave
      mac80211: dont assign seqno to or aggregate QoS Null frames

John W. Linville (3):
      Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
      Merge branch 'master' of git://github.com/padovan/bluetooth-next
      Merge branch 'master' of git://git.infradead.org/users/linville/wireless-next into for-davem

Jouni Malinen (37):
      ath6kl: Use cfg80211_inform_bss instead of cfg80211_inform_bss_frame
      ath6kl: Add functionality for starting AP mode
      ath6kl: Fix AP mode (Re)AssocReq IE processing
      ath6kl: Delay initial group key setup in AP mode
      ath6kl: Use change_station() to authorize/unauthorize STAs
      ath6kl: Add new WMI commands and events for P2P
      ath6kl: Implement remain_on_channel and cancel_remain_on_channel
      ath6kl: Implement mgmt_tx
      ath6kl: Request P2P capabilities during target init
      ath6kl: Add cfg80211 calls for remain-on-channel events
      ath6kl: Use set_appie command to add Probe Request IEs
      ath6kl: Report received Probe Request frames to cfg80211
      ath6kl: Notify cfg80211 of TX status of mgmt_tx frames
      ath6kl: Report received Action frames to cfg80211
      ath6kl: Advertise supported mgmt_stypes
      ath6kl: Add support for new P2P iftypes in mode changes
      ath6kl: Include P2P IE(s) in GO Probe Response depending on request
      ath6kl: Return error from wmi.c instead of -EIO in ath6kl_cfg80211_scan
      ath6kl: Define __CHECK_ENDIAN__ for sparse
      ath6kl: Do not enable Probe Request reporting by default
      athk6l: Fix channel list processing in scan requests
      ath6kl: Fix WMI message structure for AP_SET_PVB
      ath6kl: Fix AP mode connect event parsing and TIM updates
      ath6kl: Allow AP mode to be configured
      ath6kl: Allow enabling of P2P support
      ath6kl: Fix static WEP configuration in AP mode
      ath6kl: Fix BSS update on roaming
      ath6kl: Remove deprecated WMI_OPT_RX_FRAME_EVENTID processing
      ath6kl: Remove RSSI update for internal node table
      ath6kl: Remove unnecessary node table update on disconnect event
      ath6kl: Replace internal node table with cfg80211 BSS table
      ath6kl: Remove the unused node table implementation
      ath6kl: Remove unnecessary bssinfo event header conversion
      ath6kl: Update BSS information after connection
      ath6kl: Export beacon interval and DTIM period through STA info
      ath6kl: Report PMKSA candidate events through cfg80211
      ath6kl: fix TCP corruption

Kalle Valo (28):
      ath6kl: fix indentation in htc_issued_send()
      ath6kl: implement suspend support
      ath6kl: add testmode support
      ath6kl: fix compilation when NL80211_TESTMODE is disabled
      ath6kl: add firmware log support
      ath6kl: implement support to set firmware log parameters
      ath6kl: cleanup diagnose window read and write functions
      ath6kl: read fwlog from firmware ring buffer
      ath6kl: unify tx function names in htc.c
      ath6kl: unify rx function naming in htc.c
      ath6kl: separate firmware fetch from upload
      ath6kl: fix busy loop in ath6kl_bmi_get_rx_lkahd()
      ath6kl: add support for firmware API 2 format
      ath6kl: refactor firmware load address code
      ath6kl: refactor firmware ext data addr and reserved ram handling size
      ath6kl: read firmware start address from hardware
      ath6kl: read reserved ram size from firmware file
      ath6kl: add firmware capabilities support
      Merge remote branch 'wireless-next/master' into ath6kl-next
      ath6kl: pass only unicast frames for aggregation
      ath6kl: allow firmware to override firmware patch address
      ath6kl: silence "invalid rate" warning
      ath6kl: add prefix parameter to ath6kl_dbg_dump()
      ath6kl: add sdio debug messages
      ath6kl: add debug logs for booting
      ath6kl: improve wmi debug messages
      ath6kl: fix size_t related warnings
      ath6kl: include vmalloc.h in debug.c

Kevin Fang (1):
      ath6kl: Add beginning of AR6004 initialisation support

Larry Finger (2):
      rtlwifi: Remove unused routine _usb_readN_sync
      rtlwifi: Remove unused _usb_nbytes_read_write and _usb_writeN_sync

Lorenzo Bianconi (1):
      mac80211: max_tp_rate2 management of minstrel_ht

Luis R. Rodriguez (1):
      ath9k_htc: add AVM FRITZ!WLAN 11N v2 support

Mat Martineau (3):
      Bluetooth: Linearize skbs for use in BNEP, CMTP, HIDP, and RFCOMM
      Bluetooth: Handle fragmented skbs in bt_sock_stream_recvmsg()
      Bluetooth: Perform L2CAP SDU reassembly without copying data

Mohammed Shafi Shajakhan (4):
      ath9k/ath9k_htc: Fix PS wrappers for RF kill
      ath9k_hw: extend GPIO pin select mask for rfkill
      ath9k_hw: Fix number of GPIO pins for AR9287/9300
      ath9k_hw: set pci_express capability true for AR9480

Oliver Neukum (1):
      btusb: add device entry for Broadcom SoftSailing

Peter Hurley (1):
      Bluetooth: Allow ACL packets over USB in HCI_RAW mode

Raja Mani (2):
      ath6kl: Avoid finding bss presence in cfg80211 scan list
      ath6kl: Check sme state before delivering disconnect event to cfg80211

Rajkumar Manoharan (4):
      ath6kl: Fix compilation error while compiling w/o debug
      ath9k: Remove unnecessary AMPDU check at tx status
      ath9k: Remove redundant my beacon check at ath_rx_ps_beacon
      mac80211: Send nullfunc frames at lower rate during connection monitor

Sam Leffler (1):
      ath6kl: query device tree for firmware board-id

Sangwook Lee (1):
      net:rfkill: add a gpio setup function into GPIO rfkill

Stephen Rothwell (1):
      wireless/ath6kl: use of module_param requires the inclusion of moduleparam.h

Szymon Janc (1):
      Bluetooth: Mark not declared l2cap_core functions as static

Vasanthakumar Thiagarajan (21):
      ath6kl: Release ar->lock right afer updating net_stats in ath6kl_rx()
      ath6kl: Minor cleanup in min_hdr_len computation
      ath6kl: Cleanup ath6kl_wmi_data_hdr_remove()
      ath6kl: Fix bug in computing AMSU subframe padding
      ath6kl: Fix buffer alignment for scatter-gather I/O
      ath6kl: Fix system freeze under heavy data load
      ath6kl: Remove unused meta_v2 from ath6kl_data_tx()
      ath6kl: Add wmi meta data information only it is available
      ath6kl: Avoid rolling back of entire scatter setup in case of failure
      ath6kl: Add initial debugfs changes
      ath6kl: Add debugfs entry to dump target stats
      ath6kl: Add debugfs file entry to dump credit distribution stats
      ath6kl: Add debugfs interface to dump diagnostic registers from firmware
      ath6kl: Fix endianness in requesting chip register read
      ath6kl: Make ath6kl_diag_write32() non-static
      ath6kl: Fix endianness in register write
      ath6kl: Add debugfs support to write a chip register
      ath6kl: Remove auth type fall back in auto authentication mode
      ath6kl: Set the sme_state to disconnected in disconnect() callback
      ath6kl: Fix disconnect event reporting
      ath6kl: Remove unnecessary retrieval of first list entry in ath6kl_htc_tx_setup_scat_list()

Vivek Natarajan (4):
      ath6kl: Add debugfs entry to modify roaming parameters.
      ath6kl: Process regulatory requests from firmware.
      ath6kl: deinitialise wiphy on error
      ath6kl: Indicate the roaming capability of the firmware

Waldemar Rymarkiewicz (1):
      Bluetooth: Fix possible NULL pointer dereference

Yogesh Ashok Powar (1):
      mwifiex: add cfg80211 handlers add/del_virtual_intf

 Documentation/DocBook/80211.tmpl                 |   11 +-
 Documentation/feature-removal-schedule.txt       |    9 +
 drivers/bluetooth/btusb.c                        |    6 +-
 drivers/net/wireless/Makefile                    |    2 +-
 drivers/net/wireless/at76c50x-usb.c              |   18 +-
 drivers/net/wireless/ath/ath5k/mac80211-ops.c    |    2 +-
 drivers/net/wireless/ath/ath6kl/Makefile         |    4 +-
 drivers/net/wireless/ath/ath6kl/bmi.c            |   23 +-
 drivers/net/wireless/ath/ath6kl/bmi.h            |    4 +-
 drivers/net/wireless/ath/ath6kl/cfg80211.c       |  894 ++++++++++++-----
 drivers/net/wireless/ath/ath6kl/common.h         |   83 --
 drivers/net/wireless/ath/ath6kl/core.h           |  145 +++-
 drivers/net/wireless/ath/ath6kl/debug.c          |  784 +++++++++++++++
 drivers/net/wireless/ath/ath6kl/debug.h          |   49 +-
 drivers/net/wireless/ath/ath6kl/hif-ops.h        |    5 +
 drivers/net/wireless/ath/ath6kl/hif.h            |    1 +
 drivers/net/wireless/ath/ath6kl/htc.c            |  271 +++---
 drivers/net/wireless/ath/ath6kl/init.c           |  794 ++++++++++++----
 drivers/net/wireless/ath/ath6kl/main.c           |  448 ++++++---
 drivers/net/wireless/ath/ath6kl/node.c           |  234 -----
 drivers/net/wireless/ath/ath6kl/sdio.c           |   79 ++-
 drivers/net/wireless/ath/ath6kl/target.h         |   41 +-
 drivers/net/wireless/ath/ath6kl/testmode.c       |  167 ++++
 drivers/net/wireless/ath/ath6kl/testmode.h       |   36 +
 drivers/net/wireless/ath/ath6kl/txrx.c           |   61 +-
 drivers/net/wireless/ath/ath6kl/wmi.c            | 1126 +++++++++++++++-------
 drivers/net/wireless/ath/ath6kl/wmi.h            |  350 ++++++-
 drivers/net/wireless/ath/ath9k/ath9k.h           |    3 +-
 drivers/net/wireless/ath/ath9k/eeprom.h          |    7 +-
 drivers/net/wireless/ath/ath9k/gpio.c            |    7 +-
 drivers/net/wireless/ath/ath9k/hif_usb.c         |    1 +
 drivers/net/wireless/ath/ath9k/htc_drv_gpio.c    |   10 +-
 drivers/net/wireless/ath/ath9k/htc_drv_main.c    |    3 +-
 drivers/net/wireless/ath/ath9k/hw.c              |   11 +-
 drivers/net/wireless/ath/ath9k/main.c            |    6 +-
 drivers/net/wireless/ath/ath9k/rc.c              |    6 -
 drivers/net/wireless/ath/ath9k/recv.c            |   23 +-
 drivers/net/wireless/ath/ath9k/xmit.c            |   19 +-
 drivers/net/wireless/ath/carl9170/main.c         |    3 +-
 drivers/net/wireless/b43/main.c                  |    3 +-
 drivers/net/wireless/b43legacy/main.c            |    3 +-
 drivers/net/wireless/iwlegacy/iwl-4965-tx.c      |    2 +-
 drivers/net/wireless/iwlegacy/iwl-core.c         |    3 +-
 drivers/net/wireless/iwlegacy/iwl-core.h         |    3 +-
 drivers/net/wireless/iwlwifi/Kconfig             |   22 +-
 drivers/net/wireless/iwlwifi/Makefile            |   40 +-
 drivers/net/wireless/iwlwifi/iwl-agn-rs.c        |    3 -
 drivers/net/wireless/iwlwifi/iwl-agn-tx.c        |    2 +-
 drivers/net/wireless/iwlwifi/iwl-agn.c           |    1 +
 drivers/net/wireless/iwlwifi/iwl-core.c          |    5 +-
 drivers/net/wireless/iwlwifi/iwl-core.h          |    3 +-
 drivers/net/wireless/iwlwifi/iwl-shared.h        |    2 +-
 drivers/net/wireless/libertas/dev.h              |    1 +
 drivers/net/wireless/libertas/main.c             |   35 +
 drivers/net/wireless/mac80211_hwsim.c            |    3 +-
 drivers/net/wireless/mwifiex/11n_aggr.c          |    2 -
 drivers/net/wireless/mwifiex/11n_aggr.h          |    1 +
 drivers/net/wireless/mwifiex/cfg80211.c          |  176 +++-
 drivers/net/wireless/mwifiex/cfg80211.h          |    3 +-
 drivers/net/wireless/mwifiex/decl.h              |    8 -
 drivers/net/wireless/mwifiex/init.c              |    2 +-
 drivers/net/wireless/mwifiex/main.c              |  266 +----
 drivers/net/wireless/mwifiex/main.h              |   19 +-
 drivers/net/wireless/mwifiex/sta_ioctl.c         |   46 +-
 drivers/net/wireless/mwifiex/wmm.c               |   32 +-
 drivers/net/wireless/mwl8k.c                     |    5 +-
 drivers/net/wireless/p54/main.c                  |    3 +-
 drivers/net/wireless/p54/txrx.c                  |    2 +-
 drivers/net/wireless/rt2x00/rt2400pci.c          |    5 +-
 drivers/net/wireless/rt2x00/rt2800lib.c          |    5 +-
 drivers/net/wireless/rt2x00/rt2800lib.h          |    3 +-
 drivers/net/wireless/rt2x00/rt2x00.h             |    3 +-
 drivers/net/wireless/rt2x00/rt2x00mac.c          |    3 +-
 drivers/net/wireless/rt2x00/rt61pci.c            |    5 +-
 drivers/net/wireless/rt2x00/rt73usb.c            |    5 +-
 drivers/net/wireless/rtl818x/rtl8187/dev.c       |    3 +-
 drivers/net/wireless/rtlwifi/core.c              |    3 +-
 drivers/net/wireless/rtlwifi/usb.c               |   40 -
 drivers/net/wireless/rtlwifi/wifi.h              |    8 +-
 drivers/net/wireless/wl1251/main.c               |    3 +-
 drivers/net/wireless/wl12xx/main.c               |    3 +-
 drivers/staging/brcm80211/brcmsmac/mac80211_if.c |    7 +-
 include/linux/ieee80211.h                        |   85 ++
 include/linux/if_ether.h                         |    1 +
 include/linux/nl80211.h                          |   44 +
 include/linux/rfkill-gpio.h                      |    4 +
 include/net/bluetooth/l2cap.h                    |    3 +-
 include/net/cfg80211.h                           |   29 +
 include/net/ieee80211_radiotap.h                 |    1 +
 include/net/mac80211.h                           |  229 +++++-
 net/bluetooth/af_bluetooth.c                     |   30 +-
 net/bluetooth/bnep/core.c                        |    5 +-
 net/bluetooth/cmtp/core.c                        |    5 +-
 net/bluetooth/hci_conn.c                         |   14 +-
 net/bluetooth/hci_event.c                        |   20 +-
 net/bluetooth/hidp/core.c                        |   10 +-
 net/bluetooth/l2cap_core.c                       |  255 ++----
 net/bluetooth/rfcomm/core.c                      |    5 +-
 net/mac80211/Kconfig                             |   12 +
 net/mac80211/agg-rx.c                            |    2 +-
 net/mac80211/agg-tx.c                            |    2 +-
 net/mac80211/cfg.c                               |  380 +++++++-
 net/mac80211/debugfs_sta.c                       |   37 +-
 net/mac80211/driver-ops.h                        |   33 +-
 net/mac80211/driver-trace.h                      |   77 ++
 net/mac80211/ht.c                                |    2 +-
 net/mac80211/ibss.c                              |    4 +-
 net/mac80211/ieee80211_i.h                       |   16 +-
 net/mac80211/iface.c                             |    4 +-
 net/mac80211/key.c                               |    4 +-
 net/mac80211/main.c                              |   18 +
 net/mac80211/mesh.c                              |   58 --
 net/mac80211/mesh.h                              |    4 -
 net/mac80211/mesh_plink.c                        |   12 +-
 net/mac80211/mlme.c                              |   34 +-
 net/mac80211/pm.c                                |    2 +-
 net/mac80211/rate.c                              |    8 +-
 net/mac80211/rc80211_minstrel_ht.c               |    2 +
 net/mac80211/rx.c                                |  118 ++-
 net/mac80211/sta_info.c                          |  636 ++++++++++---
 net/mac80211/sta_info.h                          |  136 ++--
 net/mac80211/status.c                            |   54 +-
 net/mac80211/tx.c                                |  187 +++--
 net/mac80211/util.c                              |   76 ++-
 net/mac80211/wme.c                               |    4 +-
 net/rfkill/rfkill-gpio.c                         |   11 +
 net/wireless/nl80211.c                           |  109 ++-
 net/wireless/util.c                              |    5 +-
 128 files changed, 6629 insertions(+), 2696 deletions(-)
 delete mode 100644 drivers/net/wireless/ath/ath6kl/node.c
 create mode 100644 drivers/net/wireless/ath/ath6kl/testmode.c
 create mode 100644 drivers/net/wireless/ath/ath6kl/testmode.h
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH] wl12xx: handle injected packets
From: Luciano Coelho @ 2011-10-11 19:26 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless
In-Reply-To: <1318333945-27839-1-git-send-email-eliad@wizery.com>

On Tue, 2011-10-11 at 13:52 +0200, Eliad Peller wrote: 
> Injected packets are sent with no vif, causing the wl12xx
> to NULL-dereference in multiple places.
> 
> Furthermore, injected packets are currently not sent at all,
> as system_hlid doesn't belong to any specific role, so
> wl1271_skb_dequeue() never return its packets.
> 
> Handle both these problems.
> 
> Signed-off-by: Eliad Peller <eliad@wizery.com>
> ---

Applied and added my:

Reported-by: Luciano Coelho <coelho@ti.com>

As agreed on IRC. ;)

-- 
Cheers,
Luca.


^ permalink raw reply

* [PATCH] ath6kl: Fix endpoint_stats debugfs buffer length calculation
From: Jouni Malinen @ 2011-10-11 19:08 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Joe Perches

The previous version did not really make much sense and the theoretical
maximum length would be a bit longer. Calculate the length more
accurately. In addition, there is no need to clear the buffer, so use
kmalloc instead of kzalloc. For bonus points, add the forgotten
cred_rpt_from_other value to the file.

Reported-by: Joe Perches <joe@perches.com>
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/debug.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 7b1c9ae..dd37785 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -624,8 +624,9 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file,
 	unsigned int buf_len, len = 0;
 	ssize_t ret_cnt;
 
-	buf_len = 1000 + ENDPOINT_MAX * 100;
-	buf = kzalloc(buf_len, GFP_KERNEL);
+	buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) *
+		(25 + ENDPOINT_MAX * 11);
+	buf = kmalloc(buf_len, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
@@ -640,6 +641,7 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file,
 	EPSTAT(tx_dropped);
 	EPSTAT(tx_cred_rpt);
 	EPSTAT(cred_rpt_from_rx);
+	EPSTAT(cred_rpt_from_other);
 	EPSTAT(cred_rpt_ep0);
 	EPSTAT(cred_from_rx);
 	EPSTAT(cred_from_other);
-- 
1.7.4.1


-- 
Jouni Malinen                                            PGP id EFC895FA

^ permalink raw reply related

* Compat-wireless release for 2011-10-11 is baked
From: Compat-wireless cronjob account @ 2011-10-11 19:05 UTC (permalink / raw)
  To: linux-wireless

>From git://github.com/sfrothwell/linux-next
 + 186cf8e...706f460 akpm-end   -> origin/akpm-end  (forced update)
   3ee72ca..65112dc  akpm-start -> origin/akpm-start
 + 12d1b9a...5c56568 master     -> origin/master  (forced update)
   3ee72ca..65112dc  stable     -> origin/stable
 * [new tag]         next-20111011 -> next-20111011

compat-wireless code metrics

    811841 - Total upstream lines of code being pulled
      2431 - backport code changes
      2113 - backport code additions
       318 - backport code deletions
      8588 - backport from compat module
     11019 - total backport code
    1.3573 - % of code consists of backport work

^ permalink raw reply

* Re: [PATCH v2 1/5] ath6kl: Add endpoint_stats debugfs file
From: Jouni Malinen @ 2011-10-11 18:52 UTC (permalink / raw)
  To: Joe Perches; +Cc: kvalo, linux-wireless
In-Reply-To: <1318351171.1839.43.camel@Joe-Laptop>

On Tue, Oct 11, 2011 at 09:39:31AM -0700, Joe Perches wrote:
> > +static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
> > +					unsigned int buf_len, unsigned int len,
> > +					int offset, const char *name)
> 
> Perhaps the function name is wrong.
> This doesn't print, it fills a buffer.

Well, it prints the stuff into a buffer just like scnprintf prints
things.. Feel free to send a patch if you want to try to rename
*print* functions ;-).

> len and offset are to me oddly used variable names.

I guess len could be renamed to pos, but the use of len here matches
with the function used in the main function, i.e., this
print_endpoint_stat is more of a replacement for a macro. offset sounds
correct to me, i.e., it is the offset within the statistics structure.

> > +		counter = ((u32 *) ep_st) + (offset / 4);

> perhaps:
> 
> static int endpoint_stats(struct htc_target *target,
> 			  char *buf, size_t len,
> 			  size_t pos, int index, const char *name)

I would have nothing against pos, but index would be a bit confusing
here since that parameter is really the byte offset and not the index.

> 	pos += scnprintf(buf + pos, len - pos, "%s:", name);
> 	for (i = 0; i < ENDPOINT_MAX; i++) {
> 		u32 *stats = (u32 *)&target->endpoint[i].ep_st;
> 		offset += scnprintf(buf + pos, len - pos, " %u", stats[index]);

Well, okay, index to a u32 array.. If you feel strongly enough, please
send a separate cleanup patch since Kalle applied this already.


> > +static ssize_t ath6kl_endpoint_stats_read(struct file *file,
> > +					  char __user *user_buf,
> > +					  size_t count, loff_t *ppos)
> > +{
> > +	struct ath6kl *ar = file->private_data;
> > +	struct htc_target *target = ar->htc_target;
> > +	char *buf;
> > +	unsigned int buf_len, len = 0;
> 
> size_t len = 0;
> (or maybe pos instead)

This follows the style used throughout this file. Feel free to propose
cleanup to all the functions.

> 
> > +	ssize_t ret_cnt;
> > +
> > +	buf_len = 1000 + ENDPOINT_MAX * 100;
> 
> It seems odd to start with size using 1000

Yeah.. I think I had something as a prefix first and then just forgot to
remove that extra addition.

> There's ENDPOINT_MAX rows (9)
> Each row contains:
> 	up to 20 byte row name
> 	20 counters * up to 10 bytes per counter
> up to 220 bytes per row

It's actually the other way around, i.e., 20 rows with 9 counters.

> Perhaps this?
> 	const size_t buf_len = ENDPOINT_MAX * (20 + sizeof(struct htc_endpoint_stats) / sizeof(u32) * 10);

I was too lazy to count the exact maximum. If there is any chance of
overflowing the buf_len, this would obviously need to be fixed. The
theoretical maximum would likely be something like 20 * (22 + 9 * 11),
so yes, while I don't think this happens in practice, this buffer length
should be incremented to cover the theoretical case (and to make some
more sense).

> > +	buf = kzalloc(buf_len, GFP_KERNEL);
> 
> kzalloc doesn't seem necessary,
> everything is overwritten.  just kmalloc?

Yeah, I probably copied that from an existing function, but I would
agree that that is not really any need for clearing the buffer.

> As is, it's (barely) possible to overflow
> the buffer length and end up non-null terminated.
> Perhaps that doesn't matter.

I don't think there is any need for null-terminating the buffer since
this is really binary data with length returned. As I noted, this is
unlikely to end up having large enough counter values to overflow in
practice, but changing the buf_len calculation to make more sense is
useful cleanup anyway.

> > +	len = print_endpoint_stat(target, buf, buf_len, len,		\
> > +				  offsetof(struct htc_endpoint_stats, name), \
> > +				  #name)
> 
> perhaps
> 
> #define EPSTAT(name)							\
> 	len = endpoint_stat(target, buf, buf_len, len,			\
> 			    offsetof(struct htc_endpoint_stats, name) / sizeof(u32), \
> 			    #name)

I'm fine with this, too, as a separate cleanup patch.

> > +	if (len > buf_len)
> > +		len = buf_len;
> 
> Maybe it's better to ensure 0 termination?
> 	if (len > buf_len) {
> 		len = buf_len;
> 		buf[buf_len - 1] = 0;
> 	}

Why? This is a read file op.. It is not like the caller is expecting a
null-terminated string to come back from here.

-- 
Jouni Malinen                                            PGP id EFC895FA

^ permalink raw reply


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