Commit d4b98c63 authored by Ryder Lee's avatar Ryder Lee Committed by Felix Fietkau
Browse files

mt76: mt7615: 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.

Tested-by: default avatarFrank Wunderlich <frank-w@public-files.de>
Signed-off-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 2122dfbf
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -118,7 +118,8 @@ mt7615_mac_init(struct mt7615_dev *dev)

	mt76_wr(dev, MT_DMA_DCR0,
		FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072) |
		MT_DMA_DCR0_RX_VEC_DROP | MT_DMA_DCR0_DAMSDU_EN);
		MT_DMA_DCR0_RX_VEC_DROP | MT_DMA_DCR0_DAMSDU_EN |
		MT_DMA_DCR0_RX_HDR_TRANS_EN);
	/* disable TDLS filtering */
	mt76_clear(dev, MT_WF_PFCR, MT_WF_PFCR_TDLS_EN);
	mt76_set(dev, MT_WF_MIB_SCR0, MT_MIB_SCR0_AGG_CNT_RANGE_EN);
@@ -128,6 +129,7 @@ mt7615_mac_init(struct mt7615_dev *dev)
	} else {
		mt7615_init_mac_chain(dev, 1);
	}
	mt7615_mcu_set_rx_hdr_trans_blacklist(dev);
}

static void
@@ -360,6 +362,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
	ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
	ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
	ieee80211_hw_set(hw, WANT_MONITOR_VIF);
	ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);

	if (is_mt7615(&phy->dev->mt76))
		hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM;
+33 −11
Original line number Diff line number Diff line
@@ -236,10 +236,12 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
	u32 rxd2 = le32_to_cpu(rxd[2]);
	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
	__le32 rxd12 = rxd[12];
	bool unicast, remove_pad, insert_ccmp_hdr = false;
	bool unicast, hdr_trans, remove_pad, insert_ccmp_hdr = false;
	int phy_idx;
	int i, idx;
	u8 chfreq, amsdu_info;
	u8 chfreq, amsdu_info, qos_ctl = 0;
	u16 seq_ctrl = 0;
	__le16 fc = 0;

	memset(status, 0, sizeof(*status));

@@ -260,6 +262,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)

	unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
	idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
	hdr_trans = rxd1 & MT_RXD1_NORMAL_HDR_TRANS;
	status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);

	if (status->wcid) {
@@ -295,6 +298,13 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)

	rxd += 4;
	if (rxd0 & MT_RXD0_NORMAL_GROUP_4) {
		u32 v0 = le32_to_cpu(rxd[0]);
		u32 v2 = le32_to_cpu(rxd[2]);

		fc = cpu_to_le16(FIELD_GET(MT_RXD4_FRAME_CONTROL, v0));
		qos_ctl = FIELD_GET(MT_RXD6_QOS_CTL, v2);
		seq_ctrl = FIELD_GET(MT_RXD6_SEQ_CTRL, v2);

		rxd += 4;
		if ((u8 *)rxd - skb->data >= skb->len)
			return -EINVAL;
@@ -458,25 +468,37 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
	if (status->amsdu) {
		status->first_amsdu = amsdu_info == MT_RXD1_FIRST_AMSDU_FRAME;
		status->last_amsdu = amsdu_info == MT_RXD1_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 = (struct ieee80211_hdr *)skb->data;
	if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
		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_8023;
	}

	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;
}
+5 −0
Original line number Diff line number Diff line
@@ -81,6 +81,11 @@ enum rx_pkt_type {
#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS	BIT(8)
#define MT_RXD3_NORMAL_RXV_SEQ		GENMASK(7, 0)

#define MT_RXD4_FRAME_CONTROL		GENMASK(15, 0)

#define MT_RXD6_SEQ_CTRL		GENMASK(15, 0)
#define MT_RXD6_QOS_CTL			GENMASK(31, 16)

#define MT_RXV1_ACID_DET_H		BIT(31)
#define MT_RXV1_ACID_DET_L		BIT(30)
#define MT_RXV1_VHTA2_B8_B3		GENMASK(29, 24)
+17 −0
Original line number Diff line number Diff line
@@ -1087,6 +1087,22 @@ static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw,
	return 0;
}

static void mt7615_sta_set_decap_offload(struct ieee80211_hw *hw,
				 struct ieee80211_vif *vif,
				 struct ieee80211_sta *sta,
				 bool enabled)
{
	struct mt7615_dev *dev = mt7615_hw_dev(hw);
	struct mt7615_sta *msta = (struct mt7615_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);

	mt7615_mcu_sta_update_hdr_trans(dev, vif, sta);
}

#ifdef CONFIG_PM
static int mt7615_suspend(struct ieee80211_hw *hw,
			  struct cfg80211_wowlan *wowlan)
@@ -1187,6 +1203,7 @@ const struct ieee80211_ops mt7615_ops = {
	.sta_remove = mt7615_sta_remove,
	.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
	.set_key = mt7615_set_key,
	.sta_set_decap_offload = mt7615_sta_set_decap_offload,
	.ampdu_action = mt7615_ampdu_action,
	.set_rts_threshold = mt7615_set_rts_threshold,
	.wake_tx_queue = mt7615_wake_tx_queue,
+39 −0
Original line number Diff line number Diff line
@@ -1097,6 +1097,25 @@ static const struct mt7615_mcu_ops sta_update_ops = {
	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
};

int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
				    struct ieee80211_vif *vif,
				    struct ieee80211_sta *sta)
{
	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
	struct wtbl_req_hdr *wtbl_hdr;
	struct sk_buff *skb = NULL;

	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
						  WTBL_SET, NULL, &skb);
	if (IS_ERR(wtbl_hdr))
		return PTR_ERR(wtbl_hdr);

	mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, sta, NULL, wtbl_hdr);

	return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE,
				     true);
}

static int
mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
{
@@ -2500,6 +2519,26 @@ int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy)
	return ret;
}

int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev)
{
	struct {
		u8 operation;
		u8 count;
		u8 _rsv[2];
		u8 index;
		u8 enable;
		__le16 etype;
	} req = {
		.operation = 1,
		.count = 1,
		.enable = 1,
		.etype = cpu_to_le16(ETH_P_PAE),
	};

	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS,
				 &req, sizeof(req), false);
}

int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
			  bool enable)
{
Loading