All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] ath10k: add basic tdls support
@ 2015-02-25  7:55 ` Marek Puzyniak
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Puzyniak

This patchset introduces tdls funtionality without tdls peer uapsd
and tdls channel switching. Tdls is supported by qca6174 hardware
what is indicated by firmware through supported services.
Tdls station when authorized requires some parameters that are filled in
by rate control initialization. Because of that this patches contains
one patch for mac80211 which moves rate control initialization before
calling drivers station state with transition to authorized state.

v2:
-introduce tdls peer counter
-minor changes after review

Marek Puzyniak (3):
  ath10k: make peer type configurable
  mac80211: initialize rate control earlier for tdls station
  ath10k: introduce basic tdls functionality

Michal Kazior (1):
  ath10k: unify tx mode and dispatch

 drivers/net/wireless/ath/ath10k/core.h    |   3 +
 drivers/net/wireless/ath/ath10k/htt_rx.c  |   8 -
 drivers/net/wireless/ath/ath10k/htt_tx.c  |  30 ++-
 drivers/net/wireless/ath/ath10k/mac.c     | 307 +++++++++++++++++++++++++-----
 drivers/net/wireless/ath/ath10k/mac.h     |   8 +
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  50 ++++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 157 ++++++++++++++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.h |  52 +++++
 drivers/net/wireless/ath/ath10k/wmi.c     |   3 +-
 drivers/net/wireless/ath/ath10k/wmi.h     |  43 +++++
 net/mac80211/cfg.c                        |  20 +-
 11 files changed, 597 insertions(+), 84 deletions(-)

-- 
2.1.4


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

* [PATCH v2 0/4] ath10k: add basic tdls support
@ 2015-02-25  7:55 ` Marek Puzyniak
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Puzyniak

This patchset introduces tdls funtionality without tdls peer uapsd
and tdls channel switching. Tdls is supported by qca6174 hardware
what is indicated by firmware through supported services.
Tdls station when authorized requires some parameters that are filled in
by rate control initialization. Because of that this patches contains
one patch for mac80211 which moves rate control initialization before
calling drivers station state with transition to authorized state.

v2:
-introduce tdls peer counter
-minor changes after review

Marek Puzyniak (3):
  ath10k: make peer type configurable
  mac80211: initialize rate control earlier for tdls station
  ath10k: introduce basic tdls functionality

Michal Kazior (1):
  ath10k: unify tx mode and dispatch

 drivers/net/wireless/ath/ath10k/core.h    |   3 +
 drivers/net/wireless/ath/ath10k/htt_rx.c  |   8 -
 drivers/net/wireless/ath/ath10k/htt_tx.c  |  30 ++-
 drivers/net/wireless/ath/ath10k/mac.c     | 307 +++++++++++++++++++++++++-----
 drivers/net/wireless/ath/ath10k/mac.h     |   8 +
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  50 ++++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 157 ++++++++++++++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.h |  52 +++++
 drivers/net/wireless/ath/ath10k/wmi.c     |   3 +-
 drivers/net/wireless/ath/ath10k/wmi.h     |  43 +++++
 net/mac80211/cfg.c                        |  20 +-
 11 files changed, 597 insertions(+), 84 deletions(-)

-- 
2.1.4


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* [PATCH v2 1/4] ath10k: unify tx mode and dispatch
  2015-02-25  7:55 ` Marek Puzyniak
@ 2015-02-25  7:55   ` Marek Puzyniak
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Michal Kazior, Marek Puzyniak

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

There are a few different tx paths depending on
firmware and frame itself.

Creating a uniform decision will make it possible
to switch between different txmode easier, both
for testing and for future features as well.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h   |   2 +
 drivers/net/wireless/ath/ath10k/htt_rx.c |   8 --
 drivers/net/wireless/ath/ath10k/htt_tx.c |  30 +++---
 drivers/net/wireless/ath/ath10k/mac.c    | 155 ++++++++++++++++++++++++-------
 drivers/net/wireless/ath/ath10k/mac.h    |   8 ++
 5 files changed, 144 insertions(+), 59 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index d60e46f..94a8788 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -82,6 +82,8 @@ struct ath10k_skb_cb {
 	dma_addr_t paddr;
 	u8 eid;
 	u8 vdev_id;
+	enum ath10k_hw_txrx_mode txmode;
+	bool is_protected;
 
 	struct {
 		u8 tid;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index c1da44f..6d4bb5e 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -637,14 +637,6 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
 	return 0;
 }
 
-struct rfc1042_hdr {
-	u8 llc_dsap;
-	u8 llc_ssap;
-	u8 llc_ctrl;
-	u8 snap_oui[3];
-	__be16 snap_type;
-} __packed;
-
 struct amsdu_subframe_hdr {
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index cbd2bc9..5b2c61b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -420,9 +420,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	int res;
 	u8 flags0 = 0;
 	u16 msdu_id, flags1 = 0;
-	dma_addr_t paddr;
-	u32 frags_paddr;
-	bool use_frags;
+	dma_addr_t paddr = 0;
+	u32 frags_paddr = 0;
 
 	res = ath10k_htt_tx_inc_pending(htt);
 	if (res)
@@ -440,12 +439,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	prefetch_len = min(htt->prefetch_len, msdu->len);
 	prefetch_len = roundup(prefetch_len, 4);
 
-	/* Since HTT 3.0 there is no separate mgmt tx command. However in case
-	 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
-	 * fragment list host driver specifies directly frame pointer. */
-	use_frags = htt->target_version_major < 3 ||
-		    !ieee80211_is_mgmt(hdr->frame_control);
-
 	skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
 					   &paddr);
 	if (!skb_cb->htt.txbuf) {
@@ -466,7 +459,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	if (res)
 		goto err_free_txbuf;
 
-	if (likely(use_frags)) {
+	switch (skb_cb->txmode) {
+	case ATH10K_HW_TXRX_RAW:
+	case ATH10K_HW_TXRX_NATIVE_WIFI:
+		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+		/* pass through */
+	case ATH10K_HW_TXRX_ETHERNET:
 		frags = skb_cb->htt.txbuf->frags;
 
 		frags[0].paddr = __cpu_to_le32(skb_cb->paddr);
@@ -474,15 +472,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 		frags[1].paddr = 0;
 		frags[1].len = 0;
 
-		flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
-			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+		flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
 
 		frags_paddr = skb_cb->htt.txbuf_paddr;
-	} else {
+		break;
+	case ATH10K_HW_TXRX_MGMT:
 		flags0 |= SM(ATH10K_HW_TXRX_MGMT,
 			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
 
 		frags_paddr = skb_cb->paddr;
+		break;
 	}
 
 	/* Normally all commands go through HTC which manages tx credits for
@@ -508,11 +508,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 			prefetch_len);
 	skb_cb->htt.txbuf->htc_hdr.flags = 0;
 
-	if (!ieee80211_has_protected(hdr->frame_control))
+	if (!skb_cb->is_protected)
 		flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
 
-	flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
-
 	flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
 	flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
 	if (msdu->ip_summed == CHECKSUM_PARTIAL) {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index d6d2f0f..6d126d0 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2182,6 +2182,43 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
 	return 0;
 }
 
+static enum ath10k_hw_txrx_mode
+ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
+		       struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr = (void *)skb->data;
+	__le16 fc = hdr->frame_control;
+
+	if (!vif || vif->type == NL80211_IFTYPE_MONITOR)
+		return ATH10K_HW_TXRX_RAW;
+
+	if (ieee80211_is_mgmt(fc))
+		return ATH10K_HW_TXRX_MGMT;
+
+	/* Workaround:
+	 *
+	 * NullFunc frames are mostly used to ping if a client or AP are still
+	 * reachable and responsive. This implies tx status reports must be
+	 * accurate - otherwise either mac80211 or userspace (e.g. hostapd) can
+	 * come to a conclusion that the other end disappeared and tear down
+	 * BSS connection or it can never disconnect from BSS/client (which is
+	 * the case).
+	 *
+	 * Firmware with HTT older than 3.0 delivers incorrect tx status for
+	 * NullFunc frames to driver. However there's a HTT Mgmt Tx command
+	 * which seems to deliver correct tx reports for NullFunc frames. The
+	 * downside of using it is it ignores client powersave state so it can
+	 * end up disconnecting sleeping clients in AP mode. It should fix STA
+	 * mode though because AP don't sleep.
+	 */
+	if (ar->htt.target_version_major < 3 &&
+	    (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
+	    !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features))
+		return ATH10K_HW_TXRX_MGMT;
+
+	return ATH10K_HW_TXRX_NATIVE_WIFI;
+}
+
 /* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS
  * Control in the header.
  */
@@ -2211,6 +2248,33 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
 	}
 }
 
+static void ath10k_tx_h_8023(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr;
+	struct rfc1042_hdr *rfc1042;
+	struct ethhdr *eth;
+	size_t hdrlen;
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
+	__be16 type;
+
+	hdr = (void *)skb->data;
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	rfc1042 = (void *)skb->data + hdrlen;
+
+	ether_addr_copy(da, ieee80211_get_DA(hdr));
+	ether_addr_copy(sa, ieee80211_get_SA(hdr));
+	type = rfc1042->snap_type;
+
+	skb_pull(skb, hdrlen + sizeof(*rfc1042));
+	skb_push(skb, sizeof(*eth));
+
+	eth = (void *)skb->data;
+	ether_addr_copy(eth->h_dest, da);
+	ether_addr_copy(eth->h_source, sa);
+	eth->h_proto = type;
+}
+
 static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
 				       struct ieee80211_vif *vif,
 				       struct sk_buff *skb)
@@ -2247,45 +2311,51 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
 		 ar->htt.target_version_minor >= 4);
 }
 
-static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue;
 	int ret = 0;
 
-	if (ar->htt.target_version_major >= 3) {
-		/* Since HTT 3.0 there is no separate mgmt tx command */
-		ret = ath10k_htt_tx(&ar->htt, skb);
-		goto exit;
+	spin_lock_bh(&ar->data_lock);
+
+	if (skb_queue_len(q) == ATH10K_MAX_NUM_MGMT_PENDING) {
+		ath10k_warn(ar, "wmi mgmt tx queue is full\n");
+		ret = -ENOSPC;
+		goto unlock;
 	}
 
-	if (ieee80211_is_mgmt(hdr->frame_control)) {
-		if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
-			     ar->fw_features)) {
-			if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
-			    ATH10K_MAX_NUM_MGMT_PENDING) {
-				ath10k_warn(ar, "reached WMI management transmit queue limit\n");
-				ret = -EBUSY;
-				goto exit;
-			}
+	__skb_queue_tail(q, skb);
+	ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
 
-			skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb);
-			ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
-		} else {
-			ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
-		}
-	} else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
-			     ar->fw_features) &&
-		   ieee80211_is_nullfunc(hdr->frame_control)) {
-		/* FW does not report tx status properly for NullFunc frames
-		 * unless they are sent through mgmt tx path. mac80211 sends
-		 * those frames when it detects link/beacon loss and depends
-		 * on the tx status to be correct. */
-		ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
-	} else {
-		ret = ath10k_htt_tx(&ar->htt, skb);
+unlock:
+	spin_unlock_bh(&ar->data_lock);
+
+	return ret;
+}
+
+static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
+{
+	struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
+	struct ath10k_htt *htt = &ar->htt;
+	int ret = 0;
+
+	switch (cb->txmode) {
+	case ATH10K_HW_TXRX_RAW:
+	case ATH10K_HW_TXRX_NATIVE_WIFI:
+	case ATH10K_HW_TXRX_ETHERNET:
+		ret = ath10k_htt_tx(htt, skb);
+		break;
+	case ATH10K_HW_TXRX_MGMT:
+		if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
+			     ar->fw_features))
+			ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
+		else if (ar->htt.target_version_major >= 3)
+			ret = ath10k_htt_tx(htt, skb);
+		else
+			ret = ath10k_htt_mgmt_tx(htt, skb);
+		break;
 	}
 
-exit:
 	if (ret) {
 		ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
 			    ret);
@@ -2358,7 +2428,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 		ar->offchan_tx_skb = skb;
 		spin_unlock_bh(&ar->data_lock);
 
-		ath10k_tx_htt(ar, skb);
+		ath10k_mac_tx(ar, skb);
 
 		ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
 						  3 * HZ);
@@ -2572,6 +2642,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_vif *vif = info->control.vif;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	__le16 fc = hdr->frame_control;
 
 	/* We should disable CCK RATE due to P2P */
 	if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
@@ -2580,12 +2651,26 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	ATH10K_SKB_CB(skb)->htt.is_offchan = false;
 	ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
 	ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
+	ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, skb);
+	ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
 
-	/* it makes no sense to process injected frames like that */
-	if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
+	switch (ATH10K_SKB_CB(skb)->txmode) {
+	case ATH10K_HW_TXRX_MGMT:
+	case ATH10K_HW_TXRX_NATIVE_WIFI:
 		ath10k_tx_h_nwifi(hw, skb);
 		ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
 		ath10k_tx_h_seq_no(vif, skb);
+		break;
+	case ATH10K_HW_TXRX_ETHERNET:
+		ath10k_tx_h_8023(skb);
+		break;
+	case ATH10K_HW_TXRX_RAW:
+		/* FIXME: Packet injection isn't implemented. It should be
+		 * doable with firmware 10.2 on qca988x.
+		 */
+		WARN_ON_ONCE(1);
+		ieee80211_free_txskb(hw, skb);
+		return;
 	}
 
 	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
@@ -2607,7 +2692,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 		}
 	}
 
-	ath10k_tx_htt(ar, skb);
+	ath10k_mac_tx(ar, skb);
 }
 
 /* Must not be called with conf_mutex held as workers can use that also. */
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 6829611..7b63def 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -28,6 +28,14 @@ struct ath10k_generic_iter {
 	int ret;
 };
 
+struct rfc1042_hdr {
+	u8 llc_dsap;
+	u8 llc_ssap;
+	u8 llc_ctrl;
+	u8 snap_oui[3];
+	__be16 snap_type;
+} __packed;
+
 struct ath10k *ath10k_mac_create(size_t priv_size);
 void ath10k_mac_destroy(struct ath10k *ar);
 int ath10k_mac_register(struct ath10k *ar);
-- 
2.1.4


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

* [PATCH v2 1/4] ath10k: unify tx mode and dispatch
@ 2015-02-25  7:55   ` Marek Puzyniak
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Puzyniak, Michal Kazior

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

There are a few different tx paths depending on
firmware and frame itself.

Creating a uniform decision will make it possible
to switch between different txmode easier, both
for testing and for future features as well.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h   |   2 +
 drivers/net/wireless/ath/ath10k/htt_rx.c |   8 --
 drivers/net/wireless/ath/ath10k/htt_tx.c |  30 +++---
 drivers/net/wireless/ath/ath10k/mac.c    | 155 ++++++++++++++++++++++++-------
 drivers/net/wireless/ath/ath10k/mac.h    |   8 ++
 5 files changed, 144 insertions(+), 59 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index d60e46f..94a8788 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -82,6 +82,8 @@ struct ath10k_skb_cb {
 	dma_addr_t paddr;
 	u8 eid;
 	u8 vdev_id;
+	enum ath10k_hw_txrx_mode txmode;
+	bool is_protected;
 
 	struct {
 		u8 tid;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index c1da44f..6d4bb5e 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -637,14 +637,6 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
 	return 0;
 }
 
-struct rfc1042_hdr {
-	u8 llc_dsap;
-	u8 llc_ssap;
-	u8 llc_ctrl;
-	u8 snap_oui[3];
-	__be16 snap_type;
-} __packed;
-
 struct amsdu_subframe_hdr {
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index cbd2bc9..5b2c61b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -420,9 +420,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	int res;
 	u8 flags0 = 0;
 	u16 msdu_id, flags1 = 0;
-	dma_addr_t paddr;
-	u32 frags_paddr;
-	bool use_frags;
+	dma_addr_t paddr = 0;
+	u32 frags_paddr = 0;
 
 	res = ath10k_htt_tx_inc_pending(htt);
 	if (res)
@@ -440,12 +439,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	prefetch_len = min(htt->prefetch_len, msdu->len);
 	prefetch_len = roundup(prefetch_len, 4);
 
-	/* Since HTT 3.0 there is no separate mgmt tx command. However in case
-	 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
-	 * fragment list host driver specifies directly frame pointer. */
-	use_frags = htt->target_version_major < 3 ||
-		    !ieee80211_is_mgmt(hdr->frame_control);
-
 	skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
 					   &paddr);
 	if (!skb_cb->htt.txbuf) {
@@ -466,7 +459,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	if (res)
 		goto err_free_txbuf;
 
-	if (likely(use_frags)) {
+	switch (skb_cb->txmode) {
+	case ATH10K_HW_TXRX_RAW:
+	case ATH10K_HW_TXRX_NATIVE_WIFI:
+		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+		/* pass through */
+	case ATH10K_HW_TXRX_ETHERNET:
 		frags = skb_cb->htt.txbuf->frags;
 
 		frags[0].paddr = __cpu_to_le32(skb_cb->paddr);
@@ -474,15 +472,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 		frags[1].paddr = 0;
 		frags[1].len = 0;
 
-		flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
-			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+		flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
 
 		frags_paddr = skb_cb->htt.txbuf_paddr;
-	} else {
+		break;
+	case ATH10K_HW_TXRX_MGMT:
 		flags0 |= SM(ATH10K_HW_TXRX_MGMT,
 			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
 
 		frags_paddr = skb_cb->paddr;
+		break;
 	}
 
 	/* Normally all commands go through HTC which manages tx credits for
@@ -508,11 +508,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 			prefetch_len);
 	skb_cb->htt.txbuf->htc_hdr.flags = 0;
 
-	if (!ieee80211_has_protected(hdr->frame_control))
+	if (!skb_cb->is_protected)
 		flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
 
-	flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
-
 	flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
 	flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
 	if (msdu->ip_summed == CHECKSUM_PARTIAL) {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index d6d2f0f..6d126d0 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2182,6 +2182,43 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
 	return 0;
 }
 
+static enum ath10k_hw_txrx_mode
+ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
+		       struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr = (void *)skb->data;
+	__le16 fc = hdr->frame_control;
+
+	if (!vif || vif->type == NL80211_IFTYPE_MONITOR)
+		return ATH10K_HW_TXRX_RAW;
+
+	if (ieee80211_is_mgmt(fc))
+		return ATH10K_HW_TXRX_MGMT;
+
+	/* Workaround:
+	 *
+	 * NullFunc frames are mostly used to ping if a client or AP are still
+	 * reachable and responsive. This implies tx status reports must be
+	 * accurate - otherwise either mac80211 or userspace (e.g. hostapd) can
+	 * come to a conclusion that the other end disappeared and tear down
+	 * BSS connection or it can never disconnect from BSS/client (which is
+	 * the case).
+	 *
+	 * Firmware with HTT older than 3.0 delivers incorrect tx status for
+	 * NullFunc frames to driver. However there's a HTT Mgmt Tx command
+	 * which seems to deliver correct tx reports for NullFunc frames. The
+	 * downside of using it is it ignores client powersave state so it can
+	 * end up disconnecting sleeping clients in AP mode. It should fix STA
+	 * mode though because AP don't sleep.
+	 */
+	if (ar->htt.target_version_major < 3 &&
+	    (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
+	    !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features))
+		return ATH10K_HW_TXRX_MGMT;
+
+	return ATH10K_HW_TXRX_NATIVE_WIFI;
+}
+
 /* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS
  * Control in the header.
  */
@@ -2211,6 +2248,33 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
 	}
 }
 
+static void ath10k_tx_h_8023(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr;
+	struct rfc1042_hdr *rfc1042;
+	struct ethhdr *eth;
+	size_t hdrlen;
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
+	__be16 type;
+
+	hdr = (void *)skb->data;
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	rfc1042 = (void *)skb->data + hdrlen;
+
+	ether_addr_copy(da, ieee80211_get_DA(hdr));
+	ether_addr_copy(sa, ieee80211_get_SA(hdr));
+	type = rfc1042->snap_type;
+
+	skb_pull(skb, hdrlen + sizeof(*rfc1042));
+	skb_push(skb, sizeof(*eth));
+
+	eth = (void *)skb->data;
+	ether_addr_copy(eth->h_dest, da);
+	ether_addr_copy(eth->h_source, sa);
+	eth->h_proto = type;
+}
+
 static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
 				       struct ieee80211_vif *vif,
 				       struct sk_buff *skb)
@@ -2247,45 +2311,51 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
 		 ar->htt.target_version_minor >= 4);
 }
 
-static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue;
 	int ret = 0;
 
-	if (ar->htt.target_version_major >= 3) {
-		/* Since HTT 3.0 there is no separate mgmt tx command */
-		ret = ath10k_htt_tx(&ar->htt, skb);
-		goto exit;
+	spin_lock_bh(&ar->data_lock);
+
+	if (skb_queue_len(q) == ATH10K_MAX_NUM_MGMT_PENDING) {
+		ath10k_warn(ar, "wmi mgmt tx queue is full\n");
+		ret = -ENOSPC;
+		goto unlock;
 	}
 
-	if (ieee80211_is_mgmt(hdr->frame_control)) {
-		if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
-			     ar->fw_features)) {
-			if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
-			    ATH10K_MAX_NUM_MGMT_PENDING) {
-				ath10k_warn(ar, "reached WMI management transmit queue limit\n");
-				ret = -EBUSY;
-				goto exit;
-			}
+	__skb_queue_tail(q, skb);
+	ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
 
-			skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb);
-			ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
-		} else {
-			ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
-		}
-	} else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
-			     ar->fw_features) &&
-		   ieee80211_is_nullfunc(hdr->frame_control)) {
-		/* FW does not report tx status properly for NullFunc frames
-		 * unless they are sent through mgmt tx path. mac80211 sends
-		 * those frames when it detects link/beacon loss and depends
-		 * on the tx status to be correct. */
-		ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
-	} else {
-		ret = ath10k_htt_tx(&ar->htt, skb);
+unlock:
+	spin_unlock_bh(&ar->data_lock);
+
+	return ret;
+}
+
+static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
+{
+	struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
+	struct ath10k_htt *htt = &ar->htt;
+	int ret = 0;
+
+	switch (cb->txmode) {
+	case ATH10K_HW_TXRX_RAW:
+	case ATH10K_HW_TXRX_NATIVE_WIFI:
+	case ATH10K_HW_TXRX_ETHERNET:
+		ret = ath10k_htt_tx(htt, skb);
+		break;
+	case ATH10K_HW_TXRX_MGMT:
+		if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
+			     ar->fw_features))
+			ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
+		else if (ar->htt.target_version_major >= 3)
+			ret = ath10k_htt_tx(htt, skb);
+		else
+			ret = ath10k_htt_mgmt_tx(htt, skb);
+		break;
 	}
 
-exit:
 	if (ret) {
 		ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
 			    ret);
@@ -2358,7 +2428,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 		ar->offchan_tx_skb = skb;
 		spin_unlock_bh(&ar->data_lock);
 
-		ath10k_tx_htt(ar, skb);
+		ath10k_mac_tx(ar, skb);
 
 		ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
 						  3 * HZ);
@@ -2572,6 +2642,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_vif *vif = info->control.vif;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	__le16 fc = hdr->frame_control;
 
 	/* We should disable CCK RATE due to P2P */
 	if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
@@ -2580,12 +2651,26 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	ATH10K_SKB_CB(skb)->htt.is_offchan = false;
 	ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
 	ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
+	ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, skb);
+	ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
 
-	/* it makes no sense to process injected frames like that */
-	if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
+	switch (ATH10K_SKB_CB(skb)->txmode) {
+	case ATH10K_HW_TXRX_MGMT:
+	case ATH10K_HW_TXRX_NATIVE_WIFI:
 		ath10k_tx_h_nwifi(hw, skb);
 		ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
 		ath10k_tx_h_seq_no(vif, skb);
+		break;
+	case ATH10K_HW_TXRX_ETHERNET:
+		ath10k_tx_h_8023(skb);
+		break;
+	case ATH10K_HW_TXRX_RAW:
+		/* FIXME: Packet injection isn't implemented. It should be
+		 * doable with firmware 10.2 on qca988x.
+		 */
+		WARN_ON_ONCE(1);
+		ieee80211_free_txskb(hw, skb);
+		return;
 	}
 
 	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
@@ -2607,7 +2692,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 		}
 	}
 
-	ath10k_tx_htt(ar, skb);
+	ath10k_mac_tx(ar, skb);
 }
 
 /* Must not be called with conf_mutex held as workers can use that also. */
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 6829611..7b63def 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -28,6 +28,14 @@ struct ath10k_generic_iter {
 	int ret;
 };
 
+struct rfc1042_hdr {
+	u8 llc_dsap;
+	u8 llc_ssap;
+	u8 llc_ctrl;
+	u8 snap_oui[3];
+	__be16 snap_type;
+} __packed;
+
 struct ath10k *ath10k_mac_create(size_t priv_size);
 void ath10k_mac_destroy(struct ath10k *ar);
 int ath10k_mac_register(struct ath10k *ar);
-- 
2.1.4


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* [PATCH v2 2/4] ath10k: make peer type configurable
  2015-02-25  7:55 ` Marek Puzyniak
@ 2015-02-25  7:55   ` Marek Puzyniak
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Puzyniak, Marek Kwaczynski

Peer type was hardcoded to default value.
For future implementation it is required
to make is configurable.

Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
Signed-off-by: Marek Kwaczynski <marek.kwaczynski@tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c     | 17 +++++++++++------
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  8 +++++---
 drivers/net/wireless/ath/ath10k/wmi-tlv.c |  5 +++--
 drivers/net/wireless/ath/ath10k/wmi.c     |  3 ++-
 drivers/net/wireless/ath/ath10k/wmi.h     |  6 ++++++
 5 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 6d126d0..7378656 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -364,7 +364,8 @@ static u8 ath10k_parse_mpdudensity(u8 mpdudensity)
 	}
 }
 
-static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr,
+			      enum wmi_peer_type peer_type)
 {
 	int ret;
 
@@ -373,7 +374,7 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 	if (ar->num_peers >= ar->max_num_peers)
 		return -ENOBUFS;
 
-	ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
+	ret = ath10k_wmi_peer_create(ar, vdev_id, addr, peer_type);
 	if (ret) {
 		ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
 			    addr, vdev_id, ret);
@@ -1187,7 +1188,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
 		return;
 	}
 
-	ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
+	ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer,
+				 WMI_PEER_TYPE_DEFAULT);
 	if (ret) {
 		ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
 			    self_peer, arvif->vdev_id, ret);
@@ -2417,7 +2419,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 				   peer_addr, vdev_id);
 
 		if (!peer) {
-			ret = ath10k_peer_create(ar, vdev_id, peer_addr);
+			ret = ath10k_peer_create(ar, vdev_id, peer_addr,
+						 WMI_PEER_TYPE_DEFAULT);
 			if (ret)
 				ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
 					    peer_addr, vdev_id, ret);
@@ -3300,7 +3303,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 	}
 
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
-		ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
+		ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr,
+					 WMI_PEER_TYPE_DEFAULT);
 		if (ret) {
 			ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
 				    arvif->vdev_id, ret);
@@ -4023,7 +4027,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			goto exit;
 		}
 
-		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
+		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr,
+					 WMI_PEER_TYPE_DEFAULT);
 		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 04dc4b9..a2cded8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -81,7 +81,8 @@ struct wmi_ops {
 	struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id,
 					     const struct wmi_wmm_params_all_arg *arg);
 	struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id,
-					   const u8 peer_addr[ETH_ALEN]);
+					   const u8 peer_addr[ETH_ALEN],
+					   enum wmi_peer_type peer_type);
 	struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id,
 					   const u8 peer_addr[ETH_ALEN]);
 	struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id,
@@ -625,14 +626,15 @@ ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
 
 static inline int
 ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
-		       const u8 peer_addr[ETH_ALEN])
+		       const u8 peer_addr[ETH_ALEN],
+		       enum wmi_peer_type peer_type)
 {
 	struct sk_buff *skb;
 
 	if (!ar->wmi.ops->gen_peer_create)
 		return -EOPNOTSUPP;
 
-	skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr);
+	skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr, peer_type);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 71614ba..809c046 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1681,7 +1681,8 @@ ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar,
 
 static struct sk_buff *
 ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
-				  const u8 peer_addr[ETH_ALEN])
+				  const u8 peer_addr[ETH_ALEN],
+				  enum wmi_peer_type peer_type)
 {
 	struct wmi_tlv_peer_create_cmd *cmd;
 	struct wmi_tlv *tlv;
@@ -1696,7 +1697,7 @@ ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
 	tlv->len = __cpu_to_le16(sizeof(*cmd));
 	cmd = (void *)tlv->value;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
-	cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */
+	cmd->peer_type = __cpu_to_le32(peer_type);
 	ether_addr_copy(cmd->peer_addr.addr, peer_addr);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n");
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index aeea1c7..b285291 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4519,7 +4519,8 @@ ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id,
 
 static struct sk_buff *
 ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
-			      const u8 peer_addr[ETH_ALEN])
+			      const u8 peer_addr[ETH_ALEN],
+			      enum wmi_peer_type peer_type)
 {
 	struct wmi_peer_create_cmd *cmd;
 	struct sk_buff *skb;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 20ce360..0ffa90a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4324,6 +4324,12 @@ struct wmi_peer_create_cmd {
 	struct wmi_mac_addr peer_macaddr;
 } __packed;
 
+enum wmi_peer_type {
+	WMI_PEER_TYPE_DEFAULT = 0,
+	WMI_PEER_TYPE_BSS = 1,
+	WMI_PEER_TYPE_TDLS = 2,
+};
+
 struct wmi_peer_delete_cmd {
 	__le32 vdev_id;
 	struct wmi_mac_addr peer_macaddr;
-- 
2.1.4


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

* [PATCH v2 2/4] ath10k: make peer type configurable
@ 2015-02-25  7:55   ` Marek Puzyniak
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Kwaczynski, Marek Puzyniak

Peer type was hardcoded to default value.
For future implementation it is required
to make is configurable.

Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
Signed-off-by: Marek Kwaczynski <marek.kwaczynski@tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c     | 17 +++++++++++------
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  8 +++++---
 drivers/net/wireless/ath/ath10k/wmi-tlv.c |  5 +++--
 drivers/net/wireless/ath/ath10k/wmi.c     |  3 ++-
 drivers/net/wireless/ath/ath10k/wmi.h     |  6 ++++++
 5 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 6d126d0..7378656 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -364,7 +364,8 @@ static u8 ath10k_parse_mpdudensity(u8 mpdudensity)
 	}
 }
 
-static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr,
+			      enum wmi_peer_type peer_type)
 {
 	int ret;
 
@@ -373,7 +374,7 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 	if (ar->num_peers >= ar->max_num_peers)
 		return -ENOBUFS;
 
-	ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
+	ret = ath10k_wmi_peer_create(ar, vdev_id, addr, peer_type);
 	if (ret) {
 		ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
 			    addr, vdev_id, ret);
@@ -1187,7 +1188,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
 		return;
 	}
 
-	ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
+	ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer,
+				 WMI_PEER_TYPE_DEFAULT);
 	if (ret) {
 		ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
 			    self_peer, arvif->vdev_id, ret);
@@ -2417,7 +2419,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 				   peer_addr, vdev_id);
 
 		if (!peer) {
-			ret = ath10k_peer_create(ar, vdev_id, peer_addr);
+			ret = ath10k_peer_create(ar, vdev_id, peer_addr,
+						 WMI_PEER_TYPE_DEFAULT);
 			if (ret)
 				ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
 					    peer_addr, vdev_id, ret);
@@ -3300,7 +3303,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 	}
 
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
-		ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
+		ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr,
+					 WMI_PEER_TYPE_DEFAULT);
 		if (ret) {
 			ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
 				    arvif->vdev_id, ret);
@@ -4023,7 +4027,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			goto exit;
 		}
 
-		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
+		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr,
+					 WMI_PEER_TYPE_DEFAULT);
 		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 04dc4b9..a2cded8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -81,7 +81,8 @@ struct wmi_ops {
 	struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id,
 					     const struct wmi_wmm_params_all_arg *arg);
 	struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id,
-					   const u8 peer_addr[ETH_ALEN]);
+					   const u8 peer_addr[ETH_ALEN],
+					   enum wmi_peer_type peer_type);
 	struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id,
 					   const u8 peer_addr[ETH_ALEN]);
 	struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id,
@@ -625,14 +626,15 @@ ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
 
 static inline int
 ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
-		       const u8 peer_addr[ETH_ALEN])
+		       const u8 peer_addr[ETH_ALEN],
+		       enum wmi_peer_type peer_type)
 {
 	struct sk_buff *skb;
 
 	if (!ar->wmi.ops->gen_peer_create)
 		return -EOPNOTSUPP;
 
-	skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr);
+	skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr, peer_type);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 71614ba..809c046 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1681,7 +1681,8 @@ ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar,
 
 static struct sk_buff *
 ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
-				  const u8 peer_addr[ETH_ALEN])
+				  const u8 peer_addr[ETH_ALEN],
+				  enum wmi_peer_type peer_type)
 {
 	struct wmi_tlv_peer_create_cmd *cmd;
 	struct wmi_tlv *tlv;
@@ -1696,7 +1697,7 @@ ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
 	tlv->len = __cpu_to_le16(sizeof(*cmd));
 	cmd = (void *)tlv->value;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
-	cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */
+	cmd->peer_type = __cpu_to_le32(peer_type);
 	ether_addr_copy(cmd->peer_addr.addr, peer_addr);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n");
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index aeea1c7..b285291 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4519,7 +4519,8 @@ ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id,
 
 static struct sk_buff *
 ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
-			      const u8 peer_addr[ETH_ALEN])
+			      const u8 peer_addr[ETH_ALEN],
+			      enum wmi_peer_type peer_type)
 {
 	struct wmi_peer_create_cmd *cmd;
 	struct sk_buff *skb;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 20ce360..0ffa90a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4324,6 +4324,12 @@ struct wmi_peer_create_cmd {
 	struct wmi_mac_addr peer_macaddr;
 } __packed;
 
+enum wmi_peer_type {
+	WMI_PEER_TYPE_DEFAULT = 0,
+	WMI_PEER_TYPE_BSS = 1,
+	WMI_PEER_TYPE_TDLS = 2,
+};
+
 struct wmi_peer_delete_cmd {
 	__le32 vdev_id;
 	struct wmi_mac_addr peer_macaddr;
-- 
2.1.4


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-02-25  7:55 ` Marek Puzyniak
@ 2015-02-25  7:55   ` Marek Puzyniak
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Puzyniak

Currently when TDLS station in driver goes from assoc
to authorized state it can not use rate control parameters
because rate control is not initialized yet. Some drivers
require parameters already initialized by rate control when
entering authorized state. It can be done by initializing
rate control after station transition to authorized state
but before notifying driver about that.

Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
---
 net/mac80211/cfg.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index dd4ff36..ae24ed3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -983,12 +983,21 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
 	}
 
 	if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
-		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
+		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
+			/*
+			 * When peer becomes authorized, init rate control as
+			 * well. Some drivers require rate control initialized
+			 * before drv_sta_state() is called.
+			 */
+			if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+				rate_control_rate_init(sta);
+
 			ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
-		else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+		} else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
 			ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-		else
+		} else {
 			ret = 0;
+		}
 		if (ret)
 			return ret;
 	}
@@ -1377,11 +1386,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 	if (err)
 		goto out_err;
 
-	/* When peer becomes authorized, init rate control as well */
-	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
-	    test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-		rate_control_rate_init(sta);
-
 	mutex_unlock(&local->sta_mtx);
 
 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
-- 
2.1.4


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

* [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-02-25  7:55   ` Marek Puzyniak
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Puzyniak

Currently when TDLS station in driver goes from assoc
to authorized state it can not use rate control parameters
because rate control is not initialized yet. Some drivers
require parameters already initialized by rate control when
entering authorized state. It can be done by initializing
rate control after station transition to authorized state
but before notifying driver about that.

Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
---
 net/mac80211/cfg.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index dd4ff36..ae24ed3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -983,12 +983,21 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
 	}
 
 	if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
-		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
+		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
+			/*
+			 * When peer becomes authorized, init rate control as
+			 * well. Some drivers require rate control initialized
+			 * before drv_sta_state() is called.
+			 */
+			if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+				rate_control_rate_init(sta);
+
 			ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
-		else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+		} else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
 			ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-		else
+		} else {
 			ret = 0;
+		}
 		if (ret)
 			return ret;
 	}
@@ -1377,11 +1386,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 	if (err)
 		goto out_err;
 
-	/* When peer becomes authorized, init rate control as well */
-	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
-	    test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-		rate_control_rate_init(sta);
-
 	mutex_unlock(&local->sta_mtx);
 
 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
-- 
2.1.4


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* [PATCH v2 4/4] ath10k: introduce basic tdls functionality
  2015-02-25  7:55 ` Marek Puzyniak
@ 2015-02-25  7:55   ` Marek Puzyniak
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Puzyniak, Michal Kazior, Marek Kwaczynski

This patch adds functions to enable/disable tdls
and to configure tdls peer station for tlv based firmware.
Tdls peer uapsd and tdls channel switching are not supported.
Transmitting tdls data frames works only for ethernet
type frames, that's why data addressed to tdls sta
is in ethernet format.

Tdls functionality for ath10k requires changes in mac80211
provided in patch:
mac80211: initialize rate control earlier for tdls station

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Marek Kwaczynski <marek.kwaczynski@tieto.com>
Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h    |   1 +
 drivers/net/wireless/ath/ath10k/mac.c     | 141 +++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  42 +++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 152 ++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.h |  52 ++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h     |  37 ++++++++
 6 files changed, 417 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 94a8788..14b99c8 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -604,6 +604,7 @@ struct ath10k {
 	/* protected by conf_mutex */
 	int num_peers;
 	int num_stations;
+	int tdls_peers;
 
 	int max_num_peers;
 	int max_num_stations;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 7378656..21720b8 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -518,6 +518,73 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 	ar->num_stations = 0;
 }
 
+static int ath10k_mac_enable_tdls(struct ath10k *ar, u32 vdev_id, bool enable)
+{
+	int ret = 0;
+	bool changed = false;
+	enum wmi_tdls_state state = WMI_TDLS_DISABLE;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (enable) {
+		state = WMI_TDLS_ENABLE_ACTIVE;
+		if (!ar->tdls_peers)
+			changed = true;
+		ar->tdls_peers++;
+	} else {
+		if (ar->tdls_peers > 0) {
+			ar->tdls_peers--;
+			if (ar->tdls_peers == 0)
+				changed = true;
+		}
+	}
+
+	if (!changed)
+		return 0;
+
+	ret = ath10k_wmi_update_fw_tdls_state(ar, vdev_id, state);
+
+	if (ret) {
+		ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n",
+			    vdev_id, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int ath10k_mac_tdls_peer_update(struct ath10k *ar, u32 vdev_id,
+				       struct ieee80211_sta *sta,
+				       enum wmi_tdls_peer_state state)
+{
+	int ret;
+	struct wmi_tdls_peer_update_cmd_arg arg;
+	struct wmi_tdls_peer_capab_arg cap = {};
+	struct wmi_channel_arg chan_arg = {};
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	arg.vdev_id = vdev_id;
+	arg.peer_state = state;
+	ether_addr_copy(arg.addr, sta->addr);
+
+	cap.peer_max_sp = sta->max_sp;
+	cap.peer_uapsd_queues = sta->uapsd_queues;
+
+	if (state == WMI_TDLS_PEER_STATE_CONNECTED) {
+		if (!sta->tdls_initiator)
+			cap.is_peer_responder = 1;
+	}
+
+	ret = ath10k_wmi_tdls_peer_update(ar, &arg, &cap, &chan_arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to update tdls peer %pM on vdev %i: %i\n",
+			    arg.addr, vdev_id, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 /************************/
 /* Interface management */
 /************************/
@@ -2186,7 +2253,7 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
 
 static enum ath10k_hw_txrx_mode
 ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
-		       struct sk_buff *skb)
+		       struct ieee80211_sta *sta, struct sk_buff *skb)
 {
 	const struct ieee80211_hdr *hdr = (void *)skb->data;
 	__le16 fc = hdr->frame_control;
@@ -2218,6 +2285,15 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
 	    !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features))
 		return ATH10K_HW_TXRX_MGMT;
 
+	/* Workaround:
+	 *
+	 * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for
+	 * NativeWifi txmode - it selects AP key instead of peer key. It seems
+	 * to work with Ethernet txmode so use it.
+	 */
+	if (ieee80211_is_data_present(fc) && sta && sta->tdls)
+		return ATH10K_HW_TXRX_ETHERNET;
+
 	return ATH10K_HW_TXRX_NATIVE_WIFI;
 }
 
@@ -2644,6 +2720,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	struct ath10k *ar = hw->priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_vif *vif = info->control.vif;
+	struct ieee80211_sta *sta = control->sta;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	__le16 fc = hdr->frame_control;
 
@@ -2654,7 +2731,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	ATH10K_SKB_CB(skb)->htt.is_offchan = false;
 	ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
 	ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
-	ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, skb);
+	ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);
 	ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
 
 	switch (ATH10K_SKB_CB(skb)->txmode) {
@@ -2726,6 +2803,8 @@ void ath10k_halt(struct ath10k *ar)
 
 	ar->monitor_started = false;
 
+	ar->tdls_peers = 0;
+
 	ath10k_scan_finish(ar);
 	ath10k_peer_cleanup_all(ar);
 	ath10k_core_stop(ar);
@@ -4014,6 +4093,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 		/*
 		 * New station addition.
 		 */
+		enum wmi_peer_type peer_type = WMI_PEER_TYPE_DEFAULT;
+
 		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
 			   arvif->vdev_id, sta->addr,
@@ -4027,8 +4108,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			goto exit;
 		}
 
+		if (sta->tdls) {
+			peer_type = WMI_PEER_TYPE_TDLS;
+			ath10k_mac_enable_tdls(ar, arvif->vdev_id, true);
+		}
+
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr,
-					 WMI_PEER_TYPE_DEFAULT);
+					 peer_type);
 		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
@@ -4036,7 +4122,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			goto exit;
 		}
 
-		if (vif->type == NL80211_IFTYPE_STATION) {
+		if (vif->type == NL80211_IFTYPE_STATION &&
+		    !sta->tdls) {
 			WARN_ON(arvif->is_started);
 
 			ret = ath10k_vdev_start(arvif);
@@ -4051,6 +4138,16 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 
 			arvif->is_started = true;
 		}
+
+		if (!sta->tdls)
+			goto exit;
+
+		ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+						  WMI_TDLS_PEER_STATE_PEERING);
+		if (ret)
+			ath10k_warn(ar,
+				    "failed to update tdls peer %pM for vdev %d when adding a new sta: %i\n",
+				    sta->addr, arvif->vdev_id, ret);
 	} else if ((old_state == IEEE80211_STA_NONE &&
 		    new_state == IEEE80211_STA_NOTEXIST)) {
 		/*
@@ -4060,7 +4157,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			   "mac vdev %d peer delete %pM (sta gone)\n",
 			   arvif->vdev_id, sta->addr);
 
-		if (vif->type == NL80211_IFTYPE_STATION) {
+		if (vif->type == NL80211_IFTYPE_STATION &&
+		    !sta->tdls) {
 			WARN_ON(!arvif->is_started);
 
 			ret = ath10k_vdev_stop(arvif);
@@ -4077,6 +4175,9 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 				    sta->addr, arvif->vdev_id, ret);
 
 		ath10k_mac_dec_num_stations(arvif);
+
+		if (sta->tdls)
+			ath10k_mac_enable_tdls(ar, arvif->vdev_id, false);
 	} else if (old_state == IEEE80211_STA_AUTH &&
 		   new_state == IEEE80211_STA_ASSOC &&
 		   (vif->type == NL80211_IFTYPE_AP ||
@@ -4092,9 +4193,30 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 	} else if (old_state == IEEE80211_STA_ASSOC &&
-		   new_state == IEEE80211_STA_AUTH &&
-		   (vif->type == NL80211_IFTYPE_AP ||
-		    vif->type == NL80211_IFTYPE_ADHOC)) {
+		   new_state == IEEE80211_STA_AUTHORIZED &&
+		   sta->tdls) {
+		/*
+		 * Tdls station authorized.
+		 */
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac tdls sta %pM authorized\n",
+			   sta->addr);
+
+		ret = ath10k_station_assoc(ar, vif, sta, false);
+		if (ret) {
+			ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
+				    sta->addr, arvif->vdev_id, ret);
+			goto exit;
+		}
+
+		ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+						  WMI_TDLS_PEER_STATE_CONNECTED);
+		if (ret)
+			ath10k_warn(ar, "failed to update tdls peer %pM for vdev %i: %i\n",
+				    sta->addr, arvif->vdev_id, ret);
+	} else if (old_state == IEEE80211_STA_ASSOC &&
+		    new_state == IEEE80211_STA_AUTH &&
+		    (vif->type == NL80211_IFTYPE_AP ||
+		     vif->type == NL80211_IFTYPE_ADHOC)) {
 		/*
 		 * Disassociation.
 		 */
@@ -5476,6 +5598,9 @@ int ath10k_mac_register(struct ath10k *ar)
 			NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 	}
 
+	if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map))
+		ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
 	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 	ar->hw->wiphy->max_remain_on_channel_duration = 5000;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index a2cded8..b869c9b 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -150,6 +150,13 @@ struct wmi_ops {
 					      u32 num_ac);
 	struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar,
 					     const struct wmi_sta_keepalive_arg *arg);
+	struct sk_buff *(*gen_update_fw_tdls_state)(struct ath10k *ar,
+						    u32 vdev_id,
+						    enum wmi_tdls_state state);
+	struct sk_buff *(*gen_tdls_peer_update)(struct ath10k *ar,
+						const struct wmi_tdls_peer_update_cmd_arg *arg,
+						const struct wmi_tdls_peer_capab_arg *cap,
+						const struct wmi_channel_arg *chan);
 };
 
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1063,4 +1070,39 @@ ath10k_wmi_sta_keepalive(struct ath10k *ar,
 	return ath10k_wmi_cmd_send(ar, skb, cmd_id);
 }
 
+static inline int
+ath10k_wmi_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+				enum wmi_tdls_state state)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_update_fw_tdls_state)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_update_fw_tdls_state(ar, vdev_id, state);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->tdls_set_state_cmdid);
+}
+
+static inline int
+ath10k_wmi_tdls_peer_update(struct ath10k *ar,
+			    const struct wmi_tdls_peer_update_cmd_arg *arg,
+			    const struct wmi_tdls_peer_capab_arg *cap,
+			    const struct wmi_channel_arg *chan)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_tdls_peer_update)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_tdls_peer_update(ar, arg, cap, chan);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->tdls_peer_update_cmdid);
+}
+
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 809c046..7a4b711 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -2386,6 +2386,154 @@ ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id,
 	return skb;
 }
 
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+					   enum wmi_tdls_state state)
+{
+	struct wmi_tdls_set_state_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	void *ptr;
+	size_t len;
+	/* Set to options from wmi_tlv_tdls_options,
+	 * for now none of them are enabled.
+	 */
+	u32 options = 0;
+
+	len = sizeof(*tlv) + sizeof(*cmd);
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->state = __cpu_to_le32(state);
+	cmd->notification_interval_ms = __cpu_to_le32(5000);
+	cmd->tx_discovery_threshold = __cpu_to_le32(100);
+	cmd->tx_teardown_threshold = __cpu_to_le32(5);
+	cmd->rssi_teardown_threshold = __cpu_to_le32(-75);
+	cmd->rssi_delta = __cpu_to_le32(-20);
+	cmd->tdls_options = __cpu_to_le32(options);
+	cmd->tdls_peer_traffic_ind_window = __cpu_to_le32(2);
+	cmd->tdls_peer_traffic_response_timeout_ms = __cpu_to_le32(5000);
+	cmd->tdls_puapsd_mask = __cpu_to_le32(0xf);
+	cmd->tdls_puapsd_inactivity_time_ms = __cpu_to_le32(0);
+	cmd->tdls_puapsd_rx_frame_threshold = __cpu_to_le32(10);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv update fw tdls state %d for vdev %i\n",
+		   state, vdev_id);
+	return skb;
+}
+
+static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
+{
+	u32 peer_qos = 0;
+
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VO;
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VI;
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BK;
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BE;
+	peer_qos |= (sp << WMI_TLV_TDLS_PEER_SP_POS);
+
+	return peer_qos;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
+				       const struct wmi_tdls_peer_update_cmd_arg *arg,
+				       const struct wmi_tdls_peer_capab_arg *cap,
+				       const struct wmi_channel_arg *chan_arg)
+{
+	struct wmi_tdls_peer_update_cmd *cmd;
+	struct wmi_tdls_peer_capab *peer_cap;
+	struct wmi_channel *chan;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u32 peer_qos;
+	void *ptr;
+	int len;
+	int i;
+
+	len = sizeof(*tlv) + sizeof(*cmd) +
+	      sizeof(*tlv) + sizeof(*peer_cap) +
+	      sizeof(*tlv) + cap->peer_chan_len * sizeof(*chan);
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+	ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
+	cmd->peer_state = __cpu_to_le32(arg->peer_state);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES);
+	tlv->len = __cpu_to_le16(sizeof(*peer_cap));
+	peer_cap = (void *)tlv->value;
+	peer_qos = ath10k_wmi_tlv_prepare_peer_qos(cap->peer_uapsd_queues,
+						   cap->peer_max_sp);
+	peer_cap->peer_qos = __cpu_to_le32(peer_qos);
+	peer_cap->buff_sta_support = __cpu_to_le32(cap->buff_sta_support);
+	peer_cap->off_chan_support = __cpu_to_le32(cap->off_chan_support);
+	peer_cap->peer_curr_operclass = __cpu_to_le32(cap->peer_curr_operclass);
+	peer_cap->self_curr_operclass = __cpu_to_le32(cap->self_curr_operclass);
+	peer_cap->peer_chan_len = __cpu_to_le32(cap->peer_chan_len);
+	peer_cap->peer_operclass_len = __cpu_to_le32(cap->peer_operclass_len);
+
+	for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++)
+		peer_cap->peer_operclass[i] = cap->peer_operclass[i];
+
+	peer_cap->is_peer_responder = __cpu_to_le32(cap->is_peer_responder);
+	peer_cap->pref_offchan_num = __cpu_to_le32(cap->pref_offchan_num);
+	peer_cap->pref_offchan_bw = __cpu_to_le32(cap->pref_offchan_bw);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*peer_cap);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+	tlv->len = __cpu_to_le16(cap->peer_chan_len * sizeof(*chan));
+
+	ptr += sizeof(*tlv);
+
+	for (i = 0; i < cap->peer_chan_len; i++) {
+		tlv = ptr;
+		tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+		tlv->len = __cpu_to_le16(sizeof(*chan));
+		chan = (void *)tlv->value;
+		ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);
+
+		ptr += sizeof(*tlv);
+		ptr += sizeof(*chan);
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "wmi tlv tdls peer update vdev %i state %d n_chans %u\n",
+		   arg->vdev_id, arg->peer_state, cap->peer_chan_len);
+	return skb;
+}
+
 /****************/
 /* TLV mappings */
 /****************/
@@ -2510,6 +2658,8 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
 	.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
 	.pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
 	.vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
+	.tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
+	.tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,
 };
 
 static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
@@ -2682,6 +2832,8 @@ static const struct wmi_ops wmi_tlv_ops = {
 	.gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie,
 	.gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
 	.gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
+	.gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
+	.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
 };
 
 /************/
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index de68fe7..934c7a8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1439,6 +1439,58 @@ struct wmi_tlv_sta_keepalive_cmd {
 	__le32 interval; /* in seconds */
 } __packed;
 
+/* TDLS Options */
+enum wmi_tlv_tdls_options {
+	WMI_TLV_TDLS_OFFCHAN_EN = BIT(0),
+	WMI_TLV_TDLS_BUFFER_STA_EN = BIT(1),
+	WMI_TLV_TDLS_SLEEP_STA_EN = BIT(2),
+};
+
+struct wmi_tdls_set_state_cmd {
+	__le32 vdev_id;
+	__le32 state;
+	__le32 notification_interval_ms;
+	__le32 tx_discovery_threshold;
+	__le32 tx_teardown_threshold;
+	__le32 rssi_teardown_threshold;
+	__le32 rssi_delta;
+	__le32 tdls_options;
+	__le32 tdls_peer_traffic_ind_window;
+	__le32 tdls_peer_traffic_response_timeout_ms;
+	__le32 tdls_puapsd_mask;
+	__le32 tdls_puapsd_inactivity_time_ms;
+	__le32 tdls_puapsd_rx_frame_threshold;
+} __packed;
+
+struct wmi_tdls_peer_update_cmd {
+	__le32 vdev_id;
+	struct wmi_mac_addr peer_macaddr;
+	__le32 peer_state;
+} __packed;
+
+enum {
+	WMI_TLV_TDLS_PEER_QOS_AC_VO = BIT(0),
+	WMI_TLV_TDLS_PEER_QOS_AC_VI = BIT(1),
+	WMI_TLV_TDLS_PEER_QOS_AC_BK = BIT(2),
+	WMI_TLV_TDLS_PEER_QOS_AC_BE = BIT(3),
+};
+
+#define WMI_TLV_TDLS_PEER_SP_POS 5
+
+struct wmi_tdls_peer_capab {
+	__le32 peer_qos;
+	__le32 buff_sta_support;
+	__le32 off_chan_support;
+	__le32 peer_curr_operclass;
+	__le32 self_curr_operclass;
+	__le32 peer_chan_len;
+	__le32 peer_operclass_len;
+	u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+	__le32 is_peer_responder;
+	__le32 pref_offchan_num;
+	__le32 pref_offchan_bw;
+} __packed;
+
 void ath10k_wmi_tlv_attach(struct ath10k *ar);
 
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 0ffa90a..99f0694 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -552,6 +552,8 @@ struct wmi_cmd_map {
 	u32 gpio_output_cmdid;
 	u32 pdev_get_temperature_cmdid;
 	u32 vdev_set_wmm_params_cmdid;
+	u32 tdls_set_state_cmdid;
+	u32 tdls_peer_update_cmdid;
 };
 
 /*
@@ -4858,6 +4860,41 @@ struct wmi_pdev_temperature_event {
 	__le32 temperature;
 } __packed;
 
+enum wmi_tdls_state {
+	WMI_TDLS_DISABLE,
+	WMI_TDLS_ENABLE_PASSIVE,
+	WMI_TDLS_ENABLE_ACTIVE,
+};
+
+enum wmi_tdls_peer_state {
+	WMI_TDLS_PEER_STATE_PEERING,
+	WMI_TDLS_PEER_STATE_CONNECTED,
+	WMI_TDLS_PEER_STATE_TEARDOWN,
+};
+
+struct wmi_tdls_peer_update_cmd_arg {
+	u32 vdev_id;
+	enum wmi_tdls_peer_state peer_state;
+	u8 addr[ETH_ALEN];
+} __packed;
+
+#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32
+
+struct wmi_tdls_peer_capab_arg {
+	u8 peer_uapsd_queues;
+	u8 peer_max_sp;
+	u32 buff_sta_support;
+	u32 off_chan_support;
+	u32 peer_curr_operclass;
+	u32 self_curr_operclass;
+	u32 peer_chan_len;
+	u32 peer_operclass_len;
+	u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+	u32 is_peer_responder;
+	u32 pref_offchan_num;
+	u32 pref_offchan_bw;
+} __packed;
+
 struct ath10k;
 struct ath10k_vif;
 struct ath10k_fw_stats_pdev;
-- 
2.1.4


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

* [PATCH v2 4/4] ath10k: introduce basic tdls functionality
@ 2015-02-25  7:55   ` Marek Puzyniak
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-02-25  7:55 UTC (permalink / raw)
  To: linux-wireless, ath10k; +Cc: Marek Kwaczynski, Marek Puzyniak, Michal Kazior

This patch adds functions to enable/disable tdls
and to configure tdls peer station for tlv based firmware.
Tdls peer uapsd and tdls channel switching are not supported.
Transmitting tdls data frames works only for ethernet
type frames, that's why data addressed to tdls sta
is in ethernet format.

Tdls functionality for ath10k requires changes in mac80211
provided in patch:
mac80211: initialize rate control earlier for tdls station

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Marek Kwaczynski <marek.kwaczynski@tieto.com>
Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h    |   1 +
 drivers/net/wireless/ath/ath10k/mac.c     | 141 +++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  42 +++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 152 ++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.h |  52 ++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h     |  37 ++++++++
 6 files changed, 417 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 94a8788..14b99c8 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -604,6 +604,7 @@ struct ath10k {
 	/* protected by conf_mutex */
 	int num_peers;
 	int num_stations;
+	int tdls_peers;
 
 	int max_num_peers;
 	int max_num_stations;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 7378656..21720b8 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -518,6 +518,73 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 	ar->num_stations = 0;
 }
 
+static int ath10k_mac_enable_tdls(struct ath10k *ar, u32 vdev_id, bool enable)
+{
+	int ret = 0;
+	bool changed = false;
+	enum wmi_tdls_state state = WMI_TDLS_DISABLE;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (enable) {
+		state = WMI_TDLS_ENABLE_ACTIVE;
+		if (!ar->tdls_peers)
+			changed = true;
+		ar->tdls_peers++;
+	} else {
+		if (ar->tdls_peers > 0) {
+			ar->tdls_peers--;
+			if (ar->tdls_peers == 0)
+				changed = true;
+		}
+	}
+
+	if (!changed)
+		return 0;
+
+	ret = ath10k_wmi_update_fw_tdls_state(ar, vdev_id, state);
+
+	if (ret) {
+		ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n",
+			    vdev_id, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int ath10k_mac_tdls_peer_update(struct ath10k *ar, u32 vdev_id,
+				       struct ieee80211_sta *sta,
+				       enum wmi_tdls_peer_state state)
+{
+	int ret;
+	struct wmi_tdls_peer_update_cmd_arg arg;
+	struct wmi_tdls_peer_capab_arg cap = {};
+	struct wmi_channel_arg chan_arg = {};
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	arg.vdev_id = vdev_id;
+	arg.peer_state = state;
+	ether_addr_copy(arg.addr, sta->addr);
+
+	cap.peer_max_sp = sta->max_sp;
+	cap.peer_uapsd_queues = sta->uapsd_queues;
+
+	if (state == WMI_TDLS_PEER_STATE_CONNECTED) {
+		if (!sta->tdls_initiator)
+			cap.is_peer_responder = 1;
+	}
+
+	ret = ath10k_wmi_tdls_peer_update(ar, &arg, &cap, &chan_arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to update tdls peer %pM on vdev %i: %i\n",
+			    arg.addr, vdev_id, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 /************************/
 /* Interface management */
 /************************/
@@ -2186,7 +2253,7 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
 
 static enum ath10k_hw_txrx_mode
 ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
-		       struct sk_buff *skb)
+		       struct ieee80211_sta *sta, struct sk_buff *skb)
 {
 	const struct ieee80211_hdr *hdr = (void *)skb->data;
 	__le16 fc = hdr->frame_control;
@@ -2218,6 +2285,15 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
 	    !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features))
 		return ATH10K_HW_TXRX_MGMT;
 
+	/* Workaround:
+	 *
+	 * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for
+	 * NativeWifi txmode - it selects AP key instead of peer key. It seems
+	 * to work with Ethernet txmode so use it.
+	 */
+	if (ieee80211_is_data_present(fc) && sta && sta->tdls)
+		return ATH10K_HW_TXRX_ETHERNET;
+
 	return ATH10K_HW_TXRX_NATIVE_WIFI;
 }
 
@@ -2644,6 +2720,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	struct ath10k *ar = hw->priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_vif *vif = info->control.vif;
+	struct ieee80211_sta *sta = control->sta;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	__le16 fc = hdr->frame_control;
 
@@ -2654,7 +2731,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 	ATH10K_SKB_CB(skb)->htt.is_offchan = false;
 	ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
 	ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
-	ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, skb);
+	ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);
 	ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
 
 	switch (ATH10K_SKB_CB(skb)->txmode) {
@@ -2726,6 +2803,8 @@ void ath10k_halt(struct ath10k *ar)
 
 	ar->monitor_started = false;
 
+	ar->tdls_peers = 0;
+
 	ath10k_scan_finish(ar);
 	ath10k_peer_cleanup_all(ar);
 	ath10k_core_stop(ar);
@@ -4014,6 +4093,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 		/*
 		 * New station addition.
 		 */
+		enum wmi_peer_type peer_type = WMI_PEER_TYPE_DEFAULT;
+
 		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
 			   arvif->vdev_id, sta->addr,
@@ -4027,8 +4108,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			goto exit;
 		}
 
+		if (sta->tdls) {
+			peer_type = WMI_PEER_TYPE_TDLS;
+			ath10k_mac_enable_tdls(ar, arvif->vdev_id, true);
+		}
+
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr,
-					 WMI_PEER_TYPE_DEFAULT);
+					 peer_type);
 		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
@@ -4036,7 +4122,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			goto exit;
 		}
 
-		if (vif->type == NL80211_IFTYPE_STATION) {
+		if (vif->type == NL80211_IFTYPE_STATION &&
+		    !sta->tdls) {
 			WARN_ON(arvif->is_started);
 
 			ret = ath10k_vdev_start(arvif);
@@ -4051,6 +4138,16 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 
 			arvif->is_started = true;
 		}
+
+		if (!sta->tdls)
+			goto exit;
+
+		ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+						  WMI_TDLS_PEER_STATE_PEERING);
+		if (ret)
+			ath10k_warn(ar,
+				    "failed to update tdls peer %pM for vdev %d when adding a new sta: %i\n",
+				    sta->addr, arvif->vdev_id, ret);
 	} else if ((old_state == IEEE80211_STA_NONE &&
 		    new_state == IEEE80211_STA_NOTEXIST)) {
 		/*
@@ -4060,7 +4157,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			   "mac vdev %d peer delete %pM (sta gone)\n",
 			   arvif->vdev_id, sta->addr);
 
-		if (vif->type == NL80211_IFTYPE_STATION) {
+		if (vif->type == NL80211_IFTYPE_STATION &&
+		    !sta->tdls) {
 			WARN_ON(!arvif->is_started);
 
 			ret = ath10k_vdev_stop(arvif);
@@ -4077,6 +4175,9 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 				    sta->addr, arvif->vdev_id, ret);
 
 		ath10k_mac_dec_num_stations(arvif);
+
+		if (sta->tdls)
+			ath10k_mac_enable_tdls(ar, arvif->vdev_id, false);
 	} else if (old_state == IEEE80211_STA_AUTH &&
 		   new_state == IEEE80211_STA_ASSOC &&
 		   (vif->type == NL80211_IFTYPE_AP ||
@@ -4092,9 +4193,30 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 	} else if (old_state == IEEE80211_STA_ASSOC &&
-		   new_state == IEEE80211_STA_AUTH &&
-		   (vif->type == NL80211_IFTYPE_AP ||
-		    vif->type == NL80211_IFTYPE_ADHOC)) {
+		   new_state == IEEE80211_STA_AUTHORIZED &&
+		   sta->tdls) {
+		/*
+		 * Tdls station authorized.
+		 */
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac tdls sta %pM authorized\n",
+			   sta->addr);
+
+		ret = ath10k_station_assoc(ar, vif, sta, false);
+		if (ret) {
+			ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
+				    sta->addr, arvif->vdev_id, ret);
+			goto exit;
+		}
+
+		ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+						  WMI_TDLS_PEER_STATE_CONNECTED);
+		if (ret)
+			ath10k_warn(ar, "failed to update tdls peer %pM for vdev %i: %i\n",
+				    sta->addr, arvif->vdev_id, ret);
+	} else if (old_state == IEEE80211_STA_ASSOC &&
+		    new_state == IEEE80211_STA_AUTH &&
+		    (vif->type == NL80211_IFTYPE_AP ||
+		     vif->type == NL80211_IFTYPE_ADHOC)) {
 		/*
 		 * Disassociation.
 		 */
@@ -5476,6 +5598,9 @@ int ath10k_mac_register(struct ath10k *ar)
 			NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 	}
 
+	if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map))
+		ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
 	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 	ar->hw->wiphy->max_remain_on_channel_duration = 5000;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index a2cded8..b869c9b 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -150,6 +150,13 @@ struct wmi_ops {
 					      u32 num_ac);
 	struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar,
 					     const struct wmi_sta_keepalive_arg *arg);
+	struct sk_buff *(*gen_update_fw_tdls_state)(struct ath10k *ar,
+						    u32 vdev_id,
+						    enum wmi_tdls_state state);
+	struct sk_buff *(*gen_tdls_peer_update)(struct ath10k *ar,
+						const struct wmi_tdls_peer_update_cmd_arg *arg,
+						const struct wmi_tdls_peer_capab_arg *cap,
+						const struct wmi_channel_arg *chan);
 };
 
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1063,4 +1070,39 @@ ath10k_wmi_sta_keepalive(struct ath10k *ar,
 	return ath10k_wmi_cmd_send(ar, skb, cmd_id);
 }
 
+static inline int
+ath10k_wmi_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+				enum wmi_tdls_state state)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_update_fw_tdls_state)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_update_fw_tdls_state(ar, vdev_id, state);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->tdls_set_state_cmdid);
+}
+
+static inline int
+ath10k_wmi_tdls_peer_update(struct ath10k *ar,
+			    const struct wmi_tdls_peer_update_cmd_arg *arg,
+			    const struct wmi_tdls_peer_capab_arg *cap,
+			    const struct wmi_channel_arg *chan)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_tdls_peer_update)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_tdls_peer_update(ar, arg, cap, chan);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->tdls_peer_update_cmdid);
+}
+
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 809c046..7a4b711 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -2386,6 +2386,154 @@ ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id,
 	return skb;
 }
 
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+					   enum wmi_tdls_state state)
+{
+	struct wmi_tdls_set_state_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	void *ptr;
+	size_t len;
+	/* Set to options from wmi_tlv_tdls_options,
+	 * for now none of them are enabled.
+	 */
+	u32 options = 0;
+
+	len = sizeof(*tlv) + sizeof(*cmd);
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->state = __cpu_to_le32(state);
+	cmd->notification_interval_ms = __cpu_to_le32(5000);
+	cmd->tx_discovery_threshold = __cpu_to_le32(100);
+	cmd->tx_teardown_threshold = __cpu_to_le32(5);
+	cmd->rssi_teardown_threshold = __cpu_to_le32(-75);
+	cmd->rssi_delta = __cpu_to_le32(-20);
+	cmd->tdls_options = __cpu_to_le32(options);
+	cmd->tdls_peer_traffic_ind_window = __cpu_to_le32(2);
+	cmd->tdls_peer_traffic_response_timeout_ms = __cpu_to_le32(5000);
+	cmd->tdls_puapsd_mask = __cpu_to_le32(0xf);
+	cmd->tdls_puapsd_inactivity_time_ms = __cpu_to_le32(0);
+	cmd->tdls_puapsd_rx_frame_threshold = __cpu_to_le32(10);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv update fw tdls state %d for vdev %i\n",
+		   state, vdev_id);
+	return skb;
+}
+
+static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
+{
+	u32 peer_qos = 0;
+
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VO;
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VI;
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BK;
+	if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
+		peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BE;
+	peer_qos |= (sp << WMI_TLV_TDLS_PEER_SP_POS);
+
+	return peer_qos;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
+				       const struct wmi_tdls_peer_update_cmd_arg *arg,
+				       const struct wmi_tdls_peer_capab_arg *cap,
+				       const struct wmi_channel_arg *chan_arg)
+{
+	struct wmi_tdls_peer_update_cmd *cmd;
+	struct wmi_tdls_peer_capab *peer_cap;
+	struct wmi_channel *chan;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u32 peer_qos;
+	void *ptr;
+	int len;
+	int i;
+
+	len = sizeof(*tlv) + sizeof(*cmd) +
+	      sizeof(*tlv) + sizeof(*peer_cap) +
+	      sizeof(*tlv) + cap->peer_chan_len * sizeof(*chan);
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+	ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
+	cmd->peer_state = __cpu_to_le32(arg->peer_state);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES);
+	tlv->len = __cpu_to_le16(sizeof(*peer_cap));
+	peer_cap = (void *)tlv->value;
+	peer_qos = ath10k_wmi_tlv_prepare_peer_qos(cap->peer_uapsd_queues,
+						   cap->peer_max_sp);
+	peer_cap->peer_qos = __cpu_to_le32(peer_qos);
+	peer_cap->buff_sta_support = __cpu_to_le32(cap->buff_sta_support);
+	peer_cap->off_chan_support = __cpu_to_le32(cap->off_chan_support);
+	peer_cap->peer_curr_operclass = __cpu_to_le32(cap->peer_curr_operclass);
+	peer_cap->self_curr_operclass = __cpu_to_le32(cap->self_curr_operclass);
+	peer_cap->peer_chan_len = __cpu_to_le32(cap->peer_chan_len);
+	peer_cap->peer_operclass_len = __cpu_to_le32(cap->peer_operclass_len);
+
+	for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++)
+		peer_cap->peer_operclass[i] = cap->peer_operclass[i];
+
+	peer_cap->is_peer_responder = __cpu_to_le32(cap->is_peer_responder);
+	peer_cap->pref_offchan_num = __cpu_to_le32(cap->pref_offchan_num);
+	peer_cap->pref_offchan_bw = __cpu_to_le32(cap->pref_offchan_bw);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*peer_cap);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+	tlv->len = __cpu_to_le16(cap->peer_chan_len * sizeof(*chan));
+
+	ptr += sizeof(*tlv);
+
+	for (i = 0; i < cap->peer_chan_len; i++) {
+		tlv = ptr;
+		tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+		tlv->len = __cpu_to_le16(sizeof(*chan));
+		chan = (void *)tlv->value;
+		ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);
+
+		ptr += sizeof(*tlv);
+		ptr += sizeof(*chan);
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "wmi tlv tdls peer update vdev %i state %d n_chans %u\n",
+		   arg->vdev_id, arg->peer_state, cap->peer_chan_len);
+	return skb;
+}
+
 /****************/
 /* TLV mappings */
 /****************/
@@ -2510,6 +2658,8 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
 	.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
 	.pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
 	.vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
+	.tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
+	.tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,
 };
 
 static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
@@ -2682,6 +2832,8 @@ static const struct wmi_ops wmi_tlv_ops = {
 	.gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie,
 	.gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
 	.gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
+	.gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
+	.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
 };
 
 /************/
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index de68fe7..934c7a8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1439,6 +1439,58 @@ struct wmi_tlv_sta_keepalive_cmd {
 	__le32 interval; /* in seconds */
 } __packed;
 
+/* TDLS Options */
+enum wmi_tlv_tdls_options {
+	WMI_TLV_TDLS_OFFCHAN_EN = BIT(0),
+	WMI_TLV_TDLS_BUFFER_STA_EN = BIT(1),
+	WMI_TLV_TDLS_SLEEP_STA_EN = BIT(2),
+};
+
+struct wmi_tdls_set_state_cmd {
+	__le32 vdev_id;
+	__le32 state;
+	__le32 notification_interval_ms;
+	__le32 tx_discovery_threshold;
+	__le32 tx_teardown_threshold;
+	__le32 rssi_teardown_threshold;
+	__le32 rssi_delta;
+	__le32 tdls_options;
+	__le32 tdls_peer_traffic_ind_window;
+	__le32 tdls_peer_traffic_response_timeout_ms;
+	__le32 tdls_puapsd_mask;
+	__le32 tdls_puapsd_inactivity_time_ms;
+	__le32 tdls_puapsd_rx_frame_threshold;
+} __packed;
+
+struct wmi_tdls_peer_update_cmd {
+	__le32 vdev_id;
+	struct wmi_mac_addr peer_macaddr;
+	__le32 peer_state;
+} __packed;
+
+enum {
+	WMI_TLV_TDLS_PEER_QOS_AC_VO = BIT(0),
+	WMI_TLV_TDLS_PEER_QOS_AC_VI = BIT(1),
+	WMI_TLV_TDLS_PEER_QOS_AC_BK = BIT(2),
+	WMI_TLV_TDLS_PEER_QOS_AC_BE = BIT(3),
+};
+
+#define WMI_TLV_TDLS_PEER_SP_POS 5
+
+struct wmi_tdls_peer_capab {
+	__le32 peer_qos;
+	__le32 buff_sta_support;
+	__le32 off_chan_support;
+	__le32 peer_curr_operclass;
+	__le32 self_curr_operclass;
+	__le32 peer_chan_len;
+	__le32 peer_operclass_len;
+	u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+	__le32 is_peer_responder;
+	__le32 pref_offchan_num;
+	__le32 pref_offchan_bw;
+} __packed;
+
 void ath10k_wmi_tlv_attach(struct ath10k *ar);
 
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 0ffa90a..99f0694 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -552,6 +552,8 @@ struct wmi_cmd_map {
 	u32 gpio_output_cmdid;
 	u32 pdev_get_temperature_cmdid;
 	u32 vdev_set_wmm_params_cmdid;
+	u32 tdls_set_state_cmdid;
+	u32 tdls_peer_update_cmdid;
 };
 
 /*
@@ -4858,6 +4860,41 @@ struct wmi_pdev_temperature_event {
 	__le32 temperature;
 } __packed;
 
+enum wmi_tdls_state {
+	WMI_TDLS_DISABLE,
+	WMI_TDLS_ENABLE_PASSIVE,
+	WMI_TDLS_ENABLE_ACTIVE,
+};
+
+enum wmi_tdls_peer_state {
+	WMI_TDLS_PEER_STATE_PEERING,
+	WMI_TDLS_PEER_STATE_CONNECTED,
+	WMI_TDLS_PEER_STATE_TEARDOWN,
+};
+
+struct wmi_tdls_peer_update_cmd_arg {
+	u32 vdev_id;
+	enum wmi_tdls_peer_state peer_state;
+	u8 addr[ETH_ALEN];
+} __packed;
+
+#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32
+
+struct wmi_tdls_peer_capab_arg {
+	u8 peer_uapsd_queues;
+	u8 peer_max_sp;
+	u32 buff_sta_support;
+	u32 off_chan_support;
+	u32 peer_curr_operclass;
+	u32 self_curr_operclass;
+	u32 peer_chan_len;
+	u32 peer_operclass_len;
+	u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+	u32 is_peer_responder;
+	u32 pref_offchan_num;
+	u32 pref_offchan_bw;
+} __packed;
+
 struct ath10k;
 struct ath10k_vif;
 struct ath10k_fw_stats_pdev;
-- 
2.1.4


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 4/4] ath10k: introduce basic tdls functionality
  2015-02-25  7:55   ` Marek Puzyniak
@ 2015-02-25 10:34     ` Michal Kazior
  -1 siblings, 0 replies; 36+ messages in thread
From: Michal Kazior @ 2015-02-25 10:34 UTC (permalink / raw)
  To: Marek Puzyniak; +Cc: linux-wireless, ath10k, Marek Kwaczynski

On 25 February 2015 at 08:55, Marek Puzyniak <marek.puzyniak@tieto.com> wrote:
[...]
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index 94a8788..14b99c8 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -604,6 +604,7 @@ struct ath10k {
>         /* protected by conf_mutex */
>         int num_peers;
>         int num_stations;
> +       int tdls_peers;

I don't like the idea of having another var in ath10k which isn't on
hotpath and can be derived from other structures/tools we already
have, i.e. ieee80211_iterate_stations_atomic(). You can use that to
implement ath10k_mac_tdls_num_peers(arvif).


>
>         int max_num_peers;
>         int max_num_stations;
> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
> index 7378656..21720b8 100644
> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -518,6 +518,73 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
>         ar->num_stations = 0;
>  }
>
> +static int ath10k_mac_enable_tdls(struct ath10k *ar, u32 vdev_id, bool enable)

With number of tdls peers being derived you won't be able to have this
kind of "recalc" logic anymore. I guess that's a good thing. You'll
need to call ath10k_wmi_update_fw_tdls_state() explicitly in
ath10k_sta_state() depending on context and numbers of peers.


> +static int ath10k_mac_tdls_peer_update(struct ath10k *ar, u32 vdev_id,
> +                                      struct ieee80211_sta *sta,
> +                                      enum wmi_tdls_peer_state state)
> +{
> +       int ret;
> +       struct wmi_tdls_peer_update_cmd_arg arg;

I would `arg = {};` to make sure it's clean. Even if you're positive
you fill all `arg` members here it leaves it open for bugs sneaking in
when you extend the structure later on and forget to init new members
here as well.


> +       struct wmi_tdls_peer_capab_arg cap = {};
> +       struct wmi_channel_arg chan_arg = {};
> +
> +       lockdep_assert_held(&ar->conf_mutex);
> +
> +       arg.vdev_id = vdev_id;
> +       arg.peer_state = state;
> +       ether_addr_copy(arg.addr, sta->addr);
> +
> +       cap.peer_max_sp = sta->max_sp;
> +       cap.peer_uapsd_queues = sta->uapsd_queues;
> +
> +       if (state == WMI_TDLS_PEER_STATE_CONNECTED) {
> +               if (!sta->tdls_initiator)
> +                       cap.is_peer_responder = 1;
> +       }

You can probably make it into a single if() ?


> @@ -4092,9 +4193,30 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
>                         ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
>                                     sta->addr, arvif->vdev_id, ret);
>         } else if (old_state == IEEE80211_STA_ASSOC &&
> -                  new_state == IEEE80211_STA_AUTH &&
> -                  (vif->type == NL80211_IFTYPE_AP ||
> -                   vif->type == NL80211_IFTYPE_ADHOC)) {
> +                  new_state == IEEE80211_STA_AUTHORIZED &&
> +                  sta->tdls) {
> +               /*
> +                * Tdls station authorized.
> +                */
> +               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac tdls sta %pM authorized\n",
> +                          sta->addr);
> +
> +               ret = ath10k_station_assoc(ar, vif, sta, false);
> +               if (ret) {
> +                       ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",

"failed to associate tdls station...." would be nicer I guess?


> +static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
> +{
> +       u32 peer_qos = 0;
> +
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VO;
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VI;
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BK;
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BE;
> +       peer_qos |= (sp << WMI_TLV_TDLS_PEER_SP_POS);

peer_qos |= (sp << WMI_TLV_TDLS_PEER_SP_SHIFT);

Or even provide _MASK + _SHIFT defines and use SM/MS macros.


> +struct wmi_tdls_peer_update_cmd_arg {
> +       u32 vdev_id;
> +       enum wmi_tdls_peer_state peer_state;
> +       u8 addr[ETH_ALEN];
> +} __packed;

No need to pack local/driver-only structures.


> +struct wmi_tdls_peer_capab_arg {
> +       u8 peer_uapsd_queues;
> +       u8 peer_max_sp;
> +       u32 buff_sta_support;
> +       u32 off_chan_support;
> +       u32 peer_curr_operclass;
> +       u32 self_curr_operclass;
> +       u32 peer_chan_len;
> +       u32 peer_operclass_len;
> +       u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
> +       u32 is_peer_responder;
> +       u32 pref_offchan_num;
> +       u32 pref_offchan_bw;
> +} __packed;

No need to pack local/driver-only structures.


Michał

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

* Re: [PATCH v2 4/4] ath10k: introduce basic tdls functionality
@ 2015-02-25 10:34     ` Michal Kazior
  0 siblings, 0 replies; 36+ messages in thread
From: Michal Kazior @ 2015-02-25 10:34 UTC (permalink / raw)
  To: Marek Puzyniak; +Cc: Marek Kwaczynski, linux-wireless, ath10k

On 25 February 2015 at 08:55, Marek Puzyniak <marek.puzyniak@tieto.com> wrote:
[...]
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index 94a8788..14b99c8 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -604,6 +604,7 @@ struct ath10k {
>         /* protected by conf_mutex */
>         int num_peers;
>         int num_stations;
> +       int tdls_peers;

I don't like the idea of having another var in ath10k which isn't on
hotpath and can be derived from other structures/tools we already
have, i.e. ieee80211_iterate_stations_atomic(). You can use that to
implement ath10k_mac_tdls_num_peers(arvif).


>
>         int max_num_peers;
>         int max_num_stations;
> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
> index 7378656..21720b8 100644
> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -518,6 +518,73 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
>         ar->num_stations = 0;
>  }
>
> +static int ath10k_mac_enable_tdls(struct ath10k *ar, u32 vdev_id, bool enable)

With number of tdls peers being derived you won't be able to have this
kind of "recalc" logic anymore. I guess that's a good thing. You'll
need to call ath10k_wmi_update_fw_tdls_state() explicitly in
ath10k_sta_state() depending on context and numbers of peers.


> +static int ath10k_mac_tdls_peer_update(struct ath10k *ar, u32 vdev_id,
> +                                      struct ieee80211_sta *sta,
> +                                      enum wmi_tdls_peer_state state)
> +{
> +       int ret;
> +       struct wmi_tdls_peer_update_cmd_arg arg;

I would `arg = {};` to make sure it's clean. Even if you're positive
you fill all `arg` members here it leaves it open for bugs sneaking in
when you extend the structure later on and forget to init new members
here as well.


> +       struct wmi_tdls_peer_capab_arg cap = {};
> +       struct wmi_channel_arg chan_arg = {};
> +
> +       lockdep_assert_held(&ar->conf_mutex);
> +
> +       arg.vdev_id = vdev_id;
> +       arg.peer_state = state;
> +       ether_addr_copy(arg.addr, sta->addr);
> +
> +       cap.peer_max_sp = sta->max_sp;
> +       cap.peer_uapsd_queues = sta->uapsd_queues;
> +
> +       if (state == WMI_TDLS_PEER_STATE_CONNECTED) {
> +               if (!sta->tdls_initiator)
> +                       cap.is_peer_responder = 1;
> +       }

You can probably make it into a single if() ?


> @@ -4092,9 +4193,30 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
>                         ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
>                                     sta->addr, arvif->vdev_id, ret);
>         } else if (old_state == IEEE80211_STA_ASSOC &&
> -                  new_state == IEEE80211_STA_AUTH &&
> -                  (vif->type == NL80211_IFTYPE_AP ||
> -                   vif->type == NL80211_IFTYPE_ADHOC)) {
> +                  new_state == IEEE80211_STA_AUTHORIZED &&
> +                  sta->tdls) {
> +               /*
> +                * Tdls station authorized.
> +                */
> +               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac tdls sta %pM authorized\n",
> +                          sta->addr);
> +
> +               ret = ath10k_station_assoc(ar, vif, sta, false);
> +               if (ret) {
> +                       ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",

"failed to associate tdls station...." would be nicer I guess?


> +static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
> +{
> +       u32 peer_qos = 0;
> +
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VO;
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VI;
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BK;
> +       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
> +               peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BE;
> +       peer_qos |= (sp << WMI_TLV_TDLS_PEER_SP_POS);

peer_qos |= (sp << WMI_TLV_TDLS_PEER_SP_SHIFT);

Or even provide _MASK + _SHIFT defines and use SM/MS macros.


> +struct wmi_tdls_peer_update_cmd_arg {
> +       u32 vdev_id;
> +       enum wmi_tdls_peer_state peer_state;
> +       u8 addr[ETH_ALEN];
> +} __packed;

No need to pack local/driver-only structures.


> +struct wmi_tdls_peer_capab_arg {
> +       u8 peer_uapsd_queues;
> +       u8 peer_max_sp;
> +       u32 buff_sta_support;
> +       u32 off_chan_support;
> +       u32 peer_curr_operclass;
> +       u32 self_curr_operclass;
> +       u32 peer_chan_len;
> +       u32 peer_operclass_len;
> +       u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
> +       u32 is_peer_responder;
> +       u32 pref_offchan_num;
> +       u32 pref_offchan_bw;
> +} __packed;

No need to pack local/driver-only structures.


Michał

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-02-25  7:55   ` Marek Puzyniak
@ 2015-02-27 12:50     ` Johannes Berg
  -1 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-02-27 12:50 UTC (permalink / raw)
  To: Marek Puzyniak, Arik Nemtsov; +Cc: linux-wireless, ath10k

+Arik.

It'd be nice (for me anyway) if you didn't send this in a series of
other patches I don't care about - I only ever saw this due to
patchwork.

On Wed, 2015-02-25 at 08:55 +0100, Marek Puzyniak wrote:
> Currently when TDLS station in driver goes from assoc
> to authorized state it can not use rate control parameters
> because rate control is not initialized yet. Some drivers
> require parameters already initialized by rate control when
> entering authorized state. It can be done by initializing
> rate control after station transition to authorized state
> but before notifying driver about that.

Arik, you have a similar patch handling only NSS. Does this one look
fine to you, and would it solve the problem your other patch solved?

johannes


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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-02-27 12:50     ` Johannes Berg
  0 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-02-27 12:50 UTC (permalink / raw)
  To: Marek Puzyniak, Arik Nemtsov; +Cc: linux-wireless, ath10k

+Arik.

It'd be nice (for me anyway) if you didn't send this in a series of
other patches I don't care about - I only ever saw this due to
patchwork.

On Wed, 2015-02-25 at 08:55 +0100, Marek Puzyniak wrote:
> Currently when TDLS station in driver goes from assoc
> to authorized state it can not use rate control parameters
> because rate control is not initialized yet. Some drivers
> require parameters already initialized by rate control when
> entering authorized state. It can be done by initializing
> rate control after station transition to authorized state
> but before notifying driver about that.

Arik, you have a similar patch handling only NSS. Does this one look
fine to you, and would it solve the problem your other patch solved?

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-02-27 12:50     ` Johannes Berg
@ 2015-03-01  8:21       ` Arik Nemtsov
  -1 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-01  8:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Fri, Feb 27, 2015 at 2:50 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> +Arik.
>
> It'd be nice (for me anyway) if you didn't send this in a series of
> other patches I don't care about - I only ever saw this due to
> patchwork.
>
> On Wed, 2015-02-25 at 08:55 +0100, Marek Puzyniak wrote:
>> Currently when TDLS station in driver goes from assoc
>> to authorized state it can not use rate control parameters
>> because rate control is not initialized yet. Some drivers
>> require parameters already initialized by rate control when
>> entering authorized state. It can be done by initializing
>> rate control after station transition to authorized state
>> but before notifyiIEEE80211_STA_ASSOCng driver about that.
>
> Arik, you have a similar patch handling only NSS. Does this one look
> fine to you, and would it solve the problem your other patch solved?

Well currently iwlmvm requires the NSS to be set before
IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
I could change mvm a bit to make it work, but I don't really see a
good reason for it :)

The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).

Arik

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-01  8:21       ` Arik Nemtsov
  0 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-01  8:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Fri, Feb 27, 2015 at 2:50 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> +Arik.
>
> It'd be nice (for me anyway) if you didn't send this in a series of
> other patches I don't care about - I only ever saw this due to
> patchwork.
>
> On Wed, 2015-02-25 at 08:55 +0100, Marek Puzyniak wrote:
>> Currently when TDLS station in driver goes from assoc
>> to authorized state it can not use rate control parameters
>> because rate control is not initialized yet. Some drivers
>> require parameters already initialized by rate control when
>> entering authorized state. It can be done by initializing
>> rate control after station transition to authorized state
>> but before notifyiIEEE80211_STA_ASSOCng driver about that.
>
> Arik, you have a similar patch handling only NSS. Does this one look
> fine to you, and would it solve the problem your other patch solved?

Well currently iwlmvm requires the NSS to be set before
IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
I could change mvm a bit to make it work, but I don't really see a
good reason for it :)

The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).

Arik

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-01  8:21       ` Arik Nemtsov
@ 2015-03-03  9:18         ` Johannes Berg
  -1 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-03  9:18 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:

> > Arik, you have a similar patch handling only NSS. Does this one look
> > fine to you, and would it solve the problem your other patch solved?
> 
> Well currently iwlmvm requires the NSS to be set before
> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
> I could change mvm a bit to make it work, but I don't really see a
> good reason for it :)
> 
> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).

Ok, thanks. Do you think it would be possible to move all of this before
ASSOC?

(if not, why not, and how is it that we have valid NSS if we don't have
the remaining data valid?)

johannes


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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-03  9:18         ` Johannes Berg
  0 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-03  9:18 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:

> > Arik, you have a similar patch handling only NSS. Does this one look
> > fine to you, and would it solve the problem your other patch solved?
> 
> Well currently iwlmvm requires the NSS to be set before
> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
> I could change mvm a bit to make it work, but I don't really see a
> good reason for it :)
> 
> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).

Ok, thanks. Do you think it would be possible to move all of this before
ASSOC?

(if not, why not, and how is it that we have valid NSS if we don't have
the remaining data valid?)

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-03  9:18         ` Johannes Berg
@ 2015-03-03 10:02           ` Arik Nemtsov
  -1 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-03 10:02 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Tue, Mar 3, 2015 at 11:18 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:
>
>> > Arik, you have a similar patch handling only NSS. Does this one look
>> > fine to you, and would it solve the problem your other patch solved?
>>
>> Well currently iwlmvm requires the NSS to be set before
>> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
>> I could change mvm a bit to make it work, but I don't really see a
>> good reason for it :)
>>
>> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).
>
> Ok, thanks. Do you think it would be possible to move all of this before
> ASSOC?

We can probably move his rate_control_rate_init() to assoc, since we have this:

/*
* TDLS -- everything follows authorized, but
* only becoming authorized is possible, not
* going back
*/
if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
      BIT(NL80211_STA_FLAG_ASSOCIATED);
mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
BIT(NL80211_STA_FLAG_ASSOCIATED);
}

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-03 10:02           ` Arik Nemtsov
  0 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-03 10:02 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Tue, Mar 3, 2015 at 11:18 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:
>
>> > Arik, you have a similar patch handling only NSS. Does this one look
>> > fine to you, and would it solve the problem your other patch solved?
>>
>> Well currently iwlmvm requires the NSS to be set before
>> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
>> I could change mvm a bit to make it work, but I don't really see a
>> good reason for it :)
>>
>> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).
>
> Ok, thanks. Do you think it would be possible to move all of this before
> ASSOC?

We can probably move his rate_control_rate_init() to assoc, since we have this:

/*
* TDLS -- everything follows authorized, but
* only becoming authorized is possible, not
* going back
*/
if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
      BIT(NL80211_STA_FLAG_ASSOCIATED);
mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
BIT(NL80211_STA_FLAG_ASSOCIATED);
}

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-03 10:02           ` Arik Nemtsov
@ 2015-03-03 10:06             ` Johannes Berg
  -1 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-03 10:06 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Tue, 2015-03-03 at 12:02 +0200, Arik Nemtsov wrote:
> On Tue, Mar 3, 2015 at 11:18 AM, Johannes Berg
> <johannes@sipsolutions.net> wrote:
> > On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:
> >
> >> > Arik, you have a similar patch handling only NSS. Does this one look
> >> > fine to you, and would it solve the problem your other patch solved?
> >>
> >> Well currently iwlmvm requires the NSS to be set before
> >> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
> >> I could change mvm a bit to make it work, but I don't really see a
> >> good reason for it :)
> >>
> >> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).
> >
> > Ok, thanks. Do you think it would be possible to move all of this before
> > ASSOC?
> 
> We can probably move his rate_control_rate_init() to assoc, since we have this:

And doing so would also address the nss problem, right? IIRC that's done
in the rate control init inline.

johannes


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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-03 10:06             ` Johannes Berg
  0 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-03 10:06 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Tue, 2015-03-03 at 12:02 +0200, Arik Nemtsov wrote:
> On Tue, Mar 3, 2015 at 11:18 AM, Johannes Berg
> <johannes@sipsolutions.net> wrote:
> > On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:
> >
> >> > Arik, you have a similar patch handling only NSS. Does this one look
> >> > fine to you, and would it solve the problem your other patch solved?
> >>
> >> Well currently iwlmvm requires the NSS to be set before
> >> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
> >> I could change mvm a bit to make it work, but I don't really see a
> >> good reason for it :)
> >>
> >> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).
> >
> > Ok, thanks. Do you think it would be possible to move all of this before
> > ASSOC?
> 
> We can probably move his rate_control_rate_init() to assoc, since we have this:

And doing so would also address the nss problem, right? IIRC that's done
in the rate control init inline.

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-03 10:06             ` Johannes Berg
@ 2015-03-03 10:07               ` Arik Nemtsov
  -1 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-03 10:07 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Tue, Mar 3, 2015 at 12:06 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Tue, 2015-03-03 at 12:02 +0200, Arik Nemtsov wrote:
>> On Tue, Mar 3, 2015 at 11:18 AM, Johannes Berg
>> <johannes@sipsolutions.net> wrote:
>> > On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:
>> >
>> >> > Arik, you have a similar patch handling only NSS. Does this one look
>> >> > fine to you, and would it solve the problem your other patch solved?
>> >>
>> >> Well currently iwlmvm requires the NSS to be set before
>> >> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
>> >> I could change mvm a bit to make it work, but I don't really see a
>> >> good reason for it :)
>> >>
>> >> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).
>> >
>> > Ok, thanks. Do you think it would be possible to move all of this before
>> > ASSOC?
>>
>> We can probably move his rate_control_rate_init() to assoc, since we have this:
>
> And doing so would also address the nss problem, right? IIRC that's done
> in the rate control init inline.

Right.

Arik

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-03 10:07               ` Arik Nemtsov
  0 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-03 10:07 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Tue, Mar 3, 2015 at 12:06 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Tue, 2015-03-03 at 12:02 +0200, Arik Nemtsov wrote:
>> On Tue, Mar 3, 2015 at 11:18 AM, Johannes Berg
>> <johannes@sipsolutions.net> wrote:
>> > On Sun, 2015-03-01 at 10:21 +0200, Arik Nemtsov wrote:
>> >
>> >> > Arik, you have a similar patch handling only NSS. Does this one look
>> >> > fine to you, and would it solve the problem your other patch solved?
>> >>
>> >> Well currently iwlmvm requires the NSS to be set before
>> >> IEEE80211_STA_ASSOC (earlier), so this doesn't help directly.
>> >> I could change mvm a bit to make it work, but I don't really see a
>> >> good reason for it :)
>> >>
>> >> The patch looks good. Shouldn't introduce new issues (at least for iwlwifi).
>> >
>> > Ok, thanks. Do you think it would be possible to move all of this before
>> > ASSOC?
>>
>> We can probably move his rate_control_rate_init() to assoc, since we have this:
>
> And doing so would also address the nss problem, right? IIRC that's done
> in the rate control init inline.

Right.

Arik

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-03 10:07               ` Arik Nemtsov
@ 2015-03-04  8:16                 ` Johannes Berg
  -1 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-04  8:16 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Tue, 2015-03-03 at 12:07 +0200, Arik Nemtsov wrote:

> > And doing so would also address the nss problem, right? IIRC that's done
> > in the rate control init inline.
> 
> Right.

Can one of you (Marek/Arik) send a combined patch then please? :)

johannes


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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-04  8:16                 ` Johannes Berg
  0 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-04  8:16 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Tue, 2015-03-03 at 12:07 +0200, Arik Nemtsov wrote:

> > And doing so would also address the nss problem, right? IIRC that's done
> > in the rate control init inline.
> 
> Right.

Can one of you (Marek/Arik) send a combined patch then please? :)

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-04  8:16                 ` Johannes Berg
@ 2015-03-04 10:04                   ` Arik Nemtsov
  -1 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-04 10:04 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Wed, Mar 4, 2015 at 10:16 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Tue, 2015-03-03 at 12:07 +0200, Arik Nemtsov wrote:
>
>> > And doing so would also address the nss problem, right? IIRC that's done
>> > in the rate control init inline.
>>
>> Right.
>
> Can one of you (Marek/Arik) send a combined patch then please? :)

I can do it, but I'll probably only get to it next week.

Arik

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-04 10:04                   ` Arik Nemtsov
  0 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-04 10:04 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Wed, Mar 4, 2015 at 10:16 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Tue, 2015-03-03 at 12:07 +0200, Arik Nemtsov wrote:
>
>> > And doing so would also address the nss problem, right? IIRC that's done
>> > in the rate control init inline.
>>
>> Right.
>
> Can one of you (Marek/Arik) send a combined patch then please? :)

I can do it, but I'll probably only get to it next week.

Arik

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-04 10:04                   ` Arik Nemtsov
@ 2015-03-04 10:38                     ` Marek Puzyniak
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-03-04 10:38 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Johannes Berg, Arik Nemtsov, linux-wireless, ath10k

On 4 March 2015 at 11:04, Arik Nemtsov <arik@wizery.com> wrote:
> I can do it, but I'll probably only get to it next week.

I will try to prepare patch this week, if not I will wait for Arik's
proposition.

For ath10k rate control need to be initialised before moving to
STA_AUTHORIZED, so initialising rate control before STA_ASSOC is
perfectly fine.

Marek

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-04 10:38                     ` Marek Puzyniak
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Puzyniak @ 2015-03-04 10:38 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Johannes Berg, linux-wireless, ath10k, Arik Nemtsov

On 4 March 2015 at 11:04, Arik Nemtsov <arik@wizery.com> wrote:
> I can do it, but I'll probably only get to it next week.

I will try to prepare patch this week, if not I will wait for Arik's
proposition.

For ath10k rate control need to be initialised before moving to
STA_AUTHORIZED, so initialising rate control before STA_ASSOC is
perfectly fine.

Marek

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-02-27 12:50     ` Johannes Berg
@ 2015-03-04 15:01       ` Kalle Valo
  -1 siblings, 0 replies; 36+ messages in thread
From: Kalle Valo @ 2015-03-04 15:01 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

Johannes Berg <johannes@sipsolutions.net> writes:

> +Arik.
>
> It'd be nice (for me anyway) if you didn't send this in a series of
> other patches I don't care about - I only ever saw this due to
> patchwork.

Yes, mac80211 and driver patches need to be sent in separate series. I
will drop this series for now, please resend ath10k patches separetely.

AND please clearly document what mac80211 patches the ath10k patches
depend on.

-- 
Kalle Valo

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-04 15:01       ` Kalle Valo
  0 siblings, 0 replies; 36+ messages in thread
From: Kalle Valo @ 2015-03-04 15:01 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

Johannes Berg <johannes@sipsolutions.net> writes:

> +Arik.
>
> It'd be nice (for me anyway) if you didn't send this in a series of
> other patches I don't care about - I only ever saw this due to
> patchwork.

Yes, mac80211 and driver patches need to be sent in separate series. I
will drop this series for now, please resend ath10k patches separetely.

AND please clearly document what mac80211 patches the ath10k patches
depend on.

-- 
Kalle Valo

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-04 10:38                     ` Marek Puzyniak
@ 2015-03-04 16:30                       ` Arik Nemtsov
  -1 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-04 16:30 UTC (permalink / raw)
  To: Marek Puzyniak; +Cc: Johannes Berg, Arik Nemtsov, linux-wireless, ath10k

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

On Wed, Mar 4, 2015 at 12:38 PM, Marek Puzyniak
<marek.puzyniak@tieto.com> wrote:
> On 4 March 2015 at 11:04, Arik Nemtsov <arik@wizery.com> wrote:
>> I can do it, but I'll probably only get to it next week.
>
> I will try to prepare patch this week, if not I will wait for Arik's
> proposition.
>
> For ath10k rate control need to be initialised before moving to
> STA_AUTHORIZED, so initialising rate control before STA_ASSOC is
> perfectly fine.

Ok I did get to it today :)
With the attached patch applied, and the patch "mac80211: update TDLS
sta spatial streams before auth" reverted, I'm getting good
performance on iwlwifi.

Arik

[-- Attachment #2: 0001-mac80211-initialize-rate-control-earlier-for-tdls-st.patch --]
[-- Type: text/x-patch, Size: 1915 bytes --]

From 133a9b280c23fa0d49e93dae8655b9514ac71fee Mon Sep 17 00:00:00 2001
From: Marek Puzyniak <marek.puzyniak@tieto.com>
Date: Wed, 25 Feb 2015 08:55:10 +0100
Subject: [PATCH] mac80211: initialize rate control earlier for tdls station

Currently when TDLS station in driver goes from assoc
to authorized state it can not use rate control parameters
because rate control is not initialized yet. Some drivers
require parameters already initialized by rate control when
entering authorized state. It can be done by initializing
rate control after station transition to authorized state
but before notifying driver about that.

Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
---
 net/mac80211/cfg.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c13b1af..55b88c7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -977,6 +977,14 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
 	if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
 	    set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
 	    !test_sta_flag(sta, WLAN_STA_ASSOC)) {
+		/*
+		 * When peer becomes authorized, init rate control as
+		 * well. Some drivers require rate control initialized
+		 * before drv_sta_state() is called.
+		 */
+		if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+			rate_control_rate_init(sta);
+
 		ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
 		if (ret)
 			return ret;
@@ -1381,11 +1389,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 	if (err)
 		goto out_err;
 
-	/* When peer becomes authorized, init rate control as well */
-	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
-	    test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-		rate_control_rate_init(sta);
-
 	mutex_unlock(&local->sta_mtx);
 
 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
-- 
2.1.0


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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-04 16:30                       ` Arik Nemtsov
  0 siblings, 0 replies; 36+ messages in thread
From: Arik Nemtsov @ 2015-03-04 16:30 UTC (permalink / raw)
  To: Marek Puzyniak; +Cc: Johannes Berg, linux-wireless, ath10k, Arik Nemtsov

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

On Wed, Mar 4, 2015 at 12:38 PM, Marek Puzyniak
<marek.puzyniak@tieto.com> wrote:
> On 4 March 2015 at 11:04, Arik Nemtsov <arik@wizery.com> wrote:
>> I can do it, but I'll probably only get to it next week.
>
> I will try to prepare patch this week, if not I will wait for Arik's
> proposition.
>
> For ath10k rate control need to be initialised before moving to
> STA_AUTHORIZED, so initialising rate control before STA_ASSOC is
> perfectly fine.

Ok I did get to it today :)
With the attached patch applied, and the patch "mac80211: update TDLS
sta spatial streams before auth" reverted, I'm getting good
performance on iwlwifi.

Arik

[-- Attachment #2: 0001-mac80211-initialize-rate-control-earlier-for-tdls-st.patch --]
[-- Type: text/x-patch, Size: 1915 bytes --]

From 133a9b280c23fa0d49e93dae8655b9514ac71fee Mon Sep 17 00:00:00 2001
From: Marek Puzyniak <marek.puzyniak@tieto.com>
Date: Wed, 25 Feb 2015 08:55:10 +0100
Subject: [PATCH] mac80211: initialize rate control earlier for tdls station

Currently when TDLS station in driver goes from assoc
to authorized state it can not use rate control parameters
because rate control is not initialized yet. Some drivers
require parameters already initialized by rate control when
entering authorized state. It can be done by initializing
rate control after station transition to authorized state
but before notifying driver about that.

Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
---
 net/mac80211/cfg.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c13b1af..55b88c7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -977,6 +977,14 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
 	if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
 	    set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
 	    !test_sta_flag(sta, WLAN_STA_ASSOC)) {
+		/*
+		 * When peer becomes authorized, init rate control as
+		 * well. Some drivers require rate control initialized
+		 * before drv_sta_state() is called.
+		 */
+		if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+			rate_control_rate_init(sta);
+
 		ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
 		if (ret)
 			return ret;
@@ -1381,11 +1389,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 	if (err)
 		goto out_err;
 
-	/* When peer becomes authorized, init rate control as well */
-	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
-	    test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-		rate_control_rate_init(sta);
-
 	mutex_unlock(&local->sta_mtx);
 
 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
-- 
2.1.0


[-- Attachment #3: Type: text/plain, Size: 146 bytes --]

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
  2015-03-04 16:30                       ` Arik Nemtsov
@ 2015-03-04 18:30                         ` Johannes Berg
  -1 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-04 18:30 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, Arik Nemtsov, linux-wireless, ath10k

On Wed, 2015-03-04 at 18:30 +0200, Arik Nemtsov wrote:
> On Wed, Mar 4, 2015 at 12:38 PM, Marek Puzyniak
> <marek.puzyniak@tieto.com> wrote:
> > On 4 March 2015 at 11:04, Arik Nemtsov <arik@wizery.com> wrote:
> >> I can do it, but I'll probably only get to it next week.
> >
> > I will try to prepare patch this week, if not I will wait for Arik's
> > proposition.
> >
> > For ath10k rate control need to be initialised before moving to
> > STA_AUTHORIZED, so initialising rate control before STA_ASSOC is
> > perfectly fine.
> 
> Ok I did get to it today :)
> With the attached patch applied, and the patch "mac80211: update TDLS
> sta spatial streams before auth" reverted, I'm getting good
> performance on iwlwifi.

Cool. I think I'll apply this, but with the comment fixed to say
"associated" :)

But perhaps you can send this as a real patch to the list?

johannes


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

* Re: [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station
@ 2015-03-04 18:30                         ` Johannes Berg
  0 siblings, 0 replies; 36+ messages in thread
From: Johannes Berg @ 2015-03-04 18:30 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Marek Puzyniak, linux-wireless, ath10k, Arik Nemtsov

On Wed, 2015-03-04 at 18:30 +0200, Arik Nemtsov wrote:
> On Wed, Mar 4, 2015 at 12:38 PM, Marek Puzyniak
> <marek.puzyniak@tieto.com> wrote:
> > On 4 March 2015 at 11:04, Arik Nemtsov <arik@wizery.com> wrote:
> >> I can do it, but I'll probably only get to it next week.
> >
> > I will try to prepare patch this week, if not I will wait for Arik's
> > proposition.
> >
> > For ath10k rate control need to be initialised before moving to
> > STA_AUTHORIZED, so initialising rate control before STA_ASSOC is
> > perfectly fine.
> 
> Ok I did get to it today :)
> With the attached patch applied, and the patch "mac80211: update TDLS
> sta spatial streams before auth" reverted, I'm getting good
> performance on iwlwifi.

Cool. I think I'll apply this, but with the comment fixed to say
"associated" :)

But perhaps you can send this as a real patch to the list?

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

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

end of thread, other threads:[~2015-03-04 18:31 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-25  7:55 [PATCH v2 0/4] ath10k: add basic tdls support Marek Puzyniak
2015-02-25  7:55 ` Marek Puzyniak
2015-02-25  7:55 ` [PATCH v2 1/4] ath10k: unify tx mode and dispatch Marek Puzyniak
2015-02-25  7:55   ` Marek Puzyniak
2015-02-25  7:55 ` [PATCH v2 2/4] ath10k: make peer type configurable Marek Puzyniak
2015-02-25  7:55   ` Marek Puzyniak
2015-02-25  7:55 ` [PATCH v2 3/4] mac80211: initialize rate control earlier for tdls station Marek Puzyniak
2015-02-25  7:55   ` Marek Puzyniak
2015-02-27 12:50   ` Johannes Berg
2015-02-27 12:50     ` Johannes Berg
2015-03-01  8:21     ` Arik Nemtsov
2015-03-01  8:21       ` Arik Nemtsov
2015-03-03  9:18       ` Johannes Berg
2015-03-03  9:18         ` Johannes Berg
2015-03-03 10:02         ` Arik Nemtsov
2015-03-03 10:02           ` Arik Nemtsov
2015-03-03 10:06           ` Johannes Berg
2015-03-03 10:06             ` Johannes Berg
2015-03-03 10:07             ` Arik Nemtsov
2015-03-03 10:07               ` Arik Nemtsov
2015-03-04  8:16               ` Johannes Berg
2015-03-04  8:16                 ` Johannes Berg
2015-03-04 10:04                 ` Arik Nemtsov
2015-03-04 10:04                   ` Arik Nemtsov
2015-03-04 10:38                   ` Marek Puzyniak
2015-03-04 10:38                     ` Marek Puzyniak
2015-03-04 16:30                     ` Arik Nemtsov
2015-03-04 16:30                       ` Arik Nemtsov
2015-03-04 18:30                       ` Johannes Berg
2015-03-04 18:30                         ` Johannes Berg
2015-03-04 15:01     ` Kalle Valo
2015-03-04 15:01       ` Kalle Valo
2015-02-25  7:55 ` [PATCH v2 4/4] ath10k: introduce basic tdls functionality Marek Puzyniak
2015-02-25  7:55   ` Marek Puzyniak
2015-02-25 10:34   ` Michal Kazior
2015-02-25 10:34     ` Michal Kazior

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.