11c099ab4SSean Wang // SPDX-License-Identifier: ISC
21c099ab4SSean Wang /* Copyright (C) 2020 MediaTek Inc. */
31c099ab4SSean Wang
41c099ab4SSean Wang #include <linux/fs.h>
523bdc5d8SMing Yen Hsieh #include <linux/firmware.h>
61c099ab4SSean Wang #include "mt7921.h"
71c099ab4SSean Wang #include "mcu.h"
8140efef3SLorenzo Bianconi #include "../mt76_connac2_mac.h"
9c74df1c0SLorenzo Bianconi #include "../mt792x_trace.h"
101c099ab4SSean Wang
111c099ab4SSean Wang #define MT_STA_BFER BIT(0)
121c099ab4SSean Wang #define MT_STA_BFEE BIT(1)
131c099ab4SSean Wang
1423bdc5d8SMing Yen Hsieh static bool mt7921_disable_clc;
1523bdc5d8SMing Yen Hsieh module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
1623bdc5d8SMing Yen Hsieh MODULE_PARM_DESC(disable_clc, "disable CLC support");
1723bdc5d8SMing Yen Hsieh
mt7921_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)18dfc7743dSSean Wang int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
191c099ab4SSean Wang struct sk_buff *skb, int seq)
201c099ab4SSean Wang {
21680a2eadSLorenzo Bianconi int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
22fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
231c099ab4SSean Wang int ret = 0;
241c099ab4SSean Wang
251c099ab4SSean Wang if (!skb) {
2653d35b1aSLorenzo Bianconi dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
271c099ab4SSean Wang cmd, seq);
28311f121cSLorenzo Bianconi mt792x_reset(mdev);
29d43b3257SLorenzo Bianconi
301c099ab4SSean Wang return -ETIMEDOUT;
311c099ab4SSean Wang }
321c099ab4SSean Wang
33fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
341c099ab4SSean Wang if (seq != rxd->seq)
351c099ab4SSean Wang return -EAGAIN;
361c099ab4SSean Wang
3745b6f9cbSYN Chen if (cmd == MCU_CMD(PATCH_SEM_CONTROL) ||
3845b6f9cbSYN Chen cmd == MCU_CMD(PATCH_FINISH_REQ)) {
391c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) - 4);
401c099ab4SSean Wang ret = *skb->data;
419d8d136cSLorenzo Bianconi } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
421c099ab4SSean Wang skb_pull(skb, sizeof(*rxd) + 4);
431c099ab4SSean Wang ret = le32_to_cpu(*(__le32 *)skb->data);
4454722402SLorenzo Bianconi } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
4554722402SLorenzo Bianconi cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
4654722402SLorenzo Bianconi cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
4754722402SLorenzo Bianconi cmd == MCU_UNI_CMD(HIF_CTRL) ||
4854722402SLorenzo Bianconi cmd == MCU_UNI_CMD(OFFLOAD) ||
4954722402SLorenzo Bianconi cmd == MCU_UNI_CMD(SUSPEND)) {
5061d1f545SLorenzo Bianconi struct mt76_connac_mcu_uni_event *event;
511c099ab4SSean Wang
521c099ab4SSean Wang skb_pull(skb, sizeof(*rxd));
5361d1f545SLorenzo Bianconi event = (struct mt76_connac_mcu_uni_event *)skb->data;
541c099ab4SSean Wang ret = le32_to_cpu(event->status);
55cd3f3873SDeren Wu /* skip invalid event */
56cd3f3873SDeren Wu if (mcu_cmd != event->cid)
57cd3f3873SDeren Wu ret = -EAGAIN;
58680a2eadSLorenzo Bianconi } else if (cmd == MCU_CE_QUERY(REG_READ)) {
5961d1f545SLorenzo Bianconi struct mt76_connac_mcu_reg_event *event;
601c099ab4SSean Wang
611c099ab4SSean Wang skb_pull(skb, sizeof(*rxd));
6261d1f545SLorenzo Bianconi event = (struct mt76_connac_mcu_reg_event *)skb->data;
631c099ab4SSean Wang ret = (int)le32_to_cpu(event->val);
64e6d2070dSLorenzo Bianconi } else {
65fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
661c099ab4SSean Wang }
671c099ab4SSean Wang
681c099ab4SSean Wang return ret;
691c099ab4SSean Wang }
708910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response);
711c099ab4SSean Wang
mt7921_mcu_read_eeprom(struct mt792x_dev * dev,u32 offset,u8 * val)72975e122dSLorenzo Bianconi static int mt7921_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)
7323bdc5d8SMing Yen Hsieh {
7423bdc5d8SMing Yen Hsieh struct mt7921_mcu_eeprom_info *res, req = {
7523bdc5d8SMing Yen Hsieh .addr = cpu_to_le32(round_down(offset,
7623bdc5d8SMing Yen Hsieh MT7921_EEPROM_BLOCK_SIZE)),
7723bdc5d8SMing Yen Hsieh };
7823bdc5d8SMing Yen Hsieh struct sk_buff *skb;
7923bdc5d8SMing Yen Hsieh int ret;
8023bdc5d8SMing Yen Hsieh
8123bdc5d8SMing Yen Hsieh ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS),
8223bdc5d8SMing Yen Hsieh &req, sizeof(req), true, &skb);
8323bdc5d8SMing Yen Hsieh if (ret)
8423bdc5d8SMing Yen Hsieh return ret;
8523bdc5d8SMing Yen Hsieh
8623bdc5d8SMing Yen Hsieh res = (struct mt7921_mcu_eeprom_info *)skb->data;
8723bdc5d8SMing Yen Hsieh *val = res->data[offset % MT7921_EEPROM_BLOCK_SIZE];
8823bdc5d8SMing Yen Hsieh dev_kfree_skb(skb);
8923bdc5d8SMing Yen Hsieh
9023bdc5d8SMing Yen Hsieh return 0;
9123bdc5d8SMing Yen Hsieh }
9223bdc5d8SMing Yen Hsieh
935fc201aaSDeren Wu #ifdef CONFIG_PM
945fc201aaSDeren Wu
955fc201aaSDeren Wu static int
mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev * dev,struct ieee80211_vif * vif,bool suspend)965fc201aaSDeren Wu mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev *dev,
975fc201aaSDeren Wu struct ieee80211_vif *vif, bool suspend)
985fc201aaSDeren Wu {
9915ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
1005fc201aaSDeren Wu struct {
1015fc201aaSDeren Wu struct {
1025fc201aaSDeren Wu u8 bss_idx;
1035fc201aaSDeren Wu u8 pad[3];
1045fc201aaSDeren Wu } __packed hdr;
1055fc201aaSDeren Wu struct mt76_connac_arpns_tlv arpns;
1065fc201aaSDeren Wu } req = {
1075fc201aaSDeren Wu .hdr = {
1085fc201aaSDeren Wu .bss_idx = mvif->mt76.idx,
1095fc201aaSDeren Wu },
1105fc201aaSDeren Wu .arpns = {
1115fc201aaSDeren Wu .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND),
1125fc201aaSDeren Wu .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),
1135fc201aaSDeren Wu .mode = suspend,
1145fc201aaSDeren Wu },
1155fc201aaSDeren Wu };
1165fc201aaSDeren Wu
1175fc201aaSDeren Wu return mt76_mcu_send_msg(dev, MCU_UNI_CMD_OFFLOAD, &req, sizeof(req),
1185fc201aaSDeren Wu true);
1195fc201aaSDeren Wu }
1205fc201aaSDeren Wu
mt7921_mcu_set_suspend_iter(void * priv,u8 * mac,struct ieee80211_vif * vif)1215fc201aaSDeren Wu void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
1225fc201aaSDeren Wu {
1235fc201aaSDeren Wu if (IS_ENABLED(CONFIG_IPV6)) {
1245fc201aaSDeren Wu struct mt76_phy *phy = priv;
1255fc201aaSDeren Wu
1265fc201aaSDeren Wu mt7921_mcu_set_ipv6_ns_filter(phy->dev, vif,
1275fc201aaSDeren Wu !test_bit(MT76_STATE_RUNNING,
1285fc201aaSDeren Wu &phy->state));
1295fc201aaSDeren Wu }
1305fc201aaSDeren Wu
1315fc201aaSDeren Wu mt76_connac_mcu_set_suspend_iter(priv, mac, vif);
1325fc201aaSDeren Wu }
1335fc201aaSDeren Wu
1345fc201aaSDeren Wu #endif /* CONFIG_PM */
1355fc201aaSDeren Wu
1361c099ab4SSean Wang static void
mt7921_mcu_uni_roc_event(struct mt792x_dev * dev,struct sk_buff * skb)137975e122dSLorenzo Bianconi mt7921_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb)
138034ae28bSSean Wang {
139034ae28bSSean Wang struct mt7921_roc_grant_tlv *grant;
140034ae28bSSean Wang struct mt76_connac2_mcu_rxd *rxd;
141034ae28bSSean Wang int duration;
142034ae28bSSean Wang
143034ae28bSSean Wang rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
144034ae28bSSean Wang grant = (struct mt7921_roc_grant_tlv *)(rxd->tlv + 4);
145034ae28bSSean Wang
146034ae28bSSean Wang /* should never happen */
147034ae28bSSean Wang WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT));
148034ae28bSSean Wang
149034ae28bSSean Wang if (grant->reqtype == MT7921_ROC_REQ_ROC)
150034ae28bSSean Wang ieee80211_ready_on_channel(dev->mt76.phy.hw);
151034ae28bSSean Wang
152034ae28bSSean Wang dev->phy.roc_grant = true;
153034ae28bSSean Wang wake_up(&dev->phy.roc_wait);
154034ae28bSSean Wang duration = le32_to_cpu(grant->max_interval);
155034ae28bSSean Wang mod_timer(&dev->phy.roc_timer,
156c36457a8SDeren Wu jiffies + msecs_to_jiffies(duration));
157034ae28bSSean Wang }
158034ae28bSSean Wang
159034ae28bSSean Wang static void
mt7921_mcu_scan_event(struct mt792x_dev * dev,struct sk_buff * skb)160975e122dSLorenzo Bianconi mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb)
1611c099ab4SSean Wang {
1621c099ab4SSean Wang struct mt76_phy *mphy = &dev->mt76.phy;
16378562b2cSLorenzo Bianconi struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv;
1641c099ab4SSean Wang
1651c099ab4SSean Wang spin_lock_bh(&dev->mt76.lock);
1661c099ab4SSean Wang __skb_queue_tail(&phy->scan_event_list, skb);
1671c099ab4SSean Wang spin_unlock_bh(&dev->mt76.lock);
1681c099ab4SSean Wang
1691c099ab4SSean Wang ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
1707d403f3aSLorenzo Bianconi MT792x_HW_SCAN_TIMEOUT);
1711c099ab4SSean Wang }
1721c099ab4SSean Wang
1731c099ab4SSean Wang static void
mt7921_mcu_connection_loss_iter(void * priv,u8 * mac,struct ieee80211_vif * vif)17410de032aSSean Wang mt7921_mcu_connection_loss_iter(void *priv, u8 *mac,
17510de032aSSean Wang struct ieee80211_vif *vif)
17610de032aSSean Wang {
17710de032aSSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
17810de032aSSean Wang struct mt76_connac_beacon_loss_event *event = priv;
17910de032aSSean Wang
18010de032aSSean Wang if (mvif->idx != event->bss_idx)
18110de032aSSean Wang return;
18210de032aSSean Wang
183116c6960SSean Wang if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) ||
184116c6960SSean Wang vif->type != NL80211_IFTYPE_STATION)
18510de032aSSean Wang return;
18610de032aSSean Wang
18710de032aSSean Wang ieee80211_connection_loss(vif);
18810de032aSSean Wang }
18910de032aSSean Wang
19010de032aSSean Wang static void
mt7921_mcu_connection_loss_event(struct mt792x_dev * dev,struct sk_buff * skb)191975e122dSLorenzo Bianconi mt7921_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb)
192b88f5c64SSean Wang {
19367aa2743SLorenzo Bianconi struct mt76_connac_beacon_loss_event *event;
19410de032aSSean Wang struct mt76_phy *mphy = &dev->mt76.phy;
195b88f5c64SSean Wang
196fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
19767aa2743SLorenzo Bianconi event = (struct mt76_connac_beacon_loss_event *)skb->data;
198b88f5c64SSean Wang
199b88f5c64SSean Wang ieee80211_iterate_active_interfaces_atomic(mphy->hw,
200b88f5c64SSean Wang IEEE80211_IFACE_ITER_RESUME_ALL,
20110de032aSSean Wang mt7921_mcu_connection_loss_iter, event);
202b88f5c64SSean Wang }
203b88f5c64SSean Wang
204b88f5c64SSean Wang static void
mt7921_mcu_debug_msg_event(struct mt792x_dev * dev,struct sk_buff * skb)205975e122dSLorenzo Bianconi mt7921_mcu_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
2061c099ab4SSean Wang {
207c7cc5ec5SLorenzo Bianconi struct mt7921_debug_msg {
2081c099ab4SSean Wang __le16 id;
2091c099ab4SSean Wang u8 type;
2101c099ab4SSean Wang u8 flag;
2111c099ab4SSean Wang __le32 value;
2121c099ab4SSean Wang __le16 len;
2131c099ab4SSean Wang u8 content[512];
214c7cc5ec5SLorenzo Bianconi } __packed * msg;
215c7cc5ec5SLorenzo Bianconi
216fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
217c7cc5ec5SLorenzo Bianconi msg = (struct mt7921_debug_msg *)skb->data;
218c7cc5ec5SLorenzo Bianconi
219c7cc5ec5SLorenzo Bianconi if (msg->type == 3) { /* fw log */
220c7cc5ec5SLorenzo Bianconi u16 len = min_t(u16, le16_to_cpu(msg->len), 512);
2211c099ab4SSean Wang int i;
2221c099ab4SSean Wang
223c7cc5ec5SLorenzo Bianconi for (i = 0 ; i < len; i++) {
224c7cc5ec5SLorenzo Bianconi if (!msg->content[i])
225c7cc5ec5SLorenzo Bianconi msg->content[i] = ' ';
226c7cc5ec5SLorenzo Bianconi }
2272bf301bcSDan Carpenter wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content);
2281c099ab4SSean Wang }
2291c099ab4SSean Wang }
2301c099ab4SSean Wang
2311c099ab4SSean Wang static void
mt7921_mcu_low_power_event(struct mt792x_dev * dev,struct sk_buff * skb)232975e122dSLorenzo Bianconi mt7921_mcu_low_power_event(struct mt792x_dev *dev, struct sk_buff *skb)
2332afd17b4SLorenzo Bianconi {
2342afd17b4SLorenzo Bianconi struct mt7921_mcu_lp_event {
2352afd17b4SLorenzo Bianconi u8 state;
2362afd17b4SLorenzo Bianconi u8 reserved[3];
2372afd17b4SLorenzo Bianconi } __packed * event;
2382afd17b4SLorenzo Bianconi
239fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
2402afd17b4SLorenzo Bianconi event = (struct mt7921_mcu_lp_event *)skb->data;
2412afd17b4SLorenzo Bianconi
2422afd17b4SLorenzo Bianconi trace_lp_event(dev, event->state);
2432afd17b4SLorenzo Bianconi }
2442afd17b4SLorenzo Bianconi
2452afd17b4SLorenzo Bianconi static void
mt7921_mcu_tx_done_event(struct mt792x_dev * dev,struct sk_buff * skb)246975e122dSLorenzo Bianconi mt7921_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb)
247e0bf699aSDeren Wu {
248e0bf699aSDeren Wu struct mt7921_mcu_tx_done_event *event;
249e0bf699aSDeren Wu
250fc6ee71aSLorenzo Bianconi skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
251e0bf699aSDeren Wu event = (struct mt7921_mcu_tx_done_event *)skb->data;
252e0bf699aSDeren Wu
253e0bf699aSDeren Wu mt7921_mac_add_txs(dev, event->txs);
254e0bf699aSDeren Wu }
255e0bf699aSDeren Wu
256e0bf699aSDeren Wu static void
mt7921_mcu_rx_unsolicited_event(struct mt792x_dev * dev,struct sk_buff * skb)257975e122dSLorenzo Bianconi mt7921_mcu_rx_unsolicited_event(struct mt792x_dev *dev, struct sk_buff *skb)
2581c099ab4SSean Wang {
259fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
2601c099ab4SSean Wang
261fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
2621c099ab4SSean Wang switch (rxd->eid) {
2631c099ab4SSean Wang case MCU_EVENT_BSS_BEACON_LOSS:
26410de032aSSean Wang mt7921_mcu_connection_loss_event(dev, skb);
2651c099ab4SSean Wang break;
2661c099ab4SSean Wang case MCU_EVENT_SCHED_SCAN_DONE:
2671c099ab4SSean Wang case MCU_EVENT_SCAN_DONE:
2681c099ab4SSean Wang mt7921_mcu_scan_event(dev, skb);
2691c099ab4SSean Wang return;
2701c099ab4SSean Wang case MCU_EVENT_DBG_MSG:
2711c099ab4SSean Wang mt7921_mcu_debug_msg_event(dev, skb);
2721c099ab4SSean Wang break;
2730da3c795SSean Wang case MCU_EVENT_COREDUMP:
274ca74b9b9SSean Wang dev->fw_assert = true;
2750da3c795SSean Wang mt76_connac_mcu_coredump_event(&dev->mt76, skb,
2760da3c795SSean Wang &dev->coredump);
2770da3c795SSean Wang return;
2782afd17b4SLorenzo Bianconi case MCU_EVENT_LP_INFO:
2792afd17b4SLorenzo Bianconi mt7921_mcu_low_power_event(dev, skb);
2802afd17b4SLorenzo Bianconi break;
281e0bf699aSDeren Wu case MCU_EVENT_TX_DONE:
282e0bf699aSDeren Wu mt7921_mcu_tx_done_event(dev, skb);
283e0bf699aSDeren Wu break;
2841c099ab4SSean Wang default:
2851c099ab4SSean Wang break;
2861c099ab4SSean Wang }
2871c099ab4SSean Wang dev_kfree_skb(skb);
2881c099ab4SSean Wang }
2891c099ab4SSean Wang
2905b55b6daSQuan Zhou static void
mt7921_mcu_uni_rx_unsolicited_event(struct mt792x_dev * dev,struct sk_buff * skb)291975e122dSLorenzo Bianconi mt7921_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
2925b55b6daSQuan Zhou struct sk_buff *skb)
2935b55b6daSQuan Zhou {
2945b55b6daSQuan Zhou struct mt76_connac2_mcu_rxd *rxd;
2955b55b6daSQuan Zhou
2965b55b6daSQuan Zhou rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
2975b55b6daSQuan Zhou
2985b55b6daSQuan Zhou switch (rxd->eid) {
2995b55b6daSQuan Zhou case MCU_UNI_EVENT_ROC:
300034ae28bSSean Wang mt7921_mcu_uni_roc_event(dev, skb);
3015b55b6daSQuan Zhou break;
3025b55b6daSQuan Zhou default:
3035b55b6daSQuan Zhou break;
3045b55b6daSQuan Zhou }
3055b55b6daSQuan Zhou dev_kfree_skb(skb);
3065b55b6daSQuan Zhou }
3075b55b6daSQuan Zhou
mt7921_mcu_rx_event(struct mt792x_dev * dev,struct sk_buff * skb)308975e122dSLorenzo Bianconi void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb)
3091c099ab4SSean Wang {
310fc6ee71aSLorenzo Bianconi struct mt76_connac2_mcu_rxd *rxd;
311f0ff5d3aSSean Wang
312f0ff5d3aSSean Wang if (skb_linearize(skb))
313f0ff5d3aSSean Wang return;
314f0ff5d3aSSean Wang
315fc6ee71aSLorenzo Bianconi rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
3161c099ab4SSean Wang
3175b55b6daSQuan Zhou if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) {
3185b55b6daSQuan Zhou mt7921_mcu_uni_rx_unsolicited_event(dev, skb);
3195b55b6daSQuan Zhou return;
3205b55b6daSQuan Zhou }
3215b55b6daSQuan Zhou
3221c099ab4SSean Wang if (rxd->eid == 0x6) {
3231c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb);
3241c099ab4SSean Wang return;
3251c099ab4SSean Wang }
3261c099ab4SSean Wang
3271c099ab4SSean Wang if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT ||
3281c099ab4SSean Wang rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
3291c099ab4SSean Wang rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
3301c099ab4SSean Wang rxd->eid == MCU_EVENT_SCAN_DONE ||
3313cce2b98SDeren Wu rxd->eid == MCU_EVENT_TX_DONE ||
3321c099ab4SSean Wang rxd->eid == MCU_EVENT_DBG_MSG ||
3330da3c795SSean Wang rxd->eid == MCU_EVENT_COREDUMP ||
3342afd17b4SLorenzo Bianconi rxd->eid == MCU_EVENT_LP_INFO ||
3351c099ab4SSean Wang !rxd->seq)
3361c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(dev, skb);
3371c099ab4SSean Wang else
3381c099ab4SSean Wang mt76_mcu_rx_event(&dev->mt76, skb);
3391c099ab4SSean Wang }
3401c099ab4SSean Wang
3411c099ab4SSean Wang /** starec & wtbl **/
mt7921_mcu_uni_tx_ba(struct mt792x_dev * dev,struct ieee80211_ampdu_params * params,bool enable)342975e122dSLorenzo Bianconi int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev,
3431c099ab4SSean Wang struct ieee80211_ampdu_params *params,
3441c099ab4SSean Wang bool enable)
3451c099ab4SSean Wang {
346b7bfad2cSLorenzo Bianconi struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
34767aa2743SLorenzo Bianconi
34867aa2743SLorenzo Bianconi if (enable && !params->amsdu)
34967aa2743SLorenzo Bianconi msta->wcid.amsdu = false;
35067aa2743SLorenzo Bianconi
35167aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params,
352b5322e44SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE),
35367aa2743SLorenzo Bianconi enable, true);
3541c099ab4SSean Wang }
3551c099ab4SSean Wang
mt7921_mcu_uni_rx_ba(struct mt792x_dev * dev,struct ieee80211_ampdu_params * params,bool enable)356975e122dSLorenzo Bianconi int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev,
3571c099ab4SSean Wang struct ieee80211_ampdu_params *params,
3581c099ab4SSean Wang bool enable)
3591c099ab4SSean Wang {
360b7bfad2cSLorenzo Bianconi struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
3611c099ab4SSean Wang
36267aa2743SLorenzo Bianconi return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params,
363b5322e44SLorenzo Bianconi MCU_UNI_CMD(STA_REC_UPDATE),
36467aa2743SLorenzo Bianconi enable, false);
3651c099ab4SSean Wang }
3661c099ab4SSean Wang
mt7921_load_clc(struct mt792x_dev * dev,const char * fw_name)367975e122dSLorenzo Bianconi static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
36823bdc5d8SMing Yen Hsieh {
36923bdc5d8SMing Yen Hsieh const struct mt76_connac2_fw_trailer *hdr;
37023bdc5d8SMing Yen Hsieh const struct mt76_connac2_fw_region *region;
37123bdc5d8SMing Yen Hsieh const struct mt7921_clc *clc;
37223bdc5d8SMing Yen Hsieh struct mt76_dev *mdev = &dev->mt76;
37378562b2cSLorenzo Bianconi struct mt792x_phy *phy = &dev->phy;
37423bdc5d8SMing Yen Hsieh const struct firmware *fw;
37523bdc5d8SMing Yen Hsieh int ret, i, len, offset = 0;
37623bdc5d8SMing Yen Hsieh u8 *clc_base = NULL, hw_encap = 0;
37723bdc5d8SMing Yen Hsieh
37823bdc5d8SMing Yen Hsieh if (mt7921_disable_clc ||
37923bdc5d8SMing Yen Hsieh mt76_is_usb(&dev->mt76))
38023bdc5d8SMing Yen Hsieh return 0;
38123bdc5d8SMing Yen Hsieh
38223bdc5d8SMing Yen Hsieh if (mt76_is_mmio(&dev->mt76)) {
38323bdc5d8SMing Yen Hsieh ret = mt7921_mcu_read_eeprom(dev, MT_EE_HW_TYPE, &hw_encap);
38423bdc5d8SMing Yen Hsieh if (ret)
38523bdc5d8SMing Yen Hsieh return ret;
38623bdc5d8SMing Yen Hsieh hw_encap = u8_get_bits(hw_encap, MT_EE_HW_TYPE_ENCAP);
38723bdc5d8SMing Yen Hsieh }
38823bdc5d8SMing Yen Hsieh
38923bdc5d8SMing Yen Hsieh ret = request_firmware(&fw, fw_name, mdev->dev);
39023bdc5d8SMing Yen Hsieh if (ret)
39123bdc5d8SMing Yen Hsieh return ret;
39223bdc5d8SMing Yen Hsieh
39323bdc5d8SMing Yen Hsieh if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
39423bdc5d8SMing Yen Hsieh dev_err(mdev->dev, "Invalid firmware\n");
39523bdc5d8SMing Yen Hsieh ret = -EINVAL;
39623bdc5d8SMing Yen Hsieh goto out;
39723bdc5d8SMing Yen Hsieh }
39823bdc5d8SMing Yen Hsieh
39923bdc5d8SMing Yen Hsieh hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
40023bdc5d8SMing Yen Hsieh for (i = 0; i < hdr->n_region; i++) {
40123bdc5d8SMing Yen Hsieh region = (const void *)((const u8 *)hdr -
40223bdc5d8SMing Yen Hsieh (hdr->n_region - i) * sizeof(*region));
40323bdc5d8SMing Yen Hsieh len = le32_to_cpu(region->len);
40423bdc5d8SMing Yen Hsieh
40523bdc5d8SMing Yen Hsieh /* check if we have valid buffer size */
40623bdc5d8SMing Yen Hsieh if (offset + len > fw->size) {
40723bdc5d8SMing Yen Hsieh dev_err(mdev->dev, "Invalid firmware region\n");
40823bdc5d8SMing Yen Hsieh ret = -EINVAL;
40923bdc5d8SMing Yen Hsieh goto out;
41023bdc5d8SMing Yen Hsieh }
41123bdc5d8SMing Yen Hsieh
41223bdc5d8SMing Yen Hsieh if ((region->feature_set & FW_FEATURE_NON_DL) &&
41323bdc5d8SMing Yen Hsieh region->type == FW_TYPE_CLC) {
41423bdc5d8SMing Yen Hsieh clc_base = (u8 *)(fw->data + offset);
41523bdc5d8SMing Yen Hsieh break;
41623bdc5d8SMing Yen Hsieh }
41723bdc5d8SMing Yen Hsieh offset += len;
41823bdc5d8SMing Yen Hsieh }
41923bdc5d8SMing Yen Hsieh
42023bdc5d8SMing Yen Hsieh if (!clc_base)
42123bdc5d8SMing Yen Hsieh goto out;
42223bdc5d8SMing Yen Hsieh
42323bdc5d8SMing Yen Hsieh for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) {
42423bdc5d8SMing Yen Hsieh clc = (const struct mt7921_clc *)(clc_base + offset);
42523bdc5d8SMing Yen Hsieh
42623bdc5d8SMing Yen Hsieh /* do not init buf again if chip reset triggered */
42723bdc5d8SMing Yen Hsieh if (phy->clc[clc->idx])
42823bdc5d8SMing Yen Hsieh continue;
42923bdc5d8SMing Yen Hsieh
43023bdc5d8SMing Yen Hsieh /* header content sanity */
43123bdc5d8SMing Yen Hsieh if (clc->idx == MT7921_CLC_POWER &&
43223bdc5d8SMing Yen Hsieh u8_get_bits(clc->type, MT_EE_HW_TYPE_ENCAP) != hw_encap)
43323bdc5d8SMing Yen Hsieh continue;
43423bdc5d8SMing Yen Hsieh
43523bdc5d8SMing Yen Hsieh phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc,
43623bdc5d8SMing Yen Hsieh le32_to_cpu(clc->len),
43723bdc5d8SMing Yen Hsieh GFP_KERNEL);
43823bdc5d8SMing Yen Hsieh
43923bdc5d8SMing Yen Hsieh if (!phy->clc[clc->idx]) {
44023bdc5d8SMing Yen Hsieh ret = -ENOMEM;
44123bdc5d8SMing Yen Hsieh goto out;
44223bdc5d8SMing Yen Hsieh }
44323bdc5d8SMing Yen Hsieh }
44423bdc5d8SMing Yen Hsieh ret = mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR);
44523bdc5d8SMing Yen Hsieh out:
44623bdc5d8SMing Yen Hsieh release_firmware(fw);
44723bdc5d8SMing Yen Hsieh
44823bdc5d8SMing Yen Hsieh return ret;
44923bdc5d8SMing Yen Hsieh }
45023bdc5d8SMing Yen Hsieh
mt7921_mcu_fw_log_2_host(struct mt792x_dev * dev,u8 ctrl)451975e122dSLorenzo Bianconi int mt7921_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl)
4521c099ab4SSean Wang {
4531c099ab4SSean Wang struct {
4541c099ab4SSean Wang u8 ctrl_val;
4551c099ab4SSean Wang u8 pad[3];
4561c099ab4SSean Wang } data = {
4571c099ab4SSean Wang .ctrl_val = ctrl
4581c099ab4SSean Wang };
4591c099ab4SSean Wang
460680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(FWLOG_2_HOST),
461680a2eadSLorenzo Bianconi &data, sizeof(data), false);
4621c099ab4SSean Wang }
4631c099ab4SSean Wang
mt7921_run_firmware(struct mt792x_dev * dev)464975e122dSLorenzo Bianconi int mt7921_run_firmware(struct mt792x_dev *dev)
465d32464e6SLorenzo Bianconi {
466d32464e6SLorenzo Bianconi int err;
467d32464e6SLorenzo Bianconi
468583204aeSLorenzo Bianconi err = mt792x_load_firmware(dev);
469d32464e6SLorenzo Bianconi if (err)
470d32464e6SLorenzo Bianconi return err;
471d32464e6SLorenzo Bianconi
47216d98b54SSean Wang err = mt76_connac_mcu_get_nic_capability(&dev->mphy);
47316d98b54SSean Wang if (err)
47416d98b54SSean Wang return err;
475d32464e6SLorenzo Bianconi
47616d98b54SSean Wang set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
477583204aeSLorenzo Bianconi err = mt7921_load_clc(dev, mt792x_ram_name(dev));
47823bdc5d8SMing Yen Hsieh if (err)
47923bdc5d8SMing Yen Hsieh return err;
48023bdc5d8SMing Yen Hsieh
48116d98b54SSean Wang return mt7921_mcu_fw_log_2_host(dev, 1);
482d32464e6SLorenzo Bianconi }
4838910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_run_firmware);
484d32464e6SLorenzo Bianconi
mt7921_mcu_set_tx(struct mt792x_dev * dev,struct ieee80211_vif * vif)485975e122dSLorenzo Bianconi int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif)
4861c099ab4SSean Wang {
48715ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
4881c099ab4SSean Wang struct edca {
48966ca1a7bSSean Wang __le16 cw_min;
4901c099ab4SSean Wang __le16 cw_max;
4911c099ab4SSean Wang __le16 txop;
49266ca1a7bSSean Wang __le16 aifs;
49366ca1a7bSSean Wang u8 guardtime;
49466ca1a7bSSean Wang u8 acm;
49566ca1a7bSSean Wang } __packed;
4961c099ab4SSean Wang struct mt7921_mcu_tx {
4971c099ab4SSean Wang struct edca edca[IEEE80211_NUM_ACS];
49866ca1a7bSSean Wang u8 bss_idx;
49966ca1a7bSSean Wang u8 qos;
50066ca1a7bSSean Wang u8 wmm_idx;
50166ca1a7bSSean Wang u8 pad;
5021c099ab4SSean Wang } __packed req = {
50366ca1a7bSSean Wang .bss_idx = mvif->mt76.idx,
50466ca1a7bSSean Wang .qos = vif->bss_conf.qos,
50566ca1a7bSSean Wang .wmm_idx = mvif->mt76.wmm_idx,
5061c099ab4SSean Wang };
507bb0ae4cfSSean Wang struct mu_edca {
508bb0ae4cfSSean Wang u8 cw_min;
509bb0ae4cfSSean Wang u8 cw_max;
510bb0ae4cfSSean Wang u8 aifsn;
511bb0ae4cfSSean Wang u8 acm;
512bb0ae4cfSSean Wang u8 timer;
513bb0ae4cfSSean Wang u8 padding[3];
514bb0ae4cfSSean Wang };
515bb0ae4cfSSean Wang struct mt7921_mcu_mu_tx {
516bb0ae4cfSSean Wang u8 ver;
517bb0ae4cfSSean Wang u8 pad0;
518bb0ae4cfSSean Wang __le16 len;
519bb0ae4cfSSean Wang u8 bss_idx;
520bb0ae4cfSSean Wang u8 qos;
521bb0ae4cfSSean Wang u8 wmm_idx;
522bb0ae4cfSSean Wang u8 pad1;
523bb0ae4cfSSean Wang struct mu_edca edca[IEEE80211_NUM_ACS];
524bb0ae4cfSSean Wang u8 pad3[32];
525bb0ae4cfSSean Wang } __packed req_mu = {
526bb0ae4cfSSean Wang .bss_idx = mvif->mt76.idx,
527bb0ae4cfSSean Wang .qos = vif->bss_conf.qos,
528bb0ae4cfSSean Wang .wmm_idx = mvif->mt76.wmm_idx,
529bb0ae4cfSSean Wang };
5304abe5b92SLorenzo Bianconi static const int to_aci[] = { 1, 0, 2, 3 };
531bb0ae4cfSSean Wang int ac, ret;
5321c099ab4SSean Wang
5331c099ab4SSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
5341c099ab4SSean Wang struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
53566ca1a7bSSean Wang struct edca *e = &req.edca[to_aci[ac]];
5361c099ab4SSean Wang
5374abe5b92SLorenzo Bianconi e->aifs = cpu_to_le16(q->aifs);
5381c099ab4SSean Wang e->txop = cpu_to_le16(q->txop);
5391c099ab4SSean Wang
5401c099ab4SSean Wang if (q->cw_min)
54166ca1a7bSSean Wang e->cw_min = cpu_to_le16(q->cw_min);
5421c099ab4SSean Wang else
5434abe5b92SLorenzo Bianconi e->cw_min = cpu_to_le16(5);
5441c099ab4SSean Wang
5451c099ab4SSean Wang if (q->cw_max)
54666ca1a7bSSean Wang e->cw_max = cpu_to_le16(q->cw_max);
5471c099ab4SSean Wang else
5481c099ab4SSean Wang e->cw_max = cpu_to_le16(10);
5491c099ab4SSean Wang }
550bb0ae4cfSSean Wang
55166ca1a7bSSean Wang ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_EDCA_PARMS), &req,
55266ca1a7bSSean Wang sizeof(req), false);
553bb0ae4cfSSean Wang if (ret)
554bb0ae4cfSSean Wang return ret;
555bb0ae4cfSSean Wang
556bb0ae4cfSSean Wang if (!vif->bss_conf.he_support)
557bb0ae4cfSSean Wang return 0;
558bb0ae4cfSSean Wang
559bb0ae4cfSSean Wang for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
560bb0ae4cfSSean Wang struct ieee80211_he_mu_edca_param_ac_rec *q;
561bb0ae4cfSSean Wang struct mu_edca *e;
562bb0ae4cfSSean Wang
563bb0ae4cfSSean Wang if (!mvif->queue_params[ac].mu_edca)
564bb0ae4cfSSean Wang break;
565bb0ae4cfSSean Wang
566bb0ae4cfSSean Wang q = &mvif->queue_params[ac].mu_edca_param_rec;
567bb0ae4cfSSean Wang e = &(req_mu.edca[to_aci[ac]]);
568bb0ae4cfSSean Wang
569bb0ae4cfSSean Wang e->cw_min = q->ecw_min_max & 0xf;
570bb0ae4cfSSean Wang e->cw_max = (q->ecw_min_max & 0xf0) >> 4;
571bb0ae4cfSSean Wang e->aifsn = q->aifsn;
572bb0ae4cfSSean Wang e->timer = q->mu_edca_timer;
573bb0ae4cfSSean Wang }
574bb0ae4cfSSean Wang
575680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_MU_EDCA_PARMS),
576680a2eadSLorenzo Bianconi &req_mu, sizeof(req_mu), false);
5771c099ab4SSean Wang }
5781c099ab4SSean Wang
mt7921_mcu_set_roc(struct mt792x_phy * phy,struct mt792x_vif * vif,struct ieee80211_channel * chan,int duration,enum mt7921_roc_req type,u8 token_id)57978562b2cSLorenzo Bianconi int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
5805b55b6daSQuan Zhou struct ieee80211_channel *chan, int duration,
5815b55b6daSQuan Zhou enum mt7921_roc_req type, u8 token_id)
5825b55b6daSQuan Zhou {
5835b55b6daSQuan Zhou int center_ch = ieee80211_frequency_to_channel(chan->center_freq);
584975e122dSLorenzo Bianconi struct mt792x_dev *dev = phy->dev;
5855b55b6daSQuan Zhou struct {
5865b55b6daSQuan Zhou struct {
5875b55b6daSQuan Zhou u8 rsv[4];
5885b55b6daSQuan Zhou } __packed hdr;
5895b55b6daSQuan Zhou struct roc_acquire_tlv {
5905b55b6daSQuan Zhou __le16 tag;
5915b55b6daSQuan Zhou __le16 len;
5925b55b6daSQuan Zhou u8 bss_idx;
5935b55b6daSQuan Zhou u8 tokenid;
5945b55b6daSQuan Zhou u8 control_channel;
5955b55b6daSQuan Zhou u8 sco;
5965b55b6daSQuan Zhou u8 band;
5975b55b6daSQuan Zhou u8 bw;
5985b55b6daSQuan Zhou u8 center_chan;
5995b55b6daSQuan Zhou u8 center_chan2;
6005b55b6daSQuan Zhou u8 bw_from_ap;
6015b55b6daSQuan Zhou u8 center_chan_from_ap;
6025b55b6daSQuan Zhou u8 center_chan2_from_ap;
6035b55b6daSQuan Zhou u8 reqtype;
6045b55b6daSQuan Zhou __le32 maxinterval;
6055b55b6daSQuan Zhou u8 dbdcband;
6065b55b6daSQuan Zhou u8 rsv[3];
6075b55b6daSQuan Zhou } __packed roc;
6085b55b6daSQuan Zhou } __packed req = {
6095b55b6daSQuan Zhou .roc = {
6105b55b6daSQuan Zhou .tag = cpu_to_le16(UNI_ROC_ACQUIRE),
6115b55b6daSQuan Zhou .len = cpu_to_le16(sizeof(struct roc_acquire_tlv)),
6125b55b6daSQuan Zhou .tokenid = token_id,
6135b55b6daSQuan Zhou .reqtype = type,
6145b55b6daSQuan Zhou .maxinterval = cpu_to_le32(duration),
6155b55b6daSQuan Zhou .bss_idx = vif->mt76.idx,
6165b55b6daSQuan Zhou .control_channel = chan->hw_value,
6175b55b6daSQuan Zhou .bw = CMD_CBW_20MHZ,
6185b55b6daSQuan Zhou .bw_from_ap = CMD_CBW_20MHZ,
6195b55b6daSQuan Zhou .center_chan = center_ch,
6205b55b6daSQuan Zhou .center_chan_from_ap = center_ch,
6215b55b6daSQuan Zhou .dbdcband = 0xff, /* auto */
6225b55b6daSQuan Zhou },
6235b55b6daSQuan Zhou };
6245b55b6daSQuan Zhou
6255b55b6daSQuan Zhou if (chan->hw_value < center_ch)
6265b55b6daSQuan Zhou req.roc.sco = 1; /* SCA */
6275b55b6daSQuan Zhou else if (chan->hw_value > center_ch)
6285b55b6daSQuan Zhou req.roc.sco = 3; /* SCB */
6295b55b6daSQuan Zhou
6305b55b6daSQuan Zhou switch (chan->band) {
6315b55b6daSQuan Zhou case NL80211_BAND_6GHZ:
6325b55b6daSQuan Zhou req.roc.band = 3;
6335b55b6daSQuan Zhou break;
6345b55b6daSQuan Zhou case NL80211_BAND_5GHZ:
6355b55b6daSQuan Zhou req.roc.band = 2;
6365b55b6daSQuan Zhou break;
6375b55b6daSQuan Zhou default:
6385b55b6daSQuan Zhou req.roc.band = 1;
6395b55b6daSQuan Zhou break;
6405b55b6daSQuan Zhou }
6415b55b6daSQuan Zhou
6425b55b6daSQuan Zhou return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),
6435b55b6daSQuan Zhou &req, sizeof(req), false);
6445b55b6daSQuan Zhou }
6455b55b6daSQuan Zhou
mt7921_mcu_abort_roc(struct mt792x_phy * phy,struct mt792x_vif * vif,u8 token_id)64678562b2cSLorenzo Bianconi int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
6475b55b6daSQuan Zhou u8 token_id)
6485b55b6daSQuan Zhou {
649975e122dSLorenzo Bianconi struct mt792x_dev *dev = phy->dev;
6505b55b6daSQuan Zhou struct {
6515b55b6daSQuan Zhou struct {
6525b55b6daSQuan Zhou u8 rsv[4];
6535b55b6daSQuan Zhou } __packed hdr;
6545b55b6daSQuan Zhou struct roc_abort_tlv {
6555b55b6daSQuan Zhou __le16 tag;
6565b55b6daSQuan Zhou __le16 len;
6575b55b6daSQuan Zhou u8 bss_idx;
6585b55b6daSQuan Zhou u8 tokenid;
6595b55b6daSQuan Zhou u8 dbdcband;
6605b55b6daSQuan Zhou u8 rsv[5];
6615b55b6daSQuan Zhou } __packed abort;
6625b55b6daSQuan Zhou } __packed req = {
6635b55b6daSQuan Zhou .abort = {
6645b55b6daSQuan Zhou .tag = cpu_to_le16(UNI_ROC_ABORT),
6655b55b6daSQuan Zhou .len = cpu_to_le16(sizeof(struct roc_abort_tlv)),
6665b55b6daSQuan Zhou .tokenid = token_id,
6675b55b6daSQuan Zhou .bss_idx = vif->mt76.idx,
6685b55b6daSQuan Zhou .dbdcband = 0xff, /* auto*/
6695b55b6daSQuan Zhou },
6705b55b6daSQuan Zhou };
6715b55b6daSQuan Zhou
6725b55b6daSQuan Zhou return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),
6735b55b6daSQuan Zhou &req, sizeof(req), false);
6745b55b6daSQuan Zhou }
6755b55b6daSQuan Zhou
mt7921_mcu_set_chan_info(struct mt792x_phy * phy,int cmd)67678562b2cSLorenzo Bianconi int mt7921_mcu_set_chan_info(struct mt792x_phy *phy, int cmd)
6771c099ab4SSean Wang {
678975e122dSLorenzo Bianconi struct mt792x_dev *dev = phy->dev;
6791c099ab4SSean Wang struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
6801c099ab4SSean Wang int freq1 = chandef->center_freq1;
6811c099ab4SSean Wang struct {
6821c099ab4SSean Wang u8 control_ch;
6831c099ab4SSean Wang u8 center_ch;
6841c099ab4SSean Wang u8 bw;
6851c099ab4SSean Wang u8 tx_streams_num;
6861c099ab4SSean Wang u8 rx_streams; /* mask or num */
6871c099ab4SSean Wang u8 switch_reason;
6881c099ab4SSean Wang u8 band_idx;
6891c099ab4SSean Wang u8 center_ch2; /* for 80+80 only */
6901c099ab4SSean Wang __le16 cac_case;
6911c099ab4SSean Wang u8 channel_band;
6921c099ab4SSean Wang u8 rsv0;
6931c099ab4SSean Wang __le32 outband_freq;
6941c099ab4SSean Wang u8 txpower_drop;
6951c099ab4SSean Wang u8 ap_bw;
6961c099ab4SSean Wang u8 ap_center_ch;
6971c099ab4SSean Wang u8 rsv1[57];
6981c099ab4SSean Wang } __packed req = {
6991c099ab4SSean Wang .control_ch = chandef->chan->hw_value,
7001c099ab4SSean Wang .center_ch = ieee80211_frequency_to_channel(freq1),
70144c73d17SLorenzo Bianconi .bw = mt76_connac_chan_bw(chandef),
7021c099ab4SSean Wang .tx_streams_num = hweight8(phy->mt76->antenna_mask),
7031c099ab4SSean Wang .rx_streams = phy->mt76->antenna_mask,
7041c099ab4SSean Wang .band_idx = phy != &dev->phy,
7051c099ab4SSean Wang };
7061c099ab4SSean Wang
70750ac15a5SLorenzo Bianconi if (chandef->chan->band == NL80211_BAND_6GHZ)
70850ac15a5SLorenzo Bianconi req.channel_band = 2;
70950ac15a5SLorenzo Bianconi else
71050ac15a5SLorenzo Bianconi req.channel_band = chandef->chan->band;
71150ac15a5SLorenzo Bianconi
71224e69f6bSDeren Wu if (cmd == MCU_EXT_CMD(SET_RX_PATH) ||
71324e69f6bSDeren Wu dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR)
71400a883e6SFelix Fietkau req.switch_reason = CH_SWITCH_NORMAL;
71500a883e6SFelix Fietkau else if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
7161c099ab4SSean Wang req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
71700a883e6SFelix Fietkau else if (!cfg80211_reg_can_beacon(dev->mt76.hw->wiphy, chandef,
71800a883e6SFelix Fietkau NL80211_IFTYPE_AP))
7191c099ab4SSean Wang req.switch_reason = CH_SWITCH_DFS;
7201c099ab4SSean Wang else
7211c099ab4SSean Wang req.switch_reason = CH_SWITCH_NORMAL;
7221c099ab4SSean Wang
723e6d2070dSLorenzo Bianconi if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH))
7241c099ab4SSean Wang req.rx_streams = hweight8(req.rx_streams);
7251c099ab4SSean Wang
7261c099ab4SSean Wang if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
7271c099ab4SSean Wang int freq2 = chandef->center_freq2;
7281c099ab4SSean Wang
7291c099ab4SSean Wang req.center_ch2 = ieee80211_frequency_to_channel(freq2);
7301c099ab4SSean Wang }
7311c099ab4SSean Wang
7321c099ab4SSean Wang return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
7331c099ab4SSean Wang }
7341c099ab4SSean Wang
mt7921_mcu_set_eeprom(struct mt792x_dev * dev)735975e122dSLorenzo Bianconi int mt7921_mcu_set_eeprom(struct mt792x_dev *dev)
7361c099ab4SSean Wang {
7371c099ab4SSean Wang struct req_hdr {
7381c099ab4SSean Wang u8 buffer_mode;
7391c099ab4SSean Wang u8 format;
7401c099ab4SSean Wang __le16 len;
7411c099ab4SSean Wang } __packed req = {
7421c099ab4SSean Wang .buffer_mode = EE_MODE_EFUSE,
7431c099ab4SSean Wang .format = EE_FORMAT_WHOLE,
7441c099ab4SSean Wang };
7451c099ab4SSean Wang
746e6d2070dSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
7471c099ab4SSean Wang &req, sizeof(req), true);
7481c099ab4SSean Wang }
7498910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom);
7501c099ab4SSean Wang
mt7921_mcu_uni_bss_ps(struct mt792x_dev * dev,struct ieee80211_vif * vif)751975e122dSLorenzo Bianconi int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif)
75256d965daSSean Wang {
75315ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
75456d965daSSean Wang struct {
75556d965daSSean Wang struct {
75656d965daSSean Wang u8 bss_idx;
75756d965daSSean Wang u8 pad[3];
75856d965daSSean Wang } __packed hdr;
75956d965daSSean Wang struct ps_tlv {
76056d965daSSean Wang __le16 tag;
76156d965daSSean Wang __le16 len;
76256d965daSSean Wang u8 ps_state; /* 0: device awake
76356d965daSSean Wang * 1: static power save
76456d965daSSean Wang * 2: dynamic power saving
76556d965daSSean Wang * 3: enter TWT power saving
76656d965daSSean Wang * 4: leave TWT power saving
76756d965daSSean Wang */
76856d965daSSean Wang u8 pad[3];
76956d965daSSean Wang } __packed ps;
77056d965daSSean Wang } __packed ps_req = {
77156d965daSSean Wang .hdr = {
77256d965daSSean Wang .bss_idx = mvif->mt76.idx,
77356d965daSSean Wang },
77456d965daSSean Wang .ps = {
77556d965daSSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_PS),
77656d965daSSean Wang .len = cpu_to_le16(sizeof(struct ps_tlv)),
777a3b8008dSJohannes Berg .ps_state = vif->cfg.ps ? 2 : 0,
77856d965daSSean Wang },
77956d965daSSean Wang };
78056d965daSSean Wang
78156d965daSSean Wang if (vif->type != NL80211_IFTYPE_STATION)
78256d965daSSean Wang return -EOPNOTSUPP;
78356d965daSSean Wang
78454722402SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
78556d965daSSean Wang &ps_req, sizeof(ps_req), true);
78656d965daSSean Wang }
7874086ee28SSean Wang
788890809caSLorenzo Bianconi static int
mt7921_mcu_uni_bss_bcnft(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)789975e122dSLorenzo Bianconi mt7921_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif,
7904086ee28SSean Wang bool enable)
7914086ee28SSean Wang {
79215ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
7934086ee28SSean Wang struct {
7944086ee28SSean Wang struct {
7954086ee28SSean Wang u8 bss_idx;
7964086ee28SSean Wang u8 pad[3];
7974086ee28SSean Wang } __packed hdr;
7984086ee28SSean Wang struct bcnft_tlv {
7994086ee28SSean Wang __le16 tag;
8004086ee28SSean Wang __le16 len;
8014086ee28SSean Wang __le16 bcn_interval;
8024086ee28SSean Wang u8 dtim_period;
8034086ee28SSean Wang u8 pad;
8044086ee28SSean Wang } __packed bcnft;
8054086ee28SSean Wang } __packed bcnft_req = {
8064086ee28SSean Wang .hdr = {
8074086ee28SSean Wang .bss_idx = mvif->mt76.idx,
8084086ee28SSean Wang },
8094086ee28SSean Wang .bcnft = {
8104086ee28SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT),
8114086ee28SSean Wang .len = cpu_to_le16(sizeof(struct bcnft_tlv)),
8124086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
8134086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period,
8144086ee28SSean Wang },
8154086ee28SSean Wang };
8164086ee28SSean Wang
8174086ee28SSean Wang if (vif->type != NL80211_IFTYPE_STATION)
8184086ee28SSean Wang return 0;
8194086ee28SSean Wang
82054722402SLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
8214086ee28SSean Wang &bcnft_req, sizeof(bcnft_req), true);
8224086ee28SSean Wang }
8234086ee28SSean Wang
8249d958b60SDeren Wu int
mt7921_mcu_set_bss_pm(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)825975e122dSLorenzo Bianconi mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif,
8264086ee28SSean Wang bool enable)
8274086ee28SSean Wang {
82815ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
8294086ee28SSean Wang struct {
8304086ee28SSean Wang u8 bss_idx;
8314086ee28SSean Wang u8 dtim_period;
8324086ee28SSean Wang __le16 aid;
8334086ee28SSean Wang __le16 bcn_interval;
8344086ee28SSean Wang __le16 atim_window;
8354086ee28SSean Wang u8 uapsd;
8364086ee28SSean Wang u8 bmc_delivered_ac;
8374086ee28SSean Wang u8 bmc_triggered_ac;
8384086ee28SSean Wang u8 pad;
8394086ee28SSean Wang } req = {
8404086ee28SSean Wang .bss_idx = mvif->mt76.idx,
841f276e20bSJohannes Berg .aid = cpu_to_le16(vif->cfg.aid),
8424086ee28SSean Wang .dtim_period = vif->bss_conf.dtim_period,
8434086ee28SSean Wang .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
8444086ee28SSean Wang };
8454086ee28SSean Wang struct {
8464086ee28SSean Wang u8 bss_idx;
8474086ee28SSean Wang u8 pad[3];
8484086ee28SSean Wang } req_hdr = {
8494086ee28SSean Wang .bss_idx = mvif->mt76.idx,
8504086ee28SSean Wang };
8514086ee28SSean Wang int err;
8524086ee28SSean Wang
853680a2eadSLorenzo Bianconi err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT),
854680a2eadSLorenzo Bianconi &req_hdr, sizeof(req_hdr), false);
8554086ee28SSean Wang if (err < 0 || !enable)
8564086ee28SSean Wang return err;
8574086ee28SSean Wang
858680a2eadSLorenzo Bianconi return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED),
859680a2eadSLorenzo Bianconi &req, sizeof(req), false);
8604086ee28SSean Wang }
8611d8efc74SSean Wang
mt7921_mcu_sta_update(struct mt792x_dev * dev,struct ieee80211_sta * sta,struct ieee80211_vif * vif,bool enable,enum mt76_sta_info_state state)862975e122dSLorenzo Bianconi int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta,
863f5056657SSean Wang struct ieee80211_vif *vif, bool enable,
864f5056657SSean Wang enum mt76_sta_info_state state)
86536fcc8cfSLorenzo Bianconi {
86615ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
86736fcc8cfSLorenzo Bianconi int rssi = -ewma_rssi_read(&mvif->rssi);
86836fcc8cfSLorenzo Bianconi struct mt76_sta_cmd_info info = {
86936fcc8cfSLorenzo Bianconi .sta = sta,
87036fcc8cfSLorenzo Bianconi .vif = vif,
87136fcc8cfSLorenzo Bianconi .enable = enable,
87254722402SLorenzo Bianconi .cmd = MCU_UNI_CMD(STA_REC_UPDATE),
873f5056657SSean Wang .state = state,
87482453b1cSLorenzo Bianconi .offload_fw = true,
87536fcc8cfSLorenzo Bianconi .rcpi = to_rcpi(rssi),
87636fcc8cfSLorenzo Bianconi };
877b7bfad2cSLorenzo Bianconi struct mt792x_sta *msta;
87836fcc8cfSLorenzo Bianconi
879b7bfad2cSLorenzo Bianconi msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL;
88036fcc8cfSLorenzo Bianconi info.wcid = msta ? &msta->wcid : &mvif->sta.wcid;
881f5056657SSean Wang info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true;
88236fcc8cfSLorenzo Bianconi
883f5056657SSean Wang return mt76_connac_mcu_sta_cmd(&dev->mphy, &info);
88436fcc8cfSLorenzo Bianconi }
88536fcc8cfSLorenzo Bianconi
mt7921_mcu_set_beacon_filter(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)886975e122dSLorenzo Bianconi int mt7921_mcu_set_beacon_filter(struct mt792x_dev *dev,
887890809caSLorenzo Bianconi struct ieee80211_vif *vif,
888890809caSLorenzo Bianconi bool enable)
8891d8efc74SSean Wang {
890c222f77fSNeil Chen #define MT7921_FIF_BIT_CLR BIT(1)
891c222f77fSNeil Chen #define MT7921_FIF_BIT_SET BIT(0)
892890809caSLorenzo Bianconi int err;
8931d8efc74SSean Wang
894890809caSLorenzo Bianconi if (enable) {
895890809caSLorenzo Bianconi err = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
896890809caSLorenzo Bianconi if (err)
897890809caSLorenzo Bianconi return err;
898159f6dd6SSean Wang
899c222f77fSNeil Chen err = mt7921_mcu_set_rxfilter(dev, 0,
900c222f77fSNeil Chen MT7921_FIF_BIT_SET,
901c222f77fSNeil Chen MT_WF_RFCR_DROP_OTHER_BEACON);
902c222f77fSNeil Chen if (err)
903c222f77fSNeil Chen return err;
904890809caSLorenzo Bianconi
905890809caSLorenzo Bianconi return 0;
906890809caSLorenzo Bianconi }
907890809caSLorenzo Bianconi
908890809caSLorenzo Bianconi err = mt7921_mcu_set_bss_pm(dev, vif, false);
909890809caSLorenzo Bianconi if (err)
910890809caSLorenzo Bianconi return err;
911890809caSLorenzo Bianconi
912c222f77fSNeil Chen err = mt7921_mcu_set_rxfilter(dev, 0,
913c222f77fSNeil Chen MT7921_FIF_BIT_CLR,
914c222f77fSNeil Chen MT_WF_RFCR_DROP_OTHER_BEACON);
915c222f77fSNeil Chen if (err)
916c222f77fSNeil Chen return err;
917890809caSLorenzo Bianconi
918890809caSLorenzo Bianconi return 0;
9191d8efc74SSean Wang }
9209c9d8321SSean Wang
mt7921_get_txpwr_info(struct mt792x_dev * dev,struct mt7921_txpwr * txpwr)921975e122dSLorenzo Bianconi int mt7921_get_txpwr_info(struct mt792x_dev *dev, struct mt7921_txpwr *txpwr)
922ea29acc9SSean Wang {
923ea29acc9SSean Wang struct mt7921_txpwr_event *event;
924ea29acc9SSean Wang struct mt7921_txpwr_req req = {
925ea29acc9SSean Wang .dbdc_idx = 0,
926ea29acc9SSean Wang };
927ea29acc9SSean Wang struct sk_buff *skb;
928ea29acc9SSean Wang int ret;
929ea29acc9SSean Wang
930680a2eadSLorenzo Bianconi ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(GET_TXPWR),
931ea29acc9SSean Wang &req, sizeof(req), true, &skb);
932ea29acc9SSean Wang if (ret)
933ea29acc9SSean Wang return ret;
934ea29acc9SSean Wang
935ea29acc9SSean Wang event = (struct mt7921_txpwr_event *)skb->data;
936ea29acc9SSean Wang WARN_ON(skb->len != le16_to_cpu(event->len));
937ea29acc9SSean Wang memcpy(txpwr, &event->txpwr, sizeof(event->txpwr));
938ea29acc9SSean Wang
939ea29acc9SSean Wang dev_kfree_skb(skb);
940ea29acc9SSean Wang
941ea29acc9SSean Wang return 0;
942ea29acc9SSean Wang }
943cbaa0a40SSean Wang
mt7921_mcu_set_sniffer(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)944975e122dSLorenzo Bianconi int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
945cbaa0a40SSean Wang bool enable)
946cbaa0a40SSean Wang {
947cbaa0a40SSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
948cbaa0a40SSean Wang struct {
949cbaa0a40SSean Wang struct {
950cbaa0a40SSean Wang u8 band_idx;
951cbaa0a40SSean Wang u8 pad[3];
952cbaa0a40SSean Wang } __packed hdr;
953cbaa0a40SSean Wang struct sniffer_enable_tlv {
954cbaa0a40SSean Wang __le16 tag;
955cbaa0a40SSean Wang __le16 len;
956cbaa0a40SSean Wang u8 enable;
957cbaa0a40SSean Wang u8 pad[3];
958cbaa0a40SSean Wang } __packed enable;
959cbaa0a40SSean Wang } req = {
960cbaa0a40SSean Wang .hdr = {
961cbaa0a40SSean Wang .band_idx = mvif->band_idx,
962cbaa0a40SSean Wang },
963cbaa0a40SSean Wang .enable = {
964cbaa0a40SSean Wang .tag = cpu_to_le16(0),
965cbaa0a40SSean Wang .len = cpu_to_le16(sizeof(struct sniffer_enable_tlv)),
966cbaa0a40SSean Wang .enable = enable,
967cbaa0a40SSean Wang },
968cbaa0a40SSean Wang };
969cbaa0a40SSean Wang
970cbaa0a40SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req),
971cbaa0a40SSean Wang true);
972cbaa0a40SSean Wang }
973116c6960SSean Wang
mt7921_mcu_config_sniffer(struct mt792x_vif * vif,struct ieee80211_chanctx_conf * ctx)97415ca8970SLorenzo Bianconi int mt7921_mcu_config_sniffer(struct mt792x_vif *vif,
975914189afSDeren Wu struct ieee80211_chanctx_conf *ctx)
976914189afSDeren Wu {
977914189afSDeren Wu struct cfg80211_chan_def *chandef = &ctx->def;
978914189afSDeren Wu int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
979914189afSDeren Wu const u8 ch_band[] = {
980914189afSDeren Wu [NL80211_BAND_2GHZ] = 1,
981914189afSDeren Wu [NL80211_BAND_5GHZ] = 2,
982914189afSDeren Wu [NL80211_BAND_6GHZ] = 3,
983914189afSDeren Wu };
984914189afSDeren Wu const u8 ch_width[] = {
985914189afSDeren Wu [NL80211_CHAN_WIDTH_20_NOHT] = 0,
986914189afSDeren Wu [NL80211_CHAN_WIDTH_20] = 0,
987914189afSDeren Wu [NL80211_CHAN_WIDTH_40] = 0,
988914189afSDeren Wu [NL80211_CHAN_WIDTH_80] = 1,
989914189afSDeren Wu [NL80211_CHAN_WIDTH_160] = 2,
990914189afSDeren Wu [NL80211_CHAN_WIDTH_80P80] = 3,
991914189afSDeren Wu [NL80211_CHAN_WIDTH_5] = 4,
992914189afSDeren Wu [NL80211_CHAN_WIDTH_10] = 5,
993914189afSDeren Wu [NL80211_CHAN_WIDTH_320] = 6,
994914189afSDeren Wu };
995914189afSDeren Wu struct {
996914189afSDeren Wu struct {
997914189afSDeren Wu u8 band_idx;
998914189afSDeren Wu u8 pad[3];
999914189afSDeren Wu } __packed hdr;
1000914189afSDeren Wu struct config_tlv {
1001914189afSDeren Wu __le16 tag;
1002914189afSDeren Wu __le16 len;
1003914189afSDeren Wu u16 aid;
1004914189afSDeren Wu u8 ch_band;
1005914189afSDeren Wu u8 bw;
1006914189afSDeren Wu u8 control_ch;
1007914189afSDeren Wu u8 sco;
1008914189afSDeren Wu u8 center_ch;
1009914189afSDeren Wu u8 center_ch2;
1010914189afSDeren Wu u8 drop_err;
1011914189afSDeren Wu u8 pad[3];
1012914189afSDeren Wu } __packed tlv;
1013914189afSDeren Wu } __packed req = {
1014914189afSDeren Wu .hdr = {
1015914189afSDeren Wu .band_idx = vif->mt76.band_idx,
1016914189afSDeren Wu },
1017914189afSDeren Wu .tlv = {
1018914189afSDeren Wu .tag = cpu_to_le16(1),
1019914189afSDeren Wu .len = cpu_to_le16(sizeof(req.tlv)),
1020914189afSDeren Wu .control_ch = chandef->chan->hw_value,
1021914189afSDeren Wu .center_ch = ieee80211_frequency_to_channel(freq1),
1022914189afSDeren Wu .drop_err = 1,
1023914189afSDeren Wu },
1024914189afSDeren Wu };
1025914189afSDeren Wu if (chandef->chan->band < ARRAY_SIZE(ch_band))
1026914189afSDeren Wu req.tlv.ch_band = ch_band[chandef->chan->band];
1027914189afSDeren Wu if (chandef->width < ARRAY_SIZE(ch_width))
1028914189afSDeren Wu req.tlv.bw = ch_width[chandef->width];
1029914189afSDeren Wu
1030914189afSDeren Wu if (freq2)
1031914189afSDeren Wu req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2);
1032914189afSDeren Wu
1033914189afSDeren Wu if (req.tlv.control_ch < req.tlv.center_ch)
1034914189afSDeren Wu req.tlv.sco = 1; /* SCA */
1035914189afSDeren Wu else if (req.tlv.control_ch > req.tlv.center_ch)
1036914189afSDeren Wu req.tlv.sco = 3; /* SCB */
1037914189afSDeren Wu
1038914189afSDeren Wu return mt76_mcu_send_msg(vif->phy->mt76->dev, MCU_UNI_CMD(SNIFFER),
1039914189afSDeren Wu &req, sizeof(req), true);
1040914189afSDeren Wu }
1041914189afSDeren Wu
1042116c6960SSean Wang int
mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev * dev,struct ieee80211_hw * hw,struct ieee80211_vif * vif,bool enable)1043975e122dSLorenzo Bianconi mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,
1044116c6960SSean Wang struct ieee80211_hw *hw,
1045116c6960SSean Wang struct ieee80211_vif *vif,
1046116c6960SSean Wang bool enable)
1047116c6960SSean Wang {
104815ca8970SLorenzo Bianconi struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
1049116c6960SSean Wang struct mt76_wcid *wcid = &dev->mt76.global_wcid;
1050116c6960SSean Wang struct ieee80211_mutable_offsets offs;
1051116c6960SSean Wang struct {
1052116c6960SSean Wang struct req_hdr {
1053116c6960SSean Wang u8 bss_idx;
1054116c6960SSean Wang u8 pad[3];
1055116c6960SSean Wang } __packed hdr;
1056116c6960SSean Wang struct bcn_content_tlv {
1057116c6960SSean Wang __le16 tag;
1058116c6960SSean Wang __le16 len;
1059116c6960SSean Wang __le16 tim_ie_pos;
1060116c6960SSean Wang __le16 csa_ie_pos;
1061116c6960SSean Wang __le16 bcc_ie_pos;
1062116c6960SSean Wang /* 0: disable beacon offload
1063116c6960SSean Wang * 1: enable beacon offload
1064116c6960SSean Wang * 2: update probe respond offload
1065116c6960SSean Wang */
1066116c6960SSean Wang u8 enable;
1067116c6960SSean Wang /* 0: legacy format (TXD + payload)
1068116c6960SSean Wang * 1: only cap field IE
1069116c6960SSean Wang */
1070116c6960SSean Wang u8 type;
1071116c6960SSean Wang __le16 pkt_len;
1072116c6960SSean Wang u8 pkt[512];
1073116c6960SSean Wang } __packed beacon_tlv;
1074116c6960SSean Wang } req = {
1075116c6960SSean Wang .hdr = {
1076116c6960SSean Wang .bss_idx = mvif->mt76.idx,
1077116c6960SSean Wang },
1078116c6960SSean Wang .beacon_tlv = {
1079116c6960SSean Wang .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
1080116c6960SSean Wang .len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
1081116c6960SSean Wang .enable = enable,
1082116c6960SSean Wang },
1083116c6960SSean Wang };
1084116c6960SSean Wang struct sk_buff *skb;
1085116c6960SSean Wang
1086c149d3a9SDeren Wu /* support enable/update process only
1087c149d3a9SDeren Wu * disable flow would be handled in bss stop handler automatically
1088c149d3a9SDeren Wu */
1089116c6960SSean Wang if (!enable)
1090c149d3a9SDeren Wu return -EOPNOTSUPP;
1091116c6960SSean Wang
10926e8912a5SShaul Triebitz skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);
1093116c6960SSean Wang if (!skb)
1094116c6960SSean Wang return -EINVAL;
1095116c6960SSean Wang
1096116c6960SSean Wang if (skb->len > 512 - MT_TXD_SIZE) {
1097116c6960SSean Wang dev_err(dev->mt76.dev, "beacon size limit exceed\n");
1098116c6960SSean Wang dev_kfree_skb(skb);
1099116c6960SSean Wang return -EINVAL;
1100116c6960SSean Wang }
1101116c6960SSean Wang
1102182071cdSLorenzo Bianconi mt76_connac2_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt),
11031d5af0acSFelix Fietkau skb, wcid, NULL, 0, 0, BSS_CHANGED_BEACON);
1104116c6960SSean Wang memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
1105116c6960SSean Wang req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
1106116c6960SSean Wang req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
1107116c6960SSean Wang
1108116c6960SSean Wang if (offs.cntdwn_counter_offs[0]) {
1109116c6960SSean Wang u16 csa_offs;
1110116c6960SSean Wang
1111116c6960SSean Wang csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
1112116c6960SSean Wang req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
1113116c6960SSean Wang }
1114116c6960SSean Wang dev_kfree_skb(skb);
1115116c6960SSean Wang
1116116c6960SSean Wang return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
1117116c6960SSean Wang &req, sizeof(req), true);
1118116c6960SSean Wang }
111923bdc5d8SMing Yen Hsieh
112023bdc5d8SMing Yen Hsieh static
__mt7921_mcu_set_clc(struct mt792x_dev * dev,u8 * alpha2,enum environment_cap env_cap,struct mt7921_clc * clc,u8 idx)1121975e122dSLorenzo Bianconi int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
112223bdc5d8SMing Yen Hsieh enum environment_cap env_cap,
112323bdc5d8SMing Yen Hsieh struct mt7921_clc *clc,
112423bdc5d8SMing Yen Hsieh u8 idx)
112523bdc5d8SMing Yen Hsieh {
112623bdc5d8SMing Yen Hsieh struct sk_buff *skb;
112723bdc5d8SMing Yen Hsieh struct {
112823bdc5d8SMing Yen Hsieh u8 ver;
112923bdc5d8SMing Yen Hsieh u8 pad0;
113023bdc5d8SMing Yen Hsieh __le16 len;
113123bdc5d8SMing Yen Hsieh u8 idx;
113223bdc5d8SMing Yen Hsieh u8 env;
11337176fe65SQuan Zhou u8 acpi_conf;
11347176fe65SQuan Zhou u8 pad1;
113523bdc5d8SMing Yen Hsieh u8 alpha2[2];
113623bdc5d8SMing Yen Hsieh u8 type[2];
113723bdc5d8SMing Yen Hsieh u8 rsvd[64];
113823bdc5d8SMing Yen Hsieh } __packed req = {
1139*15173a16SMing Yen Hsieh .ver = 1,
114023bdc5d8SMing Yen Hsieh .idx = idx,
114123bdc5d8SMing Yen Hsieh .env = env_cap,
114229f5a494SLorenzo Bianconi .acpi_conf = mt792x_acpi_get_flags(&dev->phy),
114323bdc5d8SMing Yen Hsieh };
114423bdc5d8SMing Yen Hsieh int ret, valid_cnt = 0;
1145*15173a16SMing Yen Hsieh u16 buf_len = 0;
1146*15173a16SMing Yen Hsieh u8 *pos;
114723bdc5d8SMing Yen Hsieh
114823bdc5d8SMing Yen Hsieh if (!clc)
114923bdc5d8SMing Yen Hsieh return 0;
115023bdc5d8SMing Yen Hsieh
1151*15173a16SMing Yen Hsieh buf_len = le16_to_cpu(clc->len) - sizeof(*clc);
115223bdc5d8SMing Yen Hsieh pos = clc->data;
1153*15173a16SMing Yen Hsieh while (buf_len > 16) {
115423bdc5d8SMing Yen Hsieh struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos;
115523bdc5d8SMing Yen Hsieh u16 len = le16_to_cpu(rule->len);
1156*15173a16SMing Yen Hsieh u16 offset = len + sizeof(*rule);
115723bdc5d8SMing Yen Hsieh
1158*15173a16SMing Yen Hsieh pos += offset;
1159*15173a16SMing Yen Hsieh buf_len -= offset;
116023bdc5d8SMing Yen Hsieh if (rule->alpha2[0] != alpha2[0] ||
116123bdc5d8SMing Yen Hsieh rule->alpha2[1] != alpha2[1])
116223bdc5d8SMing Yen Hsieh continue;
116323bdc5d8SMing Yen Hsieh
116423bdc5d8SMing Yen Hsieh memcpy(req.alpha2, rule->alpha2, 2);
116523bdc5d8SMing Yen Hsieh memcpy(req.type, rule->type, 2);
116623bdc5d8SMing Yen Hsieh
116723bdc5d8SMing Yen Hsieh req.len = cpu_to_le16(sizeof(req) + len);
116823bdc5d8SMing Yen Hsieh skb = __mt76_mcu_msg_alloc(&dev->mt76, &req,
116923bdc5d8SMing Yen Hsieh le16_to_cpu(req.len),
117023bdc5d8SMing Yen Hsieh sizeof(req), GFP_KERNEL);
117123bdc5d8SMing Yen Hsieh if (!skb)
117223bdc5d8SMing Yen Hsieh return -ENOMEM;
117323bdc5d8SMing Yen Hsieh skb_put_data(skb, rule->data, len);
117423bdc5d8SMing Yen Hsieh
117523bdc5d8SMing Yen Hsieh ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
117623bdc5d8SMing Yen Hsieh MCU_CE_CMD(SET_CLC), false);
117723bdc5d8SMing Yen Hsieh if (ret < 0)
117823bdc5d8SMing Yen Hsieh return ret;
117923bdc5d8SMing Yen Hsieh valid_cnt++;
118023bdc5d8SMing Yen Hsieh }
118123bdc5d8SMing Yen Hsieh
118223bdc5d8SMing Yen Hsieh if (!valid_cnt)
118323bdc5d8SMing Yen Hsieh return -ENOENT;
118423bdc5d8SMing Yen Hsieh
118523bdc5d8SMing Yen Hsieh return 0;
118623bdc5d8SMing Yen Hsieh }
118723bdc5d8SMing Yen Hsieh
mt7921_mcu_set_clc(struct mt792x_dev * dev,u8 * alpha2,enum environment_cap env_cap)1188975e122dSLorenzo Bianconi int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
118923bdc5d8SMing Yen Hsieh enum environment_cap env_cap)
119023bdc5d8SMing Yen Hsieh {
119178562b2cSLorenzo Bianconi struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy;
119223bdc5d8SMing Yen Hsieh int i, ret;
119323bdc5d8SMing Yen Hsieh
119423bdc5d8SMing Yen Hsieh /* submit all clc config */
119523bdc5d8SMing Yen Hsieh for (i = 0; i < ARRAY_SIZE(phy->clc); i++) {
119623bdc5d8SMing Yen Hsieh ret = __mt7921_mcu_set_clc(dev, alpha2, env_cap,
119723bdc5d8SMing Yen Hsieh phy->clc[i], i);
119823bdc5d8SMing Yen Hsieh
119923bdc5d8SMing Yen Hsieh /* If no country found, set "00" as default */
120023bdc5d8SMing Yen Hsieh if (ret == -ENOENT)
120123bdc5d8SMing Yen Hsieh ret = __mt7921_mcu_set_clc(dev, "00",
120223bdc5d8SMing Yen Hsieh ENVIRON_INDOOR,
120323bdc5d8SMing Yen Hsieh phy->clc[i], i);
120423bdc5d8SMing Yen Hsieh if (ret < 0)
120523bdc5d8SMing Yen Hsieh return ret;
120623bdc5d8SMing Yen Hsieh }
120723bdc5d8SMing Yen Hsieh return 0;
120823bdc5d8SMing Yen Hsieh }
1209c222f77fSNeil Chen
mt7921_mcu_get_temperature(struct mt792x_phy * phy)121078562b2cSLorenzo Bianconi int mt7921_mcu_get_temperature(struct mt792x_phy *phy)
12116ae39b7cSBen Greear {
1212975e122dSLorenzo Bianconi struct mt792x_dev *dev = phy->dev;
12136ae39b7cSBen Greear struct {
12146ae39b7cSBen Greear u8 ctrl_id;
12156ae39b7cSBen Greear u8 action;
12166ae39b7cSBen Greear u8 band_idx;
12176ae39b7cSBen Greear u8 rsv[5];
12186ae39b7cSBen Greear } req = {
12196ae39b7cSBen Greear .ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
12206ae39b7cSBen Greear .band_idx = phy->mt76->band_idx,
12216ae39b7cSBen Greear };
12226ae39b7cSBen Greear
12236ae39b7cSBen Greear return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
12246ae39b7cSBen Greear sizeof(req), true);
12256ae39b7cSBen Greear }
12266ae39b7cSBen Greear
mt7921_mcu_set_rxfilter(struct mt792x_dev * dev,u32 fif,u8 bit_op,u32 bit_map)1227975e122dSLorenzo Bianconi int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
1228c222f77fSNeil Chen u8 bit_op, u32 bit_map)
1229c222f77fSNeil Chen {
1230c222f77fSNeil Chen struct {
1231c222f77fSNeil Chen u8 rsv[4];
1232c222f77fSNeil Chen u8 mode;
1233c222f77fSNeil Chen u8 rsv2[3];
1234c222f77fSNeil Chen __le32 fif;
1235c222f77fSNeil Chen __le32 bit_map; /* bit_* for bitmap update */
1236c222f77fSNeil Chen u8 bit_op;
1237c222f77fSNeil Chen u8 pad[51];
1238c222f77fSNeil Chen } __packed data = {
1239c222f77fSNeil Chen .mode = fif ? 1 : 2,
1240c222f77fSNeil Chen .fif = cpu_to_le32(fif),
1241c222f77fSNeil Chen .bit_map = cpu_to_le32(bit_map),
1242c222f77fSNeil Chen .bit_op = bit_op,
1243c222f77fSNeil Chen };
1244c222f77fSNeil Chen
1245c222f77fSNeil Chen return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_RX_FILTER),
1246c222f77fSNeil Chen &data, sizeof(data), false);
1247c222f77fSNeil Chen }
1248