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

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
...@@ -197,6 +197,7 @@ enum mt76_wcid_flags { ...@@ -197,6 +197,7 @@ enum mt76_wcid_flags {
MT_WCID_FLAG_CHECK_PS, MT_WCID_FLAG_CHECK_PS,
MT_WCID_FLAG_PS, MT_WCID_FLAG_PS,
MT_WCID_FLAG_4ADDR, MT_WCID_FLAG_4ADDR,
MT_WCID_FLAG_HDR_TRANS,
}; };
#define MT76_N_WCIDS 288 #define MT76_N_WCIDS 288
......
...@@ -109,6 +109,7 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) ...@@ -109,6 +109,7 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, WANT_MONITOR_VIF);
hw->max_tx_fragments = 4; hw->max_tx_fragments = 4;
......
...@@ -325,6 +325,10 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) ...@@ -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; u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
bool unicast, insert_ccmp_hdr = false; bool unicast, insert_ccmp_hdr = false;
u8 remove_pad, amsdu_info; u8 remove_pad, amsdu_info;
bool hdr_trans;
u16 seq_ctrl = 0;
u8 qos_ctl = 0;
__le16 fc = 0;
int i, idx; int i, idx;
memset(status, 0, sizeof(*status)); memset(status, 0, sizeof(*status));
...@@ -346,6 +350,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) ...@@ -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; unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); 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); status->wcid = mt7915_rx_get_wcid(dev, idx, unicast);
if (status->wcid) { if (status->wcid) {
...@@ -404,6 +409,13 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) ...@@ -404,6 +409,13 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
rxd += 6; rxd += 6;
if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { 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; rxd += 4;
if ((u8 *)rxd - skb->data >= skb->len) if ((u8 *)rxd - skb->data >= skb->len)
return -EINVAL; return -EINVAL;
...@@ -555,28 +567,42 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) ...@@ -555,28 +567,42 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
if (status->amsdu) { if (status->amsdu) {
status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
memmove(skb->data + 2, skb->data, if (!hdr_trans) {
ieee80211_get_hdrlen_from_skb(skb)); memmove(skb->data + 2, skb->data,
skb_pull(skb, 2); 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); u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
mt76_insert_ccmp_hdr(skb, key_id); 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) if (rxv && status->flag & RX_FLAG_RADIOTAP_HE)
mt7915_mac_decode_he_radiotap(skb, status, rxv, mode); mt7915_mac_decode_he_radiotap(skb, status, rxv, mode);
hdr = mt76_skb_get_hdr(skb); if (!status->wcid || !ieee80211_is_data_qos(fc))
if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
return 0; return 0;
status->aggr = unicast && status->aggr = unicast &&
!ieee80211_is_qos_nullfunc(hdr->frame_control); !ieee80211_is_qos_nullfunc(fc);
status->qos_ctl = *ieee80211_get_qos_ctl(hdr); status->qos_ctl = qos_ctl;
status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
return 0; return 0;
} }
......
...@@ -101,6 +101,17 @@ enum rx_pkt_type { ...@@ -101,6 +101,17 @@ enum rx_pkt_type {
#define MT_RXV_HDR_BAND_IDX BIT(24) #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 */ /* P-RXV */
#define MT_PRXV_TX_RATE GENMASK(6, 0) #define MT_PRXV_TX_RATE GENMASK(6, 0)
#define MT_PRXV_TX_DCM BIT(4) #define MT_PRXV_TX_DCM BIT(4)
......
...@@ -34,14 +34,14 @@ static int mt7915_start(struct ieee80211_hw *hw) ...@@ -34,14 +34,14 @@ static int mt7915_start(struct ieee80211_hw *hw)
if (!running) { if (!running) {
mt7915_mcu_set_pm(dev, 0, 0); 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_mcu_set_scs(dev, 0, true);
mt7915_mac_enable_nf(dev, 0); mt7915_mac_enable_nf(dev, 0);
} }
if (phy != &dev->phy) { if (phy != &dev->phy) {
mt7915_mcu_set_pm(dev, 1, 0); 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_mcu_set_scs(dev, 1, true);
mt7915_mac_enable_nf(dev, 1); mt7915_mac_enable_nf(dev, 1);
} }
...@@ -888,6 +888,22 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw, ...@@ -888,6 +888,22 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
mt7915_mcu_sta_update_hdr_trans(dev, vif, sta); 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 = { const struct ieee80211_ops mt7915_ops = {
.tx = mt7915_tx, .tx = mt7915_tx,
.start = mt7915_start, .start = mt7915_start,
...@@ -920,6 +936,7 @@ const struct ieee80211_ops mt7915_ops = { ...@@ -920,6 +936,7 @@ const struct ieee80211_ops mt7915_ops = {
.set_coverage_class = mt7915_set_coverage_class, .set_coverage_class = mt7915_set_coverage_class,
.sta_statistics = mt7915_sta_statistics, .sta_statistics = mt7915_sta_statistics,
.sta_set_4addr = mt7915_sta_set_4addr, .sta_set_4addr = mt7915_sta_set_4addr,
.sta_set_decap_offload = mt7915_sta_set_decap_offload,
CFG80211_TESTMODE_CMD(mt76_testmode_cmd) CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
CFG80211_TESTMODE_DUMP(mt76_testmode_dump) CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
......
...@@ -1685,6 +1685,7 @@ mt7915_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, ...@@ -1685,6 +1685,7 @@ mt7915_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
return; return;
msta = (struct mt7915_sta *)sta->drv_priv; msta = (struct mt7915_sta *)sta->drv_priv;
htr->no_rx_trans = !test_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags)) { if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags)) {
htr->to_ds = true; htr->to_ds = true;
htr->from_ds = true; htr->from_ds = true;
...@@ -2869,6 +2870,27 @@ void mt7915_mcu_exit(struct mt7915_dev *dev) ...@@ -2869,6 +2870,27 @@ void mt7915_mcu_exit(struct mt7915_dev *dev)
skb_queue_purge(&dev->mt76.mcu.res_q); skb_queue_purge(&dev->mt76.mcu.res_q);
} }
static int
mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev *dev, int band)
{
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 mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band,
bool enable, bool hdr_trans) bool enable, bool hdr_trans)
{ {
...@@ -2899,6 +2921,9 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, ...@@ -2899,6 +2921,9 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band,
if (ret) if (ret)
return ret; return ret;
if (hdr_trans)
mt7915_mcu_set_rx_hdr_trans_blacklist(dev, band);
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL), return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL),
&req_mac, sizeof(req_mac), true); &req_mac, sizeof(req_mac), true);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment