2015-01-25 08:53:23

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 00/10] wil6210 patches

Performance tuning; some AP features; some small fixes

Dedy Lansky (2):
wil6210: fix timing of netif_carrier_on indication
wil6210: ignore firmware failure to gracefully stop AP

Vladimir Kondratiev (4):
wil6210: sync WMI with firmware
wil6210: Tx status
wil6210: probe_client
wil6210: move Rx reorder buffer allocation out of spinlock

Vladimir Shulman (4):
wil6210: Add Tx queue len configuration
wil6210: tuning rings size
wil6210: interrupt moderation configuration update
wil6210: remove unnecessary interrupt moderation module parameters

drivers/net/wireless/ath/wil6210/cfg80211.c | 112 ++++++++++++++++++++++++--
drivers/net/wireless/ath/wil6210/main.c | 73 ++++-------------
drivers/net/wireless/ath/wil6210/netdev.c | 15 ++--
drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 +-
drivers/net/wireless/ath/wil6210/txrx.c | 19 ++++-
drivers/net/wireless/ath/wil6210/wil6210.h | 25 ++++--
drivers/net/wireless/ath/wil6210/wmi.c | 17 ++--
drivers/net/wireless/ath/wil6210/wmi.h | 58 +++++++++++--
8 files changed, 227 insertions(+), 100 deletions(-)

--
2.1.0



2015-01-25 08:53:28

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 03/10] wil6210: ignore firmware failure to gracefully stop AP

From: Dedy Lansky <[email protected]>

upon cfg80211_stop_ap, a graceful AP shutdown is requested from firmware
followed by firmware reset.
In case graceful request failed, error was returned to cfg80211.

The change is to return success in this scenario, because firmware
reset will anyhow shutdown the AP.

Signed-off-by: Dedy Lansky <[email protected]>
Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 553aa2e..6b7664d 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -773,7 +773,6 @@ out:
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
struct net_device *ndev)
{
- int rc, rc1;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);

wil_dbg_misc(wil, "%s()\n", __func__);
@@ -783,14 +782,17 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,

mutex_lock(&wil->mutex);

- rc = wmi_pcp_stop(wil);
+ wmi_pcp_stop(wil);

__wil_down(wil);
- rc1 = __wil_up(wil);
+ __wil_up(wil);

mutex_unlock(&wil->mutex);

- return min(rc, rc1);
+ /* some functions above might fail (e.g. __wil_up). Nevertheless, we
+ * return success because AP has stopped
+ */
+ return 0;
}

static int wil_cfg80211_del_station(struct wiphy *wiphy,
--
2.1.0


2015-01-25 08:53:26

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 02/10] wil6210: fix timing of netif_carrier_on indication

From: Dedy Lansky <[email protected]>

netif_carrier_on indication was too late. In case Rx packet received
before netif_carrier_on indication, upper layers could not send
Tx packet back.

The fix is to indicate netif_carrier_on earlier:
for STA, indicate netif_carrier_on when association starts.
for AP/PCP, indicate netif_carrier_on upon starting AP/PCP.

Signed-off-by: Dedy Lansky <[email protected]>
Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 8 +++++---
drivers/net/wireless/ath/wil6210/main.c | 30 ++++++-----------------------
drivers/net/wireless/ath/wil6210/netdev.c | 4 +---
drivers/net/wireless/ath/wil6210/wil6210.h | 2 --
drivers/net/wireless/ath/wil6210/wmi.c | 2 --
5 files changed, 12 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index bd013fd..553aa2e 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -454,6 +454,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,

rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
if (rc == 0) {
+ netif_carrier_on(ndev);
/* Connect can take lots of time */
mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000));
@@ -757,12 +758,12 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,

wil->secure_pcp = info->privacy;

+ netif_carrier_on(ndev);
+
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
channel->hw_value);
if (rc)
- goto out;
-
- netif_carrier_on(ndev);
+ netif_carrier_off(ndev);

out:
mutex_unlock(&wil->mutex);
@@ -777,6 +778,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,

wil_dbg_misc(wil, "%s()\n", __func__);

+ netif_carrier_off(ndev);
wil_set_recovery_state(wil, fw_recovery_idle);

mutex_lock(&wil->mutex);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 62dc241..00c9b0f 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -248,7 +248,9 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
- wil_link_off(wil);
+ netif_tx_stop_all_queues(ndev);
+ netif_carrier_off(ndev);
+
if (test_bit(wil_status_fwconnected, wil->status)) {
clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code,
@@ -395,6 +397,8 @@ static void wil_connect_worker(struct work_struct *work)
int rc;
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
connect_worker);
+ struct net_device *ndev = wil_to_ndev(wil);
+
int cid = wil->pending_connect_cid;
int ringid = wil_find_free_vring(wil);

@@ -409,7 +413,7 @@ static void wil_connect_worker(struct work_struct *work)
wil->pending_connect_cid = -1;
if (rc == 0) {
wil->sta[cid].status = wil_sta_connected;
- wil_link_on(wil);
+ netif_tx_wake_all_queues(ndev);
} else {
wil->sta[cid].status = wil_sta_unused;
}
@@ -741,28 +745,6 @@ void wil_fw_error_recovery(struct wil6210_priv *wil)
schedule_work(&wil->fw_error_worker);
}

-void wil_link_on(struct wil6210_priv *wil)
-{
- struct net_device *ndev = wil_to_ndev(wil);
-
- wil_dbg_misc(wil, "%s()\n", __func__);
-
- netif_carrier_on(ndev);
- wil_dbg_misc(wil, "netif_tx_wake : link on\n");
- netif_tx_wake_all_queues(ndev);
-}
-
-void wil_link_off(struct wil6210_priv *wil)
-{
- struct net_device *ndev = wil_to_ndev(wil);
-
- wil_dbg_misc(wil, "%s()\n", __func__);
-
- netif_tx_stop_all_queues(ndev);
- wil_dbg_misc(wil, "netif_tx_stop : link off\n");
- netif_carrier_off(ndev);
-}
-
int __wil_up(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index e81703c..f1f9e51 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -174,7 +174,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);

- wil_link_off(wil);
+ netif_tx_stop_all_queues(ndev);

return wil;

@@ -217,8 +217,6 @@ int wil_if_add(struct wil6210_priv *wil)
return rc;
}

- wil_link_off(wil);
-
return 0;
}

diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index da3fe78..b4404e7 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -649,8 +649,6 @@ void wil_priv_deinit(struct wil6210_priv *wil);
int wil_reset(struct wil6210_priv *wil);
void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_set_recovery_state(struct wil6210_priv *wil, int state);
-void wil_link_on(struct wil6210_priv *wil);
-void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 097d78b..0f3e433 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -566,7 +566,6 @@ static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize)

static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
{
- struct net_device *ndev = wil_to_ndev(wil);
struct wmi_data_port_open_event *evt = d;
u8 cid = evt->cid;

@@ -580,7 +579,6 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
wil->sta[cid].data_port_open = true;
if (agg_wsize >= 0)
wil_addba_tx_cid(wil, cid, agg_wsize);
- netif_carrier_on(ndev);
}

static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
--
2.1.0


2015-01-29 07:56:29

by Kalle Valo

[permalink] [raw]
Subject: Re: [01/10] wil6210: sync WMI with firmware


> Incorporate changes from firmware.
>
> Signed-off-by: Vladimir Kondratiev <[email protected]>

Thanks, 10 patches applied to wireless-drivers-next.git:

8c6796758f0a wil6210: sync WMI with firmware
c5e96c91fa8f wil6210: fix timing of netif_carrier_on indication
32a20d46b3dc wil6210: ignore firmware failure to gracefully stop AP
f1871cd95067 wil6210: Add Tx queue len configuration
3baedd9167c2 wil6210: tuning rings size
918465a3c2f7 wil6210: interrupt moderation configuration update
1f80af2e38f7 wil6210: remove unnecessary interrupt moderation module parameters
713c8a29e4d8 wil6210: implement skb Tx status reporting
40822a901e3c wil6210: implement cfg80211 probe_client() op
382afc3d055b wil6210: move Rx reorder buffer allocation out of spinlock

Kalle Valo

2015-01-26 13:38:18

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 09/10] wil6210: probe_client

Vladimir Kondratiev <[email protected]> writes:

> Access point require this API to check peer alive status.
> Assume peer is alive when it is connected, because
> firmware implements keep alive checks and will disconnect
> peer if it is not alive.
>
> Signed-off-by: Vladimir Kondratiev <[email protected]>

Here the title is again too short, is it ok if I change it to this:

wil6210: implement cfg80211 probe_client() op

--
Kalle Valo

2015-01-25 08:53:32

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 05/10] wil6210: tuning rings size

From: Vladimir Shulman <[email protected]>

Tuning rings size for performance optimization.
Increasing Tx ring size, allows buffering more packets for HW, thus
eliminating idle periods which were observed with smaller ring at
high throughput, because HW was fetching packets faster than driver was
filling them into the TX ring. Rx ring was similarly increased to
avoid same problems in Rx.

Signed-off-by: Vladimir Shulman <[email protected]>
Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index fc196bf..2521ba1 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -45,8 +45,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_MEM_SIZE (2*1024*1024UL)

#define WIL_TX_Q_LEN_DEFAULT (4000)
-#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9)
-#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9)
+#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
+#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10)
/* limit ring size in range [32..32k] */
#define WIL_RING_SIZE_ORDER_MIN (5)
#define WIL_RING_SIZE_ORDER_MAX (15)
--
2.1.0


2015-01-26 13:39:03

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 07/10] wil6210: remove unnecessary interrupt moderation module parameters

Vladimir Kondratiev <[email protected]> writes:

> From: Vladimir Shulman <[email protected]>
>
> Interrupt moderation parameters will never be passed as module
> parameters. For product, they will be hard-coded after lab testing,
> and for debugging, they can be altered via debugfs.
>
> Signed-off-by: Vladimir Shulman <[email protected]>
> Signed-off-by: Vladimir Kondratiev <[email protected]>

Perfect, thanks for doing this.

--
Kalle Valo

2015-01-25 08:53:39

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 09/10] wil6210: probe_client

Access point require this API to check peer alive status.
Assume peer is alive when it is connected, because
firmware implements keep alive checks and will disconnect
peer if it is not alive.

Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 91 +++++++++++++++++++++++++++++
drivers/net/wireless/ath/wil6210/main.c | 5 ++
drivers/net/wireless/ath/wil6210/wil6210.h | 12 ++++
3 files changed, 108 insertions(+)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index f65da91..e758f43 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -808,6 +808,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
return 0;
}

+/* probe_client handling */
+static void wil_probe_client_handle(struct wil6210_priv *wil,
+ struct wil_probe_client_req *req)
+{
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct wil_sta_info *sta = &wil->sta[req->cid];
+ /* assume STA is alive if it is still connected,
+ * else FW will disconnect it
+ */
+ bool alive = (sta->status == wil_sta_connected);
+
+ cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL);
+}
+
+static struct list_head *next_probe_client(struct wil6210_priv *wil)
+{
+ struct list_head *ret = NULL;
+
+ mutex_lock(&wil->probe_client_mutex);
+
+ if (!list_empty(&wil->probe_client_pending)) {
+ ret = wil->probe_client_pending.next;
+ list_del(ret);
+ }
+
+ mutex_unlock(&wil->probe_client_mutex);
+
+ return ret;
+}
+
+void wil_probe_client_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ probe_client_worker);
+ struct wil_probe_client_req *req;
+ struct list_head *lh;
+
+ while ((lh = next_probe_client(wil)) != NULL) {
+ req = list_entry(lh, struct wil_probe_client_req, list);
+
+ wil_probe_client_handle(wil, req);
+ kfree(req);
+ }
+}
+
+void wil_probe_client_flush(struct wil6210_priv *wil)
+{
+ struct wil_probe_client_req *req, *t;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ mutex_lock(&wil->probe_client_mutex);
+
+ list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) {
+ list_del(&req->list);
+ kfree(req);
+ }
+
+ mutex_unlock(&wil->probe_client_mutex);
+}
+
+static int wil_cfg80211_probe_client(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *peer, u64 *cookie)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil_probe_client_req *req;
+ int cid = wil_find_cid(wil, peer);
+
+ wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid);
+
+ if (cid < 0)
+ return -ENOLINK;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->cid = cid;
+ req->cookie = cid;
+
+ mutex_lock(&wil->probe_client_mutex);
+ list_add_tail(&req->list, &wil->probe_client_pending);
+ mutex_unlock(&wil->probe_client_mutex);
+
+ *cookie = req->cookie;
+ queue_work(wil->wq_service, &wil->probe_client_worker);
+ return 0;
+}
+
static struct cfg80211_ops wil_cfg80211_ops = {
.scan = wil_cfg80211_scan,
.connect = wil_cfg80211_connect,
@@ -827,6 +917,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station,
+ .probe_client = wil_cfg80211_probe_client,
};

static void wil_wiphy_init(struct wiphy *wiphy)
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index d259416..b04e0af 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -405,6 +405,7 @@ int wil_priv_init(struct wil6210_priv *wil)
mutex_init(&wil->wmi_mutex);
mutex_init(&wil->back_rx_mutex);
mutex_init(&wil->back_tx_mutex);
+ mutex_init(&wil->probe_client_mutex);

init_completion(&wil->wmi_ready);
init_completion(&wil->wmi_call);
@@ -419,10 +420,12 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
+ INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);

INIT_LIST_HEAD(&wil->pending_wmi_ev);
INIT_LIST_HEAD(&wil->back_rx_pending);
INIT_LIST_HEAD(&wil->back_tx_pending);
+ INIT_LIST_HEAD(&wil->probe_client_pending);
spin_lock_init(&wil->wmi_ev_lock);
init_waitqueue_head(&wil->wq);

@@ -485,6 +488,8 @@ void wil_priv_deinit(struct wil6210_priv *wil)
cancel_work_sync(&wil->back_rx_worker);
wil_back_tx_flush(wil);
cancel_work_sync(&wil->back_tx_worker);
+ wil_probe_client_flush(wil);
+ cancel_work_sync(&wil->probe_client_worker);
destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq);
}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 3575b5d..90dc24f 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -504,6 +504,12 @@ struct wil_back_tx {
u16 agg_timeout;
};

+struct wil_probe_client_req {
+ struct list_head list;
+ u64 cookie;
+ u8 cid;
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
int n_msi;
@@ -564,6 +570,10 @@ struct wil6210_priv {
struct list_head back_tx_pending;
struct mutex back_tx_mutex; /* protect @back_tx_pending */
struct work_struct back_tx_worker;
+ /* keep alive */
+ struct list_head probe_client_pending;
+ struct mutex probe_client_mutex; /* protect @probe_client_pending */
+ struct work_struct probe_client_worker;
/* DMA related */
struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
@@ -722,6 +732,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event);
+void wil_probe_client_flush(struct wil6210_priv *wil);
+void wil_probe_client_worker(struct work_struct *work);

int wil_rx_init(struct wil6210_priv *wil, u16 size);
void wil_rx_fini(struct wil6210_priv *wil);
--
2.1.0


2015-01-25 08:53:30

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 04/10] wil6210: Add Tx queue len configuration

From: Vladimir Shulman <[email protected]>

Tx queue was hard-coded to 1000 in ether_setup. Add wil_dev_setup
function which configures tx queue len to chosen default value
after calling ether_setup.

Signed-off-by: Vladimir Shulman <[email protected]>
Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/netdev.c | 11 ++++++++---
drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++-
2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index f1f9e51..ace30c1 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,6 @@
*/

#include <linux/etherdevice.h>
-
#include "wil6210.h"
#include "txrx.h"

@@ -122,6 +121,12 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
return min(tx_done, budget);
}

+static void wil_dev_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
+}
+
void *wil_if_alloc(struct device *dev, void __iomem *csr)
{
struct net_device *ndev;
@@ -153,7 +158,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);

- ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup);
+ ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
if (!ndev) {
dev_err(dev, "alloc_netdev_mqs failed\n");
rc = -ENOMEM;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index b4404e7..fc196bf 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -44,6 +44,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)

#define WIL6210_MEM_SIZE (2*1024*1024UL)

+#define WIL_TX_Q_LEN_DEFAULT (4000)
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9)
#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9)
/* limit ring size in range [32..32k] */
--
2.1.0


2015-01-25 08:53:38

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 08/10] wil6210: Tx status

Implement Tx status reporting

Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 1 +
drivers/net/wireless/ath/wil6210/txrx.c | 19 +++++++++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 6b7664d..f65da91 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -858,6 +858,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->cipher_suites = wil_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
wiphy->mgmt_stypes = wil_mgmt_stypes;
+ wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
}

struct wireless_dev *wil_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index b58ee52..0499ebc 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1121,6 +1121,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NET_XMIT_DROP;
}

+static inline bool wil_need_txstat(struct sk_buff *skb)
+{
+ struct ethhdr *eth = (void *)skb->data;
+
+ return is_unicast_ether_addr(eth->h_dest) && skb->sk &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS);
+}
+
+static inline void wil_consume_skb(struct sk_buff *skb, bool acked)
+{
+ if (unlikely(wil_need_txstat(skb)))
+ skb_complete_wifi_ack(skb, acked);
+ else
+ acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb);
+}
+
/**
* Clean up transmitted skb's from the Tx VRING
*
@@ -1199,8 +1215,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
ndev->stats.tx_errors++;
stats->tx_errors++;
}
-
- dev_kfree_skb_any(skb);
+ wil_consume_skb(skb, d->dma.error == 0);
}
memset(ctx, 0, sizeof(*ctx));
/* There is no need to touch HW descriptor:
--
2.1.0


2015-01-26 18:50:34

by Vladimir Kondratiev

[permalink] [raw]
Subject: Re: [PATCH 08/10] wil6210: Tx status

On 01/26/2015 03:36 PM, Kalle Valo wrote:
> Vladimir Kondratiev <[email protected]> writes:
>
>> Implement Tx status reporting
>>
>> Signed-off-by: Vladimir Kondratiev <[email protected]>
>
> I think the title is too short. I would like to change it to this, is
> that ok?
>
> wil6210: implement skb Tx status reporting
>
> Implment Tx status reporting using skb_complete_wifi_ack().
>

Yes, it is fine.

Thanks, Vladimir

2015-01-25 08:53:24

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 01/10] wil6210: sync WMI with firmware

Incorporate changes from firmware.

Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/wmi.c | 15 +++++----
drivers/net/wireless/ath/wil6210/wmi.h | 58 ++++++++++++++++++++++++++++++----
2 files changed, 59 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index b2b0fe1..097d78b 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1133,12 +1133,13 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
return rc;
}

-int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
+int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
{
int rc;
struct wmi_temp_sense_cmd cmd = {
- .measure_marlon_m_en = cpu_to_le32(!!t_m),
- .measure_marlon_r_en = cpu_to_le32(!!t_r),
+ .measure_baseband_en = cpu_to_le32(!!t_bb),
+ .measure_rf_en = cpu_to_le32(!!t_rf),
+ .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -1150,10 +1151,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
if (rc)
return rc;

- if (t_m)
- *t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
- if (t_r)
- *t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
+ if (t_bb)
+ *t_bb = le32_to_cpu(reply.evt.baseband_t1000);
+ if (t_rf)
+ *t_rf = le32_to_cpu(reply.evt.rf_t1000);

return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index b5102f0..8a4af61 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -29,8 +29,10 @@

/* General */
#define WILOCITY_MAX_ASSOC_STA (8)
+#define WILOCITY_DEFAULT_ASSOC_STA (1)
#define WMI_MAC_LEN (6)
#define WMI_PROX_RANGE_NUM (3)
+#define WMI_MAX_LOSS_DMG_BEACONS (32)

/* List of Commands */
enum wmi_command_id {
@@ -48,7 +50,7 @@ enum wmi_command_id {
WMI_SET_WSC_STATUS_CMDID = 0x0041,
WMI_PXMT_RANGE_CFG_CMDID = 0x0042,
WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043,
- WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300,
+/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */
WMI_MEM_READ_CMDID = 0x0800,
WMI_MEM_WR_CMDID = 0x0801,
WMI_ECHO_CMDID = 0x0803,
@@ -102,6 +104,8 @@ enum wmi_command_id {
WMI_MAINTAIN_RESUME_CMDID = 0x0851,
WMI_RS_MGMT_CMDID = 0x0852,
WMI_RF_MGMT_CMDID = 0x0853,
+ WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854,
+ WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855,
/* Performance monitoring commands */
WMI_BF_CTRL_CMDID = 0x0862,
WMI_NOTIFY_REQ_CMDID = 0x0863,
@@ -136,6 +140,7 @@ enum wmi_command_id {
WMI_EAPOL_TX_CMDID = 0xf04c,
WMI_MAC_ADDR_REQ_CMDID = 0xf04d,
WMI_FW_VER_CMDID = 0xf04e,
+ WMI_PMC_CMDID = 0xf04f,
};

/*
@@ -283,8 +288,8 @@ enum wmi_scan_type {
WMI_LONG_SCAN = 0,
WMI_SHORT_SCAN = 1,
WMI_PBC_SCAN = 2,
- WMI_ACTIVE_SCAN = 3,
- WMI_DIRECT_SCAN = 4,
+ WMI_DIRECT_SCAN = 3,
+ WMI_ACTIVE_SCAN = 4,
};

struct wmi_start_scan_cmd {
@@ -375,6 +380,17 @@ struct wmi_rf_mgmt_cmd {
} __packed;

/*
+ * WMI_THERMAL_THROTTLING_CTRL_CMDID
+ */
+#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF)
+
+struct wmi_thermal_throttling_ctrl_cmd {
+ __le32 time_on_usec;
+ __le32 time_off_usec;
+ __le32 max_txop_length_usec;
+} __packed;
+
+/*
* WMI_RF_RX_TEST_CMDID
*/
struct wmi_rf_rx_test_cmd {
@@ -648,6 +664,7 @@ enum wmi_cfg_rx_chain_cmd_action {
enum wmi_cfg_rx_chain_cmd_decap_trans_type {
WMI_DECAP_TYPE_802_3 = 0,
WMI_DECAP_TYPE_NATIVE_WIFI = 1,
+ WMI_DECAP_TYPE_NONE = 2,
};

enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type {
@@ -785,9 +802,17 @@ struct wmi_echo_cmd {
*
* Measure MAC and radio temperatures
*/
+
+/* Possible modes for temperature measurement */
+enum wmi_temperature_measure_mode {
+ TEMPERATURE_USE_OLD_VALUE = 0x1,
+ TEMPERATURE_MEASURE_NOW = 0x2,
+};
+
struct wmi_temp_sense_cmd {
- __le32 measure_marlon_m_en;
- __le32 measure_marlon_r_en;
+ __le32 measure_baseband_en;
+ __le32 measure_rf_en;
+ __le32 measure_mode;
} __packed;

/*
@@ -843,6 +868,7 @@ enum wmi_event_id {
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
WMI_RF_MGMT_STATUS_EVENTID = 0x1853,
+ WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855,
WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838,
WMI_RX_MGMT_PACKET_EVENTID = 0x1840,
WMI_TX_MGMT_PACKET_EVENTID = 0x1841,
@@ -859,6 +885,7 @@ enum wmi_event_id {
WMI_FLASH_READ_DONE_EVENTID = 0x1902,
WMI_FLASH_WRITE_DONE_EVENTID = 0x1903,
/*P2P*/
+ WMI_P2P_CFG_DONE_EVENTID = 0x1910,
WMI_PORT_ALLOCATED_EVENTID = 0x1911,
WMI_PORT_DELETED_EVENTID = 0x1912,
WMI_LISTEN_STARTED_EVENTID = 0x1914,
@@ -899,6 +926,15 @@ struct wmi_rf_mgmt_status_event {
} __packed;

/*
+ * WMI_THERMAL_THROTTLING_STATUS_EVENTID
+ */
+struct wmi_thermal_throttling_status_event {
+ __le32 time_on_usec;
+ __le32 time_off_usec;
+ __le32 max_txop_length_usec;
+} __packed;
+
+/*
* WMI_GET_STATUS_DONE_EVENTID
*/
struct wmi_get_status_done_event {
@@ -1155,6 +1191,14 @@ struct wmi_get_pcp_channel_event {
} __packed;

/*
+ * WMI_P2P_CFG_DONE_EVENTID
+ */
+struct wmi_p2p_cfg_done_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
* WMI_PORT_ALLOCATED_EVENTID
*/
struct wmi_port_allocated_event {
@@ -1282,8 +1326,8 @@ struct wmi_echo_event {
* Measure MAC and radio temperatures
*/
struct wmi_temp_sense_done_event {
- __le32 marlon_m_t1000;
- __le32 marlon_r_t1000;
+ __le32 baseband_t1000;
+ __le32 rf_t1000;
} __packed;

#endif /* __WILOCITY_WMI_H__ */
--
2.1.0


2015-01-26 13:36:52

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 08/10] wil6210: Tx status

Vladimir Kondratiev <[email protected]> writes:

> Implement Tx status reporting
>
> Signed-off-by: Vladimir Kondratiev <[email protected]>

I think the title is too short. I would like to change it to this, is
that ok?

wil6210: implement skb Tx status reporting

Implment Tx status reporting using skb_complete_wifi_ack().

--
Kalle Valo

2015-01-26 18:51:55

by Vladimir Kondratiev

[permalink] [raw]
Subject: Re: [PATCH 09/10] wil6210: probe_client

On 01/26/2015 03:38 PM, Kalle Valo wrote:
> Vladimir Kondratiev <[email protected]> writes:
>
>> Access point require this API to check peer alive status.
>> Assume peer is alive when it is connected, because
>> firmware implements keep alive checks and will disconnect
>> peer if it is not alive.
>>
>> Signed-off-by: Vladimir Kondratiev <[email protected]>
>
> Here the title is again too short, is it ok if I change it to this:
>
> wil6210: implement cfg80211 probe_client() op
>
Yes, this is OK.

Thanks, Vladimir

2015-01-25 08:53:34

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 06/10] wil6210: interrupt moderation configuration update

From: Vladimir Shulman <[email protected]>

Due to HW limitation, inter-packet gap timeout max value is 13 usec.
Update of current thresholds from 15 to 13 usec.

Signed-off-by: Vladimir Shulman <[email protected]>
Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 2521ba1..3575b5d 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -78,8 +78,8 @@ static inline u32 wil_mtu2macbuf(u32 mtu)
#define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8)
/* Max supported by wil6210 value for interrupt threshold is 5sec. */
#define WIL6210_ITR_TRSH_MAX (5000000)
-#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */
-#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */
+#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */
+#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */
#define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */
#define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */
#define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */
--
2.1.0


2015-01-25 08:53:36

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 07/10] wil6210: remove unnecessary interrupt moderation module parameters

From: Vladimir Shulman <[email protected]>

Interrupt moderation parameters will never be passed as module
parameters. For product, they will be hard-coded after lab testing,
and for debugging, they can be altered via debugfs.

Signed-off-by: Vladimir Shulman <[email protected]>
Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/main.c | 38 +++++----------------------------
1 file changed, 5 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 00c9b0f..d259416 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -33,34 +33,6 @@ static bool no_fw_load = true;
module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");

-static unsigned int tx_interframe_timeout =
- WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT;
-
-module_param(tx_interframe_timeout, uint, S_IRUGO);
-MODULE_PARM_DESC(tx_interframe_timeout,
- " Interrupt moderation TX interframe timeout, usecs.");
-
-static unsigned int rx_interframe_timeout =
- WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT;
-
-module_param(rx_interframe_timeout, uint, S_IRUGO);
-MODULE_PARM_DESC(rx_interframe_timeout,
- " Interrupt moderation RX interframe timeout, usecs.");
-
-static unsigned int tx_max_burst_duration =
- WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT;
-
-module_param(tx_max_burst_duration, uint, S_IRUGO);
-MODULE_PARM_DESC(tx_max_burst_duration,
- " Interrupt moderation TX max burst duration, usecs.");
-
-static unsigned int rx_max_burst_duration =
- WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT;
-
-module_param(rx_max_burst_duration, uint, S_IRUGO);
-MODULE_PARM_DESC(rx_max_burst_duration,
- " Interrupt moderation RX max burst duration, usecs.");
-
/* if not set via modparam, will be set to default value of 1/8 of
* rx ring size during init flow
*/
@@ -463,10 +435,10 @@ int wil_priv_init(struct wil6210_priv *wil)
goto out_wmi_wq;

wil->last_fw_recovery = jiffies;
- wil->tx_interframe_timeout = tx_interframe_timeout;
- wil->rx_interframe_timeout = rx_interframe_timeout;
- wil->tx_max_burst_duration = tx_max_burst_duration;
- wil->rx_max_burst_duration = rx_max_burst_duration;
+ wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT;
+ wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT;
+ wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT;
+ wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT;

if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
--
2.1.0


2015-01-25 08:53:41

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH 10/10] wil6210: move Rx reorder buffer allocation out of spinlock

This fixes issue reported by Dan Carpenter:
The patch 3277213feb1b: "wil6210: ADDBA/DELBA flows" from Dec 23,
2014, leads to the following static checker warning:

drivers/net/wireless/ath/wil6210/rx_reorder.c:205 wil_tid_ampdu_rx_alloc()
error: scheduling with locks held: 'spin_lock:tid_rx_lock'

drivers/net/wireless/ath/wil6210/rx_reorder.c
202 struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
203 int size, u16 ssn)
204 {
205 struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
^^^^^^^^^^
206
207 if (!r)
208 return NULL;
209
210 r->reorder_buf =
211 kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
^^^^^^^^^^^
212 r->reorder_time =
213 kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
^^^^^^^^^^^
214 if (!r->reorder_buf || !r->reorder_time) {
215 kfree(r->reorder_buf);
216 kfree(r->reorder_time);
217 kfree(r);
218 return NULL;
219 }
220

[ snip ]

331 spin_lock_bh(&sta->tid_rx_lock);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
spin lock held.

332
333 wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
334 sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
function called with the lock held.

335
336 spin_unlock_bh(&sta->tid_rx_lock);

Reported-by: Dan Carpenter <[email protected]>
Signed-off-by: Vladimir Kondratiev <[email protected]>
---
drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 5522092..ca10dcf 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -292,6 +292,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
u16 agg_timeout = req->ba_timeout;
u16 status = WLAN_STATUS_SUCCESS;
u16 ssn = req->ba_seq_ctrl >> 4;
+ struct wil_tid_ampdu_rx *r;
int rc;

might_sleep();
@@ -328,11 +329,10 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
return;

/* apply */
+ r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
spin_lock_bh(&sta->tid_rx_lock);
-
wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
- sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
-
+ sta->tid_rx[tid] = r;
spin_unlock_bh(&sta->tid_rx_lock);
}

--
2.1.0