Commit 90e3abf0 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

mt76: mt7915: add support for rx decapsulation offload



For AP and Client mode, the hardware can pass received packets as 802.3 frames
that can be passed to the network stack as-is.

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 94244d2e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -197,6 +197,7 @@ enum mt76_wcid_flags {
	MT_WCID_FLAG_CHECK_PS,
	MT_WCID_FLAG_PS,
	MT_WCID_FLAG_4ADDR,
	MT_WCID_FLAG_HDR_TRANS,
};

#define MT76_N_WCIDS 288
+1 −0
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)

	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
	ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
	ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
	ieee80211_hw_set(hw, WANT_MONITOR_VIF);

	hw->max_tx_fragments = 4;
+35 −9
Original line number Diff line number Diff line
@@ -325,6 +325,10 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
	bool unicast, insert_ccmp_hdr = false;
	u8 remove_pad, amsdu_info;
	bool hdr_trans;
	u16 seq_ctrl = 0;
	u8 qos_ctl = 0;
	__le16 fc = 0;
	int i, idx;

	memset(status, 0, sizeof(*status));
@@ -346,6 +350,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)

	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
	hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
	status->wcid = mt7915_rx_get_wcid(dev, idx, unicast);

	if (status->wcid) {
@@ -404,6 +409,13 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)

	rxd += 6;
	if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
		u32 v0 = le32_to_cpu(rxd[0]);
		u32 v2 = le32_to_cpu(rxd[2]);

		fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0));
		qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2);
		seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2);

		rxd += 4;
		if ((u8 *)rxd - skb->data >= skb->len)
			return -EINVAL;
@@ -555,28 +567,42 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
	if (status->amsdu) {
		status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
		status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
		if (!hdr_trans) {
			memmove(skb->data + 2, skb->data,
				ieee80211_get_hdrlen_from_skb(skb));
			skb_pull(skb, 2);
		}
	}

	if (insert_ccmp_hdr) {
	if (insert_ccmp_hdr && !hdr_trans) {
		u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);

		mt76_insert_ccmp_hdr(skb, key_id);
	}

	if (!hdr_trans) {
		hdr = mt76_skb_get_hdr(skb);
		fc = hdr->frame_control;
		if (ieee80211_is_data_qos(fc)) {
			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
			qos_ctl = *ieee80211_get_qos_ctl(hdr);
		}
	} else {
		status->flag &= ~(RX_FLAG_RADIOTAP_HE |
				  RX_FLAG_RADIOTAP_HE_MU);
		status->flag |= RX_FLAG_8023;
	}

	if (rxv && status->flag & RX_FLAG_RADIOTAP_HE)
		mt7915_mac_decode_he_radiotap(skb, status, rxv, mode);

	hdr = mt76_skb_get_hdr(skb);
	if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
	if (!status->wcid || !ieee80211_is_data_qos(fc))
		return 0;

	status->aggr = unicast &&
		       !ieee80211_is_qos_nullfunc(hdr->frame_control);
	status->qos_ctl = *ieee80211_get_qos_ctl(hdr);
	status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
		       !ieee80211_is_qos_nullfunc(fc);
	status->qos_ctl = qos_ctl;
	status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);

	return 0;
}
+11 −0
Original line number Diff line number Diff line
@@ -101,6 +101,17 @@ enum rx_pkt_type {

#define MT_RXV_HDR_BAND_IDX		BIT(24)

/* RXD GROUP4 */
#define MT_RXD6_FRAME_CONTROL		GENMASK(15, 0)
#define MT_RXD6_TA_LO			GENMASK(31, 16)

#define MT_RXD7_TA_HI			GENMASK(31, 0)

#define MT_RXD8_SEQ_CTRL		GENMASK(15, 0)
#define MT_RXD8_QOS_CTL			GENMASK(31, 16)

#define MT_RXD9_HT_CONTROL		GENMASK(31, 0)

/* P-RXV */
#define MT_PRXV_TX_RATE			GENMASK(6, 0)
#define MT_PRXV_TX_DCM			BIT(4)
+19 −2
Original line number Diff line number Diff line
@@ -34,14 +34,14 @@ static int mt7915_start(struct ieee80211_hw *hw)

	if (!running) {
		mt7915_mcu_set_pm(dev, 0, 0);
		mt7915_mcu_set_mac(dev, 0, true, false);
		mt7915_mcu_set_mac(dev, 0, true, true);
		mt7915_mcu_set_scs(dev, 0, true);
		mt7915_mac_enable_nf(dev, 0);
	}

	if (phy != &dev->phy) {
		mt7915_mcu_set_pm(dev, 1, 0);
		mt7915_mcu_set_mac(dev, 1, true, false);
		mt7915_mcu_set_mac(dev, 1, true, true);
		mt7915_mcu_set_scs(dev, 1, true);
		mt7915_mac_enable_nf(dev, 1);
	}
@@ -888,6 +888,22 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
	mt7915_mcu_sta_update_hdr_trans(dev, vif, sta);
}

static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw,
				 struct ieee80211_vif *vif,
				 struct ieee80211_sta *sta,
				 bool enabled)
{
	struct mt7915_dev *dev = mt7915_hw_dev(hw);
	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;

	if (enabled)
		set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
	else
		clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);

	mt7915_mcu_sta_update_hdr_trans(dev, vif, sta);
}

const struct ieee80211_ops mt7915_ops = {
	.tx = mt7915_tx,
	.start = mt7915_start,
@@ -920,6 +936,7 @@ const struct ieee80211_ops mt7915_ops = {
	.set_coverage_class = mt7915_set_coverage_class,
	.sta_statistics = mt7915_sta_statistics,
	.sta_set_4addr = mt7915_sta_set_4addr,
	.sta_set_decap_offload = mt7915_sta_set_decap_offload,
	CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
	CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
#ifdef CONFIG_MAC80211_DEBUGFS
Loading