|
@@ -21,6 +21,7 @@
|
|
|
#include "txrx.h"
|
|
|
#include "debug.h"
|
|
|
#include "trace.h"
|
|
|
+#include "mac.h"
|
|
|
|
|
|
#include <linux/log2.h>
|
|
|
|
|
@@ -307,7 +308,8 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb)
|
|
|
static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
|
|
u8 **fw_desc, int *fw_desc_len,
|
|
|
struct sk_buff **head_msdu,
|
|
|
- struct sk_buff **tail_msdu)
|
|
|
+ struct sk_buff **tail_msdu,
|
|
|
+ u32 *attention)
|
|
|
{
|
|
|
int msdu_len, msdu_chaining = 0;
|
|
|
struct sk_buff *msdu;
|
|
@@ -357,6 +359,11 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ *attention |= __le32_to_cpu(rx_desc->attention.flags) &
|
|
|
+ (RX_ATTENTION_FLAGS_TKIP_MIC_ERR |
|
|
|
+ RX_ATTENTION_FLAGS_DECRYPT_ERR |
|
|
|
+ RX_ATTENTION_FLAGS_FCS_ERR |
|
|
|
+ RX_ATTENTION_FLAGS_MGMT_TYPE);
|
|
|
/*
|
|
|
* Copy the FW rx descriptor for this MSDU from the rx
|
|
|
* indication message into the MSDU's netbuf. HL uses the
|
|
@@ -1215,13 +1222,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|
|
for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) {
|
|
|
struct sk_buff *msdu_head, *msdu_tail;
|
|
|
|
|
|
+ attention = 0;
|
|
|
msdu_head = NULL;
|
|
|
msdu_tail = NULL;
|
|
|
ret = ath10k_htt_rx_amsdu_pop(htt,
|
|
|
&fw_desc,
|
|
|
&fw_desc_len,
|
|
|
&msdu_head,
|
|
|
- &msdu_tail);
|
|
|
+ &msdu_tail,
|
|
|
+ &attention);
|
|
|
|
|
|
if (ret < 0) {
|
|
|
ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
|
|
@@ -1233,7 +1242,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|
|
rxd = container_of((void *)msdu_head->data,
|
|
|
struct htt_rx_desc,
|
|
|
msdu_payload);
|
|
|
- attention = __le32_to_cpu(rxd->attention.flags);
|
|
|
|
|
|
if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head,
|
|
|
status,
|
|
@@ -1286,6 +1294,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
|
|
u8 *fw_desc;
|
|
|
int fw_desc_len, hdrlen, paramlen;
|
|
|
int trim;
|
|
|
+ u32 attention = 0;
|
|
|
|
|
|
fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes);
|
|
|
fw_desc = (u8 *)frag->fw_msdu_rx_desc;
|
|
@@ -1295,7 +1304,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
|
|
|
|
|
spin_lock_bh(&htt->rx_ring.lock);
|
|
|
ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
|
|
|
- &msdu_head, &msdu_tail);
|
|
|
+ &msdu_head, &msdu_tail,
|
|
|
+ &attention);
|
|
|
spin_unlock_bh(&htt->rx_ring.lock);
|
|
|
|
|
|
ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
|
|
@@ -1312,10 +1322,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *)msdu_head->data;
|
|
|
rxd = (void *)msdu_head->data - sizeof(*rxd);
|
|
|
- tkip_mic_err = !!(__le32_to_cpu(rxd->attention.flags) &
|
|
|
- RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
|
|
|
- decrypt_err = !!(__le32_to_cpu(rxd->attention.flags) &
|
|
|
- RX_ATTENTION_FLAGS_DECRYPT_ERR);
|
|
|
+ tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
|
|
|
+ decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR);
|
|
|
fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
|
|
|
RX_MSDU_START_INFO1_DECAP_FORMAT);
|
|
|
|
|
@@ -1422,6 +1430,86 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
|
|
|
+{
|
|
|
+ struct htt_rx_addba *ev = &resp->rx_addba;
|
|
|
+ struct ath10k_peer *peer;
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
+ u16 info0, tid, peer_id;
|
|
|
+
|
|
|
+ info0 = __le16_to_cpu(ev->info0);
|
|
|
+ tid = MS(info0, HTT_RX_BA_INFO0_TID);
|
|
|
+ peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
|
|
|
+
|
|
|
+ ath10k_dbg(ATH10K_DBG_HTT,
|
|
|
+ "htt rx addba tid %hu peer_id %hu size %hhu\n",
|
|
|
+ tid, peer_id, ev->window_size);
|
|
|
+
|
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
|
+ peer = ath10k_peer_find_by_id(ar, peer_id);
|
|
|
+ if (!peer) {
|
|
|
+ ath10k_warn("received addba event for invalid peer_id: %hu\n",
|
|
|
+ peer_id);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ arvif = ath10k_get_arvif(ar, peer->vdev_id);
|
|
|
+ if (!arvif) {
|
|
|
+ ath10k_warn("received addba event for invalid vdev_id: %u\n",
|
|
|
+ peer->vdev_id);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ath10k_dbg(ATH10K_DBG_HTT,
|
|
|
+ "htt rx start rx ba session sta %pM tid %hu size %hhu\n",
|
|
|
+ peer->addr, tid, ev->window_size);
|
|
|
+
|
|
|
+ ieee80211_start_rx_ba_session_offl(arvif->vif, peer->addr, tid);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+}
|
|
|
+
|
|
|
+static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
|
|
|
+{
|
|
|
+ struct htt_rx_delba *ev = &resp->rx_delba;
|
|
|
+ struct ath10k_peer *peer;
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
+ u16 info0, tid, peer_id;
|
|
|
+
|
|
|
+ info0 = __le16_to_cpu(ev->info0);
|
|
|
+ tid = MS(info0, HTT_RX_BA_INFO0_TID);
|
|
|
+ peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
|
|
|
+
|
|
|
+ ath10k_dbg(ATH10K_DBG_HTT,
|
|
|
+ "htt rx delba tid %hu peer_id %hu\n",
|
|
|
+ tid, peer_id);
|
|
|
+
|
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
|
+ peer = ath10k_peer_find_by_id(ar, peer_id);
|
|
|
+ if (!peer) {
|
|
|
+ ath10k_warn("received addba event for invalid peer_id: %hu\n",
|
|
|
+ peer_id);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ arvif = ath10k_get_arvif(ar, peer->vdev_id);
|
|
|
+ if (!arvif) {
|
|
|
+ ath10k_warn("received addba event for invalid vdev_id: %u\n",
|
|
|
+ peer->vdev_id);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ath10k_dbg(ATH10K_DBG_HTT,
|
|
|
+ "htt rx stop rx ba session sta %pM tid %hu\n",
|
|
|
+ peer->addr, tid);
|
|
|
+
|
|
|
+ ieee80211_stop_rx_ba_session_offl(arvif->vif, peer->addr, tid);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+}
|
|
|
+
|
|
|
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
|
|
{
|
|
|
struct ath10k_htt *htt = &ar->htt;
|
|
@@ -1516,9 +1604,25 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
|
|
trace_ath10k_htt_stats(skb->data, skb->len);
|
|
|
break;
|
|
|
case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
|
|
|
+ /* Firmware can return tx frames if it's unable to fully
|
|
|
+ * process them and suspects host may be able to fix it. ath10k
|
|
|
+ * sends all tx frames as already inspected so this shouldn't
|
|
|
+ * happen unless fw has a bug.
|
|
|
+ */
|
|
|
+ ath10k_warn("received an unexpected htt tx inspect event\n");
|
|
|
+ break;
|
|
|
case HTT_T2H_MSG_TYPE_RX_ADDBA:
|
|
|
+ ath10k_htt_rx_addba(ar, resp);
|
|
|
+ break;
|
|
|
case HTT_T2H_MSG_TYPE_RX_DELBA:
|
|
|
- case HTT_T2H_MSG_TYPE_RX_FLUSH:
|
|
|
+ ath10k_htt_rx_delba(ar, resp);
|
|
|
+ break;
|
|
|
+ case HTT_T2H_MSG_TYPE_RX_FLUSH: {
|
|
|
+ /* Ignore this event because mac80211 takes care of Rx
|
|
|
+ * aggregation reordering.
|
|
|
+ */
|
|
|
+ break;
|
|
|
+ }
|
|
|
default:
|
|
|
ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n",
|
|
|
resp->hdr.msg_type);
|