ath11k_nss: ath11k support dynamic vlan

also support offload for the following:

  mac80211:
    * vlan
    * mesh (partial)
  ath11k:
    * vlan
This commit is contained in:
Qosmio 2024-01-13 08:19:32 -05:00 committed by Sean Khan
parent 6e41396273
commit b7fe6cbb4c
17 changed files with 6277 additions and 0 deletions

View File

@ -0,0 +1,381 @@
From 71add81f4a3f1ea505f498d789e7a1721c4d7a6e Mon Sep 17 00:00:00 2001
From: Seevalamuthu Mariappan <seevalam@codeaurora.org>
Date: Mon, 4 Sep 2023 12:48:19 +0530
Subject: [PATCH] ath11k: Add support for dynamic vlan
This patch adds support for dynamic vlan. VLAN group traffics
are encrypted in software. vlan unicast packets shall be taking
8023 xmit path if encap offload is enabled and mcast/bcast will
be using 80211 xmit path.
Metadata info in dp_tx added to notify firmware that the
multicast/broadcast packets are encrypted in sw.
Signed-off-by: Seevalamuthu Mariappan <seevalam@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/core.h | 1 +
drivers/net/wireless/ath/ath11k/dp_tx.c | 80 +++++++++-
drivers/net/wireless/ath/ath11k/dp_tx.h | 198 ++++++++++++++++++++++++
drivers/net/wireless/ath/ath11k/mac.c | 3 +
4 files changed, 279 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -116,6 +116,7 @@ struct ath11k_skb_cb {
u32 cipher;
struct ath11k *ar;
struct ieee80211_vif *vif;
+ u32 pkt_offset;
} __packed;
struct ath11k_skb_rxcb {
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -79,6 +79,43 @@ enum hal_encrypt_type ath11k_dp_tx_get_e
}
}
+#define HTT_META_DATA_ALIGNMENT 0x8
+
+static int ath11k_dp_metadata_align_skb(struct sk_buff *skb, u8 align_len)
+{
+ if (unlikely(skb_cow_head(skb, align_len)))
+ return -ENOMEM;
+
+ skb_push(skb, align_len);
+ memset(skb->data, 0, align_len);
+ return 0;
+}
+
+static int ath11k_dp_prepare_htt_metadata(struct sk_buff *skb,
+ u8 *htt_metadata_size)
+{
+ u8 htt_desc_size;
+ /* Size rounded of multiple of 8 bytes */
+ u8 htt_desc_size_aligned;
+ int ret;
+ struct htt_tx_msdu_desc_ext *desc_ext;
+
+ htt_desc_size = sizeof(struct htt_tx_msdu_desc_ext);
+ htt_desc_size_aligned = ALIGN(htt_desc_size, HTT_META_DATA_ALIGNMENT);
+
+ ret = ath11k_dp_metadata_align_skb(skb, htt_desc_size_aligned);
+ if (unlikely(ret))
+ return ret;
+
+ desc_ext = (struct htt_tx_msdu_desc_ext *)skb->data;
+ desc_ext->valid_encrypt_type = 1;
+ desc_ext->encrypt_type = 0;
+ desc_ext->host_tx_desc_pool = 1;
+ *htt_metadata_size = htt_desc_size_aligned;
+
+ return 0;
+}
+
int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
struct ath11k_sta *arsta, struct sk_buff *skb)
{
@@ -96,7 +133,8 @@ int ath11k_dp_tx(struct ath11k *ar, stru
int ret;
u32 ring_selector = 0;
u8 ring_map = 0;
- bool tcl_ring_retry;
+ bool tcl_ring_retry, is_diff_encap = false;
+ u8 align_pad, htt_meta_size = 0;
if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)))
return -ESHUTDOWN;
@@ -189,7 +227,10 @@ tcl_ring_sel:
switch (ti.encap_type) {
case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
- ath11k_dp_tx_encap_nwifi(skb);
+ if (arvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
+ is_diff_encap = true;
+ else
+ ath11k_dp_tx_encap_nwifi(skb);
break;
case HAL_TCL_ENCAP_TYPE_RAW:
if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) {
@@ -208,6 +249,33 @@ tcl_ring_sel:
goto fail_remove_idr;
}
+ /* Add metadata for sw encrypted vlan group traffic */
+ if ((!test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) &&
+ !(info->control.flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
+ !info->control.hw_key && ieee80211_has_protected(hdr->frame_control)) ||
+ (skb->protocol == cpu_to_be16(ETH_P_PAE) && is_diff_encap)) {
+ /* HW requirement is that metadata should always point to a
+ * 8-byte aligned address. So we add alignment pad to start of
+ * buffer. HTT Metadata should be ensured to be multiple of 8-bytes
+ * to get 8-byte aligned start address along with align_pad added
+ */
+ align_pad = ((unsigned long)skb->data) & (HTT_META_DATA_ALIGNMENT - 1);
+ ret = ath11k_dp_metadata_align_skb(skb, align_pad);
+ if (unlikely(ret))
+ goto fail_remove_idr;
+
+ ti.pkt_offset += align_pad;
+ ret = ath11k_dp_prepare_htt_metadata(skb, &htt_meta_size);
+ if (unlikely(ret))
+ goto fail_remove_idr;
+
+ ti.pkt_offset += htt_meta_size;
+ ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT;
+ ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TO_FW, 1);
+ ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW;
+ ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
+ }
+
ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) {
atomic_inc(&ab->soc_stats.tx_err.misc_fail);
@@ -216,7 +284,8 @@ tcl_ring_sel:
goto fail_remove_idr;
}
- ti.data_len = skb->len;
+ ti.data_len = skb->len - ti.pkt_offset;
+ skb_cb->pkt_offset = ti.pkt_offset;
skb_cb->paddr = ti.paddr;
skb_cb->vif = arvif->vif;
skb_cb->ar = ar;
@@ -272,6 +341,8 @@ fail_unmap_dma:
dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
fail_remove_idr:
+ if (ti.pkt_offset)
+ skb_pull(skb, ti.pkt_offset);
spin_lock_bh(&tx_ring->tx_idr_lock);
idr_remove(&tx_ring->txbuf_idr,
FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ti.desc_id));
@@ -358,6 +429,9 @@ ath11k_dp_tx_htt_tx_complete_buf(struct
flags = skb_cb->flags;
vif = skb_cb->vif;
+ if (skb_cb->pkt_offset)
+ skb_pull(msdu, skb_cb->pkt_offset); /* removing the alignment and htt meta data */
+
memset(&info->status, 0, sizeof(info->status));
if (ts->acked) {
--- a/drivers/net/wireless/ath/ath11k/dp_tx.h
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.h
@@ -16,6 +16,204 @@ struct ath11k_dp_htt_wbm_tx_status {
u16 peer_id;
};
+/* htt_tx_msdu_desc_ext
+ *
+ * valid_pwr
+ * if set, tx pwr spec is valid
+ *
+ * valid_mcs_mask
+ * if set, tx MCS mask is valid
+ *
+ * valid_nss_mask
+ * if set, tx Nss mask is valid
+ *
+ * valid_preamble_type
+ * if set, tx preamble spec is valid
+ *
+ * valid_retries
+ * if set, tx retries spec is valid
+ *
+ * valid_bw_info
+ * if set, tx dyn_bw and bw_mask are valid
+ *
+ * valid_guard_interval
+ * if set, tx guard intv spec is valid
+ *
+ * valid_chainmask
+ * if set, tx chainmask is valid
+ *
+ * valid_encrypt_type
+ * if set, encrypt type is valid
+ *
+ * valid_key_flags
+ * if set, key flags is valid
+ *
+ * valid_expire_tsf
+ * if set, tx expire TSF spec is valid
+ *
+ * valid_chanfreq
+ * if set, chanfreq is valid
+ *
+ * is_dsrc
+ * if set, MSDU is a DSRC frame
+ *
+ * guard_interval
+ * 0.4us, 0.8us, 1.6us, 3.2us
+ *
+ * encrypt_type
+ * 0 = NO_ENCRYPT,
+ * 1 = ENCRYPT,
+ * 2 ~ 3 - Reserved
+ *
+ * retry_limit
+ * Specify the maximum number of transmissions, including the
+ * initial transmission, to attempt before giving up if no ack
+ * is received.
+ * If the tx rate is specified, then all retries shall use the
+ * same rate as the initial transmission.
+ * If no tx rate is specified, the target can choose whether to
+ * retain the original rate during the retransmissions, or to
+ * fall back to a more robust rate.
+ *
+ * use_dcm_11ax
+ * If set, Use Dual subcarrier modulation.
+ * Valid only for 11ax preamble types HE_SU
+ * and HE_EXT_SU
+ *
+ * ltf_subtype_11ax
+ * Takes enum values of htt_11ax_ltf_subtype_t
+ * Valid only for 11ax preamble types HE_SU
+ * and HE_EXT_SU
+ *
+ * dyn_bw
+ * 0 = static bw, 1 = dynamic bw
+ *
+ * bw_mask
+ * Valid only if dyn_bw == 0 (static bw).
+ *
+ * host_tx_desc_pool
+ * If set, Firmware allocates tx_descriptors
+ * in WAL_BUFFERID_TX_HOST_DATA_EXP,instead
+ * of WAL_BUFFERID_TX_TCL_DATA_EXP.
+ * Use cases:
+ * Any time firmware uses TQM-BYPASS for Data
+ * TID, firmware expect host to set this bit.
+ *
+ * power
+ * unit of the power field is 0.5 dbm
+ * signed value ranging from -64dbm to 63.5 dbm
+ *
+ * mcs_mask
+ * mcs bit mask of 0 ~ 11
+ * Setting more than one MCS isn't currently
+ * supported by the target (but is supported
+ * in the interface in case in the future
+ * the target supports specifications of
+ * a limited set of MCS values.
+ *
+ * nss_mask
+ * Nss bit mask 0 ~ 7
+ * Setting more than one Nss isn't currently
+ * supported by the target (but is supported
+ * in the interface in case in the future
+ * the target supports specifications of
+ * a limited set of Nss values.
+ *
+ * pream_type
+ * Preamble types
+ *
+ * update_peer_cache
+ * When set these custom values will be
+ * used for all packets, until the next
+ * update via this ext header.
+ * This is to make sure not all packets
+ * need to include this header.
+ *
+ * chain_mask
+ * specify which chains to transmit from
+ *
+ * key_flags
+ * Key Index and related flags - used in mesh mode
+ *
+ * chanfreq
+ * Channel frequency: This identifies the desired channel
+ * frequency (in MHz) for tx frames. This is used by FW to help
+ * determine when it is safe to transmit or drop frames for
+ * off-channel operation.
+ * The default value of zero indicates to FW that the corresponding
+ * VDEV's home channel (if there is one) is the desired channel
+ * frequency.
+ *
+ * expire_tsf_lo
+ * tx expiry time (TSF) LSBs
+ *
+ * expire_tsf_hi
+ * tx expiry time (TSF) MSBs
+ *
+ * learning_frame
+ * When this flag is set, this frame will be dropped by FW
+ * rather than being enqueued to the Transmit Queue Manager (TQM) HW.
+ *
+ * send_as_standalone
+ * This will indicate if the msdu needs to be sent as a singleton PPDU,
+ * i.e. with no A-MSDU or A-MPDU aggregation.
+ * The scope is extended to other use-cases.
+ *
+ * is_host_opaque_valid
+ * set this bit to 1 if the host_opaque_cookie is populated
+ * with valid information.
+ *
+ * host_opaque_cookie
+ * Host opaque cookie for special frames
+ */
+
+struct htt_tx_msdu_desc_ext {
+ u32
+ valid_pwr : 1,
+ valid_mcs_mask : 1,
+ valid_nss_mask : 1,
+ valid_preamble_type : 1,
+ valid_retries : 1,
+ valid_bw_info : 1,
+ valid_guard_interval : 1,
+ valid_chainmask : 1,
+ valid_encrypt_type : 1,
+ valid_key_flags : 1,
+ valid_expire_tsf : 1,
+ valid_chanfreq : 1,
+ is_dsrc : 1,
+ guard_interval : 2,
+ encrypt_type : 2,
+ retry_limit : 4,
+ use_dcm_11ax : 1,
+ ltf_subtype_11ax : 2,
+ dyn_bw : 1,
+ bw_mask : 6,
+ host_tx_desc_pool : 1;
+ u32
+ power : 8,
+ mcs_mask : 12,
+ nss_mask : 8,
+ pream_type : 3,
+ update_peer_cache : 1;
+ u32
+ chain_mask : 8,
+ key_flags : 8,
+ chanfreq : 16;
+
+ u32 expire_tsf_lo;
+ u32 expire_tsf_hi;
+
+ u32
+ learning_frame : 1,
+ send_as_standalone : 1,
+ is_host_opaque_valid : 1,
+ rsvd0 : 29;
+ u32
+ host_opaque_cookie : 16,
+ rsvd1 : 16;
+} __packed;
+
void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts);
int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab);
int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -9764,6 +9764,9 @@ static int __ath11k_mac_register(struct
*/
ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR);
+ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+ ar->hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
+
/* Apply the regd received during initialization */
ret = ath11k_regd_update(ar);
if (ret) {

View File

@ -0,0 +1,80 @@
From 6a9662d48c4f277380283050370ab3f1f940b6a6 Mon Sep 17 00:00:00 2001
From: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
Date: Mon, 4 Sep 2023 13:44:47 +0530
Subject: [PATCH] ath11k: skip HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE config
Don't set HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE flag to TCL,
HW only take care of tid classification if this flag is not set.
Signed-off-by: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
---
drivers/net/wireless/ath/ath11k/dp_tx.c | 19 +------------------
drivers/net/wireless/ath/ath11k/hal_tx.c | 1 -
drivers/net/wireless/ath/ath11k/mac.c | 2 ++
3 files changed, 3 insertions(+), 19 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -44,19 +44,6 @@ static void ath11k_dp_tx_encap_nwifi(str
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
}
-static u8 ath11k_dp_tx_get_tid(struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr = (void *)skb->data;
- struct ath11k_skb_cb *cb = ATH11K_SKB_CB(skb);
-
- if (cb->flags & ATH11K_SKB_HW_80211_ENCAP)
- return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
- else if (!ieee80211_is_data_qos(hdr->frame_control))
- return HAL_DESC_REO_NON_QOS_TID;
- else
- return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
-}
-
enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher)
{
switch (cipher) {
@@ -143,9 +130,8 @@ int ath11k_dp_tx(struct ath11k *ar, stru
!ieee80211_is_data(hdr->frame_control)))
return -ENOTSUPP;
- pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
-
ring_selector = ab->hw_params.hw_ops->get_ring_selector(skb);
+ pool_id = ring_selector;
tcl_ring_sel:
tcl_ring_retry = false;
@@ -221,10 +207,6 @@ tcl_ring_sel:
if (ieee80211_vif_is_mesh(arvif->vif))
ti.enable_mesh = true;
- ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE, 1);
-
- ti.tid = ath11k_dp_tx_get_tid(skb);
-
switch (ti.encap_type) {
case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
if (arvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
--- a/drivers/net/wireless/ath/ath11k/hal_tx.c
+++ b/drivers/net/wireless/ath/ath11k/hal_tx.c
@@ -65,7 +65,6 @@ void ath11k_hal_tx_cmd_desc_setup(struct
FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_PKT_OFFSET, ti->pkt_offset);
tcl_cmd->info2 = ti->flags1 |
- FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID, ti->tid) |
FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_LMAC_ID, ti->lmac_id);
tcl_cmd->info3 = FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_DSCP_TID_TABLE_IDX,
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -9682,6 +9682,8 @@ static int __ath11k_mac_register(struct
ieee80211_hw_set(ar->hw, USES_RSS);
}
+ ieee80211_hw_set(ar->hw, SUPPORTS_TID_CLASS_OFFLOAD);
+
ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;

View File

@ -0,0 +1,45 @@
From c7bd857a315fb299e4c984be2f3720428477ae6e Mon Sep 17 00:00:00 2001
From: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
Date: Thu, 11 Nov 2021 11:14:08 +0530
Subject: [PATCH] ath11k: skip HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE config
Don't set HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE flag to TCL,
HW only take care of tid classification if this flag is not set.
Signed-off-by: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
Signed-off-by: Gautham Kumar Senthilkumaran <quic_gauthamk@quicinc.com>
---
include/net/mac80211.h | 3 +++
net/mac80211/debugfs.c | 1 +
net/mac80211/wme.c | 3 +++
3 files changed, 7 insertions(+)
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2727,6 +2727,8 @@ struct ieee80211_txq {
*
* @IEEE80211_HW_SUPPORTS_NSS_OFFLOAD: Hardware/driver supports NSS offload
*
+ * @IEEE80211_HW_SUPPORTS_TID_CLASS_OFFLOAD: Hardware suports tid calssification offload.
+ *
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@@ -2786,6 +2788,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX,
IEEE80211_HW_SUPPORTS_NSS_OFFLOAD,
IEEE80211_HW_SUPPORTS_MESH_NSS_OFFLOAD,
+ IEEE80211_HW_SUPPORTS_TID_CLASS_OFFLOAD,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -498,6 +498,7 @@ static const char *hw_flag_names[] = {
FLAG(MLO_MCAST_MULTI_LINK_TX),
FLAG(SUPPORTS_NSS_OFFLOAD),
FLAG(SUPPORTS_MESH_NSS_OFFLOAD),
+ FLAG(SUPPORTS_TID_CLASS_OFFLOAD),
#undef FLAG
};

View File

@ -0,0 +1,208 @@
From 0f024902a8a54c70204f5b2f824c5dc74888c536 Mon Sep 17 00:00:00 2001
From: Sriram R <quic_srirrama@quicinc.com>
Date: Wed, 29 Sep 2021 09:30:21 +0530
Subject: [PATCH] mac80211: Add support for mesh fast Rx path
Add support to process rx frames for the mesh destination
when driver supports fast Rx by offloading PN, Duplicate,
reordering to the HW.
Fast Rx from a peer is enabled once the PLINK is established.
Fast Rx is not supported for the forwarding path currently.
Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
---
net/mac80211/cfg.c | 5 +
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh_plink.c | 5 +
net/mac80211/rx.c | 262 ++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 269 insertions(+), 4 deletions(-)
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1747,6 +1747,8 @@ static void sta_apply_mesh_params(struct
/* init at low value */
ewma_mesh_tx_rate_avg_add(&sta->mesh->tx_rate_avg, 10);
+ ieee80211_check_fast_rx(sta);
+
break;
case NL80211_PLINK_LISTEN:
case NL80211_PLINK_BLOCKED:
@@ -1761,6 +1763,7 @@ static void sta_apply_mesh_params(struct
ieee80211_mps_sta_status_update(sta);
changed |= ieee80211_mps_set_sta_local_pm(sta,
NL80211_MESH_POWER_UNKNOWN);
+ ieee80211_check_fast_rx(sta);
break;
default:
/* nothing */
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -381,6 +381,8 @@ static u64 __mesh_plink_deactivate(struc
changed |= ieee80211_mps_set_sta_local_pm(sta,
NL80211_MESH_POWER_UNKNOWN);
+ ieee80211_check_fast_rx(sta);
+
return changed;
}
@@ -846,6 +848,7 @@ static u64 mesh_plink_establish(struct i
mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr);
ieee80211_mps_sta_status_update(sta);
changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode);
+ ieee80211_check_fast_rx(sta);
return changed;
}
@@ -864,7 +867,7 @@ static u64 mesh_plink_fsm(struct ieee802
struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
enum ieee80211_self_protected_actioncode action = 0;
u64 changed = 0;
- bool flush = false;
+ bool flush = false, check_fast_rx = false;
mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,
mplstates[sta->mesh->plink_state], mplevents[event]);
@@ -924,6 +927,7 @@ static u64 mesh_plink_fsm(struct ieee802
break;
case CNF_ACPT:
changed |= mesh_plink_establish(sdata, sta);
+ check_fast_rx = true;
break;
default:
break;
@@ -939,6 +943,7 @@ static u64 mesh_plink_fsm(struct ieee802
break;
case OPN_ACPT:
changed |= mesh_plink_establish(sdata, sta);
+ check_fast_rx = true;
action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
default:
@@ -985,6 +990,10 @@ static u64 mesh_plink_fsm(struct ieee802
break;
}
spin_unlock_bh(&sta->mesh->plink_lock);
+
+ if (check_fast_rx)
+ ieee80211_check_fast_rx(sta);
+
if (flush)
mesh_path_flush_by_nexthop(sta);
if (action) {
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4663,10 +4663,15 @@ void ieee80211_check_fast_rx(struct sta_
break;
case NL80211_IFTYPE_MESH_POINT:
+ /* Not required for NSS mode */
+ if (ieee80211_hw_check(&local->hw, SUPPORTS_NSS_OFFLOAD))
+ goto clear;
+ /* Note: da and sa offs are not static, determine in fast rx path */
+
fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_FROMDS |
IEEE80211_FCTL_TODS);
- fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
- fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
+
+ fastrx.internal_forward = 0;
break;
default:
goto clear;
@@ -4707,7 +4712,7 @@ void ieee80211_check_fast_rx(struct sta_
__release(check_fast_rx);
if (assign)
- new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
+ new = kmemdup(&fastrx, sizeof(fastrx), GFP_ATOMIC);
offload_flags = get_bss_sdata(sdata)->vif.offload_flags;
offload = offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED;
@@ -4890,6 +4895,10 @@ static bool ieee80211_invoke_fast_rx(str
u8 sa[ETH_ALEN];
} addrs __aligned(2);
struct ieee80211_sta_rx_stats *stats;
+ struct ieee80211s_hdr *mesh_hdr;
+ struct mesh_path *mppath;
+ u8 da_offs = fast_rx->da_offs, sa_offs = fast_rx->sa_offs;
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
/* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
* to a common data structure; drivers can implement that per queue
@@ -4939,6 +4948,37 @@ static bool ieee80211_invoke_fast_rx(str
snap_offs += IEEE80211_CCMP_HDR_LEN;
}
+ /* Find corresponding offsets for mesh hdr */
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ if (status->rx_flags & IEEE80211_RX_AMSDU)
+ return false;
+
+ /* All mesh data frames needs to be QoS Data */
+ if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+ return false;
+
+ /* TODO forwarding not handled yet in fast rx */
+ if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr3))
+ return false;
+
+ /* Check if Min Mesh hdr is present */
+ if (!pskb_may_pull(skb, hdrlen + 6))
+ goto drop;
+
+ /* Goto mesh hdr, located at snap offs compared to AP/STA */
+ mesh_hdr = (struct ieee80211s_hdr *) (skb->data + snap_offs);
+
+ /* Only Ext Mesh hdr supported in this path now */
+ if ((mesh_hdr->flags & MESH_FLAGS_AE) != MESH_FLAGS_AE_A5_A6)
+ return false;
+
+ /* Point to eaddr1 and eaddr2 */
+ da_offs = snap_offs + ETH_ALEN;
+ sa_offs = da_offs + ETH_ALEN;
+
+ snap_offs += sizeof(struct ieee80211s_hdr);
+ }
+
if (!ieee80211_vif_is_mesh(&rx->sdata->vif) &&
!(status->rx_flags & IEEE80211_RX_AMSDU)) {
if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
@@ -4976,9 +5016,33 @@ static bool ieee80211_invoke_fast_rx(str
return true;
}
+ /* Update MPP table for the received packet */
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ char *proxied_addr, *mpp_addr;
+
+ mpp_addr = hdr->addr4;
+ proxied_addr = mesh_hdr->eaddr2;
+
+ /* Update mpp for the SA */
+ rcu_read_lock();
+ mppath = mpp_path_lookup(sdata, proxied_addr);
+ if (!mppath) {
+ mpp_path_add(sdata, proxied_addr, mpp_addr);
+ } else {
+ spin_lock_bh(&mppath->state_lock);
+
+ if (!ether_addr_equal(mppath->mpp, mpp_addr))
+ ether_addr_copy(mppath->mpp, mpp_addr);
+
+ mppath->exp_time = jiffies;
+ spin_unlock_bh(&mppath->state_lock);
+ }
+ rcu_read_unlock();
+ }
+
/* do the header conversion - first grab the addresses */
- ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
- ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
+ ether_addr_copy(addrs.da, skb->data + da_offs);
+ ether_addr_copy(addrs.sa, skb->data + sa_offs);
if (ieee80211_vif_is_mesh(&rx->sdata->vif)) {
skb_pull(skb, snap_offs - 2);
put_unaligned_be16(skb->len - 2, skb->data);

View File

@ -0,0 +1,33 @@
From 0628e831520aa2e57aed02aee4a1772b40ce4f9d Mon Sep 17 00:00:00 2001
From: Nagarajan Maran <quic_nmaran@quicinc.com>
Date: Thu, 30 Jun 2022 17:20:29 +0530
Subject: [PATCH] mac80211: fix dynamic vlan warning with monitor interface restart
When monitor interface restarts, in nss offload disabled
case, the encap and decap offload flags are removed
from all the interfaces in that phy#.
However when dynamic VLAN and monitor interfaces are
created in the same phy#, these flags are not updated
correctly, due to which warning calltrace is observed.
Add condition check to update the correct flags in
dynamic VLAN case.
Signed-off-by: Nagarajan Maran <quic_nmaran@quicinc.com>
---
net/mac80211/iface.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -994,7 +994,8 @@ static bool ieee80211_set_sdata_offload_
flags |= IEEE80211_OFFLOAD_DECAP_ENABLED;
if (local->monitors &&
- !ieee80211_hw_check(&local->hw, SUPPORTS_CONC_MON_RX_DECAP))
+ (!ieee80211_hw_check(&local->hw, SUPPORTS_NSS_OFFLOAD) ||
+ !ieee80211_hw_check(&local->hw, SUPPORTS_CONC_MON_RX_DECAP)))
flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;
} else {
flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;

View File

@ -0,0 +1,113 @@
From a76238143218ea348cec4b5d26fe9411338ae09e Mon Sep 17 00:00:00 2001
From: Aaradhana Sahu <quic_aarasahu@quicinc.com>
Date: Fri, 6 Oct 2023 18:19:53 +0530
Subject: [PATCH] mac80211: fix mesh ping issue
Signed-off-by: Aaradhana Sahu <quic_aarasahu@quicinc.com>
---
net/mac80211/rx.c | 68 +++--------------------------------------------
1 file changed, 4 insertions(+), 64 deletions(-)
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4748,16 +4748,14 @@ void ieee80211_check_fast_rx(struct sta_
break;
case NL80211_IFTYPE_MESH_POINT:
- /* Not required for NSS mode */
- if (ieee80211_hw_check(&local->hw, SUPPORTS_NSS_OFFLOAD))
- goto clear;
/* Note: da and sa offs are not static, determine in fast rx path */
fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_FROMDS |
IEEE80211_FCTL_TODS);
-
- fastrx.internal_forward = 0;
- break;
+ fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
+ fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr4);
+ break;
+
default:
goto clear;
}
@@ -4980,10 +4978,7 @@ static bool ieee80211_invoke_fast_rx(str
u8 sa[ETH_ALEN];
} addrs __aligned(2);
struct ieee80211_sta_rx_stats *stats;
- struct ieee80211s_hdr *mesh_hdr;
- struct mesh_path *mppath;
u8 da_offs = fast_rx->da_offs, sa_offs = fast_rx->sa_offs;
- struct ieee80211_sub_if_data *sdata = rx->sdata;
/* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
* to a common data structure; drivers can implement that per queue
@@ -5033,37 +5028,6 @@ static bool ieee80211_invoke_fast_rx(str
snap_offs += IEEE80211_CCMP_HDR_LEN;
}
- /* Find corresponding offsets for mesh hdr */
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- if (status->rx_flags & IEEE80211_RX_AMSDU)
- return false;
-
- /* All mesh data frames needs to be QoS Data */
- if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
- return false;
-
- /* TODO forwarding not handled yet in fast rx */
- if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr3))
- return false;
-
- /* Check if Min Mesh hdr is present */
- if (!pskb_may_pull(skb, hdrlen + 6))
- goto drop;
-
- /* Goto mesh hdr, located at snap offs compared to AP/STA */
- mesh_hdr = (struct ieee80211s_hdr *) (skb->data + snap_offs);
-
- /* Only Ext Mesh hdr supported in this path now */
- if ((mesh_hdr->flags & MESH_FLAGS_AE) != MESH_FLAGS_AE_A5_A6)
- return false;
-
- /* Point to eaddr1 and eaddr2 */
- da_offs = snap_offs + ETH_ALEN;
- sa_offs = da_offs + ETH_ALEN;
-
- snap_offs += sizeof(struct ieee80211s_hdr);
- }
-
if (!ieee80211_vif_is_mesh(&rx->sdata->vif) &&
!(status->rx_flags & IEEE80211_RX_AMSDU)) {
if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
@@ -5101,30 +5065,6 @@ static bool ieee80211_invoke_fast_rx(str
return true;
}
- /* Update MPP table for the received packet */
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- char *proxied_addr, *mpp_addr;
-
- mpp_addr = hdr->addr4;
- proxied_addr = mesh_hdr->eaddr2;
-
- /* Update mpp for the SA */
- rcu_read_lock();
- mppath = mpp_path_lookup(sdata, proxied_addr);
- if (!mppath) {
- mpp_path_add(sdata, proxied_addr, mpp_addr);
- } else {
- spin_lock_bh(&mppath->state_lock);
-
- if (!ether_addr_equal(mppath->mpp, mpp_addr))
- ether_addr_copy(mppath->mpp, mpp_addr);
-
- mppath->exp_time = jiffies;
- spin_unlock_bh(&mppath->state_lock);
- }
- rcu_read_unlock();
- }
-
/* do the header conversion - first grab the addresses */
ether_addr_copy(addrs.da, skb->data + da_offs);
ether_addr_copy(addrs.sa, skb->data + sa_offs);

View File

@ -0,0 +1,324 @@
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -30,6 +30,7 @@
#include "spectral.h"
#include "wow.h"
#include "nss.h"
+#include "vendor.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -637,6 +638,11 @@ struct ath11k_coex_info {
u32 pta_priority;
};
+enum ath11k_ap_ps_state {
+ ATH11K_AP_PS_STATE_OFF,
+ ATH11K_AP_PS_STATE_ON,
+};
+
struct ath11k {
struct ath11k_base *ab;
struct ath11k_pdev *pdev;
@@ -765,6 +771,8 @@ struct ath11k {
int monitor_vdev_id;
struct completion fw_mode_reset;
u8 ftm_msgref;
+ int ap_ps_enabled;
+ enum ath11k_ap_ps_state ap_ps_state;
#ifdef CPTCFG_ATH11K_DEBUGFS
struct ath11k_debug debug;
#endif
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -4963,6 +4963,33 @@ static void ath11k_mac_dec_num_stations(
ar->num_stations--;
}
+int ath11k_mac_ap_ps_recalc(struct ath11k *ar)
+{
+ struct ath11k_vif *arvif;
+ bool has_sta_iface = false;
+ enum ath11k_ap_ps_state state = ATH11K_AP_PS_STATE_OFF;
+ int ret = 0;
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
+ has_sta_iface = true;
+ break;
+ }
+ }
+
+ if (!has_sta_iface && !ar->num_stations && ar->ap_ps_enabled)
+ state = ATH11K_AP_PS_STATE_ON;
+
+ if (ar->ap_ps_state == state)
+ return ret;
+
+ ret = ath11k_wmi_pdev_ap_ps_cmd_send(ar, ar->pdev->pdev_id, state);
+ if (!ret)
+ ar->ap_ps_state = state;
+
+ return ret;
+}
+
static int ath11k_mac_station_add(struct ath11k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -5002,6 +5029,12 @@ static int ath11k_mac_station_add(struct
ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
sta->addr, arvif->vdev_id);
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to send ap ps ret %d\n", ret);
+ goto exit;
+ }
+
if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
if (!arsta->tx_stats) {
@@ -5158,6 +5191,9 @@ static int ath11k_mac_op_sta_state(struc
kfree(arsta->tx_stats);
arsta->tx_stats = NULL;
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret)
+ ath11k_warn(ar->ab, "failed to send ap ps ret %d\n", ret);
kfree(arsta->rx_stats);
arsta->rx_stats = NULL;
@@ -6566,6 +6602,7 @@ static void ath11k_mac_op_stop(struct ie
clear_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
ar->state = ATH11K_STATE_OFF;
+ ar->ap_ps_state = ATH11K_AP_PS_STATE_OFF;
mutex_unlock(&ar->conf_mutex);
cancel_delayed_work_sync(&ar->scan.timeout);
@@ -6973,7 +7010,6 @@ static int ath11k_mac_op_add_interface(s
arvif->vdev_id, ret);
goto err;
}
-
ar->num_created_vdevs++;
ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM created, vdev_id %d\n",
vif->addr, arvif->vdev_id);
@@ -7120,6 +7156,10 @@ static int ath11k_mac_op_add_interface(s
ret);
}
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret)
+ ath11k_warn(ar->ab, "failed to set ap ps ret %d\n", ret);
+
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -7227,6 +7267,7 @@ err_vdev_del:
/* Recalc txpower for remaining vdev */
ath11k_mac_txpower_recalc(ar);
+ ath11k_mac_ap_ps_recalc(ar);
ath11k_debugfs_remove_interface(arvif);
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -135,6 +135,7 @@ void ath11k_mac_11d_scan_start(struct at
void ath11k_mac_11d_scan_stop(struct ath11k *ar);
void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab);
+int ath11k_mac_ap_ps_recalc(struct ath11k *ar);
void ath11k_mac_destroy(struct ath11k_base *ab);
void ath11k_mac_unregister(struct ath11k_base *ab);
int ath11k_mac_register(struct ath11k_base *ab);
--- a/drivers/net/wireless/ath/ath11k/vendor.c
+++ b/drivers/net/wireless/ath/ath11k/vendor.c
@@ -6,7 +6,6 @@
#include <net/netlink.h>
#include <net/mac80211.h>
#include "core.h"
-#include "vendor.h"
#include "debug.h"
static const struct nla_policy
@@ -21,6 +20,11 @@ ath11k_vendor_wlan_prio_policy[QCA_WLAN_
[QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_WEIGHT] = { .type = NLA_U8 },
};
+static const struct nla_policy
+ath11k_vendor_set_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_CONFIG_GTX] = {.type = NLA_FLAG}
+};
+
static int ath11k_vendor_btcoex_configure(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
@@ -101,6 +105,51 @@ out:
return ret;
}
+static int ath11k_vendor_set_wifi_config(struct wiphy *wihpy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ struct ieee80211_vif *vif;
+ struct ath11k_vif *arvif;
+ struct ath11k *ar;
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1];
+ int ret = 0;
+
+ if (!wdev)
+ return -EINVAL;
+
+ vif = wdev_to_ieee80211_vif(wdev);
+ if (!vif)
+ return -EINVAL;
+
+ arvif = (struct ath11k_vif*)vif->drv_priv;
+ if (!arvif)
+ return -EINVAL;
+
+ ar = arvif->ar;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, data, data_len,
+ ath11k_vendor_set_wifi_config_policy, NULL);
+ if (ret) {
+ ath11k_warn(ar->ab, "invalid set wifi config policy attribute\n");
+ goto exit;
+ }
+
+ ar->ap_ps_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GTX]);
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to send ap ps ret %d\n", ret);
+ goto exit;
+ }
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
static struct wiphy_vendor_command ath11k_vendor_commands[] = {
{
.info.vendor_id = QCA_NL80211_VENDOR_ID,
@@ -108,8 +157,18 @@ static struct wiphy_vendor_command ath11
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = ath11k_vendor_btcoex_configure,
- .policy = ath11k_vendor_btcoex_config_policy
- }
+ .policy = ath11k_vendor_btcoex_config_policy,
+ .maxattr = QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_MAX
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = ath11k_vendor_set_wifi_config,
+ .policy = ath11k_vendor_set_wifi_config_policy,
+ .maxattr = QCA_WLAN_VENDOR_ATTR_CONFIG_MAX
+ },
};
int ath11k_vendor_register(struct ath11k *ar)
--- a/drivers/net/wireless/ath/ath11k/vendor.h
+++ b/drivers/net/wireless/ath/ath11k/vendor.h
@@ -9,6 +9,9 @@
#define QCA_NL80211_VENDOR_ID 0x001374
enum qca_nl80211_vendor_subcmds {
+ /* Wi-Fi configuration subcommand */
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
+
/* QCA_NL80211_VENDOR_SUBCMD_BTCOEX_CONFIG: This command is used to
* enable/disable BTCOEX and set priority for different type of WLAN
* traffic over BT low priority traffic. This uses attributes in
@@ -58,7 +61,17 @@ enum qca_wlan_vendor_attr_wlan_prio {
QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_LAST - 1,
};
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION
+ */
+enum qca_wlan_vendor_attr_config {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
+};
/**
* enum qca_wlan_vendor_attr_btcoex_config - Used by the vendor command
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1446,6 +1446,38 @@ ath11k_wmi_rx_reord_queue_remove(struct
return ret;
}
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u8 pdev_id,
+ u32 param_value)
+{
+ struct ath11k_pdev_wmi *wmi = ar->wmi;
+ struct wmi_pdev_ap_ps_cmd *cmd;
+ struct sk_buff *skb;
+ int ret;
+
+ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_pdev_ap_ps_cmd *)skb->data;
+ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+ WMI_TAG_PDEV_GREEN_AP_PS_ENABLE_CMD) |
+ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+ cmd->pdev_id = pdev_id;
+ cmd->param_value = param_value;
+
+ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to send ap ps enable/disable cmd\n");
+ dev_kfree_skb(skb);
+ }
+
+ ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+ "wmi pdev ap ps set pdev id %d value %d\n",
+ pdev_id, param_value);
+
+ return ret;
+}
+
int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id,
u32 param_value, u8 pdev_id)
{
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -3110,6 +3110,12 @@ struct set_fwtest_params {
u32 value;
};
+struct wmi_pdev_ap_ps_cmd {
+ u32 tlv_header;
+ u32 pdev_id;
+ u32 param_value;
+} __packed;
+
struct wmi_fwtest_set_param_cmd_param {
u32 tlv_header;
u32 param_id;
@@ -6628,6 +6634,7 @@ int ath11k_wmi_pdev_non_srg_obss_bssid_e
u32 *bitmap);
int ath11k_send_coex_config_cmd(struct ath11k *ar,
struct coex_config_arg *coex_config);
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u8 pdev_id, u32 value);
int ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id,
u8 bss_color, u32 period,
bool enable);

View File

@ -0,0 +1,68 @@
From 0ff455d1d446e34ae6c2596d4d8491f66fc61913 Mon Sep 17 00:00:00 2001
From: Manish Dharanenthiran <quic_mdharane@quicinc.com>
Date: Sat, 2 Dec 2023 03:38:31 +0530
Subject: [PATCH] wifi: mac80211: Fix memory corruption during mesh beacon
update
During mesh beacon update, u64 flag is used to check for
bit set/unset for validation purpose. But, in
'ieee80211_mbss_info_change_notify' API, unsigned long flag
is modified using sizeof(u64). This leads to following issue:
> 'mbss_changed' flag in 'ieee80211_if_mesh' is declared as
unsigned_long which creates an architecture dependency
(32bit vs 64bit) while modifying it with u64 flag which
leads to memory corruption.
Fix above mentioned issue by replacing unsigned long with u64
for changed flag.
Signed-off-by: Manish Dharanenthiran <quic_mdharane@quicinc.com>
---
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/mesh.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -683,7 +683,7 @@ struct ieee80211_if_mesh {
struct timer_list mesh_path_root_timer;
unsigned long wrkq_flags;
- unsigned long mbss_changed[64 / BITS_PER_LONG];
+ unsigned long mbss_changed;
bool userspace_handles_dfs;
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1183,7 +1183,7 @@ void ieee80211_mbss_info_change_notify(s
/* if we race with running work, worst case this work becomes a noop */
for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
- set_bit(bit, ifmsh->mbss_changed);
+ set_bit(bit, &ifmsh->mbss_changed);
set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
}
@@ -1265,7 +1265,7 @@ void ieee80211_stop_mesh(struct ieee8021
/* clear any mesh work (for next join) we may have accrued */
ifmsh->wrkq_flags = 0;
- memset(ifmsh->mbss_changed, 0, sizeof(ifmsh->mbss_changed));
+ ifmsh->mbss_changed = 0;
local->fif_other_bss--;
atomic_dec(&local->iff_allmultis);
@@ -1732,9 +1732,9 @@ static void mesh_bss_info_changed(struct
u32 bit;
u64 changed = 0;
- for_each_set_bit(bit, ifmsh->mbss_changed,
+ for_each_set_bit(bit, &ifmsh->mbss_changed,
sizeof(changed) * BITS_PER_BYTE) {
- clear_bit(bit, ifmsh->mbss_changed);
+ clear_bit(bit, &ifmsh->mbss_changed);
changed |= BIT(bit);
}

View File

@ -0,0 +1,113 @@
From fbe5a76d8c9ff1cf3f906a3c863928fc1adcbc95 Mon Sep 17 00:00:00 2001
From: Karthikeyan Kathirvel <kathirve@codeaurora.org>
Date: Tue, 16 Feb 2021 13:44:39 +0530
Subject: [PATCH] ath11k: Add mesh nss offload support
- New capability advertising nss offload support for mesh type
- Mesh obj vap and link vap registration/clean up
- Command/event handling
- New .ch files in ath11k for nss mesh offload related debugs
- Tx/Rx data path on mesh link vap uses native wifi format
- Mesh obj vap handls packets in ether format. No Tx on Mesh
obj vap is expected as packets transmitted in slow path is
supposed to be encapsulated in 802.11 format.
- New mac80211-driver callbacks for mesh vap, mpath and mpp
configurations.
Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@codeaurora.org>
Change-Id: Ib6950344286ba18fab43586262c62dcd09557614
Co-developed-by: Karthikeyan Kathirvel <kathirve@codeaurora.org>
Signed-off-by: Karthikeyan Kathirvel <kathirve@codeaurora.org>
Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/nss.c | 1482 ++++++++++++++++++++++++---
--- a/drivers/net/wireless/ath/ath11k/nss.c
+++ b/drivers/net/wireless/ath/ath11k/nss.c
@@ -35,6 +35,30 @@ ath11k_nss_get_vdev_opmode(struct ath11k
return ATH11K_NSS_OPMODE_UNKNOWN;
}
+static struct ath11k_vif *ath11k_nss_get_arvif_from_dev(struct net_device *dev)
+{
+ struct wireless_dev *wdev;
+ struct ieee80211_vif *vif;
+ struct ath11k_vif *arvif;
+
+ if (!dev)
+ return NULL;
+
+ wdev = dev->ieee80211_ptr;
+ if (!wdev)
+ return NULL;
+
+ vif = wdev_to_ieee80211_vif(wdev);
+ if (!vif)
+ return NULL;
+
+ arvif = (struct ath11k_vif *)vif->drv_priv;
+ if (!arvif)
+ return NULL;
+
+ return arvif;
+}
+
static void ath11k_nss_wifili_stats_sync(struct ath11k_base *ab,
struct nss_wifili_stats_sync_msg *wlsoc_stats)
{
@@ -294,6 +318,9 @@ void ath11k_nss_wifili_event_receive(str
switch (msg_type) {
case NSS_WIFILI_INIT_MSG:
+ ab->nss.response = response;
+ complete(&ab->nss.complete);
+ break;
case NSS_WIFILI_PDEV_INIT_MSG:
case NSS_WIFILI_START_MSG:
case NSS_WIFILI_SOC_RESET_MSG:
@@ -302,7 +329,6 @@ void ath11k_nss_wifili_event_receive(str
ab->nss.response = response;
complete(&ab->nss.complete);
break;
-
case NSS_WIFILI_PEER_CREATE_MSG:
if (response != NSS_CMN_RESPONSE_EMSG)
break;
@@ -463,7 +489,9 @@ ath11k_nss_wifili_ext_callback_fn(struct
ath11k_nss_process_mic_error(ab, skb);
break;
default:
- kfree(skb);
+ ath11k_dbg(ab, ATH11K_DBG_NSS, "unknown packet type received in wifili ext cb %d",
+ wepm->pkt_type);
+ dev_kfree_skb_any(skb);
break;
}
}
@@ -786,24 +814,7 @@ ath11k_nss_vdev_special_data_receive(str
int ret = 0;
struct ath11k_peer *ta_peer = NULL;
- if (!dev) {
- dev_kfree_skb_any(skb);
- return;
- }
-
- wdev = dev->ieee80211_ptr;
- if (!wdev) {
- dev_kfree_skb_any(skb);
- return;
- }
-
- vif = wdev_to_ieee80211_vif(wdev);
- if (!vif) {
- dev_kfree_skb_any(skb);
- return;
- }
-
- arvif = (struct ath11k_vif *)vif->drv_priv;
+ arvif = ath11k_nss_get_arvif_from_dev(dev);
if (!arvif) {
dev_kfree_skb_any(skb);
return;

View File

@ -0,0 +1,608 @@
From 4635ca1f29bc5838d556b09e3c186b76a5198ddb Mon Sep 17 00:00:00 2001
From: Manikanta Pubbisetty <mpubbise@codeaurora.org>
Date: Fri, 18 Aug 2023 11:43:33 +0530
Subject: [PATCH] ath11k: add rx histogram stats
Adding rx rate table and byte level peer rx statistics. Also,
adding a debugfs knob to reset rx stats specific to the peer.
Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/core.h | 19 ++-
drivers/net/wireless/ath/ath11k/debugfs_sta.c | 152 ++++++++++++++++--
drivers/net/wireless/ath/ath11k/dp_rx.c | 95 +++++++++--
drivers/net/wireless/ath/ath11k/dp_rx.h | 19 +++
drivers/net/wireless/ath/ath11k/hal_rx.c | 85 +++++++---
drivers/net/wireless/ath/ath11k/hal_rx.h | 21 +++
drivers/net/wireless/ath/ath11k/hw.c | 18 +++
drivers/net/wireless/ath/ath11k/hw.h | 1 +
8 files changed, 351 insertions(+), 59 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -44,6 +44,8 @@
#define ATH11K_INVALID_HW_MAC_ID 0xFF
#define ATH11K_CONNECTION_LOSS_HZ (3 * HZ)
+#define ATH11K_RX_RATE_TABLE_NUM 320
+#define ATH11K_RX_RATE_TABLE_11AX_NUM 576
/* SMBIOS type containing Board Data File Name Extension */
#define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8
@@ -420,6 +422,17 @@ struct ath11k_vif_iter {
struct ath11k_vif *arvif;
};
+struct ath11k_rx_peer_rate_stats {
+ u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1];
+ u64 vht_mcs_count[HAL_RX_MAX_MCS_VHT + 1];
+ u64 he_mcs_count[HAL_RX_MAX_MCS_HE + 1];
+ u64 nss_count[HAL_RX_MAX_NSS];
+ u64 bw_count[HAL_RX_BW_MAX];
+ u64 gi_count[HAL_RX_GI_MAX];
+ u64 legacy_count[HAL_RX_MAX_NUM_LEGACY_RATES];
+ u64 rx_rate[ATH11K_RX_RATE_TABLE_11AX_NUM];
+};
+
struct ath11k_rx_peer_stats {
u64 num_msdu;
u64 num_mpdu_fcs_ok;
@@ -431,10 +444,6 @@ struct ath11k_rx_peer_stats {
u64 non_ampdu_msdu_count;
u64 stbc_count;
u64 beamformed_count;
- u64 mcs_count[HAL_RX_MAX_MCS + 1];
- u64 nss_count[HAL_RX_MAX_NSS];
- u64 bw_count[HAL_RX_BW_MAX];
- u64 gi_count[HAL_RX_GI_MAX];
u64 coding_count[HAL_RX_SU_MU_CODING_MAX];
u64 tid_count[IEEE80211_NUM_TIDS + 1];
u64 pream_cnt[HAL_RX_PREAMBLE_MAX];
@@ -442,6 +451,8 @@ struct ath11k_rx_peer_stats {
u64 rx_duration;
u64 dcm_count;
u64 ru_alloc_cnt[HAL_RX_RU_ALLOC_TYPE_MAX];
+ struct ath11k_rx_peer_rate_stats pkt_stats;
+ struct ath11k_rx_peer_rate_stats byte_stats;
};
#define ATH11K_HE_MCS_NUM 12
--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
@@ -10,6 +10,7 @@
#include "peer.h"
#include "debug.h"
#include "dp_tx.h"
+#include "dp_rx.h"
#include "debugfs_htt_stats.h"
static inline u32 ath11k_he_tones_in_ru_to_nl80211_he_ru_alloc(u16 ru_tones)
@@ -390,8 +391,14 @@ static ssize_t ath11k_dbg_sta_dump_rx_st
struct ath11k *ar = arsta->arvif->ar;
struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
int len = 0, i, retval = 0;
- const int size = 4096;
+ const int size = 4 * 4096;
char *buf;
+ int he_rates_avail = (rx_stats->pream_cnt[HAL_RX_PREAMBLE_11AX] > 1) ? 1 : 0;
+ int rate_table_len = he_rates_avail ? ATH11K_RX_RATE_TABLE_11AX_NUM :
+ ATH11K_RX_RATE_TABLE_NUM;
+ char *legacy_rate_str[] = {"1Mbps", "2Mbps", "5.5Mbps", "6Mbps",
+ "9Mbps", "11Mbps", "12Mbps", "18Mbps",
+ "24Mbps", "36 Mbps", "48Mbps", "54Mbps"};
if (!rx_stats)
return -ENOENT;
@@ -422,14 +429,6 @@ static ssize_t ath11k_dbg_sta_dump_rx_st
rx_stats->num_mpdu_fcs_ok);
len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
rx_stats->num_mpdu_fcs_err);
- len += scnprintf(buf + len, size - len,
- "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
- rx_stats->gi_count[0], rx_stats->gi_count[1],
- rx_stats->gi_count[2], rx_stats->gi_count[3]);
- len += scnprintf(buf + len, size - len,
- "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
- rx_stats->bw_count[0], rx_stats->bw_count[1],
- rx_stats->bw_count[2], rx_stats->bw_count[3]);
len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
rx_stats->coding_count[0], rx_stats->coding_count[1]);
len += scnprintf(buf + len, size - len,
@@ -444,14 +443,96 @@ static ssize_t ath11k_dbg_sta_dump_rx_st
len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
- len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
- for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
- len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
- len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
- for (i = 0; i < HAL_RX_MAX_NSS; i++)
- len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
- len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
+ len += scnprintf(buf + len, size - len, "\nRX Duration:%llu\n",
rx_stats->rx_duration);
+
+ len += scnprintf(buf + len, size - len, "\nRX success packet stats:\n");
+ len += scnprintf(buf + len, size - len, "\nHE packet stats:\n");
+ for (i = 0; i <= HAL_RX_MAX_MCS_HE; i++)
+ len += scnprintf(buf + len, size - len, "MCS %d: %llu%s", i,
+ rx_stats->pkt_stats.he_mcs_count[i],
+ (i + 1) % 6 ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len, "\nVHT packet stats:\n");
+ for (i = 0; i <= HAL_RX_MAX_MCS_VHT; i++)
+ len += scnprintf(buf + len, size - len, "MCS %d: %llu%s", i,
+ rx_stats->pkt_stats.vht_mcs_count[i],
+ (i + 1) % 5 ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len, "\nHT packet stats:\n");
+ for (i = 0; i <= HAL_RX_MAX_MCS_HT; i++)
+ len += scnprintf(buf + len, size - len, "MCS %d: %llu%s", i,
+ rx_stats->pkt_stats.ht_mcs_count[i],
+ (i + 1) % 8 ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len, "\nLegacy rate packet stats:\n");
+ for (i = 0; i < HAL_RX_MAX_NUM_LEGACY_RATES; i++)
+ len += scnprintf(buf + len, size - len, "%s: %llu%s", legacy_rate_str[i],
+ rx_stats->pkt_stats.legacy_count[i],
+ (i + 1) % 4 ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len, "\nNSS packet stats:\n");
+ for (i = 0; i < HAL_RX_MAX_NSS; i++)
+ len += scnprintf(buf + len, size - len, "%dx%d: %llu ", i + 1, i + 1,
+ rx_stats->pkt_stats.nss_count[i]);
+ len += scnprintf(buf + len, size - len,
+ "\n\nGI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
+ rx_stats->pkt_stats.gi_count[0],
+ rx_stats->pkt_stats.gi_count[1],
+ rx_stats->pkt_stats.gi_count[2],
+ rx_stats->pkt_stats.gi_count[3]);
+ len += scnprintf(buf + len, size - len,
+ "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
+ rx_stats->pkt_stats.bw_count[0],
+ rx_stats->pkt_stats.bw_count[1],
+ rx_stats->pkt_stats.bw_count[2],
+ rx_stats->pkt_stats.bw_count[3]);
+ len += scnprintf(buf + len, size - len, "\nRate Table (packets):\n");
+ for (i = 0; i < rate_table_len; i++)
+ len += scnprintf(buf + len, size - len, "%10llu%s",
+ rx_stats->pkt_stats.rx_rate[i],
+ (i + 1) % (he_rates_avail ? 12 : 8) ? "\t" : "\n");
+
+ len += scnprintf(buf + len, size - len, "\nRX success byte stats:\n");
+ len += scnprintf(buf + len, size - len, "\nHE byte stats:\n");
+ for (i = 0; i <= HAL_RX_MAX_MCS_HE; i++)
+ len += scnprintf(buf + len, size - len, "MCS %d: %llu%s", i,
+ rx_stats->byte_stats.he_mcs_count[i],
+ (i + 1) % 6 ? "\t" : "\n");
+
+ len += scnprintf(buf + len, size - len, "\nVHT byte stats:\n");
+ for (i = 0; i <= HAL_RX_MAX_MCS_VHT; i++)
+ len += scnprintf(buf + len, size - len, "MCS %d: %llu%s", i,
+ rx_stats->byte_stats.vht_mcs_count[i],
+ (i + 1) % 5 ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len, "\nHT byte stats:\n");
+ for (i = 0; i <= HAL_RX_MAX_MCS_HT; i++)
+ len += scnprintf(buf + len, size - len, "MCS %d: %llu%s", i,
+ rx_stats->byte_stats.ht_mcs_count[i],
+ (i + 1) % 8 ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len, "\nLegacy rate byte stats:\n");
+ for (i = 0; i < HAL_RX_MAX_NUM_LEGACY_RATES; i++)
+ len += scnprintf(buf + len, size - len, "%s: %llu%s", legacy_rate_str[i],
+ rx_stats->byte_stats.legacy_count[i],
+ (i + 1) % 4 ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len, "\nNSS byte stats:\n");
+ for (i = 0; i < HAL_RX_MAX_NSS; i++)
+ len += scnprintf(buf + len, size - len, "%dx%d: %llu ", i + 1, i + 1,
+ rx_stats->byte_stats.nss_count[i]);
+ len += scnprintf(buf + len, size - len,
+ "\n\nGI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
+ rx_stats->byte_stats.gi_count[0],
+ rx_stats->byte_stats.gi_count[1],
+ rx_stats->byte_stats.gi_count[2],
+ rx_stats->byte_stats.gi_count[3]);
+ len += scnprintf(buf + len, size - len,
+ "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
+ rx_stats->byte_stats.bw_count[0],
+ rx_stats->byte_stats.bw_count[1],
+ rx_stats->byte_stats.bw_count[2],
+ rx_stats->byte_stats.bw_count[3]);
+ len += scnprintf(buf + len, size - len, "\nRate Table (bytes):\n");
+ for (i = 0; i < rate_table_len; i++)
+ len += scnprintf(buf + len, size - len, "%10llu%s",
+ rx_stats->byte_stats.rx_rate[i],
+ (i + 1) % (he_rates_avail ? 12 : 8) ? "\t" : "\n");
+
len += scnprintf(buf + len, size - len,
"\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -3400,10 +3400,43 @@ exit:
return total_msdu_reaped;
}
+static void
+ath11k_dp_rx_update_peer_rate_table_stats(struct ath11k_rx_peer_stats *rx_stats,
+ struct hal_rx_mon_ppdu_info *ppdu_info,
+ u32 num_msdu)
+{
+ u32 rate_idx = 0;
+ u32 mcs_idx = ppdu_info->mcs;
+ u32 nss_idx = ppdu_info->nss - 1;
+ u32 bw_idx = ppdu_info->bw;
+ u32 gi_idx = ppdu_info->gi;
+
+ if ((mcs_idx > HAL_RX_MAX_MCS_HE) || (nss_idx >= HAL_RX_MAX_NSS) ||
+ (bw_idx >= HAL_RX_BW_MAX) || (gi_idx >= HAL_RX_GI_MAX)) {
+ return;
+ }
+
+ if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11N ||
+ ppdu_info->preamble_type == HAL_RX_PREAMBLE_11AC) {
+ rate_idx = mcs_idx * 8 + 8 * 10 * nss_idx;
+ rate_idx += bw_idx * 2 + gi_idx;
+ } else if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11AX) {
+ gi_idx = ath11k_he_gi_to_nl80211_he_gi(ppdu_info->gi);
+ rate_idx = mcs_idx * 12 + 12 * 12 * nss_idx;
+ rate_idx += bw_idx * 3 + gi_idx;
+ } else {
+ return;
+ }
+
+ rx_stats->pkt_stats.rx_rate[rate_idx] += num_msdu;
+ rx_stats->byte_stats.rx_rate[rate_idx] += ppdu_info->mpdu_len;
+}
+
static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
+ struct ath11k *ar = arsta->arvif->ar;
u32 num_msdu;
int i;
@@ -3413,6 +3446,8 @@ static void ath11k_dp_rx_update_peer_sta
arsta->rssi_comb = ppdu_info->rssi_comb;
ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb);
+ if (!ath11k_debugfs_is_extd_rx_stats_enabled(ar))
+ return;
num_msdu = ppdu_info->tcp_msdu_count + ppdu_info->tcp_ack_msdu_count +
ppdu_info->udp_msdu_count + ppdu_info->other_msdu_count;
@@ -3429,18 +3464,6 @@ static void ath11k_dp_rx_update_peer_sta
ppdu_info->tid = IEEE80211_NUM_TIDS;
}
- if (ppdu_info->nss > 0 && ppdu_info->nss <= HAL_RX_MAX_NSS)
- rx_stats->nss_count[ppdu_info->nss - 1] += num_msdu;
-
- if (ppdu_info->mcs <= HAL_RX_MAX_MCS)
- rx_stats->mcs_count[ppdu_info->mcs] += num_msdu;
-
- if (ppdu_info->gi < HAL_RX_GI_MAX)
- rx_stats->gi_count[ppdu_info->gi] += num_msdu;
-
- if (ppdu_info->bw < HAL_RX_BW_MAX)
- rx_stats->bw_count[ppdu_info->bw] += num_msdu;
-
if (ppdu_info->ldpc < HAL_RX_SU_MU_CODING_MAX)
rx_stats->coding_count[ppdu_info->ldpc] += num_msdu;
@@ -3469,8 +3492,6 @@ static void ath11k_dp_rx_update_peer_sta
rx_stats->dcm_count += ppdu_info->dcm;
rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu;
- arsta->rssi_comb = ppdu_info->rssi_comb;
-
BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
ARRAY_SIZE(ppdu_info->rssi_chain_pri20));
@@ -3479,6 +3500,52 @@ static void ath11k_dp_rx_update_peer_sta
rx_stats->rx_duration += ppdu_info->rx_duration;
arsta->rx_duration = rx_stats->rx_duration;
+
+ if (ppdu_info->nss > 0 && ppdu_info->nss <= HAL_RX_MAX_NSS) {
+ rx_stats->pkt_stats.nss_count[ppdu_info->nss - 1] += num_msdu;
+ rx_stats->byte_stats.nss_count[ppdu_info->nss - 1] += ppdu_info->mpdu_len;
+ }
+
+ if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11N &&
+ ppdu_info->mcs <= HAL_RX_MAX_MCS_HT) {
+ rx_stats->pkt_stats.ht_mcs_count[ppdu_info->mcs] += num_msdu;
+ rx_stats->byte_stats.ht_mcs_count[ppdu_info->mcs] += ppdu_info->mpdu_len;
+ /* To fit into rate table for HT packets */
+ ppdu_info->mcs = ppdu_info->mcs % 8;
+ }
+
+ if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11AC &&
+ ppdu_info->mcs <= HAL_RX_MAX_MCS_VHT) {
+ rx_stats->pkt_stats.vht_mcs_count[ppdu_info->mcs] += num_msdu;
+ rx_stats->byte_stats.vht_mcs_count[ppdu_info->mcs] += ppdu_info->mpdu_len;
+ }
+
+ if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11AX &&
+ ppdu_info->mcs <= HAL_RX_MAX_MCS_HE) {
+ rx_stats->pkt_stats.he_mcs_count[ppdu_info->mcs] += num_msdu;
+ rx_stats->byte_stats.he_mcs_count[ppdu_info->mcs] += ppdu_info->mpdu_len;
+ }
+
+
+ if ((ppdu_info->preamble_type == HAL_RX_PREAMBLE_11A ||
+ ppdu_info->preamble_type == HAL_RX_PREAMBLE_11B) &&
+ ppdu_info->rate < HAL_RX_LEGACY_RATE_INVALID) {
+ rx_stats->pkt_stats.legacy_count[ppdu_info->rate] += num_msdu;
+ rx_stats->byte_stats.legacy_count[ppdu_info->rate] += ppdu_info->mpdu_len;
+ }
+
+ if (ppdu_info->gi < HAL_RX_GI_MAX) {
+ rx_stats->pkt_stats.gi_count[ppdu_info->gi] += num_msdu;
+ rx_stats->byte_stats.gi_count[ppdu_info->gi] += ppdu_info->mpdu_len;
+ }
+
+ if (ppdu_info->bw < HAL_RX_BW_MAX) {
+ rx_stats->pkt_stats.bw_count[ppdu_info->bw] += num_msdu;
+ rx_stats->byte_stats.bw_count[ppdu_info->bw] += ppdu_info->mpdu_len;
+ }
+
+ ath11k_dp_rx_update_peer_rate_table_stats(rx_stats, ppdu_info, num_msdu);
+
}
static struct sk_buff *ath11k_dp_rx_alloc_mon_status_buf(struct ath11k_base *ab,
--- a/drivers/net/wireless/ath/ath11k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.h
@@ -69,6 +69,25 @@ struct ath11k_dp_rfc1042_hdr {
__be16 snap_type;
} __packed;
+static inline u32 ath11k_he_gi_to_nl80211_he_gi(u8 sgi)
+{
+ u32 ret = 0;
+
+ switch (sgi) {
+ case RX_MSDU_START_SGI_0_8_US:
+ ret = NL80211_RATE_INFO_HE_GI_0_8;
+ break;
+ case RX_MSDU_START_SGI_1_6_US:
+ ret = NL80211_RATE_INFO_HE_GI_1_6;
+ break;
+ case RX_MSDU_START_SGI_3_2_US:
+ ret = NL80211_RATE_INFO_HE_GI_3_2;
+ break;
+ }
+
+ return ret;
+}
+
int ath11k_dp_rx_ampdu_start(struct ath11k_vif *arvif,
struct ieee80211_ampdu_params *params);
int ath11k_dp_rx_ampdu_stop(struct ath11k_vif *arvif,
--- a/drivers/net/wireless/ath/ath11k/hal_rx.c
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.c
@@ -978,44 +978,78 @@ ath11k_hal_rx_parse_mon_status_tlv(struc
ppdu_info->is_stbc = FIELD_GET(HAL_RX_HT_SIG_INFO_INFO1_STBC,
info1);
ppdu_info->ldpc = FIELD_GET(HAL_RX_HT_SIG_INFO_INFO1_FEC_CODING, info1);
- ppdu_info->gi = info1 & HAL_RX_HT_SIG_INFO_INFO1_GI;
-
- switch (ppdu_info->mcs) {
- case 0 ... 7:
- ppdu_info->nss = 1;
- break;
- case 8 ... 15:
- ppdu_info->nss = 2;
- break;
- case 16 ... 23:
- ppdu_info->nss = 3;
- break;
- case 24 ... 31:
- ppdu_info->nss = 4;
- break;
- }
-
- if (ppdu_info->nss > 1)
- ppdu_info->mcs = ppdu_info->mcs % 8;
-
+ ppdu_info->gi = FIELD_GET(HAL_RX_HT_SIG_INFO_INFO1_GI, info1);
+ ppdu_info->nss = (ppdu_info->mcs >> 3) + 1;
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
break;
}
case HAL_PHYRX_L_SIG_B: {
struct hal_rx_lsig_b_info *lsigb =
(struct hal_rx_lsig_b_info *)tlv_data;
+ u8 rate;
+
+ rate = FIELD_GET(HAL_RX_LSIG_B_INFO_INFO0_RATE,
+ __le32_to_cpu(lsigb->info0));
- ppdu_info->rate = FIELD_GET(HAL_RX_LSIG_B_INFO_INFO0_RATE,
- __le32_to_cpu(lsigb->info0));
+ switch (rate) {
+ case 1:
+ rate = HAL_RX_LEGACY_RATE_1_MBPS;
+ break;
+ case 2:
+ case 5:
+ rate = HAL_RX_LEGACY_RATE_2_MBPS;
+ break;
+ case 3:
+ case 6:
+ rate = HAL_RX_LEGACY_RATE_5_5_MBPS;
+ break;
+ case 4:
+ case 7:
+ rate = HAL_RX_LEGACY_RATE_11_MBPS;
+ break;
+ default:
+ rate = HAL_RX_LEGACY_RATE_INVALID;
+ }
+ ppdu_info->rate = rate;
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
break;
}
case HAL_PHYRX_L_SIG_A: {
struct hal_rx_lsig_a_info *lsiga =
(struct hal_rx_lsig_a_info *)tlv_data;
+ u8 rate;
- ppdu_info->rate = FIELD_GET(HAL_RX_LSIG_A_INFO_INFO0_RATE,
- __le32_to_cpu(lsiga->info0));
+ rate = FIELD_GET(HAL_RX_LSIG_A_INFO_INFO0_RATE,
+ __le32_to_cpu(lsiga->info0));
+ switch (rate) {
+ case 8:
+ rate = HAL_RX_LEGACY_RATE_48_MBPS;
+ break;
+ case 9:
+ rate = HAL_RX_LEGACY_RATE_24_MBPS;
+ break;
+ case 10:
+ rate = HAL_RX_LEGACY_RATE_12_MBPS;
+ break;
+ case 11:
+ rate = HAL_RX_LEGACY_RATE_6_MBPS;
+ break;
+ case 12:
+ rate = HAL_RX_LEGACY_RATE_54_MBPS;
+ break;
+ case 13:
+ rate = HAL_RX_LEGACY_RATE_36_MBPS;
+ break;
+ case 14:
+ rate = HAL_RX_LEGACY_RATE_18_MBPS;
+ break;
+ case 15:
+ rate = HAL_RX_LEGACY_RATE_9_MBPS;
+ break;
+ default:
+ rate = HAL_RX_LEGACY_RATE_INVALID;
+ }
+ ppdu_info->rate = rate;
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
break;
}
@@ -1473,6 +1507,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struc
peer_id = ath11k_hal_rx_mpduinfo_get_peerid(ab, mpdu_info);
if (peer_id)
ppdu_info->peer_id = peer_id;
+
+ ppdu_info->mpdu_len += ab->hw_params.hw_ops->rx_desc_get_hal_mpdu_len(mpdu_info);
+
break;
}
case HAL_RXPCU_PPDU_END_INFO: {
--- a/drivers/net/wireless/ath/ath11k/hal_rx.h
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.h
@@ -19,7 +19,11 @@ struct hal_rx_wbm_rel_info {
#define VHT_SIG_SU_NSS_MASK 0x7
#define HAL_RX_MAX_MCS 12
+#define HAL_RX_MAX_MCS_HT 31
+#define HAL_RX_MAX_MCS_VHT 9
+#define HAL_RX_MAX_MCS_HE 11
#define HAL_RX_MAX_NSS 8
+#define HAL_RX_MAX_NUM_LEGACY_RATES 12
struct hal_rx_mon_status_tlv_hdr {
u32 hdr;
@@ -104,6 +108,22 @@ struct hal_rx_user_status {
u32 mpdu_err_byte_count;
};
+enum hal_rx_legacy_rate {
+ HAL_RX_LEGACY_RATE_1_MBPS,
+ HAL_RX_LEGACY_RATE_2_MBPS,
+ HAL_RX_LEGACY_RATE_5_5_MBPS,
+ HAL_RX_LEGACY_RATE_6_MBPS,
+ HAL_RX_LEGACY_RATE_9_MBPS,
+ HAL_RX_LEGACY_RATE_11_MBPS,
+ HAL_RX_LEGACY_RATE_12_MBPS,
+ HAL_RX_LEGACY_RATE_18_MBPS,
+ HAL_RX_LEGACY_RATE_24_MBPS,
+ HAL_RX_LEGACY_RATE_36_MBPS,
+ HAL_RX_LEGACY_RATE_48_MBPS,
+ HAL_RX_LEGACY_RATE_54_MBPS,
+ HAL_RX_LEGACY_RATE_INVALID,
+};
+
#define HAL_TLV_STATUS_PPDU_NOT_DONE HAL_RX_MON_STATUS_PPDU_NOT_DONE
#define HAL_TLV_STATUS_PPDU_DONE HAL_RX_MON_STATUS_PPDU_DONE
#define HAL_TLV_STATUS_BUF_DONE HAL_RX_MON_STATUS_BUF_DONE
@@ -128,6 +148,7 @@ struct hal_rx_mon_ppdu_info {
u32 num_mpdu_fcs_ok;
u32 num_mpdu_fcs_err;
u32 preamble_type;
+ u32 mpdu_len;
u16 chan_num;
u16 tcp_msdu_count;
u16 tcp_ack_msdu_count;
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -1051,6 +1051,17 @@ static u32 ath11k_hw_wcn6750_get_tcl_rin
return skb_get_hash(skb);
}
+static u32 ath11k_hw_ipq8074_rx_desc_get_hal_mpdu_len(struct hal_rx_mpdu_info *mpdu_info)
+{
+ return FIELD_GET(HAL_RX_MPDU_INFO_INFO1_MPDU_LEN,
+ __le32_to_cpu(mpdu_info->u.ipq8074.info1));
+}
+
+static u32 ath11k_hw_qcn9074_rx_desc_get_hal_mpdu_len(struct hal_rx_mpdu_info *mpdu_info)
+{
+ return FIELD_GET(HAL_RX_MPDU_INFO_INFO1_MPDU_LEN,
+ __le32_to_cpu(mpdu_info->u.qcn9074.info1));
+}
const struct ath11k_hw_ops ipq8074_ops = {
.get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id,
.wmi_init_config = ath11k_init_wmi_config_ipq8074,
@@ -1089,6 +1100,7 @@ const struct ath11k_hw_ops ipq8074_ops =
.rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
+ .rx_desc_get_hal_mpdu_len = ath11k_hw_ipq8074_rx_desc_get_hal_mpdu_len,
#ifdef CPTCFG_ATH11K_MEM_PROFILE_512M
.rx_desc_get_offset = ath11k_hw_ipq8074_rx_desc_get_offset,
#endif
@@ -1136,6 +1148,7 @@ const struct ath11k_hw_ops ipq6018_ops =
.rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
+ .rx_desc_get_hal_mpdu_len = ath11k_hw_ipq8074_rx_desc_get_hal_mpdu_len,
};
const struct ath11k_hw_ops qca6390_ops = {
@@ -1177,6 +1190,7 @@ const struct ath11k_hw_ops qca6390_ops =
.rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
+ .rx_desc_get_hal_mpdu_len = ath11k_hw_ipq8074_rx_desc_get_hal_mpdu_len,
};
const struct ath11k_hw_ops qcn9074_ops = {
@@ -1217,6 +1231,7 @@ const struct ath11k_hw_ops qcn9074_ops =
.reo_setup = ath11k_hw_ipq8074_reo_setup,
.mpdu_info_get_peerid = ath11k_hw_qcn9074_mpdu_info_get_peerid,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
+ .rx_desc_get_hal_mpdu_len = ath11k_hw_ipq8074_rx_desc_get_hal_mpdu_len,
};
const struct ath11k_hw_ops wcn6855_ops = {
@@ -1339,6 +1354,7 @@ const struct ath11k_hw_ops ipq5018_ops =
.rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
+ .rx_desc_get_hal_mpdu_len = ath11k_hw_qcn9074_rx_desc_get_hal_mpdu_len,
};
#define ATH11K_TX_RING_MASK_0 BIT(0)
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -315,6 +315,7 @@ struct ath11k_hw_ops {
bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc);
u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc);
u32 (*get_ring_selector)(struct sk_buff *skb);
+ u32 (*rx_desc_get_hal_mpdu_len)(struct hal_rx_mpdu_info *mpdu_info);
#ifdef CPTCFG_ATH11K_MEM_PROFILE_512M
void (*rx_desc_get_offset)(struct htt_rx_ring_tlv_filter *tlv_filter);
#endif

View File

@ -0,0 +1,452 @@
--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
@@ -532,6 +532,12 @@ static ssize_t ath11k_dbg_sta_dump_rx_st
len += scnprintf(buf + len, size - len, "%10llu%s",
rx_stats->byte_stats.rx_rate[i],
(i + 1) % (he_rates_avail ? 12 : 8) ? "\t" : "\n");
+ len += scnprintf(buf + len, size - len,
+ "\nDCM: %llu\nRU26: %llu \nRU52: %llu \nRU106: %llu \nRU242: %llu \nRU484: %llu \nRU996: %llu\n",
+ rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
+ rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
+ rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
+ rx_stats->ru_alloc_cnt[5]);
len += scnprintf(buf + len, size - len,
"\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -3236,11 +3236,12 @@ exit:
static void
ath11k_dp_rx_update_peer_rate_table_stats(struct ath11k_rx_peer_stats *rx_stats,
struct hal_rx_mon_ppdu_info *ppdu_info,
+ struct hal_rx_user_status* user_stats,
u32 num_msdu)
{
u32 rate_idx = 0;
- u32 mcs_idx = ppdu_info->mcs;
- u32 nss_idx = ppdu_info->nss - 1;
+ u32 mcs_idx = (user_stats) ? user_stats->mcs : ppdu_info->mcs;
+ u32 nss_idx = (user_stats) ? user_stats->nss - 1 : ppdu_info->nss - 1;
u32 bw_idx = ppdu_info->bw;
u32 gi_idx = ppdu_info->gi;
@@ -3262,10 +3263,13 @@ ath11k_dp_rx_update_peer_rate_table_stat
}
rx_stats->pkt_stats.rx_rate[rate_idx] += num_msdu;
- rx_stats->byte_stats.rx_rate[rate_idx] += ppdu_info->mpdu_len;
+ if (user_stats)
+ rx_stats->byte_stats.rx_rate[rate_idx] += user_stats->mpdu_ok_byte_count;
+ else
+ rx_stats->byte_stats.rx_rate[rate_idx] += ppdu_info->mpdu_len;
}
-static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta,
+static void ath11k_dp_rx_update_peer_su_stats(struct ath11k_sta *arsta,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
@@ -3323,7 +3327,6 @@ static void ath11k_dp_rx_update_peer_sta
rx_stats->num_mpdu_fcs_ok += ppdu_info->num_mpdu_fcs_ok;
rx_stats->num_mpdu_fcs_err += ppdu_info->num_mpdu_fcs_err;
rx_stats->dcm_count += ppdu_info->dcm;
- rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu;
BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
ARRAY_SIZE(ppdu_info->rssi_chain_pri20));
@@ -3341,10 +3344,10 @@ static void ath11k_dp_rx_update_peer_sta
if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11N &&
ppdu_info->mcs <= HAL_RX_MAX_MCS_HT) {
- rx_stats->pkt_stats.ht_mcs_count[ppdu_info->mcs] += num_msdu;
- rx_stats->byte_stats.ht_mcs_count[ppdu_info->mcs] += ppdu_info->mpdu_len;
- /* To fit into rate table for HT packets */
- ppdu_info->mcs = ppdu_info->mcs % 8;
+ rx_stats->pkt_stats.ht_mcs_count[ppdu_info->mcs] += num_msdu;
+ rx_stats->byte_stats.ht_mcs_count[ppdu_info->mcs] += ppdu_info->mpdu_len;
+ /* To fit into rate table for HT packets */
+ ppdu_info->mcs = ppdu_info->mcs % 8;
}
if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11AC &&
@@ -3377,7 +3380,120 @@ static void ath11k_dp_rx_update_peer_sta
rx_stats->byte_stats.bw_count[ppdu_info->bw] += ppdu_info->mpdu_len;
}
- ath11k_dp_rx_update_peer_rate_table_stats(rx_stats, ppdu_info, num_msdu);
+ ath11k_dp_rx_update_peer_rate_table_stats(rx_stats, ppdu_info, NULL, num_msdu);
+
+}
+
+static void ath11k_dp_rx_update_user_stats(struct ath11k *ar,
+ struct hal_rx_mon_ppdu_info *ppdu_info,
+ u32 uid)
+{
+ struct ath11k_sta *arsta = NULL;
+ struct ath11k_rx_peer_stats *rx_stats = NULL;
+ struct hal_rx_user_status* user_stats = &ppdu_info->userstats[uid];
+ struct ath11k_peer *peer;
+ u32 num_msdu;
+
+ if (user_stats->ast_index == 0 || user_stats->ast_index == 0xFFFF)
+ return;
+
+ peer = ath11k_peer_find_by_ast(ar->ab, user_stats->ast_index);
+
+ if (peer == NULL) {
+ ath11k_warn(ar->ab, "peer ast idx %d can't be found\n",
+ user_stats->ast_index);
+ return;
+ }
+
+ arsta = (struct ath11k_sta *)peer->sta->drv_priv;
+ rx_stats = arsta->rx_stats;
+
+ if (!rx_stats)
+ return;
+
+ arsta->rssi_comb = ppdu_info->rssi_comb;
+
+ num_msdu = user_stats->tcp_msdu_count + user_stats->tcp_ack_msdu_count +
+ user_stats->udp_msdu_count + user_stats->other_msdu_count;
+
+ rx_stats->num_msdu += num_msdu;
+ rx_stats->tcp_msdu_count += user_stats->tcp_msdu_count +
+ user_stats->tcp_ack_msdu_count;
+ rx_stats->udp_msdu_count += user_stats->udp_msdu_count;
+ rx_stats->other_msdu_count += user_stats->other_msdu_count;
+
+ if (ppdu_info->ldpc < HAL_RX_SU_MU_CODING_MAX)
+ rx_stats->coding_count[ppdu_info->ldpc] += num_msdu;
+
+ if (user_stats->tid <= IEEE80211_NUM_TIDS)
+ rx_stats->tid_count[user_stats->tid] += num_msdu;
+
+ if (user_stats->preamble_type < HAL_RX_PREAMBLE_MAX)
+ rx_stats->pream_cnt[user_stats->preamble_type] += num_msdu;
+
+ if (ppdu_info->reception_type < HAL_RX_RECEPTION_TYPE_MAX)
+ rx_stats->reception_type[ppdu_info->reception_type] += num_msdu;
+
+ if (ppdu_info->is_stbc)
+ rx_stats->stbc_count += num_msdu;
+
+ if (ppdu_info->beamformed)
+ rx_stats->beamformed_count += num_msdu;
+
+ if (user_stats->mpdu_cnt_fcs_ok > 1)
+ rx_stats->ampdu_msdu_count += num_msdu;
+ else
+ rx_stats->non_ampdu_msdu_count += num_msdu;
+
+ rx_stats->num_mpdu_fcs_ok += user_stats->mpdu_cnt_fcs_ok;
+ rx_stats->num_mpdu_fcs_err += user_stats->mpdu_cnt_fcs_err;
+ rx_stats->dcm_count += ppdu_info->dcm;
+ if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_MU_OFDMA ||
+ ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_MU_OFDMA_MIMO)
+ rx_stats->ru_alloc_cnt[user_stats->ul_ofdma_ru_size] += num_msdu;
+
+ rx_stats->rx_duration += ppdu_info->rx_duration;
+ arsta->rx_duration = rx_stats->rx_duration;
+
+ if (user_stats->nss > 0 && user_stats->nss <= HAL_RX_MAX_NSS) {
+ rx_stats->pkt_stats.nss_count[user_stats->nss - 1] += num_msdu;
+ rx_stats->byte_stats.nss_count[user_stats->nss - 1] += user_stats->mpdu_ok_byte_count;
+ }
+
+ if (user_stats->preamble_type == HAL_RX_PREAMBLE_11AX &&
+ user_stats->mcs <= HAL_RX_MAX_MCS_HE) {
+ rx_stats->pkt_stats.he_mcs_count[user_stats->mcs] += num_msdu;
+ rx_stats->byte_stats.he_mcs_count[user_stats->mcs] += user_stats->mpdu_ok_byte_count;
+ }
+
+ if (ppdu_info->gi < HAL_RX_GI_MAX) {
+ rx_stats->pkt_stats.gi_count[ppdu_info->gi] += num_msdu;
+ rx_stats->byte_stats.gi_count[ppdu_info->gi] += user_stats->mpdu_ok_byte_count;
+ }
+
+ if (ppdu_info->bw < HAL_RX_BW_MAX) {
+ rx_stats->pkt_stats.bw_count[ppdu_info->bw] += num_msdu;
+ rx_stats->byte_stats.bw_count[ppdu_info->bw] += user_stats->mpdu_ok_byte_count;
+ }
+
+ ath11k_dp_rx_update_peer_rate_table_stats(rx_stats, ppdu_info, user_stats, num_msdu);
+}
+
+static void ath11k_dp_rx_update_peer_mu_stats(struct ath11k *ar,
+ struct hal_rx_mon_ppdu_info *ppdu_info)
+{
+ u32 num_users, i;
+
+ if (!ath11k_debugfs_is_extd_rx_stats_enabled(ar))
+ return;
+
+ num_users = ppdu_info->num_users;
+ if (num_users > HAL_MAX_UL_MU_USERS)
+ num_users = HAL_MAX_UL_MU_USERS;
+
+ for (i = 0; i < num_users; i++) {
+ ath11k_dp_rx_update_user_stats(ar, ppdu_info, i);
+ }
}
@@ -5846,6 +5962,55 @@ static void ath11k_dp_rx_mon_dest_proces
}
}
+void ath11k_dp_rx_mon_process_ulofdma(struct hal_rx_mon_ppdu_info *ppdu_info)
+{
+ struct hal_rx_user_status *rx_user_status;
+ u32 num_users;
+ uint32_t i;
+ uint32_t mu_ul_user_v0_word0;
+ uint32_t mu_ul_user_v0_word1;
+ uint32_t ru_size;
+
+ if (!(ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_MU_OFDMA ||
+ ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_MU_OFDMA_MIMO))
+ return;
+
+ num_users = ppdu_info->num_users;
+ if (num_users > HAL_MAX_UL_MU_USERS)
+ num_users = HAL_MAX_UL_MU_USERS;
+
+ for (i = 0; i < num_users; i++) {
+ rx_user_status = &ppdu_info->userstats[i];
+ mu_ul_user_v0_word0 =
+ rx_user_status->ul_ofdma_user_v0_word0;
+ mu_ul_user_v0_word1 =
+ rx_user_status->ul_ofdma_user_v0_word1;
+
+ if (FIELD_GET(HAL_RX_UL_OFDMA_USER_INFO_V0_W0_VALID,
+ mu_ul_user_v0_word0) &&
+ !FIELD_GET(HAL_RX_UL_OFDMA_USER_INFO_V0_W0_VER,
+ mu_ul_user_v0_word0)) {
+ rx_user_status->mcs =
+ FIELD_GET(HAL_RX_UL_OFDMA_USER_INFO_V0_W1_MCS,
+ mu_ul_user_v0_word1);
+ rx_user_status->nss =
+ FIELD_GET(HAL_RX_UL_OFDMA_USER_INFO_V0_W1_NSS,
+ mu_ul_user_v0_word1) + 1;
+
+ rx_user_status->ofdma_info_valid = 1;
+ rx_user_status->ul_ofdma_ru_start_index =
+ FIELD_GET(HAL_RX_UL_OFDMA_USER_INFO_V0_W1_RU_START,
+ mu_ul_user_v0_word1);
+
+ ru_size = FIELD_GET(HAL_RX_UL_OFDMA_USER_INFO_V0_W1_RU_SIZE,
+ mu_ul_user_v0_word1);
+ rx_user_status->ul_ofdma_ru_width = ru_size;
+ rx_user_status->ul_ofdma_ru_size = ru_size;
+ }
+ }
+
+}
+
int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
struct napi_struct *napi, int budget)
{
@@ -5919,8 +6084,13 @@ int ath11k_dp_rx_process_mon_status(stru
if ((ppdu_info->fc_valid) &&
(ppdu_info->ast_index != HAL_AST_IDX_INVALID)) {
- arsta = (struct ath11k_sta *)peer->sta->drv_priv;
- ath11k_dp_rx_update_peer_stats(arsta, ppdu_info);
+ if (ppdu_info.reception_type == HAL_RX_RECEPTION_TYPE_SU) {
+ arsta = (struct ath11k_sta *)peer->sta->drv_priv;
+ ath11k_dp_rx_update_peer_su_stats(arsta, &ppdu_info);
+ } else {
+ ath11k_dp_rx_mon_process_ulofdma(&ppdu_info);
+ ath11k_dp_rx_update_peer_mu_stats(ar, &ppdu_info);
+ }
}
if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr))
--- a/drivers/net/wireless/ath/ath11k/hal_rx.c
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.c
@@ -804,7 +804,6 @@ void ath11k_hal_reo_init_cmd_ring(struct
}
}
-#define HAL_MAX_UL_MU_USERS 37
static inline void
ath11k_hal_rx_handle_ofdma_info(void *rx_tlv,
struct hal_rx_user_status *rx_user_status)
@@ -836,6 +835,8 @@ ath11k_hal_rx_populate_mu_user_info(void
{
rx_user_status->ast_index = ppdu_info->ast_index;
rx_user_status->tid = ppdu_info->tid;
+ rx_user_status->tcp_ack_msdu_count =
+ ppdu_info->tcp_ack_msdu_count;
rx_user_status->tcp_msdu_count =
ppdu_info->tcp_msdu_count;
rx_user_status->udp_msdu_count =
@@ -859,6 +860,9 @@ ath11k_hal_rx_populate_mu_user_info(void
ppdu_info->num_mpdu_fcs_ok;
rx_user_status->mpdu_cnt_fcs_err =
ppdu_info->num_mpdu_fcs_err;
+ memcpy(&rx_user_status->mpdu_fcs_ok_bitmap[0], &ppdu_info->mpdu_fcs_ok_bitmap[0],
+ HAL_RX_NUM_WORDS_PER_PPDU_BITMAP *
+ sizeof(ppdu_info->mpdu_fcs_ok_bitmap[0]));
ath11k_hal_rx_populate_byte_count(rx_tlv, ppdu_info, rx_user_status);
}
@@ -888,6 +892,14 @@ ath11k_hal_rx_parse_mon_status_tlv(struc
__le32_to_cpu(ppdu_start->info0));
ppdu_info->chan_num = __le32_to_cpu(ppdu_start->chan_num);
ppdu_info->ppdu_ts = __le32_to_cpu(ppdu_start->ppdu_start_ts);
+
+ if (ppdu_info->ppdu_id != ppdu_info->last_ppdu_id) {
+ ppdu_info->last_ppdu_id = ppdu_info->ppdu_id;
+ ppdu_info->num_users = 0;
+ memset(&ppdu_info->mpdu_fcs_ok_bitmap, 0,
+ HAL_RX_NUM_WORDS_PER_PPDU_BITMAP *
+ sizeof(ppdu_info->mpdu_fcs_ok_bitmap[0]));
+ }
break;
}
case HAL_RX_PPDU_END_USER_STATS: {
@@ -942,15 +954,16 @@ ath11k_hal_rx_parse_mon_status_tlv(struc
if (userid < HAL_MAX_UL_MU_USERS) {
struct hal_rx_user_status *rxuser_stats =
- &ppdu_info->userstats;
+ &ppdu_info->userstats[userid];
+ ppdu_info->num_users += 1;
ath11k_hal_rx_handle_ofdma_info(tlv_data, rxuser_stats);
ath11k_hal_rx_populate_mu_user_info(tlv_data, ppdu_info,
rxuser_stats);
}
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[0] =
+ ppdu_info->mpdu_fcs_ok_bitmap[0] =
__le32_to_cpu(eu_stats->rsvd1[0]);
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[1] =
+ ppdu_info->mpdu_fcs_ok_bitmap[1] =
__le32_to_cpu(eu_stats->rsvd1[1]);
break;
@@ -958,12 +971,12 @@ ath11k_hal_rx_parse_mon_status_tlv(struc
case HAL_RX_PPDU_END_USER_STATS_EXT: {
struct hal_rx_ppdu_end_user_stats_ext *eu_stats =
(struct hal_rx_ppdu_end_user_stats_ext *)tlv_data;
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[2] = eu_stats->info1;
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[3] = eu_stats->info2;
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[4] = eu_stats->info3;
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[5] = eu_stats->info4;
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[6] = eu_stats->info5;
- ppdu_info->userstats.mpdu_fcs_ok_bitmap[7] = eu_stats->info6;
+ ppdu_info->mpdu_fcs_ok_bitmap[2] = eu_stats->info1;
+ ppdu_info->mpdu_fcs_ok_bitmap[3] = eu_stats->info2;
+ ppdu_info->mpdu_fcs_ok_bitmap[4] = eu_stats->info3;
+ ppdu_info->mpdu_fcs_ok_bitmap[5] = eu_stats->info4;
+ ppdu_info->mpdu_fcs_ok_bitmap[6] = eu_stats->info5;
+ ppdu_info->mpdu_fcs_ok_bitmap[7] = eu_stats->info6;
break;
}
case HAL_PHYRX_HT_SIG: {
--- a/drivers/net/wireless/ath/ath11k/hal_rx.h
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.h
@@ -72,6 +72,10 @@ enum hal_rx_reception_type {
#define HAL_RX_FCS_LEN 4
#define HAL_AST_IDX_INVALID 0xFFFF
+#define HAL_MAX_UL_MU_USERS 37
+#define HAL_RX_MAX_MPDU 256
+#define HAL_RX_NUM_WORDS_PER_PPDU_BITMAP (HAL_RX_MAX_MPDU >> 5)
+
enum hal_rx_mon_status {
HAL_RX_MON_STATUS_PPDU_NOT_DONE,
HAL_RX_MON_STATUS_PPDU_DONE,
@@ -82,14 +86,15 @@ struct hal_rx_user_status {
u32 mcs:4,
nss:3,
ofdma_info_valid:1,
- dl_ofdma_ru_start_index:7,
- dl_ofdma_ru_width:7,
- dl_ofdma_ru_size:8;
+ ul_ofdma_ru_start_index:7,
+ ul_ofdma_ru_width:7,
+ ul_ofdma_ru_size:8;
u32 ul_ofdma_user_v0_word0;
u32 ul_ofdma_user_v0_word1;
u32 ast_index;
u32 tid;
u16 tcp_msdu_count;
+ u16 tcp_ack_msdu_count;
u16 udp_msdu_count;
u16 other_msdu_count;
u16 frame_control;
@@ -103,7 +108,7 @@ struct hal_rx_user_status {
u8 rs_flags;
u32 mpdu_cnt_fcs_ok;
u32 mpdu_cnt_fcs_err;
- u32 mpdu_fcs_ok_bitmap[8];
+ u32 mpdu_fcs_ok_bitmap[HAL_RX_NUM_WORDS_PER_PPDU_BITMAP];
u32 mpdu_ok_byte_count;
u32 mpdu_err_byte_count;
};
@@ -144,6 +149,7 @@ struct hal_sw_mon_ring_entries {
struct hal_rx_mon_ppdu_info {
u32 ppdu_id;
+ u32 last_ppdu_id;
u32 ppdu_ts;
u32 num_mpdu_fcs_ok;
u32 num_mpdu_fcs_err;
@@ -212,9 +218,20 @@ struct hal_rx_mon_ppdu_info {
u8 ltf_size;
u8 rxpcu_filter_pass;
char rssi_chain[8][8];
- struct hal_rx_user_status userstats;
+ u32 num_users;
+ u32 mpdu_fcs_ok_bitmap[HAL_RX_NUM_WORDS_PER_PPDU_BITMAP];
+ struct hal_rx_user_status userstats[HAL_MAX_UL_MU_USERS];
};
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W0_VALID BIT(30)
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W0_VER BIT(31)
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_NSS GENMASK(2, 0)
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_MCS GENMASK(6, 3)
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_LDPC BIT(7)
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_DCM BIT(8)
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_RU_START GENMASK(15, 9)
+#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_RU_SIZE GENMASK(18, 16)
+
#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0)
struct hal_rx_ppdu_start {
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -94,6 +94,20 @@ struct ath11k_peer *ath11k_peer_find_by_
return NULL;
}
+struct ath11k_peer *ath11k_peer_find_by_ast(struct ath11k_base *ab,
+ int ast_hash)
+{
+ struct ath11k_peer *peer;
+
+ lockdep_assert_held(&ab->base_lock);
+
+ list_for_each_entry(peer, &ab->peers, list)
+ if (ast_hash == peer->ast_hash)
+ return peer;
+
+ return NULL;
+}
+
#ifdef CPTCFG_ATH11K_NSS_SUPPORT
struct ath11k_ast_entry *ath11k_peer_ast_find_by_peer(struct ath11k_base *ab,
struct ath11k_peer *peer,
--- a/drivers/net/wireless/ath/ath11k/peer.h
+++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -112,6 +112,7 @@ struct ath11k_peer *ath11k_peer_find(str
struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
const u8 *addr);
struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, int peer_id);
+struct ath11k_peer *ath11k_peer_find_by_ast(struct ath11k_base *ab, int ast_hash);
void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id);
int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr);
int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,

View File

@ -0,0 +1,146 @@
From 41363c3109235a96d90d5946bbc01d1cc8dad47e Mon Sep 17 00:00:00 2001
From: Anilkumar Kolli <akolli@codeaurora.org>
Date: Sun, 6 Sep 2020 11:01:38 +0530
Subject: [PATCH] ath11k: update debugfs support for mupltiple radios in PCI
bus
debugfs_ath11k struct is moved to ath11k_core, since its common
for both pci and ahb.
Current ath11k_pci insmod fails if there are multiple PCI rdaios,
debugfs directory is created with soc_name and bus_id to allow
creating debugfs directory for second PCI radio.
with this Debugfs entries looks like,
# ls -l /sys/kernel/debug/ath11k/
ipq8074 hw2.0 qcn9000 hw1.0_0000:01:00.0 qcn9000 hw1.0_0001:01:00.0
# ls -l /sys/kernel/debug/ath11k/ipq8074 hw2.0/
mac0 mac1 simulate_fw_crash soc_dp_stats
# ls -l /sys/kernel/debug/ath11k/qcn9000 hw1.0_0000:01:00.0
mac0 simulate_fw_crash soc_dp_stats
# /sys/kernel/debug/ath11k/qcn9000 hw1.0_0001:01:00.0:
mac0 simulate_fw_crash soc_dp_stats
Signed-off-by: Anilkumar Kolli <akolli@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/core.c | 12 +++++++
drivers/net/wireless/ath/ath11k/core.h | 1 -
drivers/net/wireless/ath/ath11k/debugfs.c | 57 ++++++++++++++++++++++++------
drivers/net/wireless/ath/ath11k/debugfs.h | 11 ++++++
5 files changed, 72 insertions(+), 13 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -2260,5 +2260,17 @@ err_sc_free:
}
EXPORT_SYMBOL(ath11k_core_alloc);
+int ath11k_init(void)
+{
+ return ath11k_debugfs_create();
+}
+module_init(ath11k_init);
+
+void ath11k_exit(void)
+{
+ ath11k_debugfs_destroy();
+}
+module_exit(ath11k_exit);
+
MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -15,6 +15,8 @@
#include "hif.h"
#include "qmi.h"
+struct dentry *debugfs_ath11k;
+
static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
"REO2SW1_RING",
"REO2SW2_RING",
@@ -1228,8 +1230,6 @@ int ath11k_debugfs_pdev_create(struct at
void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab)
{
- debugfs_remove_recursive(ab->debugfs_soc);
- ab->debugfs_soc = NULL;
}
int ath11k_debugfs_soc_create(struct ath11k_base *ab)
@@ -1282,6 +1282,24 @@ void ath11k_debugfs_soc_destroy(struct a
}
EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);
+int ath11k_debugfs_create(void)
+{
+ debugfs_ath11k = debugfs_create_dir("ath11k", NULL);
+ if (IS_ERR_OR_NULL(debugfs_ath11k)) {
+ if (IS_ERR(debugfs_ath11k))
+ return PTR_ERR(debugfs_ath11k);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ath11k_debugfs_destroy(void)
+{
+ debugfs_remove_recursive(debugfs_ath11k);
+ debugfs_ath11k = NULL;
+}
+
void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
{
struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
@@ -1932,6 +1950,9 @@ void ath11k_debugfs_unregister(struct at
kfree(dbr_debug);
ar->debug.dbr_debug[i] = NULL;
}
+
+ debugfs_remove_recursive(ar->debug.debugfs_pdev);
+ ar->debug.debugfs_pdev = NULL;
}
static ssize_t ath11k_write_twt_add_dialog(struct file *file,
@@ -2294,6 +2315,9 @@ int ath11k_debugfs_register(struct ath11
char pdev_name[10];
char buf[100] = {0};
+ if (!(IS_ERR_OR_NULL(ar->debug.debugfs_pdev)))
+ return 0;
+
snprintf(pdev_name, sizeof(pdev_name), "%s%u", "mac", ar->pdev_idx);
ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
--- a/drivers/net/wireless/ath/ath11k/debugfs.h
+++ b/drivers/net/wireless/ath/ath11k/debugfs.h
@@ -282,6 +282,8 @@ do { \
#endif
#ifdef CPTCFG_ATH11K_DEBUGFS
+int ath11k_debugfs_create(void);
+void ath11k_debugfs_destroy(void);
int ath11k_debugfs_soc_create(struct ath11k_base *ab);
void ath11k_debugfs_soc_destroy(struct ath11k_base *ab);
int ath11k_debugfs_pdev_create(struct ath11k_base *ab);
@@ -338,6 +340,15 @@ static inline int ath11k_debug_is_memory
}
#else
+static inline int ath11k_debugfs_create(void)
+{
+ return 0;
+}
+
+static inline void ath11k_debugfs_destroy(void)
+{
+}
+
static inline int ath11k_debugfs_soc_create(struct ath11k_base *ab)
{
return 0;

View File

@ -0,0 +1,253 @@
From 91df8aa674d2d4064ab22f47515c3fb126527208 Mon Sep 17 00:00:00 2001
From: Karthikeyan Kathirvel <kathirve@codeaurora.org>
Date: Thu, 12 Nov 2020 15:02:56 +0530
Subject: [PATCH] ath11k: NSS MCBC Exception added for STA
Since NSS FW is not supporting PN check for MCBC pkts, those pkts are
excepted from NSS offload to pass through mac80211 PN check.
Signed-off-by: Karthikeyan Kathirvel <kathirve@codeaurora.org>
Change-Id: I4a6ac67a1c2cf3ab7a219d0953907191606a5e70
---
drivers/net/wireless/ath/ath11k/nss.c | 128 +++++++++++++++++++++
drivers/net/wireless/ath/ath11k/nss.h | 51 ++++----
2 files changed, 153 insertions(+), 26 deletions(-)
create mode 100644 mac80211/patches/301-ath11k-nss-mcbc-exception.patch
--- a/drivers/net/wireless/ath/ath11k/nss.c
+++ b/drivers/net/wireless/ath/ath11k/nss.c
@@ -611,7 +611,7 @@ static int ath11k_nss_undecap_nwifi(stru
static void ath11k_nss_wds_type_rx(struct ath11k *ar, struct net_device *dev,
u8* src_mac, u8 is_sa_valid, u8 addr4_valid,
- u16 peer_id, bool *drop)
+ u16 peer_id)
{
struct ath11k_base *ab = ar->ab;
struct ath11k_ast_entry *ast_entry = NULL;
@@ -647,8 +647,6 @@ static void ath11k_nss_wds_type_rx(struc
}
}
- if (!ta_peer->nss.ext_vdev_up)
- *drop = true;
}
spin_unlock_bh(&ab->base_lock);
@@ -692,8 +690,7 @@ static void ath11k_nss_mec_handler(struc
static void ath11k_nss_vdev_spl_receive_ext_wdsdata(struct ath11k_vif *arvif,
struct sk_buff *skb,
- struct nss_wifi_vdev_wds_per_packet_metadata *wds_metadata,
- bool *drop)
+ struct nss_wifi_vdev_wds_per_packet_metadata *wds_metadata)
{
struct ath11k *ar = arvif->ar;
struct ath11k_base *ab = ar->ab;
@@ -715,7 +712,7 @@ static void ath11k_nss_vdev_spl_receive_
switch (wds_type) {
case NSS_WIFI_VDEV_WDS_TYPE_RX:
ath11k_nss_wds_type_rx(ar, skb->dev, src_mac, is_sa_valid,
- addr4_valid, peer_id, drop);
+ addr4_valid, peer_id);
break;
case NSS_WIFI_VDEV_WDS_TYPE_MEC:
ath11k_nss_mec_handler(ar, (u8 *)(skb->data));
@@ -778,14 +775,16 @@ ath11k_nss_vdev_special_data_receive(str
{
struct nss_wifi_vdev_per_packet_metadata *wifi_metadata = NULL;
struct nss_wifi_vdev_wds_per_packet_metadata *wds_metadata = NULL;
+ struct nss_wifi_vdev_addr4_data_metadata *addr4_metadata = NULL;
struct wireless_dev *wdev;
struct ieee80211_vif *vif;
struct ath11k_vif *arvif;
struct ath11k_base *ab;
- bool drop = false;
+ struct ath11k_skb_rxcb *rxcb;
bool eth_decap = false;
int data_offs = 0;
int ret = 0;
+ struct ath11k_peer *ta_peer = NULL;
if (!dev) {
dev_kfree_skb_any(skb);
@@ -834,15 +833,50 @@ ath11k_nss_vdev_special_data_receive(str
return;
}
- if (eth_decap && wifi_metadata->pkt_type ==
- NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_WDS_LEARN) {
- wds_metadata = &wifi_metadata->metadata.wds_metadata;
- ath11k_nss_vdev_spl_receive_ext_wdsdata(arvif, skb,
- wds_metadata, &drop);
- }
+ switch(wifi_metadata->pkt_type) {
+ case NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_WDS_LEARN:
+ if (eth_decap) {
+ wds_metadata = &wifi_metadata->metadata.wds_metadata;
+ ath11k_nss_vdev_spl_receive_ext_wdsdata(arvif, skb,
+ wds_metadata);
+ }
+ dev_kfree_skb_any(skb);
+ break;
+ case NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_MCBC_RX:
+ ath11k_dbg_dump(ab, ATH11K_DBG_DP_RX, "",
+ "mcbc packet exception from nss: ",
+ skb->data, skb->len);
+ rxcb = ATH11K_SKB_RXCB(skb);
+ rxcb->rx_desc = (struct hal_rx_desc *)skb->head;
+ rxcb->is_first_msdu = rxcb->is_last_msdu = true;
+ rxcb->is_continuation = false;
+ rxcb->is_mcbc = true;
+ ath11k_dp_rx_from_nss(arvif->ar, skb, napi);
+ break;
+ case NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_4ADDR:
+ if (eth_decap) {
+ addr4_metadata = &wifi_metadata->metadata.addr4_metadata;
+
+ spin_lock_bh(&ab->base_lock);
+ ta_peer = ath11k_peer_find_by_id(ab, addr4_metadata->peer_id);
+ if (!ta_peer) {
+ spin_unlock_bh(&ab->base_lock);
+ dev_kfree_skb_any(skb);
+ return;
+ }
- if (!drop)
- ath11k_nss_deliver_rx(arvif->vif, skb, eth_decap, data_offs, napi);
+ ath11k_dbg(ab, ATH11K_DBG_NSS_WDS, "4addr exception ta_peer %pM\n",
+ ta_peer->addr);
+ if (!ta_peer->nss.ext_vdev_up && addr4_metadata->addr4_valid)
+ ieee80211_rx_nss_notify_4addr(dev, ta_peer->addr);
+ spin_unlock_bh(&ab->base_lock);
+ }
+ dev_kfree_skb_any(skb);
+ break;
+ default:
+ ath11k_warn(ab, "unsupported pkt_type %d from nss\n", wifi_metadata->pkt_type);
+ dev_kfree_skb_any(skb);
+ }
}
static void
@@ -1049,6 +1083,9 @@ int ath11k_nss_vdev_set_cmd(struct ath11
case ATH11K_NSS_WIFI_VDEV_CFG_WDS_BACKHAUL_CMD:
cmd = NSS_WIFI_VDEV_CFG_WDS_BACKHAUL_CMD;
break;
+ case ATH11K_NSS_WIFI_VDEV_CFG_MCBC_EXC_TO_HOST_CMD:
+ cmd = NSS_WIFI_VDEV_CFG_MCBC_EXC_TO_HOST_CMD;
+ break;
default:
return -EINVAL;
}
@@ -1299,12 +1336,31 @@ int ath11k_nss_vdev_create(struct ath11k
goto free_vdev;
switch (arvif->vif->type) {
- case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
ret = ath11k_nss_vdev_configure(arvif);
if (ret)
goto unregister_vdev;
+ ret = ath11k_nss_vdev_set_cmd(arvif,
+ ATH11K_NSS_WIFI_VDEV_CFG_MCBC_EXC_TO_HOST_CMD,
+ ATH11K_NSS_ENABLE_MCBC_EXC);
+ if (ret) {
+ ath11k_err(ab, "failed to set MCBC in nss %d\n", ret);
+ goto unregister_vdev;
+ }
+ break;
+ case NL80211_IFTYPE_AP:
+ ret = ath11k_nss_vdev_configure(arvif);
+ if (ret)
+ goto unregister_vdev;
+
+ ret = ath11k_nss_vdev_set_cmd(arvif,
+ ATH11K_NSS_WIFI_VDEV_CFG_WDS_BACKHAUL_CMD,
+ true);
+ if (ret) {
+ ath11k_warn(ab, "failed to cfg wds backhaul in nss %d\n", ret);
+ goto unregister_vdev;
+ }
break;
default:
ret = -ENOTSUPP;
@@ -1463,7 +1519,7 @@ int ath11k_nss_ext_vdev_cfg_wds_peer(str
cfg_wds_msg = &ext_vdev_msg->msg.wmsg;
cfg_wds_msg->wds_peer_id = wds_peer_id;
- ether_addr_copy(cfg_wds_msg->mac_addr, wds_addr);
+ ether_addr_copy((u8 *) cfg_wds_msg->mac_addr, wds_addr);
nss_wifi_ext_vdev_msg_init(ext_vdev_msg, arvif->nss.if_num,
NSS_WIFI_EXT_VDEV_MSG_CONFIGURE_WDS,
@@ -1587,7 +1643,6 @@ static int ath11k_nss_ext_vdev_register(
{
struct ath11k *ar = arvif->ar;
struct ath11k_base *ab = ar->ab;
- nss_tx_status_t status;
u32 features = 0;
if (arvif->vif->type != NL80211_IFTYPE_AP_VLAN || arvif->nss.ctx)
@@ -1601,7 +1656,7 @@ static int ath11k_nss_ext_vdev_register(
if (!arvif->nss.ctx) {
ath11k_warn(ab, "failed to register nss vdev if_num %d nss_err:%d\n",
- arvif->nss.if_num, status);
+ arvif->nss.if_num, NSS_TX_FAILURE);
return -EINVAL;
}
--- a/drivers/net/wireless/ath/ath11k/nss.h
+++ b/drivers/net/wireless/ath/ath11k/nss.h
@@ -110,10 +110,14 @@ enum ath11k_nss_vdev_cmd {
ATH11K_NSS_WIFI_VDEV_ENCAP_TYPE_CMD,
ATH11K_NSS_WIFI_VDEV_DECAP_TYPE_CMD,
ATH11K_NSS_WIFI_VDEV_CFG_WDS_BACKHAUL_CMD,
+ ATH11K_NSS_WIFI_VDEV_CFG_MCBC_EXC_TO_HOST_CMD,
};
#define WIFILI_SCHEME_ID_INVALID -1
+/* Enables the MCBC exception in NSS fw, 1 = enable */
+#define ATH11K_NSS_ENABLE_MCBC_EXC 1
+
enum ath11k_nss_opmode {
ATH11K_NSS_OPMODE_UNKNOWN,
ATH11K_NSS_OPMODE_AP,
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -3086,6 +3086,23 @@ static void ath11k_dp_rx_process_receive
}
}
+void ath11k_dp_rx_from_nss(struct ath11k *ar, struct sk_buff *msdu,
+ struct napi_struct *napi)
+{
+ struct ieee80211_rx_status rx_status = {0};
+ struct ath11k_skb_rxcb *rxcb;
+ bool fast_rx = false;
+
+ rxcb = ATH11K_SKB_RXCB(msdu);
+
+ ath11k_dp_rx_h_ppdu(ar, rxcb->rx_desc, &rx_status);
+ ath11k_dp_rx_h_mpdu(ar, msdu, rxcb->rx_desc, &rx_status, &fast_rx);
+
+ rx_status.flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED;
+
+ ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status);
+}
+
int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id,
struct napi_struct *napi, int budget)
{
--- a/drivers/net/wireless/ath/ath11k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.h
@@ -157,4 +157,6 @@ bool ath11k_dp_rx_h_attn_is_mcbc(struct
struct hal_rx_desc *desc);
u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab,
struct hal_rx_desc *desc);
+void ath11k_dp_rx_from_nss(struct ath11k *ar, struct sk_buff *msdu,
+ struct napi_struct *napi);
#endif /* ATH11K_DP_RX_H */

View File

@ -0,0 +1,522 @@
From 9e1f28f343347774b01f330d76d2c5323fcd07ae Mon Sep 17 00:00:00 2001
From: Rameshkumar Sundaram <ramess@codeaurora.org>
Date: Fri, 24 Sep 2021 18:25:08 +0530
Subject: [PATCH] ath11k: sync wds ast entry on peer/entry deletions
Peer specific ast entries list is shared between
peer_unmap_event(softirq) and peer_ast_wds_wmi_wk
(worker). The worker sends a WMI command and hence tends to
sleep.
complete_work_sync() is used in peer_unmap_event bh handler
which tries to yield the CPU(calls schedule)
until the worker completes. This results kernel reporting
schedule in atomic context and system crash.
Add new global wmi_ast_list and add all ast add/update
work to this list.
Add a new global wmi_ast_work and queue this
work on each entry to global wmi_ast_list list.
Process the wmi_ast_list in worker and send updates
to FW.
Each ast entry node is shared between global wmi_ast list
and peer specific ast_list and deletes will be done
in sync between two lists.
On peer deletion all the peer specific entries will
be deleted from wmi_ast_list and peer delete in progress
will be set to avoid new ast entries adding up and therefore
peer unmap evnt won't find any ast worker in progress
entries to free in irq context.
This peer ast cleanup and worker processing same entry
will be synchronized with new base_ast_lock mutex.
FW indpendently Deleting a single wds ast entry in irq context &
worker already processing the same cannot be synchronized.
As we can't hold bh scheduling while worker tries to sleep,
and entry in scheduled update work will be sent to FW.
Signed-off-by: Rameshkumar Sundaram <ramess@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/ahb.c | 1 +
drivers/net/wireless/ath/ath11k/core.c | 3 +
drivers/net/wireless/ath/ath11k/core.h | 4 +
drivers/net/wireless/ath/ath11k/nss.c | 6 +-
drivers/net/wireless/ath/ath11k/nss.h | 8 +-
drivers/net/wireless/ath/ath11k/pci.c | 1 +
drivers/net/wireless/ath/ath11k/peer.c | 172 ++++++++++++++++++++++++---------
drivers/net/wireless/ath/ath11k/peer.h | 3 +-
8 files changed, 144 insertions(+), 54 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -1245,6 +1245,7 @@ static void ath11k_ahb_remove_prepare(st
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
cancel_work_sync(&ab->restart_work);
cancel_work_sync(&ab->qmi.event_work);
+ cancel_work_sync(&ab->wmi_ast_work);
}
static void ath11k_ahb_free_resources(struct ath11k_base *ab)
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -2230,6 +2230,7 @@ struct ath11k_base *ath11k_core_alloc(st
mutex_init(&ab->core_lock);
mutex_init(&ab->tbl_mtx_lock);
+ mutex_init(&ab->base_ast_lock);
spin_lock_init(&ab->base_lock);
mutex_init(&ab->vdev_id_11d_lock);
init_completion(&ab->reset_complete);
@@ -2243,6 +2244,8 @@ struct ath11k_base *ath11k_core_alloc(st
INIT_WORK(&ab->restart_work, ath11k_core_restart);
INIT_WORK(&ab->update_11d_work, ath11k_update_11d);
INIT_WORK(&ab->reset_work, ath11k_core_reset);
+ INIT_WORK(&ab->wmi_ast_work, ath11k_peer_ast_wds_wmi_wk);
+ INIT_LIST_HEAD(&ab->wmi_ast_list);
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
init_completion(&ab->htc_suspend);
init_completion(&ab->wow.wakeup_completed);
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -32,6 +32,7 @@
#include "rx_desc.h"
#include "nss.h"
#include "vendor.h"
+#include "peer.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -1131,6 +1132,11 @@ struct ath11k_base {
u32 max_ast_index;
u32 num_ast_entries;
+
+ struct mutex base_ast_lock;
+ struct work_struct wmi_ast_work;
+ struct list_head wmi_ast_list;
+
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
--- a/drivers/net/wireless/ath/ath11k/nss.c
+++ b/drivers/net/wireless/ath/ath11k/nss.c
@@ -691,8 +691,9 @@ static void ath11k_nss_wds_type_rx(struc
spin_unlock_bh(&ab->base_lock);
}
-static void ath11k_nss_mec_handler(struct ath11k *ar, u8* mec_mac_addr)
+static void ath11k_nss_mec_handler(struct ath11k_vif *arvif, u8* mec_mac_addr)
{
+ struct ath11k *ar = arvif->ar;
struct ath11k_base *ab = ar->ab;
struct ath11k_peer *peer = ar->bss_peer;
u8 mac_addr[ETH_ALEN];
@@ -719,7 +720,7 @@ static void ath11k_nss_mec_handler(struc
memcpy(mac_addr, mac_addr_h16, ETH_ALEN - 4);
memcpy(mac_addr + 2, mac_addr_l32, 4);
- if (!ether_addr_equal(ar->mac_addr, mac_addr)) {
+ if (!ether_addr_equal(arvif->vif->addr, mac_addr)) {
spin_lock_bh(&ab->base_lock);
ath11k_peer_add_ast(ar, peer, mac_addr,
ATH11K_AST_TYPE_MEC);
@@ -754,7 +755,7 @@ static void ath11k_nss_vdev_spl_receive_
addr4_valid, peer_id);
break;
case NSS_WIFI_VDEV_WDS_TYPE_MEC:
- ath11k_nss_mec_handler(ar, (u8 *)(skb->data));
+ ath11k_nss_mec_handler(arvif, (u8 *)(skb->data));
break;
default:
ath11k_warn(ab, "unsupported wds_type %d\n", wds_type);
@@ -3848,11 +3849,7 @@ int ath11k_nss_add_wds_peer(struct ath11
wds_peer_msg->ast_type = type;
wds_peer_msg->peer_id = peer->peer_id;
- if (type == ATH11K_AST_TYPE_MEC)
- ether_addr_copy(wds_peer_msg->peer_mac, ar->mac_addr);
- else
- ether_addr_copy(wds_peer_msg->peer_mac, peer->addr);
-
+ ether_addr_copy(wds_peer_msg->peer_mac, peer->addr);
ether_addr_copy(wds_peer_msg->dest_mac, dest_mac);
msg_cb = (nss_wifili_msg_callback_t)ath11k_nss_wifili_event_receive;
@@ -3975,7 +3972,7 @@ msg_free:
return ret;
}
-int ath11k_nss_del_wds_peer(struct ath11k *ar, struct ath11k_peer *peer,
+int ath11k_nss_del_wds_peer(struct ath11k *ar, u8 *peer_addr, int peer_id,
u8 *dest_mac)
{
struct ath11k_base *ab = ar->ab;
@@ -3993,8 +3990,8 @@ int ath11k_nss_del_wds_peer(struct ath11
wds_peer_msg->pdev_id = ar->pdev->pdev_id;
wds_peer_msg->ast_type = ATH11K_AST_TYPE_NONE;
- wds_peer_msg->peer_id = peer->peer_id;
- ether_addr_copy(wds_peer_msg->peer_mac, peer->addr);
+ wds_peer_msg->peer_id = peer_id;
+ ether_addr_copy(wds_peer_msg->peer_mac, peer_addr);
ether_addr_copy(wds_peer_msg->dest_mac, dest_mac);
msg_cb = (nss_wifili_msg_callback_t)ath11k_nss_wifili_event_receive;
--- a/drivers/net/wireless/ath/ath11k/nss.h
+++ b/drivers/net/wireless/ath/ath11k/nss.h
@@ -291,8 +291,8 @@ int ath11k_nss_update_wds_peer(struct at
u8 *dest_mac);
int ath11k_nss_map_wds_peer(struct ath11k *ar, struct ath11k_peer *peer,
u8 *dest_mac, enum ath11k_ast_entry_type type);
-int ath11k_nss_del_wds_peer(struct ath11k *ar, struct ath11k_peer *peer,
- u8 *dest_mac);
+int ath11k_nss_del_wds_peer(struct ath11k *ar, u8 *peer_addr,
+ int peer_id, u8 *dest_mac);
int ath11k_nss_ext_vdev_cfg_wds_peer(struct ath11k_vif *arvif,
u8 *wds_addr, u32 wds_peer_id);
int ath11k_nss_ext_vdev_wds_4addr_allow(struct ath11k_vif *arvif,
@@ -404,8 +404,8 @@ static inline int ath11k_nss_map_wds_pee
return 0;
}
-static inline int ath11k_nss_del_wds_peer(struct ath11k_vif *arvif, struct ath11k_peer *peer,
- u8 *dest_mac)
+static inline int ath11k_nss_del_wds_peer(struct ath11k *ar, u8 *peer_addr,
+ int peer_id, u8 *dest_mac)
{
return 0;
}
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -970,6 +970,7 @@ static void ath11k_pci_remove(struct pci
}
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
+ cancel_work_sync(&ab->wmi_ast_work);
ath11k_core_deinit(ab);
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -160,49 +160,68 @@ struct ath11k_ast_entry *ath11k_peer_ast
void ath11k_peer_ast_wds_wmi_wk(struct work_struct *wk)
{
- struct ath11k_ast_entry *ast_entry = container_of(wk,
- struct ath11k_ast_entry,
- wds_wmi_wk);
- struct ath11k *ar;
+ struct ath11k_ast_entry *ast_entry, *entry;
+ struct ath11k_base *ab = container_of(wk, struct ath11k_base, wmi_ast_work);
struct ath11k_peer *peer;
+ struct ath11k *ar;
int ret;
+ u8 peer_addr[ETH_ALEN];
+ int peer_id;
- if (!ast_entry)
- return;
+ ast_entry = kzalloc(sizeof(*ast_entry), GFP_ATOMIC);
- ar = ast_entry->ar;
- peer = ast_entry->peer;
+ mutex_lock(&ab->base_ast_lock);
+ spin_lock_bh(&ab->base_lock);
+
+ while ((entry = list_first_entry_or_null(&ab->wmi_ast_list,
+ struct ath11k_ast_entry, wmi_list))) {
+ list_del_init(&entry->wmi_list);
- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "ath11k_peer_ast_wds_wmi_wk action %d ast_entry %pM next_node %pM vdev %d\n",
- ast_entry->action, ast_entry->addr, ast_entry->next_node_mac,
- ast_entry->vdev_id);
-
- if (ast_entry->action == ATH11K_WDS_WMI_ADD) {
- ret = ath11k_wmi_send_add_update_wds_entry_cmd(ar,
- ast_entry->next_node_mac,
- ast_entry->addr,
- ast_entry->vdev_id,
- true);
- if (ret) {
- ath11k_warn(ar->ab, "add wds_entry_cmd failed %d for %pM next_node %pM\n",
- ret, ast_entry->addr,
- ast_entry->next_node_mac);
- if (peer)
- ath11k_nss_del_wds_peer(ar, peer,
- ast_entry->addr);
+ if (!entry->ar || (entry->peer && entry->peer->delete_in_progress)) {
+ continue;
}
- } else if (ast_entry->action == ATH11K_WDS_WMI_UPDATE) {
- if (!peer)
- return;
+ memcpy(ast_entry, entry, sizeof(*ast_entry));
+ ar = ast_entry->ar;
+ peer = ast_entry->peer;
+ memcpy(peer_addr, peer->addr, sizeof(peer_addr));
+ peer_id = peer->peer_id;
+
+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+ "ath11k_peer_ast_wds_wmi_wk action %d ast_entry %pM peer %pM vdev %d\n",
+ ast_entry->action, ast_entry->addr, peer_addr,
+ ast_entry->vdev_id);
- ret = ath11k_wmi_send_add_update_wds_entry_cmd(ar, peer->addr,
- ast_entry->addr,
- ast_entry->vdev_id,
- false);
- if (ret)
- ath11k_warn(ar->ab, "update wds_entry_cmd failed %d for %pM on peer %pM\n",
- ret, ast_entry->addr, peer->addr);
+ if (ast_entry->action == ATH11K_WDS_WMI_ADD) {
+ spin_unlock_bh(&ab->base_lock);
+ ret = ath11k_wmi_send_add_update_wds_entry_cmd(ar, peer_addr,
+ ast_entry->addr,
+ ast_entry->vdev_id,
+ true);
+ if (ret) {
+ ath11k_warn(ar->ab, "add wds_entry_cmd failed %d for %pM, peer %pM\n",
+ ret, ast_entry->addr, peer_addr);
+ if (peer)
+ ath11k_nss_del_wds_peer(ar, peer_addr, peer_id,
+ ast_entry->addr);
+ }
+ } else if (ast_entry->action == ATH11K_WDS_WMI_UPDATE) {
+ if (!peer) {
+ continue;
+ }
+ spin_unlock_bh(&ab->base_lock);
+ ret = ath11k_wmi_send_add_update_wds_entry_cmd(ar, peer_addr,
+ ast_entry->addr,
+ ast_entry->vdev_id,
+ false);
+ if (ret)
+ ath11k_warn(ar->ab, "update wds_entry_cmd failed %d for %pM on peer %pM\n",
+ ret, ast_entry->addr, peer_addr);
+ }
+ spin_lock_bh(&ab->base_lock);
}
+ spin_unlock_bh(&ab->base_lock);
+ mutex_unlock(&ab->base_ast_lock);
+ kfree(ast_entry);
}
int ath11k_peer_add_ast(struct ath11k *ar, struct ath11k_peer *peer,
@@ -211,6 +230,8 @@ int ath11k_peer_add_ast(struct ath11k *a
struct ath11k_ast_entry *ast_entry = NULL;
struct ath11k_base *ab = ar->ab;
+ lockdep_assert_held(&ab->base_lock);
+
if (ab->num_ast_entries == ab->max_ast_index) {
ath11k_warn(ab, "failed to add ast for %pM due to insufficient ast entry resource %d in target\n",
mac_addr, ab->max_ast_index);
@@ -226,6 +247,9 @@ int ath11k_peer_add_ast(struct ath11k *a
}
}
+ if (peer && peer->delete_in_progress)
+ return -EINVAL;
+
ast_entry = kzalloc(sizeof(*ast_entry), GFP_ATOMIC);
if (!ast_entry) {
ath11k_warn(ab, "failed to alloc ast_entry for %pM\n",
@@ -257,7 +281,7 @@ int ath11k_peer_add_ast(struct ath11k *a
}
INIT_LIST_HEAD(&ast_entry->ase_list);
- INIT_WORK(&ast_entry->wds_wmi_wk, ath11k_peer_ast_wds_wmi_wk);
+ INIT_LIST_HEAD(&ast_entry->wmi_list);
ast_entry->vdev_id = peer->vdev_id;
ast_entry->pdev_idx = peer->pdev_idx;
ast_entry->is_mapped = false;
@@ -271,16 +295,12 @@ int ath11k_peer_add_ast(struct ath11k *a
ath11k_dbg(ab, ATH11K_DBG_MAC, "ath11k_peer_add_ast peer %pM ast_entry %pM, ast_type %d\n",
peer->addr, mac_addr, ast_entry->type);
- if (type == ATH11K_AST_TYPE_MEC)
- ether_addr_copy(ast_entry->next_node_mac, ar->mac_addr);
- else if (type == ATH11K_AST_TYPE_WDS)
- ether_addr_copy(ast_entry->next_node_mac, peer->addr);
-
if ((ast_entry->type == ATH11K_AST_TYPE_WDS) ||
(ast_entry->type == ATH11K_AST_TYPE_MEC)) {
ath11k_nss_add_wds_peer(ar, peer, mac_addr, ast_entry->type);
ast_entry->action = ATH11K_WDS_WMI_ADD;
- ieee80211_queue_work(ar->hw, &ast_entry->wds_wmi_wk);
+ list_add_tail(&ast_entry->wmi_list, &ab->wmi_ast_list);
+ ieee80211_queue_work(ar->hw, &ab->wmi_ast_work);
}
ab->num_ast_entries++;
@@ -293,6 +313,8 @@ int ath11k_peer_update_ast(struct ath11k
struct ath11k_peer *old_peer = ast_entry->peer;
struct ath11k_base *ab = ar->ab;
+ lockdep_assert_held(&ab->base_lock);
+
if (!ast_entry->is_mapped) {
ath11k_warn(ab, "ath11k_peer_update_ast: ast_entry %pM not mapped yet\n",
ast_entry->addr);
@@ -305,6 +327,9 @@ int ath11k_peer_update_ast(struct ath11k
(ast_entry->is_active))
return 0;
+ if (peer && peer->delete_in_progress)
+ return -EINVAL;
+
ast_entry->vdev_id = peer->vdev_id;
ast_entry->pdev_idx = peer->pdev_idx;
ast_entry->type = ATH11K_AST_TYPE_WDS;
@@ -317,7 +342,14 @@ int ath11k_peer_update_ast(struct ath11k
old_peer->addr, peer->addr, ast_entry->addr);
ast_entry->action = ATH11K_WDS_WMI_UPDATE;
- ieee80211_queue_work(ar->hw, &ast_entry->wds_wmi_wk);
+
+ /* wmi_list entry might've been processed & removed.*/
+ if (list_empty(&ast_entry->wmi_list))
+ list_add_tail(&ast_entry->wmi_list, &ab->wmi_ast_list);
+ else
+ list_move_tail(&ast_entry->wmi_list, &ab->wmi_ast_list);
+
+ ieee80211_queue_work(ar->hw, &ab->wmi_ast_work);
return 0;
}
@@ -363,16 +395,23 @@ void ath11k_peer_del_ast(struct ath11k *
ath11k_dbg(ab, ATH11K_DBG_MAC, "ath11k_peer_del_ast pdev:%d peer %pM ast_entry %pM\n",
ar->pdev->pdev_id, peer->addr, ast_entry->addr);
- if (ast_entry->is_mapped)
- list_del(&ast_entry->ase_list);
+ if ((ast_entry->type == ATH11K_AST_TYPE_WDS) ||
+ (ast_entry->type == ATH11K_AST_TYPE_MEC)) {
+ if (!list_empty(&ast_entry->wmi_list)) {
+ ath11k_dbg(ab, ATH11K_DBG_MAC,
+ "ath11k_peer_del_ast deleting unprocessed ast entry %pM "
+ "of peer %pM from wmi list\n", ast_entry->addr, peer->addr);
+ list_del_init(&ast_entry->wmi_list);
+ }
+ }
+ list_del(&ast_entry->ase_list);
/* WDS, MEC type AST entries need to be deleted on NSS */
if (ast_entry->next_hop)
- ath11k_nss_del_wds_peer(ar, peer, ast_entry->addr);
+ ath11k_nss_del_wds_peer(ar, peer->addr, peer->peer_id,
+ ast_entry->addr);
- cancel_work_sync(&ast_entry->wds_wmi_wk);
kfree(ast_entry);
-
ab->num_ast_entries--;
}
@@ -681,6 +720,10 @@ void ath11k_peer_cleanup(struct ath11k *
lockdep_assert_held(&ar->conf_mutex);
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
+ mutex_lock(&ab->base_ast_lock);
+#endif
+
mutex_lock(&ab->tbl_mtx_lock);
spin_lock_bh(&ab->base_lock);
list_for_each_entry_safe(peer, tmp_peer, &ab->peers, list) {
@@ -709,6 +752,9 @@ void ath11k_peer_cleanup(struct ath11k *
spin_unlock_bh(&ab->base_lock);
mutex_unlock(&ab->tbl_mtx_lock);
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
+ mutex_unlock(&ab->base_ast_lock);
+#endif
}
static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
@@ -743,12 +789,18 @@ static int __ath11k_peer_delete(struct a
int ret;
struct ath11k_peer *peer;
struct ath11k_base *ab = ar->ab;
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
+ struct ath11k_ast_entry *ast_entry, *tmp_ast;
+#endif
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->peer_delete_done);
ath11k_nss_peer_delete(ar->ab, vdev_id, addr);
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
+ mutex_lock(&ab->base_ast_lock);
+#endif
mutex_lock(&ab->tbl_mtx_lock);
spin_lock_bh(&ab->base_lock);
@@ -771,17 +823,35 @@ static int __ath11k_peer_delete(struct a
return -EINVAL;
}
- /* Check if the found peer is what we want to remove.
- * While the sta is transitioning to another band we may
- * have 2 peer with the same addr assigned to different
- * vdev_id. Make sure we are deleting the correct peer.
- */
- if (peer && peer->vdev_id == vdev_id)
+ if (peer) {
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
+ peer->delete_in_progress = true;
+ if (peer->self_ast_entry) {
+ ath11k_peer_del_ast(ar, peer->self_ast_entry);
+ peer->self_ast_entry = NULL;
+ }
+
+ list_for_each_entry_safe(ast_entry, tmp_ast,
+ &peer->ast_entry_list, ase_list)
+ if ((ast_entry->type == ATH11K_AST_TYPE_WDS) ||
+ (ast_entry->type == ATH11K_AST_TYPE_MEC)) {
+ if (!list_empty(&ast_entry->wmi_list)) {
+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+ "%s deleting unprocessed ast entry %pM of peer %pM from wmi list\n",
+ __func__, ast_entry->addr, addr);
+ list_del_init(&ast_entry->wmi_list);
+ }
+ }
+#endif
ath11k_peer_rhash_delete(ab, peer);
+ }
spin_unlock_bh(&ab->base_lock);
mutex_unlock(&ab->tbl_mtx_lock);
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
+ mutex_unlock(&ab->base_ast_lock);
+#endif
ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
if (ret) {
--- a/drivers/net/wireless/ath/ath11k/peer.h
+++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -31,9 +31,7 @@ enum ath11k_wds_wmi_action {
struct ath11k_ast_entry {
u16 ast_idx;
u8 addr[ETH_ALEN];
- u8 next_node_mac[ETH_ALEN];
enum ath11k_wds_wmi_action action;
- struct work_struct wds_wmi_wk;
struct ath11k_peer *peer;
struct ath11k *ar;
bool next_hop;
@@ -47,6 +45,7 @@ struct ath11k_ast_entry {
bool delete_in_progress;
void *cookie;
struct list_head ase_list;
+ struct list_head wmi_list;
};
struct ppdu_user_delayba {
@@ -97,6 +96,7 @@ struct ath11k_peer {
bool dp_setup_done;
struct ppdu_user_delayba ppdu_stats_delayba;
bool delayba_flag;
+ bool delete_in_progress;
};
void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id);

View File

@ -0,0 +1,96 @@
From 396176575be9767a79d451fba4fe2931305f0435 Mon Sep 17 00:00:00 2001
From: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
Date: Mon, 7 Nov 2022 21:49:20 +0530
Subject: [PATCH] ath11k: fix incorrect ast index assignment for wds peer
Currently, same ast index is assigned for different nss wds peer mac
addresses which is incorrect. However, firmware provides the correct
and different ast index for different mac addresses.
Hence, fix this issue by assigning the correct ast index provided by
the firmware.
Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
---
drivers/net/wireless/ath/ath11k/nss.c | 5 +++--
drivers/net/wireless/ath/ath11k/nss.h | 6 ++++--
drivers/net/wireless/ath/ath11k/peer.c | 3 +--
3 files changed, 8 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/nss.c
+++ b/drivers/net/wireless/ath/ath11k/nss.c
@@ -805,8 +805,6 @@ ath11k_nss_vdev_special_data_receive(str
struct nss_wifi_vdev_per_packet_metadata *wifi_metadata = NULL;
struct nss_wifi_vdev_wds_per_packet_metadata *wds_metadata = NULL;
struct nss_wifi_vdev_addr4_data_metadata *addr4_metadata = NULL;
- struct wireless_dev *wdev;
- struct ieee80211_vif *vif;
struct ath11k_vif *arvif;
struct ath11k_base *ab;
struct ath11k_skb_rxcb *rxcb;
@@ -2487,13 +2485,14 @@ msg_free:
}
int ath11k_nss_map_wds_peer(struct ath11k *ar, struct ath11k_peer *peer,
- u8 *dest_mac, enum ath11k_ast_entry_type type)
+ u8 *dest_mac, struct ath11k_ast_entry *ast_entry)
{
struct ath11k_base *ab = ar->ab;
struct nss_wifili_wds_peer_map_msg *wds_peer_map_msg;
struct nss_wifili_msg *wlmsg = NULL;
nss_wifili_msg_callback_t msg_cb;
nss_tx_status_t status;
+ enum ath11k_ast_entry_type type = ast_entry->type;
int ret = 0;
wlmsg = kzalloc(sizeof(struct nss_wifili_msg), GFP_ATOMIC);
@@ -2503,7 +2502,7 @@ int ath11k_nss_map_wds_peer(struct ath11
wds_peer_map_msg = &wlmsg->msg.wdspeermapmsg;
wds_peer_map_msg->vdev_id = peer->vdev_id;
- wds_peer_map_msg->ast_idx = peer->hw_peer_id;
+ wds_peer_map_msg->ast_idx = ast_entry->ast_idx;
if (type == ATH11K_AST_TYPE_MEC)
wds_peer_map_msg->peer_id = NSS_WIFILI_MEC_PEER_ID;
--- a/drivers/net/wireless/ath/ath11k/nss.h
+++ b/drivers/net/wireless/ath/ath11k/nss.h
@@ -16,6 +16,7 @@ struct ath11k;
struct ath11k_base;
struct ath11k_vif;
struct ath11k_peer;
+struct ath11k_ast_entry;
struct ath11k_sta;
enum ath11k_ast_entry_type;
struct hal_rx_mon_ppdu_info;
@@ -241,7 +242,7 @@ int ath11k_nss_add_wds_peer(struct ath11
int ath11k_nss_update_wds_peer(struct ath11k *ar, struct ath11k_peer *peer,
u8 *dest_mac);
int ath11k_nss_map_wds_peer(struct ath11k *ar, struct ath11k_peer *peer,
- u8 *dest_mac, enum ath11k_ast_entry_type type);
+ u8 *dest_mac, struct ath11k_ast_entry *ast_entry);
int ath11k_nss_del_wds_peer(struct ath11k *ar, u8 *peer_addr,
int peer_id, u8 *dest_mac);
int ath11k_nss_ext_vdev_cfg_wds_peer(struct ath11k_vif *arvif,
@@ -337,7 +338,8 @@ static inline int ath11k_nss_update_wds_
}
static inline int ath11k_nss_map_wds_peer(struct ath11k *ar, struct ath11k_peer *peer,
- u8 *dest_mac, int type)
+ u8 *dest_mac,
+ struct ath11k_ast_entry *ast_entry)
{
return 0;
}
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -373,8 +373,7 @@ void ath11k_peer_map_ast(struct ath11k *
if ((ast_entry->type == ATH11K_AST_TYPE_WDS) ||
(ast_entry->type == ATH11K_AST_TYPE_MEC))
- ath11k_nss_map_wds_peer(ar, peer, mac_addr,
- ast_entry->type);
+ ath11k_nss_map_wds_peer(ar, peer, mac_addr, ast_entry);
ath11k_dbg(ab, ATH11K_DBG_MAC, "ath11k_peer_map_ast peer %pM ast_entry %pM\n",
peer->addr, ast_entry->addr);