diff --git a/package/kernel/mac80211/patches/ath/902-1-ath11k-ethernet-rx-decap-offload.patch b/package/kernel/mac80211/patches/ath/902-1-ath11k-ethernet-rx-decap-offload.patch new file mode 100644 index 000000000..2873b6634 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/902-1-ath11k-ethernet-rx-decap-offload.patch @@ -0,0 +1,438 @@ +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -294,6 +294,14 @@ static int ath11k_dp_purge_mon_ring(stru + return -ETIMEDOUT; + } + ++static bool ath11k_dp_rx_h_attn_is_mcbc(struct hal_rx_desc *desc) ++{ ++ return (!!FIELD_GET(RX_MSDU_END_INFO2_DA_IS_MCBC, ++ __le32_to_cpu(desc->msdu_end.info2))) && ++ (!!FIELD_GET(RX_ATTENTION_INFO1_MCAST_BCAST, ++ __le32_to_cpu(desc->attention.info1))); ++} ++ + /* Returns number of Rx buffers replenished */ + int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id, + struct dp_rxdma_ring *rx_ring, +@@ -2250,6 +2272,7 @@ static void ath11k_dp_rx_h_undecap(struc + { + u8 *first_hdr; + u8 decap; ++ struct ethhdr *ehdr; + + first_hdr = ath11k_dp_rx_h_80211_hdr(ar->ab, rx_desc); + decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc); +@@ -2264,9 +2287,21 @@ static void ath11k_dp_rx_h_undecap(struc + decrypted); + break; + case DP_RX_DECAP_TYPE_ETHERNET2_DIX: +- /* TODO undecap support for middle/last msdu's of amsdu */ +- ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, +- enctype, status); ++ ehdr = (struct ethhdr *) msdu->data; ++ ++ /* mac80211 allows fast path only for authorized STA */ ++ if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) { ++ ATH11K_SKB_RXCB(msdu)->is_eapol = true; ++ ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, ++ enctype, status); ++ } ++ ++ /* PN for mcast packets will be validated in mac80211; ++ * remove eth header and add 802.11 header. ++ */ ++ if (ATH11K_SKB_RXCB(msdu)->is_mcbc && decrypted) ++ ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, ++ enctype, status); + break; + case DP_RX_DECAP_TYPE_8023: + /* TODO: Handle undecap for these formats */ +@@ -2274,34 +2309,56 @@ static void ath11k_dp_rx_h_undecap(struc + } + } + ++static struct ath11k_peer * ++ath11k_dp_rx_h_find_peer(struct ath11k_base *ab, struct sk_buff *msdu) ++{ ++ struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); ++ struct hal_rx_desc *rx_desc = rxcb->rx_desc; ++ struct ath11k_peer *peer = NULL; ++ lockdep_assert_held(&ab->base_lock); ++ if (rxcb->peer_id) ++ peer = ath11k_peer_find_by_id(ab, rxcb->peer_id); ++ if (peer) ++ return peer; ++ ++ if (!rx_desc || ++ !(rx_desc->mpdu_start.info1 & RX_MPDU_START_INFO1_MAC_ADDR2_VALID)) ++ return NULL; ++ peer = ath11k_peer_find_by_addr(ab, rx_desc->mpdu_start.addr2); ++ return peer; ++} ++ + static void ath11k_dp_rx_h_mpdu(struct ath11k *ar, + struct sk_buff *msdu, + struct hal_rx_desc *rx_desc, + struct ieee80211_rx_status *rx_status) + { +- bool fill_crypto_hdr, mcast; ++ bool fill_crypto_hdr; + enum hal_encrypt_type enctype; + bool is_decrypted = false; ++ struct ath11k_skb_rxcb *rxcb; + struct ieee80211_hdr *hdr; + struct ath11k_peer *peer; + u32 err_bitmap; + +- hdr = (struct ieee80211_hdr *)msdu->data; +- + /* PN for multicast packets will be checked in mac80211 */ ++ rxcb = ATH11K_SKB_RXCB(msdu); ++ rxcb->is_mcbc = fill_crypto_hdr = ath11k_dp_rx_h_attn_is_mcbc(rx_desc); + +- mcast = is_multicast_ether_addr(hdr->addr1); +- fill_crypto_hdr = mcast; ++ if (rxcb->is_mcbc) { ++ rxcb->peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(rx_desc); ++ rxcb->seq_no = ath11k_dp_rx_h_mpdu_start_seq_no(rx_desc); ++ } + + spin_lock_bh(&ar->ab->base_lock); +- peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr2); ++ peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); + if (peer) { +- if (mcast) ++ if (rxcb->is_mcbc) + enctype = peer->sec_type_grp; + else + enctype = peer->sec_type; + } else { +- enctype = HAL_ENCRYPT_TYPE_OPEN; ++ enctype = ath11k_dp_rx_h_mpdu_start_enctype(rx_desc); + } + spin_unlock_bh(&ar->ab->base_lock); + +@@ -2341,8 +2398,11 @@ static void ath11k_dp_rx_h_mpdu(struct a + if (!is_decrypted || fill_crypto_hdr) + return; + +- hdr = (void *)msdu->data; +- hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); ++ if (ath11k_dp_rx_h_msdu_start_decap_type(rx_desc) != ++ DP_RX_DECAP_TYPE_ETHERNET2_DIX) { ++ hdr = (void *)msdu->data; ++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); ++ } + } + + static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc, +@@ -2516,51 +2576,46 @@ static void ath11k_dp_rx_h_ppdu(struct a + ath11k_dp_rx_h_rate(ar, rx_desc, rx_status); + } + +-static char *ath11k_print_get_tid(struct ieee80211_hdr *hdr, char *out, +- size_t size) +-{ +- u8 *qc; +- int tid; +- +- if (!ieee80211_is_data_qos(hdr->frame_control)) +- return ""; +- +- qc = ieee80211_get_qos_ctl(hdr); +- tid = *qc & IEEE80211_QOS_CTL_TID_MASK; +- snprintf(out, size, "tid %d", tid); +- +- return out; +-} +- + static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *napi, +- struct sk_buff *msdu) ++ struct sk_buff *msdu, ++ struct ieee80211_rx_status *status) + { + static const struct ieee80211_radiotap_he known = { + .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), + .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), + }; +- struct ieee80211_rx_status *status; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; ++ struct ieee80211_rx_status *rx_status; + struct ieee80211_radiotap_he *he = NULL; +- char tid[32]; ++ struct ieee80211_sta *pubsta = NULL; ++ struct ath11k_peer *peer; ++ struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); ++ u8 decap = DP_RX_DECAP_TYPE_RAW; ++ bool is_mcbc = rxcb->is_mcbc; ++ bool is_eapol = rxcb->is_eapol; + +- status = IEEE80211_SKB_RXCB(msdu); +- if (status->encoding == RX_ENC_HE) { ++ if ((status->encoding == RX_ENC_HE) && !(status->flag & RX_FLAG_RADIOTAP_HE) && ++ !(status->flag & RX_FLAG_SKIP_MONITOR)) { + he = skb_push(msdu, sizeof(known)); + memcpy(he, &known, sizeof(known)); + status->flag |= RX_FLAG_RADIOTAP_HE; + } + ++ decap = ath11k_dp_rx_h_msdu_start_decap_type(rxcb->rx_desc); ++ spin_lock_bh(&ar->ab->base_lock); ++ peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); ++ if (peer && peer->sta) ++ pubsta = peer->sta; ++ spin_unlock_bh(&ar->ab->base_lock); ++ + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, + "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + msdu, + msdu->len, +- ieee80211_get_SA(hdr), +- ath11k_print_get_tid(hdr, tid, sizeof(tid)), +- is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? +- "mcast" : "ucast", +- (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, ++ peer ? peer->addr : NULL, ++ rxcb->tid, ++ (is_mcbc) ? "mcast" : "ucast", ++ rxcb->seq_no, + (status->encoding == RX_ENC_LEGACY) ? "legacy" : "", + (status->encoding == RX_ENC_HT) ? "ht" : "", + (status->encoding == RX_ENC_VHT) ? "vht" : "", +@@ -2519,21 +2575,30 @@ static void ath11k_dp_rx_deliver_msdu(st + + ath11k_dbg_dump(ar->ab, ATH11K_DBG_DP_RX, NULL, "dp rx msdu: ", + msdu->data, msdu->len); ++ rx_status = IEEE80211_SKB_RXCB(msdu); ++ *rx_status = *status; + + /* TODO: trace rx packet */ + +- ieee80211_rx_napi(ar->hw, NULL, msdu, napi); ++ /* PN for multicast packets are not validate in HW, ++ * so skip 802.3 rx path ++ * Also, fast_rx expectes the STA to be authorized, hence ++ * eapol packets are sent in slow path. ++ */ ++ if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && ++ !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) ++ rx_status->flag |= RX_FLAG_8023; ++ ++ ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + } + + static int ath11k_dp_rx_process_msdu(struct ath11k *ar, + struct sk_buff *msdu, +- struct sk_buff_head *msdu_list) ++ struct sk_buff_head *msdu_list, ++ struct ieee80211_rx_status *rx_status) + { + struct hal_rx_desc *rx_desc, *lrx_desc; +- struct ieee80211_rx_status rx_status = {0}; +- struct ieee80211_rx_status *status; + struct ath11k_skb_rxcb *rxcb; +- struct ieee80211_hdr *hdr; + struct sk_buff *last_buf; + u8 l3_pad_bytes; + u8 *hdr_status; +@@ -2591,19 +2656,11 @@ static int ath11k_dp_rx_process_msdu(str + } + } + +- hdr = (struct ieee80211_hdr *)msdu->data; +- +- /* Process only data frames */ +- if (!ieee80211_is_data(hdr->frame_control)) +- return -EINVAL; +- +- ath11k_dp_rx_h_ppdu(ar, rx_desc, &rx_status); +- ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, &rx_status); ++ ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status); ++ ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status); + +- rx_status.flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; ++ rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; + +- status = IEEE80211_SKB_RXCB(msdu); +- *status = rx_status; + return 0; + + free_out: +@@ -2618,6 +2675,7 @@ static void ath11k_dp_rx_process_receive + struct ath11k_skb_rxcb *rxcb; + struct sk_buff *msdu; + struct ath11k *ar; ++ struct ieee80211_rx_status rx_status = {0}; + u8 mac_id; + int ret; + +@@ -2640,7 +2698,7 @@ static void ath11k_dp_rx_process_receive + continue; + } + +- ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list); ++ ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "Unable to process msdu %d", ret); +@@ -2648,7 +2706,7 @@ static void ath11k_dp_rx_process_receive + continue; + } + +- ath11k_dp_rx_deliver_msdu(ar, napi, msdu); ++ ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); + (*quota)--; + } + +@@ -2730,10 +2788,14 @@ try_again: + RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); + rxcb->is_continuation = !!(desc.rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); +- rxcb->mac_id = mac_id; ++ rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, ++ desc.rx_mpdu_info.meta_data); ++ rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, ++ desc.rx_mpdu_info.info0); + rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, + desc.info0); + ++ rxcb->mac_id = mac_id; + __skb_queue_tail(&msdu_list, msdu); + + if (total_msdu_reaped >= quota && !rxcb->is_continuation) { +@@ -4105,7 +4167,6 @@ static void ath11k_dp_rx_wbm_err(struct + { + struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); + struct ieee80211_rx_status rxs = {0}; +- struct ieee80211_rx_status *status; + bool drop = true; + + switch (rxcb->err_rel_src) { +@@ -4125,10 +4186,7 @@ static void ath11k_dp_rx_wbm_err(struct + return; + } + +- status = IEEE80211_SKB_RXCB(msdu); +- *status = rxs; +- +- ath11k_dp_rx_deliver_msdu(ar, napi, msdu); ++ ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rxs); + } + + int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, +@@ -5080,7 +5138,7 @@ static int ath11k_dp_rx_mon_deliver(stru + { + struct ath11k_pdev_dp *dp = &ar->dp; + struct sk_buff *mon_skb, *skb_next, *header; +- struct ieee80211_rx_status *rxs = &dp->rx_status, *status; ++ struct ieee80211_rx_status *rxs = &dp->rx_status; + + mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, + tail_msdu, rxs); +@@ -5106,10 +5164,7 @@ static int ath11k_dp_rx_mon_deliver(stru + } + rxs->flag |= RX_FLAG_ONLY_MONITOR; + +- status = IEEE80211_SKB_RXCB(mon_skb); +- *status = *rxs; +- +- ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb); ++ ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb, rxs); + mon_skb = skb_next; + } while (mon_skb); + rxs->flag = 0; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5198,7 +5198,8 @@ static void ath11k_mac_op_update_vif_off + if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET || + (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP)) +- vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED | ++ IEEE80211_OFFLOAD_DECAP_ENABLED); + + if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) + param_value = ATH11K_HW_TXRX_ETHERNET; +@@ -5214,6 +5215,22 @@ static void ath11k_mac_op_update_vif_off + arvif->vdev_id, ret); + vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; + } ++ ++ param_id = WMI_VDEV_PARAM_RX_DECAP_TYPE; ++ if (vif->offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED) ++ param_value = ATH11K_HW_TXRX_ETHERNET; ++ else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) ++ param_value = ATH11K_HW_TXRX_RAW; ++ else ++ param_value = ATH11K_HW_TXRX_NATIVE_WIFI; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ param_id, param_value); ++ if (ret) { ++ ath11k_warn(ab, "failed to set vdev %d rx decap mode: %d\n", ++ arvif->vdev_id, ret); ++ vif->offload_flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; ++ } + } + + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, +@@ -7301,7 +7318,10 @@ static int __ath11k_mac_register(struct + ieee80211_hw_set(ar->hw, QUEUE_CONTROL); + ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); +- ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET) { ++ ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ ieee80211_hw_set(ar->hw, SUPPORTS_RX_DECAP_OFFLOAD); ++ } + if (ht_cap & WMI_HT_CAP_ENABLED) { + ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); + ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -97,6 +97,8 @@ struct ath11k_skb_rxcb { + bool is_first_msdu; + bool is_last_msdu; + bool is_continuation; ++ bool is_mcbc; ++ bool is_eapol; + struct hal_rx_desc *rx_desc; + u8 err_rel_src; + u8 err_code; +@@ -104,6 +106,8 @@ struct ath11k_skb_rxcb { + u8 unmapped; + u8 is_frag; + u8 tid; ++ u16 peer_id; ++ u16 seq_no; + }; + + enum ath11k_hw_rev { +--- a/drivers/net/wireless/ath/ath11k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath11k/hal_desc.h +@@ -497,6 +497,8 @@ struct hal_tlv_hdr { + #define RX_MPDU_DESC_INFO0_DA_IDX_TIMEOUT BIT(29) + #define RX_MPDU_DESC_INFO0_RAW_MPDU BIT(30) + ++#define RX_MPDU_DESC_META_DATA_PEER_ID GENMASK(15, 0) ++ + struct rx_mpdu_desc { + u32 info0; /* %RX_MPDU_DESC_INFO */ + u32 meta_data; +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -25,10 +25,10 @@ module_param_named(crypto_mode, ath11k_c + MODULE_PARM_DESC(crypto_mode, "crypto mode: 0-hardware, 1-software"); + + /* frame mode values are mapped as per enum ath11k_hw_txrx_mode */ +-unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_NATIVE_WIFI; ++unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_ETHERNET; + module_param_named(frame_mode, ath11k_frame_mode, uint, 0644); + MODULE_PARM_DESC(frame_mode, +- "Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)"); ++ "Datapath frame mode (0: raw, 1: native wifi, 2: ethernet(default))"); + + static const struct ath11k_hw_params ath11k_hw_params[] = { + { diff --git a/package/kernel/mac80211/patches/ath/902-2-ath11k-add-8023-undecap-support.patch b/package/kernel/mac80211/patches/ath/902-2-ath11k-add-8023-undecap-support.patch new file mode 100644 index 000000000..ba9113c10 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/902-2-ath11k-add-8023-undecap-support.patch @@ -0,0 +1,55 @@ +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2264,6 +2264,42 @@ static void ath11k_dp_rx_h_undecap_eth(s + ether_addr_copy(ieee80211_get_SA(hdr), sa); + } + ++static void ath11k_dp_rx_h_undecap_snap(struct ath11k *ar, ++ struct sk_buff *msdu, ++ u8 *first_hdr, ++ enum hal_encrypt_type enctype, ++ struct ieee80211_rx_status *status) ++{ ++ struct ieee80211_hdr *hdr; ++ size_t hdr_len; ++ u8 l3_pad_bytes; ++ struct hal_rx_desc *rx_desc; ++ ++ /* Delivered decapped frame: ++ * [amsdu header] <-- replaced with 802.11 hdr ++ * [rfc1042/llc] ++ * [payload] ++ */ ++ ++ rx_desc = (void *)msdu->data - sizeof(*rx_desc); ++ l3_pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(rx_desc); ++ ++ skb_put(msdu, l3_pad_bytes); ++ skb_pull(msdu, sizeof(struct ath11k_dp_amsdu_subframe_hdr) + l3_pad_bytes); ++ ++ hdr = (struct ieee80211_hdr *)first_hdr; ++ hdr_len = ieee80211_hdrlen(hdr->frame_control); ++ ++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) { ++ memcpy(skb_push(msdu, ++ ath11k_dp_rx_crypto_param_len(ar, enctype)), ++ (void *)hdr + hdr_len, ++ ath11k_dp_rx_crypto_param_len(ar, enctype)); ++ } ++ ++ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); ++} ++ + static void ath11k_dp_rx_h_undecap(struct ath11k *ar, struct sk_buff *msdu, + struct hal_rx_desc *rx_desc, + enum hal_encrypt_type enctype, +@@ -2294,7 +2330,8 @@ static void ath11k_dp_rx_h_undecap(struc + enctype, status); + break; + case DP_RX_DECAP_TYPE_8023: +- /* TODO: Handle undecap for these formats */ ++ ath11k_dp_rx_h_undecap_snap(ar, msdu, first_hdr, ++ enctype, status); + break; + } + }