All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/22] wil6210 patches
@ 2014-12-23  7:47 Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 01/22] wil6210: ADDBA/DELBA flows Vladimir Kondratiev
                   ` (22 more replies)
  0 siblings, 23 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Several topics:
- block ack with secure and insecure connection
- MTU
- some infrastructure fixes
- some debugfs changes

Vladimir Kondratiev (22):
  wil6210: ADDBA/DELBA flows
  wil6210: simple ADDBA on originator (Tx) side
  wil6210: allow to configure ADDBA request
  wil6210: improve debugfs for reorder buffer
  wil6210: fix disconnect 1 STA in AP
  wil6210: improve debugfs for VRING
  wil6210: control AMSDU on Tx side of Block Ack
  wil6210: delba for responder
  wil6210: fix max. MPDU size
  wil6210: consider SNAP header in MTU calculations
  wil6210: Increase number of associated stations
  wil6210: use bitmap API for "status"
  wil6210: fix Tx VRING for STA mode
  wil6210: rework debugfs for BACK
  wil6210: detect HW capabilities
  wil6210: use HW capabilities mask in reset
  wil6210: add advanced interrupt moderation
  wil6210: RX high threshold interrupt configuration
  wil6210: fix reordering for MCAST
  wil6210: Tx/Rx descriptors documentation
  wil6210: workaround for BACK establishment race
  wil6210: relax spinlocks in rx reorder

 drivers/net/wireless/ath/wil6210/cfg80211.c   |  12 +-
 drivers/net/wireless/ath/wil6210/debugfs.c    | 160 +++++++++++++--
 drivers/net/wireless/ath/wil6210/ethtool.c    |  46 +++--
 drivers/net/wireless/ath/wil6210/interrupt.c  | 109 ++++++++--
 drivers/net/wireless/ath/wil6210/main.c       | 194 ++++++++++--------
 drivers/net/wireless/ath/wil6210/pcie_bus.c   |  65 ++++--
 drivers/net/wireless/ath/wil6210/rx_reorder.c | 275 +++++++++++++++++++++++++-
 drivers/net/wireless/ath/wil6210/txrx.c       |  70 +++++--
 drivers/net/wireless/ath/wil6210/txrx.h       | 158 ++++++++++-----
 drivers/net/wireless/ath/wil6210/wil6210.h    | 161 +++++++++++++--
 drivers/net/wireless/ath/wil6210/wmi.c        | 221 +++++++++++++++++----
 drivers/net/wireless/ath/wil6210/wmi.h        |  12 +-
 12 files changed, 1199 insertions(+), 284 deletions(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 01/22] wil6210: ADDBA/DELBA flows
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 02/22] wil6210: simple ADDBA on originator (Tx) side Vladimir Kondratiev
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.

debugfs usage:
to establish BACK with agg_wsize 16:
  echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
  echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew

ADDBA flow for:

- originator

Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs

- recipient

Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.

policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes

DELBA flow for:

- originator

driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.

- recipient

firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer

ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c    |  53 ++++++++-
 drivers/net/wireless/ath/wil6210/main.c       |  24 ++--
 drivers/net/wireless/ath/wil6210/rx_reorder.c | 146 +++++++++++++++++++++++
 drivers/net/wireless/ath/wil6210/txrx.c       |   2 +-
 drivers/net/wireless/ath/wil6210/wil6210.h    |  36 +++++-
 drivers/net/wireless/ath/wil6210/wmi.c        | 159 +++++++++++++++++++++-----
 6 files changed, 376 insertions(+), 44 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 4e6e145..18f5b67 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -110,9 +110,11 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
 
 			snprintf(name, sizeof(name), "tx_%2d", i);
 
-			seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n",
-				   wil->sta[cid].addr, cid, tid, used, avail,
-				   (int)idle);
+			seq_printf(s,
+				   "\n%pM CID %d TID %d BACK([%d] %d TU) [%3d|%3d] idle %3d%%\n",
+				   wil->sta[cid].addr, cid, tid,
+				   txdata->agg_wsize, txdata->agg_timeout,
+				   used, avail, (int)idle);
 
 			wil_print_vring(s, wil, name, vring, '_', 'H');
 		}
@@ -558,6 +560,50 @@ static const struct file_operations fops_rxon = {
 	.open  = simple_open,
 };
 
+/* block ack for vring 0
+ * write 0 to it to trigger DELBA
+ * write positive agg_wsize to trigger ADDBA
+ */
+static ssize_t wil_write_addba(struct file *file, const char __user *buf,
+			       size_t len, loff_t *ppos)
+{
+	struct wil6210_priv *wil = file->private_data;
+	int rc;
+	uint agg_wsize;
+	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+
+	if (!kbuf)
+		return -ENOMEM;
+
+	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
+	if (rc != len) {
+		kfree(kbuf);
+		return rc >= 0 ? -EIO : rc;
+	}
+
+	kbuf[len] = '\0';
+	rc = kstrtouint(kbuf, 0, &agg_wsize);
+	kfree(kbuf);
+
+	if (rc)
+		return rc;
+
+	if (!wil->vring_tx[0].va)
+		return -EINVAL;
+
+	if (agg_wsize > 0)
+		wmi_addba(wil, 0, agg_wsize, 0);
+	else
+		wmi_delba(wil, 0, 0);
+
+	return len;
+}
+
+static const struct file_operations fops_addba = {
+	.write = wil_write_addba,
+	.open  = simple_open,
+};
+
 /*---tx_mgmt---*/
 /* Write mgmt frame to this file to send it */
 static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -1217,6 +1263,7 @@ static const struct {
 	{"rxon",		  S_IWUSR,	&fops_rxon},
 	{"tx_mgmt",		  S_IWUSR,	&fops_txmgmt},
 	{"wmi_send",		  S_IWUSR,	&fops_wmi},
+	{"addba",		  S_IWUSR,	&fops_addba},
 	{"temp",	S_IRUGO,		&fops_temp},
 	{"freq",	S_IRUGO,		&fops_freq},
 	{"link",	S_IRUGO,		&fops_link},
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 8ff3fe3..9b402b9 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -384,6 +384,7 @@ int wil_priv_init(struct wil6210_priv *wil)
 
 	mutex_init(&wil->mutex);
 	mutex_init(&wil->wmi_mutex);
+	mutex_init(&wil->back_rx_mutex);
 
 	init_completion(&wil->wmi_ready);
 	init_completion(&wil->wmi_call);
@@ -396,25 +397,30 @@ int wil_priv_init(struct wil6210_priv *wil)
 	INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
 	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
 	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
+	INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
 
 	INIT_LIST_HEAD(&wil->pending_wmi_ev);
+	INIT_LIST_HEAD(&wil->back_rx_pending);
 	spin_lock_init(&wil->wmi_ev_lock);
 	init_waitqueue_head(&wil->wq);
 
-	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
+	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
 	if (!wil->wmi_wq)
 		return -EAGAIN;
 
-	wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
-	if (!wil->wmi_wq_conn) {
-		destroy_workqueue(wil->wmi_wq);
-		return -EAGAIN;
-	}
+	wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
+	if (!wil->wq_service)
+		goto out_wmi_wq;
 
 	wil->last_fw_recovery = jiffies;
 	wil->itr_trsh = itr_trsh;
 
 	return 0;
+
+out_wmi_wq:
+	destroy_workqueue(wil->wmi_wq);
+
+	return -EAGAIN;
 }
 
 /**
@@ -448,7 +454,9 @@ void wil_priv_deinit(struct wil6210_priv *wil)
 	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
 	mutex_unlock(&wil->mutex);
 	wmi_event_flush(wil);
-	destroy_workqueue(wil->wmi_wq_conn);
+	wil_back_rx_flush(wil);
+	cancel_work_sync(&wil->back_rx_worker);
+	destroy_workqueue(wil->wq_service);
 	destroy_workqueue(wil->wmi_wq);
 }
 
@@ -649,7 +657,7 @@ int wil_reset(struct wil6210_priv *wil)
 
 	wmi_event_flush(wil);
 
-	flush_workqueue(wil->wmi_wq_conn);
+	flush_workqueue(wil->wq_service);
 	flush_workqueue(wil->wmi_wq);
 
 	rc = wil_target_reset(wil);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 489cb73..8e6d25a 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -219,3 +219,149 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
 	kfree(r->reorder_time);
 	kfree(r);
 }
+
+/* ADDBA processing */
+static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
+{
+	u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE /
+				 (mtu_max + WIL_MAX_MPDU_OVERHEAD));
+
+	if (!req_agg_wsize)
+		return max_agg_size;
+
+	return min(max_agg_size, req_agg_wsize);
+}
+
+/* Block Ack - Rx side (recipient */
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
+			 u8 dialog_token, __le16 ba_param_set,
+			 __le16 ba_timeout, __le16 ba_seq_ctrl)
+{
+	struct wil_back_rx *req = kzalloc(sizeof(*req), GFP_KERNEL);
+
+	if (!req)
+		return -ENOMEM;
+
+	req->cidxtid = cidxtid;
+	req->dialog_token = dialog_token;
+	req->ba_param_set = le16_to_cpu(ba_param_set);
+	req->ba_timeout = le16_to_cpu(ba_timeout);
+	req->ba_seq_ctrl = le16_to_cpu(ba_seq_ctrl);
+
+	mutex_lock(&wil->back_rx_mutex);
+	list_add_tail(&req->list, &wil->back_rx_pending);
+	mutex_unlock(&wil->back_rx_mutex);
+
+	queue_work(wil->wq_service, &wil->back_rx_worker);
+
+	return 0;
+}
+
+static void wil_back_rx_handle(struct wil6210_priv *wil,
+			       struct wil_back_rx *req)
+{
+	struct wil_sta_info *sta;
+	u8 cid, tid;
+	u16 agg_wsize = 0;
+	/* bit 0: A-MSDU supported
+	 * bit 1: policy (should be 0 for us)
+	 * bits 2..5: TID
+	 * bits 6..15: buffer size
+	 */
+	u16 req_agg_wsize = WIL_GET_BITS(req->ba_param_set, 6, 15);
+	bool agg_amsdu = !!(req->ba_param_set & BIT(0));
+	int ba_policy = req->ba_param_set & BIT(1);
+	u16 agg_timeout = req->ba_timeout;
+	u16 status = WLAN_STATUS_SUCCESS;
+	unsigned long flags;
+	int rc;
+
+	parse_cidxtid(req->cidxtid, &cid, &tid);
+
+	/* sanity checks */
+	if (cid >= WIL6210_MAX_CID) {
+		wil_err(wil, "BACK: invalid CID %d\n", cid);
+		return;
+	}
+
+	sta = &wil->sta[cid];
+	if (sta->status != wil_sta_connected) {
+		wil_err(wil, "BACK: CID %d not connected\n", cid);
+		return;
+	}
+
+	wil_dbg_wmi(wil,
+		    "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d\n",
+		    cid, sta->addr, tid, req_agg_wsize, req->ba_timeout,
+		    agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token);
+
+	/* apply policies */
+	if (ba_policy) {
+		wil_err(wil, "BACK requested unsupported ba_policy == 1\n");
+		status = WLAN_STATUS_INVALID_QOS_PARAM;
+	}
+	if (status == WLAN_STATUS_SUCCESS)
+		agg_wsize = wil_agg_size(wil, req_agg_wsize);
+
+	rc = wmi_addba_rx_resp(wil, cid, tid, req->dialog_token, status,
+			       agg_amsdu, agg_wsize, agg_timeout);
+	if (rc || (status != WLAN_STATUS_SUCCESS))
+		return;
+
+	/* apply */
+	spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+	wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
+	sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize,
+						  req->ba_seq_ctrl >> 4);
+
+	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+}
+
+void wil_back_rx_flush(struct wil6210_priv *wil)
+{
+	struct wil_back_rx *evt, *t;
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	mutex_lock(&wil->back_rx_mutex);
+
+	list_for_each_entry_safe(evt, t, &wil->back_rx_pending, list) {
+		list_del(&evt->list);
+		kfree(evt);
+	}
+
+	mutex_unlock(&wil->back_rx_mutex);
+}
+
+/* Retrieve next ADDBA request from the pending list */
+static struct list_head *next_back_rx(struct wil6210_priv *wil)
+{
+	struct list_head *ret = NULL;
+
+	mutex_lock(&wil->back_rx_mutex);
+
+	if (!list_empty(&wil->back_rx_pending)) {
+		ret = wil->back_rx_pending.next;
+		list_del(ret);
+	}
+
+	mutex_unlock(&wil->back_rx_mutex);
+
+	return ret;
+}
+
+void wil_back_rx_worker(struct work_struct *work)
+{
+	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+						back_rx_worker);
+	struct wil_back_rx *evt;
+	struct list_head *lh;
+
+	while ((lh = next_back_rx(wil)) != NULL) {
+		evt = list_entry(lh, struct wil_back_rx, list);
+
+		wil_back_rx_handle(wil, evt);
+		kfree(evt);
+	}
+}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index e3f8bdc..d926860 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -653,7 +653,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
 			.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
 			.mac_ctrl = 0,
 			.to_resolution = 0,
-			.agg_max_wsize = 16,
+			.agg_max_wsize = 0,
 			.schd_params = {
 				.priority = cpu_to_le16(0),
 				.timeslot_us = cpu_to_le16(0xfff),
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index c6ec5b9..4a9a68e 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -57,6 +57,15 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
 #define WIL6210_MAX_TX_RINGS	(24) /* HW limit */
 #define WIL6210_MAX_CID		(8) /* HW limit */
 #define WIL6210_NAPI_BUDGET	(16) /* arbitrary */
+#define WIL_MAX_AMPDU_SIZE	(64 * 1024) /* FW/HW limit */
+#define WIL_MAX_AGG_WSIZE	(32) /* FW/HW limit */
+/* Hardware offload block adds the following:
+ * 26 bytes - 3-address QoS data header
+ *  8 bytes - SNAP
+ *  4 bytes - CRC
+ * 24 bytes - security related (if connection is secure)
+ */
+#define WIL_MAX_MPDU_OVERHEAD	(62)
 /* Max supported by wil6210 value for interrupt threshold is 5sec. */
 #define WIL6210_ITR_TRSH_MAX (5000000)
 #define WIL6210_ITR_TRSH_DEFAULT	(300) /* usec */
@@ -303,6 +312,8 @@ struct vring {
 struct vring_tx_data {
 	int enabled;
 	cycles_t idle, last_idle, begin;
+	u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
+	u16 agg_timeout;
 };
 
 enum { /* for wil6210_priv.status */
@@ -397,6 +408,16 @@ enum {
 	fw_recovery_running = 2,
 };
 
+struct wil_back_rx {
+	struct list_head list;
+	/* request params, converted to CPU byte order - what we asked for */
+	u8 cidxtid;
+	u8 dialog_token;
+	u16 ba_param_set;
+	u16 ba_timeout;
+	u16 ba_seq_ctrl;
+};
+
 struct wil6210_priv {
 	struct pci_dev *pdev;
 	int n_msi;
@@ -429,7 +450,7 @@ struct wil6210_priv {
 	u16 reply_size;
 	struct workqueue_struct *wmi_wq; /* for deferred calls */
 	struct work_struct wmi_event_worker;
-	struct workqueue_struct *wmi_wq_conn; /* for connect worker */
+	struct workqueue_struct *wq_service;
 	struct work_struct connect_worker;
 	struct work_struct disconnect_worker;
 	struct work_struct fw_error_worker;	/* for FW error recovery */
@@ -445,6 +466,10 @@ struct wil6210_priv {
 	spinlock_t wmi_ev_lock;
 	struct napi_struct napi_rx;
 	struct napi_struct napi_tx;
+	/* BACK */
+	struct list_head back_rx_pending;
+	struct mutex back_rx_mutex; /* protect @back_rx_pending */
+	struct work_struct back_rx_worker;
 	/* DMA related */
 	struct vring vring_rx;
 	struct vring vring_tx[WIL6210_MAX_TX_RINGS];
@@ -567,6 +592,15 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
 int wmi_rxon(struct wil6210_priv *wil, bool on);
 int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
 int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
+int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
+int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason);
+int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+		      u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
+			 u8 dialog_token, __le16 ba_param_set,
+			 __le16 ba_timeout, __le16 ba_seq_ctrl);
+void wil_back_rx_worker(struct work_struct *work);
+void wil_back_rx_flush(struct wil6210_priv *wil);
 
 void wil6210_clear_irq(struct wil6210_priv *wil);
 int wil6210_init_irq(struct wil6210_priv *wil, int irq);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 63476c8..e790c45 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -471,7 +471,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
 	wil->sta[evt->cid].status = wil_sta_conn_pending;
 
 	wil->pending_connect_cid = evt->cid;
-	queue_work(wil->wmi_wq_conn, &wil->connect_worker);
+	queue_work(wil->wq_service, &wil->connect_worker);
 }
 
 static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
@@ -583,10 +583,7 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
 			      int len)
 {
 	struct wmi_vring_ba_status_event *evt = d;
-	struct wil_sta_info *sta;
-	uint i, cid;
-
-	/* TODO: use Rx BA status, not Tx one */
+	struct vring_tx_data *txdata;
 
 	wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
 		    evt->ringid,
@@ -598,40 +595,71 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
 		return;
 	}
 
-	mutex_lock(&wil->mutex);
-
-	cid = wil->vring2cid_tid[evt->ringid][0];
-	if (cid >= WIL6210_MAX_CID) {
-		wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
-		goto out;
+	if (evt->status != WMI_BA_AGREED) {
+		evt->ba_timeout = 0;
+		evt->agg_wsize = 0;
 	}
 
-	sta = &wil->sta[cid];
-	if (sta->status == wil_sta_unused) {
-		wil_err(wil, "CID %d unused\n", cid);
-		goto out;
-	}
-
-	wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
-	for (i = 0; i < WIL_STA_TID_NUM; i++) {
-		struct wil_tid_ampdu_rx *r;
-		unsigned long flags;
+	txdata = &wil->vring_tx_data[evt->ringid];
 
-		spin_lock_irqsave(&sta->tid_rx_lock, flags);
+	txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
+	txdata->agg_wsize = evt->agg_wsize;
+}
 
-		r = sta->tid_rx[i];
-		sta->tid_rx[i] = NULL;
-		wil_tid_ampdu_rx_free(wil, r);
+static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
+				 int len)
+{
+	struct wmi_rcp_addba_req_event *evt = d;
 
-		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+	wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
+			     evt->ba_param_set, evt->ba_timeout,
+			     evt->ba_seq_ctrl);
+}
 
-		if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
-			sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
-						evt->agg_wsize, 0);
+static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
+{
+	struct wmi_delba_event *evt = d;
+	u8 cid, tid;
+	u16 reason = __le16_to_cpu(evt->reason);
+	struct wil_sta_info *sta;
+	struct wil_tid_ampdu_rx *r;
+	unsigned long flags;
+
+	parse_cidxtid(evt->cidxtid, &cid, &tid);
+	wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
+		    cid, tid,
+		    evt->from_initiator ? "originator" : "recipient",
+		    reason);
+	if (!evt->from_initiator) {
+		int i;
+		/* find Tx vring it belongs to */
+		for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
+			if ((wil->vring2cid_tid[i][0] == cid) &&
+			    (wil->vring2cid_tid[i][1] == tid)) {
+				struct vring_tx_data *txdata =
+					&wil->vring_tx_data[i];
+
+				wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
+				txdata->agg_timeout = 0;
+				txdata->agg_wsize = 0;
+
+				break; /* max. 1 matching ring */
+			}
+		}
+		if (i >= ARRAY_SIZE(wil->vring2cid_tid))
+			wil_err(wil, "DELBA: unable to find Tx vring\n");
+		return;
 	}
 
-out:
-	mutex_unlock(&wil->mutex);
+	sta = &wil->sta[cid];
+
+	spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+	r = sta->tid_rx[tid];
+	sta->tid_rx[tid] = NULL;
+	wil_tid_ampdu_rx_free(wil, r);
+
+	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
 }
 
 static const struct {
@@ -649,6 +677,8 @@ static const struct {
 	{WMI_DATA_PORT_OPEN_EVENTID,	wmi_evt_linkup},
 	{WMI_WBE_LINKDOWN_EVENTID,	wmi_evt_linkdown},
 	{WMI_BA_STATUS_EVENTID,		wmi_evt_ba_status},
+	{WMI_RCP_ADDBA_REQ_EVENTID,	wmi_evt_addba_rx_req},
+	{WMI_DELBA_EVENTID,		wmi_evt_delba},
 };
 
 /*
@@ -1111,6 +1141,73 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
 	return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd));
 }
 
+int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
+{
+	struct wmi_vring_ba_en_cmd cmd = {
+		.ringid = ringid,
+		.agg_max_wsize = size,
+		.ba_timeout = cpu_to_le16(timeout),
+	};
+
+	wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__,
+		    ringid, size, timeout);
+
+	return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason)
+{
+	struct wmi_vring_ba_dis_cmd cmd = {
+		.ringid = ringid,
+		.reason = cpu_to_le16(reason),
+	};
+
+	wil_dbg_wmi(wil, "%s(ring %d reason %d)\n", __func__,
+		    ringid, reason);
+
+	return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+		      u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
+{
+	int rc;
+	struct wmi_rcp_addba_resp_cmd cmd = {
+		.cidxtid = mk_cidxtid(cid, tid),
+		.dialog_token = token,
+		.status_code = cpu_to_le16(status),
+		/* bit 0: A-MSDU supported
+		 * bit 1: policy (should be 0 for us)
+		 * bits 2..5: TID
+		 * bits 6..15: buffer size
+		 */
+		.ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
+					    (agg_wsize << 6)),
+		.ba_timeout = cpu_to_le16(timeout),
+	};
+	struct {
+		struct wil6210_mbox_hdr_wmi wmi;
+		struct wmi_rcp_addba_resp_sent_event evt;
+	} __packed reply;
+
+	wil_dbg_wmi(wil,
+		    "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
+		    cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
+
+	rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
+		      WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100);
+	if (rc)
+		return rc;
+
+	if (reply.evt.status) {
+		wil_err(wil, "ADDBA response failed with status %d\n",
+			le16_to_cpu(reply.evt.status));
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
 void wmi_event_flush(struct wil6210_priv *wil)
 {
 	struct pending_wmi_event *evt, *t;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 02/22] wil6210: simple ADDBA on originator (Tx) side
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 01/22] wil6210: ADDBA/DELBA flows Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 03/22] wil6210: allow to configure ADDBA request Vladimir Kondratiev
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Upon Tx vring creation, initiate BACK establishment
with maximum possible window size.

When establishing secure connection, there is EAPOL data exchange
between connection itself and "data port open", where security
is done and non-EAPOL data may be transferred. It is better to
send EAPOL frames using normal ACK because of firmware considerations.

send ADDBA only is 2 conditions met:
- data port open for the corresponded STA
- vring created

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/main.c       |  5 ++
 drivers/net/wireless/ath/wil6210/rx_reorder.c | 91 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/wil6210/txrx.c       |  4 ++
 drivers/net/wireless/ath/wil6210/wil6210.h    | 15 +++++
 drivers/net/wireless/ath/wil6210/wmi.c        | 19 ++++++
 5 files changed, 134 insertions(+)

diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 9b402b9..42e1192 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -385,6 +385,7 @@ int wil_priv_init(struct wil6210_priv *wil)
 	mutex_init(&wil->mutex);
 	mutex_init(&wil->wmi_mutex);
 	mutex_init(&wil->back_rx_mutex);
+	mutex_init(&wil->back_tx_mutex);
 
 	init_completion(&wil->wmi_ready);
 	init_completion(&wil->wmi_call);
@@ -398,9 +399,11 @@ int wil_priv_init(struct wil6210_priv *wil)
 	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
 	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_LIST_HEAD(&wil->pending_wmi_ev);
 	INIT_LIST_HEAD(&wil->back_rx_pending);
+	INIT_LIST_HEAD(&wil->back_tx_pending);
 	spin_lock_init(&wil->wmi_ev_lock);
 	init_waitqueue_head(&wil->wq);
 
@@ -456,6 +459,8 @@ void wil_priv_deinit(struct wil6210_priv *wil)
 	wmi_event_flush(wil);
 	wil_back_rx_flush(wil);
 	cancel_work_sync(&wil->back_rx_worker);
+	wil_back_tx_flush(wil);
+	cancel_work_sync(&wil->back_tx_worker);
 	destroy_workqueue(wil->wq_service);
 	destroy_workqueue(wil->wmi_wq);
 }
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 8e6d25a..ce1206a 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -365,3 +365,94 @@ void wil_back_rx_worker(struct work_struct *work)
 		kfree(evt);
 	}
 }
+
+/* BACK - Tx (originator) side */
+static void wil_back_tx_handle(struct wil6210_priv *wil,
+			       struct wil_back_tx *req)
+{
+	struct vring_tx_data *txdata = &wil->vring_tx_data[req->ringid];
+	int rc;
+
+	if (txdata->addba_in_progress) {
+		wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n",
+			     req->ringid);
+		return;
+	}
+	if (txdata->agg_wsize) {
+		wil_dbg_misc(wil,
+			     "ADDBA for vring[%d] already established wsize %d\n",
+			     req->ringid, txdata->agg_wsize);
+		return;
+	}
+	txdata->addba_in_progress = true;
+	rc = wmi_addba(wil, req->ringid, req->agg_wsize, req->agg_timeout);
+	if (rc)
+		txdata->addba_in_progress = false;
+}
+
+static struct list_head *next_back_tx(struct wil6210_priv *wil)
+{
+	struct list_head *ret = NULL;
+
+	mutex_lock(&wil->back_tx_mutex);
+
+	if (!list_empty(&wil->back_tx_pending)) {
+		ret = wil->back_tx_pending.next;
+		list_del(ret);
+	}
+
+	mutex_unlock(&wil->back_tx_mutex);
+
+	return ret;
+}
+
+void wil_back_tx_worker(struct work_struct *work)
+{
+	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+						 back_tx_worker);
+	struct wil_back_tx *evt;
+	struct list_head *lh;
+
+	while ((lh = next_back_tx(wil)) != NULL) {
+		evt = list_entry(lh, struct wil_back_tx, list);
+
+		wil_back_tx_handle(wil, evt);
+		kfree(evt);
+	}
+}
+
+void wil_back_tx_flush(struct wil6210_priv *wil)
+{
+	struct wil_back_tx *evt, *t;
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	mutex_lock(&wil->back_tx_mutex);
+
+	list_for_each_entry_safe(evt, t, &wil->back_tx_pending, list) {
+		list_del(&evt->list);
+		kfree(evt);
+	}
+
+	mutex_unlock(&wil->back_tx_mutex);
+}
+
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid)
+{
+	struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL);
+
+	if (!req)
+		return -ENOMEM;
+
+	req->ringid = ringid;
+	req->agg_wsize = wil_agg_size(wil, 0);
+	req->agg_timeout = 0;
+
+	mutex_lock(&wil->back_tx_mutex);
+	list_add_tail(&req->list, &wil->back_tx_pending);
+	mutex_unlock(&wil->back_tx_mutex);
+
+	queue_work(wil->wq_service, &wil->back_tx_worker);
+
+	return 0;
+}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index d926860..71eaeec 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -701,6 +701,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
 	vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
 
 	txdata->enabled = 1;
+	if (wil->sta[cid].data_port_open)
+		wil_addba_tx_request(wil, id);
 
 	return 0;
  out_free:
@@ -713,6 +715,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
 void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
 {
 	struct vring *vring = &wil->vring_tx[id];
+	struct vring_tx_data *txdata = &wil->vring_tx_data[id];
 
 	WARN_ON(!mutex_is_locked(&wil->mutex));
 
@@ -727,6 +730,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
 		napi_synchronize(&wil->napi_tx);
 
 	wil_vring_free(wil, vring, 1);
+	memset(txdata, 0, sizeof(*txdata));
 }
 
 static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 4a9a68e..9cd76da 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -314,6 +314,7 @@ struct vring_tx_data {
 	cycles_t idle, last_idle, begin;
 	u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
 	u16 agg_timeout;
+	bool addba_in_progress; /* if set, agg_xxx is for request in progress */
 };
 
 enum { /* for wil6210_priv.status */
@@ -418,6 +419,14 @@ struct wil_back_rx {
 	u16 ba_seq_ctrl;
 };
 
+struct wil_back_tx {
+	struct list_head list;
+	/* request params, converted to CPU byte order - what we asked for */
+	u8 ringid;
+	u8 agg_wsize;
+	u16 agg_timeout;
+};
+
 struct wil6210_priv {
 	struct pci_dev *pdev;
 	int n_msi;
@@ -470,6 +479,9 @@ struct wil6210_priv {
 	struct list_head back_rx_pending;
 	struct mutex back_rx_mutex; /* protect @back_rx_pending */
 	struct work_struct back_rx_worker;
+	struct list_head back_tx_pending;
+	struct mutex back_tx_mutex; /* protect @back_tx_pending */
+	struct work_struct back_tx_worker;
 	/* DMA related */
 	struct vring vring_rx;
 	struct vring vring_tx[WIL6210_MAX_TX_RINGS];
@@ -601,6 +613,9 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
 			 __le16 ba_timeout, __le16 ba_seq_ctrl);
 void wil_back_rx_worker(struct work_struct *work);
 void wil_back_rx_flush(struct wil6210_priv *wil);
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid);
+void wil_back_tx_worker(struct work_struct *work);
+void wil_back_tx_flush(struct wil6210_priv *wil);
 
 void wil6210_clear_irq(struct wil6210_priv *wil);
 int wil6210_init_irq(struct wil6210_priv *wil, int irq);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index e790c45..8a4f8b7 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -544,6 +544,22 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
 	}
 }
 
+static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid)
+{
+	struct vring_tx_data *t;
+	int i;
+
+	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+		if (cid != wil->vring2cid_tid[i][0])
+			continue;
+		t = &wil->vring_tx_data[i];
+		if (!t->enabled)
+			continue;
+
+		wil_addba_tx_request(wil, i);
+	}
+}
+
 static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
@@ -558,6 +574,7 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
 	}
 
 	wil->sta[cid].data_port_open = true;
+	wil_addba_tx_cid(wil, cid);
 	netif_carrier_on(ndev);
 }
 
@@ -604,6 +621,7 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
 
 	txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
 	txdata->agg_wsize = evt->agg_wsize;
+	txdata->addba_in_progress = false;
 }
 
 static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
@@ -642,6 +660,7 @@ static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
 				wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
 				txdata->agg_timeout = 0;
 				txdata->agg_wsize = 0;
+				txdata->addba_in_progress = false;
 
 				break; /* max. 1 matching ring */
 			}
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 03/22] wil6210: allow to configure ADDBA request
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 01/22] wil6210: ADDBA/DELBA flows Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 02/22] wil6210: simple ADDBA on originator (Tx) side Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 04/22] wil6210: improve debugfs for reorder buffer Vladimir Kondratiev
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

For manual ADDBA configuration, allow to set desired window size or
disable automatic mechanism.

Introduce module parameter (int) agg_wsize. It can be changed on run time,
will be taken into account on the next connect. Interpretation:
- <0 - disable automatic ADDBA; intended for manual testing through debugfs
- 0 - use automatically calculated window size
- >0 - use this for window size. Clipped by maximum supported by the hardware
with current environment.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/rx_reorder.c |  4 ++--
 drivers/net/wireless/ath/wil6210/txrx.c       |  4 ++--
 drivers/net/wireless/ath/wil6210/wil6210.h    |  3 ++-
 drivers/net/wireless/ath/wil6210/wmi.c        | 12 +++++++++---
 4 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index ce1206a..0865c34 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -437,7 +437,7 @@ void wil_back_tx_flush(struct wil6210_priv *wil)
 	mutex_unlock(&wil->back_tx_mutex);
 }
 
-int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid)
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
 {
 	struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL);
 
@@ -445,7 +445,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid)
 		return -ENOMEM;
 
 	req->ringid = ringid;
-	req->agg_wsize = wil_agg_size(wil, 0);
+	req->agg_wsize = wil_agg_size(wil, wsize);
 	req->agg_timeout = 0;
 
 	mutex_lock(&wil->back_tx_mutex);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 71eaeec..b7ffcfb 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -701,8 +701,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
 	vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
 
 	txdata->enabled = 1;
-	if (wil->sta[cid].data_port_open)
-		wil_addba_tx_request(wil, id);
+	if (wil->sta[cid].data_port_open && (agg_wsize >= 0))
+		wil_addba_tx_request(wil, id, agg_wsize);
 
 	return 0;
  out_free:
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 9cd76da..a94d67d 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -25,6 +25,7 @@
 
 extern bool no_fw_recovery;
 extern unsigned int mtu_max;
+extern int agg_wsize;
 
 #define WIL_NAME "wil6210"
 #define WIL_FW_NAME "wil6210.fw"
@@ -613,7 +614,7 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
 			 __le16 ba_timeout, __le16 ba_seq_ctrl);
 void wil_back_rx_worker(struct work_struct *work);
 void wil_back_rx_flush(struct wil6210_priv *wil);
-int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid);
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
 void wil_back_tx_worker(struct work_struct *work);
 void wil_back_tx_flush(struct wil6210_priv *wil);
 
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 8a4f8b7..2538161 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -27,6 +27,11 @@ static uint max_assoc_sta = 1;
 module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
 
+int agg_wsize; /* = 0; */
+module_param(agg_wsize, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
+		 " 0 - use default; < 0 - don't auto-establish");
+
 /**
  * WMI event receiving - theory of operations
  *
@@ -544,7 +549,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
 	}
 }
 
-static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid)
+static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize)
 {
 	struct vring_tx_data *t;
 	int i;
@@ -556,7 +561,7 @@ static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid)
 		if (!t->enabled)
 			continue;
 
-		wil_addba_tx_request(wil, i);
+		wil_addba_tx_request(wil, i, wsize);
 	}
 }
 
@@ -574,7 +579,8 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
 	}
 
 	wil->sta[cid].data_port_open = true;
-	wil_addba_tx_cid(wil, cid);
+	if (agg_wsize >= 0)
+		wil_addba_tx_cid(wil, cid, agg_wsize);
 	netif_carrier_on(ndev);
 }
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 04/22] wil6210: improve debugfs for reorder buffer
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (2 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 03/22] wil6210: allow to configure ADDBA request Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 05/22] wil6210: fix disconnect 1 STA in AP Vladimir Kondratiev
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

When printing debugfs for the reorder buffer, include BACK
parameters: window size and timeout

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 18f5b67..5117a02 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1162,7 +1162,8 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
 	int i;
 	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
 
-	seq_printf(s, "0x%03x [", r->head_seq_num);
+	seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
+		   r->head_seq_num);
 	for (i = 0; i < r->buf_size; i++) {
 		if (i == index)
 			seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 05/22] wil6210: fix disconnect 1 STA in AP
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (3 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 04/22] wil6210: improve debugfs for reorder buffer Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 06/22] wil6210: improve debugfs for VRING Vladimir Kondratiev
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

When disconnecting single STA in AP, it might be that STA
in question is already disconnected. In this case, need to do nothing.
Previously, it was mis-interpreted as "disconnect all"

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/main.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 42e1192..18a2eb5 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -188,18 +188,29 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
 	struct wireless_dev *wdev = wil->wdev;
 
 	might_sleep();
-	if (bssid) {
+	wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
+		     reason_code, from_event ? "+" : "-");
+
+	/* Cases are:
+	 * - disconnect single STA, still connected
+	 * - disconnect single STA, already disconnected
+	 * - disconnect all
+	 *
+	 * For "disconnect all", there are 2 options:
+	 * - bssid == NULL
+	 * - bssid is our MAC address
+	 */
+	if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) {
 		cid = wil_find_cid(wil, bssid);
-		wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
-	} else {
-		wil_dbg_misc(wil, "%s(all)\n", __func__);
-	}
-
-	if (cid >= 0) /* disconnect 1 peer */
-		wil_disconnect_cid(wil, cid, reason_code, from_event);
-	else /* disconnect all */
+		wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
+			     bssid, cid, reason_code);
+		if (cid >= 0) /* disconnect 1 peer */
+			wil_disconnect_cid(wil, cid, reason_code, from_event);
+	} else { /* all */
+		wil_dbg_misc(wil, "Disconnect all\n");
 		for (cid = 0; cid < WIL6210_MAX_CID; cid++)
 			wil_disconnect_cid(wil, cid, reason_code, from_event);
+	}
 
 	/* link state */
 	switch (wdev->iftype) {
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 06/22] wil6210: improve debugfs for VRING
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (4 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 05/22] wil6210: fix disconnect 1 STA in AP Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 07/22] wil6210: control AMSDU on Tx side of Block Ack Vladimir Kondratiev
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

When printing VRING on debugfs (file "vrings"),
software head & tail indexes were printed in decimal format
while hardware tail in hexadecimal only.

It is not comfortable to compare indexes in different formats;
on the other hand, hexadecimal output useful to see hardware
glitches.

To serve all purposes, print hardware tail in both decimal and
hexadecimal formats.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 5117a02..fedfa64 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -50,6 +50,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
 			    char _s, char _h)
 {
 	void __iomem *x = wmi_addr(wil, vring->hwtail);
+	u32 v;
 
 	seq_printf(s, "VRING %s = {\n", name);
 	seq_printf(s, "  pa     = %pad\n", &vring->pa);
@@ -58,10 +59,12 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
 	seq_printf(s, "  swtail = %d\n", vring->swtail);
 	seq_printf(s, "  swhead = %d\n", vring->swhead);
 	seq_printf(s, "  hwtail = [0x%08x] -> ", vring->hwtail);
-	if (x)
-		seq_printf(s, "0x%08x\n", ioread32(x));
-	else
+	if (x) {
+		v = ioread32(x);
+		seq_printf(s, "0x%08x = %d\n", v, v);
+	} else {
 		seq_puts(s, "???\n");
+	}
 
 	if (vring->va && (vring->size < 1025)) {
 		uint i;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 07/22] wil6210: control AMSDU on Tx side of Block Ack
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (5 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 06/22] wil6210: improve debugfs for VRING Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 08/22] wil6210: delba for responder Vladimir Kondratiev
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

When establishing Block Ack as originator (Tx), control
AMSDU flag when sending ADDBA and update status upon
establishment flow completion. To be used in AMSDU flows

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c |  3 ++-
 drivers/net/wireless/ath/wil6210/wil6210.h |  1 +
 drivers/net/wireless/ath/wil6210/wmi.c     |  8 ++++++--
 drivers/net/wireless/ath/wil6210/wmi.h     | 12 +++++++++++-
 4 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index fedfa64..c57cc2d 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -114,9 +114,10 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
 			snprintf(name, sizeof(name), "tx_%2d", i);
 
 			seq_printf(s,
-				   "\n%pM CID %d TID %d BACK([%d] %d TU) [%3d|%3d] idle %3d%%\n",
+				   "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n",
 				   wil->sta[cid].addr, cid, tid,
 				   txdata->agg_wsize, txdata->agg_timeout,
+				   txdata->agg_amsdu ? "+" : "-",
 				   used, avail, (int)idle);
 
 			wil_print_vring(s, wil, name, vring, '_', 'H');
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index a94d67d..747052d 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -315,6 +315,7 @@ struct vring_tx_data {
 	cycles_t idle, last_idle, begin;
 	u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
 	u16 agg_timeout;
+	u8 agg_amsdu;
 	bool addba_in_progress; /* if set, agg_xxx is for request in progress */
 };
 
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 2538161..00cba4a 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -608,10 +608,11 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
 	struct wmi_vring_ba_status_event *evt = d;
 	struct vring_tx_data *txdata;
 
-	wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
+	wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
 		    evt->ringid,
 		    evt->status == WMI_BA_AGREED ? "OK" : "N/A",
-		    evt->agg_wsize, __le16_to_cpu(evt->ba_timeout));
+		    evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
+		    evt->amsdu ? "+" : "-");
 
 	if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
 		wil_err(wil, "invalid ring id %d\n", evt->ringid);
@@ -621,12 +622,14 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
 	if (evt->status != WMI_BA_AGREED) {
 		evt->ba_timeout = 0;
 		evt->agg_wsize = 0;
+		evt->amsdu = 0;
 	}
 
 	txdata = &wil->vring_tx_data[evt->ringid];
 
 	txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
 	txdata->agg_wsize = evt->agg_wsize;
+	txdata->agg_amsdu = evt->amsdu;
 	txdata->addba_in_progress = false;
 }
 
@@ -1172,6 +1175,7 @@ int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
 		.ringid = ringid,
 		.agg_max_wsize = size,
 		.ba_timeout = cpu_to_le16(timeout),
+		.amsdu = 0,
 	};
 
 	wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__,
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 27b9743..b5102f0 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -586,6 +586,7 @@ struct wmi_vring_ba_en_cmd {
 	u8 ringid;
 	u8 agg_max_wsize;
 	__le16 ba_timeout;
+	u8 amsdu;
 } __packed;
 
 /*
@@ -1052,14 +1053,23 @@ struct wmi_scan_complete_event {
 enum wmi_vring_ba_status {
 	WMI_BA_AGREED			= 0,
 	WMI_BA_NON_AGREED		= 1,
+	/* BA_EN in middle of teardown flow */
+	WMI_BA_TD_WIP			= 2,
+	/* BA_DIS or BA_EN in middle of BA SETUP flow */
+	WMI_BA_SETUP_WIP		= 3,
+	/* BA_EN when the BA session is already active */
+	WMI_BA_SESSION_ACTIVE		= 4,
+	/* BA_DIS when the BA session is not active */
+	WMI_BA_SESSION_NOT_ACTIVE	= 5,
 };
 
 struct wmi_vring_ba_status_event {
-	__le16 status;
+	__le16 status; /* enum wmi_vring_ba_status */
 	u8 reserved[2];
 	u8 ringid;
 	u8 agg_wsize;
 	__le16 ba_timeout;
+	u8 amsdu;
 } __packed;
 
 /*
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 08/22] wil6210: delba for responder
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (6 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 07/22] wil6210: control AMSDU on Tx side of Block Ack Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 09/22] wil6210: fix max. MPDU size Vladimir Kondratiev
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Implement delba flow for the responder (Rx) side

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c |  2 +-
 drivers/net/wireless/ath/wil6210/wil6210.h |  3 ++-
 drivers/net/wireless/ath/wil6210/wmi.c     | 15 ++++++++++++++-
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index c57cc2d..316c7c1 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -598,7 +598,7 @@ static ssize_t wil_write_addba(struct file *file, const char __user *buf,
 	if (agg_wsize > 0)
 		wmi_addba(wil, 0, agg_wsize, 0);
 	else
-		wmi_delba(wil, 0, 0);
+		wmi_delba_tx(wil, 0, 0);
 
 	return len;
 }
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 747052d..1b4efd2 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -607,7 +607,8 @@ int wmi_rxon(struct wil6210_priv *wil, bool on);
 int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
 int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
 int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
-int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason);
+int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
+int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
 int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
 		      u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
 int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 00cba4a..af2ca46 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1184,7 +1184,7 @@ int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
 	return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
 }
 
-int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason)
+int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
 {
 	struct wmi_vring_ba_dis_cmd cmd = {
 		.ringid = ringid,
@@ -1197,6 +1197,19 @@ int wmi_delba(struct wil6210_priv *wil, u8 ringid, u16 reason)
 	return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
 }
 
+int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
+{
+	struct wmi_rcp_delba_cmd cmd = {
+		.cidxtid = cidxtid,
+		.reason = cpu_to_le16(reason),
+	};
+
+	wil_dbg_wmi(wil, "%s(CID %d TID %d reason %d)\n", __func__,
+		    cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason);
+
+	return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
+}
+
 int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
 		      u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
 {
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 09/22] wil6210: fix max. MPDU size
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (7 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 08/22] wil6210: delba for responder Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 10/22] wil6210: consider SNAP header in MTU calculations Vladimir Kondratiev
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

When configuring Tx/Rx VRING's, driver need to specify max. MPDU size
It should take into account all overhead introduced by 802.3->208.11
transformation.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/main.c    |  2 +-
 drivers/net/wireless/ath/wil6210/txrx.c    |  2 +-
 drivers/net/wireless/ath/wil6210/txrx.h    |  4 ++--
 drivers/net/wireless/ath/wil6210/wil6210.h | 12 +++++++++++-
 drivers/net/wireless/ath/wil6210/wmi.c     |  2 +-
 5 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 18a2eb5..0af51fc 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
 /* We allow allocation of more than 1 page buffers to support large packets.
  * It is suboptimal behavior performance wise in case MTU above page size.
  */
-unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN;
+unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
 static int mtu_max_set(const char *val, const struct kernel_param *kp)
 {
 	int ret;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index b7ffcfb..f33ea57 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -645,7 +645,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
 		.vring_cfg = {
 			.tx_sw_ring = {
 				.max_mpdu_size =
-					cpu_to_le16(mtu_max + ETH_HLEN),
+					cpu_to_le16(wil_mtu2macbuf(mtu_max)),
 				.ring_size = cpu_to_le16(size),
 			},
 			.ringid = id,
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index 630aeb5..e7db356 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -20,8 +20,8 @@
 #define BUF_SW_OWNED    (1)
 #define BUF_HW_OWNED    (0)
 
-/* size of max. Tx/Rx buffers, as supported by FW */
-#define TXRX_BUF_LEN_DEFAULT (2242)
+/* default size of MAC Tx/Rx buffers */
+#define TXRX_BUF_LEN_DEFAULT (2048)
 
 /* how many bytes to reserve for rtap header? */
 #define WIL6210_RTAP_SIZE (128)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 1b4efd2..bedb9ed 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -62,11 +62,21 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
 #define WIL_MAX_AGG_WSIZE	(32) /* FW/HW limit */
 /* Hardware offload block adds the following:
  * 26 bytes - 3-address QoS data header
+ *  8 bytes - IV + EIV (for GCMP)
  *  8 bytes - SNAP
+ * 16 bytes - MIC (for GCMP)
  *  4 bytes - CRC
- * 24 bytes - security related (if connection is secure)
  */
 #define WIL_MAX_MPDU_OVERHEAD	(62)
+
+/* Calculate MAC buffer size for the firmware. It includes all overhead,
+ * as it will go over the air, and need to be 8 byte aligned
+ */
+static inline u32 wil_mtu2macbuf(u32 mtu)
+{
+	return ALIGN(mtu + WIL_MAX_MPDU_OVERHEAD, 8);
+}
+
 /* Max supported by wil6210 value for interrupt threshold is 5sec. */
 #define WIL6210_ITR_TRSH_MAX (5000000)
 #define WIL6210_ITR_TRSH_DEFAULT	(300) /* usec */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index af2ca46..70b055c 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1083,7 +1083,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
 	struct wmi_cfg_rx_chain_cmd cmd = {
 		.action = WMI_RX_CHAIN_ADD,
 		.rx_sw_ring = {
-			.max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN),
+			.max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
 			.ring_mem_base = cpu_to_le64(vring->pa),
 			.ring_size = cpu_to_le16(vring->size),
 		},
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 10/22] wil6210: consider SNAP header in MTU calculations
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (8 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 09/22] wil6210: fix max. MPDU size Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 11/22] wil6210: Increase number of associated stations Vladimir Kondratiev
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

When encapsulating 802.3 frames into the 802.11 ones,
8-byte SNAP header added to save ethtype. SNAP is part of
the frame body, thus should be counted in MSDU. So,
MTU = MSDU - SNAP

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/main.c    | 2 +-
 drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 0af51fc..71ebbc1 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -53,7 +53,7 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp)
 	if (ret)
 		return ret;
 
-	if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG)
+	if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
 		ret = -EINVAL;
 
 	return ret;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index bedb9ed..81309dc 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -77,6 +77,10 @@ static inline u32 wil_mtu2macbuf(u32 mtu)
 	return ALIGN(mtu + WIL_MAX_MPDU_OVERHEAD, 8);
 }
 
+/* MTU for Ethernet need to take into account 8-byte SNAP header
+ * to be added when encapsulating Ethernet frame into 802.11
+ */
+#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_TRSH_DEFAULT	(300) /* usec */
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 11/22] wil6210: Increase number of associated stations
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (9 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 10/22] wil6210: consider SNAP header in MTU calculations Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 12/22] wil6210: use bitmap API for "status" Vladimir Kondratiev
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210, Hamad Kadmany

Change default to support maximum number of associated
stations to an AP

Signed-off-by: Hamad Kadmany <qca_hkadmany@qca.qualcomm.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 70b055c..245215a 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -23,7 +23,7 @@
 #include "wmi.h"
 #include "trace.h"
 
-static uint max_assoc_sta = 1;
+static uint max_assoc_sta = WIL6210_MAX_CID;
 module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 12/22] wil6210: use bitmap API for "status"
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (10 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 11/22] wil6210: Increase number of associated stations Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 13/22] wil6210: fix Tx VRING for STA mode Vladimir Kondratiev
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

wil->status used as bitmap; use DECLARE_BITMAP for it.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/cfg80211.c  | 12 ++++++------
 drivers/net/wireless/ath/wil6210/debugfs.c   |  2 +-
 drivers/net/wireless/ath/wil6210/interrupt.c | 16 ++++++++--------
 drivers/net/wireless/ath/wil6210/main.c      | 27 ++++++++++++++-------------
 drivers/net/wireless/ath/wil6210/txrx.c      |  6 +++---
 drivers/net/wireless/ath/wil6210/wil6210.h   |  3 ++-
 drivers/net/wireless/ath/wil6210/wmi.c       | 12 ++++++------
 7 files changed, 40 insertions(+), 38 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 38332a6..5c79f1d 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -162,7 +162,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
 	sinfo->tx_packets = stats->tx_packets;
 	sinfo->tx_failed = stats->tx_errors;
 
-	if (test_bit(wil_status_fwconnected, &wil->status)) {
+	if (test_bit(wil_status_fwconnected, wil->status)) {
 		sinfo->filled |= STATION_INFO_SIGNAL;
 		sinfo->signal = reply.evt.sqi;
 	}
@@ -282,7 +282,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
 	}
 
 	/* FW don't support scan after connection attempt */
-	if (test_bit(wil_status_dontscan, &wil->status)) {
+	if (test_bit(wil_status_dontscan, wil->status)) {
 		wil_err(wil, "Can't scan now\n");
 		return -EBUSY;
 	}
@@ -362,8 +362,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
 	int ch;
 	int rc = 0;
 
-	if (test_bit(wil_status_fwconnecting, &wil->status) ||
-	    test_bit(wil_status_fwconnected, &wil->status))
+	if (test_bit(wil_status_fwconnecting, wil->status) ||
+	    test_bit(wil_status_fwconnected, wil->status))
 		return -EALREADY;
 
 	wil_print_connect_params(wil, sme);
@@ -450,7 +450,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
 	memcpy(conn.bssid, bss->bssid, ETH_ALEN);
 	memcpy(conn.dst_mac, bss->bssid, ETH_ALEN);
 
-	set_bit(wil_status_fwconnecting, &wil->status);
+	set_bit(wil_status_fwconnecting, wil->status);
 
 	rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
 	if (rc == 0) {
@@ -458,7 +458,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
 		mod_timer(&wil->connect_timer,
 			  jiffies + msecs_to_jiffies(2000));
 	} else {
-		clear_bit(wil_status_fwconnecting, &wil->status);
+		clear_bit(wil_status_fwconnecting, wil->status);
 	}
 
  out:
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 316c7c1..338a811 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1313,7 +1313,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
 /* fields in struct wil6210_priv */
 static const struct dbg_off dbg_wil_off[] = {
 	WIL_FIELD(secure_pcp,	S_IRUGO | S_IWUSR,	doff_u32),
-	WIL_FIELD(status,	S_IRUGO | S_IWUSR,	doff_ulong),
+	WIL_FIELD(status[0],	S_IRUGO | S_IWUSR,	doff_ulong),
 	WIL_FIELD(fw_version,	S_IRUGO,		doff_u32),
 	WIL_FIELD(hw_version,	S_IRUGO,		doff_x32),
 	WIL_FIELD(recovery_count, S_IRUGO,		doff_u32),
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 4bcbd62..5a0ea72 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -102,7 +102,7 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
 	iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
 		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
 
-	clear_bit(wil_status_irqen, &wil->status);
+	clear_bit(wil_status_irqen, wil->status);
 }
 
 void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
@@ -130,7 +130,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
 {
 	wil_dbg_irq(wil, "%s()\n", __func__);
 
-	set_bit(wil_status_irqen, &wil->status);
+	set_bit(wil_status_irqen, wil->status);
 
 	iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr +
 		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
@@ -198,8 +198,8 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
 				"of overflow\" interrupt\n");
 
 		isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH);
-		if (test_bit(wil_status_reset_done, &wil->status)) {
-			if (test_bit(wil_status_napi_en, &wil->status)) {
+		if (test_bit(wil_status_reset_done, wil->status)) {
+			if (test_bit(wil_status_napi_en, wil->status)) {
 				wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
 				need_unmask = false;
 				napi_schedule(&wil->napi_rx);
@@ -248,7 +248,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
 		isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
 		/* clear also all VRING interrupts */
 		isr &= ~(BIT(25) - 1UL);
-		if (test_bit(wil_status_reset_done, &wil->status)) {
+		if (test_bit(wil_status_reset_done, wil->status)) {
 			wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
 			need_unmask = false;
 			napi_schedule(&wil->napi_tx);
@@ -310,7 +310,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
 
 	if (isr & ISR_MISC_FW_ERROR) {
 		wil_err(wil, "Firmware error detected\n");
-		clear_bit(wil_status_fwready, &wil->status);
+		clear_bit(wil_status_fwready, wil->status);
 		/*
 		 * do not clear @isr here - we do 2-nd part in thread
 		 * there, user space get notified, and it should be done
@@ -321,7 +321,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
 	if (isr & ISR_MISC_FW_READY) {
 		wil_dbg_irq(wil, "IRQ: FW ready\n");
 		wil_cache_mbox_regs(wil);
-		set_bit(wil_status_reset_done, &wil->status);
+		set_bit(wil_status_reset_done, wil->status);
 		/**
 		 * Actual FW ready indicated by the
 		 * WMI_FW_READY_EVENTID
@@ -394,7 +394,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
  */
 static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
 {
-	if (!test_bit(wil_status_irqen, &wil->status)) {
+	if (!test_bit(wil_status_irqen, wil->status)) {
 		u32 icm_rx = wil_ioread32_and_clear(wil->csr +
 				HOSTADDR(RGF_DMA_EP_RX_ICR) +
 				offsetof(struct RGF_ICR, ICM));
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 71ebbc1..a17278f 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -217,16 +217,16 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_P2P_CLIENT:
 		wil_link_off(wil);
-		if (test_bit(wil_status_fwconnected, &wil->status)) {
-			clear_bit(wil_status_fwconnected, &wil->status);
+		if (test_bit(wil_status_fwconnected, wil->status)) {
+			clear_bit(wil_status_fwconnected, wil->status);
 			cfg80211_disconnected(ndev, reason_code,
 					      NULL, 0, GFP_KERNEL);
-		} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
+		} else if (test_bit(wil_status_fwconnecting, wil->status)) {
 			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
 						WLAN_STATUS_UNSPECIFIED_FAILURE,
 						GFP_KERNEL);
 		}
-		clear_bit(wil_status_fwconnecting, &wil->status);
+		clear_bit(wil_status_fwconnecting, wil->status);
 		break;
 	default:
 		break;
@@ -259,7 +259,7 @@ static void wil_scan_timer_fn(ulong x)
 {
 	struct wil6210_priv *wil = (void *)x;
 
-	clear_bit(wil_status_fwready, &wil->status);
+	clear_bit(wil_status_fwready, wil->status);
 	wil_err(wil, "Scan timeout detected, start fw error recovery\n");
 	wil->recovery_state = fw_recovery_pending;
 	schedule_work(&wil->fw_error_worker);
@@ -654,12 +654,13 @@ int wil_reset(struct wil6210_priv *wil)
 	wil_dbg_misc(wil, "%s()\n", __func__);
 
 	WARN_ON(!mutex_is_locked(&wil->mutex));
-	WARN_ON(test_bit(wil_status_napi_en, &wil->status));
+	WARN_ON(test_bit(wil_status_napi_en, wil->status));
 
 	cancel_work_sync(&wil->disconnect_worker);
 	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
 
-	wil->status = 0; /* prevent NAPI from being scheduled */
+	/* prevent NAPI from being scheduled */
+	bitmap_zero(wil->status, wil_status_last);
 
 	if (wil->scan_request) {
 		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -798,7 +799,7 @@ int __wil_up(struct wil6210_priv *wil)
 	wil_dbg_misc(wil, "NAPI enable\n");
 	napi_enable(&wil->napi_rx);
 	napi_enable(&wil->napi_tx);
-	set_bit(wil_status_napi_en, &wil->status);
+	set_bit(wil_status_napi_en, wil->status);
 
 	if (wil->platform_ops.bus_request)
 		wil->platform_ops.bus_request(wil->platform_handle,
@@ -831,7 +832,7 @@ int __wil_down(struct wil6210_priv *wil)
 		wil->platform_ops.bus_request(wil->platform_handle, 0);
 
 	wil_disable_irq(wil);
-	if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
+	if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
 		napi_disable(&wil->napi_rx);
 		napi_disable(&wil->napi_tx);
 		wil_dbg_misc(wil, "NAPI disable\n");
@@ -846,15 +847,15 @@ int __wil_down(struct wil6210_priv *wil)
 		wil->scan_request = NULL;
 	}
 
-	if (test_bit(wil_status_fwconnected, &wil->status) ||
-	    test_bit(wil_status_fwconnecting, &wil->status))
+	if (test_bit(wil_status_fwconnected, wil->status) ||
+	    test_bit(wil_status_fwconnecting, wil->status))
 		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
 
 	/* make sure wil is idle (not connected) */
 	mutex_unlock(&wil->mutex);
 	while (iter--) {
-		int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
-			   !test_bit(wil_status_fwconnecting, &wil->status);
+		int idle = !test_bit(wil_status_fwconnected, wil->status) &&
+			   !test_bit(wil_status_fwconnecting, wil->status);
 		if (idle)
 			break;
 		msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index f33ea57..33961ca 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -726,7 +726,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
 
 	/* make sure NAPI won't touch this vring */
 	wil->vring_tx_data[id].enabled = 0;
-	if (test_bit(wil_status_napi_en, &wil->status))
+	if (test_bit(wil_status_napi_en, wil->status))
 		napi_synchronize(&wil->napi_tx);
 
 	wil_vring_free(wil, vring, 1);
@@ -1038,14 +1038,14 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	int rc;
 
 	wil_dbg_txrx(wil, "%s()\n", __func__);
-	if (!test_bit(wil_status_fwready, &wil->status)) {
+	if (!test_bit(wil_status_fwready, wil->status)) {
 		if (!pr_once_fw) {
 			wil_err(wil, "FW not ready\n");
 			pr_once_fw = true;
 		}
 		goto drop;
 	}
-	if (!test_bit(wil_status_fwconnected, &wil->status)) {
+	if (!test_bit(wil_status_fwconnected, wil->status)) {
 		wil_err(wil, "FW not connected\n");
 		goto drop;
 	}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 81309dc..64a6d49 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -341,6 +341,7 @@ enum { /* for wil6210_priv.status */
 	wil_status_reset_done,
 	wil_status_irqen, /* FIXME: interrupts enabled - for debug */
 	wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
+	wil_status_last /* keep last */
 };
 
 struct pci_dev;
@@ -448,7 +449,7 @@ struct wil6210_priv {
 	int n_msi;
 	struct wireless_dev *wdev;
 	void __iomem *csr;
-	ulong status;
+	DECLARE_BITMAP(status, wil_status_last);
 	u32 fw_version;
 	u32 hw_version;
 	struct wil_board *board;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 245215a..a4b30a4 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -202,7 +202,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
 
 	might_sleep();
 
-	if (!test_bit(wil_status_fwready, &wil->status)) {
+	if (!test_bit(wil_status_fwready, wil->status)) {
 		wil_err(wil, "WMI: cannot send command while FW not ready\n");
 		return -EAGAIN;
 	}
@@ -305,7 +305,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
 	wil_dbg_wmi(wil, "WMI: got FW ready event\n");
 
 	wil_set_recovery_state(wil, fw_recovery_idle);
-	set_bit(wil_status_fwready, &wil->status);
+	set_bit(wil_status_fwready, wil->status);
 	/* let the reset sequence continue */
 	complete(&wil->wmi_ready);
 }
@@ -443,7 +443,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
 
 	if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
 	    (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
-		if (!test_bit(wil_status_fwconnecting, &wil->status)) {
+		if (!test_bit(wil_status_fwconnecting, wil->status)) {
 			wil_err(wil, "Not in connecting state\n");
 			return;
 		}
@@ -467,8 +467,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
 
 		cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
 	}
-	clear_bit(wil_status_fwconnecting, &wil->status);
-	set_bit(wil_status_fwconnected, &wil->status);
+	clear_bit(wil_status_fwconnecting, wil->status);
+	set_bit(wil_status_fwconnected, wil->status);
 
 	/* FIXME FW can transmit only ucast frames to peer */
 	/* FIXME real ring_id instead of hard coded 0 */
@@ -726,7 +726,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
 	ulong flags;
 	unsigned n;
 
-	if (!test_bit(wil_status_reset_done, &wil->status)) {
+	if (!test_bit(wil_status_reset_done, wil->status)) {
 		wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
 		return;
 	}
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 13/22] wil6210: fix Tx VRING for STA mode
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (11 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 12/22] wil6210: use bitmap API for "status" Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 14/22] wil6210: rework debugfs for BACK Vladimir Kondratiev
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

In STA mode, all Tx should be directed to the same VRING towards the AP.
Thus, look up for the 1-st eligible VRING and use it.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/txrx.c | 46 +++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 33961ca..4c145ee 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -777,6 +777,38 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
 
 static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 			struct sk_buff *skb);
+
+static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
+					   struct sk_buff *skb)
+{
+	struct vring *v;
+	int i;
+	u8 cid;
+
+	/* In the STA mode, it is expected to have only 1 VRING
+	 * for the AP we connected to.
+	 * find 1-st vring and see whether it is eligible for data
+	 */
+	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+		v = &wil->vring_tx[i];
+		if (!v->va)
+			continue;
+
+		cid = wil->vring2cid_tid[i][0];
+		if (!wil->sta[cid].data_port_open &&
+		    (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+			break;
+
+		wil_dbg_txrx(wil, "Tx -> ring %d\n", i);
+
+		return v;
+	}
+
+	wil_dbg_txrx(wil, "Tx while no vrings active?\n");
+
+	return NULL;
+}
+
 /*
  * Find 1-st vring and return it; set dest address for this vring in skb
  * duplicate skb and send it to other active vrings
@@ -1056,15 +1088,19 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	pr_once_fw = false;
 
 	/* find vring */
-	if (is_unicast_ether_addr(eth->h_dest))
-		vring = wil_find_tx_vring(wil, skb);
-	else
-		vring = wil_tx_bcast(wil, skb);
+	if (wil->wdev->iftype == NL80211_IFTYPE_STATION) {
+		/* in STA mode (ESS), all to same VRING */
+		vring = wil_find_tx_vring_sta(wil, skb);
+	} else { /* direct communication, find matching VRING */
+		if (is_unicast_ether_addr(eth->h_dest))
+			vring = wil_find_tx_vring(wil, skb);
+		else
+			vring = wil_tx_bcast(wil, skb);
+	}
 	if (!vring) {
 		wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
 		goto drop;
 	}
-
 	/* set up vring entry */
 	rc = wil_tx_vring(wil, vring, skb);
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 14/22] wil6210: rework debugfs for BACK
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (12 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 13/22] wil6210: fix Tx VRING for STA mode Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 15/22] wil6210: detect HW capabilities Vladimir Kondratiev
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Enable more flexible control over block ack:
- allow addba for any Tx vring
- allow to specify block ack timeout
- allow to delba for Tx or Rx side of any agreement; with reason

Renamed "addba" entry to "back"; it prints short help when read;
write:
 - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
If missing, <timeout> defaults to 0
 - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
 - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
If missing, <reason> set to "STA_LEAVING" (36)

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c | 71 +++++++++++++++++++++++-------
 1 file changed, 54 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 338a811..a36a753 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -564,17 +564,19 @@ static const struct file_operations fops_rxon = {
 	.open  = simple_open,
 };
 
-/* block ack for vring 0
- * write 0 to it to trigger DELBA
- * write positive agg_wsize to trigger ADDBA
+/* block ack control, write:
+ * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
+ * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
+ * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
  */
-static ssize_t wil_write_addba(struct file *file, const char __user *buf,
-			       size_t len, loff_t *ppos)
+static ssize_t wil_write_back(struct file *file, const char __user *buf,
+			      size_t len, loff_t *ppos)
 {
 	struct wil6210_priv *wil = file->private_data;
 	int rc;
-	uint agg_wsize;
 	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+	char cmd[8];
+	int p1, p2, p3;
 
 	if (!kbuf)
 		return -ENOMEM;
@@ -586,25 +588,60 @@ static ssize_t wil_write_addba(struct file *file, const char __user *buf,
 	}
 
 	kbuf[len] = '\0';
-	rc = kstrtouint(kbuf, 0, &agg_wsize);
+	rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
 	kfree(kbuf);
 
-	if (rc)
+	if (rc < 0)
 		return rc;
-
-	if (!wil->vring_tx[0].va)
+	if (rc < 2)
 		return -EINVAL;
 
-	if (agg_wsize > 0)
-		wmi_addba(wil, 0, agg_wsize, 0);
-	else
-		wmi_delba_tx(wil, 0, 0);
+	if (0 == strcmp(cmd, "add")) {
+		if (rc < 3) {
+			wil_err(wil, "BACK: add require at least 2 params\n");
+			return -EINVAL;
+		}
+		if (rc < 4)
+			p3 = 0;
+		wmi_addba(wil, p1, p2, p3);
+	} else if (0 == strcmp(cmd, "del_tx")) {
+		if (rc < 3)
+			p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
+		wmi_delba_tx(wil, p1, p2);
+	} else if (0 == strcmp(cmd, "del_rx")) {
+		if (rc < 3) {
+			wil_err(wil,
+				"BACK: del_rx require at least 2 params\n");
+			return -EINVAL;
+		}
+		if (rc < 4)
+			p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
+		wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
+	} else {
+		wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
+		return -EINVAL;
+	}
 
 	return len;
 }
 
-static const struct file_operations fops_addba = {
-	.write = wil_write_addba,
+static ssize_t wil_read_back(struct file *file, char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	static const char text[] = "block ack control, write:\n"
+	" - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
+	"If missing, <timeout> defaults to 0\n"
+	" - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
+	" - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
+	"If missing, <reason> set to \"STA_LEAVING\" (36)\n";
+
+	return simple_read_from_buffer(user_buf, count, ppos, text,
+				       sizeof(text));
+}
+
+static const struct file_operations fops_back = {
+	.read = wil_read_back,
+	.write = wil_write_back,
 	.open  = simple_open,
 };
 
@@ -1268,7 +1305,7 @@ static const struct {
 	{"rxon",		  S_IWUSR,	&fops_rxon},
 	{"tx_mgmt",		  S_IWUSR,	&fops_txmgmt},
 	{"wmi_send",		  S_IWUSR,	&fops_wmi},
-	{"addba",		  S_IWUSR,	&fops_addba},
+	{"back",	S_IRUGO | S_IWUSR,	&fops_back},
 	{"temp",	S_IRUGO,		&fops_temp},
 	{"freq",	S_IRUGO,		&fops_freq},
 	{"link",	S_IRUGO,		&fops_link},
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 15/22] wil6210: detect HW capabilities
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (13 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 14/22] wil6210: rework debugfs for BACK Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 16/22] wil6210: use HW capabilities mask in reset Vladimir Kondratiev
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Read relevant information (HW ID for now) once on init
and set capabilities accordingly.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/pcie_bus.c | 32 ++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/wil6210/wil6210.h  | 20 ++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 66626a8..371809d 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -31,6 +31,36 @@ static bool debug_fw; /* = false; */
 module_param(debug_fw, bool, S_IRUGO);
 MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
 
+static
+void wil_set_capabilities(struct wil6210_priv *wil)
+{
+	u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID));
+
+	bitmap_zero(wil->hw_capabilities, hw_capability_last);
+
+	switch (rev_id) {
+	case JTAG_DEV_ID_MARLON_B0:
+		wil_info(wil, "Board hardware is Marlon B0\n");
+		wil->hw_version = HW_VER_MARLON_B0;
+		break;
+	case JTAG_DEV_ID_SPARROW_A0:
+		wil_info(wil, "Board hardware is Sparrow A0\n");
+		wil->hw_version = HW_VER_SPARROW_A0;
+		break;
+	case JTAG_DEV_ID_SPARROW_A1:
+		wil_info(wil, "Board hardware is Sparrow A1\n");
+		wil->hw_version = HW_VER_SPARROW_A1;
+		break;
+	case JTAG_DEV_ID_SPARROW_B0:
+		wil_info(wil, "Board hardware is Sparrow B0\n");
+		wil->hw_version = HW_VER_SPARROW_B0;
+		break;
+	default:
+		wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id);
+		wil->hw_version = HW_VER_UNKNOWN;
+	}
+}
+
 void wil_disable_irq(struct wil6210_priv *wil)
 {
 	int irq = wil->pdev->irq;
@@ -205,7 +235,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	pci_set_drvdata(pdev, wil);
 	wil->pdev = pdev;
 	wil->board = board;
-
+	wil_set_capabilities(wil);
 	wil6210_clear_irq(wil);
 
 	wil->platform_handle =
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 64a6d49..d296f2e 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -188,6 +188,20 @@ struct RGF_ICR {
 #define RGF_CAF_PLL_LOCK_STATUS		(0x88afec)
 	#define BIT_CAF_OSC_DIG_XTAL_STABLE	BIT(0)
 
+#define RGF_USER_JTAG_DEV_ID	(0x880b34) /* device ID */
+	#define JTAG_DEV_ID_MARLON_B0	(0x0612072f)
+	#define JTAG_DEV_ID_SPARROW_A0	(0x0632072f)
+	#define JTAG_DEV_ID_SPARROW_A1	(0x1632072f)
+	#define JTAG_DEV_ID_SPARROW_B0	(0x2632072f)
+
+enum {
+	HW_VER_UNKNOWN,
+	HW_VER_MARLON_B0,  /* JTAG_DEV_ID_MARLON_B0  */
+	HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */
+	HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */
+	HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */
+};
+
 /* popular locations */
 #define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
 #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -426,6 +440,11 @@ enum {
 	fw_recovery_running = 2,
 };
 
+enum {
+	hw_capability_dummy, /* to avoid zero array */
+	hw_capability_last
+};
+
 struct wil_back_rx {
 	struct list_head list;
 	/* request params, converted to CPU byte order - what we asked for */
@@ -452,6 +471,7 @@ struct wil6210_priv {
 	DECLARE_BITMAP(status, wil_status_last);
 	u32 fw_version;
 	u32 hw_version;
+	DECLARE_BITMAP(hw_capabilities, hw_capability_last);
 	struct wil_board *board;
 	u8 n_mids; /* number of additional MIDs as reported by FW */
 	u32 recovery_count; /* num of FW recovery attempts in a short time */
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 16/22] wil6210: use HW capabilities mask in reset
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (14 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 15/22] wil6210: detect HW capabilities Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 17/22] wil6210: add advanced interrupt moderation Vladimir Kondratiev
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Use the proper reset follow based on HW capabilities
detection instead of chip ID.
Remove old hw ID mechanism which was used only for reset flow.
Remove support for Marlon A0.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/interrupt.c | 11 +++++----
 drivers/net/wireless/ath/wil6210/main.c      | 33 +++++++++++--------------
 drivers/net/wireless/ath/wil6210/pcie_bus.c  | 37 +++++++++++-----------------
 drivers/net/wireless/ath/wil6210/wil6210.h   | 11 ++-------
 4 files changed, 36 insertions(+), 56 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 5a0ea72..384bb31 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -194,18 +194,19 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
 		wil_dbg_irq(wil, "RX done\n");
 
 		if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)
-			wil_err_ratelimited(wil, "Received \"Rx buffer is in risk "
-				"of overflow\" interrupt\n");
+			wil_err_ratelimited(wil,
+					    "Received \"Rx buffer is in risk of overflow\" interrupt\n");
 
-		isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH);
+		isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
+			 BIT_DMA_EP_RX_ICR_RX_HTRSH);
 		if (test_bit(wil_status_reset_done, wil->status)) {
 			if (test_bit(wil_status_napi_en, wil->status)) {
 				wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
 				need_unmask = false;
 				napi_schedule(&wil->napi_rx);
 			} else {
-				wil_err(wil, "Got Rx interrupt while "
-					"stopping interface\n");
+				wil_err(wil,
+					"Got Rx interrupt while stopping interface\n");
 			}
 		} else {
 			wil_err(wil, "Got Rx interrupt while in reset\n");
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index a17278f..fb73ac5 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -502,13 +502,10 @@ static int wil_target_reset(struct wil6210_priv *wil)
 {
 	int delay = 0;
 	u32 x;
-	u32 rev_id;
-	bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
+	bool is_reset_v2 = test_bit(hw_capability_reset_v2,
+				    wil->hw_capabilities);
 
-	wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
-
-	wil->hw_version = R(RGF_USER_FW_REV_ID);
-	rev_id = wil->hw_version & 0xff;
+	wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
 
 	/* Clear MAC link up */
 	S(RGF_HP_CTRL, BIT(15));
@@ -520,7 +517,7 @@ static int wil_target_reset(struct wil6210_priv *wil)
 	/* Clear Fw Download notification */
 	C(RGF_USER_USAGE_6, BIT(0));
 
-	if (is_sparrow) {
+	if (is_reset_v2) {
 		S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
 		/* XTAL stabilization should take about 3ms */
 		usleep_range(5000, 7000);
@@ -541,10 +538,11 @@ static int wil_target_reset(struct wil6210_priv *wil)
 
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
-	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
+	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3,
+	  is_reset_v2 ? 0x000000f0 : 0x00000170);
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
 
-	if (is_sparrow) {
+	if (is_reset_v2) {
 		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
 		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
 	}
@@ -554,19 +552,14 @@ static int wil_target_reset(struct wil6210_priv *wil)
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
 
-	if (is_sparrow) {
+	if (is_reset_v2) {
 		W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
 		/* reset A2 PCIE AHB */
 		W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
 	} else {
 		W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
-		if (rev_id == 1) {
-			/* reset A1 BOTH PCIE AHB & PCIE RGF */
-			W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
-		} else {
-			W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
-			W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
-		}
+		W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
+		W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
 	}
 
 	/* TODO: check order here!!! Erez code is different */
@@ -583,8 +576,7 @@ static int wil_target_reset(struct wil6210_priv *wil)
 		}
 	} while (x != HW_MACHINE_BOOT_DONE);
 
-	/* TODO: Erez check rev_id != 1 */
-	if (!is_sparrow && (rev_id != 1))
+	if (!is_reset_v2)
 		W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
 
 	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
@@ -653,6 +645,9 @@ int wil_reset(struct wil6210_priv *wil)
 
 	wil_dbg_misc(wil, "%s()\n", __func__);
 
+	if (wil->hw_version == HW_VER_UNKNOWN)
+		return -ENODEV;
+
 	WARN_ON(!mutex_is_locked(&wil->mutex));
 	WARN_ON(test_bit(wil_status_napi_en, wil->status));
 
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 371809d..9b1a589 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -40,25 +40,31 @@ void wil_set_capabilities(struct wil6210_priv *wil)
 
 	switch (rev_id) {
 	case JTAG_DEV_ID_MARLON_B0:
-		wil_info(wil, "Board hardware is Marlon B0\n");
+		wil->hw_name = "Marlon B0";
 		wil->hw_version = HW_VER_MARLON_B0;
 		break;
 	case JTAG_DEV_ID_SPARROW_A0:
-		wil_info(wil, "Board hardware is Sparrow A0\n");
+		wil->hw_name = "Sparrow A0";
 		wil->hw_version = HW_VER_SPARROW_A0;
 		break;
 	case JTAG_DEV_ID_SPARROW_A1:
-		wil_info(wil, "Board hardware is Sparrow A1\n");
+		wil->hw_name = "Sparrow A1";
 		wil->hw_version = HW_VER_SPARROW_A1;
 		break;
 	case JTAG_DEV_ID_SPARROW_B0:
-		wil_info(wil, "Board hardware is Sparrow B0\n");
+		wil->hw_name = "Sparrow B0";
 		wil->hw_version = HW_VER_SPARROW_B0;
 		break;
 	default:
 		wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id);
+		wil->hw_name = "Unknown";
 		wil->hw_version = HW_VER_UNKNOWN;
 	}
+
+	wil_info(wil, "Board hardware is %s\n", wil->hw_name);
+
+	if (wil->hw_version >= HW_VER_SPARROW_A0)
+		set_bit(hw_capability_reset_v2, wil->hw_capabilities);
 }
 
 void wil_disable_irq(struct wil6210_priv *wil)
@@ -179,12 +185,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	struct wil6210_priv *wil;
 	struct device *dev = &pdev->dev;
 	void __iomem *csr;
-	struct wil_board *board = (struct wil_board *)id->driver_data;
 	int rc;
 
 	/* check HW */
 	dev_info(&pdev->dev, WIL_NAME
-		 " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name,
+		 " device found [%04x:%04x] (rev %x)\n",
 		 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
 
 	if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
@@ -234,7 +239,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pci_set_drvdata(pdev, wil);
 	wil->pdev = pdev;
-	wil->board = board;
 	wil_set_capabilities(wil);
 	wil6210_clear_irq(wil);
 
@@ -296,23 +300,10 @@ static void wil_pcie_remove(struct pci_dev *pdev)
 	pci_disable_device(pdev);
 }
 
-static const struct wil_board wil_board_marlon = {
-	.board = WIL_BOARD_MARLON,
-	.name = "marlon",
-};
-
-static const struct wil_board wil_board_sparrow = {
-	.board = WIL_BOARD_SPARROW,
-	.name = "sparrow",
-};
-
 static const struct pci_device_id wil6210_pcie_ids[] = {
-	{ PCI_DEVICE(0x1ae9, 0x0301),
-	  .driver_data = (kernel_ulong_t)&wil_board_marlon },
-	{ PCI_DEVICE(0x1ae9, 0x0310),
-	  .driver_data = (kernel_ulong_t)&wil_board_sparrow },
-	{ PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
-	  .driver_data = (kernel_ulong_t)&wil_board_sparrow },
+	{ PCI_DEVICE(0x1ae9, 0x0301) },
+	{ PCI_DEVICE(0x1ae9, 0x0310) },
+	{ PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
 	{ /* end: all zeroes */	},
 };
 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index d296f2e..8a52a5f 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -32,13 +32,6 @@ extern int agg_wsize;
 
 #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
 
-struct wil_board {
-	int board;
-#define WIL_BOARD_MARLON	(1)
-#define WIL_BOARD_SPARROW	(2)
-	const char * const name;
-};
-
 /**
  * extract bits [@b0:@b1] (inclusive) from the value @x
  * it should be @b0 <= @b1, or result is incorrect
@@ -441,7 +434,7 @@ enum {
 };
 
 enum {
-	hw_capability_dummy, /* to avoid zero array */
+	hw_capability_reset_v2 = 0,
 	hw_capability_last
 };
 
@@ -471,8 +464,8 @@ struct wil6210_priv {
 	DECLARE_BITMAP(status, wil_status_last);
 	u32 fw_version;
 	u32 hw_version;
+	const char *hw_name;
 	DECLARE_BITMAP(hw_capabilities, hw_capability_last);
-	struct wil_board *board;
 	u8 n_mids; /* number of additional MIDs as reported by FW */
 	u32 recovery_count; /* num of FW recovery attempts in a short time */
 	u32 recovery_state; /* FW recovery state machine */
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 17/22] wil6210: add advanced interrupt moderation
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (15 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 16/22] wil6210: use HW capabilities mask in reset Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2015-01-07  8:12   ` Kalle Valo
  2014-12-23  7:47 ` [PATCH 18/22] wil6210: RX high threshold interrupt configuration Vladimir Kondratiev
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Add advanced interrupt moderation support available since "Sparrow B0".
Legacy interrupt moderation used only one counter to moderate tx, rx,
and misc interrupts.
Advanced interrupt moderation bypasses misc, and handles separately tx
and rx interrupts. In addition it has two timers for each interrupt type.
Max burst duration timer which defines how long to postpone interrupt after
first event (receive event for rx and tx complete event for tx), and
interframe timeout which defines how to determine the end of the burst and
issue interrupt even if the first timer still pending.
Capabilities flags in wil_priv is set on initialization according to
HW. The rest of the code checks for advanced interrupt capability bit
in capabilities flags field.
Debugfs is split accordingly: "legacy" interrupt moderation remains
unchanged, new debugs files added for advanced interrupt moderation
support.
Module params are aligned to support advanced interrupt moderation
(tx & rx). When not available (for legacy interrupt moderation) will
use only rx configuration; Tx configuration will be ignored in this
case.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c   | 49 ++++++++++++++++-
 drivers/net/wireless/ath/wil6210/ethtool.c   | 46 ++++++++++++----
 drivers/net/wireless/ath/wil6210/interrupt.c | 82 +++++++++++++++++++++++++++-
 drivers/net/wireless/ath/wil6210/main.c      | 56 +++++++++++--------
 drivers/net/wireless/ath/wil6210/pcie_bus.c  |  4 ++
 drivers/net/wireless/ath/wil6210/wil6210.h   | 56 +++++++++++++++++--
 6 files changed, 247 insertions(+), 46 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index a36a753..59d764c 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -390,24 +390,67 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
 	return 0;
 }
 
-static const struct dbg_off itr_cnt_off[] = {
+static const struct dbg_off lgc_itr_cnt_off[] = {
 	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
 	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
 	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
 	{},
 };
 
+static const struct dbg_off tx_itr_cnt_off[] = {
+	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
+	 doff_io32},
+	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
+	 doff_io32},
+	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
+	 doff_io32},
+	{"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
+	 doff_io32},
+	{"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
+	 doff_io32},
+	{"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
+	 doff_io32},
+	{},
+};
+
+static const struct dbg_off rx_itr_cnt_off[] = {
+	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
+	 doff_io32},
+	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
+	 doff_io32},
+	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
+	 doff_io32},
+	{"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
+	 doff_io32},
+	{"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
+	 doff_io32},
+	{"IDL_CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
+	 doff_io32},
+	{},
+};
+
 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
 					  struct dentry *parent)
 {
-	struct dentry *d = debugfs_create_dir("ITR_CNT", parent);
+	struct dentry *d, *dtx, *drx;
 
+	d = debugfs_create_dir("ITR_CNT", parent);
 	if (IS_ERR_OR_NULL(d))
 		return -ENODEV;
 
+	dtx = debugfs_create_dir("TX", d);
+	drx = debugfs_create_dir("RX", d);
+	if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
+		return -ENODEV;
+
 	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
-				    itr_cnt_off);
+				    lgc_itr_cnt_off);
+
+	wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
+				    tx_itr_cnt_off);
 
+	wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
+				    rx_itr_cnt_off);
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
index d686638..4c44a82 100644
--- a/drivers/net/wireless/ath/wil6210/ethtool.c
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -45,16 +45,35 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
 				       struct ethtool_coalesce *cp)
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
-	u32 itr_en, itr_val = 0;
+	u32 tx_itr_en, tx_itr_val = 0;
+	u32 rx_itr_en, rx_itr_val = 0;
 
 	wil_dbg_misc(wil, "%s()\n", __func__);
 
-	itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
-	if (itr_en & BIT_DMA_ITR_CNT_CRL_EN)
-		itr_val = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
-
-	cp->rx_coalesce_usecs = itr_val;
+	if (test_bit(hw_capability_advanced_itr_moderation,
+		     wil->hw_capabilities)) {
+		tx_itr_en = ioread32(wil->csr +
+				     HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL));
+		if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
+			tx_itr_val =
+				ioread32(wil->csr +
+					 HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH));
+
+		rx_itr_en = ioread32(wil->csr +
+				     HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL));
+		if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
+			rx_itr_val =
+				ioread32(wil->csr +
+					 HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH));
+	} else {
+		rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+		if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN)
+			rx_itr_val = ioread32(wil->csr +
+					      HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
+	}
 
+	cp->tx_coalesce_usecs = tx_itr_val;
+	cp->rx_coalesce_usecs = rx_itr_val;
 	return 0;
 }
 
@@ -63,22 +82,25 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
-	wil_dbg_misc(wil, "%s(%d usec)\n", __func__, cp->rx_coalesce_usecs);
+	wil_dbg_misc(wil, "%s(rx %d usec, tx %d usec)\n", __func__,
+		     cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
 
 	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
 		wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
 		return -EINVAL;
 	}
 
-	/* only @rx_coalesce_usecs supported, ignore
-	 * other parameters
+	/* only @rx_coalesce_usecs and @tx_coalesce_usecs supported,
+	 * ignore other parameters
 	 */
 
-	if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
+	if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX ||
+	    cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
 		goto out_bad;
 
-	wil->itr_trsh = cp->rx_coalesce_usecs;
-	wil_set_itr_trsh(wil);
+	wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
+	wil->rx_max_burst_duration = cp->rx_coalesce_usecs;
+	wil_configure_interrupt_moderation(wil);
 
 	return 0;
 
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 384bb31..a6f9230 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -157,15 +157,91 @@ void wil_unmask_irq(struct wil6210_priv *wil)
 	iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
 		  offsetof(struct RGF_ICR, ICC));
 
-	/* interrupt moderation parameters */
-	wil_set_itr_trsh(wil);
-
 	wil6210_unmask_irq_pseudo(wil);
 	wil6210_unmask_irq_tx(wil);
 	wil6210_unmask_irq_rx(wil);
 	wil6210_unmask_irq_misc(wil);
 }
 
+/* target write operation */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+
+static
+void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil)
+{
+	/* Disable and clear tx counter before (re)configuration */
+	W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR);
+	W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration);
+	wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n",
+		 wil->tx_max_burst_duration);
+	/* Configure TX max burst duration timer to use usec units */
+	W(RGF_DMA_ITR_TX_CNT_CTL,
+	  BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL);
+
+	/* Disable and clear tx idle counter before (re)configuration */
+	W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR);
+	W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout);
+	wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n",
+		 wil->tx_interframe_timeout);
+	/* Configure TX max burst duration timer to use usec units */
+	W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN |
+				      BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL);
+
+	/* Disable and clear rx counter before (re)configuration */
+	W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR);
+	W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration);
+	wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n",
+		 wil->rx_max_burst_duration);
+	/* Configure TX max burst duration timer to use usec units */
+	W(RGF_DMA_ITR_RX_CNT_CTL,
+	  BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL);
+
+	/* Disable and clear rx idle counter before (re)configuration */
+	W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR);
+	W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout);
+	wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n",
+		 wil->rx_interframe_timeout);
+	/* Configure TX max burst duration timer to use usec units */
+	W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN |
+				      BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);
+}
+
+static
+void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil)
+{
+	/* disable, use usec resolution */
+	W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR);
+
+	wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration);
+	W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration);
+	/* start it */
+	W(RGF_DMA_ITR_CNT_CRL,
+	  BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK);
+}
+
+#undef W
+
+void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
+{
+	wil_dbg_irq(wil, "%s()\n", __func__);
+
+	/* disable interrupt moderation for monitor
+	 * to get better timestamp precision
+	 */
+	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
+		return;
+
+	if (test_bit(hw_capability_advanced_itr_moderation,
+		     wil->hw_capabilities))
+		wil_configure_interrupt_moderation_new(wil);
+	else {
+		/* Advanced interrupt moderation is not available before
+		 * Sparrow v2. Will use legacy interrupt moderation
+		 */
+		wil_configure_interrupt_moderation_lgc(wil);
+	}
+}
+
 static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
 {
 	struct wil6210_priv *wil = cookie;
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index fb73ac5..d286153 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -33,10 +33,34 @@ 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 itr_trsh = WIL6210_ITR_TRSH_DEFAULT;
+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.");
 
-module_param(itr_trsh, uint, S_IRUGO);
-MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
 
 /* We allow allocation of more than 1 page buffers to support large packets.
  * It is suboptimal behavior performance wise in case MTU above page size.
@@ -427,7 +451,10 @@ int wil_priv_init(struct wil6210_priv *wil)
 		goto out_wmi_wq;
 
 	wil->last_fw_recovery = jiffies;
-	wil->itr_trsh = itr_trsh;
+	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;
 
 	return 0;
 
@@ -585,26 +612,6 @@ static int wil_target_reset(struct wil6210_priv *wil)
 	return 0;
 }
 
-/**
- * wil_set_itr_trsh: - apply interrupt coalescing params
- */
-void wil_set_itr_trsh(struct wil6210_priv *wil)
-{
-	/* disable, use usec resolution */
-	W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EXT_TICK);
-
-	/* disable interrupt moderation for monitor
-	 * to get better timestamp precision
-	 */
-	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
-		return;
-
-	wil_info(wil, "set ITR_TRSH = %d usec\n", wil->itr_trsh);
-	W(RGF_DMA_ITR_CNT_TRSH, wil->itr_trsh);
-	W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EN |
-	  BIT_DMA_ITR_CNT_CRL_EXT_TICK); /* start it */
-}
-
 #undef R
 #undef W
 #undef S
@@ -708,6 +715,7 @@ int wil_reset(struct wil6210_priv *wil)
 	reinit_completion(&wil->wmi_ready);
 	reinit_completion(&wil->wmi_call);
 
+	wil_configure_interrupt_moderation(wil);
 	wil_unmask_irq(wil);
 
 	/* we just started MAC, wait for FW ready */
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 9b1a589..3dd2670 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -65,6 +65,10 @@ void wil_set_capabilities(struct wil6210_priv *wil)
 
 	if (wil->hw_version >= HW_VER_SPARROW_A0)
 		set_bit(hw_capability_reset_v2, wil->hw_capabilities);
+
+	if (wil->hw_version >= HW_VER_SPARROW_B0)
+		set_bit(hw_capability_advanced_itr_moderation,
+			wil->hw_capabilities);
 }
 
 void wil_disable_irq(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 8a52a5f..a6d63c1 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -76,7 +76,10 @@ 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_TRSH_DEFAULT	(300) /* usec */
+#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (15) /* usec */
+#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (15) /* 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 */
 #define WIL6210_FW_RECOVERY_TO	msecs_to_jiffies(5000)
 #define WIL6210_SCAN_TO		msecs_to_jiffies(10000)
@@ -152,7 +155,7 @@ struct RGF_ICR {
 	#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT	BIT(1)
 	#define BIT_DMA_EP_MISC_ICR_FW_INT(n)	BIT(28+n) /* n = [0..3] */
 
-/* Interrupt moderation control */
+/* Legacy interrupt moderation control (before Sparrow v2)*/
 #define RGF_DMA_ITR_CNT_TRSH		(0x881c5c)
 #define RGF_DMA_ITR_CNT_DATA		(0x881c60)
 #define RGF_DMA_ITR_CNT_CRL		(0x881c64)
@@ -162,6 +165,46 @@ struct RGF_ICR {
 	#define BIT_DMA_ITR_CNT_CRL_CLR		BIT(3)
 	#define BIT_DMA_ITR_CNT_CRL_REACH_TRSH	BIT(4)
 
+/* New (sparrow v2+) interrupt moderation control */
+#define RGF_DMA_ITR_TX_DESQ_NO_MOD		(0x881d40)
+#define RGF_DMA_ITR_TX_CNT_TRSH			(0x881d34)
+#define RGF_DMA_ITR_TX_CNT_DATA			(0x881d38)
+#define RGF_DMA_ITR_TX_CNT_CTL			(0x881d3c)
+	#define BIT_DMA_ITR_TX_CNT_CTL_EN		BIT(0)
+	#define BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL	BIT(1)
+	#define BIT_DMA_ITR_TX_CNT_CTL_FOREVER		BIT(2)
+	#define BIT_DMA_ITR_TX_CNT_CTL_CLR		BIT(3)
+	#define BIT_DMA_ITR_TX_CNT_CTL_REACHED_TRESH	BIT(4)
+	#define BIT_DMA_ITR_TX_CNT_CTL_CROSS_EN		BIT(5)
+	#define BIT_DMA_ITR_TX_CNT_CTL_FREE_RUNNIG	BIT(6)
+#define RGF_DMA_ITR_TX_IDL_CNT_TRSH			(0x881d60)
+#define RGF_DMA_ITR_TX_IDL_CNT_DATA			(0x881d64)
+#define RGF_DMA_ITR_TX_IDL_CNT_CTL			(0x881d68)
+	#define BIT_DMA_ITR_TX_IDL_CNT_CTL_EN			BIT(0)
+	#define BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL		BIT(1)
+	#define BIT_DMA_ITR_TX_IDL_CNT_CTL_FOREVER		BIT(2)
+	#define BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR			BIT(3)
+	#define BIT_DMA_ITR_TX_IDL_CNT_CTL_REACHED_TRESH	BIT(4)
+#define RGF_DMA_ITR_RX_DESQ_NO_MOD		(0x881d50)
+#define RGF_DMA_ITR_RX_CNT_TRSH			(0x881d44)
+#define RGF_DMA_ITR_RX_CNT_DATA			(0x881d48)
+#define RGF_DMA_ITR_RX_CNT_CTL			(0x881d4c)
+	#define BIT_DMA_ITR_RX_CNT_CTL_EN		BIT(0)
+	#define BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL	BIT(1)
+	#define BIT_DMA_ITR_RX_CNT_CTL_FOREVER		BIT(2)
+	#define BIT_DMA_ITR_RX_CNT_CTL_CLR		BIT(3)
+	#define BIT_DMA_ITR_RX_CNT_CTL_REACHED_TRESH	BIT(4)
+	#define BIT_DMA_ITR_RX_CNT_CTL_CROSS_EN		BIT(5)
+	#define BIT_DMA_ITR_RX_CNT_CTL_FREE_RUNNIG	BIT(6)
+#define RGF_DMA_ITR_RX_IDL_CNT_TRSH			(0x881d54)
+#define RGF_DMA_ITR_RX_IDL_CNT_DATA			(0x881d58)
+#define RGF_DMA_ITR_RX_IDL_CNT_CTL			(0x881d5c)
+	#define BIT_DMA_ITR_RX_IDL_CNT_CTL_EN			BIT(0)
+	#define BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL		BIT(1)
+	#define BIT_DMA_ITR_RX_IDL_CNT_CTL_FOREVER		BIT(2)
+	#define BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR			BIT(3)
+	#define BIT_DMA_ITR_RX_IDL_CNT_CTL_REACHED_TRESH	BIT(4)
+
 #define RGF_DMA_PSEUDO_CAUSE		(0x881c68)
 #define RGF_DMA_PSEUDO_CAUSE_MASK_SW	(0x881c6c)
 #define RGF_DMA_PSEUDO_CAUSE_MASK_FW	(0x881c70)
@@ -435,6 +478,7 @@ enum {
 
 enum {
 	hw_capability_reset_v2 = 0,
+	hw_capability_advanced_itr_moderation = 1,
 	hw_capability_last
 };
 
@@ -475,7 +519,11 @@ struct wil6210_priv {
 	u32 monitor_flags;
 	u32 secure_pcp; /* create secure PCP? */
 	int sinfo_gen;
-	u32 itr_trsh;
+	/* interrupt moderation */
+	u32 tx_max_burst_duration;
+	u32 tx_interframe_timeout;
+	u32 rx_max_burst_duration;
+	u32 rx_interframe_timeout;
 	/* cached ISR registers */
 	u32 isr_misc;
 	/* mailbox related */
@@ -596,7 +644,6 @@ void wil_if_remove(struct wil6210_priv *wil);
 int wil_priv_init(struct wil6210_priv *wil);
 void wil_priv_deinit(struct wil6210_priv *wil);
 int wil_reset(struct wil6210_priv *wil);
-void wil_set_itr_trsh(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);
@@ -653,6 +700,7 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq);
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
 void wil_mask_irq(struct wil6210_priv *wil);
 void wil_unmask_irq(struct wil6210_priv *wil);
+void wil_configure_interrupt_moderation(struct wil6210_priv *wil);
 void wil_disable_irq(struct wil6210_priv *wil);
 void wil_enable_irq(struct wil6210_priv *wil);
 int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 18/22] wil6210: RX high threshold interrupt configuration
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (16 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 17/22] wil6210: add advanced interrupt moderation Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 19/22] wil6210: fix reordering for MCAST Vladimir Kondratiev
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Rx high threshold interrupt is reported by the hardware in case
when number of not utilized by the HW descriptors in the Rx ring
becomes low.
Introduce module parameter for RX high threshold.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/main.c    | 9 +++++++++
 drivers/net/wireless/ath/wil6210/wil6210.h | 5 ++++-
 drivers/net/wireless/ath/wil6210/wmi.c     | 1 +
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index d286153..f44b640 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -61,6 +61,13 @@ 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
+ */
+unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
+module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO);
+MODULE_PARM_DESC(rx_ring_overflow_thrsh,
+		 " RX ring overflow threshold in descriptors.");
 
 /* We allow allocation of more than 1 page buffers to support large packets.
  * It is suboptimal behavior performance wise in case MTU above page size.
@@ -456,6 +463,8 @@ int wil_priv_init(struct wil6210_priv *wil)
 	wil->tx_max_burst_duration = tx_max_burst_duration;
 	wil->rx_max_burst_duration = rx_max_burst_duration;
 
+	if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
+		rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
 	return 0;
 
 out_wmi_wq:
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index a6d63c1..da3fe78 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -25,6 +25,7 @@
 
 extern bool no_fw_recovery;
 extern unsigned int mtu_max;
+extern unsigned short rx_ring_overflow_thrsh;
 extern int agg_wsize;
 
 #define WIL_NAME "wil6210"
@@ -83,7 +84,9 @@ static inline u32 wil_mtu2macbuf(u32 mtu)
 #define WIL6210_FW_RECOVERY_RETRIES	(5) /* try to recover this many times */
 #define WIL6210_FW_RECOVERY_TO	msecs_to_jiffies(5000)
 #define WIL6210_SCAN_TO		msecs_to_jiffies(10000)
-
+#define WIL6210_RX_HIGH_TRSH_INIT		(0)
+#define WIL6210_RX_HIGH_TRSH_DEFAULT \
+				(1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
 /* Hardware definitions begin */
 
 /*
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index a4b30a4..432ec55 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1090,6 +1090,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
 		.mid = 0, /* TODO - what is it? */
 		.decap_trans_type = WMI_DECAP_TYPE_802_3,
 		.reorder_type = WMI_RX_SW_REORDER,
+		.host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
 	};
 	struct {
 		struct wil6210_mbox_hdr_wmi wmi;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 19/22] wil6210: fix reordering for MCAST
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (17 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 18/22] wil6210: RX high threshold interrupt configuration Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 20/22] wil6210: Tx/Rx descriptors documentation Vladimir Kondratiev
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

In the reordering block, Ethernet DA was checked for MCAST, this is wrong.
Check instead MCAST indication from 802.11 MAC header. Hardware saves
this into Rx descriptor.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/rx_reorder.c | 10 ++++++++--
 drivers/net/wireless/ath/wil6210/txrx.c       |  8 +-------
 drivers/net/wireless/ath/wil6210/txrx.h       |  5 +++++
 3 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 0865c34..20d65f2 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -97,14 +97,20 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
 	int cid = wil_rxdesc_cid(d);
 	int mid = wil_rxdesc_mid(d);
 	u16 seq = wil_rxdesc_seq(d);
+	int mcast = wil_rxdesc_mcast(d);
 	struct wil_sta_info *sta = &wil->sta[cid];
 	struct wil_tid_ampdu_rx *r;
 	u16 hseq;
 	int index;
 	unsigned long flags;
 
-	wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
-		     mid, cid, tid, seq);
+	wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
+		     mid, cid, tid, seq, mcast);
+
+	if (unlikely(mcast)) {
+		wil_netif_rx_any(skb, ndev);
+		return;
+	}
 
 	spin_lock_irqsave(&sta->tid_rx_lock, flags);
 
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 4c145ee..5fc5f56 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -581,14 +581,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
 			skb->protocol = htons(ETH_P_802_2);
 			wil_netif_rx_any(skb, ndev);
 		} else {
-			struct ethhdr *eth = (void *)skb->data;
-
 			skb->protocol = eth_type_trans(skb, ndev);
-
-			if (is_unicast_ether_addr(eth->h_dest))
-				wil_rx_reorder(wil, skb);
-			else
-				wil_netif_rx_any(skb, ndev);
+			wil_rx_reorder(wil, skb);
 		}
 	}
 	wil_rx_refill(wil, v->size);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index e7db356..c906c5f0 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -423,6 +423,11 @@ static inline int wil_rxdesc_mcs(struct vring_rx_desc *d)
 	return WIL_GET_BITS(d->mac.d1, 21, 24);
 }
 
+static inline int wil_rxdesc_mcast(struct vring_rx_desc *d)
+{
+	return WIL_GET_BITS(d->mac.d1, 13, 14);
+}
+
 static inline int wil_rxdesc_phy_length(struct vring_rx_desc *d)
 {
 	return WIL_GET_BITS(d->dma.d0, 16, 29);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 20/22] wil6210: Tx/Rx descriptors documentation
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (18 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 19/22] wil6210: fix reordering for MCAST Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 21/22] wil6210: workaround for BACK establishment race Vladimir Kondratiev
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

Sync documentation for the Tx/Rx descriptors with the
firmware/hardware documentation.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/txrx.c |   2 +-
 drivers/net/wireless/ath/wil6210/txrx.h | 149 +++++++++++++++++++++-----------
 2 files changed, 98 insertions(+), 53 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 5fc5f56..b58ee52 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -463,7 +463,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
 	 * and in case of error drop the packet
 	 * higher stack layers will handle retransmission (if required)
 	 */
-	if (d->dma.status & RX_DMA_STATUS_L4_IDENT) {
+	if (d->dma.status & RX_DMA_STATUS_L4I) {
 		/* L4 protocol identified, csum calculated */
 		if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0)
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index c906c5f0..d90c8aa 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -28,9 +28,7 @@
 
 /* Tx/Rx path */
 
-/*
- * Common representation of physical address in Vring
- */
+/* Common representation of physical address in Vring */
 struct vring_dma_addr {
 	__le32 addr_low;
 	__le16 addr_high;
@@ -49,11 +47,10 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
 	addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa));
 }
 
-/*
- * Tx descriptor - MAC part
+/* Tx descriptor - MAC part
  * [dword 0]
  * bit  0.. 9 : lifetime_expiry_value:10
- * bit     10 : interrup_en:1
+ * bit     10 : interrupt_en:1
  * bit     11 : status_en:1
  * bit 12..13 : txss_override:2
  * bit     14 : timestamp_insertion:1
@@ -61,15 +58,12 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
  * bit 16..21 : reserved0:6
  * bit 22..26 : mcs_index:5
  * bit     27 : mcs_en:1
- * bit 28..29 : reserved1:2
- * bit     30 : reserved2:1
+ * bit 28..30 : reserved1:3
  * bit     31 : sn_preserved:1
  * [dword 1]
  * bit  0.. 3 : pkt_mode:4
  * bit      4 : pkt_mode_en:1
- * bit  5.. 7 : reserved0:3
- * bit  8..13 : reserved1:6
- * bit     14 : reserved2:1
+ * bit  5..14 : reserved0:10
  * bit     15 : ack_policy_en:1
  * bit 16..19 : dst_index:4
  * bit     20 : dst_index_en:1
@@ -80,7 +74,7 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
  * [dword 2]
  * bit  0.. 7 : num_of_descriptors:8
  * bit  8..17 : reserved:10
- * bit 18..19 : l2_translation_type:2
+ * bit 18..19 : l2_translation_type:2 00 - bypass, 01 - 802.3, 10 - 802.11
  * bit     20 : snap_hdr_insertion_en:1
  * bit     21 : vlan_removal_en:1
  * bit 22..31 : reserved0:10
@@ -247,6 +241,46 @@ struct vring_tx_mac {
 
 #define TX_DMA_STATUS_DU         BIT(0)
 
+/* Tx descriptor - DMA part
+ * [dword 0]
+ * bit  0.. 7 : l4_length:8 layer 4 length
+ * bit      8 : cmd_eop:1 This descriptor is the last one in the packet
+ * bit      9 : reserved
+ * bit     10 : cmd_dma_it:1 immediate interrupt
+ * bit 11..12 : SBD - Segment Buffer Details
+ *		00 - Header Segment
+ *		01 - First Data Segment
+ *		10 - Medium Data Segment
+ *		11 - Last Data Segment
+ * bit     13 : TSE - TCP Segmentation Enable
+ * bit     14 : IIC - Directs the HW to Insert IPv4 Checksum
+ * bit     15 : ITC - Directs the HW to Insert TCP/UDP Checksum
+ * bit 16..20 : QID - The target QID that the packet should be stored
+ *		in the MAC.
+ * bit     21 : PO - Pseudo header Offload:
+ *		0 - Use the pseudo header value from the TCP checksum field
+ *		1- Calculate Pseudo header Checksum
+ * bit     22 : NC - No UDP Checksum
+ * bit 23..29 : reserved
+ * bit 30..31 : L4T - Layer 4 Type: 00 - UDP , 10 - TCP , 10, 11 - Reserved
+ *		If L4Len equal 0, no L4 at all
+ * [dword 1]
+ * bit  0..31 : addr_low:32 The payload buffer low address
+ * [dword 2]
+ * bit  0..15 : addr_high:16 The payload buffer high address
+ * bit 16..23 : ip_length:8 The IP header length for the TX IP checksum
+ *		offload feature
+ * bit 24..30 : mac_length:7
+ * bit     31 : ip_version:1 1 - IPv4, 0 - IPv6
+ * [dword 3]
+ *  [byte 12] error
+ * bit  0   2 : mac_status:3
+ * bit  3   7 : reserved:5
+ *  [byte 13] status
+ * bit      0 : DU:1 Descriptor Used
+ * bit  1   7 : reserved:7
+ *  [word 7] length
+ */
 struct vring_tx_dma {
 	u32 d0;
 	struct vring_dma_addr addr;
@@ -257,45 +291,45 @@ struct vring_tx_dma {
 	__le16 length;
 } __packed;
 
-/*
- * Rx descriptor - MAC part
+/* Rx descriptor - MAC part
  * [dword 0]
  * bit  0.. 3 : tid:4 The QoS (b3-0) TID Field
- * bit  4.. 6 : connection_id:3 :The Source index that  was found during
- *  Parsing the TA.  This field is used to  define the source of the packet
+ * bit  4.. 6 : cid:3 The Source index that  was found during parsing the TA.
+ *		This field is used to define the source of the packet
  * bit      7 : reserved:1
- * bit  8.. 9 : mac_id:2 : The MAC virtual  Ring number (always zero)
- * bit 10..11 : frame_type:2 : The FC Control  (b3-2) -  MPDU Type
- *              (management, data, control  and extension)
- * bit 12..15 : frame_subtype:4 : The FC Control  (b7-4) -  Frame Subtype
+ * bit  8.. 9 : mid:2 The MAC virtual number
+ * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
+ *		(management, data, control and extension)
+ * bit 12..15 : frame_subtype:4 : The FC (b7-4) - Frame Subtype
  * bit 16..27 : seq_number:12 The received Sequence number field
  * bit 28..31 : extended:4 extended subtype
  * [dword 1]
  * bit  0.. 3 : reserved
  * bit  4.. 5 : key_id:2
  * bit      6 : decrypt_bypass:1
- * bit      7 : security:1
- * bit  8.. 9 : ds_bits:2
- * bit     10 : a_msdu_present:1  from qos header
- * bit     11 : a_msdu_type:1  from qos header
+ * bit      7 : security:1 FC (b14)
+ * bit  8.. 9 : ds_bits:2 FC (b9-8)
+ * bit     10 : a_msdu_present:1  QoS (b7)
+ * bit     11 : a_msdu_type:1  QoS (b8)
  * bit     12 : a_mpdu:1  part of AMPDU aggregation
  * bit     13 : broadcast:1
  * bit     14 : mutlicast:1
  * bit     15 : reserved:1
- * bit 16..20 : rx_mac_qid:5   The Queue Identifier that the packet
- *                             is received from
+ * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet
+ *		is received from
  * bit 21..24 : mcs:4
- * bit 25..28 : mic_icr:4
+ * bit 25..28 : mic_icr:4 this signal tells the DMA to assert an interrupt
+ *		after it writes the packet
  * bit 29..31 : reserved:3
  * [dword 2]
  * bit  0.. 2 : time_slot:3 The timeslot that the MPDU is received
- * bit      3 : fc_protocol_ver:1 The FC Control  (b0) - Protocol  Version
- * bit      4 : fc_order:1 The FC Control (b15) -Order
- * bit  5.. 7 : qos_ack_policy:3  The QoS (b6-5) ack policy Field
+ * bit  3.. 4 : fc_protocol_ver:1 The FC (b1-0) - Protocol Version
+ * bit      5 : fc_order:1 The FC Control (b15) -Order
+ * bit  6.. 7 : qos_ack_policy:2 The QoS (b6-5) ack policy Field
  * bit      8 : esop:1 The QoS (b4) ESOP field
- * bit      9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG  field
- * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved  field
- * bit     15 : qos_ac_constraint:1
+ * bit      9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field
+ * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field
+ * bit     15 : qos_ac_constraint:1 QoS (b15)
  * bit 16..31 : pn_15_0:16 low 2 bytes of PN
  * [dword 3]
  * bit  0..31 : pn_47_16:32 high 4 bytes of PN
@@ -308,35 +342,46 @@ struct vring_rx_mac {
 	u32 pn_47_16;
 } __packed;
 
-/*
- * Rx descriptor - DMA part
+/* Rx descriptor - DMA part
  * [dword 0]
- * bit  0.. 7 : l4_length:8 layer 4 length
- * bit  8.. 9 : reserved:2
- * bit     10 : cmd_dma_it:1
+ * bit  0.. 7 : l4_length:8 layer 4 length. The field is only valid if
+ *		L4I bit is set
+ * bit      8 : cmd_eop:1 set to 1
+ * bit      9 : cmd_rt:1 set to 1
+ * bit     10 : cmd_dma_it:1 immediate interrupt
  * bit 11..15 : reserved:5
- * bit 16..29 : phy_info_length:14
+ * bit 16..29 : phy_info_length:14 It is valid when the PII is set.
+ *		When the FFM bit is set bits 29-27 are used for for
+ *		Flex Filter Match. Matching Index to one of the L2
+ *		EtherType Flex Filter
  * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field
+ *		00 - UDP, 01 - TCP, 10, 11 - reserved
  * [dword 1]
  * bit  0..31 : addr_low:32 The payload buffer low address
  * [dword 2]
  * bit  0..15 : addr_high:16 The payload buffer high address
- * bit 16..23 : ip_length:8
+ * bit 16..23 : ip_length:8 The filed is valid only if the L3I bit is set
  * bit 24..30 : mac_length:7
- * bit     31 : ip_version:1
+ * bit     31 : ip_version:1 1 - IPv4, 0 - IPv6
  * [dword 3]
  *  [byte 12] error
+ * bit      0 : FCS:1
+ * bit      1 : MIC:1
+ * bit      2 : Key miss:1
+ * bit      3 : Replay:1
+ * bit      4 : L3:1 IPv4 checksum
+ * bit      5 : L4:1 TCP/UDP checksum
+ * bit  6   7 : reserved:2
  *  [byte 13] status
- * bit      0 : du:1
- * bit      1 : eop:1
+ * bit      0 : DU:1 Descriptor Used
+ * bit      1 : EOP:1 The descriptor indicates the End of Packet
  * bit      2 : error:1
- * bit      3 : mi:1
- * bit      4 : l3_identified:1
- * bit      5 : l4_identified:1
- * bit      6 : phy_info_included:1
- * bit      7 : reserved:1
+ * bit      3 : MI:1 MAC Interrupt is asserted (according to parser decision)
+ * bit      4 : L3I:1 L3 identified and checksum calculated
+ * bit      5 : L4I:1 L4 identified and checksum calculated
+ * bit      6 : PII:1 PHY Info Included in the packet
+ * bit      7 : FFM:1 EtherType Flex Filter Match
  *  [word 7] length
- *
  */
 
 #define RX_DMA_D0_CMD_DMA_IT     BIT(10)
@@ -349,9 +394,9 @@ struct vring_rx_mac {
 #define RX_DMA_STATUS_DU         BIT(0)
 #define RX_DMA_STATUS_ERROR      BIT(2)
 
-#define RX_DMA_STATUS_L3_IDENT   BIT(4)
-#define RX_DMA_STATUS_L4_IDENT   BIT(5)
-#define RX_DMA_STATUS_PHY_INFO   BIT(6)
+#define RX_DMA_STATUS_L3I	BIT(4)
+#define RX_DMA_STATUS_L4I	BIT(5)
+#define RX_DMA_STATUS_PHY_INFO	BIT(6)
 
 struct vring_rx_dma {
 	u32 d0;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 21/22] wil6210: workaround for BACK establishment race
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (19 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 20/22] wil6210: Tx/Rx descriptors documentation Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2014-12-23  7:47 ` [PATCH 22/22] wil6210: relax spinlocks in rx reorder Vladimir Kondratiev
  2015-01-15 12:37 ` [PATCH 00/22] wil6210 patches Kalle Valo
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

When establishing BACK, WMI may be handled earlier then Rx, in this case
late Rx will be mis-handled.

Detect early Rx and pass it to the stack, bypass reordering

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/rx_reorder.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 20d65f2..5af8012 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -127,13 +127,24 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
 	 * reported, and data Rx, few packets may be pass up before reorder
 	 * buffer get allocated. Catch up by pretending SSN is what we
 	 * see in the 1-st Rx packet
+	 *
+	 * Another scenario, Rx get delayed and we got packet from before
+	 * BACK. Pass it to the stack and wait.
 	 */
 	if (r->first_time) {
 		r->first_time = false;
 		if (seq != r->head_seq_num) {
-			wil_err(wil, "Error: 1-st frame with wrong sequence"
-				" %d, should be %d. Fixing...\n", seq,
-				r->head_seq_num);
+			if (seq_less(seq, r->head_seq_num)) {
+				wil_err(wil,
+					"Error: frame with early sequence 0x%03x, should be 0x%03x. Waiting...\n",
+					seq, r->head_seq_num);
+				r->first_time = true;
+				wil_netif_rx_any(skb, ndev);
+				goto out;
+			}
+			wil_err(wil,
+				"Error: 1-st frame with wrong sequence 0x%03x, should be 0x%03x. Fixing...\n",
+				seq, r->head_seq_num);
 			r->head_seq_num = seq;
 			r->ssn = seq;
 		}
@@ -279,6 +290,7 @@ static void wil_back_rx_handle(struct wil6210_priv *wil,
 	int ba_policy = req->ba_param_set & BIT(1);
 	u16 agg_timeout = req->ba_timeout;
 	u16 status = WLAN_STATUS_SUCCESS;
+	u16 ssn = req->ba_seq_ctrl >> 4;
 	unsigned long flags;
 	int rc;
 
@@ -297,9 +309,9 @@ static void wil_back_rx_handle(struct wil6210_priv *wil,
 	}
 
 	wil_dbg_wmi(wil,
-		    "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d\n",
+		    "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n",
 		    cid, sta->addr, tid, req_agg_wsize, req->ba_timeout,
-		    agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token);
+		    agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token, ssn);
 
 	/* apply policies */
 	if (ba_policy) {
@@ -318,8 +330,7 @@ static void wil_back_rx_handle(struct wil6210_priv *wil,
 	spin_lock_irqsave(&sta->tid_rx_lock, flags);
 
 	wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
-	sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize,
-						  req->ba_seq_ctrl >> 4);
+	sta->tid_rx[tid] = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
 
 	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
 }
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 22/22] wil6210: relax spinlocks in rx reorder
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (20 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 21/22] wil6210: workaround for BACK establishment race Vladimir Kondratiev
@ 2014-12-23  7:47 ` Vladimir Kondratiev
  2015-01-15 12:37 ` [PATCH 00/22] wil6210 patches Kalle Valo
  22 siblings, 0 replies; 27+ messages in thread
From: Vladimir Kondratiev @ 2014-12-23  7:47 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Vladimir Kondratiev, linux-wireless, wil6210

In the Rx reorder mechanism, nothing is done in the interrupt
context, so there is no need to use 'irq' flavors of spinlock.
Rx done in NAPI context (tasklet), other manipulations - in the
thread context.

Having interrupts enabled makes it better for the OS in general.
Besides, if enslaved under bonding, bridge or team driver, Rx
won't work with interrupts disabled.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/debugfs.c    |  6 +++---
 drivers/net/wireless/ath/wil6210/main.c       |  7 ++++---
 drivers/net/wireless/ath/wil6210/rx_reorder.c | 17 +++++++++--------
 drivers/net/wireless/ath/wil6210/wmi.c        |  7 ++++---
 4 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 59d764c..c7ea765 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1258,10 +1258,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
 }
 
 static int wil_sta_debugfs_show(struct seq_file *s, void *data)
+__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
 {
 	struct wil6210_priv *wil = s->private;
 	int i, tid;
-	unsigned long flags;
 
 	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
 		struct wil_sta_info *p = &wil->sta[i];
@@ -1282,7 +1282,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
 			   (p->data_port_open ? " data_port_open" : ""));
 
 		if (p->status == wil_sta_connected) {
-			spin_lock_irqsave(&p->tid_rx_lock, flags);
+			spin_lock_bh(&p->tid_rx_lock);
 			for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
 				struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
 
@@ -1291,7 +1291,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
 					wil_print_rxtid(s, r);
 				}
 			}
-			spin_unlock_irqrestore(&p->tid_rx_lock, flags);
+			spin_unlock_bh(&p->tid_rx_lock);
 		}
 	}
 
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index f44b640..62dc241 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -166,12 +166,14 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
 
 static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
 			       u16 reason_code, bool from_event)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
 {
 	uint i;
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct wireless_dev *wdev = wil->wdev;
 	struct wil_sta_info *sta = &wil->sta[cid];
 
+	might_sleep();
 	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
 		     sta->status);
 
@@ -194,15 +196,14 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
 
 	for (i = 0; i < WIL_STA_TID_NUM; i++) {
 		struct wil_tid_ampdu_rx *r;
-		unsigned long flags;
 
-		spin_lock_irqsave(&sta->tid_rx_lock, flags);
+		spin_lock_bh(&sta->tid_rx_lock);
 
 		r = sta->tid_rx[i];
 		sta->tid_rx[i] = NULL;
 		wil_tid_ampdu_rx_free(wil, r);
 
-		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+		spin_unlock_bh(&sta->tid_rx_lock);
 	}
 	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
 		if (wil->vring2cid_tid[i][0] == cid)
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 5af8012..5522092 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -89,7 +89,9 @@ static void wil_reorder_release(struct wil6210_priv *wil,
 	}
 }
 
+/* called in NAPI context */
 void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct vring_rx_desc *d = wil_skb_rxdesc(skb);
@@ -102,7 +104,6 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
 	struct wil_tid_ampdu_rx *r;
 	u16 hseq;
 	int index;
-	unsigned long flags;
 
 	wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
 		     mid, cid, tid, seq, mcast);
@@ -112,13 +113,12 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
 		return;
 	}
 
-	spin_lock_irqsave(&sta->tid_rx_lock, flags);
+	spin_lock(&sta->tid_rx_lock);
 
 	r = sta->tid_rx[tid];
 	if (!r) {
-		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
 		wil_netif_rx_any(skb, ndev);
-		return;
+		goto out;
 	}
 
 	hseq = r->head_seq_num;
@@ -196,7 +196,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
 	wil_reorder_release(wil, r);
 
 out:
-	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+	spin_unlock(&sta->tid_rx_lock);
 }
 
 struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
@@ -276,6 +276,7 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
 
 static void wil_back_rx_handle(struct wil6210_priv *wil,
 			       struct wil_back_rx *req)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
 {
 	struct wil_sta_info *sta;
 	u8 cid, tid;
@@ -291,9 +292,9 @@ static void wil_back_rx_handle(struct wil6210_priv *wil,
 	u16 agg_timeout = req->ba_timeout;
 	u16 status = WLAN_STATUS_SUCCESS;
 	u16 ssn = req->ba_seq_ctrl >> 4;
-	unsigned long flags;
 	int rc;
 
+	might_sleep();
 	parse_cidxtid(req->cidxtid, &cid, &tid);
 
 	/* sanity checks */
@@ -327,12 +328,12 @@ static void wil_back_rx_handle(struct wil6210_priv *wil,
 		return;
 
 	/* apply */
-	spin_lock_irqsave(&sta->tid_rx_lock, flags);
+	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);
 
-	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+	spin_unlock_bh(&sta->tid_rx_lock);
 }
 
 void wil_back_rx_flush(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 432ec55..f3524a1 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -644,14 +644,15 @@ static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
 }
 
 static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
 {
 	struct wmi_delba_event *evt = d;
 	u8 cid, tid;
 	u16 reason = __le16_to_cpu(evt->reason);
 	struct wil_sta_info *sta;
 	struct wil_tid_ampdu_rx *r;
-	unsigned long flags;
 
+	might_sleep();
 	parse_cidxtid(evt->cidxtid, &cid, &tid);
 	wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
 		    cid, tid,
@@ -681,13 +682,13 @@ static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
 
 	sta = &wil->sta[cid];
 
-	spin_lock_irqsave(&sta->tid_rx_lock, flags);
+	spin_lock_bh(&sta->tid_rx_lock);
 
 	r = sta->tid_rx[tid];
 	sta->tid_rx[tid] = NULL;
 	wil_tid_ampdu_rx_free(wil, r);
 
-	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+	spin_unlock_bh(&sta->tid_rx_lock);
 }
 
 static const struct {
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH 17/22] wil6210: add advanced interrupt moderation
  2014-12-23  7:47 ` [PATCH 17/22] wil6210: add advanced interrupt moderation Vladimir Kondratiev
@ 2015-01-07  8:12   ` Kalle Valo
  2015-01-08 12:24     ` Vladimir Kondratiev
  0 siblings, 1 reply; 27+ messages in thread
From: Kalle Valo @ 2015-01-07  8:12 UTC (permalink / raw)
  To: Vladimir Kondratiev; +Cc: linux-wireless, wil6210

Vladimir Kondratiev <QCA_vkondrat@QCA.qualcomm.com> writes:

> Add advanced interrupt moderation support available since "Sparrow B0".
> Legacy interrupt moderation used only one counter to moderate tx, rx,
> and misc interrupts.
> Advanced interrupt moderation bypasses misc, and handles separately tx
> and rx interrupts. In addition it has two timers for each interrupt type.
> Max burst duration timer which defines how long to postpone interrupt after
> first event (receive event for rx and tx complete event for tx), and
> interframe timeout which defines how to determine the end of the burst and
> issue interrupt even if the first timer still pending.
> Capabilities flags in wil_priv is set on initialization according to
> HW. The rest of the code checks for advanced interrupt capability bit
> in capabilities flags field.
> Debugfs is split accordingly: "legacy" interrupt moderation remains
> unchanged, new debugs files added for advanced interrupt moderation
> support.
> Module params are aligned to support advanced interrupt moderation
> (tx & rx). When not available (for legacy interrupt moderation) will
> use only rx configuration; Tx configuration will be ignored in this
> case.
>
> Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>

[...]

> --- a/drivers/net/wireless/ath/wil6210/main.c
> +++ b/drivers/net/wireless/ath/wil6210/main.c
> @@ -33,10 +33,34 @@ 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 itr_trsh = WIL6210_ITR_TRSH_DEFAULT;
> +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.");
>  
> -module_param(itr_trsh, uint, S_IRUGO);
> -MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");

The number of module parameters feels a little excessive, especially
when you add one more in the following patch. Is it really necessary for
the user to configure all these? Why can't the driver pick good
defaults?

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 17/22] wil6210: add advanced interrupt moderation
  2015-01-07  8:12   ` Kalle Valo
@ 2015-01-08 12:24     ` Vladimir Kondratiev
  2015-01-15 12:15       ` Kalle Valo
  0 siblings, 1 reply; 27+ messages in thread
From: Vladimir Kondratiev @ 2015-01-08 12:24 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, wil6210

On 01/07/2015 10:12 AM, Kalle Valo wrote:
> The number of module parameters feels a little excessive, especially
> when you add one more in the following patch. Is it really necessary for
> the user to configure all these? Why can't the driver pick good
> defaults?

Unfortunately, all these are really tunable parameters that impact 
performance.
I also realized it is too much. If we will find appropriate defaults for 
some parameters, not requiting tuning, I'll upload patch removing it.

Thanks, Vladimir

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 17/22] wil6210: add advanced interrupt moderation
  2015-01-08 12:24     ` Vladimir Kondratiev
@ 2015-01-15 12:15       ` Kalle Valo
  0 siblings, 0 replies; 27+ messages in thread
From: Kalle Valo @ 2015-01-15 12:15 UTC (permalink / raw)
  To: Vladimir Kondratiev; +Cc: linux-wireless, wil6210

Vladimir Kondratiev <QCA_vkondrat@QCA.qualcomm.com> writes:

> On 01/07/2015 10:12 AM, Kalle Valo wrote:
>> The number of module parameters feels a little excessive, especially
>> when you add one more in the following patch. Is it really necessary for
>> the user to configure all these? Why can't the driver pick good
>> defaults?
>
> Unfortunately, all these are really tunable parameters that impact
> performance. I also realized it is too much. If we will find
> appropriate defaults for some parameters, not requiting tuning, I'll
> upload patch removing it.

Ok, fair enough. But in the future please try to think twice before
using module parameters. They should not be abused by having too many of
them.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 00/22] wil6210 patches
  2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
                   ` (21 preceding siblings ...)
  2014-12-23  7:47 ` [PATCH 22/22] wil6210: relax spinlocks in rx reorder Vladimir Kondratiev
@ 2015-01-15 12:37 ` Kalle Valo
  22 siblings, 0 replies; 27+ messages in thread
From: Kalle Valo @ 2015-01-15 12:37 UTC (permalink / raw)
  To: Vladimir Kondratiev; +Cc: linux-wireless, wil6210

Vladimir Kondratiev <QCA_vkondrat@QCA.qualcomm.com> writes:

> Several topics:
> - block ack with secure and insecure connection
> - MTU
> - some infrastructure fixes
> - some debugfs changes
>
> Vladimir Kondratiev (22):
>   wil6210: ADDBA/DELBA flows
>   wil6210: simple ADDBA on originator (Tx) side
>   wil6210: allow to configure ADDBA request
>   wil6210: improve debugfs for reorder buffer
>   wil6210: fix disconnect 1 STA in AP
>   wil6210: improve debugfs for VRING
>   wil6210: control AMSDU on Tx side of Block Ack
>   wil6210: delba for responder
>   wil6210: fix max. MPDU size
>   wil6210: consider SNAP header in MTU calculations
>   wil6210: Increase number of associated stations
>   wil6210: use bitmap API for "status"
>   wil6210: fix Tx VRING for STA mode
>   wil6210: rework debugfs for BACK
>   wil6210: detect HW capabilities
>   wil6210: use HW capabilities mask in reset
>   wil6210: add advanced interrupt moderation
>   wil6210: RX high threshold interrupt configuration
>   wil6210: fix reordering for MCAST
>   wil6210: Tx/Rx descriptors documentation
>   wil6210: workaround for BACK establishment race
>   wil6210: relax spinlocks in rx reorder

Thanks, all 22 applied.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2015-01-15 12:37 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-23  7:47 [PATCH 00/22] wil6210 patches Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 01/22] wil6210: ADDBA/DELBA flows Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 02/22] wil6210: simple ADDBA on originator (Tx) side Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 03/22] wil6210: allow to configure ADDBA request Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 04/22] wil6210: improve debugfs for reorder buffer Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 05/22] wil6210: fix disconnect 1 STA in AP Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 06/22] wil6210: improve debugfs for VRING Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 07/22] wil6210: control AMSDU on Tx side of Block Ack Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 08/22] wil6210: delba for responder Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 09/22] wil6210: fix max. MPDU size Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 10/22] wil6210: consider SNAP header in MTU calculations Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 11/22] wil6210: Increase number of associated stations Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 12/22] wil6210: use bitmap API for "status" Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 13/22] wil6210: fix Tx VRING for STA mode Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 14/22] wil6210: rework debugfs for BACK Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 15/22] wil6210: detect HW capabilities Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 16/22] wil6210: use HW capabilities mask in reset Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 17/22] wil6210: add advanced interrupt moderation Vladimir Kondratiev
2015-01-07  8:12   ` Kalle Valo
2015-01-08 12:24     ` Vladimir Kondratiev
2015-01-15 12:15       ` Kalle Valo
2014-12-23  7:47 ` [PATCH 18/22] wil6210: RX high threshold interrupt configuration Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 19/22] wil6210: fix reordering for MCAST Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 20/22] wil6210: Tx/Rx descriptors documentation Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 21/22] wil6210: workaround for BACK establishment race Vladimir Kondratiev
2014-12-23  7:47 ` [PATCH 22/22] wil6210: relax spinlocks in rx reorder Vladimir Kondratiev
2015-01-15 12:37 ` [PATCH 00/22] wil6210 patches Kalle Valo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.