diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76')
75 files changed, 12012 insertions, 3203 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index 31015d2a8e7d..9ff43f1fc50d 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -24,8 +24,13 @@ config MT76x02_USB tristate select MT76_USB +config MT76_CONNAC_LIB + tristate + select MT76_CORE + source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig" +source "drivers/net/wireless/mediatek/mt76/mt7921/Kconfig" diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index e53584db0756..94efe3c29053 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_MT76_USB) += mt76-usb.o obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o +obj-$(CONFIG_MT76_CONNAC_LIB) += mt76-connac-lib.o mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ @@ -26,8 +27,11 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o +mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o + obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ obj-$(CONFIG_MT7603E) += mt7603/ obj-$(CONFIG_MT7615_COMMON) += mt7615/ obj-$(CONFIG_MT7915E) += mt7915/ +obj-$(CONFIG_MT7921E) += mt7921/ diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index e81dfaf99bcb..19098b852d0a 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -411,8 +411,12 @@ unmap: free: #ifdef CONFIG_NL80211_TESTMODE /* fix tx_done accounting on queue overflow */ - if (tx_info.skb == dev->test.tx_skb) - dev->test.tx_done--; + if (mt76_is_testmode_skb(dev, skb, &hw)) { + struct mt76_phy *phy = hw->priv; + + if (tx_info.skb == phy->test.tx_skb) + phy->test.tx_done--; + } #endif e.skb = tx_info.skb; diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 90278aeb6721..665b54c5c8ae 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -75,8 +75,8 @@ mt76_get_of_eeprom(struct mt76_dev *dev, int len) } #ifdef CONFIG_NL80211_TESTMODE - dev->test.mtd_name = devm_kstrdup(dev->dev, part, GFP_KERNEL); - dev->test.mtd_offset = offset; + dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL); + dev->test_mtd.offset = offset; #endif out_put_node: diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index a840396f2c74..696d00d1976c 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -387,9 +387,9 @@ void mt76_unregister_phy(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; - dev->phy2 = NULL; mt76_tx_status_check(dev, NULL, true); ieee80211_unregister_hw(phy->hw); + dev->phy2 = NULL; } EXPORT_SYMBOL_GPL(mt76_unregister_phy); @@ -519,10 +519,10 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) } #ifdef CONFIG_NL80211_TESTMODE - if (dev->test.state == MT76_TM_STATE_RX_FRAMES) { - dev->test.rx_stats.packets[q]++; + if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { + phy->test.rx_stats.packets[q]++; if (status->flag & RX_FLAG_FAILED_FCS_CRC) - dev->test.rx_stats.fcs_error[q]++; + phy->test.rx_stats.fcs_error[q]++; } #endif __skb_queue_tail(&dev->rx_skb[q], skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3e496a188bf0..8bf45497cfca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -81,6 +81,7 @@ enum mt76_rxq_id { MT_RXQ_MCU, MT_RXQ_MCU_WA, MT_RXQ_EXT, + MT_RXQ_EXT_WA, __MT_RXQ_MAX }; @@ -515,10 +516,10 @@ struct mt76_rx_status { }; struct mt76_testmode_ops { - int (*set_state)(struct mt76_dev *dev, enum mt76_testmode_state state); - int (*set_params)(struct mt76_dev *dev, struct nlattr **tb, + int (*set_state)(struct mt76_phy *phy, enum mt76_testmode_state state); + int (*set_params)(struct mt76_phy *phy, struct nlattr **tb, enum mt76_testmode_state new_state); - int (*dump_stats)(struct mt76_dev *dev, struct sk_buff *msg); + int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg); }; struct mt76_testmode_data { @@ -539,17 +540,20 @@ struct mt76_testmode_data { u8 tx_ltf; u8 tx_antenna_mask; + u8 tx_spe_idx; + + u8 tx_duty_cycle; + u32 tx_time; + u32 tx_ipg; u32 freq_offset; u8 tx_power[4]; u8 tx_power_control; - const char *mtd_name; - u32 mtd_offset; - u32 tx_pending; u32 tx_queued; + u16 tx_queued_limit; u32 tx_done; struct { u64 packets[__MT_RXQ_MAX]; @@ -557,6 +561,14 @@ struct mt76_testmode_data { } rx_stats; }; +struct mt76_vif { + u8 idx; + u8 omac_idx; + u8 band_idx; + u8 wmm_idx; + u8 scan_seq_num; +}; + struct mt76_phy { struct ieee80211_hw *hw; struct mt76_dev *dev; @@ -578,10 +590,16 @@ struct mt76_phy { u8 macaddr[ETH_ALEN]; - u32 vif_mask; - int txpower_cur; u8 antenna_mask; + u16 chainmask; + +#ifdef CONFIG_NL80211_TESTMODE + struct mt76_testmode_data test; +#endif + + struct delayed_work mac_work; + u8 mac_work_count; }; struct mt76_dev { @@ -622,7 +640,6 @@ struct mt76_dev { struct mt76_worker tx_worker; struct napi_struct tx_napi; - struct delayed_work mac_work; wait_queue_head_t tx_wait; struct sk_buff_head status_list; @@ -630,6 +647,8 @@ struct mt76_dev { u32 wcid_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)]; u32 wcid_phy_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)]; + u32 vif_mask; + struct mt76_wcid global_wcid; struct mt76_wcid __rcu *wcid[MT76_N_WCIDS]; @@ -646,6 +665,7 @@ struct mt76_dev { struct mt76_rate_power rate_power; + char alpha2[3]; enum nl80211_dfs_regions region; u32 debugfs_reg; @@ -661,9 +681,11 @@ struct mt76_dev { #ifdef CONFIG_NL80211_TESTMODE const struct mt76_testmode_ops *test_ops; - struct mt76_testmode_data test; + struct { + const char *name; + u32 offset; + } test_mtd; #endif - struct workqueue_struct *wq; union { @@ -931,10 +953,27 @@ static inline u8 mt76_tx_power_nss_delta(u8 nss) return nss_delta[nss - 1]; } -static inline bool mt76_testmode_enabled(struct mt76_dev *dev) +static inline bool mt76_testmode_enabled(struct mt76_phy *phy) { #ifdef CONFIG_NL80211_TESTMODE - return dev->test.state != MT76_TM_STATE_OFF; + return phy->test.state != MT76_TM_STATE_OFF; +#else + return false; +#endif +} + +static inline bool mt76_is_testmode_skb(struct mt76_dev *dev, + struct sk_buff *skb, + struct ieee80211_hw **hw) +{ +#ifdef CONFIG_NL80211_TESTMODE + if (skb == dev->phy.test.tx_skb) + *hw = dev->phy.hw; + else if (dev->phy2 && skb == dev->phy2->test.tx_skb) + *hw = dev->phy2->hw; + else + return false; + return true; #else return false; #endif @@ -1016,17 +1055,17 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, struct netlink_callback *cb, void *data, int len); -int mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state); +int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state); -static inline void mt76_testmode_reset(struct mt76_dev *dev, bool disable) +static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable) { #ifdef CONFIG_NL80211_TESTMODE enum mt76_testmode_state state = MT76_TM_STATE_IDLE; - if (disable || dev->test.state == MT76_TM_STATE_OFF) + if (disable || phy->test.state == MT76_TM_STATE_OFF) state = MT76_TM_STATE_OFF; - mt76_testmode_set_state(dev, state); + mt76_testmode_set_state(phy, state); #endif } @@ -1052,7 +1091,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, struct napi_struct *napi); void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames); -void mt76_testmode_tx_pending(struct mt76_dev *dev); +void mt76_testmode_tx_pending(struct mt76_phy *phy); void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_entry *e); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index b14e08046e20..f0b879c3eba8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -532,7 +532,7 @@ int mt7603_register_device(struct mt7603_dev *dev) spin_lock_init(&dev->sta_poll_lock); spin_lock_init(&dev->ps_lock); - INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work); + INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7603_mac_work); tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet); dev->slottime = 9; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 55095e66f2ef..cc4e7bc48294 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1631,9 +1631,13 @@ mt7603_edcca_check(struct mt7603_dev *dev) if (rssi0 > 128) rssi0 -= 256; - rssi1 = FIELD_GET(MT_AGC_41_RSSI_1, val); - if (rssi1 > 128) - rssi1 -= 256; + if (dev->mphy.antenna_mask & BIT(1)) { + rssi1 = FIELD_GET(MT_AGC_41_RSSI_1, val); + if (rssi1 > 128) + rssi1 -= 256; + } else { + rssi1 = rssi0; + } if (max(rssi0, rssi1) >= -40 && dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH) @@ -1788,7 +1792,7 @@ out: void mt7603_mac_work(struct work_struct *work) { struct mt7603_dev *dev = container_of(work, struct mt7603_dev, - mt76.mac_work.work); + mphy.mac_work.work); bool reset = false; int i, idx; @@ -1796,7 +1800,7 @@ void mt7603_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); - dev->mac_work_count++; + dev->mphy.mac_work_count++; mt76_update_survey(&dev->mt76); mt7603_edcca_check(dev); @@ -1807,7 +1811,7 @@ void mt7603_mac_work(struct work_struct *work) dev->mt76.aggr_stats[idx++] += val >> 16; } - if (dev->mac_work_count == 10) + if (dev->mphy.mac_work_count == 10) mt7603_false_cca_check(dev); if (mt7603_watchdog_check(dev, &dev->rx_pse_check, @@ -1838,17 +1842,17 @@ void mt7603_mac_work(struct work_struct *work) dev->rx_dma_idx = ~0; memset(dev->tx_dma_idx, 0xff, sizeof(dev->tx_dma_idx)); reset = true; - dev->mac_work_count = 0; + dev->mphy.mac_work_count = 0; } - if (dev->mac_work_count >= 10) - dev->mac_work_count = 0; + if (dev->mphy.mac_work_count >= 10) + dev->mphy.mac_work_count = 0; mutex_unlock(&dev->mt76.mutex); if (reset) mt7603_mac_watchdog_reset(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, msecs_to_jiffies(MT7603_WATCHDOG_TIME)); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 6d47b57cbc39..8edea1e7a602 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -17,7 +17,7 @@ mt7603_start(struct ieee80211_hw *hw) mt7603_mac_start(dev); dev->mphy.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mphy.state); - mt7603_mac_work(&dev->mt76.mac_work.work); + mt7603_mac_work(&dev->mphy.mac_work.work); return 0; } @@ -28,7 +28,7 @@ mt7603_stop(struct ieee80211_hw *hw) struct mt7603_dev *dev = hw->priv; clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); mt7603_mac_stop(dev); } @@ -44,7 +44,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mutex_lock(&dev->mt76.mutex); - mvif->idx = ffs(~dev->mphy.vif_mask) - 1; + mvif->idx = ffs(~dev->mt76.vif_mask) - 1; if (mvif->idx >= MT7603_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -65,7 +65,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; - dev->mphy.vif_mask |= BIT(mvif->idx); + dev->mt76.vif_mask |= BIT(mvif->idx); INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; @@ -105,7 +105,7 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) spin_unlock_bh(&dev->sta_poll_lock); mutex_lock(&dev->mt76.mutex); - dev->mphy.vif_mask &= ~BIT(mvif->idx); + dev->mt76.vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); } @@ -137,7 +137,7 @@ mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def) u8 bw = MT_BW_20; bool failed = false; - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); tasklet_disable(&dev->mt76.pre_tbtt_tasklet); mutex_lock(&dev->mt76.mutex); @@ -178,7 +178,7 @@ mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def) mt76_txq_schedule_all(&dev->mphy); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, msecs_to_jiffies(MT7603_WATCHDOG_TIME)); /* reset channel stats */ @@ -200,7 +200,7 @@ out: tasklet_enable(&dev->mt76.pre_tbtt_tasklet); if (failed) - mt7603_mac_work(&dev->mt76.mac_work.work); + mt7603_mac_work(&dev->mphy.mac_work.work); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 6e0a92a28b1c..b787c56fd8d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -132,8 +132,6 @@ struct mt7603_dev { spinlock_t ps_lock; - u8 mac_work_count; - u8 mcu_running; u8 ed_monitor_enabled; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index f372fb629caf..30fba36ff46b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -2,7 +2,8 @@ config MT7615_COMMON tristate - select MT76_CORE + select WANT_DEV_COREDUMP + select MT76_CONNAC_LIB config MT7615E tristate "MediaTek MT7615E and MT7663E (PCIe) support" diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 4d5e3f8b2a62..7ae48b4fa564 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -21,6 +21,20 @@ mt7615_radar_pattern_set(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_pattern, NULL, mt7615_radar_pattern_set, "%lld\n"); +static int mt7615_config(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + int ret; + + mt7615_mutex_acquire(dev); + ret = mt76_connac_mcu_chip_config(&dev->mt76); + mt7615_mutex_release(dev); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_config, NULL, mt7615_config, "%lld\n"); + static int mt7615_scs_set(void *data, u64 val) { @@ -525,6 +539,9 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_u32("rf_regidx", 0600, dir, &dev->debugfs_rf_reg); debugfs_create_file_unsafe("rf_regval", 0600, dir, dev, &fops_rf_reg); + if (is_mt7663(&dev->mt76)) + debugfs_create_file("chip_config", 0600, dir, dev, + &fops_config); if (mt76_is_sdio(&dev->mt76)) debugfs_create_devm_seqfile(dev->mt76.dev, "sched-quota", dir, mt7663s_sched_quota_read); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 3232ebd5eda6..2eab23898c77 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -161,7 +161,7 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) dev->chainmask = BIT(tx_mask) - 1; dev->mphy.antenna_mask = dev->chainmask; - dev->phy.chainmask = dev->chainmask; + dev->mphy.chainmask = dev->chainmask; } static int mt7663_eeprom_get_target_power_index(struct mt7615_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index a73b76e57c7f..571390fa4de7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -10,15 +10,16 @@ #include <linux/etherdevice.h> #include "mt7615.h" #include "mac.h" +#include "mcu.h" #include "eeprom.h" -void mt7615_phy_init(struct mt7615_dev *dev) +static void +mt7615_phy_init(struct mt7615_dev *dev) { /* disable rf low power beacon mode */ mt76_set(dev, MT_WF_PHY_WF2_RFCTRL0(0), MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN); mt76_set(dev, MT_WF_PHY_WF2_RFCTRL0(1), MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN); } -EXPORT_SYMBOL_GPL(mt7615_phy_init); static void mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) @@ -79,7 +80,8 @@ mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) } } -void mt7615_mac_init(struct mt7615_dev *dev) +static void +mt7615_mac_init(struct mt7615_dev *dev) { int i; @@ -95,7 +97,7 @@ void mt7615_mac_init(struct mt7615_dev *dev) MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | MT_TMAC_CTCR0_INS_DDLMT_EN); - mt7615_mcu_set_rts_thresh(&dev->phy, 0x92b); + mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); mt7615_mac_set_scs(&dev->phy, true); mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS, @@ -128,9 +130,9 @@ void mt7615_mac_init(struct mt7615_dev *dev) mt7615_init_mac_chain(dev, 1); } } -EXPORT_SYMBOL_GPL(mt7615_mac_init); -void mt7615_check_offload_capability(struct mt7615_dev *dev) +static void +mt7615_check_offload_capability(struct mt7615_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; @@ -162,7 +164,6 @@ void mt7615_check_offload_capability(struct mt7615_dev *dev) wiphy->max_sched_scan_reqs = 0; } } -EXPORT_SYMBOL_GPL(mt7615_check_offload_capability); bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev) { @@ -286,6 +287,16 @@ void mt7615_init_txpower(struct mt7615_dev *dev, } EXPORT_SYMBOL_GPL(mt7615_init_txpower); +void mt7615_init_work(struct mt7615_dev *dev) +{ + mt7615_mcu_set_eeprom(dev); + mt7615_mac_init(dev); + mt7615_phy_init(dev); + mt7615_mcu_del_wtbl_all(dev); + mt7615_check_offload_capability(dev); +} +EXPORT_SYMBOL_GPL(mt7615_init_work); + static void mt7615_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -296,13 +307,16 @@ mt7615_regd_notifier(struct wiphy *wiphy, struct mt7615_phy *phy = mphy->priv; struct cfg80211_chan_def *chandef = &mphy->chandef; + memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; - if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) - return; - mt7615_mutex_acquire(dev); - mt7615_dfs_init_radar_detector(phy); + + if (chandef->chan->flags & IEEE80211_CHAN_RADAR) + mt7615_dfs_init_radar_detector(phy); + if (mt7615_firmware_offload(phy->dev)) + mt76_connac_mcu_set_channel_domain(mphy); + mt7615_mutex_release(dev); } @@ -331,11 +345,12 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) } wiphy->reg_notifier = mt7615_regd_notifier; - wiphy->max_sched_scan_plan_interval = MT7615_MAX_SCHED_SCAN_INTERVAL; + wiphy->max_sched_scan_plan_interval = + MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL; wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; - wiphy->max_scan_ie_len = MT7615_SCAN_IE_LEN; - wiphy->max_sched_scan_ssids = MT7615_MAX_SCHED_SCAN_SSID; - wiphy->max_match_sets = MT7615_MAX_SCAN_MATCH; + wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; + wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; + wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; wiphy->max_sched_scan_reqs = 1; wiphy->max_scan_ssids = 4; @@ -362,9 +377,9 @@ mt7615_cap_dbdc_enable(struct mt7615_dev *dev) dev->mphy.antenna_mask = dev->chainmask >> 2; else dev->mphy.antenna_mask = dev->chainmask >> 1; - dev->phy.chainmask = dev->mphy.antenna_mask; - dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; - dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; + dev->mphy.chainmask = dev->mphy.antenna_mask; + dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; mt76_set_stream_caps(&dev->mphy, true); } @@ -375,7 +390,7 @@ mt7615_cap_dbdc_disable(struct mt7615_dev *dev) IEEE80211_VHT_CAP_SHORT_GI_160 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; dev->mphy.antenna_mask = dev->chainmask; - dev->phy.chainmask = dev->chainmask; + dev->mphy.chainmask = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; mt76_set_stream_caps(&dev->mphy, true); @@ -404,11 +419,11 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) phy = mphy->priv; phy->dev = dev; phy->mt76 = mphy; - phy->chainmask = dev->chainmask & ~dev->phy.chainmask; - mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1; + mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask; + mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1; mt7615_init_wiphy(mphy->hw); - INIT_DELAYED_WORK(&phy->mac_work, mt7615_mac_work); + INIT_DELAYED_WORK(&mphy->mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); skb_queue_head_init(&phy->scan_event_list); @@ -471,9 +486,11 @@ void mt7615_init_device(struct mt7615_dev *dev) init_completion(&dev->pm.wake_cmpl); spin_lock_init(&dev->pm.txq_lock); set_bit(MT76_STATE_PM, &dev->mphy.state); - INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work); + INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); + INIT_DELAYED_WORK(&dev->coredump.work, mt7615_coredump_work); skb_queue_head_init(&dev->phy.scan_event_list); + skb_queue_head_init(&dev->coredump.msg_list); INIT_LIST_HEAD(&dev->sta_poll_list); spin_lock_init(&dev->sta_poll_lock); init_waitqueue_head(&dev->reset_wait); @@ -488,7 +505,6 @@ void mt7615_init_device(struct mt7615_dev *dev) dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.vht_cap.cap |= - IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; mt7615_cap_dbdc_disable(dev); dev->phy.dfs_state = -1; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 0f360be0b885..59fdd0fc2ad4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -7,6 +7,7 @@ * Lorenzo Bianconi <lorenzo@kernel.org> */ +#include <linux/devcoredump.h> #include <linux/etherdevice.h> #include <linux/timekeeping.h> #include "mt7615.h" @@ -14,6 +15,7 @@ #include "../dma.h" #include "mt7615_trace.h" #include "mac.h" +#include "mcu.h" #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) @@ -186,7 +188,7 @@ mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, status->freq = ieee80211_channel_to_frequency(chfreq, status->band); } -static void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv) +static void mt7615_mac_fill_tm_rx(struct mt7615_phy *phy, __le32 *rxv) { #ifdef CONFIG_NL80211_TESTMODE u32 rxv1 = le32_to_cpu(rxv[0]); @@ -210,13 +212,13 @@ static void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv) foe = (foe * foe_const) >> 15; } - dev->test.last_freq_offset = foe; - dev->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4); - dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4); - dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4); - dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4); - dev->test.last_ib_rssi[0] = FIELD_GET(MT_RXV3_IB_RSSI, rxv3); - dev->test.last_wb_rssi[0] = FIELD_GET(MT_RXV3_WB_RSSI, rxv3); + phy->test.last_freq_offset = foe; + phy->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4); + phy->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4); + phy->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4); + phy->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4); + phy->test.last_ib_rssi[0] = FIELD_GET(MT_RXV3_IB_RSSI, rxv3); + phy->test.last_wb_rssi[0] = FIELD_GET(MT_RXV3_WB_RSSI, rxv3); #endif } @@ -326,7 +328,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) * that PHY. */ if (phy_idx < 0) { - int first_chain = ffs(phy2->chainmask) - 1; + int first_chain = ffs(phy2->mt76->chainmask) - 1; phy_idx = ((rxdg5 >> (first_chain * 8)) & 0xff) == 0; } @@ -435,7 +437,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) status->chain_signal[i]); } - mt7615_mac_fill_tm_rx(dev, rxd); + mt7615_mac_fill_tm_rx(mphy->priv, rxd); rxd += 6; if ((u8 *)rxd - skb->data >= skb->len) @@ -544,7 +546,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, u16 seqno = 0; if (vif) { - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; omac_idx = mvif->omac_idx; wmm_idx = mvif->wmm_idx; @@ -1465,7 +1467,7 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) mt7615_mac_sta_poll(dev); rcu_read_unlock(); - mt7615_pm_power_save_sched(dev); + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); mt76_worker_schedule(&dev->mt76.tx_worker); } @@ -1789,11 +1791,11 @@ void mt7615_update_channel(struct mt76_dev *mdev) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - if (mt7615_pm_wake(dev)) + if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) return; __mt7615_update_channel(dev); - mt7615_pm_power_save_sched(dev); + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt7615_update_channel); @@ -1862,97 +1864,20 @@ void mt7615_pm_wake_work(struct work_struct *work) { struct mt7615_dev *dev; struct mt76_phy *mphy; - int i; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, pm.wake_work); mphy = dev->phy.mt76; - if (mt7615_mcu_set_drv_ctrl(dev)) { + if (!mt7615_mcu_set_drv_ctrl(dev)) + mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); + else dev_err(mphy->dev->dev, "failed to wake device\n"); - goto out; - } - - spin_lock_bh(&dev->pm.txq_lock); - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - struct mt7615_sta *msta = dev->pm.tx_q[i].msta; - struct ieee80211_sta *sta = NULL; - struct mt76_wcid *wcid; - - if (!dev->pm.tx_q[i].skb) - continue; - - wcid = msta ? &msta->wcid : &dev->mt76.global_wcid; - if (msta && wcid->sta) - sta = container_of((void *)msta, struct ieee80211_sta, - drv_priv); - - mt76_tx(mphy, sta, wcid, dev->pm.tx_q[i].skb); - dev->pm.tx_q[i].skb = NULL; - } - spin_unlock_bh(&dev->pm.txq_lock); - - mt76_worker_schedule(&dev->mt76.tx_worker); -out: ieee80211_wake_queues(mphy->hw); complete_all(&dev->pm.wake_cmpl); } -int mt7615_pm_wake(struct mt7615_dev *dev) -{ - struct mt76_phy *mphy = dev->phy.mt76; - - if (!mt7615_firmware_offload(dev)) - return 0; - - if (!mt76_is_mmio(mphy->dev)) - return 0; - - if (!test_bit(MT76_STATE_PM, &mphy->state)) - return 0; - - if (test_bit(MT76_HW_SCANNING, &mphy->state) || - test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) - return 0; - - if (queue_work(dev->mt76.wq, &dev->pm.wake_work)) - reinit_completion(&dev->pm.wake_cmpl); - - if (!wait_for_completion_timeout(&dev->pm.wake_cmpl, 3 * HZ)) { - ieee80211_wake_queues(mphy->hw); - return -ETIMEDOUT; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mt7615_pm_wake); - -void mt7615_pm_power_save_sched(struct mt7615_dev *dev) -{ - struct mt76_phy *mphy = dev->phy.mt76; - - if (!mt7615_firmware_offload(dev)) - return; - - if (!mt76_is_mmio(mphy->dev)) - return; - - if (!dev->pm.enable || !test_bit(MT76_STATE_RUNNING, &mphy->state)) - return; - - dev->pm.last_activity = jiffies; - - if (test_bit(MT76_HW_SCANNING, &mphy->state) || - test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) - return; - - if (!test_bit(MT76_STATE_PM, &mphy->state)) - queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, - dev->pm.idle_timeout); -} -EXPORT_SYMBOL_GPL(mt7615_pm_power_save_sched); - void mt7615_pm_power_save_work(struct work_struct *work) { struct mt7615_dev *dev; @@ -1976,17 +1901,17 @@ out: void mt7615_mac_work(struct work_struct *work) { struct mt7615_phy *phy; - struct mt76_dev *mdev; + struct mt76_phy *mphy; - phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, - mac_work.work); - mdev = &phy->dev->mt76; + mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, + mac_work.work); + phy = mphy->priv; mt7615_mutex_acquire(phy->dev); mt7615_update_survey(phy->dev); - if (++phy->mac_work_count == 5) { - phy->mac_work_count = 0; + if (++mphy->mac_work_count == 5) { + mphy->mac_work_count = 0; mt7615_mac_update_mib_stats(phy); mt7615_mac_scs_check(phy); @@ -1994,8 +1919,8 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mutex_release(phy->dev); - mt76_tx_status_check(mdev, NULL, false); - ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, + mt76_tx_status_check(mphy->dev, NULL, false); + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7615_WATCHDOG_TIME); } @@ -2017,7 +1942,16 @@ mt7615_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) struct ieee80211_hw *hw = priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); - mt7615_mcu_add_beacon(dev, hw, vif, vif->bss_conf.enable_beacon); + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + mt7615_mcu_add_beacon(dev, hw, vif, + vif->bss_conf.enable_beacon); + break; + default: + break; + } } static void @@ -2058,6 +1992,23 @@ void mt7615_dma_reset(struct mt7615_dev *dev) } EXPORT_SYMBOL_GPL(mt7615_dma_reset); +void mt7615_tx_token_put(struct mt7615_dev *dev) +{ + struct mt76_txwi_cache *txwi; + int id; + + spin_lock_bh(&dev->token_lock); + idr_for_each_entry(&dev->token, txwi, id) { + mt7615_txp_skb_unmap(&dev->mt76, txwi); + if (txwi->skb) + dev_kfree_skb_any(txwi->skb); + mt76_put_txwi(&dev->mt76, txwi); + } + spin_unlock_bh(&dev->token_lock); + idr_destroy(&dev->token); +} +EXPORT_SYMBOL_GPL(mt7615_tx_token_put); + void mt7615_mac_reset_work(struct work_struct *work) { struct mt7615_phy *phy2; @@ -2078,11 +2029,11 @@ void mt7615_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); - cancel_delayed_work_sync(&dev->phy.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); del_timer_sync(&dev->phy.roc_timer); cancel_work_sync(&dev->phy.roc_work); if (phy2) { - cancel_delayed_work_sync(&phy2->mac_work); + cancel_delayed_work_sync(&phy2->mt76->mac_work); del_timer_sync(&phy2->roc_timer); cancel_work_sync(&phy2->roc_work); } @@ -2101,6 +2052,9 @@ void mt7615_mac_reset_work(struct work_struct *work) mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_STOPPED); + mt7615_tx_token_put(dev); + idr_init(&dev->token); + if (mt7615_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { mt7615_dma_reset(dev); @@ -2134,10 +2088,11 @@ void mt7615_mac_reset_work(struct work_struct *work) mt7615_mutex_release(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT7615_WATCHDOG_TIME); if (phy2) - ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mac_work, + ieee80211_queue_delayed_work(ext_phy->hw, + &phy2->mt76->mac_work, MT7615_WATCHDOG_TIME); } @@ -2319,3 +2274,44 @@ int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy, return 0; } + +void mt7615_coredump_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + char *dump, *data; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + coredump.work.work); + + if (time_is_after_jiffies(dev->coredump.last_activity + + 4 * MT76_CONNAC_COREDUMP_TIMEOUT)) { + queue_delayed_work(dev->mt76.wq, &dev->coredump.work, + MT76_CONNAC_COREDUMP_TIMEOUT); + return; + } + + dump = vzalloc(MT76_CONNAC_COREDUMP_SZ); + data = dump; + + while (true) { + struct sk_buff *skb; + + spin_lock_bh(&dev->mt76.lock); + skb = __skb_dequeue(&dev->coredump.msg_list); + spin_unlock_bh(&dev->mt76.lock); + + if (!skb) + break; + + skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); + if (data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) + break; + + memcpy(data, skb->data, skb->len); + data += skb->len; + + dev_kfree_skb(skb); + } + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 56dd0b4e4460..25faf486d279 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -24,22 +24,6 @@ static bool mt7615_dev_running(struct mt7615_dev *dev) return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); } -static void mt7615_free_pending_tx_skbs(struct mt7615_dev *dev, - struct mt7615_sta *msta) -{ - int i; - - spin_lock_bh(&dev->pm.txq_lock); - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (msta && dev->pm.tx_q[i].msta != msta) - continue; - - dev_kfree_skb(dev->pm.tx_q[i].skb); - dev->pm.tx_q[i].skb = NULL; - } - spin_unlock_bh(&dev->pm.txq_lock); -} - static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = mt7615_hw_dev(hw); @@ -55,22 +39,24 @@ static int mt7615_start(struct ieee80211_hw *hw) if (!running) { mt7615_mcu_set_pm(dev, 0, 0); - mt7615_mcu_set_mac_enable(dev, 0, true); + mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, true, false); mt7615_mac_enable_nf(dev, 0); } if (phy != &dev->phy) { mt7615_mcu_set_pm(dev, 1, 0); - mt7615_mcu_set_mac_enable(dev, 1, true); + mt76_connac_mcu_set_mac_enable(&dev->mt76, 1, true, false); mt7615_mac_enable_nf(dev, 1); } - mt7615_mcu_set_channel_domain(phy); + if (mt7615_firmware_offload(dev)) + mt76_connac_mcu_set_channel_domain(phy->mt76); + mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_queue_delayed_work(hw, &phy->mac_work, + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT7615_WATCHDOG_TIME); if (!running) @@ -86,30 +72,30 @@ static void mt7615_stop(struct ieee80211_hw *hw) struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); - cancel_delayed_work_sync(&phy->mac_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); cancel_delayed_work_sync(&dev->pm.ps_work); cancel_work_sync(&dev->pm.wake_work); - mt7615_free_pending_tx_skbs(dev, NULL); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt7615_mutex_acquire(dev); - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); if (phy != &dev->phy) { mt7615_mcu_set_pm(dev, 1, 1); - mt7615_mcu_set_mac_enable(dev, 1, false); + mt76_connac_mcu_set_mac_enable(&dev->mt76, 1, false, false); } if (!mt7615_dev_running(dev)) { mt7615_mcu_set_pm(dev, 0, 1); - mt7615_mcu_set_mac_enable(dev, 0, false); + mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); } mt7615_mutex_release(dev); @@ -181,14 +167,14 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, mt7615_mutex_acquire(dev); - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); if (vif->type == NL80211_IFTYPE_MONITOR && is_zero_ether_addr(vif->addr)) phy->monitor_vif = vif; - mvif->idx = ffs(~dev->mphy.vif_mask) - 1; - if (mvif->idx >= MT7615_MAX_INTERFACES) { + mvif->mt76.idx = ffs(~dev->mt76.vif_mask) - 1; + if (mvif->mt76.idx >= MT7615_MAX_INTERFACES) { ret = -ENOSPC; goto out; } @@ -198,26 +184,26 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, ret = -ENOSPC; goto out; } - mvif->omac_idx = idx; + mvif->mt76.omac_idx = idx; - mvif->band_idx = ext_phy; + mvif->mt76.band_idx = ext_phy; if (mt7615_ext_phy(dev)) - mvif->wmm_idx = ext_phy * (MT7615_MAX_WMM_SETS / 2) + - mvif->idx % (MT7615_MAX_WMM_SETS / 2); + mvif->mt76.wmm_idx = ext_phy * (MT7615_MAX_WMM_SETS / 2) + + mvif->mt76.idx % (MT7615_MAX_WMM_SETS / 2); else - mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS; + mvif->mt76.wmm_idx = mvif->mt76.idx % MT7615_MAX_WMM_SETS; - dev->mphy.vif_mask |= BIT(mvif->idx); - dev->omac_mask |= BIT_ULL(mvif->omac_idx); - phy->omac_mask |= BIT_ULL(mvif->omac_idx); + dev->mt76.vif_mask |= BIT(mvif->mt76.idx); + dev->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); + phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); mt7615_mcu_set_dbdc(dev); - idx = MT7615_WTBL_RESERVED - mvif->idx; + idx = MT7615_WTBL_RESERVED - mvif->mt76.idx; INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.ext_phy = mvif->band_idx; + mvif->sta.wcid.ext_phy = mvif->mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; mt7615_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -228,7 +214,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, mtxq->wcid = &mvif->sta.wcid; } - ret = mt7615_mcu_add_dev_info(dev, vif, true); + ret = mt7615_mcu_add_dev_info(phy, vif, true); if (ret) goto out; @@ -252,20 +238,20 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, mt7615_mutex_acquire(dev); - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); if (vif == phy->monitor_vif) phy->monitor_vif = NULL; - mt7615_free_pending_tx_skbs(dev, msta); + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); mt7615_mac_set_beacon_filter(phy, vif, false); - mt7615_mcu_add_dev_info(dev, vif, false); + mt7615_mcu_add_dev_info(phy, vif, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - dev->mphy.vif_mask &= ~BIT(mvif->idx); - dev->omac_mask &= ~BIT_ULL(mvif->omac_idx); - phy->omac_mask &= ~BIT_ULL(mvif->omac_idx); + dev->mt76.vif_mask &= ~BIT(mvif->mt76.idx); + dev->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); + phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); mt7615_mutex_release(dev); @@ -300,7 +286,7 @@ int mt7615_set_channel(struct mt7615_phy *phy) bool ext_phy = phy != &dev->phy; int ret; - cancel_delayed_work_sync(&phy->mac_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); mt7615_mutex_acquire(dev); @@ -321,7 +307,7 @@ int mt7615_set_channel(struct mt7615_phy *phy) mt7615_mac_set_timing(phy); ret = mt7615_dfs_init_radar_detector(phy); mt7615_mac_cca_stats_reset(phy); - mt7615_mcu_set_sku_en(phy, !mt76_testmode_enabled(&dev->mt76)); + mt7615_mcu_set_sku_en(phy, true); mt7615_mac_reset_counters(dev); phy->noise = 0; @@ -334,8 +320,9 @@ out: mt76_txq_schedule_all(phy->mt76); - if (!mt76_testmode_enabled(&dev->mt76)) - ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, + if (!mt76_testmode_enabled(phy->mt76)) + ieee80211_queue_delayed_work(phy->mt76->hw, + &phy->mt76->mac_work, MT7615_WATCHDOG_TIME); return ret; @@ -411,9 +398,9 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_POWER)) { #ifdef CONFIG_NL80211_TESTMODE - if (dev->mt76.test.state != MT76_TM_STATE_OFF) { + if (phy->mt76->test.state != MT76_TM_STATE_OFF) { mt7615_mutex_acquire(dev); - mt76_testmode_reset(&dev->mt76, false); + mt76_testmode_reset(phy->mt76, false); mt7615_mutex_release(dev); } #endif @@ -425,7 +412,7 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) mt7615_mutex_acquire(dev); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; @@ -444,7 +431,7 @@ static int mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); int err; @@ -480,7 +467,7 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ phy->rxfilter &= ~(_hw); \ - if (!mt76_testmode_enabled(&dev->mt76)) \ + if (!mt76_testmode_enabled(phy->mt76)) \ phy->rxfilter |= !(flags & FIF_##_flag) * (_hw);\ } while (0) @@ -541,7 +528,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON_ENABLED) { mt7615_mcu_add_bss_info(phy, vif, NULL, info->enable_beacon); - mt7615_mcu_sta_add(dev, vif, NULL, info->enable_beacon); + mt7615_mcu_sta_add(phy, vif, NULL, info->enable_beacon); if (vif->p2p && info->enable_beacon) mt7615_mcu_set_p2p_oppps(hw, vif); @@ -552,7 +539,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); if (changed & BSS_CHANGED_PS) - mt7615_mcu_set_vif_ps(dev, vif); + mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); if (changed & BSS_CHANGED_ARP_FILTER) mt7615_mcu_update_arp_filter(hw, vif, info); @@ -578,6 +565,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_phy *phy; int idx, err; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); @@ -588,23 +576,20 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; - msta->wcid.ext_phy = mvif->band_idx; + msta->wcid.ext_phy = mvif->mt76.band_idx; - err = mt7615_pm_wake(dev); + phy = mvif->mt76.band_idx ? mt7615_ext_phy(dev) : &dev->phy; + err = mt76_connac_pm_wake(phy->mt76, &dev->pm); if (err) return err; - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - struct mt7615_phy *phy; - - phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy; + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) mt7615_mcu_add_bss_info(phy, vif, sta, true); - } mt7615_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - mt7615_mcu_sta_add(dev, vif, sta, true); + mt7615_mcu_sta_add(&dev->phy, vif, sta, true); - mt7615_pm_power_save_sched(dev); + mt76_connac_power_save_sched(phy->mt76, &dev->pm); return 0; } @@ -615,27 +600,26 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_phy *phy; + + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); - mt7615_free_pending_tx_skbs(dev, msta); - mt7615_pm_wake(dev); + phy = mvif->mt76.band_idx ? mt7615_ext_phy(dev) : &dev->phy; + mt76_connac_pm_wake(phy->mt76, &dev->pm); - mt7615_mcu_sta_add(dev, vif, sta, false); + mt7615_mcu_sta_add(&dev->phy, vif, sta, false); mt7615_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct mt7615_phy *phy; - - phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy; + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) mt7615_mcu_add_bss_info(phy, vif, sta, false); - } spin_lock_bh(&dev->sta_poll_lock); if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); - mt7615_pm_power_save_sched(dev); + mt76_connac_power_save_sched(phy->mt76, &dev->pm); } EXPORT_SYMBOL_GPL(mt7615_mac_sta_remove); @@ -720,25 +704,17 @@ static void mt7615_tx(struct ieee80211_hw *hw, skb_set_queue_mapping(skb, qid); } - spin_lock_bh(&dev->pm.txq_lock); - if (!dev->pm.tx_q[qid].skb) { - ieee80211_stop_queues(hw); - dev->pm.tx_q[qid].msta = msta; - dev->pm.tx_q[qid].skb = skb; - queue_work(dev->mt76.wq, &dev->pm.wake_work); - } else { - dev_kfree_skb(skb); - } - spin_unlock_bh(&dev->pm.txq_lock); + mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); } static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); + int band = phy != &dev->phy; mt7615_mutex_acquire(dev); - mt7615_mcu_set_rts_thresh(phy, val); + mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, band); mt7615_mutex_release(dev); return 0; @@ -910,7 +886,7 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) else tx_ant <<= 1; } - phy->chainmask = tx_ant; + phy->mt76->chainmask = tx_ant; mt76_set_stream_caps(phy->mt76, true); @@ -993,8 +969,12 @@ mt7615_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_phy *mphy = hw->priv; int err; + /* fall-back to sw-scan */ + if (!mt7615_firmware_offload(dev)) + return 1; + mt7615_mutex_acquire(dev); - err = mt7615_mcu_hw_scan(mphy->priv, vif, req); + err = mt76_connac_mcu_hw_scan(mphy, vif, req); mt7615_mutex_release(dev); return err; @@ -1007,7 +987,7 @@ mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) struct mt76_phy *mphy = hw->priv; mt7615_mutex_acquire(dev); - mt7615_mcu_cancel_hw_scan(mphy->priv, vif); + mt76_connac_mcu_cancel_hw_scan(mphy, vif); mt7615_mutex_release(dev); } @@ -1020,13 +1000,16 @@ mt7615_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_phy *mphy = hw->priv; int err; + if (!mt7615_firmware_offload(dev)) + return -EOPNOTSUPP; + mt7615_mutex_acquire(dev); - err = mt7615_mcu_sched_scan_req(mphy->priv, vif, req); + err = mt76_connac_mcu_sched_scan_req(mphy, vif, req); if (err < 0) goto out; - err = mt7615_mcu_sched_scan_enable(mphy->priv, vif, true); + err = mt76_connac_mcu_sched_scan_enable(mphy, vif, true); out: mt7615_mutex_release(dev); @@ -1040,8 +1023,11 @@ mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) struct mt76_phy *mphy = hw->priv; int err; + if (!mt7615_firmware_offload(dev)) + return -EOPNOTSUPP; + mt7615_mutex_acquire(dev); - err = mt7615_mcu_sched_scan_enable(mphy->priv, vif, false); + err = mt76_connac_mcu_sched_scan_enable(mphy, vif, false); mt7615_mutex_release(dev); return err; @@ -1101,26 +1087,27 @@ static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw, static int mt7615_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { - struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt7615_dev *dev = mt7615_hw_dev(hw); int err = 0; cancel_delayed_work_sync(&dev->pm.ps_work); - mt7615_free_pending_tx_skbs(dev, NULL); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt7615_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); - cancel_delayed_work_sync(&phy->mac_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); set_bit(MT76_STATE_SUSPEND, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, - mt7615_mcu_set_suspend_iter, phy); + mt76_connac_mcu_set_suspend_iter, + phy->mt76); if (!mt7615_dev_running(dev)) - err = mt7615_mcu_set_hif_suspend(dev, true); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); mt7615_mutex_release(dev); @@ -1129,8 +1116,8 @@ static int mt7615_suspend(struct ieee80211_hw *hw, static int mt7615_resume(struct ieee80211_hw *hw) { - struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt7615_dev *dev = mt7615_hw_dev(hw); bool running; mt7615_mutex_acquire(dev); @@ -1141,7 +1128,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) if (!running) { int err; - err = mt7615_mcu_set_hif_suspend(dev, false); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); if (err < 0) { mt7615_mutex_release(dev); return err; @@ -1151,9 +1138,10 @@ static int mt7615_resume(struct ieee80211_hw *hw) clear_bit(MT76_STATE_SUSPEND, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, - mt7615_mcu_set_suspend_iter, phy); + mt76_connac_mcu_set_suspend_iter, + phy->mt76); - ieee80211_queue_delayed_work(hw, &phy->mac_work, + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT7615_WATCHDOG_TIME); mt7615_mutex_release(dev); @@ -1176,7 +1164,7 @@ static void mt7615_set_rekey_data(struct ieee80211_hw *hw, struct mt7615_dev *dev = mt7615_hw_dev(hw); mt7615_mutex_acquire(dev); - mt7615_mcu_update_gtk_rekey(hw, vif, data); + mt76_connac_mcu_update_gtk_rekey(hw, vif, data); mt7615_mutex_release(dev); } #endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index c13547841a4e..631596fc2f36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -481,29 +481,14 @@ mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb) } static void -mt7615_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct mt7615_beacon_loss_event *event = priv; - - if (mvif->idx != event->bss_idx) - return; - - if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) - return; - - ieee80211_beacon_loss(vif); -} - -static void mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb) { - struct mt7615_beacon_loss_event *event; + struct mt76_connac_beacon_loss_event *event; struct mt76_phy *mphy; u8 band_idx = 0; /* DBDC support */ skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); - event = (struct mt7615_beacon_loss_event *)skb->data; + event = (struct mt76_connac_beacon_loss_event *)skb->data; if (band_idx && dev->mt76.phy2) mphy = dev->mt76.phy2; else @@ -511,18 +496,19 @@ mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb) ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - mt7615_mcu_beacon_loss_iter, event); + mt76_connac_mcu_beacon_loss_iter, + event); } static void mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb) { - struct mt7615_mcu_bss_event *event; + struct mt76_connac_mcu_bss_event *event; struct mt76_phy *mphy; u8 band_idx = 0; /* DBDC support */ - event = (struct mt7615_mcu_bss_event *)(skb->data + - sizeof(struct mt7615_mcu_rxd)); + skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); + event = (struct mt76_connac_mcu_bss_event *)skb->data; if (band_idx && dev->mt76.phy2) mphy = dev->mt76.phy2; @@ -557,6 +543,10 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) case MCU_EVENT_BSS_ABSENCE: mt7615_mcu_bss_event(dev, skb); break; + case MCU_EVENT_COREDUMP: + mt76_connac_mcu_coredump_event(&dev->mt76, skb, + &dev->coredump); + return; default: break; } @@ -575,6 +565,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || rxd->eid == MCU_EVENT_BSS_ABSENCE || rxd->eid == MCU_EVENT_SCAN_DONE || + rxd->eid == MCU_EVENT_COREDUMP || rxd->eid == MCU_EVENT_ROC || !rxd->seq) mt7615_mcu_rx_unsolicited_event(dev, skb); @@ -582,29 +573,12 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) mt76_mcu_rx_event(&dev->mt76, skb); } -static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr, - u32 len, u32 mode) -{ - struct { - __le32 addr; - __le32 len; - __le32 mode; - } req = { - .addr = cpu_to_le32(addr), - .len = cpu_to_le32(len), - .mode = cpu_to_le32(mode), - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_TARGET_ADDRESS_LEN_REQ, - &req, sizeof(req), true); -} - static int mt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool bssid, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - u32 idx = mvif->omac_idx - REPEATER_BSSID_START; + u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START; u32 mask = dev->omac_mask >> 32 & ~BIT(idx); const u8 *addr = vif->addr; struct { @@ -636,10 +610,11 @@ mt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif, } static int -mt7615_mcu_add_dev(struct mt7615_dev *dev, struct ieee80211_vif *vif, +mt7615_mcu_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = phy->dev; struct { struct req_hdr { u8 omac_idx; @@ -657,8 +632,8 @@ mt7615_mcu_add_dev(struct mt7615_dev *dev, struct ieee80211_vif *vif, } __packed tlv; } data = { .hdr = { - .omac_idx = mvif->omac_idx, - .band_idx = mvif->band_idx, + .omac_idx = mvif->mt76.omac_idx, + .band_idx = mvif->mt76.band_idx, .tlv_num = cpu_to_le16(1), .is_tlv_append = 1, }, @@ -666,11 +641,11 @@ mt7615_mcu_add_dev(struct mt7615_dev *dev, struct ieee80211_vif *vif, .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, - .band_idx = mvif->band_idx, + .band_idx = mvif->mt76.band_idx, }, }; - if (mvif->omac_idx >= REPEATER_BSSID_START) + if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) return mt7615_mcu_muar_config(dev, vif, false, enable); memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); @@ -703,10 +678,10 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, u8 bcc_cnt; __le16 bcc_ie_pos; } __packed req = { - .omac_idx = mvif->omac_idx, + .omac_idx = mvif->mt76.omac_idx, .enable = enable, .wlan_idx = wcid->idx, - .band_idx = mvif->band_idx, + .band_idx = mvif->mt76.band_idx, }; struct sk_buff *skb; @@ -720,7 +695,7 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, return -EINVAL; } - if (mvif->band_idx) { + if (mvif->mt76.band_idx) { info = IEEE80211_SKB_CB(skb); info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; } @@ -774,86 +749,6 @@ mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) sizeof(req), true); } -static struct sk_buff * -mt7615_mcu_alloc_sta_req(struct mt7615_dev *dev, struct mt7615_vif *mvif, - struct mt7615_sta *msta) -{ - struct sta_req_hdr hdr = { - .bss_idx = mvif->idx, - .wlan_idx = msta ? msta->wcid.idx : 0, - .muar_idx = msta ? mvif->omac_idx : 0, - .is_tlv_append = 1, - }; - struct sk_buff *skb; - - skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, MT7615_STA_UPDATE_MAX_SIZE); - if (!skb) - return ERR_PTR(-ENOMEM); - - skb_put_data(skb, &hdr, sizeof(hdr)); - - return skb; -} - -static struct wtbl_req_hdr * -mt7615_mcu_alloc_wtbl_req(struct mt7615_dev *dev, struct mt7615_sta *msta, - int cmd, void *sta_wtbl, struct sk_buff **skb) -{ - struct tlv *sta_hdr = sta_wtbl; - struct wtbl_req_hdr hdr = { - .wlan_idx = msta->wcid.idx, - .operation = cmd, - }; - struct sk_buff *nskb = *skb; - - if (!nskb) { - nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL, - MT7615_WTBL_UPDATE_BA_SIZE); - if (!nskb) - return ERR_PTR(-ENOMEM); - - *skb = nskb; - } - - if (sta_hdr) - sta_hdr->len = cpu_to_le16(sizeof(hdr)); - - return skb_put_data(nskb, &hdr, sizeof(hdr)); -} - -static struct tlv * -mt7615_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, - void *sta_ntlv, void *sta_wtbl) -{ - struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; - struct tlv *sta_hdr = sta_wtbl; - struct tlv *ptlv, tlv = { - .tag = cpu_to_le16(tag), - .len = cpu_to_le16(len), - }; - u16 ntlv; - - ptlv = skb_put(skb, len); - memcpy(ptlv, &tlv, sizeof(tlv)); - - ntlv = le16_to_cpu(ntlv_hdr->tlv_num); - ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); - - if (sta_hdr) { - u16 size = le16_to_cpu(sta_hdr->len); - - sta_hdr->len = cpu_to_le16(size + len); - } - - return ptlv; -} - -static struct tlv * -mt7615_mcu_add_tlv(struct sk_buff *skb, int tag, int len) -{ - return mt7615_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); -} - static int mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) @@ -864,7 +759,7 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, u8 wlan_idx = mvif->sta.wcid.idx; struct tlv *tlv; - tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); + tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: @@ -893,7 +788,7 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, bss->network_type = cpu_to_le32(type); bss->dtim_period = vif->bss_conf.dtim_period; bss->bmc_tx_wlan_idx = wlan_idx; - bss->wmm_idx = mvif->wmm_idx; + bss->wmm_idx = mvif->mt76.wmm_idx; bss->active = enable; return 0; @@ -903,12 +798,12 @@ static void mt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + u8 omac_idx = mvif->mt76.omac_idx; struct bss_info_omac *omac; struct tlv *tlv; u32 type = 0; - u8 idx; - tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); + tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: @@ -933,11 +828,10 @@ mt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) } omac = (struct bss_info_omac *)tlv; - idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; omac->conn_type = cpu_to_le32(type); - omac->omac_idx = mvif->omac_idx; - omac->band_idx = mvif->band_idx; - omac->hw_bss_idx = idx; + omac->omac_idx = mvif->mt76.omac_idx; + omac->band_idx = mvif->mt76.band_idx; + omac->hw_bss_idx = omac_idx > EXT_BSSID_START ? HW_BSSID_0 : omac_idx; } /* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */ @@ -949,304 +843,17 @@ mt7615_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7615_vif *mvif) int ext_bss_idx, tsf_offset; struct tlv *tlv; - ext_bss_idx = mvif->omac_idx - EXT_BSSID_START; + ext_bss_idx = mvif->mt76.omac_idx - EXT_BSSID_START; if (ext_bss_idx < 0) return; - tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext)); + tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext)); ext = (struct bss_info_ext_bss *)tlv; tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME; ext->mbss_tsf_offset = cpu_to_le32(tsf_offset); } -static void -mt7615_mcu_sta_ba_tlv(struct sk_buff *skb, - struct ieee80211_ampdu_params *params, - bool enable, bool tx) -{ - struct sta_rec_ba *ba; - struct tlv *tlv; - - tlv = mt7615_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); - - ba = (struct sta_rec_ba *)tlv; - ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT, - ba->winsize = cpu_to_le16(params->buf_size); - ba->ssn = cpu_to_le16(params->ssn); - ba->ba_en = enable << params->tid; - ba->amsdu = params->amsdu; - ba->tid = params->tid; -} - -static void -mt7615_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) -{ - struct sta_rec_basic *basic; - struct tlv *tlv; - int conn_type; - - tlv = mt7615_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); - - basic = (struct sta_rec_basic *)tlv; - basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); - - if (enable) { - basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); - basic->conn_state = CONN_STATE_PORT_SECURE; - } else { - basic->conn_state = CONN_STATE_DISCONNECT; - } - - if (!sta) { - basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); - eth_broadcast_addr(basic->peer_addr); - return; - } - - switch (vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_AP: - if (vif->p2p) - conn_type = CONNECTION_P2P_GC; - else - conn_type = CONNECTION_INFRA_STA; - basic->conn_type = cpu_to_le32(conn_type); - basic->aid = cpu_to_le16(sta->aid); - break; - case NL80211_IFTYPE_STATION: - if (vif->p2p) - conn_type = CONNECTION_P2P_GO; - else - conn_type = CONNECTION_INFRA_AP; - basic->conn_type = cpu_to_le32(conn_type); - basic->aid = cpu_to_le16(vif->bss_conf.aid); - break; - case NL80211_IFTYPE_ADHOC: - basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); - basic->aid = cpu_to_le16(sta->aid); - break; - default: - WARN_ON(1); - break; - } - - memcpy(basic->peer_addr, sta->addr, ETH_ALEN); - basic->qos = sta->wme; -} - -static void -mt7615_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) -{ - struct tlv *tlv; - - if (sta->ht_cap.ht_supported) { - struct sta_rec_ht *ht; - - tlv = mt7615_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); - ht = (struct sta_rec_ht *)tlv; - ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); - } - if (sta->vht_cap.vht_supported) { - struct sta_rec_vht *vht; - - tlv = mt7615_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); - vht = (struct sta_rec_vht *)tlv; - vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; - vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; - vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); - } -} - -static void -mt7615_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct sta_rec_uapsd *uapsd; - struct tlv *tlv; - - if (vif->type != NL80211_IFTYPE_AP || !sta->wme) - return; - - tlv = mt7615_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); - uapsd = (struct sta_rec_uapsd *)tlv; - - if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { - uapsd->dac_map |= BIT(3); - uapsd->tac_map |= BIT(3); - } - if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { - uapsd->dac_map |= BIT(2); - uapsd->tac_map |= BIT(2); - } - if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { - uapsd->dac_map |= BIT(1); - uapsd->tac_map |= BIT(1); - } - if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { - uapsd->dac_map |= BIT(0); - uapsd->tac_map |= BIT(0); - } - uapsd->max_sp = sta->max_sp; -} - -static void -mt7615_mcu_wtbl_ba_tlv(struct sk_buff *skb, - struct ieee80211_ampdu_params *params, - bool enable, bool tx, void *sta_wtbl, - void *wtbl_tlv) -{ - struct wtbl_ba *ba; - struct tlv *tlv; - - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), - wtbl_tlv, sta_wtbl); - - ba = (struct wtbl_ba *)tlv; - ba->tid = params->tid; - - if (tx) { - ba->ba_type = MT_BA_TYPE_ORIGINATOR; - ba->sn = enable ? cpu_to_le16(params->ssn) : 0; - ba->ba_winsize = cpu_to_le16(params->buf_size); - ba->ba_en = enable; - } else { - memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); - ba->ba_type = MT_BA_TYPE_RECIPIENT; - ba->rst_ba_tid = params->tid; - ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; - ba->rst_ba_sb = 1; - } - - if (enable && tx) { - u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 }; - int i; - - for (i = 7; i > 0; i--) { - if (params->buf_size >= ba_range[i]) - break; - } - ba->ba_winsize_idx = i; - } -} - -static void -mt7615_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, void *sta_wtbl, - void *wtbl_tlv) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct wtbl_generic *generic; - struct wtbl_rx *rx; - struct wtbl_spe *spe; - struct tlv *tlv; - - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), - wtbl_tlv, sta_wtbl); - - generic = (struct wtbl_generic *)tlv; - - if (sta) { - if (vif->type == NL80211_IFTYPE_STATION) - generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); - else - generic->partial_aid = cpu_to_le16(sta->aid); - memcpy(generic->peer_addr, sta->addr, ETH_ALEN); - generic->muar_idx = mvif->omac_idx; - generic->qos = sta->wme; - } else { - eth_broadcast_addr(generic->peer_addr); - generic->muar_idx = 0xe; - } - - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), - wtbl_tlv, sta_wtbl); - - rx = (struct wtbl_rx *)tlv; - rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; - rx->rca2 = 1; - rx->rv = 1; - - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_SPE, sizeof(*spe), - wtbl_tlv, sta_wtbl); - spe = (struct wtbl_spe *)tlv; - spe->spe_idx = 24; -} - -static void -mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, - void *sta_wtbl, void *wtbl_tlv) -{ - struct tlv *tlv; - struct wtbl_ht *ht = NULL; - u32 flags = 0; - - if (sta->ht_cap.ht_supported) { - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), - wtbl_tlv, sta_wtbl); - ht = (struct wtbl_ht *)tlv; - ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING); - ht->af = sta->ht_cap.ampdu_factor; - ht->mm = sta->ht_cap.ampdu_density; - ht->ht = 1; - - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) - flags |= MT_WTBL_W5_SHORT_GI_20; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) - flags |= MT_WTBL_W5_SHORT_GI_40; - } - - if (sta->vht_cap.vht_supported) { - struct wtbl_vht *vht; - u8 af; - - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), - wtbl_tlv, sta_wtbl); - vht = (struct wtbl_vht *)tlv; - vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); - vht->vht = 1; - - af = (sta->vht_cap.cap & - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; - - if (ht) - ht->af = max(ht->af, af); - - if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) - flags |= MT_WTBL_W5_SHORT_GI_80; - if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) - flags |= MT_WTBL_W5_SHORT_GI_160; - } - - /* wtbl smps */ - if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) { - struct wtbl_smps *smps; - - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), - wtbl_tlv, sta_wtbl); - smps = (struct wtbl_smps *)tlv; - smps->smps = 1; - } - - if (sta->ht_cap.ht_supported) { - /* sgi */ - u32 msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 | - MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160; - struct wtbl_raw *raw; - - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_RAW_DATA, - sizeof(*raw), wtbl_tlv, - sta_wtbl); - raw = (struct wtbl_raw *)tlv; - raw->val = cpu_to_le32(flags); - raw->msk = cpu_to_le32(~msk); - raw->wtbl_idx = 1; - raw->dw = 5; - } -} - static int mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) @@ -1255,10 +862,10 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct mt7615_dev *dev = phy->dev; struct sk_buff *skb; - if (mvif->omac_idx >= REPEATER_BSSID_START) + if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) mt7615_mcu_muar_config(dev, vif, true, enable); - skb = mt7615_mcu_alloc_sta_req(dev, mvif, NULL); + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1267,8 +874,8 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, mt7615_mcu_bss_basic_tlv(skb, vif, sta, enable); - if (enable && mvif->omac_idx >= EXT_BSSID_START && - mvif->omac_idx < REPEATER_BSSID_START) + if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START && + mvif->mt76.omac_idx < REPEATER_BSSID_START) mt7615_mcu_bss_ext_tlv(skb, mvif); return mt76_mcu_skb_send_msg(&dev->mt76, skb, @@ -1286,22 +893,25 @@ mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev, struct sk_buff *skb = NULL; int err; - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb); + 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); - mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, NULL, wtbl_hdr); + mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, true, + NULL, wtbl_hdr); err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, true); if (err < 0) return err; - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7615_mcu_sta_ba_tlv(skb, params, enable, true); + mt76_connac_mcu_sta_ba_tlv(skb, params, enable, true); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_STA_REC_UPDATE, true); @@ -1318,11 +928,12 @@ mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev, struct sk_buff *skb; int err; - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7615_mcu_sta_ba_tlv(skb, params, enable, false); + mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false); err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_STA_REC_UPDATE, true); @@ -1330,47 +941,52 @@ mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev, return err; skb = NULL; - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb); + 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); - mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, NULL, wtbl_hdr); + mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false, + NULL, wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, true); } static int -mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, +mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct sk_buff *skb, *sskb, *wskb = NULL; + struct mt7615_dev *dev = phy->dev; struct wtbl_req_hdr *wtbl_hdr; struct mt7615_sta *msta; int cmd, err; msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; - sskb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); + sskb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + &msta->wcid); if (IS_ERR(sskb)) return PTR_ERR(sskb); - mt7615_mcu_sta_basic_tlv(sskb, vif, sta, enable); - if (enable && sta) { - mt7615_mcu_sta_ht_tlv(sskb, sta); - mt7615_mcu_sta_uapsd(sskb, vif, sta); - } + mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable); + if (enable && sta) + mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, - NULL, &wskb); + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, + WTBL_RESET_AND_SET, NULL, + &wskb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); if (enable) { - mt7615_mcu_wtbl_generic_tlv(wskb, vif, sta, NULL, wtbl_hdr); + mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, wskb, vif, sta, + NULL, wtbl_hdr); if (sta) - mt7615_mcu_wtbl_ht_tlv(wskb, sta, NULL, wtbl_hdr); + mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta, + NULL, wtbl_hdr); } cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE; @@ -1413,17 +1029,19 @@ mt7615_mcu_sta_ba(struct mt7615_dev *dev, struct tlv *sta_wtbl; struct sk_buff *skb; - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7615_mcu_sta_ba_tlv(skb, params, enable, tx); + mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); - sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, - &skb); - mt7615_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, + WTBL_SET, sta_wtbl, &skb); + mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, tx, + sta_wtbl, wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_STA_REC_UPDATE, true); @@ -1446,46 +1064,22 @@ mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev, } static int -mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable, int cmd) +__mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable, int cmd) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct wtbl_req_hdr *wtbl_hdr; - struct mt7615_sta *msta; - struct tlv *sta_wtbl; - struct sk_buff *skb; - - msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; - - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); - if (IS_ERR(skb)) - return PTR_ERR(skb); + struct mt76_wcid *wcid; - mt7615_mcu_sta_basic_tlv(skb, vif, sta, enable); - if (enable && sta) { - mt7615_mcu_sta_ht_tlv(skb, sta); - mt7615_mcu_sta_uapsd(skb, vif, sta); - } - - sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); - - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, - sta_wtbl, &skb); - if (enable) { - mt7615_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); - if (sta) - mt7615_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); - } - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); + wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid; + return mt76_connac_mcu_add_sta_cmd(phy, vif, sta, wcid, enable, cmd); } static int -mt7615_mcu_add_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif, +mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { - return mt7615_mcu_add_sta_cmd(dev, vif, sta, enable, - MCU_EXT_CMD_STA_REC_UPDATE); + return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, + MCU_EXT_CMD_STA_REC_UPDATE); } static const struct mt7615_mcu_ops sta_update_ops = { @@ -1501,247 +1095,12 @@ static const struct mt7615_mcu_ops sta_update_ops = { }; static int -mt7615_mcu_uni_add_dev(struct mt7615_dev *dev, - struct ieee80211_vif *vif, bool enable) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct { - struct { - u8 omac_idx; - u8 band_idx; - __le16 pad; - } __packed hdr; - struct req_tlv { - __le16 tag; - __le16 len; - u8 active; - u8 pad; - u8 omac_addr[ETH_ALEN]; - } __packed tlv; - } dev_req = { - .hdr = { - .omac_idx = mvif->omac_idx, - .band_idx = mvif->band_idx, - }, - .tlv = { - .tag = cpu_to_le16(DEV_INFO_ACTIVE), - .len = cpu_to_le16(sizeof(struct req_tlv)), - .active = enable, - }, - }; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct mt7615_bss_basic_tlv basic; - } basic_req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .basic = { - .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), - .len = cpu_to_le16(sizeof(struct mt7615_bss_basic_tlv)), - .omac_idx = mvif->omac_idx, - .band_idx = mvif->band_idx, - .wmm_idx = mvif->wmm_idx, - .active = enable, - .bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx), - .sta_idx = cpu_to_le16(mvif->sta.wcid.idx), - .conn_state = 1, - }, - }; - int err, idx, cmd, len; - void *data; - - switch (vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_AP: - basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); - break; - case NL80211_IFTYPE_STATION: - basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); - break; - case NL80211_IFTYPE_ADHOC: - basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); - break; - default: - WARN_ON(1); - break; - } - - idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; - basic_req.basic.hw_bss_idx = idx; - - memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); - - cmd = enable ? MCU_UNI_CMD_DEV_INFO_UPDATE : MCU_UNI_CMD_BSS_INFO_UPDATE; - data = enable ? (void *)&dev_req : (void *)&basic_req; - len = enable ? sizeof(dev_req) : sizeof(basic_req); - - err = mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); - if (err < 0) - return err; - - cmd = enable ? MCU_UNI_CMD_BSS_INFO_UPDATE : MCU_UNI_CMD_DEV_INFO_UPDATE; - data = enable ? (void *)&basic_req : (void *)&dev_req; - len = enable ? sizeof(basic_req) : sizeof(dev_req); - - return mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); -} - -static int mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) { return 0; } static int -mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct cfg80211_chan_def *chandef = &phy->mt76->chandef; - int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; - struct mt7615_dev *dev = phy->dev; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct mt7615_bss_basic_tlv basic; - struct mt7615_bss_qos_tlv qos; - } basic_req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .basic = { - .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), - .len = cpu_to_le16(sizeof(struct mt7615_bss_basic_tlv)), - .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), - .dtim_period = vif->bss_conf.dtim_period, - .omac_idx = mvif->omac_idx, - .band_idx = mvif->band_idx, - .wmm_idx = mvif->wmm_idx, - .active = true, /* keep bss deactivated */ - .phymode = 0x38, - }, - .qos = { - .tag = cpu_to_le16(UNI_BSS_INFO_QBSS), - .len = cpu_to_le16(sizeof(struct mt7615_bss_qos_tlv)), - .qos = vif->bss_conf.qos, - }, - }; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct rlm_tlv { - __le16 tag; - __le16 len; - u8 control_channel; - u8 center_chan; - u8 center_chan2; - u8 bw; - u8 tx_streams; - u8 rx_streams; - u8 short_st; - u8 ht_op_info; - u8 sco; - u8 pad[3]; - } __packed rlm; - } __packed rlm_req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .rlm = { - .tag = cpu_to_le16(UNI_BSS_INFO_RLM), - .len = cpu_to_le16(sizeof(struct rlm_tlv)), - .control_channel = chandef->chan->hw_value, - .center_chan = ieee80211_frequency_to_channel(freq1), - .center_chan2 = ieee80211_frequency_to_channel(freq2), - .tx_streams = hweight8(phy->mt76->antenna_mask), - .rx_streams = phy->chainmask, - .short_st = true, - }, - }; - int err, conn_type; - u8 idx; - - idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; - basic_req.basic.hw_bss_idx = idx; - - switch (vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_AP: - if (vif->p2p) - conn_type = CONNECTION_P2P_GO; - else - conn_type = CONNECTION_INFRA_AP; - basic_req.basic.conn_type = cpu_to_le32(conn_type); - break; - case NL80211_IFTYPE_STATION: - if (vif->p2p) - conn_type = CONNECTION_P2P_GC; - else - conn_type = CONNECTION_INFRA_STA; - basic_req.basic.conn_type = cpu_to_le32(conn_type); - break; - case NL80211_IFTYPE_ADHOC: - basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); - break; - default: - WARN_ON(1); - break; - } - - memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); - basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx); - basic_req.basic.sta_idx = cpu_to_le16(mvif->sta.wcid.idx); - basic_req.basic.conn_state = !enable; - - err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, - &basic_req, sizeof(basic_req), true); - if (err < 0) - return err; - - switch (chandef->width) { - case NL80211_CHAN_WIDTH_40: - rlm_req.rlm.bw = CMD_CBW_40MHZ; - break; - case NL80211_CHAN_WIDTH_80: - rlm_req.rlm.bw = CMD_CBW_80MHZ; - break; - case NL80211_CHAN_WIDTH_80P80: - rlm_req.rlm.bw = CMD_CBW_8080MHZ; - break; - case NL80211_CHAN_WIDTH_160: - rlm_req.rlm.bw = CMD_CBW_160MHZ; - break; - case NL80211_CHAN_WIDTH_5: - rlm_req.rlm.bw = CMD_CBW_5MHZ; - break; - case NL80211_CHAN_WIDTH_10: - rlm_req.rlm.bw = CMD_CBW_10MHZ; - break; - case NL80211_CHAN_WIDTH_20_NOHT: - case NL80211_CHAN_WIDTH_20: - default: - rlm_req.rlm.bw = CMD_CBW_20MHZ; - break; - } - - if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan) - rlm_req.rlm.sco = 1; /* SCA */ - else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan) - rlm_req.rlm.sco = 3; /* SCB */ - - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, - &rlm_req, sizeof(rlm_req), true); -} - -static int mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1775,7 +1134,7 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, } __packed beacon_tlv; } req = { .hdr = { - .bss_idx = mvif->idx, + .bss_idx = mvif->mt76.idx, }, .beacon_tlv = { .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), @@ -1814,44 +1173,42 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, } static int -mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev, - struct ieee80211_ampdu_params *params, - bool enable) +mt7615_mcu_uni_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif, + bool enable) { - struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; - struct mt7615_vif *mvif = msta->vif; - struct wtbl_req_hdr *wtbl_hdr; - struct tlv *sta_wtbl; - struct sk_buff *skb; - int err; - - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, - &skb); - if (IS_ERR(wtbl_hdr)) - return PTR_ERR(wtbl_hdr); + return mt76_connac_mcu_uni_add_dev(phy->mt76, vif, &mvif->sta.wcid, + enable); +} - mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, sta_wtbl, - wtbl_hdr); +static int +mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - err = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_UNI_CMD_STA_REC_UPDATE, true); - if (err < 0) - return err; + return mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, + enable); +} - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); - if (IS_ERR(skb)) - return PTR_ERR(skb); +static inline int +mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ + return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, + MCU_UNI_CMD_STA_REC_UPDATE); +} - mt7615_mcu_sta_ba_tlv(skb, params, enable, true); +static int +mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable) +{ + struct mt7615_sta *sta = (struct mt7615_sta *)params->sta->drv_priv; - return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_UNI_CMD_STA_REC_UPDATE, true); + return mt76_connac_mcu_sta_ba(&dev->mt76, &sta->vif->mt76, params, + enable, true); } static int @@ -1866,43 +1223,38 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev, struct sk_buff *skb; int err; - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7615_mcu_sta_ba_tlv(skb, params, enable, false); + mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false); err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_STA_REC_UPDATE, true); if (err < 0 || !enable) return err; - skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); - sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, + sizeof(struct tlv)); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, - &skb); + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, + WTBL_SET, sta_wtbl, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); - mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, sta_wtbl, - wtbl_hdr); + mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false, + sta_wtbl, wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_STA_REC_UPDATE, true); } -static int -mt7615_mcu_uni_add_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) -{ - return mt7615_mcu_add_sta_cmd(dev, vif, sta, enable, - MCU_UNI_CMD_STA_REC_UPDATE); -} - static const struct mt7615_mcu_ops uni_update_ops = { .add_beacon_offload = mt7615_mcu_uni_add_beacon_offload, .set_pm_state = mt7615_mcu_uni_ctrl_pm_state, @@ -1915,59 +1267,19 @@ static const struct mt7615_mcu_ops uni_update_ops = { .set_fw_ctrl = mt7615_mcu_fw_pmctrl, }; -static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr, - u32 option) -{ - struct { - __le32 option; - __le32 addr; - } req = { - .option = cpu_to_le32(option), - .addr = cpu_to_le32(addr), - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_START_REQ, &req, - sizeof(req), true); -} - int mt7615_mcu_restart(struct mt76_dev *dev) { return mt76_mcu_send_msg(dev, MCU_CMD_RESTART_DL_REQ, NULL, 0, true); } EXPORT_SYMBOL_GPL(mt7615_mcu_restart); -static int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get) -{ - struct { - __le32 op; - } req = { - .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_SEM_CONTROL, &req, - sizeof(req), true); -} - -static int mt7615_mcu_start_patch(struct mt7615_dev *dev) -{ - struct { - u8 check_crc; - u8 reserved[3]; - } req = { - .check_crc = 0, - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_FINISH_REQ, &req, - sizeof(req), true); -} - static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name) { const struct mt7615_patch_hdr *hdr; const struct firmware *fw = NULL; int len, ret, sem; - sem = mt7615_mcu_patch_sem_ctrl(dev, 1); + sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); switch (sem) { case PATCH_IS_DL: return 0; @@ -1995,7 +1307,8 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name) len = fw->size - sizeof(*hdr); - ret = mt7615_mcu_init_download(dev, addr, len, DL_MODE_NEED_RSP); + ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, + DL_MODE_NEED_RSP); if (ret) { dev_err(dev->mt76.dev, "Download request failed\n"); goto out; @@ -2008,14 +1321,14 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name) goto out; } - ret = mt7615_mcu_start_patch(dev); + ret = mt76_connac_mcu_start_patch(&dev->mt76); if (ret) dev_err(dev->mt76.dev, "Failed to start patch\n"); out: release_firmware(fw); - sem = mt7615_mcu_patch_sem_ctrl(dev, 0); + sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); switch (sem) { case PATCH_REL_SEM_SUCCESS: break; @@ -2056,7 +1369,8 @@ mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN; addr = le32_to_cpu(hdr[i].addr); - err = mt7615_mcu_init_download(dev, addr, len, mode); + err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, + mode); if (err) { dev_err(dev->mt76.dev, "Download request failed\n"); return err; @@ -2075,15 +1389,6 @@ mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, return 0; } -static const struct wiphy_wowlan_support mt7615_wowlan_support = { - .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT, - .n_patterns = 1, - .pattern_min_len = 1, - .pattern_max_len = MT7615_WOW_PATTEN_MAX_LEN, - .max_nd_match_sets = 10, -}; - static int mt7615_load_n9(struct mt7615_dev *dev, const char *name) { const struct mt7615_fw_trailer *hdr; @@ -2110,8 +1415,9 @@ static int mt7615_load_n9(struct mt7615_dev *dev, const char *name) if (ret) goto out; - ret = mt7615_mcu_start_firmware(dev, le32_to_cpu(hdr->addr), - FW_START_OVERRIDE); + ret = mt76_connac_mcu_start_firmware(&dev->mt76, + le32_to_cpu(hdr->addr), + FW_START_OVERRIDE); if (ret) { dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); goto out; @@ -2161,7 +1467,8 @@ static int mt7615_load_cr4(struct mt7615_dev *dev, const char *name) if (ret) goto out; - ret = mt7615_mcu_start_firmware(dev, 0, FW_START_WORKING_PDA_CR4); + ret = mt76_connac_mcu_start_firmware(&dev->mt76, 0, + FW_START_WORKING_PDA_CR4); if (ret) { dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n"); goto out; @@ -2298,7 +1605,8 @@ static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) addr = le32_to_cpu(buf->img_dest_addr); len = le32_to_cpu(buf->img_size); - ret = mt7615_mcu_init_download(dev, addr, len, mode); + ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, + mode); if (ret) { dev_err(dev->mt76.dev, "Download request failed\n"); goto out; @@ -2325,7 +1633,7 @@ static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n", override_addr, flag); - ret = mt7615_mcu_start_firmware(dev, override_addr, flag); + ret = mt76_connac_mcu_start_firmware(&dev->mt76, override_addr, flag); if (ret) { dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); goto out; @@ -2410,7 +1718,7 @@ int __mt7663_load_firmware(struct mt7615_dev *dev) #ifdef CONFIG_PM if (mt7615_firmware_offload(dev)) - dev->mt76.hw->wiphy->wowlan = &mt7615_wowlan_support; + dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; #endif /* CONFIG_PM */ dev_dbg(dev->mt76.dev, "Firmware init done\n"); @@ -2522,42 +1830,6 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev) return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_EFUSE_BUFFER_MODE, true); } -EXPORT_SYMBOL_GPL(mt7615_mcu_set_eeprom); - -int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable) -{ - struct { - u8 enable; - u8 band; - u8 rsv[2]; - } __packed req = { - .enable = enable, - .band = band, - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, &req, - sizeof(req), true); -} - -int mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val) -{ - struct mt7615_dev *dev = phy->dev; - struct { - u8 prot_idx; - u8 band; - u8 rsv[2]; - __le32 len_thresh; - __le32 pkt_thresh; - } __packed req = { - .prot_idx = 1, - .band = phy != &dev->phy, - .len_thresh = cpu_to_le32(val), - .pkt_thresh = cpu_to_le32(0x2), - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, &req, - sizeof(req), true); -} int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, const struct ieee80211_tx_queue_params *params) @@ -2664,7 +1936,6 @@ int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev) return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, &req, sizeof(req), true); } -EXPORT_SYMBOL_GPL(mt7615_mcu_del_wtbl_all); int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev, enum mt7615_rdd_cmd cmd, u8 index, @@ -2880,7 +2151,7 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) .control_chan = chandef->chan->hw_value, .center_chan = ieee80211_frequency_to_channel(freq1), .tx_streams = hweight8(phy->mt76->antenna_mask), - .rx_streams_mask = phy->chainmask, + .rx_streams_mask = phy->mt76->chainmask, .center_chan2 = ieee80211_frequency_to_channel(freq2), }; @@ -2895,7 +2166,7 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) req.band_idx = phy != &dev->phy; req.bw = mt7615_mcu_chan_bw(chandef); - if (mt76_testmode_enabled(&dev->mt76)) + if (mt76_testmode_enabled(phy->mt76)) memset(req.txpower_sku, 0x3f, 49); else mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); @@ -2956,296 +2227,6 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable) sizeof(req), true); } -int mt7615_mcu_set_vif_ps(struct mt7615_dev *dev, struct ieee80211_vif *vif) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct { - u8 bss_idx; - u8 ps_state; /* 0: device awake - * 1: static power save - * 2: dynamic power saving - */ - } req = { - .bss_idx = mvif->idx, - .ps_state = vif->bss_conf.ps ? 2 : 0, - }; - - if (vif->type != NL80211_IFTYPE_STATION) - return -ENOTSUPP; - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_PS_PROFILE, &req, - sizeof(req), false); -} - -int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) -{ - struct mt76_phy *mphy = phy->mt76; - struct mt7615_dev *dev = phy->dev; - struct mt7615_mcu_channel_domain { - __le32 country_code; /* regulatory_request.alpha2 */ - u8 bw_2g; /* BW_20_40M 0 - * BW_20M 1 - * BW_20_40_80M 2 - * BW_20_40_80_160M 3 - * BW_20_40_80_8080M 4 - */ - u8 bw_5g; - __le16 pad; - u8 n_2ch; - u8 n_5ch; - __le16 pad2; - } __packed hdr = { - .bw_2g = 0, - .bw_5g = 3, - .n_2ch = mphy->sband_2g.sband.n_channels, - .n_5ch = mphy->sband_5g.sband.n_channels, - }; - struct mt7615_mcu_chan { - __le16 hw_value; - __le16 pad; - __le32 flags; - } __packed; - int i, n_channels = hdr.n_2ch + hdr.n_5ch; - int len = sizeof(hdr) + n_channels * sizeof(struct mt7615_mcu_chan); - struct sk_buff *skb; - - if (!mt7615_firmware_offload(dev)) - return 0; - - skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); - if (!skb) - return -ENOMEM; - - skb_put_data(skb, &hdr, sizeof(hdr)); - - for (i = 0; i < n_channels; i++) { - struct ieee80211_channel *chan; - struct mt7615_mcu_chan channel; - - if (i < hdr.n_2ch) - chan = &mphy->sband_2g.sband.channels[i]; - else - chan = &mphy->sband_5g.sband.channels[i - hdr.n_2ch]; - - channel.hw_value = cpu_to_le16(chan->hw_value); - channel.flags = cpu_to_le32(chan->flags); - channel.pad = 0; - - skb_put_data(skb, &channel, sizeof(channel)); - } - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SET_CHAN_DOMAIN, - false); -} - -#define MT7615_SCAN_CHANNEL_TIME 60 -int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_scan_request *scan_req) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct cfg80211_scan_request *sreq = &scan_req->req; - int n_ssids = 0, err, i, duration = MT7615_SCAN_CHANNEL_TIME; - int ext_channels_num = max_t(int, sreq->n_channels - 32, 0); - struct ieee80211_channel **scan_list = sreq->channels; - struct mt7615_dev *dev = phy->dev; - bool ext_phy = phy != &dev->phy; - struct mt7615_mcu_scan_channel *chan; - struct mt7615_hw_scan_req *req; - struct sk_buff *skb; - - /* fall-back to sw-scan */ - if (!mt7615_firmware_offload(dev)) - return 1; - - skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(*req)); - if (!skb) - return -ENOMEM; - - set_bit(MT76_HW_SCANNING, &phy->mt76->state); - mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; - - req = (struct mt7615_hw_scan_req *)skb_put(skb, sizeof(*req)); - - req->seq_num = mvif->scan_seq_num | ext_phy << 7; - req->bss_idx = mvif->idx; - req->scan_type = sreq->n_ssids ? 1 : 0; - req->probe_req_num = sreq->n_ssids ? 2 : 0; - req->version = 1; - - for (i = 0; i < sreq->n_ssids; i++) { - if (!sreq->ssids[i].ssid_len) - continue; - - req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); - memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, - sreq->ssids[i].ssid_len); - n_ssids++; - } - req->ssid_type = n_ssids ? BIT(2) : BIT(0); - req->ssid_type_ext = n_ssids ? BIT(0) : 0; - req->ssids_num = n_ssids; - - /* increase channel time for passive scan */ - if (!sreq->n_ssids) - duration *= 2; - req->timeout_value = cpu_to_le16(sreq->n_channels * duration); - req->channel_min_dwell_time = cpu_to_le16(duration); - req->channel_dwell_time = cpu_to_le16(duration); - - req->channels_num = min_t(u8, sreq->n_channels, 32); - req->ext_channels_num = min_t(u8, ext_channels_num, 32); - for (i = 0; i < req->channels_num + req->ext_channels_num; i++) { - if (i >= 32) - chan = &req->ext_channels[i - 32]; - else - chan = &req->channels[i]; - - chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; - chan->channel_num = scan_list[i]->hw_value; - } - req->channel_type = sreq->n_channels ? 4 : 0; - - if (sreq->ie_len > 0) { - memcpy(req->ies, sreq->ie, sreq->ie_len); - req->ies_len = cpu_to_le16(sreq->ie_len); - } - - memcpy(req->bssid, sreq->bssid, ETH_ALEN); - if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { - get_random_mask_addr(req->random_mac, sreq->mac_addr, - sreq->mac_addr_mask); - req->scan_func = 1; - } - - err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_START_HW_SCAN, - false); - if (err < 0) - clear_bit(MT76_HW_SCANNING, &phy->mt76->state); - - return err; -} - -int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, - struct ieee80211_vif *vif) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct mt7615_dev *dev = phy->dev; - struct { - u8 seq_num; - u8 is_ext_channel; - u8 rsv[2]; - } __packed req = { - .seq_num = mvif->scan_seq_num, - }; - - if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) { - struct cfg80211_scan_info info = { - .aborted = true, - }; - - ieee80211_scan_completed(phy->mt76->hw, &info); - } - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req, - sizeof(req), false); -} - -int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, - struct ieee80211_vif *vif, - struct cfg80211_sched_scan_request *sreq) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct ieee80211_channel **scan_list = sreq->channels; - struct mt7615_dev *dev = phy->dev; - bool ext_phy = phy != &dev->phy; - struct mt7615_mcu_scan_channel *chan; - struct mt7615_sched_scan_req *req; - struct cfg80211_match_set *match; - struct cfg80211_ssid *ssid; - struct sk_buff *skb; - int i; - - if (!mt7615_firmware_offload(dev)) - return -ENOTSUPP; - - skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, - sizeof(*req) + sreq->ie_len); - if (!skb) - return -ENOMEM; - - mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; - - req = (struct mt7615_sched_scan_req *)skb_put(skb, sizeof(*req)); - req->version = 1; - req->seq_num = mvif->scan_seq_num | ext_phy << 7; - - if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { - get_random_mask_addr(req->random_mac, sreq->mac_addr, - sreq->mac_addr_mask); - req->scan_func = 1; - } - - req->ssids_num = sreq->n_ssids; - for (i = 0; i < req->ssids_num; i++) { - ssid = &sreq->ssids[i]; - memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len); - req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len); - } - - req->match_num = sreq->n_match_sets; - for (i = 0; i < req->match_num; i++) { - match = &sreq->match_sets[i]; - memcpy(req->match[i].ssid, match->ssid.ssid, - match->ssid.ssid_len); - req->match[i].rssi_th = cpu_to_le32(match->rssi_thold); - req->match[i].ssid_len = match->ssid.ssid_len; - } - - req->channel_type = sreq->n_channels ? 4 : 0; - req->channels_num = min_t(u8, sreq->n_channels, 64); - for (i = 0; i < req->channels_num; i++) { - chan = &req->channels[i]; - chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; - chan->channel_num = scan_list[i]->hw_value; - } - - req->intervals_num = sreq->n_scan_plans; - for (i = 0; i < req->intervals_num; i++) - req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval); - - if (sreq->ie_len > 0) { - req->ie_len = cpu_to_le16(sreq->ie_len); - memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len); - } - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SCHED_SCAN_REQ, - false); -} - -int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy, - struct ieee80211_vif *vif, - bool enable) -{ - struct mt7615_dev *dev = phy->dev; - struct { - u8 active; /* 0: enabled 1: disabled */ - u8 rsv[3]; - } __packed req = { - .active = !enable, - }; - - if (!mt7615_firmware_offload(dev)) - return -ENOTSUPP; - - if (enable) - set_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); - else - clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, &req, - sizeof(req), false); -} - static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur) { int i; @@ -3531,7 +2512,7 @@ int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, u8 bmc_triggered_ac; u8 pad; } req = { - .bss_idx = mvif->idx, + .bss_idx = mvif->mt76.idx, .aid = cpu_to_le16(vif->bss_conf.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), @@ -3540,7 +2521,7 @@ int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, u8 bss_idx; u8 pad[3]; } req_hdr = { - .bss_idx = mvif->idx, + .bss_idx = mvif->mt76.idx, }; int err; @@ -3556,307 +2537,13 @@ int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, sizeof(req), false); } -#ifdef CONFIG_PM -int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) -{ - struct { - struct { - u8 hif_type; /* 0x0: HIF_SDIO - * 0x1: HIF_USB - * 0x2: HIF_PCIE - */ - u8 pad[3]; - } __packed hdr; - struct hif_suspend_tlv { - __le16 tag; - __le16 len; - u8 suspend; - } __packed hif_suspend; - } req = { - .hif_suspend = { - .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ - .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), - .suspend = suspend, - }, - }; - - if (mt76_is_mmio(&dev->mt76)) - req.hdr.hif_type = 2; - else if (mt76_is_usb(&dev->mt76)) - req.hdr.hif_type = 1; - else if (mt76_is_sdio(&dev->mt76)) - req.hdr.hif_type = 0; - - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, &req, - sizeof(req), true); -} -EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); - -static int -mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif, - bool suspend, struct cfg80211_wowlan *wowlan) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct mt7615_dev *dev = phy->dev; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct mt7615_wow_ctrl_tlv wow_ctrl_tlv; - struct mt7615_wow_gpio_param_tlv gpio_tlv; - } req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .wow_ctrl_tlv = { - .tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL), - .len = cpu_to_le16(sizeof(struct mt7615_wow_ctrl_tlv)), - .cmd = suspend ? 1 : 2, - }, - .gpio_tlv = { - .tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM), - .len = cpu_to_le16(sizeof(struct mt7615_wow_gpio_param_tlv)), - .gpio_pin = 0xff, /* follow fw about GPIO pin */ - }, - }; - - if (wowlan->magic_pkt) - req.wow_ctrl_tlv.trigger |= BIT(0); - if (wowlan->disconnect) - req.wow_ctrl_tlv.trigger |= BIT(2); - if (wowlan->nd_config) { - mt7615_mcu_sched_scan_req(phy, vif, wowlan->nd_config); - req.wow_ctrl_tlv.trigger |= BIT(5); - mt7615_mcu_sched_scan_enable(phy, vif, suspend); - } - - if (mt76_is_mmio(&dev->mt76)) - req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE; - else if (mt76_is_usb(&dev->mt76)) - req.wow_ctrl_tlv.wakeup_hif = WOW_USB; - else if (mt76_is_sdio(&dev->mt76)) - req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO; - - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, &req, - sizeof(req), true); -} - -static int -mt7615_mcu_set_wow_pattern(struct mt7615_dev *dev, - struct ieee80211_vif *vif, - u8 index, bool enable, - struct cfg80211_pkt_pattern *pattern) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct mt7615_wow_pattern_tlv *ptlv; - struct sk_buff *skb; - struct req_hdr { - u8 bss_idx; - u8 pad[3]; - } __packed hdr = { - .bss_idx = mvif->idx, - }; - - skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, - sizeof(hdr) + sizeof(*ptlv)); - if (!skb) - return -ENOMEM; - - skb_put_data(skb, &hdr, sizeof(hdr)); - ptlv = (struct mt7615_wow_pattern_tlv *)skb_put(skb, sizeof(*ptlv)); - ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); - ptlv->len = cpu_to_le16(sizeof(*ptlv)); - ptlv->data_len = pattern->pattern_len; - ptlv->enable = enable; - ptlv->index = index; - - memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); - memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8); - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_SUSPEND, - true); -} - -static int -mt7615_mcu_set_suspend_mode(struct mt7615_dev *dev, - struct ieee80211_vif *vif, - bool enable, u8 mdtim, bool wow_suspend) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct mt7615_suspend_tlv suspend_tlv; - } req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .suspend_tlv = { - .tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING), - .len = cpu_to_le16(sizeof(struct mt7615_suspend_tlv)), - .enable = enable, - .mdtim = mdtim, - .wow_suspend = wow_suspend, - }, - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, &req, - sizeof(req), true); -} - -static int -mt7615_mcu_set_gtk_rekey(struct mt7615_dev *dev, - struct ieee80211_vif *vif, - bool suspend) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct mt7615_gtk_rekey_tlv gtk_tlv; - } __packed req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .gtk_tlv = { - .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY), - .len = cpu_to_le16(sizeof(struct mt7615_gtk_rekey_tlv)), - .rekey_mode = !suspend, - }, - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, &req, - sizeof(req), true); -} - -static int -mt7615_mcu_set_arp_filter(struct mt7615_dev *dev, struct ieee80211_vif *vif, - bool suspend) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct { - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr; - struct mt7615_arpns_tlv arpns; - } req = { - .hdr = { - .bss_idx = mvif->idx, - }, - .arpns = { - .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), - .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), - .mode = suspend, - }, - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, &req, - sizeof(req), true); -} - -void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, - struct ieee80211_vif *vif) -{ - struct mt7615_phy *phy = priv; - bool suspend = test_bit(MT76_STATE_SUSPEND, &phy->mt76->state); - struct ieee80211_hw *hw = phy->mt76->hw; - struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; - int i; - - mt7615_mcu_set_gtk_rekey(phy->dev, vif, suspend); - mt7615_mcu_set_arp_filter(phy->dev, vif, suspend); - - mt7615_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); - - for (i = 0; i < wowlan->n_patterns; i++) - mt7615_mcu_set_wow_pattern(phy->dev, vif, i, suspend, - &wowlan->patterns[i]); - mt7615_mcu_set_wow_ctrl(phy, vif, suspend, wowlan); -} - -static void -mt7615_mcu_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, struct ieee80211_key_conf *key, - void *data) -{ - struct mt7615_gtk_rekey_tlv *gtk_tlv = data; - u32 cipher; - - if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC && - key->cipher != WLAN_CIPHER_SUITE_CCMP && - key->cipher != WLAN_CIPHER_SUITE_TKIP) - return; - - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1); - cipher = BIT(3); - } else { - gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2); - cipher = BIT(4); - } - - /* we are assuming here to have a single pairwise key */ - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - gtk_tlv->pairwise_cipher = cpu_to_le32(cipher); - gtk_tlv->group_cipher = cpu_to_le32(cipher); - gtk_tlv->keyid = key->keyidx; - } -} - -int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_gtk_rekey_data *key) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct mt7615_dev *dev = mt7615_hw_dev(hw); - struct mt7615_gtk_rekey_tlv *gtk_tlv; - struct sk_buff *skb; - struct { - u8 bss_idx; - u8 pad[3]; - } __packed hdr = { - .bss_idx = mvif->idx, - }; - - skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, - sizeof(hdr) + sizeof(*gtk_tlv)); - if (!skb) - return -ENOMEM; - - skb_put_data(skb, &hdr, sizeof(hdr)); - gtk_tlv = (struct mt7615_gtk_rekey_tlv *)skb_put(skb, - sizeof(*gtk_tlv)); - gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY); - gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv)); - gtk_tlv->rekey_mode = 2; - gtk_tlv->option = 1; - - rcu_read_lock(); - ieee80211_iter_keys_rcu(hw, vif, mt7615_mcu_key_iter, gtk_tlv); - rcu_read_unlock(); - - memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN); - memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN); - memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN); - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_OFFLOAD, - true); -} -#endif /* CONFIG_PM */ - int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = phy->dev; struct mt7615_roc_tlv req = { - .bss_idx = mvif->idx, + .bss_idx = mvif->mt76.idx, .active = !chan, .max_interval = cpu_to_le32(duration), .primary_chan = chan ? chan->hw_value : 0, @@ -3884,14 +2571,14 @@ int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, u8 bss_idx; u8 pad[3]; } __packed hdr; - struct mt7615_arpns_tlv arp; + struct mt76_connac_arpns_tlv arp; } req_hdr = { .hdr = { - .bss_idx = mvif->idx, + .bss_idx = mvif->mt76.idx, }, .arp = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), - .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), + .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)), .ips_num = len, .mode = 2, /* update */ .option = 1, @@ -3929,7 +2616,7 @@ int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, u8 rsv[3]; } __packed req = { .ct_win = cpu_to_le32(ct_window), - .bss_idx = mvif->idx, + .bss_idx = mvif->mt76.idx, }; if (!mt7615_firmware_offload(dev)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 6ef5670211d1..3874f45da9eb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -4,6 +4,8 @@ #ifndef __MT7615_MCU_H #define __MT7615_MCU_H +#include "../mt76_connac_mcu.h" + struct mt7615_mcu_txd { __le32 txd[8]; @@ -90,6 +92,7 @@ enum { MCU_EVENT_SCHED_SCAN_DONE = 0x23, MCU_EVENT_EXT = 0xed, MCU_EVENT_RESTART_DL = 0xef, + MCU_EVENT_COREDUMP = 0xf0, }; /* ext event table */ @@ -236,64 +239,6 @@ enum { MCU_S2D_H2CN }; -#define MCU_FW_PREFIX BIT(31) -#define MCU_UNI_PREFIX BIT(30) -#define MCU_CE_PREFIX BIT(29) -#define MCU_QUERY_PREFIX BIT(28) -#define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX | \ - MCU_CE_PREFIX | MCU_QUERY_PREFIX) - -#define MCU_QUERY_MASK BIT(16) - -enum { - MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01, - MCU_CMD_FW_START_REQ = MCU_FW_PREFIX | 0x02, - MCU_CMD_INIT_ACCESS_REG = 0x3, - MCU_CMD_PATCH_START_REQ = 0x05, - MCU_CMD_PATCH_FINISH_REQ = MCU_FW_PREFIX | 0x07, - MCU_CMD_PATCH_SEM_CONTROL = MCU_FW_PREFIX | 0x10, - MCU_CMD_EXT_CID = 0xED, - MCU_CMD_FW_SCATTER = MCU_FW_PREFIX | 0xEE, - MCU_CMD_RESTART_DL_REQ = MCU_FW_PREFIX | 0xEF, -}; - -enum { - MCU_EXT_CMD_RF_REG_ACCESS = 0x02, - MCU_EXT_CMD_PM_STATE_CTRL = 0x07, - MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, - MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11, - MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, - MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, - MCU_EXT_CMD_STA_REC_UPDATE = 0x25, - MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, - MCU_EXT_CMD_EDCA_UPDATE = 0x27, - MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, - MCU_EXT_CMD_GET_TEMP = 0x2c, - MCU_EXT_CMD_WTBL_UPDATE = 0x32, - MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, - MCU_EXT_CMD_ATE_CTRL = 0x3d, - MCU_EXT_CMD_PROTECT_CTRL = 0x3e, - MCU_EXT_CMD_DBDC_CTRL = 0x45, - MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, - MCU_EXT_CMD_MUAR_UPDATE = 0x48, - MCU_EXT_CMD_BCN_OFFLOAD = 0x49, - MCU_EXT_CMD_SET_RX_PATH = 0x4e, - MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, - MCU_EXT_CMD_RXDCOC_CAL = 0x59, - MCU_EXT_CMD_TXDPD_CAL = 0x60, - MCU_EXT_CMD_SET_RDD_TH = 0x7c, - MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d, -}; - -enum { - MCU_UNI_CMD_DEV_INFO_UPDATE = MCU_UNI_PREFIX | 0x01, - MCU_UNI_CMD_BSS_INFO_UPDATE = MCU_UNI_PREFIX | 0x02, - MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, - MCU_UNI_CMD_SUSPEND = MCU_UNI_PREFIX | 0x05, - MCU_UNI_CMD_OFFLOAD = MCU_UNI_PREFIX | 0x06, - MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07, -}; - enum { MCU_ATE_SET_FREQ_OFFSET = 0xa, MCU_ATE_SET_TX_POWER_CONTROL = 0x15, @@ -305,269 +250,11 @@ struct mt7615_mcu_uni_event { __le32 status; /* 0: success, others: fail */ } __packed; -struct mt7615_beacon_loss_event { - u8 bss_idx; - u8 reason; - u8 pad[2]; -} __packed; - -struct mt7615_mcu_scan_ssid { - __le32 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; -} __packed; - -struct mt7615_mcu_scan_channel { - u8 band; /* 1: 2.4GHz - * 2: 5.0GHz - * Others: Reserved - */ - u8 channel_num; -} __packed; - -struct mt7615_mcu_scan_match { - __le32 rssi_th; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - u8 rsv[3]; -} __packed; - -struct mt7615_hw_scan_req { - u8 seq_num; - u8 bss_idx; - u8 scan_type; /* 0: PASSIVE SCAN - * 1: ACTIVE SCAN - */ - u8 ssid_type; /* BIT(0) wildcard SSID - * BIT(1) P2P wildcard SSID - * BIT(2) specified SSID + wildcard SSID - * BIT(2) + ssid_type_ext BIT(0) specified SSID only - */ - u8 ssids_num; - u8 probe_req_num; /* Number of probe request for each SSID */ - u8 scan_func; /* BIT(0) Enable random MAC scan - * BIT(1) Disable DBDC scan type 1~3. - * BIT(2) Use DBDC scan type 3 (dedicated one RF to scan). - */ - u8 version; /* 0: Not support fields after ies. - * 1: Support fields after ies. - */ - struct mt7615_mcu_scan_ssid ssids[4]; - __le16 probe_delay_time; - __le16 channel_dwell_time; /* channel Dwell interval */ - __le16 timeout_value; - u8 channel_type; /* 0: Full channels - * 1: Only 2.4GHz channels - * 2: Only 5GHz channels - * 3: P2P social channel only (channel #1, #6 and #11) - * 4: Specified channels - * Others: Reserved - */ - u8 channels_num; /* valid when channel_type is 4 */ - /* valid when channels_num is set */ - struct mt7615_mcu_scan_channel channels[32]; - __le16 ies_len; - u8 ies[MT7615_SCAN_IE_LEN]; - /* following fields are valid if version > 0 */ - u8 ext_channels_num; - u8 ext_ssids_num; - __le16 channel_min_dwell_time; - struct mt7615_mcu_scan_channel ext_channels[32]; - struct mt7615_mcu_scan_ssid ext_ssids[6]; - u8 bssid[ETH_ALEN]; - u8 random_mac[ETH_ALEN]; /* valid when BIT(1) in scan_func is set. */ - u8 pad[63]; - u8 ssid_type_ext; -} __packed; - -#define SCAN_DONE_EVENT_MAX_CHANNEL_NUM 64 -struct mt7615_hw_scan_done { - u8 seq_num; - u8 sparse_channel_num; - struct mt7615_mcu_scan_channel sparse_channel; - u8 complete_channel_num; - u8 current_state; - u8 version; - u8 pad; - __le32 beacon_scan_num; - u8 pno_enabled; - u8 pad2[3]; - u8 sparse_channel_valid_num; - u8 pad3[3]; - u8 channel_num[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; - /* idle format for channel_idle_time - * 0: first bytes: idle time(ms) 2nd byte: dwell time(ms) - * 1: first bytes: idle time(8ms) 2nd byte: dwell time(8ms) - * 2: dwell time (16us) - */ - __le16 channel_idle_time[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; - /* beacon and probe response count */ - u8 beacon_probe_num[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; - u8 mdrdy_count[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; - __le32 beacon_2g_num; - __le32 beacon_5g_num; -} __packed; - -struct mt7615_sched_scan_req { - u8 version; - u8 seq_num; - u8 stop_on_match; - u8 ssids_num; - u8 match_num; - u8 pad; - __le16 ie_len; - struct mt7615_mcu_scan_ssid ssids[MT7615_MAX_SCHED_SCAN_SSID]; - struct mt7615_mcu_scan_match match[MT7615_MAX_SCAN_MATCH]; - u8 channel_type; - u8 channels_num; - u8 intervals_num; - u8 scan_func; /* BIT(0) eable random mac address */ - struct mt7615_mcu_scan_channel channels[64]; - __le16 intervals[MT7615_MAX_SCHED_SCAN_INTERVAL]; - u8 random_mac[ETH_ALEN]; /* valid when BIT(0) in scan_func is set */ - u8 pad2[58]; -} __packed; - -struct nt7615_sched_scan_done { - u8 seq_num; - u8 status; /* 0: ssid found */ - __le16 pad; -} __packed; - struct mt7615_mcu_reg_event { __le32 reg; __le32 val; } __packed; -struct mt7615_mcu_bss_event { - u8 bss_idx; - u8 is_absent; - u8 free_quota; - u8 pad; -} __packed; - -struct mt7615_bss_basic_tlv { - __le16 tag; - __le16 len; - u8 active; - u8 omac_idx; - u8 hw_bss_idx; - u8 band_idx; - __le32 conn_type; - u8 conn_state; - u8 wmm_idx; - u8 bssid[ETH_ALEN]; - __le16 bmc_tx_wlan_idx; - __le16 bcn_interval; - u8 dtim_period; - u8 phymode; /* bit(0): A - * bit(1): B - * bit(2): G - * bit(3): GN - * bit(4): AN - * bit(5): AC - */ - __le16 sta_idx; - u8 nonht_basic_phy; - u8 pad[3]; -} __packed; - -struct mt7615_bss_qos_tlv { - __le16 tag; - __le16 len; - u8 qos; - u8 pad[3]; -} __packed; - -enum { - WOW_USB = 1, - WOW_PCIE = 2, - WOW_GPIO = 3, -}; - -struct mt7615_wow_ctrl_tlv { - __le16 tag; - __le16 len; - u8 cmd; /* 0x1: PM_WOWLAN_REQ_START - * 0x2: PM_WOWLAN_REQ_STOP - * 0x3: PM_WOWLAN_PARAM_CLEAR - */ - u8 trigger; /* 0: NONE - * BIT(0): NL80211_WOWLAN_TRIG_MAGIC_PKT - * BIT(1): NL80211_WOWLAN_TRIG_ANY - * BIT(2): NL80211_WOWLAN_TRIG_DISCONNECT - * BIT(3): NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE - * BIT(4): BEACON_LOST - * BIT(5): NL80211_WOWLAN_TRIG_NET_DETECT - */ - u8 wakeup_hif; /* 0x0: HIF_SDIO - * 0x1: HIF_USB - * 0x2: HIF_PCIE - * 0x3: HIF_GPIO - */ - u8 pad; - u8 rsv[4]; -} __packed; - -struct mt7615_wow_gpio_param_tlv { - __le16 tag; - __le16 len; - u8 gpio_pin; - u8 trigger_lvl; - u8 pad[2]; - __le32 gpio_interval; - u8 rsv[4]; -} __packed; - -#define MT7615_WOW_MASK_MAX_LEN 16 -#define MT7615_WOW_PATTEN_MAX_LEN 128 -struct mt7615_wow_pattern_tlv { - __le16 tag; - __le16 len; - u8 index; /* pattern index */ - u8 enable; /* 0: disable - * 1: enable - */ - u8 data_len; /* pattern length */ - u8 pad; - u8 mask[MT7615_WOW_MASK_MAX_LEN]; - u8 pattern[MT7615_WOW_PATTEN_MAX_LEN]; - u8 rsv[4]; -} __packed; - -struct mt7615_suspend_tlv { - __le16 tag; - __le16 len; - u8 enable; /* 0: suspend mode disabled - * 1: suspend mode enabled - */ - u8 mdtim; /* LP parameter */ - u8 wow_suspend; /* 0: update by origin policy - * 1: update by wow dtim - */ - u8 pad[5]; -} __packed; - -struct mt7615_gtk_rekey_tlv { - __le16 tag; - __le16 len; - u8 kek[NL80211_KEK_LEN]; - u8 kck[NL80211_KCK_LEN]; - u8 replay_ctr[NL80211_REPLAY_CTR_LEN]; - u8 rekey_mode; /* 0: rekey offload enable - * 1: rekey offload disable - * 2: rekey update - */ - u8 keyid; - u8 pad[2]; - __le32 proto; /* WPA-RSN-WAPI-OPSN */ - __le32 pairwise_cipher; - __le32 group_cipher; - __le32 key_mgmt; /* NONE-PSK-IEEE802.1X */ - __le32 mgmt_group_cipher; - u8 option; /* 1: rekey data update without enabling offload */ - u8 reserverd[3]; -} __packed; - struct mt7615_roc_tlv { u8 bss_idx; u8 token; @@ -585,65 +272,6 @@ struct mt7615_roc_tlv { u8 rsv1[8]; } __packed; -struct mt7615_arpns_tlv { - __le16 tag; - __le16 len; - u8 mode; - u8 ips_num; - u8 option; - u8 pad[1]; -} __packed; - -/* offload mcu commands */ -enum { - MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, - MCU_CMD_SET_PS_PROFILE = MCU_CE_PREFIX | 0x05, - MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, - MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16, - MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17, - MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, - MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1c, - MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33, - MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, - MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, - MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0, - MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0, -}; - -#define MCU_CMD_ACK BIT(0) -#define MCU_CMD_UNI BIT(1) -#define MCU_CMD_QUERY BIT(2) - -#define MCU_CMD_UNI_EXT_ACK (MCU_CMD_ACK | MCU_CMD_UNI | MCU_CMD_QUERY) - -enum { - UNI_BSS_INFO_BASIC = 0, - UNI_BSS_INFO_RLM = 2, - UNI_BSS_INFO_BCN_CONTENT = 7, - UNI_BSS_INFO_QBSS = 15, - UNI_BSS_INFO_UAPSD = 19, -}; - -enum { - UNI_SUSPEND_MODE_SETTING, - UNI_SUSPEND_WOW_CTRL, - UNI_SUSPEND_WOW_GPIO_PARAM, - UNI_SUSPEND_WOW_WAKEUP_PORT, - UNI_SUSPEND_WOW_PATTERN, -}; - -enum { - UNI_OFFLOAD_OFFLOAD_ARP, - UNI_OFFLOAD_OFFLOAD_ND, - UNI_OFFLOAD_OFFLOAD_GTK_REKEY, - UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, -}; - -enum { - PATCH_SEM_RELEASE = 0x0, - PATCH_SEM_GET = 0x1 -}; - enum { PATCH_NOT_DL_SEM_FAIL = 0x0, PATCH_IS_DL = 0x1, @@ -664,34 +292,6 @@ enum { FW_STATE_N9_RDY = 2, }; -#define STA_TYPE_STA BIT(0) -#define STA_TYPE_AP BIT(1) -#define STA_TYPE_ADHOC BIT(2) -#define STA_TYPE_WDS BIT(4) -#define STA_TYPE_BC BIT(5) - -#define NETWORK_INFRA BIT(16) -#define NETWORK_P2P BIT(17) -#define NETWORK_IBSS BIT(18) -#define NETWORK_WDS BIT(21) - -#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) -#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) -#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) -#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) -#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) -#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) -#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) - -#define CONN_STATE_DISCONNECT 0 -#define CONN_STATE_CONNECT 1 -#define CONN_STATE_PORT_SECURE 2 - -enum { - DEV_INFO_ACTIVE, - DEV_INFO_MAX_NUM -}; - enum { DBDC_TYPE_WMM, DBDC_TYPE_MGMT, @@ -704,11 +304,6 @@ enum { __DBDC_TYPE_MAX, }; -struct tlv { - __le16 tag; - __le16 len; -} __packed; - struct bss_info_omac { __le16 tag; __le16 len; @@ -767,157 +362,6 @@ enum { BSS_INFO_MAX_NUM }; -enum { - WTBL_RESET_AND_SET = 1, - WTBL_SET, - WTBL_QUERY, - WTBL_RESET_ALL -}; - -struct wtbl_req_hdr { - u8 wlan_idx; - u8 operation; - __le16 tlv_num; - u8 rsv[4]; -} __packed; - -struct wtbl_generic { - __le16 tag; - __le16 len; - u8 peer_addr[ETH_ALEN]; - u8 muar_idx; - u8 skip_tx; - u8 cf_ack; - u8 qos; - u8 mesh; - u8 adm; - __le16 partial_aid; - u8 baf_en; - u8 aad_om; -} __packed; - -struct wtbl_rx { - __le16 tag; - __le16 len; - u8 rcid; - u8 rca1; - u8 rca2; - u8 rv; - u8 rsv[4]; -} __packed; - -struct wtbl_ht { - __le16 tag; - __le16 len; - u8 ht; - u8 ldpc; - u8 af; - u8 mm; - u8 rsv[4]; -} __packed; - -struct wtbl_vht { - __le16 tag; - __le16 len; - u8 ldpc; - u8 dyn_bw; - u8 vht; - u8 txop_ps; - u8 rsv[4]; -} __packed; - -struct wtbl_tx_ps { - __le16 tag; - __le16 len; - u8 txps; - u8 rsv[3]; -} __packed; - -struct wtbl_hdr_trans { - __le16 tag; - __le16 len; - u8 to_ds; - u8 from_ds; - u8 disable_rx_trans; - u8 rsv; -} __packed; - -enum { - MT_BA_TYPE_INVALID, - MT_BA_TYPE_ORIGINATOR, - MT_BA_TYPE_RECIPIENT -}; - -enum { - RST_BA_MAC_TID_MATCH, - RST_BA_MAC_MATCH, - RST_BA_NO_MATCH -}; - -struct wtbl_ba { - __le16 tag; - __le16 len; - /* common */ - u8 tid; - u8 ba_type; - u8 rsv0[2]; - /* originator only */ - __le16 sn; - u8 ba_en; - u8 ba_winsize_idx; - __le16 ba_winsize; - /* recipient only */ - u8 peer_addr[ETH_ALEN]; - u8 rst_ba_tid; - u8 rst_ba_sel; - u8 rst_ba_sb; - u8 band_idx; - u8 rsv1[4]; -} __packed; - -struct wtbl_bf { - __le16 tag; - __le16 len; - u8 ibf; - u8 ebf; - u8 ibf_vht; - u8 ebf_vht; - u8 gid; - u8 pfmu_idx; - u8 rsv[2]; -} __packed; - -struct wtbl_smps { - __le16 tag; - __le16 len; - u8 smps; - u8 rsv[3]; -} __packed; - -struct wtbl_pn { - __le16 tag; - __le16 len; - u8 pn[6]; - u8 rsv[2]; -} __packed; - -struct wtbl_spe { - __le16 tag; - __le16 len; - u8 spe_idx; - u8 rsv[3]; -} __packed; - -struct wtbl_raw { - __le16 tag; - __le16 len; - u8 wtbl_idx; - u8 dw; - u8 rsv[2]; - __le32 msk; - __le32 val; -} __packed; - #define MT7615_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ sizeof(struct wtbl_generic) + \ sizeof(struct wtbl_rx) + \ @@ -943,127 +387,6 @@ struct wtbl_raw { sizeof(struct wtbl_ba)) enum { - WTBL_GENERIC, - WTBL_RX, - WTBL_HT, - WTBL_VHT, - WTBL_PEER_PS, /* not used */ - WTBL_TX_PS, - WTBL_HDR_TRANS, - WTBL_SEC_KEY, - WTBL_BA, - WTBL_RDG, /* obsoleted */ - WTBL_PROTECT, /* not used */ - WTBL_CLEAR, /* not used */ - WTBL_BF, - WTBL_SMPS, - WTBL_RAW_DATA, /* debug only */ - WTBL_PN, - WTBL_SPE, - WTBL_MAX_NUM -}; - -struct sta_ntlv_hdr { - u8 rsv[2]; - __le16 tlv_num; -} __packed; - -struct sta_req_hdr { - u8 bss_idx; - u8 wlan_idx; - __le16 tlv_num; - u8 is_tlv_append; - u8 muar_idx; - u8 rsv[2]; -} __packed; - -struct sta_rec_state { - __le16 tag; - __le16 len; - u8 state; - __le32 flags; - u8 vhtop; - u8 pad[2]; -} __packed; - -struct sta_rec_basic { - __le16 tag; - __le16 len; - __le32 conn_type; - u8 conn_state; - u8 qos; - __le16 aid; - u8 peer_addr[ETH_ALEN]; -#define EXTRA_INFO_VER BIT(0) -#define EXTRA_INFO_NEW BIT(1) - __le16 extra_info; -} __packed; - -struct sta_rec_ht { - __le16 tag; - __le16 len; - __le16 ht_cap; - u16 rsv; -} __packed; - -struct sta_rec_vht { - __le16 tag; - __le16 len; - __le32 vht_cap; - __le16 vht_rx_mcs_map; - __le16 vht_tx_mcs_map; -} __packed; - -struct sta_rec_ba { - __le16 tag; - __le16 len; - u8 tid; - u8 ba_type; - u8 amsdu; - u8 ba_en; - __le16 ssn; - __le16 winsize; -} __packed; - -struct sta_rec_uapsd { - __le16 tag; - __le16 len; - u8 dac_map; - u8 tac_map; - u8 max_sp; - u8 rsv0; - __le16 listen_interval; - u8 rsv1[2]; -} __packed; - -enum { - STA_REC_BASIC, - STA_REC_RA, - STA_REC_RA_CMM_INFO, - STA_REC_RA_UPDATE, - STA_REC_BF, - STA_REC_AMSDU, /* for CR4 */ - STA_REC_BA, - STA_REC_STATE, - STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */ - STA_REC_HT, - STA_REC_VHT, - STA_REC_APPS, - STA_REC_WTBL = 13, - STA_REC_MAX_NUM -}; - -enum { - CMD_CBW_20MHZ, - CMD_CBW_40MHZ, - CMD_CBW_80MHZ, - CMD_CBW_160MHZ, - CMD_CBW_10MHZ, - CMD_CBW_5MHZ, - CMD_CBW_8080MHZ -}; - -enum { CH_SWITCH_NORMAL = 0, CH_SWITCH_SCAN = 3, CH_SWITCH_MCC = 4, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 99b8abdbb08f..491841bc6291 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -8,7 +8,7 @@ #include <linux/interrupt.h> #include <linux/ktime.h> #include <linux/regmap.h> -#include "../mt76.h" +#include "../mt76_connac_mcu.h" #include "regs.h" #define MT7615_MAX_INTERFACES 16 @@ -65,11 +65,6 @@ #define MT7615_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7615_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ -#define MT7615_SCAN_IE_LEN 600 -#define MT7615_MAX_SCHED_SCAN_INTERVAL 10 -#define MT7615_MAX_SCHED_SCAN_SSID 10 -#define MT7615_MAX_SCAN_MATCH 16 - struct mt7615_vif; struct mt7615_sta; struct mt7615_dfs_pulse; @@ -133,12 +128,7 @@ struct mt7615_sta { }; struct mt7615_vif { - u8 idx; - u8 omac_idx; - u8 band_idx; - u8 wmm_idx; - u8 scan_seq_num; - + struct mt76_vif mt76; /* must be first */ struct mt7615_sta sta; }; @@ -171,8 +161,6 @@ struct mt7615_phy { s8 ofdm_sensitivity; s8 cck_sensitivity; - u16 chainmask; - s16 coverage_class; u8 slottime; @@ -185,9 +173,6 @@ struct mt7615_phy { struct mib_stats mib; - struct delayed_work mac_work; - u8 mac_work_count; - struct sk_buff_head scan_event_list; struct delayed_work scan_work; @@ -195,13 +180,24 @@ struct mt7615_phy { struct timer_list roc_timer; wait_queue_head_t roc_wait; bool roc_grant; + +#ifdef CONFIG_NL80211_TESTMODE + struct { + u32 *reg_backup; + + s16 last_freq_offset; + u8 last_rcpi[4]; + s8 last_ib_rssi[4]; + s8 last_wb_rssi[4]; + } test; +#endif }; #define mt7615_mcu_add_tx_ba(dev, ...) (dev)->mcu_ops->add_tx_ba((dev), __VA_ARGS__) #define mt7615_mcu_add_rx_ba(dev, ...) (dev)->mcu_ops->add_rx_ba((dev), __VA_ARGS__) -#define mt7615_mcu_sta_add(dev, ...) (dev)->mcu_ops->sta_add((dev), __VA_ARGS__) -#define mt7615_mcu_add_dev_info(dev, ...) (dev)->mcu_ops->add_dev_info((dev), __VA_ARGS__) -#define mt7615_mcu_add_bss_info(phy, ...) (phy->dev)->mcu_ops->add_bss_info((phy), __VA_ARGS__) +#define mt7615_mcu_sta_add(phy, ...) ((phy)->dev)->mcu_ops->sta_add((phy), __VA_ARGS__) +#define mt7615_mcu_add_dev_info(phy, ...) ((phy)->dev)->mcu_ops->add_dev_info((phy), __VA_ARGS__) +#define mt7615_mcu_add_bss_info(phy, ...) ((phy)->dev)->mcu_ops->add_bss_info((phy), __VA_ARGS__) #define mt7615_mcu_add_beacon(dev, ...) (dev)->mcu_ops->add_beacon_offload((dev), __VA_ARGS__) #define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__) #define mt7615_mcu_set_drv_ctrl(dev) (dev)->mcu_ops->set_drv_ctrl((dev)) @@ -213,11 +209,10 @@ struct mt7615_mcu_ops { int (*add_rx_ba)(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable); - int (*sta_add)(struct mt7615_dev *dev, - struct ieee80211_vif *vif, + int (*sta_add)(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable); - int (*add_dev_info)(struct mt7615_dev *dev, - struct ieee80211_vif *vif, bool enable); + int (*add_dev_info)(struct mt7615_phy *phy, struct ieee80211_vif *vif, + bool enable); int (*add_bss_info)(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable); int (*add_beacon_offload)(struct mt7615_dev *dev, @@ -281,33 +276,8 @@ struct mt7615_dev { u32 muar_mask; -#ifdef CONFIG_NL80211_TESTMODE - struct { - u32 *reg_backup; - - s16 last_freq_offset; - u8 last_rcpi[4]; - s8 last_ib_rssi[4]; - s8 last_wb_rssi[4]; - } test; -#endif - - struct { - bool enable; - - spinlock_t txq_lock; - struct { - struct mt7615_sta *msta; - struct sk_buff *skb; - } tx_q[IEEE80211_NUM_ACS]; - - struct work_struct wake_work; - struct completion wake_cmpl; - - struct delayed_work ps_work; - unsigned long last_activity; - unsigned long idle_timeout; - } pm; + struct mt76_connac_pm pm; + struct mt76_connac_coredump coredump; }; enum tx_pkt_queue_idx { @@ -326,20 +296,6 @@ enum tx_pkt_queue_idx { }; enum { - HW_BSSID_0 = 0x0, - HW_BSSID_1, - HW_BSSID_2, - HW_BSSID_3, - HW_BSSID_MAX = HW_BSSID_3, - EXT_BSSID_START = 0x10, - EXT_BSSID_1, - EXT_BSSID_15 = 0x1f, - EXT_BSSID_MAX = EXT_BSSID_15, - REPEATER_BSSID_START = 0x20, - REPEATER_BSSID_MAX = 0x3f, -}; - -enum { MT_RX_SEL0, MT_RX_SEL1, }; @@ -407,7 +363,6 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map); u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); -void mt7615_check_offload_capability(struct mt7615_dev *dev); void mt7615_init_device(struct mt7615_dev *dev); int mt7615_register_device(struct mt7615_dev *dev); void mt7615_unregister_device(struct mt7615_dev *dev); @@ -428,8 +383,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates); void mt7615_pm_wake_work(struct work_struct *work); -int mt7615_pm_wake(struct mt7615_dev *dev); -void mt7615_pm_power_save_sched(struct mt7615_dev *dev); void mt7615_pm_power_save_work(struct work_struct *work); int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev); int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd); @@ -485,19 +438,10 @@ static inline u16 mt7615_wtbl_size(struct mt7615_dev *dev) return MT7615_WTBL_SIZE; } -static inline void mt7615_mutex_acquire(struct mt7615_dev *dev) - __acquires(&dev->mt76.mutex) -{ - mutex_lock(&dev->mt76.mutex); - mt7615_pm_wake(dev); -} - -static inline void mt7615_mutex_release(struct mt7615_dev *dev) - __releases(&dev->mt76.mutex) -{ - mt7615_pm_power_save_sched(dev); - mutex_unlock(&dev->mt76.mutex); -} +#define mt7615_mutex_acquire(dev) \ + mt76_connac_mutex_acquire(&(dev)->mt76, &(dev)->pm) +#define mt7615_mutex_release(dev) \ + mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac) { @@ -525,9 +469,8 @@ void mt7615_roc_work(struct work_struct *work); void mt7615_roc_timer(struct timer_list *timer); void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband); -void mt7615_phy_init(struct mt7615_dev *dev); -void mt7615_mac_init(struct mt7615_dev *dev); int mt7615_set_channel(struct mt7615_phy *phy); +void mt7615_init_work(struct mt7615_dev *dev); int mt7615_mcu_restart(struct mt76_dev *dev); void mt7615_update_channel(struct mt76_dev *mdev); @@ -558,24 +501,11 @@ u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg); int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val); int mt7615_mcu_set_dbdc(struct mt7615_dev *dev); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); -int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable); -int mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val); int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index); int mt7615_mcu_set_tx_power(struct mt7615_phy *phy); void mt7615_mcu_exit(struct mt7615_dev *dev); void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq); -int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy); -int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_scan_request *scan_req); -int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, - struct ieee80211_vif *vif); -int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, - struct ieee80211_vif *vif, - struct cfg80211_sched_scan_request *sreq); -int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy, - struct ieee80211_vif *vif, - bool enable); int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, @@ -583,7 +513,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt76_tx_info *tx_info); void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); - +void mt7615_tx_token_put(struct mt7615_dev *dev); void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); void mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); @@ -604,7 +534,6 @@ int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); -int mt7615_mcu_set_vif_ps(struct mt7615_dev *dev, struct ieee80211_vif *vif); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, @@ -620,18 +549,13 @@ int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy, bool enable); int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable); -int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend); -void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, - struct ieee80211_vif *vif); -int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_gtk_rekey_data *key); int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info); int __mt7663_load_firmware(struct mt7615_dev *dev); u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset); void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val); +void mt7615_coredump_work(struct work_struct *work); /* usb */ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index dbd29d897b29..71487f532f36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -10,6 +10,7 @@ #include <linux/pci.h> #include "mt7615.h" +#include "mcu.h" static const struct pci_device_id mt7615_pci_device_table[] = { { PCI_DEVICE(0x14c3, 0x7615) }, @@ -75,14 +76,14 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state) bool hif_suspend; int i, err; - err = mt7615_pm_wake(dev); + err = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (err < 0) return err; hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev); if (hif_suspend) { - err = mt7615_mcu_set_hif_suspend(dev, true); + err = mt76_connac_mcu_set_hif_suspend(mdev, true); if (err) return err; } @@ -130,7 +131,7 @@ restore: } napi_enable(&mdev->tx_napi); if (hif_suspend) - mt7615_mcu_set_hif_suspend(dev, false); + mt76_connac_mcu_set_hif_suspend(mdev, false); return err; } @@ -172,7 +173,7 @@ static int mt7615_pci_resume(struct pci_dev *pdev) if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev)) - err = mt7615_mcu_set_hif_suspend(dev, false); + err = mt76_connac_mcu_set_hif_suspend(mdev, false); return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index 27fcb1374685..72395925ddee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -12,7 +12,7 @@ #include "mac.h" #include "eeprom.h" -static void mt7615_init_work(struct work_struct *work) +static void mt7615_pci_init_work(struct work_struct *work) { struct mt7615_dev *dev = container_of(work, struct mt7615_dev, mcu_work); @@ -27,12 +27,7 @@ static void mt7615_init_work(struct work_struct *work) if (ret) return; - mt7615_mcu_set_eeprom(dev); - mt7615_mac_init(dev); - mt7615_phy_init(dev); - mt7615_mcu_del_wtbl_all(dev); - mt7615_check_offload_capability(dev); - + mt7615_init_work(dev); if (dev->dbdc_support) mt7615_register_ext_phy(dev); } @@ -44,7 +39,7 @@ static int mt7615_init_hardware(struct mt7615_dev *dev) mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); - INIT_WORK(&dev->mcu_work, mt7615_init_work); + INIT_WORK(&dev->mcu_work, mt7615_pci_init_work); spin_lock_init(&dev->token_lock); idr_init(&dev->token); @@ -160,9 +155,7 @@ int mt7615_register_device(struct mt7615_dev *dev) void mt7615_unregister_device(struct mt7615_dev *dev) { - struct mt76_txwi_cache *txwi; bool mcu_running; - int id; mcu_running = mt7615_wait_for_mcu_init(dev); @@ -172,15 +165,7 @@ void mt7615_unregister_device(struct mt7615_dev *dev) mt7615_mcu_exit(dev); mt7615_dma_cleanup(dev); - spin_lock_bh(&dev->token_lock); - idr_for_each_entry(&dev->token, txwi, id) { - mt7615_txp_skb_unmap(&dev->mt76, txwi); - if (txwi->skb) - dev_kfree_skb_any(txwi->skb); - mt76_put_txwi(&dev->mt76, txwi); - } - spin_unlock_bh(&dev->token_lock); - idr_destroy(&dev->token); + mt7615_tx_token_put(dev); tasklet_disable(&dev->irq_tasklet); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 4cf7c5d34325..1b4cb145f38e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -118,7 +118,7 @@ mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); if (vif) { - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; txp->bss_idx = mvif->idx; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index 347975eaba86..305bb8597531 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -17,6 +17,7 @@ #include "mt7615.h" #include "sdio.h" #include "mac.h" +#include "mcu.h" static const struct sdio_device_id mt7663s_table[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7603) }, @@ -227,11 +228,7 @@ static void mt7663s_init_work(struct work_struct *work) if (mt7663s_mcu_init(dev)) return; - mt7615_mcu_set_eeprom(dev); - mt7615_mac_init(dev); - mt7615_phy_init(dev); - mt7615_mcu_del_wtbl_all(dev); - mt7615_check_offload_capability(dev); + mt7615_init_work(dev); } static int mt7663s_hw_init(struct mt7615_dev *dev, struct sdio_func *func) @@ -417,7 +414,7 @@ static int mt7663s_suspend(struct device *dev) mt7615_firmware_offload(mdev)) { int err; - err = mt7615_mcu_set_hif_suspend(mdev, true); + err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true); if (err < 0) return err; } @@ -456,7 +453,7 @@ static int mt7663s_resume(struct device *dev) if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) && mt7615_firmware_offload(mdev)) - err = mt7615_mcu_set_hif_suspend(mdev, false); + err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false); return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c index 8fc97a52411a..59d99264f5e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c @@ -67,8 +67,8 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy) }; u8 *tx_power = NULL; - if (dev->mt76.test.state != MT76_TM_STATE_OFF) - tx_power = dev->mt76.test.tx_power; + if (mphy->test.state != MT76_TM_STATE_OFF) + tx_power = mphy->test.tx_power; len = MT7615_EE_MAX - MT_EE_NIC_CONF_0; skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + len); @@ -95,14 +95,15 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy) } static void -mt7615_tm_reg_backup_restore(struct mt7615_dev *dev) +mt7615_tm_reg_backup_restore(struct mt7615_phy *phy) { - u32 *b = dev->test.reg_backup; + struct mt7615_dev *dev = phy->dev; + u32 *b = phy->test.reg_backup; int n_regs = ARRAY_SIZE(reg_backup_list); int n_rf_regs = ARRAY_SIZE(rf_backup_list); int i; - if (dev->mt76.test.state == MT76_TM_STATE_OFF) { + if (phy->mt76->test.state == MT76_TM_STATE_OFF) { for (i = 0; i < n_regs; i++) mt76_wr(dev, reg_backup_list[i], b[i]); @@ -120,7 +121,7 @@ mt7615_tm_reg_backup_restore(struct mt7615_dev *dev) if (!b) return; - dev->test.reg_backup = b; + phy->test.reg_backup = b; for (i = 0; i < n_regs; i++) b[i] = mt76_rr(dev, reg_backup_list[i]); for (i = 0; i < n_rf_regs; i++) @@ -128,30 +129,23 @@ mt7615_tm_reg_backup_restore(struct mt7615_dev *dev) rf_backup_list[i].reg); } - static void -mt7615_tm_init_phy(struct mt7615_dev *dev, struct mt7615_phy *phy) +mt7615_tm_init(struct mt7615_phy *phy) { + struct mt7615_dev *dev = phy->dev; unsigned int total_flags = ~0; if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; + mt7615_mcu_set_sku_en(phy, phy->mt76->test.state == MT76_TM_STATE_OFF); + mutex_unlock(&dev->mt76.mutex); mt7615_set_channel(phy); mt7615_ops.configure_filter(phy->mt76->hw, 0, &total_flags, 0); mutex_lock(&dev->mt76.mutex); - mt7615_tm_reg_backup_restore(dev); -} - -static void -mt7615_tm_init(struct mt7615_dev *dev) -{ - mt7615_tm_init_phy(dev, &dev->phy); - - if (dev->mt76.phy2) - mt7615_tm_init_phy(dev, dev->mt76.phy2->priv); + mt7615_tm_reg_backup_restore(phy); } static void @@ -175,9 +169,10 @@ mt7615_tm_set_rx_enable(struct mt7615_dev *dev, bool en) } static void -mt7615_tm_set_tx_antenna(struct mt7615_dev *dev, bool en) +mt7615_tm_set_tx_antenna(struct mt7615_phy *phy, bool en) { - struct mt76_testmode_data *td = &dev->mt76.test; + struct mt7615_dev *dev = phy->dev; + struct mt76_testmode_data *td = &phy->mt76->test; u8 mask = td->tx_antenna_mask; int i; @@ -185,7 +180,7 @@ mt7615_tm_set_tx_antenna(struct mt7615_dev *dev, bool en) return; if (!en) - mask = dev->phy.chainmask; + mask = phy->mt76->chainmask; for (i = 0; i < 4; i++) { mt76_rmw_field(dev, MT_WF_PHY_RFINTF3_0(i), @@ -228,26 +223,28 @@ mt7615_tm_set_tx_antenna(struct mt7615_dev *dev, bool en) } static void -mt7615_tm_set_tx_frames(struct mt7615_dev *dev, bool en) +mt7615_tm_set_tx_frames(struct mt7615_phy *phy, bool en) { + struct mt7615_dev *dev = phy->dev; struct ieee80211_tx_info *info; - struct sk_buff *skb = dev->mt76.test.tx_skb; + struct sk_buff *skb = phy->mt76->test.tx_skb; - mt7615_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH); - mt7615_tm_set_tx_antenna(dev, en); + mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); + mt7615_tm_set_tx_antenna(phy, en); mt7615_tm_set_rx_enable(dev, !en); if (!en || !skb) return; info = IEEE80211_SKB_CB(skb); - info->control.vif = dev->phy.monitor_vif; + info->control.vif = phy->monitor_vif; } static void -mt7615_tm_update_params(struct mt7615_dev *dev, u32 changed) +mt7615_tm_update_params(struct mt7615_phy *phy, u32 changed) { - struct mt76_testmode_data *td = &dev->mt76.test; - bool en = dev->mt76.test.state != MT76_TM_STATE_OFF; + struct mt7615_dev *dev = phy->dev; + struct mt76_testmode_data *td = &phy->mt76->test; + bool en = phy->mt76->test.state != MT76_TM_STATE_OFF; if (changed & BIT(TM_CHANGED_TXPOWER_CTRL)) mt7615_mcu_set_test_param(dev, MCU_ATE_SET_TX_POWER_CONTROL, @@ -256,25 +253,25 @@ mt7615_tm_update_params(struct mt7615_dev *dev, u32 changed) mt7615_mcu_set_test_param(dev, MCU_ATE_SET_FREQ_OFFSET, en, en ? td->freq_offset : 0); if (changed & BIT(TM_CHANGED_TXPOWER)) - mt7615_tm_set_tx_power(&dev->phy); + mt7615_tm_set_tx_power(phy); } static int -mt7615_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state) +mt7615_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state) { - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - struct mt76_testmode_data *td = &mdev->test; + struct mt7615_phy *phy = mphy->priv; + struct mt76_testmode_data *td = &mphy->test; enum mt76_testmode_state prev_state = td->state; - mdev->test.state = state; + mphy->test.state = state; if (prev_state == MT76_TM_STATE_TX_FRAMES) - mt7615_tm_set_tx_frames(dev, false); + mt7615_tm_set_tx_frames(phy, false); else if (state == MT76_TM_STATE_TX_FRAMES) - mt7615_tm_set_tx_frames(dev, true); + mt7615_tm_set_tx_frames(phy, true); if (state <= MT76_TM_STATE_IDLE) - mt7615_tm_init(dev); + mt7615_tm_init(phy); if ((state == MT76_TM_STATE_IDLE && prev_state == MT76_TM_STATE_OFF) || @@ -290,18 +287,18 @@ mt7615_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state) changed |= BIT(i); } - mt7615_tm_update_params(dev, changed); + mt7615_tm_update_params(phy, changed); } return 0; } static int -mt7615_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, +mt7615_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, enum mt76_testmode_state new_state) { - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - struct mt76_testmode_data *td = &dev->mt76.test; + struct mt76_testmode_data *td = &mphy->test; + struct mt7615_phy *phy = mphy->priv; u32 changed = 0; int i; @@ -311,7 +308,7 @@ mt7615_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, td->state == MT76_TM_STATE_OFF) return 0; - if (td->tx_antenna_mask & ~dev->phy.chainmask) + if (td->tx_antenna_mask & ~mphy->chainmask) return -EINVAL; for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { @@ -319,15 +316,15 @@ mt7615_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, changed |= BIT(i); } - mt7615_tm_update_params(dev, changed); + mt7615_tm_update_params(phy, changed); return 0; } static int -mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) +mt7615_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) { - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt7615_phy *phy = mphy->priv; void *rx, *rssi; int i; @@ -335,15 +332,15 @@ mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) if (!rx) return -ENOMEM; - if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset)) + if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset)) return -ENOMEM; rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI); if (!rssi) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dev->test.last_rcpi); i++) - if (nla_put_u8(msg, i, dev->test.last_rcpi[i])) + for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) + if (nla_put_u8(msg, i, phy->test.last_rcpi[i])) return -ENOMEM; nla_nest_end(msg, rssi); @@ -352,8 +349,8 @@ mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) if (!rssi) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dev->test.last_ib_rssi); i++) - if (nla_put_s8(msg, i, dev->test.last_ib_rssi[i])) + for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++) + if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); @@ -362,8 +359,8 @@ mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) if (!rssi) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dev->test.last_wb_rssi); i++) - if (nla_put_s8(msg, i, dev->test.last_wb_rssi[i])) + for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++) + if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index a60cfa345521..0396ad532ba6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -29,7 +29,7 @@ static void mt7663u_stop(struct ieee80211_hw *hw) del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); cancel_delayed_work_sync(&phy->scan_work); - cancel_delayed_work_sync(&phy->mac_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); mt76u_stop_tx(&dev->mt76); } @@ -47,11 +47,7 @@ static void mt7663u_init_work(struct work_struct *work) if (mt7663u_mcu_init(dev)) return; - mt7615_mcu_set_eeprom(dev); - mt7615_mac_init(dev); - mt7615_phy_init(dev); - mt7615_mcu_del_wtbl_all(dev); - mt7615_check_offload_capability(dev); + mt7615_init_work(dev); } static int mt7663u_probe(struct usb_interface *usb_intf, @@ -173,7 +169,7 @@ static int mt7663u_suspend(struct usb_interface *intf, pm_message_t state) mt7615_firmware_offload(dev)) { int err; - err = mt7615_mcu_set_hif_suspend(dev, true); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); if (err < 0) return err; } @@ -201,7 +197,7 @@ static int mt7663u_resume(struct usb_interface *intf) if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev)) - err = mt7615_mcu_set_hif_suspend(dev, false); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h new file mode 100644 index 000000000000..0d58606391b0 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT76_CONNAC_H +#define __MT76_CONNAC_H + +#include "mt76.h" + +#define MT76_CONNAC_SCAN_IE_LEN 600 +#define MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL 10 +#define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10 +#define MT76_CONNAC_MAX_SCAN_MATCH 16 + +#define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) +#define MT76_CONNAC_COREDUMP_SZ (128 * 1024) + +enum { + CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, + CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, + CMD_CBW_80MHZ = IEEE80211_STA_RX_BW_80, + CMD_CBW_160MHZ = IEEE80211_STA_RX_BW_160, + CMD_CBW_10MHZ, + CMD_CBW_5MHZ, + CMD_CBW_8080MHZ, + + CMD_HE_MCS_BW80 = 0, + CMD_HE_MCS_BW160, + CMD_HE_MCS_BW8080, + CMD_HE_MCS_BW_NUM +}; + +enum { + HW_BSSID_0 = 0x0, + HW_BSSID_1, + HW_BSSID_2, + HW_BSSID_3, + HW_BSSID_MAX = HW_BSSID_3, + EXT_BSSID_START = 0x10, + EXT_BSSID_1, + EXT_BSSID_15 = 0x1f, + EXT_BSSID_MAX = EXT_BSSID_15, + REPEATER_BSSID_START = 0x20, + REPEATER_BSSID_MAX = 0x3f, +}; + +struct mt76_connac_pm { + bool enable; + + spinlock_t txq_lock; + struct { + struct mt76_wcid *wcid; + struct sk_buff *skb; + } tx_q[IEEE80211_NUM_ACS]; + + struct work_struct wake_work; + struct completion wake_cmpl; + + struct delayed_work ps_work; + unsigned long last_activity; + unsigned long idle_timeout; +}; + +struct mt76_connac_coredump { + struct sk_buff_head msg_list; + struct delayed_work work; + unsigned long last_activity; +}; + +extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; + +static inline bool is_mt7921(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7961; +} + +int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm); +void mt76_connac_power_save_sched(struct mt76_phy *phy, + struct mt76_connac_pm *pm); +void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, + struct mt76_wcid *wcid); + +static inline void +mt76_connac_mutex_acquire(struct mt76_dev *dev, struct mt76_connac_pm *pm) + __acquires(&dev->mutex) +{ + mutex_lock(&dev->mutex); + mt76_connac_pm_wake(&dev->phy, pm); +} + +static inline void +mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) + __releases(&dev->mutex) +{ + mt76_connac_power_save_sched(&dev->phy, pm); + mutex_unlock(&dev->mutex); +} + +void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, + struct mt76_connac_pm *pm, + struct mt76_wcid *wcid, + struct sk_buff *skb); +void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, + struct mt76_connac_pm *pm); + +#endif /* __MT76_CONNAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c new file mode 100644 index 000000000000..c5f5037f5757 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt76_connac.h" + +int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) +{ + struct mt76_dev *dev = phy->dev; + + if (!pm->enable) + return 0; + + if (!mt76_is_mmio(dev)) + return 0; + + if (!test_bit(MT76_STATE_PM, &phy->state)) + return 0; + + if (test_bit(MT76_HW_SCANNING, &phy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &phy->state)) + return 0; + + if (queue_work(dev->wq, &pm->wake_work)) + reinit_completion(&pm->wake_cmpl); + + if (!wait_for_completion_timeout(&pm->wake_cmpl, 3 * HZ)) { + ieee80211_wake_queues(phy->hw); + return -ETIMEDOUT; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac_pm_wake); + +void mt76_connac_power_save_sched(struct mt76_phy *phy, + struct mt76_connac_pm *pm) +{ + struct mt76_dev *dev = phy->dev; + + if (!mt76_is_mmio(dev)) + return; + + if (!pm->enable || !test_bit(MT76_STATE_RUNNING, &phy->state)) + return; + + pm->last_activity = jiffies; + + if (test_bit(MT76_HW_SCANNING, &phy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &phy->state)) + return; + + if (!test_bit(MT76_STATE_PM, &phy->state)) + queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout); +} +EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched); + +void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, + struct mt76_wcid *wcid) +{ + int i; + + spin_lock_bh(&pm->txq_lock); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (wcid && pm->tx_q[i].wcid != wcid) + continue; + + dev_kfree_skb(pm->tx_q[i].skb); + pm->tx_q[i].skb = NULL; + } + spin_unlock_bh(&pm->txq_lock); +} +EXPORT_SYMBOL_GPL(mt76_connac_free_pending_tx_skbs); + +void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, + struct mt76_connac_pm *pm, + struct mt76_wcid *wcid, + struct sk_buff *skb) +{ + int qid = skb_get_queue_mapping(skb); + struct mt76_phy *phy = hw->priv; + + spin_lock_bh(&pm->txq_lock); + if (!pm->tx_q[qid].skb) { + ieee80211_stop_queues(hw); + pm->tx_q[qid].wcid = wcid; + pm->tx_q[qid].skb = skb; + queue_work(phy->dev->wq, &pm->wake_work); + } else { + dev_kfree_skb(skb); + } + spin_unlock_bh(&pm->txq_lock); +} +EXPORT_SYMBOL_GPL(mt76_connac_pm_queue_skb); + +void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, + struct mt76_connac_pm *pm) +{ + int i; + + spin_lock_bh(&pm->txq_lock); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + struct mt76_wcid *wcid = pm->tx_q[i].wcid; + struct ieee80211_sta *sta = NULL; + + if (!pm->tx_q[i].skb) + continue; + + if (wcid && wcid->sta) + sta = container_of((void *)wcid, struct ieee80211_sta, + drv_priv); + + mt76_tx(phy, sta, wcid, pm->tx_q[i].skb); + pm->tx_q[i].skb = NULL; + } + spin_unlock_bh(&pm->txq_lock); + + mt76_worker_schedule(&phy->dev->tx_worker); +} +EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c new file mode 100644 index 000000000000..6cbccfb05f8b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -0,0 +1,1842 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt76_connac_mcu.h" + +int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option) +{ + struct { + __le32 option; + __le32 addr; + } req = { + .option = cpu_to_le32(option), + .addr = cpu_to_le32(addr), + }; + + return mt76_mcu_send_msg(dev, MCU_CMD_FW_START_REQ, &req, sizeof(req), + true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_start_firmware); + +int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get) +{ + u32 op = get ? PATCH_SEM_GET : PATCH_SEM_RELEASE; + struct { + __le32 op; + } req = { + .op = cpu_to_le32(op), + }; + + return mt76_mcu_send_msg(dev, MCU_CMD_PATCH_SEM_CONTROL, &req, + sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_patch_sem_ctrl); + +int mt76_connac_mcu_start_patch(struct mt76_dev *dev) +{ + struct { + u8 check_crc; + u8 reserved[3]; + } req = { + .check_crc = 0, + }; + + return mt76_mcu_send_msg(dev, MCU_CMD_PATCH_FINISH_REQ, &req, + sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_start_patch); + +#define MCU_PATCH_ADDRESS 0x200000 + +int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, + u32 mode) +{ + struct { + __le32 addr; + __le32 len; + __le32 mode; + } req = { + .addr = cpu_to_le32(addr), + .len = cpu_to_le32(len), + .mode = cpu_to_le32(mode), + }; + int cmd; + + if (is_mt7921(dev) && + (req.addr == cpu_to_le32(MCU_PATCH_ADDRESS) || addr == 0x900000)) + cmd = MCU_CMD_PATCH_START_REQ; + else + cmd = MCU_CMD_TARGET_ADDRESS_LEN_REQ; + + return mt76_mcu_send_msg(dev, cmd, &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_init_download); + +int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy) +{ + struct mt76_dev *dev = phy->dev; + struct mt76_connac_mcu_channel_domain { + u8 alpha2[4]; /* regulatory_request.alpha2 */ + u8 bw_2g; /* BW_20_40M 0 + * BW_20M 1 + * BW_20_40_80M 2 + * BW_20_40_80_160M 3 + * BW_20_40_80_8080M 4 + */ + u8 bw_5g; + __le16 pad; + u8 n_2ch; + u8 n_5ch; + __le16 pad2; + } __packed hdr = { + .bw_2g = 0, + .bw_5g = 3, + }; + struct mt76_connac_mcu_chan { + __le16 hw_value; + __le16 pad; + __le32 flags; + } __packed channel; + int len, i, n_max_channels, n_2ch = 0, n_5ch = 0; + struct ieee80211_channel *chan; + struct sk_buff *skb; + + n_max_channels = phy->sband_2g.sband.n_channels + + phy->sband_5g.sband.n_channels; + len = sizeof(hdr) + n_max_channels * sizeof(channel); + + skb = mt76_mcu_msg_alloc(dev, NULL, len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, sizeof(hdr)); + + for (i = 0; i < phy->sband_2g.sband.n_channels; i++) { + chan = &phy->sband_2g.sband.channels[i]; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + channel.hw_value = cpu_to_le16(chan->hw_value); + channel.flags = cpu_to_le32(chan->flags); + channel.pad = 0; + + skb_put_data(skb, &channel, sizeof(channel)); + n_2ch++; + } + for (i = 0; i < phy->sband_5g.sband.n_channels; i++) { + chan = &phy->sband_5g.sband.channels[i]; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + channel.hw_value = cpu_to_le16(chan->hw_value); + channel.flags = cpu_to_le32(chan->flags); + channel.pad = 0; + + skb_put_data(skb, &channel, sizeof(channel)); + n_5ch++; + } + + BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(hdr.alpha2)); + memcpy(hdr.alpha2, dev->alpha2, sizeof(dev->alpha2)); + hdr.n_2ch = n_2ch; + hdr.n_5ch = n_5ch; + + memcpy(__skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); + + return mt76_mcu_skb_send_msg(dev, skb, MCU_CMD_SET_CHAN_DOMAIN, false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_channel_domain); + +int mt76_connac_mcu_set_mac_enable(struct mt76_dev *dev, int band, bool enable, + bool hdr_trans) +{ + struct { + u8 enable; + u8 band; + u8 rsv[2]; + } __packed req_mac = { + .enable = enable, + .band = band, + }; + + return mt76_mcu_send_msg(dev, MCU_EXT_CMD_MAC_INIT_CTRL, &req_mac, + sizeof(req_mac), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_mac_enable); + +int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct { + u8 bss_idx; + u8 ps_state; /* 0: device awake + * 1: static power save + * 2: dynamic power saving + */ + } req = { + .bss_idx = mvif->idx, + .ps_state = vif->bss_conf.ps ? 2 : 0, + }; + + if (vif->type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + return mt76_mcu_send_msg(dev, MCU_CMD_SET_PS_PROFILE, &req, + sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_vif_ps); + +int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band) +{ + struct { + u8 prot_idx; + u8 band; + u8 rsv[2]; + __le32 len_thresh; + __le32 pkt_thresh; + } __packed req = { + .prot_idx = 1, + .band = band, + .len_thresh = cpu_to_le32(val), + .pkt_thresh = cpu_to_le32(0x2), + }; + + return mt76_mcu_send_msg(dev, MCU_EXT_CMD_PROTECT_CTRL, &req, + sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rts_thresh); + +void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_connac_beacon_loss_event *event = priv; + + if (mvif->idx != event->bss_idx) + return; + + if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) + return; + + ieee80211_beacon_loss(vif); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_beacon_loss_iter); + +struct tlv * +mt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, + void *sta_ntlv, void *sta_wtbl) +{ + struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; + struct tlv *sta_hdr = sta_wtbl; + struct tlv *ptlv, tlv = { + .tag = cpu_to_le16(tag), + .len = cpu_to_le16(len), + }; + u16 ntlv; + + ptlv = skb_put(skb, len); + memcpy(ptlv, &tlv, sizeof(tlv)); + + ntlv = le16_to_cpu(ntlv_hdr->tlv_num); + ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); + + if (sta_hdr) { + u16 size = le16_to_cpu(sta_hdr->len); + + sta_hdr->len = cpu_to_le16(size + len); + } + + return ptlv; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_nested_tlv); + +struct sk_buff * +mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif, + struct mt76_wcid *wcid) +{ + struct sta_req_hdr hdr = { + .bss_idx = mvif->idx, + .muar_idx = wcid ? mvif->omac_idx : 0, + .is_tlv_append = 1, + }; + struct sk_buff *skb; + + mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo, + &hdr.wlan_idx_hi); + skb = mt76_mcu_msg_alloc(dev, NULL, MT76_CONNAC_STA_UPDATE_MAX_SIZE); + if (!skb) + return ERR_PTR(-ENOMEM); + + skb_put_data(skb, &hdr, sizeof(hdr)); + + return skb; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_sta_req); + +struct wtbl_req_hdr * +mt76_connac_mcu_alloc_wtbl_req(struct mt76_dev *dev, struct mt76_wcid *wcid, + int cmd, void *sta_wtbl, struct sk_buff **skb) +{ + struct tlv *sta_hdr = sta_wtbl; + struct wtbl_req_hdr hdr = { + .operation = cmd, + }; + struct sk_buff *nskb = *skb; + + mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo, + &hdr.wlan_idx_hi); + if (!nskb) { + nskb = mt76_mcu_msg_alloc(dev, NULL, + MT76_CONNAC_WTBL_UPDATE_BA_SIZE); + if (!nskb) + return ERR_PTR(-ENOMEM); + + *skb = nskb; + } + + if (sta_hdr) + sta_hdr->len = cpu_to_le16(sizeof(hdr)); + + return skb_put_data(nskb, &hdr, sizeof(hdr)); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_wtbl_req); + +void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + bool enable) +{ + struct sta_rec_basic *basic; + struct tlv *tlv; + int conn_type; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); + + basic = (struct sta_rec_basic *)tlv; + basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); + + if (enable) { + basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); + basic->conn_state = CONN_STATE_PORT_SECURE; + } else { + basic->conn_state = CONN_STATE_DISCONNECT; + } + + if (!sta) { + basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); + eth_broadcast_addr(basic->peer_addr); + return; + } + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + if (vif->p2p) + conn_type = CONNECTION_P2P_GC; + else + conn_type = CONNECTION_INFRA_STA; + basic->conn_type = cpu_to_le32(conn_type); + basic->aid = cpu_to_le16(sta->aid); + break; + case NL80211_IFTYPE_STATION: + if (vif->p2p) + conn_type = CONNECTION_P2P_GO; + else + conn_type = CONNECTION_INFRA_AP; + basic->conn_type = cpu_to_le32(conn_type); + basic->aid = cpu_to_le16(vif->bss_conf.aid); + break; + case NL80211_IFTYPE_ADHOC: + basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + basic->aid = cpu_to_le16(sta->aid); + break; + default: + WARN_ON(1); + break; + } + + memcpy(basic->peer_addr, sta->addr, ETH_ALEN); + basic->qos = sta->wme; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_basic_tlv); + +static void +mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct sta_rec_uapsd *uapsd; + struct tlv *tlv; + + if (vif->type != NL80211_IFTYPE_AP || !sta->wme) + return; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); + uapsd = (struct sta_rec_uapsd *)tlv; + + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { + uapsd->dac_map |= BIT(3); + uapsd->tac_map |= BIT(3); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { + uapsd->dac_map |= BIT(2); + uapsd->tac_map |= BIT(2); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { + uapsd->dac_map |= BIT(1); + uapsd->tac_map |= BIT(1); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { + uapsd->dac_map |= BIT(0); + uapsd->tac_map |= BIT(0); + } + uapsd->max_sp = sta->max_sp; +} + +void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, + struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + void *sta_wtbl, void *wtbl_tlv) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct wtbl_generic *generic; + struct wtbl_rx *rx; + struct wtbl_spe *spe; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_GENERIC, + sizeof(*generic), + wtbl_tlv, sta_wtbl); + + generic = (struct wtbl_generic *)tlv; + + if (sta) { + if (vif->type == NL80211_IFTYPE_STATION) + generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); + else + generic->partial_aid = cpu_to_le16(sta->aid); + memcpy(generic->peer_addr, sta->addr, ETH_ALEN); + generic->muar_idx = mvif->omac_idx; + generic->qos = sta->wme; + } else { + if (is_mt7921(dev) && + vif->type == NL80211_IFTYPE_STATION) + memcpy(generic->peer_addr, vif->bss_conf.bssid, + ETH_ALEN); + else + eth_broadcast_addr(generic->peer_addr); + + generic->muar_idx = 0xe; + } + + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), + wtbl_tlv, sta_wtbl); + + rx = (struct wtbl_rx *)tlv; + rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; + rx->rca2 = 1; + rx->rv = 1; + + if (is_mt7921(dev)) + return; + + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SPE, sizeof(*spe), + wtbl_tlv, sta_wtbl); + spe = (struct wtbl_spe *)tlv; + spe->spe_idx = 24; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_generic_tlv); + +static void +mt76_connac_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + struct ieee80211_vif *vif) +{ + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + struct sta_rec_amsdu *amsdu; + struct tlv *tlv; + + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_STATION) + return; + + if (!sta->max_amsdu_len) + return; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); + amsdu = (struct sta_rec_amsdu *)tlv; + amsdu->max_amsdu_num = 8; + amsdu->amsdu_en = true; + amsdu->max_mpdu_size = sta->max_amsdu_len >= + IEEE80211_MAX_MPDU_LEN_VHT_7991; + + wcid->amsdu = true; +} + +#define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) +#define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) +static void +mt76_connac_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; + struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct sta_rec_he *he; + struct tlv *tlv; + u32 cap = 0; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); + + he = (struct sta_rec_he *)tlv; + + if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) + cap |= STA_REC_HE_CAP_HTC; + + if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) + cap |= STA_REC_HE_CAP_BSR; + + if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) + cap |= STA_REC_HE_CAP_OM; + + if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU) + cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; + + if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) + cap |= STA_REC_HE_CAP_BQR; + + if (elem->phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) + cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; + + if (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) + cap |= STA_REC_HE_CAP_LDPC; + + if (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) + cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) + cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) + cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) + cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; + + if (elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) + cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) + cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) + cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; + + if (elem->phy_cap_info[8] & + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; + + if (elem->phy_cap_info[8] & + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK) + cap |= STA_REC_HE_CAP_TRIG_CQI_FK; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) + cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) + cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; + + he->he_cap = cpu_to_le32(cap); + + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + if (elem->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) + he->max_nss_mcs[CMD_HE_MCS_BW8080] = + he_cap->he_mcs_nss_supp.rx_mcs_80p80; + + he->max_nss_mcs[CMD_HE_MCS_BW160] = + he_cap->he_mcs_nss_supp.rx_mcs_160; + fallthrough; + default: + he->max_nss_mcs[CMD_HE_MCS_BW80] = + he_cap->he_mcs_nss_supp.rx_mcs_80; + break; + } + + he->t_frame_dur = + HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); + he->max_ampdu_exp = + HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); + + he->bw_set = + HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); + he->device_class = + HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); + he->punc_pream_rx = + HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); + + he->dcm_tx_mode = + HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); + he->dcm_tx_max_nss = + HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); + he->dcm_rx_mode = + HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); + he->dcm_rx_max_nss = + HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); + he->dcm_rx_max_nss = + HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); + + he->pkt_ext = 2; +} + +static u8 +mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, + enum nl80211_band band, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + const struct ieee80211_sta_he_cap *he_cap; + u8 mode = 0; + + if (sta) { + ht_cap = &sta->ht_cap; + vht_cap = &sta->vht_cap; + he_cap = &sta->he_cap; + } else { + struct ieee80211_supported_band *sband; + + sband = mphy->hw->wiphy->bands[band]; + ht_cap = &sband->ht_cap; + vht_cap = &sband->vht_cap; + he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); + } + + if (band == NL80211_BAND_2GHZ) { + mode |= PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP; + + if (ht_cap->ht_supported) + mode |= PHY_TYPE_BIT_HT; + + if (he_cap->has_he) + mode |= PHY_TYPE_BIT_HE; + } else if (band == NL80211_BAND_5GHZ) { + mode |= PHY_TYPE_BIT_OFDM; + + if (ht_cap->ht_supported) + mode |= PHY_TYPE_BIT_HT; + + if (vht_cap->vht_supported) + mode |= PHY_TYPE_BIT_VHT; + + if (he_cap->has_he) + mode |= PHY_TYPE_BIT_HE; + } + + return mode; +} + +void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, + struct ieee80211_sta *sta, + struct ieee80211_vif *vif) +{ + struct cfg80211_chan_def *chandef = &mphy->chandef; + enum nl80211_band band = chandef->chan->band; + struct mt76_dev *dev = mphy->dev; + struct sta_rec_ra_info *ra_info; + struct sta_rec_state *state; + struct sta_rec_phy *phy; + struct tlv *tlv; + + /* starec ht */ + if (sta->ht_cap.ht_supported) { + struct sta_rec_ht *ht; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); + ht = (struct sta_rec_ht *)tlv; + ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); + } + + /* starec vht */ + if (sta->vht_cap.vht_supported) { + struct sta_rec_vht *vht; + int len; + + len = is_mt7921(dev) ? sizeof(*vht) : sizeof(*vht) - 4; + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len); + vht = (struct sta_rec_vht *)tlv; + vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); + vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; + } + + /* starec uapsd */ + mt76_connac_mcu_sta_uapsd(skb, vif, sta); + + if (!is_mt7921(dev)) + return; + + if (sta->ht_cap.ht_supported) + mt76_connac_mcu_sta_amsdu_tlv(skb, sta, vif); + + /* starec he */ + if (sta->he_cap.has_he) + mt76_connac_mcu_sta_he_tlv(skb, sta); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); + phy = (struct sta_rec_phy *)tlv; + phy->phy_type = mt76_connac_get_phy_mode_v2(mphy, vif, band, sta); + phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); + ra_info = (struct sta_rec_ra_info *)tlv; + ra_info->legacy = cpu_to_le16((u16)sta->supp_rates[band]); + + if (sta->ht_cap.ht_supported) + memcpy(ra_info->rx_mcs_bitmask, sta->ht_cap.mcs.rx_mask, + HT_MCS_MASK_NUM); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state)); + state = (struct sta_rec_state *)tlv; + state->state = 2; + + if (sta->vht_cap.vht_supported) { + state->vht_opmode = sta->bandwidth; + state->vht_opmode |= (sta->rx_nss - 1) << + IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; + } +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_tlv); + +static void +mt76_connac_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + void *sta_wtbl, void *wtbl_tlv) +{ + struct wtbl_smps *smps; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), + wtbl_tlv, sta_wtbl); + smps = (struct wtbl_smps *)tlv; + + if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) + smps->smps = true; +} + +void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta, void *sta_wtbl, + void *wtbl_tlv) +{ + struct wtbl_ht *ht = NULL; + struct tlv *tlv; + u32 flags = 0; + + if (sta->ht_cap.ht_supported) { + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), + wtbl_tlv, sta_wtbl); + ht = (struct wtbl_ht *)tlv; + ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING); + ht->af = sta->ht_cap.ampdu_factor; + ht->mm = sta->ht_cap.ampdu_density; + ht->ht = true; + } + + if (sta->vht_cap.vht_supported) { + struct wtbl_vht *vht; + u8 af; + + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_VHT, + sizeof(*vht), wtbl_tlv, + sta_wtbl); + vht = (struct wtbl_vht *)tlv; + vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + vht->vht = true; + + af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + sta->vht_cap.cap); + if (ht) + ht->af = max(ht->af, af); + } + + mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv); + + if (!is_mt7921(dev) && sta->ht_cap.ht_supported) { + /* sgi */ + u32 msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 | + MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160; + struct wtbl_raw *raw; + + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RAW_DATA, + sizeof(*raw), wtbl_tlv, + sta_wtbl); + + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) + flags |= MT_WTBL_W5_SHORT_GI_20; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) + flags |= MT_WTBL_W5_SHORT_GI_40; + + if (sta->vht_cap.vht_supported) { + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) + flags |= MT_WTBL_W5_SHORT_GI_80; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) + flags |= MT_WTBL_W5_SHORT_GI_160; + } + raw = (struct wtbl_raw *)tlv; + raw->val = cpu_to_le32(flags); + raw->msk = cpu_to_le32(~msk); + raw->wtbl_idx = 1; + raw->dw = 5; + } +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ht_tlv); + +int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct mt76_wcid *wcid, + bool enable, int cmd) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_dev *dev = phy->dev; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable); + if (enable && sta) + mt76_connac_mcu_sta_tlv(phy, skb, sta, vif); + + sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, + sizeof(struct tlv)); + + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, + WTBL_RESET_AND_SET, + sta_wtbl, &skb); + if (enable) { + mt76_connac_mcu_wtbl_generic_tlv(dev, skb, vif, sta, sta_wtbl, + wtbl_hdr); + if (sta) + mt76_connac_mcu_wtbl_ht_tlv(dev, skb, sta, sta_wtbl, + wtbl_hdr); + } + + return mt76_mcu_skb_send_msg(dev, skb, cmd, true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_sta_cmd); + +void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx, void *sta_wtbl, + void *wtbl_tlv) +{ + struct wtbl_ba *ba; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), + wtbl_tlv, sta_wtbl); + + ba = (struct wtbl_ba *)tlv; + ba->tid = params->tid; + + if (tx) { + ba->ba_type = MT_BA_TYPE_ORIGINATOR; + ba->sn = enable ? cpu_to_le16(params->ssn) : 0; + ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0; + ba->ba_en = enable; + } else { + memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); + ba->ba_type = MT_BA_TYPE_RECIPIENT; + ba->rst_ba_tid = params->tid; + ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; + ba->rst_ba_sb = 1; + } + + if (is_mt7921(dev)) + return; + + if (enable && tx) { + u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 }; + int i; + + for (i = 7; i > 0; i--) { + if (params->buf_size >= ba_range[i]) + break; + } + ba->ba_winsize_idx = i; + } +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ba_tlv); + +int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, + bool enable) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_dev *dev = phy->dev; + struct { + struct { + u8 omac_idx; + u8 band_idx; + __le16 pad; + } __packed hdr; + struct req_tlv { + __le16 tag; + __le16 len; + u8 active; + u8 pad; + u8 omac_addr[ETH_ALEN]; + } __packed tlv; + } dev_req = { + .hdr = { + .omac_idx = mvif->omac_idx, + .band_idx = mvif->band_idx, + }, + .tlv = { + .tag = cpu_to_le16(DEV_INFO_ACTIVE), + .len = cpu_to_le16(sizeof(struct req_tlv)), + .active = enable, + }, + }; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt76_connac_bss_basic_tlv basic; + } basic_req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .basic = { + .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), + .len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)), + .omac_idx = mvif->omac_idx, + .band_idx = mvif->band_idx, + .wmm_idx = mvif->wmm_idx, + .active = enable, + .bmc_tx_wlan_idx = cpu_to_le16(wcid->idx), + .sta_idx = cpu_to_le16(wcid->idx), + .conn_state = 1, + }, + }; + int err, idx, cmd, len; + void *data; + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + break; + case NL80211_IFTYPE_STATION: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + break; + case NL80211_IFTYPE_ADHOC: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; + default: + WARN_ON(1); + break; + } + + idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; + basic_req.basic.hw_bss_idx = idx; + + memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); + + cmd = enable ? MCU_UNI_CMD_DEV_INFO_UPDATE : MCU_UNI_CMD_BSS_INFO_UPDATE; + data = enable ? (void *)&dev_req : (void *)&basic_req; + len = enable ? sizeof(dev_req) : sizeof(basic_req); + + err = mt76_mcu_send_msg(dev, cmd, data, len, true); + if (err < 0) + return err; + + cmd = enable ? MCU_UNI_CMD_BSS_INFO_UPDATE : MCU_UNI_CMD_DEV_INFO_UPDATE; + data = enable ? (void *)&basic_req : (void *)&dev_req; + len = enable ? sizeof(basic_req) : sizeof(dev_req); + + return mt76_mcu_send_msg(dev, cmd, data, len, true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_dev); + +void mt76_connac_mcu_sta_ba_tlv(struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx) +{ + struct sta_rec_ba *ba; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); + + ba = (struct sta_rec_ba *)tlv; + ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT; + ba->winsize = cpu_to_le16(params->buf_size); + ba->ssn = cpu_to_le16(params->ssn); + ba->ba_en = enable << params->tid; + ba->amsdu = params->amsdu; + ba->tid = params->tid; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba_tlv); + +int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, + struct ieee80211_ampdu_params *params, + bool enable, bool tx) +{ + struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + int ret; + + skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, + sizeof(struct tlv)); + + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET, + sta_wtbl, &skb); + if (IS_ERR(wtbl_hdr)) + return PTR_ERR(wtbl_hdr); + + mt76_connac_mcu_wtbl_ba_tlv(dev, skb, params, enable, tx, sta_wtbl, + wtbl_hdr); + + ret = mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_STA_REC_UPDATE, true); + if (ret) + return ret; + + skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); + + return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_STA_REC_UPDATE, + true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba); + +static u8 +mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, + enum nl80211_band band, + struct ieee80211_sta *sta) +{ + struct mt76_dev *dev = phy->dev; + const struct ieee80211_sta_he_cap *he_cap; + struct ieee80211_sta_vht_cap *vht_cap; + struct ieee80211_sta_ht_cap *ht_cap; + u8 mode = 0; + + if (!is_mt7921(dev)) + return 0x38; + + if (sta) { + ht_cap = &sta->ht_cap; + vht_cap = &sta->vht_cap; + he_cap = &sta->he_cap; + } else { + struct ieee80211_supported_band *sband; + + sband = phy->hw->wiphy->bands[band]; + ht_cap = &sband->ht_cap; + vht_cap = &sband->vht_cap; + he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); + } + + if (band == NL80211_BAND_2GHZ) { + mode |= PHY_MODE_B | PHY_MODE_G; + + if (ht_cap->ht_supported) + mode |= PHY_MODE_GN; + + if (he_cap->has_he) + mode |= PHY_MODE_AX_24G; + } else if (band == NL80211_BAND_5GHZ) { + mode |= PHY_MODE_A; + + if (ht_cap->ht_supported) + mode |= PHY_MODE_AN; + + if (vht_cap->vht_supported) + mode |= PHY_MODE_AC; + + if (he_cap->has_he) + mode |= PHY_MODE_AX_5G; + } + + return mode; +} + +static const struct ieee80211_sta_he_cap * +mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif) +{ + enum nl80211_band band = phy->chandef.chan->band; + struct ieee80211_supported_band *sband; + + sband = phy->hw->wiphy->bands[band]; + + return ieee80211_get_he_iftype_cap(sband, vif->type); +} + +#define DEFAULT_HE_PE_DURATION 4 +#define DEFAULT_HE_DURATION_RTS_THRES 1023 +static void +mt76_connac_mcu_uni_bss_he_tlv(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct tlv *tlv) +{ + const struct ieee80211_sta_he_cap *cap; + struct bss_info_uni_he *he; + + cap = mt76_connac_get_he_phy_cap(phy, vif); + + he = (struct bss_info_uni_he *)tlv; + he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; + if (!he->he_pe_duration) + he->he_pe_duration = DEFAULT_HE_PE_DURATION; + + he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); + if (!he->he_rts_thres) + he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); + + he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; + he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; + he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; +} + +int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, + bool enable) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct cfg80211_chan_def *chandef = &phy->chandef; + int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; + enum nl80211_band band = chandef->chan->band; + struct mt76_dev *mdev = phy->dev; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt76_connac_bss_basic_tlv basic; + struct mt76_connac_bss_qos_tlv qos; + } basic_req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .basic = { + .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), + .len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)), + .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), + .dtim_period = vif->bss_conf.dtim_period, + .omac_idx = mvif->omac_idx, + .band_idx = mvif->band_idx, + .wmm_idx = mvif->wmm_idx, + .active = true, /* keep bss deactivated */ + .phymode = mt76_connac_get_phy_mode(phy, vif, band, NULL), + }, + .qos = { + .tag = cpu_to_le16(UNI_BSS_INFO_QBSS), + .len = cpu_to_le16(sizeof(struct mt76_connac_bss_qos_tlv)), + .qos = vif->bss_conf.qos, + }, + }; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct rlm_tlv { + __le16 tag; + __le16 len; + u8 control_channel; + u8 center_chan; + u8 center_chan2; + u8 bw; + u8 tx_streams; + u8 rx_streams; + u8 short_st; + u8 ht_op_info; + u8 sco; + u8 pad[3]; + } __packed rlm; + } __packed rlm_req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .rlm = { + .tag = cpu_to_le16(UNI_BSS_INFO_RLM), + .len = cpu_to_le16(sizeof(struct rlm_tlv)), + .control_channel = chandef->chan->hw_value, + .center_chan = ieee80211_frequency_to_channel(freq1), + .center_chan2 = ieee80211_frequency_to_channel(freq2), + .tx_streams = hweight8(phy->antenna_mask), + .rx_streams = phy->chainmask, + .short_st = true, + }, + }; + int err, conn_type; + u8 idx; + + idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; + basic_req.basic.hw_bss_idx = idx; + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + if (vif->p2p) + conn_type = CONNECTION_P2P_GO; + else + conn_type = CONNECTION_INFRA_AP; + basic_req.basic.conn_type = cpu_to_le32(conn_type); + break; + case NL80211_IFTYPE_STATION: + if (vif->p2p) + conn_type = CONNECTION_P2P_GC; + else + conn_type = CONNECTION_INFRA_STA; + basic_req.basic.conn_type = cpu_to_le32(conn_type); + break; + case NL80211_IFTYPE_ADHOC: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; + default: + WARN_ON(1); + break; + } + + memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); + basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(wcid->idx); + basic_req.basic.sta_idx = cpu_to_le16(wcid->idx); + basic_req.basic.conn_state = !enable; + + err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD_BSS_INFO_UPDATE, &basic_req, + sizeof(basic_req), true); + if (err < 0) + return err; + + if (vif->bss_conf.he_support) { + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct bss_info_uni_he he; + } he_req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .he = { + .tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC), + .len = cpu_to_le16(sizeof(struct bss_info_uni_he)), + }, + }; + + mt76_connac_mcu_uni_bss_he_tlv(phy, vif, + (struct tlv *)&he_req.he); + err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD_BSS_INFO_UPDATE, + &he_req, sizeof(he_req), true); + if (err < 0) + return err; + } + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + rlm_req.rlm.bw = CMD_CBW_40MHZ; + break; + case NL80211_CHAN_WIDTH_80: + rlm_req.rlm.bw = CMD_CBW_80MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + rlm_req.rlm.bw = CMD_CBW_8080MHZ; + break; + case NL80211_CHAN_WIDTH_160: + rlm_req.rlm.bw = CMD_CBW_160MHZ; + break; + case NL80211_CHAN_WIDTH_5: + rlm_req.rlm.bw = CMD_CBW_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + rlm_req.rlm.bw = CMD_CBW_10MHZ; + break; + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + default: + rlm_req.rlm.bw = CMD_CBW_20MHZ; + break; + } + + if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan) + rlm_req.rlm.sco = 1; /* SCA */ + else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan) + rlm_req.rlm.sco = 3; /* SCB */ + + return mt76_mcu_send_msg(mdev, MCU_UNI_CMD_BSS_INFO_UPDATE, &rlm_req, + sizeof(rlm_req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss); + +#define MT76_CONNAC_SCAN_CHANNEL_TIME 60 +int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_scan_request *scan_req) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct cfg80211_scan_request *sreq = &scan_req->req; + int n_ssids = 0, err, i, duration = MT76_CONNAC_SCAN_CHANNEL_TIME; + int ext_channels_num = max_t(int, sreq->n_channels - 32, 0); + struct ieee80211_channel **scan_list = sreq->channels; + struct mt76_dev *mdev = phy->dev; + bool ext_phy = phy == mdev->phy2; + struct mt76_connac_mcu_scan_channel *chan; + struct mt76_connac_hw_scan_req *req; + struct sk_buff *skb; + + skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req)); + if (!skb) + return -ENOMEM; + + set_bit(MT76_HW_SCANNING, &phy->state); + mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; + + req = (struct mt76_connac_hw_scan_req *)skb_put(skb, sizeof(*req)); + + req->seq_num = mvif->scan_seq_num | ext_phy << 7; + req->bss_idx = mvif->idx; + req->scan_type = sreq->n_ssids ? 1 : 0; + req->probe_req_num = sreq->n_ssids ? 2 : 0; + req->version = 1; + + for (i = 0; i < sreq->n_ssids; i++) { + if (!sreq->ssids[i].ssid_len) + continue; + + req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); + memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, + sreq->ssids[i].ssid_len); + n_ssids++; + } + req->ssid_type = n_ssids ? BIT(2) : BIT(0); + req->ssid_type_ext = n_ssids ? BIT(0) : 0; + req->ssids_num = n_ssids; + + /* increase channel time for passive scan */ + if (!sreq->n_ssids) + duration *= 2; + req->timeout_value = cpu_to_le16(sreq->n_channels * duration); + req->channel_min_dwell_time = cpu_to_le16(duration); + req->channel_dwell_time = cpu_to_le16(duration); + + req->channels_num = min_t(u8, sreq->n_channels, 32); + req->ext_channels_num = min_t(u8, ext_channels_num, 32); + for (i = 0; i < req->channels_num + req->ext_channels_num; i++) { + if (i >= 32) + chan = &req->ext_channels[i - 32]; + else + chan = &req->channels[i]; + + chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; + chan->channel_num = scan_list[i]->hw_value; + } + req->channel_type = sreq->n_channels ? 4 : 0; + + if (sreq->ie_len > 0) { + memcpy(req->ies, sreq->ie, sreq->ie_len); + req->ies_len = cpu_to_le16(sreq->ie_len); + } + + memcpy(req->bssid, sreq->bssid, ETH_ALEN); + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + get_random_mask_addr(req->random_mac, sreq->mac_addr, + sreq->mac_addr_mask); + req->scan_func = 1; + } + + err = mt76_mcu_skb_send_msg(mdev, skb, MCU_CMD_START_HW_SCAN, false); + if (err < 0) + clear_bit(MT76_HW_SCANNING, &phy->state); + + return err; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_hw_scan); + +int mt76_connac_mcu_cancel_hw_scan(struct mt76_phy *phy, + struct ieee80211_vif *vif) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct { + u8 seq_num; + u8 is_ext_channel; + u8 rsv[2]; + } __packed req = { + .seq_num = mvif->scan_seq_num, + }; + + if (test_and_clear_bit(MT76_HW_SCANNING, &phy->state)) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(phy->hw, &info); + } + + return mt76_mcu_send_msg(phy->dev, MCU_CMD_CANCEL_HW_SCAN, &req, + sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_cancel_hw_scan); + +int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *sreq) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct ieee80211_channel **scan_list = sreq->channels; + struct mt76_connac_mcu_scan_channel *chan; + struct mt76_connac_sched_scan_req *req; + struct mt76_dev *mdev = phy->dev; + bool ext_phy = phy == mdev->phy2; + struct cfg80211_match_set *match; + struct cfg80211_ssid *ssid; + struct sk_buff *skb; + int i; + + skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req) + sreq->ie_len); + if (!skb) + return -ENOMEM; + + mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; + + req = (struct mt76_connac_sched_scan_req *)skb_put(skb, sizeof(*req)); + req->version = 1; + req->seq_num = mvif->scan_seq_num | ext_phy << 7; + + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + get_random_mask_addr(req->random_mac, sreq->mac_addr, + sreq->mac_addr_mask); + req->scan_func = 1; + } + + req->ssids_num = sreq->n_ssids; + for (i = 0; i < req->ssids_num; i++) { + ssid = &sreq->ssids[i]; + memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len); + req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len); + } + + req->match_num = sreq->n_match_sets; + for (i = 0; i < req->match_num; i++) { + match = &sreq->match_sets[i]; + memcpy(req->match[i].ssid, match->ssid.ssid, + match->ssid.ssid_len); + req->match[i].rssi_th = cpu_to_le32(match->rssi_thold); + req->match[i].ssid_len = match->ssid.ssid_len; + } + + req->channel_type = sreq->n_channels ? 4 : 0; + req->channels_num = min_t(u8, sreq->n_channels, 64); + for (i = 0; i < req->channels_num; i++) { + chan = &req->channels[i]; + chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; + chan->channel_num = scan_list[i]->hw_value; + } + + req->intervals_num = sreq->n_scan_plans; + for (i = 0; i < req->intervals_num; i++) + req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval); + + if (sreq->ie_len > 0) { + req->ie_len = cpu_to_le16(sreq->ie_len); + memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len); + } + + return mt76_mcu_skb_send_msg(mdev, skb, MCU_CMD_SCHED_SCAN_REQ, false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_req); + +int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy, + struct ieee80211_vif *vif, + bool enable) +{ + struct { + u8 active; /* 0: enabled 1: disabled */ + u8 rsv[3]; + } __packed req = { + .active = !enable, + }; + + if (enable) + set_bit(MT76_HW_SCHED_SCANNING, &phy->state); + else + clear_bit(MT76_HW_SCHED_SCANNING, &phy->state); + + return mt76_mcu_send_msg(phy->dev, MCU_CMD_SCHED_SCAN_ENABLE, &req, + sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable); + +int mt76_connac_mcu_chip_config(struct mt76_dev *dev) +{ + struct { + __le16 id; + u8 type; + u8 resp_type; + __le16 data_size; + __le16 resv; + u8 data[320]; + } req = { + .resp_type = 0, + }; + + memcpy(req.data, "assert", 7); + + return mt76_mcu_send_msg(dev, MCU_CMD_CHIP_CONFIG, &req, sizeof(req), + false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config); + +void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, + struct mt76_connac_coredump *coredump) +{ + spin_lock_bh(&dev->lock); + __skb_queue_tail(&coredump->msg_list, skb); + spin_unlock_bh(&dev->lock); + + coredump->last_activity = jiffies; + + queue_delayed_work(dev->wq, &coredump->work, + MT76_CONNAC_COREDUMP_TIMEOUT); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event); + +#ifdef CONFIG_PM + +const struct wiphy_wowlan_support mt76_connac_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT, + .n_patterns = 1, + .pattern_min_len = 1, + .pattern_max_len = MT76_CONNAC_WOW_PATTEN_MAX_LEN, + .max_nd_match_sets = 10, +}; +EXPORT_SYMBOL_GPL(mt76_connac_wowlan_support); + +static void +mt76_connac_mcu_key_iter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data) +{ + struct mt76_connac_gtk_rekey_tlv *gtk_tlv = data; + u32 cipher; + + if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC && + key->cipher != WLAN_CIPHER_SUITE_CCMP && + key->cipher != WLAN_CIPHER_SUITE_TKIP) + return; + + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { + gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1); + cipher = BIT(3); + } else { + gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2); + cipher = BIT(4); + } + + /* we are assuming here to have a single pairwise key */ + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + gtk_tlv->pairwise_cipher = cpu_to_le32(cipher); + gtk_tlv->group_cipher = cpu_to_le32(cipher); + gtk_tlv->keyid = key->keyidx; + } +} + +int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *key) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_connac_gtk_rekey_tlv *gtk_tlv; + struct mt76_phy *phy = hw->priv; + struct sk_buff *skb; + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr = { + .bss_idx = mvif->idx, + }; + + skb = mt76_mcu_msg_alloc(phy->dev, NULL, + sizeof(hdr) + sizeof(*gtk_tlv)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &hdr, sizeof(hdr)); + gtk_tlv = (struct mt76_connac_gtk_rekey_tlv *)skb_put(skb, + sizeof(*gtk_tlv)); + gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY); + gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv)); + gtk_tlv->rekey_mode = 2; + gtk_tlv->option = 1; + + rcu_read_lock(); + ieee80211_iter_keys_rcu(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv); + rcu_read_unlock(); + + memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN); + memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN); + memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN); + + return mt76_mcu_skb_send_msg(phy->dev, skb, MCU_UNI_CMD_OFFLOAD, true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_gtk_rekey); + +static int +mt76_connac_mcu_set_arp_filter(struct mt76_dev *dev, struct ieee80211_vif *vif, + bool suspend) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt76_connac_arpns_tlv arpns; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .arpns = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), + .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)), + .mode = suspend, + }, + }; + + return mt76_mcu_send_msg(dev, MCU_UNI_CMD_OFFLOAD, &req, sizeof(req), + true); +} + +static int +mt76_connac_mcu_set_gtk_rekey(struct mt76_dev *dev, struct ieee80211_vif *vif, + bool suspend) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt76_connac_gtk_rekey_tlv gtk_tlv; + } __packed req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .gtk_tlv = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY), + .len = cpu_to_le16(sizeof(struct mt76_connac_gtk_rekey_tlv)), + .rekey_mode = !suspend, + }, + }; + + return mt76_mcu_send_msg(dev, MCU_UNI_CMD_OFFLOAD, &req, sizeof(req), + true); +} + +static int +mt76_connac_mcu_set_suspend_mode(struct mt76_dev *dev, + struct ieee80211_vif *vif, + bool enable, u8 mdtim, + bool wow_suspend) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt76_connac_suspend_tlv suspend_tlv; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .suspend_tlv = { + .tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING), + .len = cpu_to_le16(sizeof(struct mt76_connac_suspend_tlv)), + .enable = enable, + .mdtim = mdtim, + .wow_suspend = wow_suspend, + }, + }; + + return mt76_mcu_send_msg(dev, MCU_UNI_CMD_SUSPEND, &req, sizeof(req), + true); +} + +static int +mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev, + struct ieee80211_vif *vif, + u8 index, bool enable, + struct cfg80211_pkt_pattern *pattern) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_connac_wow_pattern_tlv *ptlv; + struct sk_buff *skb; + struct req_hdr { + u8 bss_idx; + u8 pad[3]; + } __packed hdr = { + .bss_idx = mvif->idx, + }; + + skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + sizeof(*ptlv)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &hdr, sizeof(hdr)); + ptlv = (struct mt76_connac_wow_pattern_tlv *)skb_put(skb, sizeof(*ptlv)); + ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); + ptlv->len = cpu_to_le16(sizeof(*ptlv)); + ptlv->data_len = pattern->pattern_len; + ptlv->enable = enable; + ptlv->index = index; + + memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); + memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8); + + return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_SUSPEND, true); +} + +static int +mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif, + bool suspend, struct cfg80211_wowlan *wowlan) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_dev *dev = phy->dev; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt76_connac_wow_ctrl_tlv wow_ctrl_tlv; + struct mt76_connac_wow_gpio_param_tlv gpio_tlv; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .wow_ctrl_tlv = { + .tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL), + .len = cpu_to_le16(sizeof(struct mt76_connac_wow_ctrl_tlv)), + .cmd = suspend ? 1 : 2, + }, + .gpio_tlv = { + .tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM), + .len = cpu_to_le16(sizeof(struct mt76_connac_wow_gpio_param_tlv)), + .gpio_pin = 0xff, /* follow fw about GPIO pin */ + }, + }; + + if (wowlan->magic_pkt) + req.wow_ctrl_tlv.trigger |= BIT(0); + if (wowlan->disconnect) + req.wow_ctrl_tlv.trigger |= BIT(2); + if (wowlan->nd_config) { + mt76_connac_mcu_sched_scan_req(phy, vif, wowlan->nd_config); + req.wow_ctrl_tlv.trigger |= BIT(5); + mt76_connac_mcu_sched_scan_enable(phy, vif, suspend); + } + + if (mt76_is_mmio(dev)) + req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE; + else if (mt76_is_usb(dev)) + req.wow_ctrl_tlv.wakeup_hif = WOW_USB; + else if (mt76_is_sdio(dev)) + req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO; + + return mt76_mcu_send_msg(dev, MCU_UNI_CMD_SUSPEND, &req, sizeof(req), + true); +} + +int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend) +{ + struct { + struct { + u8 hif_type; /* 0x0: HIF_SDIO + * 0x1: HIF_USB + * 0x2: HIF_PCIE + */ + u8 pad[3]; + } __packed hdr; + struct hif_suspend_tlv { + __le16 tag; + __le16 len; + u8 suspend; + } __packed hif_suspend; + } req = { + .hif_suspend = { + .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ + .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), + .suspend = suspend, + }, + }; + + if (mt76_is_mmio(dev)) + req.hdr.hif_type = 2; + else if (mt76_is_usb(dev)) + req.hdr.hif_type = 1; + else if (mt76_is_sdio(dev)) + req.hdr.hif_type = 0; + + return mt76_mcu_send_msg(dev, MCU_UNI_CMD_HIF_CTRL, &req, sizeof(req), + true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_hif_suspend); + +void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_phy *phy = priv; + bool suspend = test_bit(MT76_STATE_SUSPEND, &phy->state); + struct ieee80211_hw *hw = phy->hw; + struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; + int i; + + mt76_connac_mcu_set_gtk_rekey(phy->dev, vif, suspend); + mt76_connac_mcu_set_arp_filter(phy->dev, vif, suspend); + + mt76_connac_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); + + for (i = 0; i < wowlan->n_patterns; i++) + mt76_connac_mcu_set_wow_pattern(phy->dev, vif, i, suspend, + &wowlan->patterns[i]); + mt76_connac_mcu_set_wow_ctrl(phy, vif, suspend, wowlan); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_iter); + +#endif /* CONFIG_PM */ + +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h new file mode 100644 index 000000000000..c1e1df5f7cd7 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -0,0 +1,979 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT76_CONNAC_MCU_H +#define __MT76_CONNAC_MCU_H + +#include "mt76_connac.h" + +struct tlv { + __le16 tag; + __le16 len; +} __packed; + +/* sta_rec */ + +struct sta_ntlv_hdr { + u8 rsv[2]; + __le16 tlv_num; +} __packed; + +struct sta_req_hdr { + u8 bss_idx; + u8 wlan_idx_lo; + __le16 tlv_num; + u8 is_tlv_append; + u8 muar_idx; + u8 wlan_idx_hi; + u8 rsv; +} __packed; + +struct sta_rec_basic { + __le16 tag; + __le16 len; + __le32 conn_type; + u8 conn_state; + u8 qos; + __le16 aid; + u8 peer_addr[ETH_ALEN]; +#define EXTRA_INFO_VER BIT(0) +#define EXTRA_INFO_NEW BIT(1) + __le16 extra_info; +} __packed; + +struct sta_rec_ht { + __le16 tag; + __le16 len; + __le16 ht_cap; + u16 rsv; +} __packed; + +struct sta_rec_vht { + __le16 tag; + __le16 len; + __le32 vht_cap; + __le16 vht_rx_mcs_map; + __le16 vht_tx_mcs_map; + /* mt7921 */ + u8 rts_bw_sig; + u8 rsv[3]; +} __packed; + +struct sta_rec_uapsd { + __le16 tag; + __le16 len; + u8 dac_map; + u8 tac_map; + u8 max_sp; + u8 rsv0; + __le16 listen_interval; + u8 rsv1[2]; +} __packed; + +struct sta_rec_ba { + __le16 tag; + __le16 len; + u8 tid; + u8 ba_type; + u8 amsdu; + u8 ba_en; + __le16 ssn; + __le16 winsize; +} __packed; + +struct sta_rec_he { + __le16 tag; + __le16 len; + + __le32 he_cap; + + u8 t_frame_dur; + u8 max_ampdu_exp; + u8 bw_set; + u8 device_class; + u8 dcm_tx_mode; + u8 dcm_tx_max_nss; + u8 dcm_rx_mode; + u8 dcm_rx_max_nss; + u8 dcm_max_ru; + u8 punc_pream_rx; + u8 pkt_ext; + u8 rsv1; + + __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; + + u8 rsv2[2]; +} __packed; + +struct sta_rec_amsdu { + __le16 tag; + __le16 len; + u8 max_amsdu_num; + u8 max_mpdu_size; + u8 amsdu_en; + u8 rsv; +} __packed; + +struct sta_rec_state { + __le16 tag; + __le16 len; + __le32 flags; + u8 state; + u8 vht_opmode; + u8 action; + u8 rsv[1]; +} __packed; + +#define HT_MCS_MASK_NUM 10 +struct sta_rec_ra_info { + __le16 tag; + __le16 len; + __le16 legacy; + u8 rx_mcs_bitmask[HT_MCS_MASK_NUM]; +} __packed; + +struct sta_rec_phy { + __le16 tag; + __le16 len; + __le16 basic_rate; + u8 phy_type; + u8 ampdu; + u8 rts_policy; + u8 rcpi; + u8 rsv[2]; +} __packed; + +/* wtbl_rec */ + +struct wtbl_req_hdr { + u8 wlan_idx_lo; + u8 operation; + __le16 tlv_num; + u8 wlan_idx_hi; + u8 rsv[3]; +} __packed; + +struct wtbl_generic { + __le16 tag; + __le16 len; + u8 peer_addr[ETH_ALEN]; + u8 muar_idx; + u8 skip_tx; + u8 cf_ack; + u8 qos; + u8 mesh; + u8 adm; + __le16 partial_aid; + u8 baf_en; + u8 aad_om; +} __packed; + +struct wtbl_rx { + __le16 tag; + __le16 len; + u8 rcid; + u8 rca1; + u8 rca2; + u8 rv; + u8 rsv[4]; +} __packed; + +struct wtbl_ht { + __le16 tag; + __le16 len; + u8 ht; + u8 ldpc; + u8 af; + u8 mm; + u8 rsv[4]; +} __packed; + +struct wtbl_vht { + __le16 tag; + __le16 len; + u8 ldpc; + u8 dyn_bw; + u8 vht; + u8 txop_ps; + u8 rsv[4]; +} __packed; + +struct wtbl_tx_ps { + __le16 tag; + __le16 len; + u8 txps; + u8 rsv[3]; +} __packed; + +struct wtbl_hdr_trans { + __le16 tag; + __le16 len; + u8 to_ds; + u8 from_ds; + u8 disable_rx_trans; + u8 rsv; +} __packed; + +struct wtbl_ba { + __le16 tag; + __le16 len; + /* common */ + u8 tid; + u8 ba_type; + u8 rsv0[2]; + /* originator only */ + __le16 sn; + u8 ba_en; + u8 ba_winsize_idx; + __le16 ba_winsize; + /* recipient only */ + u8 peer_addr[ETH_ALEN]; + u8 rst_ba_tid; + u8 rst_ba_sel; + u8 rst_ba_sb; + u8 band_idx; + u8 rsv1[4]; +} __packed; + +struct wtbl_smps { + __le16 tag; + __le16 len; + u8 smps; + u8 rsv[3]; +} __packed; + +/* mt7615 only */ + +struct wtbl_bf { + __le16 tag; + __le16 len; + u8 ibf; + u8 ebf; + u8 ibf_vht; + u8 ebf_vht; + u8 gid; + u8 pfmu_idx; + u8 rsv[2]; +} __packed; + +struct wtbl_pn { + __le16 tag; + __le16 len; + u8 pn[6]; + u8 rsv[2]; +} __packed; + +struct wtbl_spe { + __le16 tag; + __le16 len; + u8 spe_idx; + u8 rsv[3]; +} __packed; + +struct wtbl_raw { + __le16 tag; + __le16 len; + u8 wtbl_idx; + u8 dw; + u8 rsv[2]; + __le32 msk; + __le32 val; +} __packed; + +#define MT76_CONNAC_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_generic) + \ + sizeof(struct wtbl_rx) + \ + sizeof(struct wtbl_ht) + \ + sizeof(struct wtbl_vht) + \ + sizeof(struct wtbl_tx_ps) + \ + sizeof(struct wtbl_hdr_trans) +\ + sizeof(struct wtbl_ba) + \ + sizeof(struct wtbl_bf) + \ + sizeof(struct wtbl_smps) + \ + sizeof(struct wtbl_pn) + \ + sizeof(struct wtbl_spe)) + +#define MT76_CONNAC_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct sta_rec_basic) + \ + sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_he) + \ + sizeof(struct sta_rec_ba) + \ + sizeof(struct sta_rec_vht) + \ + sizeof(struct sta_rec_uapsd) + \ + sizeof(struct sta_rec_amsdu) + \ + sizeof(struct tlv) + \ + MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) + +#define MT76_CONNAC_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_ba)) + +enum { + STA_REC_BASIC, + STA_REC_RA, + STA_REC_RA_CMM_INFO, + STA_REC_RA_UPDATE, + STA_REC_BF, + STA_REC_AMSDU, + STA_REC_BA, + STA_REC_STATE, + STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */ + STA_REC_HT, + STA_REC_VHT, + STA_REC_APPS, + STA_REC_KEY, + STA_REC_WTBL, + STA_REC_HE, + STA_REC_HW_AMSDU, + STA_REC_WTBL_AADOM, + STA_REC_KEY_V2, + STA_REC_MURU, + STA_REC_MUEDCA, + STA_REC_BFEE, + STA_REC_PHY = 0x15, + STA_REC_MAX_NUM +}; + +enum { + WTBL_GENERIC, + WTBL_RX, + WTBL_HT, + WTBL_VHT, + WTBL_PEER_PS, /* not used */ + WTBL_TX_PS, + WTBL_HDR_TRANS, + WTBL_SEC_KEY, + WTBL_BA, + WTBL_RDG, /* obsoleted */ + WTBL_PROTECT, /* not used */ + WTBL_CLEAR, /* not used */ + WTBL_BF, + WTBL_SMPS, + WTBL_RAW_DATA, /* debug only */ + WTBL_PN, + WTBL_SPE, + WTBL_MAX_NUM +}; + +#define STA_TYPE_STA BIT(0) +#define STA_TYPE_AP BIT(1) +#define STA_TYPE_ADHOC BIT(2) +#define STA_TYPE_WDS BIT(4) +#define STA_TYPE_BC BIT(5) + +#define NETWORK_INFRA BIT(16) +#define NETWORK_P2P BIT(17) +#define NETWORK_IBSS BIT(18) +#define NETWORK_WDS BIT(21) + +#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) +#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) +#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) +#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) +#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) +#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) +#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) + +#define CONN_STATE_DISCONNECT 0 +#define CONN_STATE_CONNECT 1 +#define CONN_STATE_PORT_SECURE 2 + +/* HE MAC */ +#define STA_REC_HE_CAP_HTC BIT(0) +#define STA_REC_HE_CAP_BQR BIT(1) +#define STA_REC_HE_CAP_BSR BIT(2) +#define STA_REC_HE_CAP_OM BIT(3) +#define STA_REC_HE_CAP_AMSDU_IN_AMPDU BIT(4) +/* HE PHY */ +#define STA_REC_HE_CAP_DUAL_BAND BIT(5) +#define STA_REC_HE_CAP_LDPC BIT(6) +#define STA_REC_HE_CAP_TRIG_CQI_FK BIT(7) +#define STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE BIT(8) +/* STBC */ +#define STA_REC_HE_CAP_LE_EQ_80M_TX_STBC BIT(9) +#define STA_REC_HE_CAP_LE_EQ_80M_RX_STBC BIT(10) +#define STA_REC_HE_CAP_GT_80M_TX_STBC BIT(11) +#define STA_REC_HE_CAP_GT_80M_RX_STBC BIT(12) +/* GI */ +#define STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI BIT(13) +#define STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI BIT(14) +#define STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI BIT(15) +#define STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI BIT(16) +#define STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI BIT(17) +/* 242 TONE */ +#define STA_REC_HE_CAP_BW20_RU242_SUPPORT BIT(18) +#define STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242 BIT(19) +#define STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242 BIT(20) + +#define PHY_MODE_A BIT(0) +#define PHY_MODE_B BIT(1) +#define PHY_MODE_G BIT(2) +#define PHY_MODE_GN BIT(3) +#define PHY_MODE_AN BIT(4) +#define PHY_MODE_AC BIT(5) +#define PHY_MODE_AX_24G BIT(6) +#define PHY_MODE_AX_5G BIT(7) +#define PHY_MODE_AX_6G BIT(8) + +#define MODE_CCK BIT(0) +#define MODE_OFDM BIT(1) +#define MODE_HT BIT(2) +#define MODE_VHT BIT(3) +#define MODE_HE BIT(4) + +enum { + PHY_TYPE_HR_DSSS_INDEX = 0, + PHY_TYPE_ERP_INDEX, + PHY_TYPE_ERP_P2P_INDEX, + PHY_TYPE_OFDM_INDEX, + PHY_TYPE_HT_INDEX, + PHY_TYPE_VHT_INDEX, + PHY_TYPE_HE_INDEX, + PHY_TYPE_INDEX_NUM +}; + +#define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) +#define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) +#define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) +#define PHY_TYPE_BIT_HT BIT(PHY_TYPE_HT_INDEX) +#define PHY_TYPE_BIT_VHT BIT(PHY_TYPE_VHT_INDEX) +#define PHY_TYPE_BIT_HE BIT(PHY_TYPE_HE_INDEX) + +#define MT_WTBL_RATE_TX_MODE GENMASK(9, 6) +#define MT_WTBL_RATE_MCS GENMASK(5, 0) +#define MT_WTBL_RATE_NSS GENMASK(12, 10) +#define MT_WTBL_RATE_HE_GI GENMASK(7, 4) +#define MT_WTBL_RATE_GI GENMASK(3, 0) + +#define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) +#define MT_WTBL_W5_SHORT_GI_20 BIT(8) +#define MT_WTBL_W5_SHORT_GI_40 BIT(9) +#define MT_WTBL_W5_SHORT_GI_80 BIT(10) +#define MT_WTBL_W5_SHORT_GI_160 BIT(11) +#define MT_WTBL_W5_BW_CAP GENMASK(13, 12) +#define MT_WTBL_W5_MPDU_FAIL_COUNT GENMASK(25, 23) +#define MT_WTBL_W5_MPDU_OK_COUNT GENMASK(28, 26) +#define MT_WTBL_W5_RATE_IDX GENMASK(31, 29) + +enum { + WTBL_RESET_AND_SET = 1, + WTBL_SET, + WTBL_QUERY, + WTBL_RESET_ALL +}; + +enum { + MT_BA_TYPE_INVALID, + MT_BA_TYPE_ORIGINATOR, + MT_BA_TYPE_RECIPIENT +}; + +enum { + RST_BA_MAC_TID_MATCH, + RST_BA_MAC_MATCH, + RST_BA_NO_MATCH +}; + +enum { + DEV_INFO_ACTIVE, + DEV_INFO_MAX_NUM +}; + +#define MCU_CMD_ACK BIT(0) +#define MCU_CMD_UNI BIT(1) +#define MCU_CMD_QUERY BIT(2) + +#define MCU_CMD_UNI_EXT_ACK (MCU_CMD_ACK | MCU_CMD_UNI | \ + MCU_CMD_QUERY) + +#define MCU_FW_PREFIX BIT(31) +#define MCU_UNI_PREFIX BIT(30) +#define MCU_CE_PREFIX BIT(29) +#define MCU_QUERY_PREFIX BIT(28) +#define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX | \ + MCU_CE_PREFIX | MCU_QUERY_PREFIX) + +#define MCU_QUERY_MASK BIT(16) + +enum { + MCU_EXT_CMD_EFUSE_ACCESS = 0x01, + MCU_EXT_CMD_RF_REG_ACCESS = 0x02, + MCU_EXT_CMD_PM_STATE_CTRL = 0x07, + MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, + MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11, + MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, + MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, + MCU_EXT_CMD_STA_REC_UPDATE = 0x25, + MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, + MCU_EXT_CMD_EDCA_UPDATE = 0x27, + MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, + MCU_EXT_CMD_GET_TEMP = 0x2c, + MCU_EXT_CMD_WTBL_UPDATE = 0x32, + MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, + MCU_EXT_CMD_ATE_CTRL = 0x3d, + MCU_EXT_CMD_PROTECT_CTRL = 0x3e, + MCU_EXT_CMD_DBDC_CTRL = 0x45, + MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, + MCU_EXT_CMD_RX_HDR_TRANS = 0x47, + MCU_EXT_CMD_MUAR_UPDATE = 0x48, + MCU_EXT_CMD_BCN_OFFLOAD = 0x49, + MCU_EXT_CMD_SET_RX_PATH = 0x4e, + MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, + MCU_EXT_CMD_RXDCOC_CAL = 0x59, + MCU_EXT_CMD_TXDPD_CAL = 0x60, + MCU_EXT_CMD_SET_RDD_TH = 0x7c, + MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d, +}; + +enum { + MCU_UNI_CMD_DEV_INFO_UPDATE = MCU_UNI_PREFIX | 0x01, + MCU_UNI_CMD_BSS_INFO_UPDATE = MCU_UNI_PREFIX | 0x02, + MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, + MCU_UNI_CMD_SUSPEND = MCU_UNI_PREFIX | 0x05, + MCU_UNI_CMD_OFFLOAD = MCU_UNI_PREFIX | 0x06, + MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07, +}; + +enum { + MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01, + MCU_CMD_FW_START_REQ = MCU_FW_PREFIX | 0x02, + MCU_CMD_INIT_ACCESS_REG = 0x3, + MCU_CMD_NIC_POWER_CTRL = MCU_FW_PREFIX | 0x4, + MCU_CMD_PATCH_START_REQ = MCU_FW_PREFIX | 0x05, + MCU_CMD_PATCH_FINISH_REQ = MCU_FW_PREFIX | 0x07, + MCU_CMD_PATCH_SEM_CONTROL = MCU_FW_PREFIX | 0x10, + MCU_CMD_EXT_CID = 0xed, + MCU_CMD_FW_SCATTER = MCU_FW_PREFIX | 0xee, + MCU_CMD_RESTART_DL_REQ = MCU_FW_PREFIX | 0xef, +}; + +/* offload mcu commands */ +enum { + MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, + MCU_CMD_SET_PS_PROFILE = MCU_CE_PREFIX | 0x05, + MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, + MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16, + MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17, + MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, + MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1d, + MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33, + MCU_CMD_SET_RATE_TX_POWER = MCU_CE_PREFIX | 0x5d, + MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, + MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, + MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0, + MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0, + MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca, + MCU_CMD_FWLOG_2_HOST = MCU_CE_PREFIX | 0xc5, + MCU_CMD_GET_WTBL = MCU_CE_PREFIX | 0xcd, +}; + +enum { + PATCH_SEM_RELEASE, + PATCH_SEM_GET +}; + +enum { + UNI_BSS_INFO_BASIC = 0, + UNI_BSS_INFO_RLM = 2, + UNI_BSS_INFO_HE_BASIC = 5, + UNI_BSS_INFO_BCN_CONTENT = 7, + UNI_BSS_INFO_QBSS = 15, + UNI_BSS_INFO_UAPSD = 19, + UNI_BSS_INFO_PS = 21, + UNI_BSS_INFO_BCNFT = 22, +}; + +enum { + UNI_OFFLOAD_OFFLOAD_ARP, + UNI_OFFLOAD_OFFLOAD_ND, + UNI_OFFLOAD_OFFLOAD_GTK_REKEY, + UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, +}; + +enum { + UNI_SUSPEND_MODE_SETTING, + UNI_SUSPEND_WOW_CTRL, + UNI_SUSPEND_WOW_GPIO_PARAM, + UNI_SUSPEND_WOW_WAKEUP_PORT, + UNI_SUSPEND_WOW_PATTERN, +}; + +enum { + WOW_USB = 1, + WOW_PCIE = 2, + WOW_GPIO = 3, +}; + +struct mt76_connac_bss_basic_tlv { + __le16 tag; + __le16 len; + u8 active; + u8 omac_idx; + u8 hw_bss_idx; + u8 band_idx; + __le32 conn_type; + u8 conn_state; + u8 wmm_idx; + u8 bssid[ETH_ALEN]; + __le16 bmc_tx_wlan_idx; + __le16 bcn_interval; + u8 dtim_period; + u8 phymode; /* bit(0): A + * bit(1): B + * bit(2): G + * bit(3): GN + * bit(4): AN + * bit(5): AC + */ + __le16 sta_idx; + u8 nonht_basic_phy; + u8 pad[3]; +} __packed; + +struct mt76_connac_bss_qos_tlv { + __le16 tag; + __le16 len; + u8 qos; + u8 pad[3]; +} __packed; + +struct mt76_connac_beacon_loss_event { + u8 bss_idx; + u8 reason; + u8 pad[2]; +} __packed; + +struct mt76_connac_mcu_bss_event { + u8 bss_idx; + u8 is_absent; + u8 free_quota; + u8 pad; +} __packed; + +struct mt76_connac_mcu_scan_ssid { + __le32 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +} __packed; + +struct mt76_connac_mcu_scan_channel { + u8 band; /* 1: 2.4GHz + * 2: 5.0GHz + * Others: Reserved + */ + u8 channel_num; +} __packed; + +struct mt76_connac_mcu_scan_match { + __le32 rssi_th; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + u8 rsv[3]; +} __packed; + +struct mt76_connac_hw_scan_req { + u8 seq_num; + u8 bss_idx; + u8 scan_type; /* 0: PASSIVE SCAN + * 1: ACTIVE SCAN + */ + u8 ssid_type; /* BIT(0) wildcard SSID + * BIT(1) P2P wildcard SSID + * BIT(2) specified SSID + wildcard SSID + * BIT(2) + ssid_type_ext BIT(0) specified SSID only + */ + u8 ssids_num; + u8 probe_req_num; /* Number of probe request for each SSID */ + u8 scan_func; /* BIT(0) Enable random MAC scan + * BIT(1) Disable DBDC scan type 1~3. + * BIT(2) Use DBDC scan type 3 (dedicated one RF to scan). + */ + u8 version; /* 0: Not support fields after ies. + * 1: Support fields after ies. + */ + struct mt76_connac_mcu_scan_ssid ssids[4]; + __le16 probe_delay_time; + __le16 channel_dwell_time; /* channel Dwell interval */ + __le16 timeout_value; + u8 channel_type; /* 0: Full channels + * 1: Only 2.4GHz channels + * 2: Only 5GHz channels + * 3: P2P social channel only (channel #1, #6 and #11) + * 4: Specified channels + * Others: Reserved + */ + u8 channels_num; /* valid when channel_type is 4 */ + /* valid when channels_num is set */ + struct mt76_connac_mcu_scan_channel channels[32]; + __le16 ies_len; + u8 ies[MT76_CONNAC_SCAN_IE_LEN]; + /* following fields are valid if version > 0 */ + u8 ext_channels_num; + u8 ext_ssids_num; + __le16 channel_min_dwell_time; + struct mt76_connac_mcu_scan_channel ext_channels[32]; + struct mt76_connac_mcu_scan_ssid ext_ssids[6]; + u8 bssid[ETH_ALEN]; + u8 random_mac[ETH_ALEN]; /* valid when BIT(1) in scan_func is set. */ + u8 pad[63]; + u8 ssid_type_ext; +} __packed; + +#define MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM 64 + +struct mt76_connac_hw_scan_done { + u8 seq_num; + u8 sparse_channel_num; + struct mt76_connac_mcu_scan_channel sparse_channel; + u8 complete_channel_num; + u8 current_state; + u8 version; + u8 pad; + __le32 beacon_scan_num; + u8 pno_enabled; + u8 pad2[3]; + u8 sparse_channel_valid_num; + u8 pad3[3]; + u8 channel_num[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + /* idle format for channel_idle_time + * 0: first bytes: idle time(ms) 2nd byte: dwell time(ms) + * 1: first bytes: idle time(8ms) 2nd byte: dwell time(8ms) + * 2: dwell time (16us) + */ + __le16 channel_idle_time[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + /* beacon and probe response count */ + u8 beacon_probe_num[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + u8 mdrdy_count[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + __le32 beacon_2g_num; + __le32 beacon_5g_num; +} __packed; + +struct mt76_connac_sched_scan_req { + u8 version; + u8 seq_num; + u8 stop_on_match; + u8 ssids_num; + u8 match_num; + u8 pad; + __le16 ie_len; + struct mt76_connac_mcu_scan_ssid ssids[MT76_CONNAC_MAX_SCHED_SCAN_SSID]; + struct mt76_connac_mcu_scan_match match[MT76_CONNAC_MAX_SCAN_MATCH]; + u8 channel_type; + u8 channels_num; + u8 intervals_num; + u8 scan_func; /* BIT(0) eable random mac address */ + struct mt76_connac_mcu_scan_channel channels[64]; + __le16 intervals[MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL]; + u8 random_mac[ETH_ALEN]; /* valid when BIT(0) in scan_func is set */ + u8 pad2[58]; +} __packed; + +struct mt76_connac_sched_scan_done { + u8 seq_num; + u8 status; /* 0: ssid found */ + __le16 pad; +} __packed; + +struct bss_info_uni_he { + __le16 tag; + __le16 len; + __le16 he_rts_thres; + u8 he_pe_duration; + u8 su_disable; + __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; + u8 rsv[2]; +} __packed; + +struct mt76_connac_gtk_rekey_tlv { + __le16 tag; + __le16 len; + u8 kek[NL80211_KEK_LEN]; + u8 kck[NL80211_KCK_LEN]; + u8 replay_ctr[NL80211_REPLAY_CTR_LEN]; + u8 rekey_mode; /* 0: rekey offload enable + * 1: rekey offload disable + * 2: rekey update + */ + u8 keyid; + u8 pad[2]; + __le32 proto; /* WPA-RSN-WAPI-OPSN */ + __le32 pairwise_cipher; + __le32 group_cipher; + __le32 key_mgmt; /* NONE-PSK-IEEE802.1X */ + __le32 mgmt_group_cipher; + u8 option; /* 1: rekey data update without enabling offload */ + u8 reserverd[3]; +} __packed; + +#define MT76_CONNAC_WOW_MASK_MAX_LEN 16 +#define MT76_CONNAC_WOW_PATTEN_MAX_LEN 128 + +struct mt76_connac_wow_pattern_tlv { + __le16 tag; + __le16 len; + u8 index; /* pattern index */ + u8 enable; /* 0: disable + * 1: enable + */ + u8 data_len; /* pattern length */ + u8 pad; + u8 mask[MT76_CONNAC_WOW_MASK_MAX_LEN]; + u8 pattern[MT76_CONNAC_WOW_PATTEN_MAX_LEN]; + u8 rsv[4]; +} __packed; + +struct mt76_connac_wow_ctrl_tlv { + __le16 tag; + __le16 len; + u8 cmd; /* 0x1: PM_WOWLAN_REQ_START + * 0x2: PM_WOWLAN_REQ_STOP + * 0x3: PM_WOWLAN_PARAM_CLEAR + */ + u8 trigger; /* 0: NONE + * BIT(0): NL80211_WOWLAN_TRIG_MAGIC_PKT + * BIT(1): NL80211_WOWLAN_TRIG_ANY + * BIT(2): NL80211_WOWLAN_TRIG_DISCONNECT + * BIT(3): NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE + * BIT(4): BEACON_LOST + * BIT(5): NL80211_WOWLAN_TRIG_NET_DETECT + */ + u8 wakeup_hif; /* 0x0: HIF_SDIO + * 0x1: HIF_USB + * 0x2: HIF_PCIE + * 0x3: HIF_GPIO + */ + u8 pad; + u8 rsv[4]; +} __packed; + +struct mt76_connac_wow_gpio_param_tlv { + __le16 tag; + __le16 len; + u8 gpio_pin; + u8 trigger_lvl; + u8 pad[2]; + __le32 gpio_interval; + u8 rsv[4]; +} __packed; + +struct mt76_connac_arpns_tlv { + __le16 tag; + __le16 len; + u8 mode; + u8 ips_num; + u8 option; + u8 pad[1]; +} __packed; + +struct mt76_connac_suspend_tlv { + __le16 tag; + __le16 len; + u8 enable; /* 0: suspend mode disabled + * 1: suspend mode enabled + */ + u8 mdtim; /* LP parameter */ + u8 wow_suspend; /* 0: update by origin policy + * 1: update by wow dtim + */ + u8 pad[5]; +} __packed; + +#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) +#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) + +static inline void +mt76_connac_mcu_get_wlan_idx(struct mt76_dev *dev, struct mt76_wcid *wcid, + u8 *wlan_idx_lo, u8 *wlan_idx_hi) +{ + *wlan_idx_hi = 0; + + if (is_mt7921(dev)) { + *wlan_idx_lo = wcid ? to_wcid_lo(wcid->idx) : 0; + *wlan_idx_hi = wcid ? to_wcid_hi(wcid->idx) : 0; + } else { + *wlan_idx_lo = wcid ? wcid->idx : 0; + } +} + +struct sk_buff * +mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif, + struct mt76_wcid *wcid); +struct wtbl_req_hdr * +mt76_connac_mcu_alloc_wtbl_req(struct mt76_dev *dev, struct mt76_wcid *wcid, + int cmd, void *sta_wtbl, struct sk_buff **skb); +struct tlv *mt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag, + int len, void *sta_ntlv, + void *sta_wtbl); +static inline struct tlv * +mt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len) +{ + return mt76_connac_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); +} + +int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy); +int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif); +void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable); +void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *sta_wtbl, + void *wtbl_tlv); +void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, + struct ieee80211_sta *sta, + struct ieee80211_vif *vif); +void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta, void *sta_wtbl, + void *wtbl_tlv); +void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx, void *sta_wtbl, + void *wtbl_tlv); +void mt76_connac_mcu_sta_ba_tlv(struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx); +int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, + bool enable); +int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, + struct ieee80211_ampdu_params *params, + bool enable, bool tx); +int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, + bool enable); +int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct mt76_wcid *wcid, + bool enable, int cmd); +void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif); +int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band); +int mt76_connac_mcu_set_mac_enable(struct mt76_dev *dev, int band, bool enable, + bool hdr_trans); +int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, + u32 mode); +int mt76_connac_mcu_start_patch(struct mt76_dev *dev); +int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get); +int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option); + +int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_scan_request *scan_req); +int mt76_connac_mcu_cancel_hw_scan(struct mt76_phy *phy, + struct ieee80211_vif *vif); +int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *sreq); +int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy, + struct ieee80211_vif *vif, + bool enable); +int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *key); +int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend); +void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif); +int mt76_connac_mcu_chip_config(struct mt76_dev *dev); +void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, + struct mt76_connac_coredump *coredump); +#endif /* __MT76_CONNAC_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index b87d8e136cb9..02d0aa0b815e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -16,7 +16,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw) mt76x02_mac_start(dev); mt76x0_phy_calibrate(dev, true); - ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mt76.mac_work, + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); @@ -28,7 +28,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw) static void mt76x0e_stop_hw(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); clear_bit(MT76_RESTART, &dev->mphy.state); if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index b12cb17cb43d..a593a7796d23 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -82,7 +82,7 @@ static void mt76x0u_stop(struct ieee80211_hw *hw) clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); cancel_delayed_work_sync(&dev->cal_work); - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); mt76u_stop_tx(&dev->mt76); mt76x02u_exit_beacon_config(dev); @@ -108,7 +108,7 @@ static int mt76x0u_start(struct ieee80211_hw *hw) return ret; mt76x0_phy_calibrate(dev, true); - ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mt76.mac_work, + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index d626817a2103..4d58c2c1c0ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -82,8 +82,6 @@ struct mt76x02_dev { struct mutex phy_mutex; - u16 chainmask; - u8 txdone_seq; DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); spinlock_t txstatus_fifo_lock; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 16b40a73fd1f..771bad60e1bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -345,7 +345,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, u16 txwi_flags = 0; u8 nss; s8 txpwr_adj, max_txpwr_adj; - u8 ccmp_pn[8], nstreams = dev->chainmask & 0xf; + u8 ccmp_pn[8], nstreams = dev->mphy.chainmask & 0xf; memset(txwi, 0, sizeof(*txwi)); @@ -685,7 +685,7 @@ mt76x02_mac_process_rate(struct mt76x02_dev *dev, status->rate_idx = idx; break; case MT_PHY_TYPE_VHT: { - u8 n_rxstream = dev->chainmask & 0xf; + u8 n_rxstream = dev->mphy.chainmask & 0xf; status->encoding = RX_ENC_VHT; status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); @@ -777,7 +777,7 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, u16 rate = le16_to_cpu(rxwi->rate); u16 tid_sn = le16_to_cpu(rxwi->tid_sn); bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); - int pad_len = 0, nstreams = dev->chainmask & 0xf; + int pad_len = 0, nstreams = dev->mphy.chainmask & 0xf; s8 signal; u8 pn_len; u8 wcid; @@ -1162,7 +1162,7 @@ static void mt76x02_edcca_check(struct mt76x02_dev *dev) void mt76x02_mac_work(struct work_struct *work) { struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, - mt76.mac_work.work); + mphy.mac_work.work); int i, idx; mutex_lock(&dev->mt76.mutex); @@ -1185,7 +1185,7 @@ void mt76x02_mac_work(struct work_struct *work) mt76_tx_status_check(&dev->mt76, NULL, false); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index e7e87311d355..e7a46ac97f51 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -416,7 +416,7 @@ static void mt76x02_reset_state(struct mt76x02_dev *dev) memset(msta, 0, sizeof(*msta)); } - dev->mphy.vif_mask = 0; + dev->mt76.vif_mask = 0; dev->mt76.beacon_mask = 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index aaadc15ea83c..2e53b0c1afdd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -16,7 +16,7 @@ void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev) val = mt76_rr(dev, MT_BBP(AGC, 0)); val &= ~BIT(4); - switch (dev->chainmask & 0xf) { + switch (dev->mphy.chainmask & 0xf) { case 2: val |= BIT(3); break; @@ -35,7 +35,7 @@ void mt76x02_phy_set_txdac(struct mt76x02_dev *dev) { int txpath; - txpath = (dev->chainmask >> 8) & 0xf; + txpath = (dev->mphy.chainmask >> 8) & 0xf; switch (txpath) { case 2: mt76_set(dev, MT_BBP(TXBE, 5), 0x3); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 7ac20d3c16d7..ab671e21f882 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -149,7 +149,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev) struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; - INIT_DELAYED_WORK(&dev->mt76.mac_work, mt76x02_mac_work); + INIT_DELAYED_WORK(&dev->mphy.mac_work, mt76x02_mac_work); hw->queues = 4; hw->max_rates = 1; @@ -197,10 +197,10 @@ void mt76x02_init_device(struct mt76x02_dev *dev) IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; - dev->chainmask = 0x202; + dev->mphy.chainmask = 0x202; dev->mphy.antenna_mask = 3; } else { - dev->chainmask = 0x101; + dev->mphy.chainmask = 0x101; dev->mphy.antenna_mask = 1; } } @@ -304,7 +304,7 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) unsigned int idx = 0; /* Allow to change address in HW if we create first interface. */ - if (!dev->mphy.vif_mask && + if (!dev->mt76.vif_mask && (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) || memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1))) mt76x02_mac_setaddr(dev, vif->addr); @@ -329,11 +329,11 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx += 8; /* vif is already set or idx is 8 for AP/Mesh/... */ - if (dev->mphy.vif_mask & BIT(idx) || + if (dev->mt76.vif_mask & BIT(idx) || (vif->type != NL80211_IFTYPE_STATION && idx > 7)) return -EBUSY; - dev->mphy.vif_mask |= BIT(idx); + dev->mt76.vif_mask |= BIT(idx); mt76x02_vif_init(dev, vif, idx); return 0; @@ -346,7 +346,7 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw, struct mt76x02_dev *dev = hw->priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; - dev->mphy.vif_mask &= ~BIT(mvif->idx); + dev->mt76.vif_mask &= ~BIT(mvif->idx); } EXPORT_SYMBOL_GPL(mt76x02_remove_interface); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c index 3c2738903d7d..ac83ce5f3e8b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c @@ -29,7 +29,7 @@ int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, .idx = channel, .scan = scan, .bw = bw, - .chainmask = cpu_to_le16(dev->chainmask), + .chainmask = cpu_to_le16(dev->mphy.chainmask), }; /* first set the channel without the extension channel info */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 620484390418..c6fa8cf92529 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -271,7 +271,7 @@ static int mt76x2_init_hardware(struct mt76x02_dev *dev) void mt76x2_stop_hardware(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); cancel_delayed_work_sync(&dev->wdt_work); clear_bit(MT76_RESTART, &dev->mphy.state); mt76x02_mcu_set_radio_state(dev, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 98f4cf398320..933125b07ea3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -14,7 +14,7 @@ mt76x2_start(struct ieee80211_hw *hw) mt76x02_mac_start(dev); mt76x2_phy_start(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, MT_WATCHDOG_TIME); @@ -116,7 +116,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, mutex_lock(&dev->mt76.mutex); - dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101; + dev->mphy.chainmask = (tx_ant == 3) ? 0x202 : 0x101; dev->mphy.antenna_mask = tx_ant; mt76_set_stream_caps(&dev->mphy, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index ffc2deba29ac..85dcdc22fbeb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -236,7 +236,7 @@ fail: void mt76x2u_stop_hw(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); mt76x2u_mac_stop(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index bab4e6e1904e..b66836928d9d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -15,7 +15,7 @@ static int mt76x2u_start(struct ieee80211_hw *hw) if (ret) return ret; - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); set_bit(MT76_STATE_RUNNING, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 7d810fbf2862..77dcd71e49a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -6,6 +6,32 @@ /** global debugfs **/ +static int +mt7915_implicit_txbf_set(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + + if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) + return -EBUSY; + + dev->ibf = !!val; + + return mt7915_mcu_set_txbf_type(dev); +} + +static int +mt7915_implicit_txbf_get(void *data, u64 *val) +{ + struct mt7915_dev *dev = data; + + *val = dev->ibf; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get, + mt7915_implicit_txbf_set, "%lld\n"); + /* test knob of system layer 1/2 error recovery */ static int mt7915_ser_trigger_set(void *data, u64 val) { @@ -355,6 +381,8 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) mt7915_queues_acq); debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats); debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); + debugfs_create_file("implicit_txbf", 0600, dir, dev, + &fops_implicit_txbf); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); /* test knobs */ debugfs_create_file("radar_trigger", 0200, dir, dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 8c1f9c77b14f..bf51304a770b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -73,34 +73,41 @@ static int mt7915_poll_tx(struct napi_struct *napi, int budget) return 0; } -void mt7915_dma_prefetch(struct mt7915_dev *dev) +static void __mt7915_dma_prefetch(struct mt7915_dev *dev, u32 ofs) { #define PREFETCH(base, depth) ((base) << 16 | (depth)) - mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); - mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x40, 0x4)); - mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x80, 0x0)); - - mt76_wr(dev, MT_WFDMA1_TX_RING0_EXT_CTRL, PREFETCH(0x80, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING1_EXT_CTRL, PREFETCH(0xc0, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING2_EXT_CTRL, PREFETCH(0x100, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING3_EXT_CTRL, PREFETCH(0x140, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING4_EXT_CTRL, PREFETCH(0x180, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING5_EXT_CTRL, PREFETCH(0x1c0, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING6_EXT_CTRL, PREFETCH(0x200, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING7_EXT_CTRL, PREFETCH(0x240, 0x4)); - - mt76_wr(dev, MT_WFDMA1_TX_RING16_EXT_CTRL, PREFETCH(0x280, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING17_EXT_CTRL, PREFETCH(0x2c0, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING18_EXT_CTRL, PREFETCH(0x300, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING19_EXT_CTRL, PREFETCH(0x340, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING20_EXT_CTRL, PREFETCH(0x380, 0x4)); - mt76_wr(dev, MT_WFDMA1_TX_RING21_EXT_CTRL, PREFETCH(0x3c0, 0x0)); - - mt76_wr(dev, MT_WFDMA1_RX_RING0_EXT_CTRL, PREFETCH(0x3c0, 0x4)); - mt76_wr(dev, MT_WFDMA1_RX_RING1_EXT_CTRL, PREFETCH(0x400, 0x4)); - mt76_wr(dev, MT_WFDMA1_RX_RING2_EXT_CTRL, PREFETCH(0x440, 0x4)); - mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL, PREFETCH(0x480, 0x0)); + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL + ofs, PREFETCH(0x0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL + ofs, PREFETCH(0x40, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL + ofs, PREFETCH(0x80, 0x0)); + + mt76_wr(dev, MT_WFDMA1_TX_RING0_EXT_CTRL + ofs, PREFETCH(0x80, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING1_EXT_CTRL + ofs, PREFETCH(0xc0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING2_EXT_CTRL + ofs, PREFETCH(0x100, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING3_EXT_CTRL + ofs, PREFETCH(0x140, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING4_EXT_CTRL + ofs, PREFETCH(0x180, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING5_EXT_CTRL + ofs, PREFETCH(0x1c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING6_EXT_CTRL + ofs, PREFETCH(0x200, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING7_EXT_CTRL + ofs, PREFETCH(0x240, 0x4)); + + mt76_wr(dev, MT_WFDMA1_TX_RING16_EXT_CTRL + ofs, PREFETCH(0x280, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING17_EXT_CTRL + ofs, PREFETCH(0x2c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING18_EXT_CTRL + ofs, PREFETCH(0x300, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING19_EXT_CTRL + ofs, PREFETCH(0x340, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING20_EXT_CTRL + ofs, PREFETCH(0x380, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING21_EXT_CTRL + ofs, PREFETCH(0x3c0, 0x0)); + + mt76_wr(dev, MT_WFDMA1_RX_RING0_EXT_CTRL + ofs, PREFETCH(0x3c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING1_EXT_CTRL + ofs, PREFETCH(0x400, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING2_EXT_CTRL + ofs, PREFETCH(0x440, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL + ofs, PREFETCH(0x480, 0x0)); +} + +void mt7915_dma_prefetch(struct mt7915_dev *dev) +{ + __mt7915_dma_prefetch(dev, 0); + if (dev->hif2) + __mt7915_dma_prefetch(dev, MT_WFDMA1_PCIE1_BASE - MT_WFDMA1_BASE); } static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) @@ -204,6 +211,7 @@ int mt7915_dma_init(struct mt7915_dev *dev) /* Increase buffer size to receive large VHT/HE MPDUs */ struct mt76_bus_ops *bus_ops; int rx_buf_size = MT_RX_BUF_SIZE * 2; + u32 hif1_ofs = 0; int ret; dev->bus_ops = dev->mt76.bus; @@ -219,14 +227,14 @@ int mt7915_dma_init(struct mt7915_dev *dev) mt76_dma_attach(&dev->mt76); + if (dev->hif2) + hif1_ofs = MT_WFDMA1_PCIE1_BASE - MT_WFDMA1_BASE; + /* configure global setting */ mt76_set(dev, MT_WFDMA1_GLO_CFG, MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); - /* configure perfetch settings */ - mt7915_dma_prefetch(dev); - /* reset dma idx */ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR, ~0); @@ -235,6 +243,21 @@ int mt7915_dma_init(struct mt7915_dev *dev) mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0); + if (dev->hif2) { + mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, + MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); + + mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR + hif1_ofs, ~0); + mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR + hif1_ofs, ~0); + + mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0 + hif1_ofs, 0); + mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0 + hif1_ofs, 0); + } + + /* configure perfetch settings */ + mt7915_dma_prefetch(dev); + /* init tx queue */ ret = mt7915_init_tx_queues(&dev->phy, MT7915_TXQ_BAND0, MT7915_TX_RING_SIZE); @@ -283,7 +306,17 @@ int mt7915_dma_init(struct mt7915_dev *dev) if (dev->dbdc_support) { ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT], MT7915_RXQ_BAND1, MT7915_RX_RING_SIZE, - rx_buf_size, MT_RX_DATA_RING_BASE); + rx_buf_size, + MT_RX_DATA_RING_BASE + hif1_ofs); + if (ret) + return ret; + + /* event from WA */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT_WA], + MT7915_RXQ_MCU_WA_EXT, + MT7915_RX_MCU_RING_SIZE, + rx_buf_size, + MT_RX_EVENT_RING_BASE + hif1_ofs); if (ret) return ret; } @@ -326,6 +359,17 @@ int mt7915_dma_init(struct mt7915_dev *dev) mt76_set(dev, MT_WFDMA1_GLO_CFG, MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + if (dev->hif2) { + mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, + (MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN)); + mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, + (MT_WFDMA1_GLO_CFG_TX_DMA_EN | + MT_WFDMA1_GLO_CFG_RX_DMA_EN)); + mt76_set(dev, MT_WFDMA_HOST_CONFIG, + MT_WFDMA_HOST_CONFIG_PDMA_BAND); + } + /* enable interrupts for TX/RX rings */ mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_MCU | MT_INT_MCU_CMD); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 7a2be3f61398..660398ac53c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -22,7 +22,10 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev) if (ret < 0) return ret; - memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE); + if (ret) + dev->flash_mode = true; + else + memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE); return 0; } @@ -50,12 +53,15 @@ void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) u32 val; val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF + ext_phy); - val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val); + val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); + if (val == MT_EE_BAND_SEL_DEFAULT && dev->dbdc_support) + val = ext_phy ? MT_EE_BAND_SEL_5GHZ : MT_EE_BAND_SEL_2GHZ; + switch (val) { - case MT_EE_5GHZ: + case MT_EE_BAND_SEL_5GHZ: phy->mt76->cap.has_5ghz = true; break; - case MT_EE_2GHZ: + case MT_EE_BAND_SEL_2GHZ: phy->mt76->cap.has_2ghz = true; break; default: @@ -67,26 +73,30 @@ void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev) { - u8 nss, tx_mask[2] = {}, *eeprom = dev->mt76.eeprom.data; + u8 nss, nss_band, *eeprom = dev->mt76.eeprom.data; mt7915_eeprom_parse_band_config(&dev->phy); /* read tx mask from eeprom */ - tx_mask[0] = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK, - eeprom[MT_EE_WIFI_CONF]); - if (dev->dbdc_support) - tx_mask[1] = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK, - eeprom[MT_EE_WIFI_CONF + 1]); - - nss = tx_mask[0] + tx_mask[1]; - if (!nss || nss > 4) { - tx_mask[0] = 4; + nss = FIELD_GET(MT_EE_WIFI_CONF0_TX_PATH, eeprom[MT_EE_WIFI_CONF]); + if (!nss || nss > 4) nss = 4; + + nss_band = nss; + + if (dev->dbdc_support) { + nss_band = FIELD_GET(MT_EE_WIFI_CONF3_TX_PATH_B0, + eeprom[MT_EE_WIFI_CONF + 3]); + if (!nss_band || nss_band > 2) + nss_band = 2; + + if (nss_band >= nss) + nss = 4; } dev->chainmask = BIT(nss) - 1; - dev->mphy.antenna_mask = BIT(tx_mask[0]) - 1; - dev->phy.chainmask = dev->mphy.antenna_mask; + dev->mphy.antenna_mask = BIT(nss_band) - 1; + dev->mphy.chainmask = dev->mphy.antenna_mask; } int mt7915_eeprom_init(struct mt7915_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 6712032b40df..3ee8c27bb61b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -25,17 +25,20 @@ enum mt7915_eeprom_field { __MT_EE_MAX = 0xe00 }; -#define MT_EE_WIFI_CONF_TX_MASK GENMASK(2, 0) -#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(7, 6) -#define MT_EE_WIFI_CONF_TSSI0_2G BIT(0) -#define MT_EE_WIFI_CONF_TSSI0_5G BIT(2) -#define MT_EE_WIFI_CONF_TSSI1_5G BIT(4) +#define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) +#define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(7, 6) +#define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(7, 6) +#define MT_EE_WIFI_CONF3_TX_PATH_B0 GENMASK(1, 0) +#define MT_EE_WIFI_CONF3_TX_PATH_B1 GENMASK(5, 4) +#define MT_EE_WIFI_CONF7_TSSI0_2G BIT(0) +#define MT_EE_WIFI_CONF7_TSSI0_5G BIT(2) +#define MT_EE_WIFI_CONF7_TSSI1_5G BIT(4) enum mt7915_eeprom_band { - MT_EE_DUAL_BAND, - MT_EE_5GHZ, - MT_EE_2GHZ, - MT_EE_DBDC, + MT_EE_BAND_SEL_DEFAULT, + MT_EE_BAND_SEL_5GHZ, + MT_EE_BAND_SEL_2GHZ, + MT_EE_BAND_SEL_DUAL, }; #define SKU_DELTA_VAL GENMASK(5, 0) @@ -116,9 +119,9 @@ mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) /* TODO: DBDC */ if (band == NL80211_BAND_5GHZ) - return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_5G; + return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_5G; else - return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G; + return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_2G; } extern const struct sku_group mt7915_sku_groups[]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 102a8f14c22d..ad4e5b95158b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -169,18 +169,19 @@ static int mt7915_txbf_init(struct mt7915_dev *dev) { int ret; - /* - * TODO: DBDC & check whether iBF phase calibration data has - * been stored in eeprom offset 0x651~0x7b8, then write down - * 0x1111 into 0x651 and 0x651 to trigger iBF. - */ + + if (dev->dbdc_support) { + ret = mt7915_mcu_set_txbf_module(dev); + if (ret) + return ret; + } /* trigger sounding packets */ ret = mt7915_mcu_set_txbf_sounding(dev); if (ret) return ret; - /* enable iBF & eBF */ + /* enable eBF */ return mt7915_mcu_set_txbf_type(dev); } @@ -235,12 +236,12 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev) phy = mphy->priv; phy->dev = dev; phy->mt76 = mphy; - phy->chainmask = dev->chainmask & ~dev->phy.chainmask; - mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1; + mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask; + mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1; mt7915_init_wiphy(mphy->hw); INIT_LIST_HEAD(&phy->stats_list); - INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work); + INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work); mt7915_eeprom_parse_band_config(phy); mt7915_set_stream_vht_txbf_caps(phy); @@ -329,7 +330,7 @@ static int mt7915_init_hardware(struct mt7915_dev *dev) void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy) { - int nss = hweight8(phy->chainmask); + int nss = hweight8(phy->mt76->chainmask); u32 *cap = &phy->mt76->sband_5g.sband.vht_cap.cap; *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | @@ -440,8 +441,7 @@ static int mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, struct ieee80211_sband_iftype_data *data) { - int i, idx = 0; - int nss = hweight8(phy->chainmask); + int i, idx = 0, nss = hweight8(phy->mt76->chainmask); u16 mcs_map = 0; for (i = 0; i < 8; i++) { @@ -622,7 +622,7 @@ int mt7915_register_device(struct mt7915_dev *dev) dev->mt76.phy.priv = &dev->phy; INIT_LIST_HEAD(&dev->phy.stats_list); INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work); - INIT_DELAYED_WORK(&dev->phy.mac_work, mt7915_mac_work); + INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work); INIT_LIST_HEAD(&dev->sta_rc_list); INIT_LIST_HEAD(&dev->sta_poll_list); spin_lock_init(&dev->sta_poll_lock); @@ -648,8 +648,8 @@ int mt7915_register_device(struct mt7915_dev *dev) dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; - dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; - dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; + dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; mt76_set_stream_caps(&dev->mphy, true); mt7915_set_stream_vht_txbf_caps(&dev->phy); @@ -672,28 +672,12 @@ int mt7915_register_device(struct mt7915_dev *dev) void mt7915_unregister_device(struct mt7915_dev *dev) { - struct mt76_txwi_cache *txwi; - int id; - mt7915_unregister_ext_phy(dev); mt76_unregister_device(&dev->mt76); mt7915_mcu_exit(dev); mt7915_dma_cleanup(dev); - spin_lock_bh(&dev->token_lock); - idr_for_each_entry(&dev->token, txwi, id) { - mt7915_txp_skb_unmap(&dev->mt76, txwi); - if (txwi->skb) { - struct ieee80211_hw *hw; - - hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); - ieee80211_free_txskb(hw, txwi->skb); - } - mt76_put_txwi(&dev->mt76, txwi); - dev->token_count--; - } - spin_unlock_bh(&dev->token_lock); - idr_destroy(&dev->token); + mt7915_tx_token_put(dev); mt76_free_device(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index f504eeb221f9..eb889f8d6fea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -565,13 +565,20 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) #ifdef CONFIG_NL80211_TESTMODE void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) { + struct mt7915_phy *phy = &dev->phy; __le32 *rxd = (__le32 *)skb->data; + __le32 *rxv_hdr = rxd + 2; __le32 *rxv = rxd + 4; u32 rcpi, ib_rssi, wb_rssi, v20, v21; + bool ext_phy; s32 foe; u8 snr; int i; + ext_phy = FIELD_GET(MT_RXV_HDR_BAND_IDX, le32_to_cpu(rxv_hdr[1])); + if (ext_phy) + phy = mt7915_ext_phy(dev); + rcpi = le32_to_cpu(rxv[6]); ib_rssi = le32_to_cpu(rxv[7]); wb_rssi = le32_to_cpu(rxv[8]) >> 5; @@ -580,9 +587,9 @@ void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) if (i == 3) wb_rssi = le32_to_cpu(rxv[9]); - dev->test.last_rcpi[i] = rcpi & 0xff; - dev->test.last_ib_rssi[i] = ib_rssi & 0xff; - dev->test.last_wb_rssi[i] = wb_rssi & 0xff; + phy->test.last_rcpi[i] = rcpi & 0xff; + phy->test.last_ib_rssi[i] = ib_rssi & 0xff; + phy->test.last_wb_rssi[i] = wb_rssi & 0xff; } v20 = le32_to_cpu(rxv[20]); @@ -593,26 +600,26 @@ void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) snr = FIELD_GET(MT_CRXV_SNR, v20) - 16; - dev->test.last_freq_offset = foe; - dev->test.last_snr = snr; + phy->test.last_freq_offset = foe; + phy->test.last_snr = snr; dev_kfree_skb(skb); } #endif static void -mt7915_mac_write_txwi_tm(struct mt7915_dev *dev, struct mt76_phy *mphy, - __le32 *txwi, struct sk_buff *skb) +mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, + struct sk_buff *skb) { #ifdef CONFIG_NL80211_TESTMODE - struct mt76_testmode_data *td = &dev->mt76.test; + struct mt76_testmode_data *td = &phy->mt76->test; u8 rate_idx = td->tx_rate_idx; u8 nss = td->tx_rate_nss; u8 bw, mode; u16 rateval = 0; u32 val; - if (skb != dev->mt76.test.tx_skb) + if (skb != phy->mt76->test.tx_skb) return; switch (td->tx_rate_mode) { @@ -644,7 +651,7 @@ mt7915_mac_write_txwi_tm(struct mt7915_dev *dev, struct mt76_phy *mphy, break; } - switch (mphy->chandef.width) { + switch (phy->mt76->chandef.width) { case NL80211_CHAN_WIDTH_40: bw = 1; break; @@ -693,12 +700,12 @@ mt7915_mac_write_txwi_tm(struct mt7915_dev *dev, struct mt76_phy *mphy, if (mode >= MT_PHY_TYPE_HE_SU) val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf); - if (td->tx_rate_ldpc) + if (td->tx_rate_ldpc || bw > 0) val |= MT_TXD6_LDPC; txwi[6] |= cpu_to_le32(val); txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, - dev->test.spe_idx)); + phy->test.spe_idx)); #endif } @@ -902,8 +909,8 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } - if (mt76_testmode_enabled(&dev->mt76)) - mt7915_mac_write_txwi_tm(dev, mphy, txwi, skb); + if (mt76_testmode_enabled(mphy)) + mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb); } static void @@ -942,6 +949,9 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, int id, i, nbuf = tx_info->nbuf - 1; u8 *txwi = (u8 *)txwi_ptr; + if (unlikely(tx_info->skb->len <= ETH_HLEN)) + return -EINVAL; + if (!wcid) wcid = &dev->mt76.global_wcid; @@ -1048,20 +1058,19 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, status.rate = &msta->stats.tx_rate; } - hw = mt76_tx_status_get_hw(mdev, skb); - #ifdef CONFIG_NL80211_TESTMODE - if (skb == mdev->test.tx_skb) { + if (mt76_is_testmode_skb(mdev, skb, &hw)) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct ieee80211_vif *vif = phy->monitor_vif; struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; mt76_tx_complete_skb(mdev, mvif->sta.wcid.idx, skb); - return; } #endif + hw = mt76_tx_status_get_hw(mdev, skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) info->flags |= IEEE80211_TX_STAT_AMPDU; @@ -1353,7 +1362,7 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) u32 val, sum = 0, n = 0; int nss, i; - for (nss = 0; nss < hweight8(phy->chainmask); nss++) { + for (nss = 0; nss < hweight8(phy->mt76->chainmask); nss++) { u32 reg = MT_WF_IRPI(nss + (idx << dev->dbdc_support)); for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { @@ -1434,7 +1443,15 @@ mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct ieee80211_hw *hw = priv; - mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon); + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon); + break; + default: + break; + } } static void @@ -1457,12 +1474,21 @@ mt7915_dma_reset(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy_ext = dev->mt76.phy2; + u32 hif1_ofs = MT_WFDMA1_PCIE1_BASE - MT_WFDMA1_BASE; int i; mt76_clear(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); mt76_clear(dev, MT_WFDMA1_GLO_CFG, MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + if (dev->hif2) { + mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, + (MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN)); + mt76_clear(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, + (MT_WFDMA1_GLO_CFG_TX_DMA_EN | + MT_WFDMA1_GLO_CFG_RX_DMA_EN)); + } usleep_range(1000, 2000); mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], true); @@ -1483,6 +1509,35 @@ mt7915_dma_reset(struct mt7915_phy *phy) MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); mt76_set(dev, MT_WFDMA1_GLO_CFG, MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + if (dev->hif2) { + mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, + (MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN)); + mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, + (MT_WFDMA1_GLO_CFG_TX_DMA_EN | + MT_WFDMA1_GLO_CFG_RX_DMA_EN)); + } +} + +void mt7915_tx_token_put(struct mt7915_dev *dev) +{ + struct mt76_txwi_cache *txwi; + int id; + + spin_lock_bh(&dev->token_lock); + idr_for_each_entry(&dev->token, txwi, id) { + mt7915_txp_skb_unmap(&dev->mt76, txwi); + if (txwi->skb) { + struct ieee80211_hw *hw; + + hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); + ieee80211_free_txskb(hw, txwi->skb); + } + mt76_put_txwi(&dev->mt76, txwi); + dev->token_count--; + } + spin_unlock_bh(&dev->token_lock); + idr_destroy(&dev->token); } /* system error recovery */ @@ -1506,9 +1561,9 @@ void mt7915_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); - cancel_delayed_work_sync(&dev->phy.mac_work); + cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) - cancel_delayed_work_sync(&phy2->mac_work); + cancel_delayed_work_sync(&phy2->mt76->mac_work); /* lock/unlock all queues to ensure that no tx is pending */ mt76_txq_schedule_all(&dev->mphy); @@ -1525,6 +1580,9 @@ void mt7915_mac_reset_work(struct work_struct *work) mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); + mt7915_tx_token_put(dev); + idr_init(&dev->token); + if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { mt7915_dma_reset(&dev->phy); @@ -1559,10 +1617,11 @@ void mt7915_mac_reset_work(struct work_struct *work) mt7915_update_beacons(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT7915_WATCHDOG_TIME); if (phy2) - ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mac_work, + ieee80211_queue_delayed_work(ext_phy->hw, + &phy2->mt76->mac_work, MT7915_WATCHDOG_TIME); } @@ -1673,17 +1732,17 @@ void mt7915_mac_sta_rc_work(struct work_struct *work) void mt7915_mac_work(struct work_struct *work) { struct mt7915_phy *phy; - struct mt76_dev *mdev; + struct mt76_phy *mphy; - phy = (struct mt7915_phy *)container_of(work, struct mt7915_phy, - mac_work.work); - mdev = &phy->dev->mt76; + mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, + mac_work.work); + phy = mphy->priv; - mutex_lock(&mdev->mutex); + mutex_lock(&mphy->dev->mutex); - mt76_update_survey(mdev); - if (++phy->mac_work_count == 5) { - phy->mac_work_count = 0; + mt76_update_survey(mphy->dev); + if (++mphy->mac_work_count == 5) { + mphy->mac_work_count = 0; mt7915_mac_update_mib_stats(phy); } @@ -1691,11 +1750,11 @@ void mt7915_mac_work(struct work_struct *work) if (++phy->sta_work_count == 10) { phy->sta_work_count = 0; mt7915_mac_sta_stats_work(phy); - }; + } - mutex_unlock(&mdev->mutex); + mutex_unlock(&mphy->dev->mutex); - ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7915_WATCHDOG_TIME); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index d420392b952d..96ff3fb0d1f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -95,6 +95,8 @@ enum rx_pkt_type { #define MT_RXD3_NORMAL_PF_MODE BIT(29) #define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) +#define MT_RXV_HDR_BAND_IDX BIT(24) + /* P-RXV */ #define MT_PRXV_TX_RATE GENMASK(6, 0) #define MT_PRXV_TX_DCM BIT(4) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 0c82aa2ef219..d4969b2e1ffb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -26,6 +26,8 @@ static int mt7915_start(struct ieee80211_hw *hw) struct mt7915_phy *phy = mt7915_hw_phy(hw); bool running; + flush_work(&dev->init_work); + mutex_lock(&dev->mt76.mutex); running = mt7915_dev_running(dev); @@ -44,13 +46,13 @@ static int mt7915_start(struct ieee80211_hw *hw) mt7915_mac_enable_nf(dev, 1); } - mt7915_mcu_set_sku_en(phy, !mt76_testmode_enabled(&dev->mt76)); - mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); + mt7915_mcu_set_sku_en(phy, true); + mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - if (!mt76_testmode_enabled(&dev->mt76)) - ieee80211_queue_delayed_work(hw, &phy->mac_work, + if (!mt76_testmode_enabled(phy->mt76)) + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT7915_WATCHDOG_TIME); if (!running) @@ -66,11 +68,11 @@ static void mt7915_stop(struct ieee80211_hw *hw) struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); - cancel_delayed_work_sync(&phy->mac_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); mutex_lock(&dev->mt76.mutex); - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -153,13 +155,13 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); if (vif->type == NL80211_IFTYPE_MONITOR && is_zero_ether_addr(vif->addr)) phy->monitor_vif = vif; - mvif->idx = ffs(~phy->mt76->vif_mask) - 1; + mvif->idx = ffs(~dev->mt76.vif_mask) - 1; if (mvif->idx >= MT7915_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -184,7 +186,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, if (ret) goto out; - phy->mt76->vif_mask |= BIT(mvif->idx); + dev->mt76.vif_mask |= BIT(mvif->idx); phy->omac_mask |= BIT_ULL(mvif->omac_idx); idx = MT7915_WTBL_RESERVED - mvif->idx; @@ -228,7 +230,7 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw, /* TODO: disable beacon for the bss */ mutex_lock(&dev->mt76.mutex); - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); mutex_unlock(&dev->mt76.mutex); if (vif == phy->monitor_vif) @@ -239,7 +241,7 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw, rcu_assign_pointer(dev->mt76.wcid[idx], NULL); mutex_lock(&dev->mt76.mutex); - phy->mt76->vif_mask &= ~BIT(mvif->idx); + dev->mt76.vif_mask &= ~BIT(mvif->idx); phy->omac_mask &= ~BIT_ULL(mvif->omac_idx); mutex_unlock(&dev->mt76.mutex); @@ -273,7 +275,7 @@ int mt7915_set_channel(struct mt7915_phy *phy) struct mt7915_dev *dev = phy->dev; int ret; - cancel_delayed_work_sync(&phy->mac_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); mutex_lock(&dev->mt76.mutex); set_bit(MT76_RESET, &phy->mt76->state); @@ -281,7 +283,7 @@ int mt7915_set_channel(struct mt7915_phy *phy) mt7915_init_dfs_state(phy); mt76_set_channel(phy->mt76); - ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH); + ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH)); if (ret) goto out; @@ -298,8 +300,9 @@ out: mt76_txq_schedule_all(phy->mt76); - if (!mt76_testmode_enabled(&dev->mt76)) - ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, + if (!mt76_testmode_enabled(phy->mt76)) + ieee80211_queue_delayed_work(phy->mt76->hw, + &phy->mt76->mac_work, MT7915_WATCHDOG_TIME); return ret; @@ -365,9 +368,9 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { #ifdef CONFIG_NL80211_TESTMODE - if (dev->mt76.test.state != MT76_TM_STATE_OFF) { + if (phy->mt76->test.state != MT76_TM_STATE_OFF) { mutex_lock(&dev->mt76.mutex); - mt76_testmode_reset(&dev->mt76, false); + mt76_testmode_reset(phy->mt76, false); mutex_unlock(&dev->mt76.mutex); } #endif @@ -396,7 +399,7 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN, enabled); - mt76_testmode_reset(&dev->mt76, true); + mt76_testmode_reset(phy->mt76, true); mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); } @@ -427,7 +430,6 @@ static void mt7915_configure_filter(struct ieee80211_hw *hw, struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); bool band = phy != &dev->phy; - u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | MT_WF_RFCR1_DROP_BF_POLL | MT_WF_RFCR1_DROP_BA | @@ -441,6 +443,8 @@ static void mt7915_configure_filter(struct ieee80211_hw *hw, phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ } while (0) + mutex_lock(&dev->mt76.mutex); + phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | MT_WF_RFCR_DROP_OTHER_BEACON | MT_WF_RFCR_DROP_FRAME_REPORT | @@ -471,6 +475,8 @@ static void mt7915_configure_filter(struct ieee80211_hw *hw, mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); else mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); + + mutex_unlock(&dev->mt76.mutex); } static void mt7915_bss_info_changed(struct ieee80211_hw *hw, @@ -808,7 +814,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) else tx_ant <<= 1; } - phy->chainmask = tx_ant; + phy->mt76->chainmask = tx_ant; mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index e211a2bd4d3c..195929242b72 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -66,9 +66,6 @@ struct mt7915_fw_region { #define MCU_PATCH_ADDRESS 0x200000 -#define MT_STA_BFER BIT(0) -#define MT_STA_BFEE BIT(1) - #define FW_FEATURE_SET_ENCRYPT BIT(0) #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) #define FW_FEATURE_OVERRIDE_ADDR BIT(5) @@ -232,18 +229,14 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, if (seq != rxd->seq) return -EAGAIN; - switch (cmd) { - case -MCU_CMD_PATCH_SEM_CONTROL: + if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; - break; - case MCU_EXT_CMD_THERMAL_CTRL: + } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { skb_pull(skb, sizeof(*rxd) + 4); ret = le32_to_cpu(*(__le32 *)skb->data); - break; - default: + } else { skb_pull(skb, sizeof(struct mt7915_mcu_rxd)); - break; } return ret; @@ -255,10 +248,10 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt7915_mcu_txd *mcu_txd; - u8 seq, pkt_fmt, qidx; enum mt76_mcuq_id qid; __le32 *txd; u32 val; + u8 seq; /* TODO: make dynamic based on msg type */ mdev->mcu.timeout = 20 * HZ; @@ -267,28 +260,22 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, if (!seq) seq = ++dev->mt76.mcu.msg_seq & 0xf; - if (cmd == -MCU_CMD_FW_SCATTER) { + if (cmd == MCU_CMD(FW_SCATTER)) { qid = MT_MCUQ_FWDL; goto exit; } mcu_txd = (struct mt7915_mcu_txd *)skb_push(skb, sizeof(*mcu_txd)); - - if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) { + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) qid = MT_MCUQ_WA; - qidx = MT_TX_MCU_PORT_RX_Q0; - pkt_fmt = MT_TX_TYPE_CMD; - } else { + else qid = MT_MCUQ_WM; - qidx = MT_TX_MCU_PORT_RX_Q0; - pkt_fmt = MT_TX_TYPE_CMD; - } txd = mcu_txd->txd; val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | - FIELD_PREP(MT_TXD0_PKT_FMT, pkt_fmt) | - FIELD_PREP(MT_TXD0_Q_IDX, qidx); + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | + FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); txd[0] = cpu_to_le32(val); val = MT_TXD1_LONG_FORMAT | @@ -296,31 +283,28 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, txd[1] = cpu_to_le32(val); mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); - mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, qidx)); + mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, + MT_TX_MCU_PORT_RX_Q0)); mcu_txd->pkt_type = MCU_PKT_ID; mcu_txd->seq = seq; - if (cmd < 0) { - mcu_txd->set_query = MCU_Q_NA; - mcu_txd->cid = -cmd; - } else { - mcu_txd->cid = MCU_CMD_EXT_CID; - mcu_txd->ext_cid = cmd; + mcu_txd->cid = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); + mcu_txd->set_query = MCU_Q_NA; + mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); + if (mcu_txd->ext_cid) { mcu_txd->ext_cid_ack = 1; /* do not use Q_SET for efuse */ - if (cmd == MCU_EXT_CMD_EFUSE_ACCESS) + if (cmd & __MCU_CMD_FIELD_QUERY) mcu_txd->set_query = MCU_Q_QUERY; else mcu_txd->set_query = MCU_Q_SET; } - if (cmd == MCU_EXT_CMD_MWDS_SUPPORT) + if (cmd & __MCU_CMD_FIELD_WA) mcu_txd->s2d_index = MCU_S2D_H2C; else mcu_txd->s2d_index = MCU_S2D_H2N; - WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && - mcu_txd->set_query != MCU_Q_QUERY); exit: if (wait_seq) @@ -330,6 +314,22 @@ exit: } static void +mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) +{ + struct { + __le32 args[3]; + } req = { + .args = { + cpu_to_le32(a1), + cpu_to_le32(a2), + cpu_to_le32(a3), + }, + }; + + mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); +} + +static void mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { if (vif->csa_active) @@ -674,6 +674,7 @@ mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MONITOR: break; case NL80211_IFTYPE_STATION: /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ @@ -702,16 +703,21 @@ mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } bss = (struct bss_info_basic *)tlv; - memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); - bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); bss->network_type = cpu_to_le32(type); - bss->dtim_period = vif->bss_conf.dtim_period; bss->bmc_wcid_lo = to_wcid_lo(wlan_idx); bss->bmc_wcid_hi = to_wcid_hi(wlan_idx); - bss->phy_mode = mt7915_get_phy_mode(phy->dev, vif, band, NULL); bss->wmm_idx = mvif->wmm_idx; bss->active = enable; + if (vif->type != NL80211_IFTYPE_MONITOR) { + memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); + bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + bss->dtim_period = vif->bss_conf.dtim_period; + bss->phy_mode = mt7915_get_phy_mode(phy->dev, vif, band, NULL); + } else { + memcpy(bss->bssid, phy->mt76->macaddr, ETH_ALEN); + } + return 0; } @@ -727,6 +733,7 @@ mt7915_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); switch (vif->type) { + case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: type = CONNECTION_INFRA_AP; @@ -832,9 +839,9 @@ static void mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) { + int max_nss = hweight8(phy->mt76->chainmask); struct bss_info_ra *ra; struct tlv *tlv; - int max_nss = hweight8(phy->chainmask); tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra)); @@ -972,7 +979,7 @@ mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif, if (enable) ether_addr_copy(req.addr, addr); - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MUAR_UPDATE, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req, sizeof(req), true); } @@ -996,6 +1003,9 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, mt7915_mcu_bss_basic_tlv(skb, vif, phy, enable); + if (vif->type == NL80211_IFTYPE_MONITOR) + goto out; + if (enable) { mt7915_mcu_bss_rfch_tlv(skb, vif, phy); mt7915_mcu_bss_bmc_tlv(skb, phy); @@ -1009,16 +1019,17 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, mvif->omac_idx < REPEATER_BSSID_START) mt7915_mcu_bss_ext_tlv(skb, mvif); } - +out: return mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, - MCU_EXT_CMD_BSS_INFO_UPDATE, true); + MCU_EXT_CMD(BSS_INFO_UPDATE), true); } /** starec & wtbl **/ static int -mt7915_mcu_sta_key_tlv(struct sk_buff *skb, struct ieee80211_key_conf *key, - enum set_key_cmd cmd) +mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb, + struct ieee80211_key_conf *key, enum set_key_cmd cmd) { + struct mt7915_sta_key_conf *bip = &msta->bip; struct sta_rec_sec *sec; struct tlv *tlv; u32 len = sizeof(*sec); @@ -1038,22 +1049,23 @@ mt7915_mcu_sta_key_tlv(struct sk_buff *skb, struct ieee80211_key_conf *key, sec_key = &sec->key[0]; sec_key->cipher_len = sizeof(*sec_key); - sec_key->key_id = key->keyidx; if (cipher == MT_CIPHER_BIP_CMAC_128) { sec_key->cipher_id = MT_CIPHER_AES_CCMP; + sec_key->key_id = bip->keyidx; sec_key->key_len = 16; - memcpy(sec_key->key, key->key, 16); + memcpy(sec_key->key, bip->key, 16); sec_key = &sec->key[1]; sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; sec_key->cipher_len = sizeof(*sec_key); sec_key->key_len = 16; - memcpy(sec_key->key, key->key + 16, 16); + memcpy(sec_key->key, key->key, 16); sec->n_cipher = 2; } else { sec_key->cipher_id = cipher; + sec_key->key_id = key->keyidx; sec_key->key_len = key->keylen; memcpy(sec_key->key, key->key, key->keylen); @@ -1063,6 +1075,12 @@ mt7915_mcu_sta_key_tlv(struct sk_buff *skb, struct ieee80211_key_conf *key, memcpy(sec_key->key + 24, key->key + 16, 8); } + /* store key_conf for BIP batch update */ + if (cipher == MT_CIPHER_AES_CCMP) { + memcpy(bip->key, key->key, key->keylen); + bip->keyidx = key->keyidx; + } + len -= sizeof(*sec_key); sec->n_cipher = 1; } @@ -1088,12 +1106,12 @@ int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (IS_ERR(skb)) return PTR_ERR(skb); - ret = mt7915_mcu_sta_key_tlv(skb, key, cmd); + ret = mt7915_mcu_sta_key_tlv(msta, skb, key, cmd); if (ret) return ret; return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); } static void @@ -1107,7 +1125,7 @@ mt7915_mcu_sta_ba_tlv(struct sk_buff *skb, tlv = mt7915_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); ba = (struct sta_rec_ba *)tlv; - ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT, + ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT; ba->winsize = cpu_to_le16(params->buf_size); ba->ssn = cpu_to_le16(params->ssn); ba->ba_en = enable << params->tid; @@ -1173,7 +1191,7 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev, mt7915_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); if (ret) return ret; @@ -1185,7 +1203,7 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev, mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); } int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, @@ -1521,7 +1539,7 @@ mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, mt7915_mcu_sta_muru_tlv(skb, sta); return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); } static void @@ -1688,7 +1706,7 @@ int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev, wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb); mt7915_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, + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(WTBL_UPDATE), true); } @@ -1713,12 +1731,13 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); } static void mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf) { + bf->bf_cap = MT_EBF; bf->sounding_phy = MT_PHY_TYPE_OFDM; bf->ndp_rate = 0; /* mcs0 */ bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ @@ -1726,13 +1745,14 @@ mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf) } static void -mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct sta_rec_bf *bf) +mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy, + struct sta_rec_bf *bf) { struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; u8 n = 0; bf->tx_mode = MT_PHY_TYPE_HT; - bf->bf_cap |= MT_IBF; + bf->bf_cap = MT_IBF; if (mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF && (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) @@ -1745,43 +1765,46 @@ mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct sta_rec_bf *bf) else if (mcs->rx_mask[1]) n = 1; + bf->nr = hweight8(phy->mt76->chainmask) - 1; bf->nc = min_t(u8, bf->nr, n); - bf->ibf_ncol = bf->nc; - - if (sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->nc) - bf->ibf_timeout = 0x48; + bf->ibf_ncol = n; } static void mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy, - struct sta_rec_bf *bf) + struct sta_rec_bf *bf, bool explicit) { struct ieee80211_sta_vht_cap *pc = &sta->vht_cap; struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap; - u8 bfee_nr, bfer_nr, n, tx_ant = hweight8(phy->chainmask) - 1; - u16 mcs_map; + u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map); + u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); + u8 tx_ant = hweight8(phy->mt76->chainmask) - 1; bf->tx_mode = MT_PHY_TYPE_VHT; - bf->bf_cap |= MT_EBF; - - mt7915_mcu_sta_sounding_rate(bf); - bfee_nr = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, - pc->cap); - bfer_nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, - vc->cap); - mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map); + if (explicit) { + u8 bfee_nr, bfer_nr; - n = min_t(u8, bfer_nr, bfee_nr); - bf->nr = min_t(u8, n, tx_ant); - n = mt7915_mcu_get_sta_nss(mcs_map); + mt7915_mcu_sta_sounding_rate(bf); + bfee_nr = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, + pc->cap); + bfer_nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, + vc->cap); + bf->nr = min_t(u8, min_t(u8, bfer_nr, bfee_nr), tx_ant); + bf->nc = min_t(u8, nss_mcs, bf->nr); + bf->ibf_ncol = bf->nc; - bf->nc = min_t(u8, n, bf->nr); - bf->ibf_ncol = bf->nc; + if (sta->bandwidth == IEEE80211_STA_RX_BW_160) + bf->nr = 1; + } else { + bf->bf_cap = MT_IBF; + bf->nr = tx_ant; + bf->nc = min_t(u8, nss_mcs, bf->nr); + bf->ibf_ncol = nss_mcs; - /* force nr from 4 to 2 */ - if (sta->bandwidth == IEEE80211_STA_RX_BW_160) - bf->nr = 1; + if (sta->bandwidth == IEEE80211_STA_RX_BW_160) + bf->ibf_nrow = 1; + } } static void @@ -1790,19 +1813,14 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, { struct ieee80211_sta_he_cap *pc = &sta->he_cap; struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; - const struct ieee80211_he_cap_elem *ve; - const struct ieee80211_sta_he_cap *vc; - u8 bfee_nr, bfer_nr, nss_mcs; - u16 mcs_map; - - vc = mt7915_get_he_phy_cap(phy, vif); - ve = &vc->he_cap_elem; + const struct ieee80211_sta_he_cap *vc = mt7915_get_he_phy_cap(phy, vif); + const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem; + u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80); + u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); + u8 bfee_nr, bfer_nr; bf->tx_mode = MT_PHY_TYPE_HE_SU; - bf->bf_cap |= MT_EBF; - mt7915_mcu_sta_sounding_rate(bf); - bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMER_FB, pe->phy_cap_info[6]); bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMER_FB, @@ -1811,10 +1829,6 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, ve->phy_cap_info[5]); bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, pe->phy_cap_info[4]); - - mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.tx_mcs_80); - nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - bf->nr = min_t(u8, bfer_nr, bfee_nr); bf->nc = min_t(u8, nss_mcs, bf->nr); bf->ibf_ncol = bf->nc; @@ -1853,11 +1867,11 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, static void mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct mt7915_phy *phy, - bool enable) + bool enable, bool explicit) { + int tx_ant = hweight8(phy->mt76->chainmask) - 1; struct sta_rec_bf *bf; struct tlv *tlv; - int tx_ant = hweight8(phy->chainmask) - 1; const u8 matrix[4][4] = { {0, 0, 0, 0}, {1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */ @@ -1875,19 +1889,29 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, return; } + /* he: eBF only, in accordance with spec + * vht: support eBF and iBF + * ht: iBF only, since mac80211 lacks of eBF support + */ + if (sta->he_cap.has_he && explicit) + mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); + else if (sta->vht_cap.vht_supported) + mt7915_mcu_sta_bfer_vht(sta, phy, bf, explicit); + else if (sta->ht_cap.ht_supported) + mt7915_mcu_sta_bfer_ht(sta, phy, bf); + else + return; + bf->bw = sta->bandwidth; bf->ibf_dbw = sta->bandwidth; bf->ibf_nrow = tx_ant; - bf->ibf_timeout = 0x18; - if (sta->he_cap.has_he) - mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); - else if (sta->vht_cap.vht_supported) - mt7915_mcu_sta_bfer_vht(sta, phy, bf); - else if (sta->ht_cap.ht_supported) - mt7915_mcu_sta_bfer_ht(sta, bf); + if (!explicit && sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->nc) + bf->ibf_timeout = 0x48; + else + bf->ibf_timeout = 0x18; - if (bf->bf_cap & MT_EBF && bf->nr != tx_ant) + if (explicit && bf->nr != tx_ant) bf->mem_20m = matrix[tx_ant][bf->nc]; else bf->mem_20m = matrix[bf->nr][bf->nc]; @@ -1910,9 +1934,9 @@ static void mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct mt7915_phy *phy) { + int tx_ant = hweight8(phy->mt76->chainmask) - 1; struct sta_rec_bfee *bfee; struct tlv *tlv; - int tx_ant = hweight8(phy->chainmask) - 1; u8 nr = 0; tlv = mt7915_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee)); @@ -1931,20 +1955,26 @@ mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, } /* reply with identity matrix to avoid 2x2 BF negative gain */ - if (nr == 1 && tx_ant == 2) - bfee->fb_identity_matrix = true; + bfee->fb_identity_matrix = !!(nr == 1 && tx_ant == 2); } -static u8 -mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int +mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) { - u8 type = 0; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_phy *phy; + struct sk_buff *skb; + int r, len; + bool ebfee = 0, ebf = 0; if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP) return 0; + phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; + if (sta->he_cap.has_he) { struct ieee80211_he_cap_elem *pe; const struct ieee80211_he_cap_elem *ve; @@ -1954,15 +1984,12 @@ mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, vc = mt7915_get_he_phy_cap(phy, vif); ve = &vc->he_cap_elem; - if ((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) || - HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) && - HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4])) - type |= MT_STA_BFEE; - - if ((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) || - HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) && - HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])) - type |= MT_STA_BFER; + ebfee = !!((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) || + HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) && + HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4])); + ebf = !!((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) || + HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) && + HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])); } else if (sta->vht_cap.vht_supported) { struct ieee80211_sta_vht_cap *pc; struct ieee80211_sta_vht_cap *vc; @@ -1975,53 +2002,30 @@ mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; - if ((pc->cap & cr) && (vc->cap & ce)) - type |= MT_STA_BFEE; - - if ((vc->cap & cr) && (pc->cap & ce)) - type |= MT_STA_BFER; - } else if (sta->ht_cap.ht_supported) { - /* TODO: iBF */ + ebfee = !!((pc->cap & cr) && (vc->cap & ce)); + ebf = !!((vc->cap & cr) && (pc->cap & ce)); } - return type; -} - -static int -mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) -{ - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct mt7915_phy *phy; - struct sk_buff *skb; - int r, len; - u8 type; - - phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; - - type = mt7915_mcu_sta_txbf_type(phy, vif, sta); - /* must keep each tag independent */ /* starec bf */ - if (type & MT_STA_BFER) { + if (ebf || dev->ibf) { len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bf); skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable); + mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable, ebf); r = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); if (r) return r; } /* starec bfee */ - if (type & MT_STA_BFEE) { + if (ebfee) { len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bfee); skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); @@ -2031,7 +2035,7 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, mt7915_mcu_sta_bfee_tlv(skb, sta, phy); r = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); if (r) return r; } @@ -2199,33 +2203,7 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); -} - -static int -mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ -#define MT_STA_BSS_GROUP 1 - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct { - __le32 action; - u8 wlan_idx_lo; - u8 status; - u8 wlan_idx_hi; - u8 rsv0[5]; - __le32 val; - u8 rsv1[8]; - } __packed req = { - .action = cpu_to_le32(MT_STA_BSS_GROUP), - .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), - .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), - .val = cpu_to_le32(mvif->idx % 16), - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_DRR_CTRL, &req, - sizeof(req), true); + MCU_EXT_CMD(STA_REC_UPDATE), true); } int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, @@ -2237,10 +2215,6 @@ int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, return 0; /* must keep the order */ - ret = mt7915_mcu_add_group(dev, vif, sta); - if (ret) - return ret; - ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); if (ret) return ret; @@ -2287,7 +2261,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, } return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); } int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, @@ -2333,7 +2307,7 @@ int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); + MCU_EXT_CMD(STA_REC_UPDATE), true); } int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, @@ -2375,7 +2349,7 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, return mt7915_mcu_muar_config(phy, vif, false, enable); memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE), &data, sizeof(data), true); } @@ -2468,7 +2442,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, dev_kfree_skb(skb); return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, - MCU_EXT_CMD_BSS_INFO_UPDATE, true); + MCU_EXT_CMD(BSS_INFO_UPDATE), true); } static int mt7915_mcu_start_firmware(struct mt7915_dev *dev, u32 addr, @@ -2482,7 +2456,7 @@ static int mt7915_mcu_start_firmware(struct mt7915_dev *dev, u32 addr, .addr = cpu_to_le32(addr), }; - return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_CMD(FW_START_REQ), &req, sizeof(req), true); } @@ -2495,7 +2469,7 @@ static int mt7915_mcu_restart(struct mt76_dev *dev) .power_mode = 1, }; - return mt76_mcu_send_msg(dev, -MCU_CMD_NIC_POWER_CTRL, &req, + return mt76_mcu_send_msg(dev, MCU_CMD(NIC_POWER_CTRL), &req, sizeof(req), false); } @@ -2507,7 +2481,7 @@ static int mt7915_mcu_patch_sem_ctrl(struct mt7915_dev *dev, bool get) .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), }; - return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_CMD(PATCH_SEM_CONTROL), &req, sizeof(req), true); } @@ -2520,7 +2494,7 @@ static int mt7915_mcu_start_patch(struct mt7915_dev *dev) .check_crc = 0, }; - return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_CMD(PATCH_FINISH_REQ), &req, sizeof(req), true); } @@ -2553,9 +2527,9 @@ static int mt7915_mcu_init_download(struct mt7915_dev *dev, u32 addr, int attr; if (req.addr == cpu_to_le32(MCU_PATCH_ADDRESS)) - attr = -MCU_CMD_PATCH_START_REQ; + attr = MCU_CMD(PATCH_START_REQ); else - attr = -MCU_CMD_TARGET_ADDRESS_LEN_REQ; + attr = MCU_CMD(TARGET_ADDRESS_LEN_REQ); return mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true); } @@ -2616,7 +2590,7 @@ static int mt7915_load_patch(struct mt7915_dev *dev) goto out; } - ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER, + ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), dl, len); if (ret) { dev_err(dev->mt76.dev, "Failed to send patch\n"); @@ -2685,7 +2659,7 @@ mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, return err; } - err = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER, + err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), data + offset, len); if (err) { dev_err(dev->mt76.dev, "Failed to send firmware.\n"); @@ -2815,7 +2789,7 @@ int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl) .ctrl_val = ctrl }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST, &data, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data, sizeof(data), true); } @@ -2833,7 +2807,7 @@ int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level) .level = level, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_DBG_CTRL, &data, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_DBG_CTRL), &data, sizeof(data), false); } @@ -2846,7 +2820,7 @@ static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled) .enable = enabled }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MWDS_SUPPORT, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req, sizeof(req), false); } @@ -2873,6 +2847,7 @@ int mt7915_mcu_init(struct mt7915_dev *dev) set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt7915_mcu_fw_log_2_host(dev, 0); mt7915_mcu_set_mwds(dev, 1); + mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_RED, 0, 0); return 0; } @@ -2919,12 +2894,12 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, }; int ret; - ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS, + ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS), &req_trans, sizeof(req_trans), false); if (ret) return ret; - 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); } @@ -2940,7 +2915,7 @@ int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable) .enable = enable + 1, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SCS_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SCS_CTRL), &req, sizeof(req), false); } @@ -2960,34 +2935,25 @@ int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val) .pkt_thresh = cpu_to_le32(0x2), }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, sizeof(req), true); } +int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param) +{ + struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param; + u8 num = req->total; + size_t len = sizeof(*req) - + (IEEE80211_NUM_ACS - num) * sizeof(struct edca); + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), req, + len, true); +} + int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) { -#define WMM_AIFS_SET BIT(0) -#define WMM_CW_MIN_SET BIT(1) -#define WMM_CW_MAX_SET BIT(2) -#define WMM_TXOP_SET BIT(3) -#define WMM_PARAM_SET GENMASK(3, 0) #define TX_CMD_MODE 1 - struct edca { - u8 queue; - u8 set; - u8 aifs; - u8 cw_min; - __le16 cw_max; - __le16 txop; - }; - struct mt7915_mcu_tx { - u8 total; - u8 action; - u8 valid; - u8 mode; - - struct edca edca[IEEE80211_NUM_ACS]; - } __packed req = { + struct mt7915_mcu_tx req = { .valid = true, .mode = TX_CMD_MODE, .total = IEEE80211_NUM_ACS, @@ -3014,8 +2980,8 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) else e->cw_max = cpu_to_le16(10); } - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, - sizeof(req), true); + + return mt7915_mcu_update_edca(dev, &req); } int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter) @@ -3045,7 +3011,7 @@ int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter) .band_idx = band, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PM_STATE_CTRL), &req, sizeof(req), true); } @@ -3066,7 +3032,7 @@ int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, .val = val, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_CTRL), &req, sizeof(req), true); } @@ -3081,7 +3047,7 @@ int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val) .min_lpn = cpu_to_le16(val), }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, sizeof(req), true); } @@ -3112,7 +3078,7 @@ int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, #undef __req_field }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, sizeof(req), true); } @@ -3129,8 +3095,8 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, u8 max_crpn; u8 min_crpr; u8 min_pw; - u32 min_pri; - u32 max_pri; + __le32 min_pri; + __le32 max_pri; u8 max_pw; u8 min_crbn; u8 max_crbn; @@ -3138,7 +3104,7 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, u8 max_stgpn; u8 min_stgpr; u8 rsv[2]; - u32 min_stgpr_diff; + __le32 min_stgpr_diff; } __packed req = { .tag = cpu_to_le32(0x2), .radar_type = cpu_to_le16(index), @@ -3164,7 +3130,7 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, #undef __req_field_u32 }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, sizeof(req), true); } @@ -3173,6 +3139,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = chandef->center_freq1; + bool ext_phy = phy != &dev->phy; struct { u8 control_ch; u8 center_ch; @@ -3196,16 +3163,22 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) .bw = mt7915_mcu_chan_bw(chandef), .tx_streams_num = hweight8(phy->mt76->antenna_mask), .rx_streams = phy->mt76->antenna_mask, - .band_idx = phy != &dev->phy, + .band_idx = ext_phy, .channel_band = chandef->chan->band, }; #ifdef CONFIG_NL80211_TESTMODE - if (dev->mt76.test.tx_antenna_mask && - (dev->mt76.test.state == MT76_TM_STATE_TX_FRAMES || - dev->mt76.test.state == MT76_TM_STATE_RX_FRAMES)) { - req.tx_streams_num = fls(dev->mt76.test.tx_antenna_mask); - req.rx_streams = dev->mt76.test.tx_antenna_mask; + if (phy->mt76->test.tx_antenna_mask && + (phy->mt76->test.state == MT76_TM_STATE_TX_FRAMES || + phy->mt76->test.state == MT76_TM_STATE_RX_FRAMES || + phy->mt76->test.state == MT76_TM_STATE_TX_CONT)) { + req.tx_streams_num = fls(phy->mt76->test.tx_antenna_mask); + req.rx_streams = phy->mt76->test.tx_antenna_mask; + + if (ext_phy) { + req.tx_streams_num = 2; + req.rx_streams >>= 2; + } } #endif @@ -3217,7 +3190,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) else req.switch_reason = CH_SWITCH_NORMAL; - if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) + if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) req.rx_streams = hweight8(req.rx_streams); if (chandef->width == NL80211_CHAN_WIDTH_80P80) { @@ -3229,18 +3202,58 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } +static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev) +{ +#define TOTAL_PAGE_MASK GENMASK(7, 5) +#define PAGE_IDX_MASK GENMASK(4, 2) +#define PER_PAGE_SIZE 0x400 + struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER }; + u8 total = MT7915_EEPROM_SIZE / PER_PAGE_SIZE; + u8 *eep = (u8 *)dev->mt76.eeprom.data; + int eep_len; + int i; + + for (i = 0; i <= total; i++, eep += eep_len) { + struct sk_buff *skb; + int ret; + + if (i == total) + eep_len = MT7915_EEPROM_SIZE % PER_PAGE_SIZE; + else + eep_len = PER_PAGE_SIZE; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(req) + eep_len); + if (!skb) + return -ENOMEM; + + req.format = FIELD_PREP(TOTAL_PAGE_MASK, total) | + FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE; + req.len = cpu_to_le16(eep_len); + + skb_put_data(skb, &req, sizeof(req)); + skb_put_data(skb, eep, eep_len); + + ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(EFUSE_BUFFER_MODE), true); + if (ret) + return ret; + } + + return 0; +} + int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) { - struct req_hdr { - u8 buffer_mode; - u8 format; - __le16 len; - } __packed req = { + struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_EFUSE, .format = EE_FORMAT_WHOLE, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, + if (dev->flash_mode) + return mt7915_mcu_set_eeprom_flash(dev); + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE), &req, sizeof(req), true); } @@ -3254,7 +3267,7 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) int ret; u8 *buf; - ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS), &req, sizeof(req), true, &skb); if (ret) return ret; @@ -3279,7 +3292,7 @@ int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index) .action = index, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_THERMAL_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, sizeof(req), true); } @@ -3297,7 +3310,7 @@ int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) .dump_group = cpu_to_le16(1), }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RATE_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RATE_CTRL), &req, sizeof(req), false); } @@ -3326,7 +3339,7 @@ int mt7915_mcu_set_sku(struct mt7915_phy *phy) req.val[i] = hw->conf.power_level * 2 + delta[i]; return mt76_mcu_send_msg(&dev->mt76, - MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); } @@ -3348,7 +3361,7 @@ int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode, .enable = en, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } @@ -3367,7 +3380,7 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) }; return mt76_mcu_send_msg(&dev->mt76, - MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); } @@ -3384,10 +3397,29 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) .band = band, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SER_TRIGGER, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SER_TRIGGER), &req, sizeof(req), false); } +int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev) +{ +#define MT_BF_MODULE_UPDATE 25 + struct { + u8 action; + u8 bf_num; + u8 bf_bitmap; + u8 bf_sel[8]; + u8 rsv[8]; + } __packed req = { + .action = MT_BF_MODULE_UPDATE, + .bf_num = 2, + .bf_bitmap = GENMASK(1, 0), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, + sizeof(req), true); +} + int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev) { #define MT_BF_TYPE_UPDATE 20 @@ -3399,10 +3431,10 @@ int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev) } __packed req = { .action = MT_BF_TYPE_UPDATE, .ebf = true, - .ibf = false, + .ibf = dev->ibf, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, sizeof(req), true); } @@ -3421,7 +3453,7 @@ int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev) .snd_mode = MT_BF_PROCESSING, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, sizeof(req), true); } @@ -3446,7 +3478,7 @@ int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, .val = cpu_to_le32(enable), }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SPR, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, sizeof(req), true); } @@ -3473,7 +3505,7 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, int ret; int i; - ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_PHY_STAT_INFO, + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(PHY_STAT_INFO), &req, sizeof(req), true, &skb); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index cd1a4256c843..2d584142c27b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -49,6 +49,8 @@ enum { enum { MCU_ATE_SET_TRX = 0x1, MCU_ATE_SET_FREQ_OFFSET = 0xa, + MCU_ATE_SET_SLOT_TIME = 0x13, + MCU_ATE_CLEAN_TXQUEUE = 0x1c, }; struct mt7915_mcu_rxd { @@ -118,6 +120,12 @@ struct mt7915_mcu_rdd_report { } hw_pulse[32]; } __packed; +struct mt7915_mcu_eeprom { + u8 buffer_mode; + u8 format; + __le16 len; +} __packed; + struct mt7915_mcu_eeprom_info { __le32 addr; __le32 valid; @@ -176,6 +184,30 @@ struct mt7915_mcu_phy_rx_info { #define MT_RA_RATE_DCM_EN BIT(4) #define MT_RA_RATE_BW GENMASK(14, 13) +struct edca { + u8 queue; + u8 set; + u8 aifs; + u8 cw_min; + __le16 cw_max; + __le16 txop; +}; + +struct mt7915_mcu_tx { + u8 total; + u8 action; + u8 valid; + u8 mode; + + struct edca edca[IEEE80211_NUM_ACS]; +} __packed; + +#define WMM_AIFS_SET BIT(0) +#define WMM_CW_MIN_SET BIT(1) +#define WMM_CW_MAX_SET BIT(2) +#define WMM_TXOP_SET BIT(3) +#define WMM_PARAM_SET GENMASK(3, 0) + #define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) #define MCU_PKT_ID 0xa0 @@ -193,6 +225,12 @@ enum { MCU_S2D_H2CN }; + +#define __MCU_CMD_FIELD_ID GENMASK(7, 0) +#define __MCU_CMD_FIELD_EXT_ID GENMASK(15, 8) +#define __MCU_CMD_FIELD_QUERY BIT(16) +#define __MCU_CMD_FIELD_WA BIT(17) + enum { MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01, MCU_CMD_FW_START_REQ = 0x02, @@ -201,6 +239,7 @@ enum { MCU_CMD_PATCH_START_REQ = 0x05, MCU_CMD_PATCH_FINISH_REQ = 0x07, MCU_CMD_PATCH_SEM_CONTROL = 0x10, + MCU_CMD_WA_PARAM = 0xC4, MCU_CMD_EXT_CID = 0xED, MCU_CMD_FW_SCATTER = 0xEE, MCU_CMD_RESTART_DL_REQ = 0xEF, @@ -208,6 +247,7 @@ enum { enum { MCU_EXT_CMD_EFUSE_ACCESS = 0x01, + MCU_EXT_CMD_RF_TEST = 0x04, MCU_EXT_CMD_PM_STATE_CTRL = 0x07, MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, @@ -239,6 +279,29 @@ enum { }; enum { + MCU_WA_PARAM_CMD_QUERY, + MCU_WA_PARAM_CMD_SET, + MCU_WA_PARAM_CMD_CAPABILITY, + MCU_WA_PARAM_CMD_DEBUG, +}; + +enum { + MCU_WA_PARAM_RED = 0x0e, +}; + +#define MCU_CMD(_t) FIELD_PREP(__MCU_CMD_FIELD_ID, MCU_CMD_##_t) +#define MCU_EXT_CMD(_t) (MCU_CMD(EXT_CID) | \ + FIELD_PREP(__MCU_CMD_FIELD_EXT_ID, \ + MCU_EXT_CMD_##_t)) +#define MCU_EXT_QUERY(_t) (MCU_EXT_CMD(_t) | __MCU_CMD_FIELD_QUERY) + +#define MCU_WA_CMD(_t) (MCU_CMD(_t) | __MCU_CMD_FIELD_WA) +#define MCU_WA_EXT_CMD(_t) (MCU_EXT_CMD(_t) | __MCU_CMD_FIELD_WA) +#define MCU_WA_PARAM_CMD(_t) (MCU_WA_CMD(WA_PARAM) | \ + FIELD_PREP(__MCU_CMD_FIELD_EXT_ID, \ + MCU_WA_PARAM_CMD_##_t)) + +enum { PATCH_SEM_RELEASE, PATCH_SEM_GET }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 0339abf360d3..5c7eefdf2013 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -61,6 +61,7 @@ enum mt7915_rxq_id { MT7915_RXQ_BAND1, MT7915_RXQ_MCU_WM = 0, MT7915_RXQ_MCU_WA, + MT7915_RXQ_MCU_WA_EXT, }; struct mt7915_sta_stats { @@ -72,6 +73,11 @@ struct mt7915_sta_stats { unsigned long jiffies; }; +struct mt7915_sta_key_conf { + s8 keyidx; + u8 key[16]; +}; + struct mt7915_sta { struct mt76_wcid wcid; /* must be first */ @@ -85,6 +91,8 @@ struct mt7915_sta { struct mt7915_sta_stats stats; unsigned long ampdu_state; + + struct mt7915_sta_key_conf bip; }; struct mt7915_vif { @@ -107,6 +115,14 @@ struct mib_stats { u16 ba_miss_cnt; }; +struct mt7915_hif { + struct list_head list; + + struct device *dev; + void __iomem *regs; + int irq; +}; + struct mt7915_phy { struct mt76_phy *mt76; struct mt7915_dev *dev; @@ -119,7 +135,6 @@ struct mt7915_phy { u64 omac_mask; u16 noise; - u16 chainmask; s16 coverage_class; u8 slottime; @@ -133,9 +148,21 @@ struct mt7915_phy { struct mib_stats mib; struct list_head stats_list; - struct delayed_work mac_work; - u8 mac_work_count; u8 sta_work_count; + +#ifdef CONFIG_NL80211_TESTMODE + struct { + u32 *reg_backup; + + s32 last_freq_offset; + u8 last_rcpi[4]; + s8 last_ib_rssi[4]; + s8 last_wb_rssi[4]; + u8 last_snr; + + u8 spe_idx; + } test; +#endif }; struct mt7915_dev { @@ -144,10 +171,13 @@ struct mt7915_dev { struct mt76_phy mphy; }; + struct mt7915_hif *hif2; + const struct mt76_bus_ops *bus_ops; struct mt7915_phy phy; u16 chainmask; + u32 hif_idx; struct work_struct init_work; struct work_struct rc_work; @@ -168,21 +198,9 @@ struct mt7915_dev { s8 **rate_power; /* TODO: use mt76_rate_power */ bool dbdc_support; + bool flash_mode; bool fw_debug; - -#ifdef CONFIG_NL80211_TESTMODE - struct { - u32 *reg_backup; - - s32 last_freq_offset; - u8 last_rcpi[4]; - s8 last_ib_rssi[4]; - s8 last_wb_rssi[4]; - u8 last_snr; - - u8 spe_idx; - } test; -#endif + bool ibf; }; enum { @@ -271,7 +289,6 @@ static inline u8 mt7915_lmac_mapping(struct mt7915_dev *dev, u8 ac) } extern const struct ieee80211_ops mt7915_ops; -extern struct pci_driver mt7915_pci_driver; extern const struct mt76_testmode_ops mt7915_testmode_ops; u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr); @@ -319,6 +336,7 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, int mt7915_set_channel(struct mt7915_phy *phy); int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd); int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif); +int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *req); int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, struct ieee80211_sta *sta, u32 rate); int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); @@ -334,6 +352,7 @@ int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); int mt7915_mcu_set_sku(struct mt7915_phy *phy); int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev); +int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev); int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, @@ -356,14 +375,23 @@ static inline bool is_mt7915(struct mt76_dev *dev) return mt76_chip(dev) == 0x7915; } +void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, bool write_reg, + u32 clear, u32 set); + static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask) { - mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); + if (dev->hif2) + mt7915_dual_hif_set_irq_mask(dev, true, 0, mask); + else + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); } static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) { - mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); + if (dev->hif2) + mt7915_dual_hif_set_irq_mask(dev, true, mask, 0); + else + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } static inline u32 @@ -463,6 +491,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info); void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); +void mt7915_tx_token_put(struct mt7915_dev *dev); int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc); void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index aeb86fbea41c..13880cc9c9e8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -12,11 +12,72 @@ #include "mac.h" #include "../trace.h" +static LIST_HEAD(hif_list); +static DEFINE_SPINLOCK(hif_lock); +static u32 hif_idx; + static const struct pci_device_id mt7915_pci_device_table[] = { - { PCI_DEVICE(0x14c3, 0x7915) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7915) }, { }, }; +static const struct pci_device_id mt7915_hif_device_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7916) }, + { }, +}; + +void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, bool write_reg, + u32 clear, u32 set) +{ + struct mt76_dev *mdev = &dev->mt76; + unsigned long flags; + + spin_lock_irqsave(&mdev->mmio.irq_lock, flags); + + mdev->mmio.irqmask &= ~clear; + mdev->mmio.irqmask |= set; + + if (write_reg) { + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); + mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + } + + spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); +} + +static struct mt7915_hif * +mt7915_pci_get_hif2(struct mt7915_dev *dev) +{ + struct mt7915_hif *hif; + u32 val; + + spin_lock_bh(&hif_lock); + + list_for_each_entry(hif, &hif_list, list) { + val = readl(hif->regs + MT_PCIE_RECOG_ID); + val &= MT_PCIE_RECOG_ID_MASK; + if (val != dev->hif_idx) + continue; + + get_device(hif->dev); + goto out; + } + hif = NULL; + +out: + spin_unlock_bh(&hif_lock); + + return hif; +} + +static void mt7915_put_hif2(struct mt7915_hif *hif) +{ + if (!hif) + return; + + put_device(hif->dev); +} + static void mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { @@ -26,6 +87,7 @@ mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) [MT_RXQ_EXT] = MT_INT_RX_DONE_DATA1, [MT_RXQ_MCU] = MT_INT_RX_DONE_WM, [MT_RXQ_MCU_WA] = MT_INT_RX_DONE_WA, + [MT_RXQ_EXT_WA] = MT_INT_RX_DONE_WA_EXT, }; mt7915_irq_enable(dev, rx_irq_mask[q]); @@ -35,12 +97,20 @@ mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) { struct mt7915_dev *dev = dev_instance; - u32 intr, mask; + u32 intr, intr1, mask; intr = mt76_rr(dev, MT_INT_SOURCE_CSR); intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + if (dev->hif2) { + intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); + intr1 &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); + + intr |= intr1; + } + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; @@ -67,6 +137,9 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) if (intr & MT_INT_RX_DONE_WA) napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]); + if (intr & MT_INT_RX_DONE_WA_EXT) + napi_schedule(&dev->mt76.napi[MT_RXQ_EXT_WA]); + if (intr & MT_INT_MCU_CMD) { u32 val = mt76_rr(dev, MT_MCU_CMD); @@ -103,6 +176,53 @@ mt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev) return 0; } +static void mt7915_pci_init_hif2(struct mt7915_dev *dev) +{ + struct mt7915_hif *hif; + + dev->hif_idx = ++hif_idx; + if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL)) + return; + + mt76_wr(dev, MT_PCIE_RECOG_ID, dev->hif_idx | MT_PCIE_RECOG_ID_SEM); + + hif = mt7915_pci_get_hif2(dev); + if (!hif) + return; + + dev->hif2 = hif; + + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + + if (devm_request_irq(dev->mt76.dev, hif->irq, mt7915_irq_handler, + IRQF_SHARED, KBUILD_MODNAME "-hif", dev)) { + mt7915_put_hif2(hif); + hif = NULL; + } + + /* master switch of PCIe tnterrupt enable */ + mt7915_l1_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); +} + +static int mt7915_pci_hif2_probe(struct pci_dev *pdev) +{ + struct mt7915_hif *hif; + + hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL); + if (!hif) + return -ENOMEM; + + hif->dev = &pdev->dev; + hif->regs = pcim_iomap_table(pdev)[0]; + hif->irq = pdev->irq; + spin_lock_bh(&hif_lock); + list_add(&hif->list, &hif_list); + spin_unlock_bh(&hif_lock); + pci_set_drvdata(pdev, hif); + + return 0; +} + static int mt7915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -141,6 +261,9 @@ static int mt7915_pci_probe(struct pci_dev *pdev, if (ret) return ret; + if (id->device == 0x7916) + return mt7915_pci_hif2_probe(pdev); + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7915_ops, &drv_ops); if (!mdev) @@ -166,6 +289,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev, if (ret) goto error; + mt7915_pci_init_hif2(dev); + ret = mt7915_register_device(dev); if (ret) goto error; @@ -177,24 +302,64 @@ error: return ret; } +static void mt7915_hif_remove(struct pci_dev *pdev) +{ + struct mt7915_hif *hif = pci_get_drvdata(pdev); + + list_del(&hif->list); +} + static void mt7915_pci_remove(struct pci_dev *pdev) { - struct mt76_dev *mdev = pci_get_drvdata(pdev); - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt76_dev *mdev; + struct mt7915_dev *dev; + mdev = pci_get_drvdata(pdev); + dev = container_of(mdev, struct mt7915_dev, mt76); + mt7915_put_hif2(dev->hif2); mt7915_unregister_device(dev); } -struct pci_driver mt7915_pci_driver = { +static struct pci_driver mt7915_hif_driver = { + .name = KBUILD_MODNAME "_hif", + .id_table = mt7915_hif_device_table, + .probe = mt7915_pci_probe, + .remove = mt7915_hif_remove, +}; + +static struct pci_driver mt7915_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7915_pci_device_table, .probe = mt7915_pci_probe, .remove = mt7915_pci_remove, }; -module_pci_driver(mt7915_pci_driver); +static int __init mt7915_init(void) +{ + int ret; + + ret = pci_register_driver(&mt7915_hif_driver); + if (ret) + return ret; + + ret = pci_register_driver(&mt7915_pci_driver); + if (ret) + pci_unregister_driver(&mt7915_hif_driver); + + return ret; +} + +static void __exit mt7915_exit(void) +{ + pci_unregister_driver(&mt7915_pci_driver); + pci_unregister_driver(&mt7915_hif_driver); +} + +module_init(mt7915_init); +module_exit(mt7915_exit); MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table); +MODULE_DEVICE_TABLE(pci, mt7915_hif_device_table); MODULE_FIRMWARE(MT7915_FIRMWARE_WA); MODULE_FIRMWARE(MT7915_FIRMWARE_WM); MODULE_FIRMWARE(MT7915_ROM_PATCH); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 848703e6eb7c..ed0c9a24bb53 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -59,6 +59,13 @@ #define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) #define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) +#define MT_TMAC_ATCR(_band) MT_WF_TMAC(_band, 0x098) +#define MT_TMAC_ATCR_TXV_TOUT GENMASK(7, 0) + +#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c) +#define MT_TMAC_TRCR0_TR2T_CHK GENMASK(8, 0) +#define MT_TMAC_TRCR0_I2T_CHK GENMASK(24, 16) + #define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4) #define MT_IFS_EIFS GENMASK(8, 0) #define MT_IFS_RIFS GENMASK(14, 10) @@ -70,7 +77,6 @@ #define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) #define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) -#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c) #define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0) #define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00) @@ -342,21 +348,36 @@ #define MT_INT_RX_DONE_DATA1 BIT(17) #define MT_INT_RX_DONE_WM BIT(0) #define MT_INT_RX_DONE_WA BIT(1) -#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | GENMASK(17, 16)) +#define MT_INT_RX_DONE_WA_EXT BIT(2) +#define MT_INT_RX_DONE_ALL (GENMASK(2, 0) | GENMASK(17, 16)) #define MT_INT_TX_DONE_MCU_WA BIT(15) #define MT_INT_TX_DONE_FWDL BIT(26) #define MT_INT_TX_DONE_MCU_WM BIT(27) #define MT_INT_TX_DONE_BAND0 BIT(30) #define MT_INT_TX_DONE_BAND1 BIT(31) + +#define MT_INT_BAND1_MASK (MT_INT_RX_DONE_WA_EXT | \ + MT_INT_TX_DONE_BAND1) + #define MT_INT_MCU_CMD BIT(29) #define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WA | \ MT_INT_TX_DONE_MCU_WM | \ MT_INT_TX_DONE_FWDL) +#define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30) +#define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0) + #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) +#define MT_INT1_SOURCE_CSR MT_WFDMA_EXT_CSR(0x88) +#define MT_INT1_MASK_CSR MT_WFDMA_EXT_CSR(0x8c) + +#define MT_PCIE_RECOG_ID MT_WFDMA_EXT_CSR(0x90) +#define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) +#define MT_PCIE_RECOG_ID_SEM BIT(31) + /* WFDMA0 PCIE1 */ #define MT_WFDMA0_PCIE1_BASE 0xd8000 #define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) @@ -411,6 +432,10 @@ #define MT_HW_CHIPID 0x70010200 #define MT_HW_REV 0x70010204 +#define MT_PCIE1_MAC_BASE 0x74020000 +#define MT_PCIE1_MAC(ofs) (MT_PCIE1_MAC_BASE + (ofs)) +#define MT_PCIE1_MAC_INT_ENABLE MT_PCIE1_MAC(0x188) + #define MT_PCIE_MAC_BASE 0x74030000 #define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) #define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index 9ee82e2d262c..7fb2170a9561 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -70,30 +70,32 @@ mt7915_tm_set_tx_power(struct mt7915_phy *phy) }; u8 *tx_power = NULL; - if (dev->mt76.test.state != MT76_TM_STATE_OFF) - tx_power = dev->mt76.test.tx_power; + if (phy->mt76->test.state != MT76_TM_STATE_OFF) + tx_power = phy->mt76->test.tx_power; /* Tx power of the other antennas are the same as antenna 0 */ if (tx_power && tx_power[0]) req.tx_power = tx_power[0]; ret = mt76_mcu_send_msg(&dev->mt76, - MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), false); return ret; } static int -mt7915_tm_set_freq_offset(struct mt7915_dev *dev, bool en, u32 val) +mt7915_tm_set_freq_offset(struct mt7915_phy *phy, bool en, u32 val) { + struct mt7915_dev *dev = phy->dev; struct mt7915_tm_cmd req = { .testmode_en = en, .param_idx = MCU_ATE_SET_FREQ_OFFSET, + .param.freq.band = phy != &dev->phy, .param.freq.freq_offset = cpu_to_le32(val), }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } @@ -110,14 +112,14 @@ mt7915_tm_mode_ctrl(struct mt7915_dev *dev, bool enable) }; return mt76_mcu_send_msg(&dev->mt76, - MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), false); } static int -mt7915_tm_set_trx(struct mt7915_dev *dev, struct mt7915_phy *phy, - int type, bool en) +mt7915_tm_set_trx(struct mt7915_phy *phy, int type, bool en) { + struct mt7915_dev *dev = phy->dev; struct mt7915_tm_cmd req = { .testmode_en = 1, .param_idx = MCU_ATE_SET_TRX, @@ -126,19 +128,230 @@ mt7915_tm_set_trx(struct mt7915_dev *dev, struct mt7915_phy *phy, .param.trx.band = phy != &dev->phy, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req, + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, + sizeof(req), false); +} + +static int +mt7915_tm_clean_hwq(struct mt7915_phy *phy, u8 wcid) +{ + struct mt7915_dev *dev = phy->dev; + struct mt7915_tm_cmd req = { + .testmode_en = 1, + .param_idx = MCU_ATE_CLEAN_TXQUEUE, + .param.clean.wcid = wcid, + .param.clean.band = phy != &dev->phy, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, + sizeof(req), false); +} + +static int +mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs) +{ + struct mt7915_dev *dev = phy->dev; + struct mt7915_tm_cmd req = { + .testmode_en = !(phy->mt76->test.state == MT76_TM_STATE_OFF), + .param_idx = MCU_ATE_SET_SLOT_TIME, + .param.slot.slot_time = slot_time, + .param.slot.sifs = sifs, + .param.slot.rifs = 2, + .param.slot.eifs = cpu_to_le16(60), + .param.slot.band = phy != &dev->phy, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } +static int +mt7915_tm_set_wmm_qid(struct mt7915_dev *dev, u8 qid, u8 aifs, u8 cw_min, + u16 cw_max, u16 txop) +{ + struct mt7915_mcu_tx req = { .total = 1 }; + struct edca *e = &req.edca[0]; + + e->queue = qid; + e->set = WMM_PARAM_SET; + + e->aifs = aifs; + e->cw_min = cw_min; + e->cw_max = cpu_to_le16(cw_max); + e->txop = cpu_to_le16(txop); + + return mt7915_mcu_update_edca(dev, &req); +} + +static int +mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode) +{ +#define TM_DEFAULT_SIFS 10 +#define TM_MAX_SIFS 127 +#define TM_MAX_AIFSN 0xf +#define TM_MIN_AIFSN 0x1 +#define BBP_PROC_TIME 1500 + struct mt7915_dev *dev = phy->dev; + u8 sig_ext = (mode == MT76_TM_TX_MODE_CCK) ? 0 : 6; + u8 slot_time = 9, sifs = TM_DEFAULT_SIFS; + u8 aifsn = TM_MIN_AIFSN; + u32 i2t_time, tr2t_time, txv_time; + bool ext_phy = phy != &dev->phy; + u16 cw = 0; + + if (ipg < sig_ext + slot_time + sifs) + ipg = 0; + + if (!ipg) + goto done; + + ipg -= sig_ext; + + if (ipg <= (TM_MAX_SIFS + slot_time)) { + sifs = ipg - slot_time; + } else { + u32 val = (ipg + slot_time) / slot_time; + + while (val >>= 1) + cw++; + + if (cw > 16) + cw = 16; + + ipg -= ((1 << cw) - 1) * slot_time; + + aifsn = ipg / slot_time; + if (aifsn > TM_MAX_AIFSN) + aifsn = TM_MAX_AIFSN; + + ipg -= aifsn * slot_time; + + if (ipg > TM_DEFAULT_SIFS) { + if (ipg < TM_MAX_SIFS) + sifs = ipg; + else + sifs = TM_MAX_SIFS; + } + } +done: + txv_time = mt76_get_field(dev, MT_TMAC_ATCR(ext_phy), + MT_TMAC_ATCR_TXV_TOUT); + txv_time *= 50; /* normal clock time */ + + i2t_time = (slot_time * 1000 - txv_time - BBP_PROC_TIME) / 50; + tr2t_time = (sifs * 1000 - txv_time - BBP_PROC_TIME) / 50; + + mt76_set(dev, MT_TMAC_TRCR0(ext_phy), + FIELD_PREP(MT_TMAC_TRCR0_TR2T_CHK, tr2t_time) | + FIELD_PREP(MT_TMAC_TRCR0_I2T_CHK, i2t_time)); + + mt7915_tm_set_slot_time(phy, slot_time, sifs); + + return mt7915_tm_set_wmm_qid(dev, + mt7915_lmac_mapping(dev, IEEE80211_AC_BE), + aifsn, cw, cw, 0); +} + +static int +mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time) +{ + struct mt76_phy *mphy = phy->mt76; + struct mt76_testmode_data *td = &mphy->test; + struct sk_buff *old = td->tx_skb, *new; + struct ieee80211_supported_band *sband; + struct rate_info rate = {}; + u16 flags = 0, tx_len; + u32 bitrate; + + if (!tx_time || !old) + return 0; + + rate.mcs = td->tx_rate_idx; + rate.nss = td->tx_rate_nss; + + switch (td->tx_rate_mode) { + case MT76_TM_TX_MODE_CCK: + case MT76_TM_TX_MODE_OFDM: + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + rate.legacy = sband->bitrates[rate.mcs].bitrate; + break; + case MT76_TM_TX_MODE_HT: + rate.mcs += rate.nss * 8; + flags |= RATE_INFO_FLAGS_MCS; + + if (td->tx_rate_sgi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT76_TM_TX_MODE_VHT: + flags |= RATE_INFO_FLAGS_VHT_MCS; + + if (td->tx_rate_sgi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT76_TM_TX_MODE_HE_SU: + case MT76_TM_TX_MODE_HE_EXT_SU: + case MT76_TM_TX_MODE_HE_TB: + case MT76_TM_TX_MODE_HE_MU: + rate.he_gi = td->tx_rate_sgi; + flags |= RATE_INFO_FLAGS_HE_MCS; + break; + default: + break; + } + rate.flags = flags; + + switch (mphy->chandef.width) { + case NL80211_CHAN_WIDTH_160: + case NL80211_CHAN_WIDTH_80P80: + rate.bw = RATE_INFO_BW_160; + break; + case NL80211_CHAN_WIDTH_80: + rate.bw = RATE_INFO_BW_80; + break; + case NL80211_CHAN_WIDTH_40: + rate.bw = RATE_INFO_BW_40; + break; + default: + rate.bw = RATE_INFO_BW_20; + break; + } + + bitrate = cfg80211_calculate_bitrate(&rate); + tx_len = bitrate * tx_time / 10 / 8; + + if (tx_len < sizeof(struct ieee80211_hdr)) + tx_len = sizeof(struct ieee80211_hdr); + else if (tx_len > IEEE80211_MAX_FRAME_LEN) + tx_len = IEEE80211_MAX_FRAME_LEN; + + new = alloc_skb(tx_len, GFP_KERNEL); + if (!new) + return -ENOMEM; + + skb_copy_header(new, old); + __skb_put_zero(new, tx_len); + memcpy(new->data, old->data, sizeof(struct ieee80211_hdr)); + + dev_kfree_skb(old); + td->tx_skb = new; + + return 0; +} + static void -mt7915_tm_reg_backup_restore(struct mt7915_dev *dev, struct mt7915_phy *phy) +mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) { int n_regs = ARRAY_SIZE(reg_backup_list); + struct mt7915_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; - u32 *b = dev->test.reg_backup; + u32 *b = phy->test.reg_backup; int i; - if (dev->mt76.test.state == MT76_TM_STATE_OFF) { + if (phy->mt76->test.state == MT76_TM_STATE_OFF) { for (i = 0; i < n_regs; i++) mt76_wr(dev, reg_backup_list[i].band[ext_phy], b[i]); return; @@ -151,7 +364,7 @@ mt7915_tm_reg_backup_restore(struct mt7915_dev *dev, struct mt7915_phy *phy) if (!b) return; - dev->test.reg_backup = b; + phy->test.reg_backup = b; for (i = 0; i < n_regs; i++) b[i] = mt76_rr(dev, reg_backup_list[i].band[ext_phy]); @@ -182,93 +395,260 @@ mt7915_tm_reg_backup_restore(struct mt7915_dev *dev, struct mt7915_phy *phy) } static void -mt7915_tm_init(struct mt7915_dev *dev) +mt7915_tm_init(struct mt7915_phy *phy, bool en) { - bool en = !(dev->mt76.test.state == MT76_TM_STATE_OFF); + struct mt7915_dev *dev = phy->dev; - if (!test_bit(MT76_STATE_RUNNING, &dev->phy.mt76->state)) + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; + mt7915_mcu_set_sku_en(phy, !en); + mt7915_tm_mode_ctrl(dev, en); - mt7915_tm_reg_backup_restore(dev, &dev->phy); - mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_TXRX, !en); + mt7915_tm_reg_backup_restore(phy); + mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en); + + mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en); +} + +static void +mt7915_tm_update_channel(struct mt7915_phy *phy) +{ + mutex_unlock(&phy->dev->mt76.mutex); + mt7915_set_channel(phy); + mutex_lock(&phy->dev->mt76.mutex); + + mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); } static void -mt7915_tm_set_tx_frames(struct mt7915_dev *dev, bool en) +mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) { static const u8 spe_idx_map[] = {0, 0, 1, 0, 3, 2, 4, 0, 9, 8, 6, 10, 16, 12, 18, 0}; - struct sk_buff *skb = dev->mt76.test.tx_skb; + struct mt76_testmode_data *td = &phy->mt76->test; + struct mt7915_dev *dev = phy->dev; struct ieee80211_tx_info *info; + u8 duty_cycle = td->tx_duty_cycle; + u32 tx_time = td->tx_time; + u32 ipg = td->tx_ipg; - mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_RX_RXV, false); + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); + mt7915_tm_clean_hwq(phy, dev->mt76.global_wcid.idx); if (en) { - u8 tx_ant = dev->mt76.test.tx_antenna_mask; + mt7915_tm_update_channel(phy); + + if (td->tx_spe_idx) { + phy->test.spe_idx = td->tx_spe_idx; + } else { + u8 tx_ant = td->tx_antenna_mask; - mutex_unlock(&dev->mt76.mutex); - mt7915_set_channel(&dev->phy); - mutex_lock(&dev->mt76.mutex); + if (phy != &dev->phy) + tx_ant >>= 2; + phy->test.spe_idx = spe_idx_map[tx_ant]; + } + } - mt7915_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH); - dev->test.spe_idx = spe_idx_map[tx_ant]; + /* if all three params are set, duty_cycle will be ignored */ + if (duty_cycle && tx_time && !ipg) { + ipg = tx_time * 100 / duty_cycle - tx_time; + } else if (duty_cycle && !tx_time && ipg) { + if (duty_cycle < 100) + tx_time = duty_cycle * ipg / (100 - duty_cycle); } - mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_TX, en); + mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode); + mt7915_tm_set_tx_len(phy, tx_time); - if (!en || !skb) + if (ipg) + td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2; + + if (!en || !td->tx_skb) return; - info = IEEE80211_SKB_CB(skb); - info->control.vif = dev->phy.monitor_vif; + info = IEEE80211_SKB_CB(td->tx_skb); + info->control.vif = phy->monitor_vif; + + mt7915_tm_set_trx(phy, TM_MAC_TX, en); } static void -mt7915_tm_set_rx_frames(struct mt7915_dev *dev, bool en) +mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en) { - if (en) { - mutex_unlock(&dev->mt76.mutex); - mt7915_set_channel(&dev->phy); - mutex_lock(&dev->mt76.mutex); + if (en) + mt7915_tm_update_channel(phy); - mt7915_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH); + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); +} + +static int +mt7915_tm_rf_switch_mode(struct mt7915_dev *dev, u32 oper) +{ + struct mt7915_tm_rf_test req = { + .op.op_mode = cpu_to_le32(oper), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, + sizeof(req), true); +} + +static int +mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en) +{ +#define TX_CONT_START 0x05 +#define TX_CONT_STOP 0x06 + struct mt7915_dev *dev = phy->dev; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + int freq1 = ieee80211_frequency_to_channel(chandef->center_freq1); + struct mt76_testmode_data *td = &phy->mt76->test; + u32 func_idx = en ? TX_CONT_START : TX_CONT_STOP; + u8 rate_idx = td->tx_rate_idx, mode; + u16 rateval; + struct mt7915_tm_rf_test req = { + .action = 1, + .icap_len = 120, + .op.rf.func_idx = cpu_to_le32(func_idx), + }; + struct tm_tx_cont *tx_cont = &req.op.rf.param.tx_cont; + + tx_cont->control_ch = chandef->chan->hw_value; + tx_cont->center_ch = freq1; + tx_cont->tx_ant = td->tx_antenna_mask; + tx_cont->band = phy != &dev->phy; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + tx_cont->bw = CMD_CBW_40MHZ; + break; + case NL80211_CHAN_WIDTH_80: + tx_cont->bw = CMD_CBW_80MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + tx_cont->bw = CMD_CBW_8080MHZ; + break; + case NL80211_CHAN_WIDTH_160: + tx_cont->bw = CMD_CBW_160MHZ; + break; + case NL80211_CHAN_WIDTH_5: + tx_cont->bw = CMD_CBW_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + tx_cont->bw = CMD_CBW_10MHZ; + break; + case NL80211_CHAN_WIDTH_20: + tx_cont->bw = CMD_CBW_20MHZ; + break; + case NL80211_CHAN_WIDTH_20_NOHT: + tx_cont->bw = CMD_CBW_20MHZ; + break; + default: + break; + } + + if (!en) { + req.op.rf.param.func_data = cpu_to_le32(phy != &dev->phy); + goto out; } - mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_RX_RXV, en); + if (td->tx_rate_mode <= MT76_TM_TX_MODE_OFDM) { + struct ieee80211_supported_band *sband; + u8 idx = rate_idx; + + if (chandef->chan->band == NL80211_BAND_5GHZ) + sband = &phy->mt76->sband_5g.sband; + else + sband = &phy->mt76->sband_2g.sband; + + if (td->tx_rate_mode == MT76_TM_TX_MODE_OFDM) + idx += 4; + rate_idx = sband->bitrates[idx].hw_value & 0xff; + } + + switch (td->tx_rate_mode) { + case MT76_TM_TX_MODE_CCK: + mode = MT_PHY_TYPE_CCK; + break; + case MT76_TM_TX_MODE_OFDM: + mode = MT_PHY_TYPE_OFDM; + break; + case MT76_TM_TX_MODE_HT: + mode = MT_PHY_TYPE_HT; + break; + case MT76_TM_TX_MODE_VHT: + mode = MT_PHY_TYPE_VHT; + break; + case MT76_TM_TX_MODE_HE_SU: + mode = MT_PHY_TYPE_HE_SU; + break; + case MT76_TM_TX_MODE_HE_EXT_SU: + mode = MT_PHY_TYPE_HE_EXT_SU; + break; + case MT76_TM_TX_MODE_HE_TB: + mode = MT_PHY_TYPE_HE_TB; + break; + case MT76_TM_TX_MODE_HE_MU: + mode = MT_PHY_TYPE_HE_MU; + break; + default: + break; + } + + rateval = mode << 6 | rate_idx; + tx_cont->rateval = cpu_to_le16(rateval); + +out: + if (!en) { + int ret; + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, + sizeof(req), true); + if (ret) + return ret; + + return mt7915_tm_rf_switch_mode(dev, RF_OPER_NORMAL); + } + + mt7915_tm_rf_switch_mode(dev, RF_OPER_RF_TEST); + mt7915_tm_update_channel(phy); + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, + sizeof(req), true); } static void -mt7915_tm_update_params(struct mt7915_dev *dev, u32 changed) +mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed) { - struct mt76_testmode_data *td = &dev->mt76.test; - bool en = dev->mt76.test.state != MT76_TM_STATE_OFF; + struct mt76_testmode_data *td = &phy->mt76->test; + bool en = phy->mt76->test.state != MT76_TM_STATE_OFF; if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) - mt7915_tm_set_freq_offset(dev, en, en ? td->freq_offset : 0); + mt7915_tm_set_freq_offset(phy, en, en ? td->freq_offset : 0); if (changed & BIT(TM_CHANGED_TXPOWER)) - mt7915_tm_set_tx_power(&dev->phy); + mt7915_tm_set_tx_power(phy); } static int -mt7915_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state) +mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state) { - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - struct mt76_testmode_data *td = &mdev->test; + struct mt76_testmode_data *td = &mphy->test; + struct mt7915_phy *phy = mphy->priv; enum mt76_testmode_state prev_state = td->state; - mdev->test.state = state; - - if (prev_state == MT76_TM_STATE_TX_FRAMES) - mt7915_tm_set_tx_frames(dev, false); - else if (state == MT76_TM_STATE_TX_FRAMES) - mt7915_tm_set_tx_frames(dev, true); - else if (prev_state == MT76_TM_STATE_RX_FRAMES) - mt7915_tm_set_rx_frames(dev, false); - else if (state == MT76_TM_STATE_RX_FRAMES) - mt7915_tm_set_rx_frames(dev, true); - else if (prev_state == MT76_TM_STATE_OFF || state == MT76_TM_STATE_OFF) - mt7915_tm_init(dev); + mphy->test.state = state; + + if (prev_state == MT76_TM_STATE_TX_FRAMES || + state == MT76_TM_STATE_TX_FRAMES) + mt7915_tm_set_tx_frames(phy, state == MT76_TM_STATE_TX_FRAMES); + else if (prev_state == MT76_TM_STATE_RX_FRAMES || + state == MT76_TM_STATE_RX_FRAMES) + mt7915_tm_set_rx_frames(phy, state == MT76_TM_STATE_RX_FRAMES); + else if (prev_state == MT76_TM_STATE_TX_CONT || + state == MT76_TM_STATE_TX_CONT) + mt7915_tm_set_tx_cont(phy, state == MT76_TM_STATE_TX_CONT); + else if (prev_state == MT76_TM_STATE_OFF || + state == MT76_TM_STATE_OFF) + mt7915_tm_init(phy, !(state == MT76_TM_STATE_OFF)); if ((state == MT76_TM_STATE_IDLE && prev_state == MT76_TM_STATE_OFF) || @@ -284,18 +664,18 @@ mt7915_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state) changed |= BIT(i); } - mt7915_tm_update_params(dev, changed); + mt7915_tm_update_params(phy, changed); } return 0; } static int -mt7915_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, +mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, enum mt76_testmode_state new_state) { - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - struct mt76_testmode_data *td = &dev->mt76.test; + struct mt76_testmode_data *td = &mphy->test; + struct mt7915_phy *phy = mphy->priv; u32 changed = 0; int i; @@ -305,7 +685,7 @@ mt7915_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, td->state == MT76_TM_STATE_OFF) return 0; - if (td->tx_antenna_mask & ~dev->phy.chainmask) + if (td->tx_antenna_mask & ~mphy->chainmask) return -EINVAL; for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { @@ -313,15 +693,15 @@ mt7915_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, changed |= BIT(i); } - mt7915_tm_update_params(dev, changed); + mt7915_tm_update_params(phy, changed); return 0; } static int -mt7915_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) +mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) { - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt7915_phy *phy = mphy->priv; void *rx, *rssi; int i; @@ -329,15 +709,15 @@ mt7915_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) if (!rx) return -ENOMEM; - if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset)) + if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset)) return -ENOMEM; rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI); if (!rssi) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dev->test.last_rcpi); i++) - if (nla_put_u8(msg, i, dev->test.last_rcpi[i])) + for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) + if (nla_put_u8(msg, i, phy->test.last_rcpi[i])) return -ENOMEM; nla_nest_end(msg, rssi); @@ -346,8 +726,8 @@ mt7915_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) if (!rssi) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dev->test.last_ib_rssi); i++) - if (nla_put_s8(msg, i, dev->test.last_ib_rssi[i])) + for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++) + if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); @@ -356,13 +736,13 @@ mt7915_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) if (!rssi) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dev->test.last_wb_rssi); i++) - if (nla_put_s8(msg, i, dev->test.last_wb_rssi[i])) + for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++) + if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); - if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, dev->test.last_snr)) + if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, phy->test.last_snr)) return -ENOMEM; nla_nest_end(msg, rx); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h index 964f2d7fde3a..8f8533ef9859 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h @@ -16,6 +16,23 @@ struct mt7915_tm_freq_offset { __le32 freq_offset; }; +struct mt7915_tm_slot_time { + u8 slot_time; + u8 sifs; + u8 rifs; + u8 _rsv; + __le16 eifs; + u8 band; + u8 _rsv1[5]; +}; + +struct mt7915_tm_clean_txq { + bool sta_pause; + u8 wcid; /* 256 sta */ + u8 band; + u8 rsv; +}; + struct mt7915_tm_cmd { u8 testmode_en; u8 param_idx; @@ -24,6 +41,8 @@ struct mt7915_tm_cmd { __le32 data; struct mt7915_tm_trx trx; struct mt7915_tm_freq_offset freq; + struct mt7915_tm_slot_time slot; + struct mt7915_tm_clean_txq clean; u8 test[72]; } param; } __packed; @@ -37,4 +56,44 @@ enum { TM_MAC_RX_RXV, }; +struct tm_tx_cont { + u8 control_ch; + u8 center_ch; + u8 bw; + u8 tx_ant; + __le16 rateval; + u8 band; + u8 txfd_mode; +}; + +struct mt7915_tm_rf_test { + u8 action; + u8 icap_len; + u8 _rsv[2]; + union { + __le32 op_mode; + __le32 freq; + + struct { + __le32 func_idx; + union { + __le32 func_data; + __le32 cal_dump; + + struct tm_tx_cont tx_cont; + + u8 _pad[80]; + } param; + } rf; + } op; +} __packed; + +enum { + RF_OPER_NORMAL, + RF_OPER_RF_TEST, + RF_OPER_ICAP, + RF_OPER_ICAP_OVERLAP, + RF_OPER_WIFI_SPECTRUM, +}; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig new file mode 100644 index 000000000000..001f2b9cec26 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: ISC +config MT7921E + tristate "MediaTek MT7921E (PCIe) support" + select MT76_CONNAC_LIB + select WANT_DEV_COREDUMP + depends on MAC80211 + depends on PCI + help + This adds support for MT7921E 802.11ax 2x2:2SS wireless devices. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile new file mode 100644 index 000000000000..09d1446ad933 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -0,0 +1,5 @@ +#SPDX-License-Identifier: ISC + +obj-$(CONFIG_MT7921E) += mt7921e.o + +mt7921e-y := pci.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c new file mode 100644 index 000000000000..0dc8e25e18e4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7921.h" +#include "eeprom.h" + +static int +mt7921_fw_debug_set(void *data, u64 val) +{ + struct mt7921_dev *dev = data; + + dev->fw_debug = (u8)val; + + mt7921_mcu_fw_log_2_host(dev, dev->fw_debug); + + return 0; +} + +static int +mt7921_fw_debug_get(void *data, u64 *val) +{ + struct mt7921_dev *dev = data; + + *val = dev->fw_debug; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7921_fw_debug_get, + mt7921_fw_debug_set, "%lld\n"); + +static void +mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy, + struct seq_file *file) +{ + struct mt7921_dev *dev = file->private; + int bound[15], range[4], i; + + if (!phy) + return; + + /* Tx ampdu stat */ + for (i = 0; i < ARRAY_SIZE(range); i++) + range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i)); + + for (i = 0; i < ARRAY_SIZE(bound); i++) + bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1; + + seq_printf(file, "\nPhy0\n"); + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i] + 1, bound[i + 1]); + + seq_puts(file, "\nCount: "); + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); + seq_puts(file, "\n"); + + seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); +} + +static int +mt7921_tx_stats_read(struct seq_file *file, void *data) +{ + struct mt7921_dev *dev = file->private; + int stat[8], i, n; + + mt7921_ampdu_stat_read_phy(&dev->phy, file); + + /* Tx amsdu info */ + seq_puts(file, "Tx MSDU stat:\n"); + for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { + stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + n += stat[i]; + } + + for (i = 0; i < ARRAY_SIZE(stat); i++) { + seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ", + i + 1, stat[i]); + if (n != 0) + seq_printf(file, "(%d%%)\n", stat[i] * 100 / n); + else + seq_puts(file, "\n"); + } + + return 0; +} + +static int +mt7921_tx_stats_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7921_tx_stats_read, inode->i_private); +} + +static const struct file_operations fops_tx_stats = { + .open = mt7921_tx_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int +mt7921_queues_acq(struct seq_file *s, void *data) +{ + struct mt7921_dev *dev = dev_get_drvdata(s->private); + int i; + + for (i = 0; i < 16; i++) { + int j, acs = i / 4, index = i % 4; + u32 ctrl, val, qlen = 0; + + val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); + ctrl = BIT(31) | BIT(15) | (acs << 8); + + for (j = 0; j < 32; j++) { + if (val & BIT(j)) + continue; + + mt76_wr(dev, MT_PLE_FL_Q0_CTRL, + ctrl | (j + (index << 5))); + qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, + GENMASK(11, 0)); + } + seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); + } + + return 0; +} + +static int +mt7921_queues_read(struct seq_file *s, void *data) +{ + struct mt7921_dev *dev = dev_get_drvdata(s->private); + struct { + struct mt76_queue *q; + char *queue; + } queue_map[] = { + { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" }, + { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" }, + { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) { + struct mt76_queue *q = queue_map[i].q; + + if (!q) + continue; + + seq_printf(s, + "%s: queued=%d head=%d tail=%d\n", + queue_map[i].queue, q->queued, q->head, + q->tail); + } + + return 0; +} + +static int +mt7921_pm_set(void *data, u64 val) +{ + struct mt7921_dev *dev = data; + struct mt76_phy *mphy = dev->phy.mt76; + int ret = 0; + + mt7921_mutex_acquire(dev); + + dev->pm.enable = val; + + ieee80211_iterate_active_interfaces(mphy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_pm_interface_iter, mphy->priv); + mt7921_mutex_release(dev); + + return ret; +} + +static int +mt7921_pm_get(void *data, u64 *val) +{ + struct mt7921_dev *dev = data; + + *val = dev->pm.enable; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n"); + +static int +mt7921_pm_idle_timeout_set(void *data, u64 val) +{ + struct mt7921_dev *dev = data; + + dev->pm.idle_timeout = msecs_to_jiffies(val); + + return 0; +} + +static int +mt7921_pm_idle_timeout_get(void *data, u64 *val) +{ + struct mt7921_dev *dev = data; + + *val = jiffies_to_msecs(dev->pm.idle_timeout); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get, + mt7921_pm_idle_timeout_set, "%lld\n"); + +static int mt7921_config(void *data, u64 val) +{ + struct mt7921_dev *dev = data; + int ret; + + mt7921_mutex_acquire(dev); + ret = mt76_connac_mcu_chip_config(&dev->mt76); + mt7921_mutex_release(dev); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_config, NULL, mt7921_config, "%lld\n"); + +int mt7921_init_debugfs(struct mt7921_dev *dev) +{ + struct dentry *dir; + + dir = mt76_register_debugfs(&dev->mt76); + if (!dir) + return -ENOMEM; + + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt7921_queues_read); + debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, + mt7921_queues_acq); + debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats); + debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); + debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm); + debugfs_create_file("idle-timeout", 0600, dir, dev, + &fops_pm_idle_timeout); + debugfs_create_file("chip_config", 0600, dir, dev, &fops_config); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c new file mode 100644 index 000000000000..cd9665610284 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7921.h" +#include "../dma.h" +#include "mac.h" + +int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc) +{ + int i, err; + + err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, MT_TX_RING_BASE); + if (err < 0) + return err; + + for (i = 0; i <= MT_TXQ_PSD; i++) + phy->mt76->q_tx[i] = phy->mt76->q_tx[0]; + + return 0; +} + +void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + enum rx_pkt_type type; + u16 flag; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0])); + + if (type == PKT_TYPE_RX_EVENT && flag == 0x1) + type = PKT_TYPE_NORMAL_MCU; + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + mt7921_mac_tx_free(dev, skb); + break; + case PKT_TYPE_RX_EVENT: + mt7921_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_NORMAL_MCU: + case PKT_TYPE_NORMAL: + if (!mt7921_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + fallthrough; + default: + dev_kfree_skb(skb); + break; + } +} + +static void +mt7921_tx_cleanup(struct mt7921_dev *dev) +{ + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false); +} + +static int mt7921_poll_tx(struct napi_struct *napi, int budget) +{ + struct mt7921_dev *dev; + + dev = container_of(napi, struct mt7921_dev, mt76.tx_napi); + + mt7921_tx_cleanup(dev); + + if (napi_complete_done(napi, 0)) + mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL); + + return 0; +} + +void mt7921_dma_prefetch(struct mt7921_dev *dev) +{ +#define PREFETCH(base, depth) ((base) << 16 | (depth)) + + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x40, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x80, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING4_EXT_CTRL, PREFETCH(0xc0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING5_EXT_CTRL, PREFETCH(0x100, 0x4)); + + mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x140, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x180, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x1c0, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x200, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x240, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x280, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING6_EXT_CTRL, PREFETCH(0x2c0, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x340, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING17_EXT_CTRL, PREFETCH(0x380, 0x4)); +} + +static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr) +{ + static const struct { + u32 phys; + u32 mapped; + u32 size; + } fixed_map[] = { + { 0x00400000, 0x80000, 0x10000}, /* WF_MCU_SYSRAM */ + { 0x00410000, 0x90000, 0x10000}, /* WF_MCU_SYSRAM (configure register) */ + { 0x40000000, 0x70000, 0x10000}, /* WF_UMAC_SYSRAM */ + { 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */ + { 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */ + { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ + { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */ + { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ + { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ + { 0x7c060000, 0xe0000, 0x10000}, /* CONN_INFRA, conn_host_csr_top */ + { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ + { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ + { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */ + { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */ + { 0x820cc000, 0x0e000, 0x2000 }, /* WF_UMAC_TOP (PP) */ + { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */ + { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */ + { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ + { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ + { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ + { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ + { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ + { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ + { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ + { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ + { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ + { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ + { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ + { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ + { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ + { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ + { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ + { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ + { 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ + { 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ + { 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ + { 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ + { 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ + { 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ + { 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ + { 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ + { 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ + }; + int i; + + if (addr < 0x100000) + return addr; + + for (i = 0; i < ARRAY_SIZE(fixed_map); i++) { + u32 ofs; + + if (addr < fixed_map[i].phys) + continue; + + ofs = addr - fixed_map[i].phys; + if (ofs > fixed_map[i].size) + continue; + + return fixed_map[i].mapped + ofs; + } + + if ((addr >= 0x18000000 && addr < 0x18c00000) || + (addr >= 0x70000000 && addr < 0x78000000) || + (addr >= 0x7c000000 && addr < 0x7c400000)) + return mt7921_reg_map_l1(dev, addr); + + dev_err(dev->mt76.dev, "Access currently unsupported address %08x\n", + addr); + + return 0; +} + +static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + u32 addr = __mt7921_reg_addr(dev, offset); + + return dev->bus_ops->rr(mdev, addr); +} + +static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + u32 addr = __mt7921_reg_addr(dev, offset); + + dev->bus_ops->wr(mdev, addr, val); +} + +static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + u32 addr = __mt7921_reg_addr(dev, offset); + + return dev->bus_ops->rmw(mdev, addr, mask, val); +} + +static int mt7921_dmashdl_disabled(struct mt7921_dev *dev) +{ + mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0, MT_WFDMA0_CSR_TX_DMASHDL_ENABLE); + mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS); + + return 0; +} + +int mt7921_dma_init(struct mt7921_dev *dev) +{ + /* Increase buffer size to receive large VHT/HE MPDUs */ + struct mt76_bus_ops *bus_ops; + int rx_buf_size = MT_RX_BUF_SIZE * 2; + int ret; + + dev->bus_ops = dev->mt76.bus; + bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), + GFP_KERNEL); + if (!bus_ops) + return -ENOMEM; + + bus_ops->rr = mt7921_rr; + bus_ops->wr = mt7921_wr; + bus_ops->rmw = mt7921_rmw; + dev->mt76.bus = bus_ops; + + mt76_dma_attach(&dev->mt76); + + /* reset */ + mt76_clear(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + mt76_set(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + ret = mt7921_dmashdl_disabled(dev); + if (ret) + return ret; + + /* disable WFDMA0 */ + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN | + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + + mt76_poll(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | + MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000); + + /* init tx queue */ + ret = mt7921_init_tx_queues(&dev->phy, MT7921_TXQ_BAND0, + MT7921_TX_RING_SIZE); + if (ret) + return ret; + + mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); + + /* command to WM */ + ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM, + MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE); + if (ret) + return ret; + + /* firmware download */ + ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7921_TXQ_FWDL, + MT7921_TX_FWDL_RING_SIZE, MT_TX_RING_BASE); + if (ret) + return ret; + + /* event from WM before firmware download */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], + MT7921_RXQ_MCU_WM, + MT7921_RX_MCU_RING_SIZE, + rx_buf_size, MT_RX_EVENT_RING_BASE); + if (ret) + return ret; + + /* Change mcu queue after firmware download */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], + MT7921_RXQ_MCU_WM, + MT7921_RX_MCU_RING_SIZE, + rx_buf_size, MT_WFDMA0(0x540)); + if (ret) + return ret; + + /* rx data */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], + MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE, + rx_buf_size, MT_RX_DATA_RING_BASE); + if (ret) + return ret; + + ret = mt76_init_queues(dev); + if (ret < 0) + return ret; + + netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi, + mt7921_poll_tx, NAPI_POLL_WEIGHT); + napi_enable(&dev->mt76.tx_napi); + + /* configure perfetch settings */ + mt7921_dma_prefetch(dev); + + /* reset dma idx */ + mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); + + /* configure delay interrupt */ + mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); + + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_WB_DDONE | + MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | + MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + + mt76_set(dev, 0x54000120, BIT(1)); + + /* enable interrupts for TX/RX rings */ + mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_MCU_CMD); + + return 0; +} + +void mt7921_dma_cleanup(struct mt7921_dev *dev) +{ + /* disable */ + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN | + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + + /* reset */ + mt76_clear(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + mt76_set(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + mt76_dma_cleanup(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c new file mode 100644 index 000000000000..691d14a1a7bf --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7921.h" +#include "eeprom.h" + +static u32 mt7921_eeprom_read(struct mt7921_dev *dev, u32 offset) +{ + u8 *data = dev->mt76.eeprom.data; + + if (data[offset] == 0xff) + mt7921_mcu_get_eeprom(dev, offset); + + return data[offset]; +} + +static int mt7921_eeprom_load(struct mt7921_dev *dev) +{ + int ret; + + ret = mt76_eeprom_init(&dev->mt76, MT7921_EEPROM_SIZE); + if (ret < 0) + return ret; + + memset(dev->mt76.eeprom.data, -1, MT7921_EEPROM_SIZE); + + return 0; +} + +static int mt7921_check_eeprom(struct mt7921_dev *dev) +{ + u8 *eeprom = dev->mt76.eeprom.data; + u16 val; + + mt7921_eeprom_read(dev, MT_EE_CHIP_ID); + val = get_unaligned_le16(eeprom); + + switch (val) { + case 0x7961: + return 0; + default: + return -EINVAL; + } +} + +void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy) +{ + struct mt7921_dev *dev = phy->dev; + u32 val; + + val = mt7921_eeprom_read(dev, MT_EE_WIFI_CONF); + val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val); + + switch (val) { + case MT_EE_5GHZ: + phy->mt76->cap.has_5ghz = true; + break; + case MT_EE_2GHZ: + phy->mt76->cap.has_2ghz = true; + break; + default: + phy->mt76->cap.has_2ghz = true; + phy->mt76->cap.has_5ghz = true; + break; + } +} + +static void mt7921_eeprom_parse_hw_cap(struct mt7921_dev *dev) +{ + u8 tx_mask; + + mt7921_eeprom_parse_band_config(&dev->phy); + + /* TODO: read NSS with MCU_CMD_NIC_CAPV2 */ + tx_mask = 2; + dev->chainmask = BIT(tx_mask) - 1; + dev->mphy.antenna_mask = dev->chainmask; + dev->mphy.chainmask = dev->mphy.antenna_mask; +} + +int mt7921_eeprom_init(struct mt7921_dev *dev) +{ + int ret; + + ret = mt7921_eeprom_load(dev); + if (ret < 0) + return ret; + + ret = mt7921_check_eeprom(dev); + if (ret) + return ret; + + mt7921_eeprom_parse_hw_cap(dev); + memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, + ETH_ALEN); + + mt76_eeprom_override(&dev->mphy); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.h new file mode 100644 index 000000000000..54f30401343c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7921_EEPROM_H +#define __MT7921_EEPROM_H + +#include "mt7921.h" + +enum mt7921_eeprom_field { + MT_EE_CHIP_ID = 0x000, + MT_EE_VERSION = 0x002, + MT_EE_MAC_ADDR = 0x004, + MT_EE_WIFI_CONF = 0x07c, + __MT_EE_MAX = 0x3bf +}; + +#define MT_EE_WIFI_CONF_TX_MASK BIT(0) +#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(3, 2) + +enum mt7921_eeprom_band { + MT_EE_NA, + MT_EE_5GHZ, + MT_EE_2GHZ, + MT_EE_DUAL_BAND, +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c new file mode 100644 index 000000000000..89a13b4a74a4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include <linux/etherdevice.h> +#include "mt7921.h" +#include "mac.h" +#include "mcu.h" +#include "eeprom.h" + +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ +} + +static struct ieee80211_rate mt7921_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(11, 60), + OFDM_RATE(15, 90), + OFDM_RATE(10, 120), + OFDM_RATE(14, 180), + OFDM_RATE(9, 240), + OFDM_RATE(13, 360), + OFDM_RATE(8, 480), + OFDM_RATE(12, 540), +}; + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max = MT7921_MAX_INTERFACES, + .types = BIT(NL80211_IFTYPE_STATION) + } +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = MT7921_MAX_INTERFACES, + .num_different_channels = 1, + .beacon_int_infra_match = true, + } +}; + +static void +mt7921_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt7921_dev *dev = mt7921_hw_dev(hw); + + memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); + dev->mt76.region = request->dfs_region; + + mt7921_mutex_acquire(dev); + mt76_connac_mcu_set_channel_domain(hw->priv); + mt7921_mutex_release(dev); +} + +static void +mt7921_init_wiphy(struct ieee80211_hw *hw) +{ + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct wiphy *wiphy = hw->wiphy; + + hw->queues = 4; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + + phy->slottime = 9; + + hw->sta_data_size = sizeof(struct mt7921_sta); + hw->vif_data_size = sizeof(struct mt7921_vif); + + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; + wiphy->max_scan_ssids = 4; + wiphy->max_sched_scan_plan_interval = + MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL; + wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; + wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; + wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; + wiphy->max_sched_scan_reqs = 1; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy->reg_notifier = mt7921_regd_notifier; + + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); + + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); + ieee80211_hw_set(hw, WANT_MONITOR_VIF); + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + + hw->max_tx_fragments = 4; +} + +static void +mt7921_mac_init_band(struct mt7921_dev *dev, u8 band) +{ + u32 mask, set; + + mt76_rmw_field(dev, MT_TMAC_CTCR0(band), + MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); + mt76_set(dev, MT_TMAC_CTCR0(band), + MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | + MT_TMAC_CTCR0_INS_DDLMT_EN); + + mask = MT_MDP_RCFR0_MCU_RX_MGMT | + MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | + MT_MDP_RCFR0_MCU_RX_CTL_BAR; + set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF); + mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set); + + mask = MT_MDP_RCFR1_MCU_RX_BYPASS | + MT_MDP_RCFR1_RX_DROPPED_UCAST | + MT_MDP_RCFR1_RX_DROPPED_MCAST; + set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); + mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); + + mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536); + /* disable rx rate report by default due to hw issues */ + mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); +} + +static void mt7921_mac_init(struct mt7921_dev *dev) +{ + int i; + + mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); + /* disable hardware de-agg */ + mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); + mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); + + for (i = 0; i < MT7921_WTBL_SIZE; i++) + mt7921_mac_wtbl_update(dev, i, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + for (i = 0; i < 2; i++) + mt7921_mac_init_band(dev, i); + + mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); +} + +static void mt7921_init_work(struct work_struct *work) +{ + struct mt7921_dev *dev = container_of(work, struct mt7921_dev, + init_work); + + mt7921_mcu_set_eeprom(dev); + mt7921_mac_init(dev); +} + +static int mt7921_init_hardware(struct mt7921_dev *dev) +{ + int ret, idx; + + INIT_WORK(&dev->init_work, mt7921_init_work); + spin_lock_init(&dev->token_lock); + idr_init(&dev->token); + + ret = mt7921_dma_init(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + /* force firmware operation mode into normal state, + * which should be set before firmware download stage. + */ + mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE); + + ret = mt7921_mcu_init(dev); + if (ret) + return ret; + + ret = mt7921_eeprom_init(dev); + if (ret < 0) + return ret; + + /* Beacon and mgmt frames should occupy wcid 0 */ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1); + if (idx) + return -ENOSPC; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx = -1; + dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; + rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); + + return 0; +} + +int mt7921_register_device(struct mt7921_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + int ret; + + dev->phy.dev = dev; + dev->phy.mt76 = &dev->mt76.phy; + dev->mt76.phy.priv = &dev->phy; + + INIT_DELAYED_WORK(&dev->pm.ps_work, mt7921_pm_power_save_work); + INIT_WORK(&dev->pm.wake_work, mt7921_pm_wake_work); + init_completion(&dev->pm.wake_cmpl); + spin_lock_init(&dev->pm.txq_lock); + set_bit(MT76_STATE_PM, &dev->mphy.state); + INIT_LIST_HEAD(&dev->phy.stats_list); + INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work); + INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work); + INIT_DELAYED_WORK(&dev->coredump.work, mt7921_coredump_work); + skb_queue_head_init(&dev->phy.scan_event_list); + skb_queue_head_init(&dev->coredump.msg_list); + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); + + init_waitqueue_head(&dev->reset_wait); + INIT_WORK(&dev->reset_work, mt7921_mac_reset_work); + + ret = mt7921_init_hardware(dev); + if (ret) + return ret; + + mt7921_init_wiphy(hw); + dev->pm.idle_timeout = MT7921_PM_TIMEOUT; + dev->mphy.sband_2g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_5g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + dev->mphy.sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; + + mt76_set_stream_caps(&dev->mphy, true); + mt7921_set_stream_he_caps(&dev->phy); + + ret = mt76_register_device(&dev->mt76, true, mt7921_rates, + ARRAY_SIZE(mt7921_rates)); + if (ret) + return ret; + + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + + return mt7921_init_debugfs(dev); +} + +void mt7921_unregister_device(struct mt7921_dev *dev) +{ + mt76_unregister_device(&dev->mt76); + mt7921_mcu_exit(dev); + mt7921_dma_cleanup(dev); + + mt7921_tx_token_put(dev); + + tasklet_disable(&dev->irq_tasklet); + mt76_free_device(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c new file mode 100644 index 000000000000..3f9097481a5e --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -0,0 +1,1516 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include <linux/devcoredump.h> +#include <linux/etherdevice.h> +#include <linux/timekeeping.h> +#include "mt7921.h" +#include "../dma.h" +#include "mac.h" +#include "mcu.h" + +#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) + +#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) +#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ + IEEE80211_RADIOTAP_HE_##f) + +static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev, + u16 idx, bool unicast) +{ + struct mt7921_sta *sta; + struct mt76_wcid *wcid; + + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + return NULL; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (unicast || !wcid) + return wcid; + + if (!wcid->sta) + return NULL; + + sta = container_of(wcid, struct mt7921_sta, wcid); + if (!sta->vif) + return NULL; + + return &sta->vif->sta.wcid; +} + +void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) +{ +} + +bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask) +{ + mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); + + return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, + 0, 5000); +} + +static u32 mt7921_mac_wtbl_lmac_addr(struct mt7921_dev *dev, u16 wcid) +{ + mt76_wr(dev, MT_WTBLON_TOP_WDUCR, + FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); + + return MT_WTBL_LMAC_OFFS(wcid, 0); +} + +static void mt7921_mac_sta_poll(struct mt7921_dev *dev) +{ + static const u8 ac_to_tid[] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + struct ieee80211_sta *sta; + struct mt7921_sta *msta; + u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; + LIST_HEAD(sta_poll_list); + int i; + + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&dev->sta_poll_list, &sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + rcu_read_lock(); + + while (true) { + bool clear = false; + u32 addr; + u16 idx; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + msta = list_first_entry(&sta_poll_list, + struct mt7921_sta, poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + idx = msta->wcid.idx; + addr = mt7921_mac_wtbl_lmac_addr(dev, idx) + 20 * 4; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + u32 tx_last = msta->airtime_ac[i]; + u32 rx_last = msta->airtime_ac[i + 4]; + + msta->airtime_ac[i] = mt76_rr(dev, addr); + msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); + + tx_time[i] = msta->airtime_ac[i] - tx_last; + rx_time[i] = msta->airtime_ac[i + 4] - rx_last; + + if ((tx_last | rx_last) & BIT(30)) + clear = true; + + addr += 8; + } + + if (clear) { + mt7921_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + u8 q = mt7921_lmac_mapping(dev, i); + u32 tx_cur = tx_time[q]; + u32 rx_cur = rx_time[q]; + u8 tid = ac_to_tid[i]; + + if (!tx_cur && !rx_cur) + continue; + + ieee80211_sta_register_airtime(sta, tid, tx_cur, + rx_cur); + } + } + + rcu_read_unlock(); +} + +static void +mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, + struct ieee80211_radiotap_he *he, + __le32 *rxv) +{ + u32 ru_h, ru_l; + u8 ru, offs = 0; + + ru_l = FIELD_GET(MT_PRXV_HE_RU_ALLOC_L, le32_to_cpu(rxv[0])); + ru_h = FIELD_GET(MT_PRXV_HE_RU_ALLOC_H, le32_to_cpu(rxv[1])); + ru = (u8)(ru_l | ru_h << 4); + + status->bw = RATE_INFO_BW_HE_RU; + + switch (ru) { + case 0 ... 36: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; + offs = ru; + break; + case 37 ... 52: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; + offs = ru - 37; + break; + case 53 ... 60: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + offs = ru - 53; + break; + case 61 ... 64: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; + offs = ru - 61; + break; + case 65 ... 66: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; + offs = ru - 65; + break; + case 67: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 68: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; + break; + } + + he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); + he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | + le16_encode_bits(offs, + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); +} + +static void +mt7921_mac_decode_he_radiotap(struct sk_buff *skb, + struct mt76_rx_status *status, + __le32 *rxv, u32 phy) +{ + /* TODO: struct ieee80211_radiotap_he_mu */ + static const struct ieee80211_radiotap_he known = { + .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | + HE_BITS(DATA1_DATA_DCM_KNOWN) | + HE_BITS(DATA1_STBC_KNOWN) | + HE_BITS(DATA1_CODING_KNOWN) | + HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | + HE_BITS(DATA1_DOPPLER_KNOWN) | + HE_BITS(DATA1_BSS_COLOR_KNOWN), + .data2 = HE_BITS(DATA2_GI_KNOWN) | + HE_BITS(DATA2_TXBF_KNOWN) | + HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | + HE_BITS(DATA2_TXOP_KNOWN), + }; + struct ieee80211_radiotap_he *he = NULL; + u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; + + he = skb_push(skb, sizeof(known)); + memcpy(he, &known, sizeof(known)); + + he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | + HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); + he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | + le16_encode_bits(ltf_size, + IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | + HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); + + switch (phy) { + case MT_PHY_TYPE_HE_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | + HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); + break; + case MT_PHY_TYPE_HE_EXT_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + break; + case MT_PHY_TYPE_HE_MU: + he->data1 |= HE_BITS(DATA1_FORMAT_MU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); + + mt7921_mac_decode_he_radiotap_ru(status, he, rxv); + break; + case MT_PHY_TYPE_HE_TB: + he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE4_KNOWN); + + he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); + + mt7921_mac_decode_he_radiotap_ru(status, he, rxv); + break; + default: + break; + } +} + +static void +mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy, + struct mt76_rx_status *status, u8 chfreq) +{ + if (!test_bit(MT76_HW_SCANNING, &mphy->state) && + !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) && + !test_bit(MT76_STATE_ROC, &mphy->state)) { + status->freq = mphy->chandef.chan->center_freq; + status->band = mphy->chandef.chan->band; + return; + } + + status->band = chfreq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + status->freq = ieee80211_channel_to_frequency(chfreq, status->band); +} + +int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7921_phy *phy = &dev->phy; + struct ieee80211_supported_band *sband; + struct ieee80211_hdr *hdr; + __le32 *rxd = (__le32 *)skb->data; + __le32 *rxv = NULL; + u32 mode = 0; + u32 rxd1 = le32_to_cpu(rxd[1]); + u32 rxd2 = le32_to_cpu(rxd[2]); + u32 rxd3 = le32_to_cpu(rxd[3]); + bool unicast, insert_ccmp_hdr = false; + u8 remove_pad; + int i, idx; + u8 chfreq; + + memset(status, 0, sizeof(*status)); + + if (rxd1 & MT_RXD1_NORMAL_BAND_IDX) + return -EINVAL; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) + return -EINVAL; + + chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3); + unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; + idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); + status->wcid = mt7921_rx_get_wcid(dev, idx, unicast); + + if (status->wcid) { + struct mt7921_sta *msta; + + msta = container_of(status->wcid, struct mt7921_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + + mt7921_get_status_freq_info(dev, mphy, status, chfreq); + + if (status->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + if (!sband->channels) + return -EINVAL; + + if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) + status->flag |= RX_FLAG_MMIC_ERROR; + + if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 && + !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED; + status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; + } + + if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (phy->rx_ampdu_ts != rxd[14]) { + if (!++phy->ampdu_ref) + phy->ampdu_ref++; + } + phy->rx_ampdu_ts = rxd[14]; + + status->ampdu_ref = phy->ampdu_ref; + } + + remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); + + if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) + return -EINVAL; + + rxd += 6; + if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { + u8 *data = (u8 *)rxd; + + if (status->flag & RX_FLAG_DECRYPTED) { + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + + insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + } + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { + rxd += 2; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + /* RXD Group 3 - P-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { + u32 v0, v1, v2; + + rxv = rxd; + rxd += 2; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + + v0 = le32_to_cpu(rxv[0]); + v1 = le32_to_cpu(rxv[1]); + v2 = le32_to_cpu(rxv[2]); + + if (v0 & MT_PRXV_HT_AD_CODE) + status->enc_flags |= RX_ENC_FLAG_LDPC; + + status->chains = mphy->antenna_mask; + status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1); + status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); + status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); + status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); + status->signal = status->chain_signal[0]; + + for (i = 1; i < hweight8(mphy->antenna_mask); i++) { + if (!(status->chains & BIT(i))) + continue; + + status->signal = max(status->signal, + status->chain_signal[i]); + } + + /* RXD Group 5 - C-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { + u8 stbc = FIELD_GET(MT_CRXV_HT_STBC, v2); + u8 gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2); + bool cck = false; + + rxd += 18; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + + idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); + mode = FIELD_GET(MT_CRXV_TX_MODE, v2); + + switch (mode) { + case MT_PHY_TYPE_CCK: + cck = true; + fallthrough; + case MT_PHY_TYPE_OFDM: + i = mt76_get_rate(&dev->mt76, sband, i, cck); + break; + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + if (i > 31) + return -EINVAL; + break; + case MT_PHY_TYPE_VHT: + status->nss = + FIELD_GET(MT_PRXV_NSTS, v0) + 1; + status->encoding = RX_ENC_VHT; + if (i > 9) + return -EINVAL; + break; + case MT_PHY_TYPE_HE_MU: + status->flag |= RX_FLAG_RADIOTAP_HE_MU; + fallthrough; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + status->nss = + FIELD_GET(MT_PRXV_NSTS, v0) + 1; + status->encoding = RX_ENC_HE; + status->flag |= RX_FLAG_RADIOTAP_HE; + i &= GENMASK(3, 0); + + if (gi <= NL80211_RATE_INFO_HE_GI_3_2) + status->he_gi = gi; + + status->he_dcm = !!(idx & MT_PRXV_TX_DCM); + break; + default: + return -EINVAL; + } + status->rate_idx = i; + + switch (FIELD_GET(MT_CRXV_FRAME_MODE, v2)) { + case IEEE80211_STA_RX_BW_20: + break; + case IEEE80211_STA_RX_BW_40: + if (mode & MT_PHY_TYPE_HE_EXT_SU && + (idx & MT_PRXV_TX_ER_SU_106T)) { + status->bw = RATE_INFO_BW_HE_RU; + status->he_ru = + NL80211_RATE_INFO_HE_RU_ALLOC_106; + } else { + status->bw = RATE_INFO_BW_40; + } + break; + case IEEE80211_STA_RX_BW_80: + status->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_160: + status->bw = RATE_INFO_BW_160; + break; + default: + return -EINVAL; + } + + status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; + if (mode < MT_PHY_TYPE_HE_SU && gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + } + } + + skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); + + if (insert_ccmp_hdr) { + u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); + + mt76_insert_ccmp_hdr(skb, key_id); + } + + if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) + mt7921_mac_decode_he_radiotap(skb, status, rxv, mode); + + hdr = mt76_skb_get_hdr(skb); + if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) + return 0; + + status->aggr = unicast && + !ieee80211_is_qos_nullfunc(hdr->frame_control); + status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + return 0; +} + +static void +mt7921_mac_write_txwi_8023(struct mt7921_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid) +{ + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + u8 fc_type, fc_stype; + bool wmm = false; + u32 val; + + if (wcid->sta) { + struct ieee80211_sta *sta; + + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); + wmm = sta->wme; + } + + val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | + FIELD_PREP(MT_TXD1_TID, tid); + + if (be16_to_cpu(skb->protocol) >= ETH_P_802_3_MIN) + val |= MT_TXD1_ETH_802_3; + + txwi[1] |= cpu_to_le32(val); + + fc_type = IEEE80211_FTYPE_DATA >> 2; + fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); + + txwi[2] |= cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + txwi[7] |= cpu_to_le32(val); +} + +static void +mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct ieee80211_key_conf *key) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool multicast = is_multicast_ether_addr(hdr->addr1); + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + __le16 fc = hdr->frame_control; + u8 fc_type, fc_stype; + u32 val; + + if (ieee80211_is_action(fc) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { + u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + + txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA); + tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK; + } else if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; + u16 control = le16_to_cpu(bar->control); + + tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control); + } + + val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | + FIELD_PREP(MT_TXD1_HDR_INFO, + ieee80211_get_hdrlen_from_skb(skb) / 2) | + FIELD_PREP(MT_TXD1_TID, tid); + txwi[1] |= cpu_to_le32(val); + + fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; + fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | + FIELD_PREP(MT_TXD2_MULTICAST, multicast); + + if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && + key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + val |= MT_TXD2_BIP; + txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); + } + + if (!ieee80211_is_data(fc) || multicast) + val |= MT_TXD2_FIX_RATE; + + txwi[2] |= cpu_to_le32(val); + + if (ieee80211_is_beacon(fc)) { + txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT); + txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); + } + + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + u16 seqno = le16_to_cpu(hdr->seq_ctrl); + + if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = le16_to_cpu(bar->start_seq_num); + } + + val = MT_TXD3_SN_VALID | + FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); + txwi[3] |= cpu_to_le32(val); + } + + val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + txwi[7] |= cpu_to_le32(val); +} + +void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, bool beacon) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct mt76_phy *mphy = &dev->mphy; + u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; + bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + u16 tx_count = 15; + u32 val; + + if (vif) { + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + + omac_idx = mvif->omac_idx; + wmm_idx = mvif->wmm_idx; + } + + if (beacon) { + p_fmt = MT_TX_TYPE_FW; + q_idx = MT_LMAC_BCN0; + } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { + p_fmt = MT_TX_TYPE_CT; + q_idx = MT_LMAC_ALTX0; + } else { + p_fmt = MT_TX_TYPE_CT; + q_idx = wmm_idx * MT7921_MAX_WMM_SETS + + mt7921_lmac_mapping(dev, skb_get_queue_mapping(skb)); + } + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | + FIELD_PREP(MT_TXD0_Q_IDX, q_idx); + txwi[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | + FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); + + txwi[1] = cpu_to_le32(val); + txwi[2] = 0; + + val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); + if (key) + val |= MT_TXD3_PROTECT_FRAME; + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + val |= MT_TXD3_NO_ACK; + + txwi[3] = cpu_to_le32(val); + txwi[4] = 0; + txwi[5] = 0; + txwi[6] = 0; + txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; + + if (is_8023) + mt7921_mac_write_txwi_8023(dev, txwi, skb, wcid); + else + mt7921_mac_write_txwi_80211(dev, txwi, skb, key); + + if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { + u16 rate; + + /* hardware won't add HTC for mgmt/ctrl frame */ + txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); + + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + rate = MT7921_5G_RATE_DEFAULT; + else + rate = MT7921_2G_RATE_DEFAULT; + + val = MT_TXD6_FIXED_BW | + FIELD_PREP(MT_TXD6_TX_RATE, rate); + txwi[6] |= cpu_to_le32(val); + txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); + } +} + +static void +mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info, + void *txp_ptr, u32 id) +{ + struct mt7921_hw_txp *txp = txp_ptr; + struct mt7921_txp_ptr *ptr = &txp->ptr[0]; + int i, nbuf = tx_info->nbuf - 1; + + tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); + tx_info->nbuf = 1; + + txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); + + for (i = 0; i < nbuf; i++) { + u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; + u32 addr = tx_info->buf[i + 1].addr; + + if (i == nbuf - 1) + len |= MT_TXD_LEN_LAST; + + if (i & 1) { + ptr->buf1 = cpu_to_le32(addr); + ptr->len1 = cpu_to_le16(len); + ptr++; + } else { + ptr->buf0 = cpu_to_le32(addr); + ptr->len0 = cpu_to_le16(len); + } + } +} + +static void mt7921_set_tx_blocked(struct mt7921_dev *dev, bool blocked) +{ + struct mt76_phy *mphy = &dev->mphy; + struct mt76_queue *q; + + q = mphy->q_tx[0]; + if (blocked == q->blocked) + return; + + q->blocked = blocked; + if (!blocked) + mt76_worker_schedule(&dev->mt76.tx_worker); +} + +int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb); + struct mt76_txwi_cache *t; + struct mt7921_txp_common *txp; + int id; + u8 *txwi = (u8 *)txwi_ptr; + + if (unlikely(tx_info->skb->len <= ETH_HLEN)) + return -EINVAL; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + cb->wcid = wcid->idx; + + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + + spin_lock_bh(&dev->token_lock); + id = idr_alloc(&dev->token, t, 0, MT7921_TOKEN_SIZE, GFP_ATOMIC); + if (id >= 0) + dev->token_count++; + + if (dev->token_count >= MT7921_TOKEN_SIZE - MT7921_TOKEN_FREE_THR) + mt7921_set_tx_blocked(dev, true); + spin_unlock_bh(&dev->token_lock); + + if (id < 0) + return id; + + mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, + false); + + txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); + memset(txp, 0, sizeof(struct mt7921_txp_common)); + mt7921_write_hw_txp(dev, tx_info, txp, id); + + tx_info->skb = DMA_DUMMY_DATA; + + return 0; +} + +static void +mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) +{ + struct mt7921_sta *msta; + u16 fc, tid; + u32 val; + + if (!sta || !sta->ht_cap.ht_supported) + return; + + tid = FIELD_GET(MT_TXD1_TID, le32_to_cpu(txwi[1])); + if (tid >= 6) /* skip VO queue */ + return; + + val = le32_to_cpu(txwi[2]); + fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 | + FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4; + if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) + return; + + msta = (struct mt7921_sta *)sta->drv_priv; + if (!test_and_set_bit(tid, &msta->ampdu_state)) + ieee80211_start_tx_ba_session(sta, tid, 0); +} + +static void +mt7921_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, + struct ieee80211_sta *sta, u8 stat, + struct list_head *free_list) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_status status = { + .sta = sta, + .info = info, + .skb = skb, + .free_list = free_list, + }; + struct ieee80211_hw *hw; + + if (sta) { + struct mt7921_sta *msta; + + msta = (struct mt7921_sta *)sta->drv_priv; + status.rate = &msta->stats.tx_rate; + } + + hw = mt76_tx_status_get_hw(mdev, skb); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) + info->flags |= IEEE80211_TX_STAT_AMPDU; + + if (stat) + ieee80211_tx_info_clear_status(info); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.tx_time = 0; + ieee80211_tx_status_ext(hw, &status); +} + +void mt7921_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *t) +{ + struct mt7921_txp_common *txp; + int i; + + txp = mt7921_txwi_to_txp(dev, t); + + for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) { + struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i]; + bool last; + u16 len; + + len = le16_to_cpu(ptr->len0); + last = len & MT_TXD_LEN_LAST; + len &= MT_TXD_LEN_MASK; + dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, + DMA_TO_DEVICE); + if (last) + break; + + len = le16_to_cpu(ptr->len1); + last = len & MT_TXD_LEN_LAST; + len &= MT_TXD_LEN_MASK; + dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, + DMA_TO_DEVICE); + if (last) + break; + } +} + +void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_tx_free *free = (struct mt7921_tx_free *)skb->data; + struct mt76_dev *mdev = &dev->mt76; + struct mt76_txwi_cache *txwi; + struct ieee80211_sta *sta = NULL; + LIST_HEAD(free_list); + struct sk_buff *tmp; + bool wake = false; + u8 i, count; + + /* clean DMA queues and unmap buffers first */ + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false); + + /* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE, + * to the time ack is received or dropped by hw (air + hw queue time). + * Should avoid accessing WTBL to get Tx airtime, and use it instead. + */ + count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl)); + for (i = 0; i < count; i++) { + u32 msdu, info = le32_to_cpu(free->info[i]); + u8 stat; + + /* 1'b1: new wcid pair. + * 1'b0: msdu_id with the same 'wcid pair' as above. + */ + if (info & MT_TX_FREE_PAIR) { + struct mt7921_sta *msta; + struct mt7921_phy *phy; + struct mt76_wcid *wcid; + u16 idx; + + count++; + idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info); + wcid = rcu_dereference(dev->mt76.wcid[idx]); + sta = wcid_to_sta(wcid); + if (!sta) + continue; + + msta = container_of(wcid, struct mt7921_sta, wcid); + phy = msta->vif->phy; + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->stats_list)) + list_add_tail(&msta->stats_list, &phy->stats_list); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + continue; + } + + msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); + stat = FIELD_GET(MT_TX_FREE_STATUS, info); + + spin_lock_bh(&dev->token_lock); + txwi = idr_remove(&dev->token, msdu); + if (txwi) + dev->token_count--; + if (dev->token_count < MT7921_TOKEN_SIZE - MT7921_TOKEN_FREE_THR && + dev->mphy.q_tx[0]->blocked) + wake = true; + spin_unlock_bh(&dev->token_lock); + + if (!txwi) + continue; + + mt7921_txp_skb_unmap(mdev, txwi); + if (txwi->skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb); + void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi); + + if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7921_tx_check_aggr(sta, txwi_ptr); + + if (sta && !info->tx_time_est) { + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + int pending; + + pending = atomic_dec_return(&wcid->non_aql_packets); + if (pending < 0) + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); + } + + mt7921_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list); + txwi->skb = NULL; + } + + mt76_put_txwi(mdev, txwi); + } + + if (wake) { + spin_lock_bh(&dev->token_lock); + mt7921_set_tx_blocked(dev, false); + spin_unlock_bh(&dev->token_lock); + } + + napi_consume_skb(skb, 1); + + list_for_each_entry_safe(skb, tmp, &free_list, list) { + skb_list_del_init(skb); + napi_consume_skb(skb, 1); + } + + if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state)) + return; + + mt7921_mac_sta_poll(dev); + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + + mt76_worker_schedule(&dev->mt76.tx_worker); +} + +void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) +{ + struct mt7921_dev *dev; + + if (!e->txwi) { + dev_kfree_skb_any(e->skb); + return; + } + + dev = container_of(mdev, struct mt7921_dev, mt76); + + /* error path */ + if (e->skb == DMA_DUMMY_DATA) { + struct mt76_txwi_cache *t; + struct mt7921_txp_common *txp; + u16 token; + + txp = mt7921_txwi_to_txp(mdev, e->txwi); + + token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID; + spin_lock_bh(&dev->token_lock); + t = idr_remove(&dev->token, token); + spin_unlock_bh(&dev->token_lock); + e->skb = t ? t->skb : NULL; + } + + if (e->skb) { + struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb); + struct mt76_wcid *wcid; + + wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]); + + mt7921_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0, + NULL); + } +} + +void mt7921_mac_reset_counters(struct mt7921_phy *phy) +{ + struct mt7921_dev *dev = phy->dev; + int i; + + for (i = 0; i < 4; i++) { + mt76_rr(dev, MT_TX_AGG_CNT(0, i)); + mt76_rr(dev, MT_TX_AGG_CNT2(0, i)); + } + + dev->mt76.phy.survey_time = ktime_get_boottime(); + memset(&dev->mt76.aggr_stats[0], 0, sizeof(dev->mt76.aggr_stats) / 2); + + /* reset airtime counters */ + mt76_rr(dev, MT_MIB_SDR9(0)); + mt76_rr(dev, MT_MIB_SDR36(0)); + mt76_rr(dev, MT_MIB_SDR37(0)); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); +} + +void mt7921_mac_set_timing(struct mt7921_phy *phy) +{ + s16 coverage_class = phy->coverage_class; + struct mt7921_dev *dev = phy->dev; + u32 val, reg_offset; + u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); + u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); + int sifs, offset; + bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; + + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; + + if (is_5ghz) + sifs = 16; + else + sifs = 10; + + mt76_set(dev, MT_ARB_SCR(0), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); + udelay(1); + + offset = 3 * coverage_class; + reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); + + mt76_wr(dev, MT_TMAC_CDTR(0), cck + reg_offset); + mt76_wr(dev, MT_TMAC_ODTR(0), ofdm + reg_offset); + mt76_wr(dev, MT_TMAC_ICR0(0), + FIELD_PREP(MT_IFS_EIFS, 360) | + FIELD_PREP(MT_IFS_RIFS, 2) | + FIELD_PREP(MT_IFS_SIFS, sifs) | + FIELD_PREP(MT_IFS_SLOT, phy->slottime)); + + if (phy->slottime < 20 || is_5ghz) + val = MT7921_CFEND_RATE_DEFAULT; + else + val = MT7921_CFEND_RATE_11B; + + mt76_rmw_field(dev, MT_AGG_ACR0(0), MT_AGG_ACR_CFEND_RATE, val); + mt76_clear(dev, MT_ARB_SCR(0), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); +} + +static u8 +mt7921_phy_get_nf(struct mt7921_phy *phy, int idx) +{ + return 0; +} + +static void +mt7921_phy_update_channel(struct mt76_phy *mphy, int idx) +{ + struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76); + struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; + struct mt76_channel_state *state; + u64 busy_time, tx_time, rx_time, obss_time; + int nf; + + busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), + MT_MIB_SDR9_BUSY_MASK); + tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), + MT_MIB_SDR36_TXTIME_MASK); + rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), + MT_MIB_SDR37_RXTIME_MASK); + obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx), + MT_MIB_OBSSTIME_MASK); + + nf = mt7921_phy_get_nf(phy, idx); + if (!phy->noise) + phy->noise = nf << 4; + else if (nf) + phy->noise += nf - (phy->noise >> 4); + + state = mphy->chan_state; + state->cc_busy += busy_time; + state->cc_tx += tx_time; + state->cc_rx += rx_time + obss_time; + state->cc_bss_rx += rx_time; + state->noise = -(phy->noise >> 4); +} + +void mt7921_update_channel(struct mt76_dev *mdev) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + + if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) + return; + + mt7921_phy_update_channel(&mdev->phy, 0); + /* reset obss airtime */ + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); +} + +static bool +mt7921_wait_reset_state(struct mt7921_dev *dev, u32 state) +{ + bool ret; + + ret = wait_event_timeout(dev->reset_wait, + (READ_ONCE(dev->reset_state) & state), + MT7921_RESET_TIMEOUT); + + WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); + return ret; +} + +static void +mt7921_dma_reset(struct mt7921_phy *phy) +{ + struct mt7921_dev *dev = phy->dev; + int i; + + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + + usleep_range(1000, 2000); + + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], true); + for (i = 0; i < __MT_TXQ_MAX; i++) + mt76_queue_tx_cleanup(dev, phy->mt76->q_tx[i], true); + + mt76_for_each_q_rx(&dev->mt76, i) { + mt76_queue_rx_reset(dev, i); + } + + /* re-init prefetch settings after reset */ + mt7921_dma_prefetch(dev); + + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); +} + +void mt7921_tx_token_put(struct mt7921_dev *dev) +{ + struct mt76_txwi_cache *txwi; + int id; + + spin_lock_bh(&dev->token_lock); + idr_for_each_entry(&dev->token, txwi, id) { + mt7921_txp_skb_unmap(&dev->mt76, txwi); + if (txwi->skb) { + struct ieee80211_hw *hw; + + hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); + ieee80211_free_txskb(hw, txwi->skb); + } + mt76_put_txwi(&dev->mt76, txwi); + dev->token_count--; + } + spin_unlock_bh(&dev->token_lock); + idr_destroy(&dev->token); +} + +/* system error recovery */ +void mt7921_mac_reset_work(struct work_struct *work) +{ + struct mt7921_dev *dev; + + dev = container_of(work, struct mt7921_dev, reset_work); + + if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) + return; + + ieee80211_stop_queues(mt76_hw(dev)); + + set_bit(MT76_RESET, &dev->mphy.state); + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + cancel_delayed_work_sync(&dev->mphy.mac_work); + + /* lock/unlock all queues to ensure that no tx is pending */ + mt76_txq_schedule_all(&dev->mphy); + + mt76_worker_disable(&dev->mt76.tx_worker); + napi_disable(&dev->mt76.napi[0]); + napi_disable(&dev->mt76.napi[1]); + napi_disable(&dev->mt76.napi[2]); + napi_disable(&dev->mt76.tx_napi); + + mt7921_mutex_acquire(dev); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); + + mt7921_tx_token_put(dev); + idr_init(&dev->token); + + if (mt7921_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { + mt7921_dma_reset(&dev->phy); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); + mt7921_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); + } + + clear_bit(MT76_MCU_RESET, &dev->mphy.state); + clear_bit(MT76_RESET, &dev->mphy.state); + + mt76_worker_enable(&dev->mt76.tx_worker); + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); + + napi_enable(&dev->mt76.napi[0]); + napi_schedule(&dev->mt76.napi[0]); + + napi_enable(&dev->mt76.napi[1]); + napi_schedule(&dev->mt76.napi[1]); + + napi_enable(&dev->mt76.napi[2]); + napi_schedule(&dev->mt76.napi[2]); + + ieee80211_wake_queues(mt76_hw(dev)); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); + mt7921_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); + + mt7921_mutex_release(dev); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, + MT7921_WATCHDOG_TIME); +} + +static void +mt7921_mac_update_mib_stats(struct mt7921_phy *phy) +{ + struct mt7921_dev *dev = phy->dev; + struct mib_stats *mib = &phy->mib; + int i, aggr0 = 0, aggr1; + + memset(mib, 0, sizeof(*mib)); + + mib->fcs_err_cnt = mt76_get_field(dev, MT_MIB_SDR3(0), + MT_MIB_SDR3_FCS_ERR_MASK); + + for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { + u32 val, val2; + + val = mt76_rr(dev, MT_MIB_MB_SDR1(0, i)); + + val2 = FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); + if (val2 > mib->ack_fail_cnt) + mib->ack_fail_cnt = val2; + + val2 = FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); + if (val2 > mib->ba_miss_cnt) + mib->ba_miss_cnt = val2; + + val = mt76_rr(dev, MT_MIB_MB_SDR0(0, i)); + val2 = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); + if (val2 > mib->rts_retries_cnt) { + mib->rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); + mib->rts_retries_cnt = val2; + } + + val = mt76_rr(dev, MT_TX_AGG_CNT(0, i)); + val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i)); + + dev->mt76.aggr_stats[aggr0++] += val & 0xffff; + dev->mt76.aggr_stats[aggr0++] += val >> 16; + dev->mt76.aggr_stats[aggr1++] += val2 & 0xffff; + dev->mt76.aggr_stats[aggr1++] += val2 >> 16; + } +} + +static void +mt7921_mac_sta_stats_work(struct mt7921_phy *phy) +{ + struct mt7921_dev *dev = phy->dev; + struct mt7921_sta *msta; + LIST_HEAD(list); + + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&phy->stats_list, &list); + + while (!list_empty(&list)) { + msta = list_first_entry(&list, struct mt7921_sta, stats_list); + list_del_init(&msta->stats_list); + spin_unlock_bh(&dev->sta_poll_lock); + + /* query wtbl info to report tx rate for further devices */ + mt7921_get_wtbl_info(dev, msta->wcid.idx); + + spin_lock_bh(&dev->sta_poll_lock); + } + + spin_unlock_bh(&dev->sta_poll_lock); +} + +void mt7921_mac_work(struct work_struct *work) +{ + struct mt7921_phy *phy; + struct mt76_phy *mphy; + + mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, + mac_work.work); + phy = mphy->priv; + + if (test_bit(MT76_STATE_PM, &mphy->state)) + goto out; + + mt7921_mutex_acquire(phy->dev); + + mt76_update_survey(mphy->dev); + if (++mphy->mac_work_count == 5) { + mphy->mac_work_count = 0; + + mt7921_mac_update_mib_stats(phy); + } + if (++phy->sta_work_count == 10) { + phy->sta_work_count = 0; + mt7921_mac_sta_stats_work(phy); + }; + + mt7921_mutex_release(phy->dev); + +out: + ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, + MT7921_WATCHDOG_TIME); +} + +void mt7921_pm_wake_work(struct work_struct *work) +{ + struct mt7921_dev *dev; + struct mt76_phy *mphy; + + dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev, + pm.wake_work); + mphy = dev->phy.mt76; + + if (!mt7921_mcu_drv_pmctrl(dev)) + mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); + else + dev_err(mphy->dev->dev, "failed to wake device\n"); + + ieee80211_wake_queues(mphy->hw); + complete_all(&dev->pm.wake_cmpl); +} + +void mt7921_pm_power_save_work(struct work_struct *work) +{ + struct mt7921_dev *dev; + unsigned long delta; + + dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev, + pm.ps_work.work); + + delta = dev->pm.idle_timeout; + if (time_is_after_jiffies(dev->pm.last_activity + delta)) { + delta = dev->pm.last_activity + delta - jiffies; + goto out; + } + + if (!mt7921_mcu_fw_pmctrl(dev)) + return; +out: + queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); +} + +int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy, + struct ieee80211_vif *vif, + bool enable) +{ + struct mt7921_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + int err; + + if (!dev->pm.enable) + return -EOPNOTSUPP; + + err = mt7921_mcu_set_bss_pm(dev, vif, enable); + if (err) + return err; + + if (enable) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mt76_set(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } else { + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + mt76_clear(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } + + return 0; +} + +void mt7921_coredump_work(struct work_struct *work) +{ + struct mt7921_dev *dev; + char *dump, *data; + + dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev, + coredump.work.work); + + if (time_is_after_jiffies(dev->coredump.last_activity + + 4 * MT76_CONNAC_COREDUMP_TIMEOUT)) { + queue_delayed_work(dev->mt76.wq, &dev->coredump.work, + MT76_CONNAC_COREDUMP_TIMEOUT); + return; + } + + dump = vzalloc(MT76_CONNAC_COREDUMP_SZ); + data = dump; + + while (true) { + struct sk_buff *skb; + + spin_lock_bh(&dev->mt76.lock); + skb = __skb_dequeue(&dev->coredump.msg_list); + spin_unlock_bh(&dev->mt76.lock); + + if (!skb) + break; + + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + if (data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) + break; + + memcpy(data, skb->data, skb->len); + data += skb->len; + + dev_kfree_skb(skb); + } + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h new file mode 100644 index 000000000000..a0c1fa0f20e4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -0,0 +1,333 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7921_MAC_H +#define __MT7921_MAC_H + +#define MT_CT_PARSE_LEN 72 +#define MT_CT_DMA_BUF_NUM 2 + +#define MT_RXD0_LENGTH GENMASK(15, 0) +#define MT_RXD0_PKT_FLAG GENMASK(19, 16) +#define MT_RXD0_PKT_TYPE GENMASK(31, 27) + +#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16) +#define MT_RXD0_NORMAL_IP_SUM BIT(23) +#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24) + +enum rx_pkt_type { + PKT_TYPE_TXS, + PKT_TYPE_TXRXV, + PKT_TYPE_NORMAL, + PKT_TYPE_RX_DUP_RFB, + PKT_TYPE_RX_TMR, + PKT_TYPE_RETRIEVE, + PKT_TYPE_TXRX_NOTIFY, + PKT_TYPE_RX_EVENT, + PKT_TYPE_NORMAL_MCU, +}; + +/* RXD DW1 */ +#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) +#define MT_RXD1_NORMAL_GROUP_1 BIT(11) +#define MT_RXD1_NORMAL_GROUP_2 BIT(12) +#define MT_RXD1_NORMAL_GROUP_3 BIT(13) +#define MT_RXD1_NORMAL_GROUP_4 BIT(14) +#define MT_RXD1_NORMAL_GROUP_5 BIT(15) +#define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16) +#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) +#define MT_RXD1_NORMAL_CM BIT(23) +#define MT_RXD1_NORMAL_CLM BIT(24) +#define MT_RXD1_NORMAL_ICV_ERR BIT(25) +#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) +#define MT_RXD1_NORMAL_FCS_ERR BIT(27) +#define MT_RXD1_NORMAL_BAND_IDX BIT(28) +#define MT_RXD1_NORMAL_SPP_EN BIT(29) +#define MT_RXD1_NORMAL_ADD_OM BIT(30) +#define MT_RXD1_NORMAL_SEC_DONE BIT(31) + +/* RXD DW2 */ +#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) +#define MT_RXD2_NORMAL_CO_ANT BIT(6) +#define MT_RXD2_NORMAL_BF_CQI BIT(7) +#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) +#define MT_RXD2_NORMAL_HDR_TRANS BIT(13) +#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14) +#define MT_RXD2_NORMAL_TID GENMASK(19, 16) +#define MT_RXD2_NORMAL_MU_BAR BIT(21) +#define MT_RXD2_NORMAL_SW_BIT BIT(22) +#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) +#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) +#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) +#define MT_RXD2_NORMAL_INT_FRAME BIT(26) +#define MT_RXD2_NORMAL_FRAG BIT(27) +#define MT_RXD2_NORMAL_NULL_FRAME BIT(28) +#define MT_RXD2_NORMAL_NDATA BIT(29) +#define MT_RXD2_NORMAL_NON_AMPDU BIT(30) +#define MT_RXD2_NORMAL_BF_REPORT BIT(31) + +/* RXD DW3 */ +#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) +#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) +#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) +#define MT_RXD3_NORMAL_U2M BIT(0) +#define MT_RXD3_NORMAL_HTC_VLD BIT(0) +#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19) +#define MT_RXD3_NORMAL_BEACON_MC BIT(20) +#define MT_RXD3_NORMAL_BEACON_UC BIT(21) +#define MT_RXD3_NORMAL_AMSDU BIT(22) +#define MT_RXD3_NORMAL_MESH BIT(23) +#define MT_RXD3_NORMAL_MHCP BIT(24) +#define MT_RXD3_NORMAL_NO_INFO_WB BIT(25) +#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26) +#define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27) +#define MT_RXD3_NORMAL_MORE BIT(28) +#define MT_RXD3_NORMAL_UNWANT BIT(29) +#define MT_RXD3_NORMAL_RX_DROP BIT(30) +#define MT_RXD3_NORMAL_VLAN2ETH BIT(31) + +/* RXD DW4 */ +#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) +#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) +#define MT_RXD4_NORMAL_CLS BIT(10) +#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) +#define MT_RXD4_NORMAL_MAGIC_PKT BIT(13) +#define MT_RXD4_NORMAL_WOL GENMASK(18, 14) +#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) +#define MT_RXD3_NORMAL_PF_MODE BIT(29) +#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) + +/* P-RXV */ +#define MT_PRXV_TX_RATE GENMASK(6, 0) +#define MT_PRXV_TX_DCM BIT(4) +#define MT_PRXV_TX_ER_SU_106T BIT(5) +#define MT_PRXV_NSTS GENMASK(9, 7) +#define MT_PRXV_HT_AD_CODE BIT(11) +#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28) +#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) +#define MT_PRXV_RCPI3 GENMASK(31, 24) +#define MT_PRXV_RCPI2 GENMASK(23, 16) +#define MT_PRXV_RCPI1 GENMASK(15, 8) +#define MT_PRXV_RCPI0 GENMASK(7, 0) + +/* C-RXV */ +#define MT_CRXV_HT_STBC GENMASK(1, 0) +#define MT_CRXV_TX_MODE GENMASK(7, 4) +#define MT_CRXV_FRAME_MODE GENMASK(10, 8) +#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) +#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) +#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) +#define MT_CRXV_HE_PE_DISAMBIG BIT(23) +#define MT_CRXV_HE_UPLINK BIT(31) + +#define MT_CRXV_HE_SR_MASK GENMASK(11, 8) +#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) +#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17) +#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) + +#define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0) +#define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6) +#define MT_CRXV_HE_BEAM_CHNG BIT(13) +#define MT_CRXV_HE_DOPPLER BIT(16) + +#define MT_CRXV_SNR GENMASK(18, 13) +#define MT_CRXV_FOE_LO GENMASK(31, 19) +#define MT_CRXV_FOE_HI GENMASK(6, 0) +#define MT_CRXV_FOE_SHIFT 13 + +enum tx_header_format { + MT_HDR_FORMAT_802_3, + MT_HDR_FORMAT_CMD, + MT_HDR_FORMAT_802_11, + MT_HDR_FORMAT_802_11_EXT, +}; + +enum tx_pkt_type { + MT_TX_TYPE_CT, + MT_TX_TYPE_SF, + MT_TX_TYPE_CMD, + MT_TX_TYPE_FW, +}; + +enum tx_port_idx { + MT_TX_PORT_IDX_LMAC, + MT_TX_PORT_IDX_MCU +}; + +enum tx_mcu_port_q_idx { + MT_TX_MCU_PORT_RX_Q0 = 0x20, + MT_TX_MCU_PORT_RX_Q1, + MT_TX_MCU_PORT_RX_Q2, + MT_TX_MCU_PORT_RX_Q3, + MT_TX_MCU_PORT_RX_FWDL = 0x3e +}; + +#define MT_CT_INFO_APPLY_TXD BIT(0) +#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) +#define MT_CT_INFO_MGMT_FRAME BIT(2) +#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) +#define MT_CT_INFO_HSR2_TX BIT(4) +#define MT_CT_INFO_FROM_HOST BIT(7) + +#define MT_TXD_SIZE (8 * 4) + +#define MT_TXD0_Q_IDX GENMASK(31, 25) +#define MT_TXD0_PKT_FMT GENMASK(24, 23) +#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) +#define MT_TXD0_TX_BYTES GENMASK(15, 0) + +#define MT_TXD1_LONG_FORMAT BIT(31) +#define MT_TXD1_TGID BIT(30) +#define MT_TXD1_OWN_MAC GENMASK(29, 24) +#define MT_TXD1_AMSDU BIT(23) +#define MT_TXD1_TID GENMASK(22, 20) +#define MT_TXD1_HDR_PAD GENMASK(19, 18) +#define MT_TXD1_HDR_FORMAT GENMASK(17, 16) +#define MT_TXD1_HDR_INFO GENMASK(15, 11) +#define MT_TXD1_ETH_802_3 BIT(15) +#define MT_TXD1_VTA BIT(10) +#define MT_TXD1_WLAN_IDX GENMASK(9, 0) + +#define MT_TXD2_FIX_RATE BIT(31) +#define MT_TXD2_FIXED_RATE BIT(30) +#define MT_TXD2_POWER_OFFSET GENMASK(29, 24) +#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) +#define MT_TXD2_FRAG GENMASK(15, 14) +#define MT_TXD2_HTC_VLD BIT(13) +#define MT_TXD2_DURATION BIT(12) +#define MT_TXD2_BIP BIT(11) +#define MT_TXD2_MULTICAST BIT(10) +#define MT_TXD2_RTS BIT(9) +#define MT_TXD2_SOUNDING BIT(8) +#define MT_TXD2_NDPA BIT(7) +#define MT_TXD2_NDP BIT(6) +#define MT_TXD2_FRAME_TYPE GENMASK(5, 4) +#define MT_TXD2_SUB_TYPE GENMASK(3, 0) + +#define MT_TXD3_SN_VALID BIT(31) +#define MT_TXD3_PN_VALID BIT(30) +#define MT_TXD3_SW_POWER_MGMT BIT(29) +#define MT_TXD3_BA_DISABLE BIT(28) +#define MT_TXD3_SEQ GENMASK(27, 16) +#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) +#define MT_TXD3_TX_COUNT GENMASK(10, 6) +#define MT_TXD3_TIMING_MEASURE BIT(5) +#define MT_TXD3_DAS BIT(4) +#define MT_TXD3_EEOSP BIT(3) +#define MT_TXD3_EMRD BIT(2) +#define MT_TXD3_PROTECT_FRAME BIT(1) +#define MT_TXD3_NO_ACK BIT(0) + +#define MT_TXD4_PN_LOW GENMASK(31, 0) + +#define MT_TXD5_PN_HIGH GENMASK(31, 16) +#define MT_TXD5_MD BIT(15) +#define MT_TXD5_ADD_BA BIT(14) +#define MT_TXD5_TX_STATUS_HOST BIT(10) +#define MT_TXD5_TX_STATUS_MCU BIT(9) +#define MT_TXD5_TX_STATUS_FMT BIT(8) +#define MT_TXD5_PID GENMASK(7, 0) + +#define MT_TXD6_TX_IBF BIT(31) +#define MT_TXD6_TX_EBF BIT(30) +#define MT_TXD6_TX_RATE GENMASK(29, 16) +#define MT_TXD6_SGI GENMASK(15, 14) +#define MT_TXD6_HELTF GENMASK(13, 12) +#define MT_TXD6_LDPC BIT(11) +#define MT_TXD6_SPE_ID_IDX BIT(10) +#define MT_TXD6_ANT_ID GENMASK(7, 4) +#define MT_TXD6_DYN_BW BIT(3) +#define MT_TXD6_FIXED_BW BIT(2) +#define MT_TXD6_BW GENMASK(1, 0) + +#define MT_TXD7_TXD_LEN GENMASK(31, 30) +#define MT_TXD7_UDP_TCP_SUM BIT(29) +#define MT_TXD7_IP_SUM BIT(28) + +#define MT_TXD7_TYPE GENMASK(21, 20) +#define MT_TXD7_SUB_TYPE GENMASK(19, 16) + +#define MT_TXD7_PSE_FID GENMASK(27, 16) +#define MT_TXD7_SPE_IDX GENMASK(15, 11) +#define MT_TXD7_HW_AMSDU BIT(10) +#define MT_TXD7_TX_TIME GENMASK(9, 0) + +#define MT_TX_RATE_STBC BIT(13) +#define MT_TX_RATE_NSS GENMASK(12, 10) +#define MT_TX_RATE_MODE GENMASK(9, 6) +#define MT_TX_RATE_SU_EXT_TONE BIT(5) +#define MT_TX_RATE_DCM BIT(4) +#define MT_TX_RATE_IDX GENMASK(3, 0) + +#define MT_TXP_MAX_BUF_NUM 6 + +struct mt7921_txp { + __le16 flags; + __le16 token; + u8 bss_idx; + __le16 rept_wds_wcid; + u8 nbuf; + __le32 buf[MT_TXP_MAX_BUF_NUM]; + __le16 len[MT_TXP_MAX_BUF_NUM]; +} __packed __aligned(4); + +struct mt7921_tx_free { + __le16 rx_byte_cnt; + __le16 ctrl; + u8 txd_cnt; + u8 rsv[3]; + __le32 info[]; +} __packed __aligned(4); + +#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) +#define MT_TX_FREE_WLAN_ID GENMASK(23, 14) +#define MT_TX_FREE_LATENCY GENMASK(12, 0) +/* 0: success, others: dropped */ +#define MT_TX_FREE_STATUS GENMASK(14, 13) +#define MT_TX_FREE_MSDU_ID GENMASK(30, 16) +#define MT_TX_FREE_PAIR BIT(31) +/* will support this field in further revision */ +#define MT_TX_FREE_RATE GENMASK(13, 0) + +static inline struct mt7921_txp_common * +mt7921_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) +{ + u8 *txwi; + + if (!t) + return NULL; + + txwi = mt76_get_txwi_ptr(dev, t); + + return (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); +} + +#define MT_HW_TXP_MAX_MSDU_NUM 4 +#define MT_HW_TXP_MAX_BUF_NUM 4 + +#define MT_MSDU_ID_VALID BIT(15) + +#define MT_TXD_LEN_MASK GENMASK(11, 0) +#define MT_TXD_LEN_MSDU_LAST BIT(14) +#define MT_TXD_LEN_AMSDU_LAST BIT(15) +#define MT_TXD_LEN_LAST BIT(15) + +struct mt7921_txp_ptr { + __le32 buf0; + __le16 len0; + __le16 len1; + __le32 buf1; +} __packed __aligned(4); + +struct mt7921_hw_txp { + __le16 msdu_id[MT_HW_TXP_MAX_MSDU_NUM]; + struct mt7921_txp_ptr ptr[MT_HW_TXP_MAX_BUF_NUM / 2]; +} __packed __aligned(4); + +struct mt7921_txp_common { + union { + struct mt7921_hw_txp hw; + }; +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c new file mode 100644 index 000000000000..729f6c42cdde --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -0,0 +1,1161 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include <linux/etherdevice.h> +#include <linux/platform_device.h> +#include <linux/pci.h> +#include <linux/module.h> +#include "mt7921.h" +#include "mcu.h" + +static void +mt7921_gen_ppe_thresh(u8 *he_ppet, int nss) +{ + u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */ + u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71}; + + he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) | + FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK, + ru_bit_mask); + + ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE * + nss * hweight8(ru_bit_mask) * 2; + ppet_size = DIV_ROUND_UP(ppet_bits, 8); + + for (i = 0; i < ppet_size - 1; i++) + he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3]; + + he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] & + (0xff >> (8 - (ppet_bits - 1) % 8)); +} + +static int +mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, + struct ieee80211_sband_iftype_data *data) +{ + int i, idx = 0; + int nss = hweight8(phy->mt76->chainmask); + u16 mcs_map = 0; + + for (i = 0; i < 8; i++) { + if (i < nss) + mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2)); + else + mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + } + + for (i = 0; i < NUM_NL80211_IFTYPES; i++) { + struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; + struct ieee80211_he_cap_elem *he_cap_elem = + &he_cap->he_cap_elem; + struct ieee80211_he_mcs_nss_supp *he_mcs = + &he_cap->he_mcs_nss_supp; + + switch (i) { + case NL80211_IFTYPE_STATION: + break; + default: + continue; + } + + data[idx].types_mask = BIT(i); + he_cap->has_he = true; + + he_cap_elem->mac_cap_info[0] = + IEEE80211_HE_MAC_CAP0_HTC_HE; + he_cap_elem->mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED; + he_cap_elem->mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + else if (band == NL80211_BAND_5GHZ) + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + + he_cap_elem->phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; + he_cap_elem->phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; + + switch (i) { + case NL80211_IFTYPE_STATION: + he_cap_elem->mac_cap_info[0] |= + IEEE80211_HE_MAC_CAP0_TWT_REQ; + he_cap_elem->mac_cap_info[1] |= + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; + else if (band == NL80211_BAND_5GHZ) + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; + + he_cap_elem->phy_cap_info[1] |= + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; + he_cap_elem->phy_cap_info[3] |= + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; + he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; + he_cap_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; + break; + } + + he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map); + he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map); + he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map); + + memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); + if (he_cap_elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { + mt7921_gen_ppe_thresh(he_cap->ppe_thres, nss); + } else { + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US; + } + idx++; + } + + return idx; +} + +void mt7921_set_stream_he_caps(struct mt7921_phy *phy) +{ + struct ieee80211_sband_iftype_data *data; + struct ieee80211_supported_band *band; + int n; + + if (phy->mt76->cap.has_2ghz) { + data = phy->iftype[NL80211_BAND_2GHZ]; + n = mt7921_init_he_caps(phy, NL80211_BAND_2GHZ, data); + + band = &phy->mt76->sband_2g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } + + if (phy->mt76->cap.has_5ghz) { + data = phy->iftype[NL80211_BAND_5GHZ]; + n = mt7921_init_he_caps(phy, NL80211_BAND_5GHZ, data); + + band = &phy->mt76->sband_5g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } +} + +static int mt7921_start(struct ieee80211_hw *hw) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + + mt7921_mutex_acquire(dev); + + mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, true, false); + mt76_connac_mcu_set_channel_domain(phy->mt76); + + mt7921_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); + mt7921_mac_reset_counters(phy); + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + MT7921_WATCHDOG_TIME); + + mt7921_mutex_release(dev); + + return 0; +} + +static void mt7921_stop(struct ieee80211_hw *hw) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + + cancel_delayed_work_sync(&phy->mt76->mac_work); + + cancel_delayed_work_sync(&dev->pm.ps_work); + cancel_work_sync(&dev->pm.wake_work); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + + mt7921_mutex_acquire(dev); + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); + mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); + mt7921_mutex_release(dev); +} + +static inline int get_free_idx(u32 mask, u8 start, u8 end) +{ + return ffs(~mask & GENMASK(end, start)); +} + +static int get_omac_idx(enum nl80211_iftype type, u64 mask) +{ + int i; + + switch (type) { + case NL80211_IFTYPE_STATION: + /* prefer hw bssid slot 1-3 */ + i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); + if (i) + return i - 1; + + if (type != NL80211_IFTYPE_STATION) + break; + + /* next, try to find a free repeater entry for the sta */ + i = get_free_idx(mask >> REPEATER_BSSID_START, 0, + REPEATER_BSSID_MAX - REPEATER_BSSID_START); + if (i) + return i + 32 - 1; + + i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); + if (i) + return i - 1; + + if (~mask & BIT(HW_BSSID_0)) + return HW_BSSID_0; + + break; + case NL80211_IFTYPE_MONITOR: + /* ap uses hw bssid 0 and ext bssid */ + if (~mask & BIT(HW_BSSID_0)) + return HW_BSSID_0; + + i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); + if (i) + return i - 1; + + break; + default: + WARN_ON(1); + break; + } + + return -1; +} + +static int mt7921_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt76_txq *mtxq; + int idx, ret = 0; + + mt7921_mutex_acquire(dev); + + if (vif->type == NL80211_IFTYPE_MONITOR && + is_zero_ether_addr(vif->addr)) + phy->monitor_vif = vif; + + mvif->mt76.idx = ffs(~dev->mt76.vif_mask) - 1; + if (mvif->mt76.idx >= MT7921_MAX_INTERFACES) { + ret = -ENOSPC; + goto out; + } + + idx = get_omac_idx(vif->type, phy->omac_mask); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + mvif->mt76.omac_idx = idx; + mvif->phy = phy; + mvif->mt76.band_idx = 0; + mvif->mt76.wmm_idx = mvif->mt76.idx % MT7921_MAX_WMM_SETS; + + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, + true); + if (ret) + goto out; + + if (dev->pm.enable) { + ret = mt7921_mcu_set_bss_pm(dev, vif, true); + if (ret) + goto out; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); + } + + dev->mt76.vif_mask |= BIT(mvif->mt76.idx); + phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); + + idx = MT7921_WTBL_RESERVED - mvif->mt76.idx; + + INIT_LIST_HEAD(&mvif->sta.stats_list); + INIT_LIST_HEAD(&mvif->sta.poll_list); + mvif->sta.wcid.idx = idx; + mvif->sta.wcid.ext_phy = mvif->mt76.band_idx; + mvif->sta.wcid.hw_key_idx = -1; + mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt7921_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + if (vif->txq) { + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + mtxq->wcid = &mvif->sta.wcid; + } + + if (vif->type != NL80211_IFTYPE_AP && + (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) + vif->offload_flags = 0; + + vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; + +out: + mt7921_mutex_release(dev); + + return ret; +} + +static void mt7921_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_sta *msta = &mvif->sta; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + int idx = msta->wcid.idx; + + if (vif == phy->monitor_vif) + phy->monitor_vif = NULL; + + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); + + if (dev->pm.enable) { + mt7921_mcu_set_bss_pm(dev, vif, false); + mt76_clear(dev, MT_WF_RFCR(0), + MT_WF_RFCR_DROP_OTHER_BEACON); + } + + mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, false); + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + + mt7921_mutex_acquire(dev); + dev->mt76.vif_mask &= ~BIT(mvif->mt76.idx); + phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); + mt7921_mutex_release(dev); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} + +int mt7921_set_channel(struct mt7921_phy *phy) +{ + struct mt7921_dev *dev = phy->dev; + int ret; + + cancel_delayed_work_sync(&phy->mt76->mac_work); + + mt7921_mutex_acquire(dev); + set_bit(MT76_RESET, &phy->mt76->state); + + mt76_set_channel(phy->mt76); + + ret = mt7921_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH); + if (ret) + goto out; + + mt7921_mac_set_timing(phy); + + mt7921_mac_reset_counters(phy); + phy->noise = 0; + +out: + clear_bit(MT76_RESET, &phy->mt76->state); + mt7921_mutex_release(dev); + + mt76_txq_schedule_all(phy->mt76); + + ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mt76->mac_work, + MT7921_WATCHDOG_TIME); + + return ret; +} + +static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_sta *msta = sta ? (struct mt7921_sta *)sta->drv_priv : + &mvif->sta; + struct mt76_wcid *wcid = &msta->wcid; + int idx = key->keyidx; + + /* The hardware does not support per-STA RX GTK, fallback + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + /* fall back to sw encryption for unsupported ciphers */ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + break; + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + case WLAN_CIPHER_SUITE_SMS4: + break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + default: + return -EOPNOTSUPP; + } + + if (cmd == SET_KEY) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + } else if (idx == wcid->hw_key_idx) { + wcid->hw_key_idx = -1; + } + mt76_wcid_key_setup(&dev->mt76, wcid, + cmd == SET_KEY ? key : NULL); + + return mt7921_mcu_add_key(dev, vif, msta, key, cmd); +} + +static int mt7921_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + bool band = phy != &dev->phy; + int ret; + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + ret = mt7921_set_channel(phy); + if (ret) + return ret; + ieee80211_wake_queues(hw); + } + + mt7921_mutex_acquire(dev); + + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); + + if (!enabled) + phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; + else + phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + + mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN, + enabled); + mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + } + + mt7921_mutex_release(dev); + + return 0; +} + +static int +mt7921_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + + /* no need to update right away, we'll get BSS_CHANGED_QOS */ + queue = mt7921_lmac_mapping(dev, queue); + mvif->queue_params[queue] = *params; + + return 0; +} + +static void mt7921_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + bool band = phy != &dev->phy; + u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | + MT_WF_RFCR1_DROP_BF_POLL | + MT_WF_RFCR1_DROP_BA | + MT_WF_RFCR1_DROP_CFEND | + MT_WF_RFCR1_DROP_CFACK; + u32 flags = 0; + +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + phy->rxfilter &= ~(_hw); \ + phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + + mt7921_mutex_acquire(dev); + + phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | + MT_WF_RFCR_DROP_OTHER_BEACON | + MT_WF_RFCR_DROP_FRAME_REPORT | + MT_WF_RFCR_DROP_PROBEREQ | + MT_WF_RFCR_DROP_MCAST_FILTERED | + MT_WF_RFCR_DROP_MCAST | + MT_WF_RFCR_DROP_BCAST | + MT_WF_RFCR_DROP_DUPLICATE | + MT_WF_RFCR_DROP_A2_BSSID | + MT_WF_RFCR_DROP_UNWANTED_CTL | + MT_WF_RFCR_DROP_STBC_MULTI); + + MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | + MT_WF_RFCR_DROP_A3_MAC | + MT_WF_RFCR_DROP_A3_BSSID); + + MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); + + MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | + MT_WF_RFCR_DROP_RTS | + MT_WF_RFCR_DROP_CTL_RSV | + MT_WF_RFCR_DROP_NDPA); + + *total_flags = flags; + mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + + if (*total_flags & FIF_CONTROL) + mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); + else + mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); + + mt7921_mutex_release(dev); +} + +static void mt7921_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = mt7921_hw_dev(hw); + + mt7921_mutex_acquire(dev); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + if (slottime != phy->slottime) { + phy->slottime = slottime; + mt7921_mac_set_timing(phy); + } + } + + /* ensure that enable txcmd_mode after bss_info */ + if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) + mt7921_mcu_set_tx(dev, vif); + + if (changed & BSS_CHANGED_PS) + mt7921_mcu_uni_bss_ps(dev, vif); + + mt7921_mutex_release(dev); +} + +int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + int ret, idx; + + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; + + INIT_LIST_HEAD(&msta->stats_list); + INIT_LIST_HEAD(&msta->poll_list); + msta->vif = mvif; + msta->wcid.sta = 1; + msta->wcid.idx = idx; + msta->wcid.ext_phy = mvif->mt76.band_idx; + msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->stats.jiffies = jiffies; + + ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); + if (ret) + return ret; + + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, + true); + + mt7921_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + ret = mt76_connac_mcu_add_sta_cmd(&dev->mphy, vif, sta, &msta->wcid, + true, MCU_UNI_CMD_STA_REC_UPDATE); + if (ret) + return ret; + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + + return 0; +} + +void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); + mt76_connac_pm_wake(&dev->mphy, &dev->pm); + + mt76_connac_mcu_add_sta_cmd(&dev->mphy, vif, sta, &msta->wcid, false, + MCU_UNI_CMD_STA_REC_UPDATE); + + mt7921_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + + mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, + false); + } + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + if (!list_empty(&msta->stats_list)) + list_del_init(&msta->stats_list); + spin_unlock_bh(&dev->sta_poll_lock); + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); +} + +static void +mt7921_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt76_phy *mphy = phy->mt76; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) + return; + + if (test_bit(MT76_STATE_PM, &mphy->state)) { + queue_work(dev->mt76.wq, &dev->pm.wake_work); + return; + } + + dev->pm.last_activity = jiffies; + mt76_worker_schedule(&dev->mt76.tx_worker); +} + +static void mt7921_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + int qid; + + if (control->sta) { + struct mt7921_sta *sta; + + sta = (struct mt7921_sta *)control->sta->drv_priv; + wcid = &sta->wcid; + } + + if (vif && !control->sta) { + struct mt7921_vif *mvif; + + mvif = (struct mt7921_vif *)vif->drv_priv; + wcid = &mvif->sta.wcid; + } + + if (!test_bit(MT76_STATE_PM, &mphy->state)) { + dev->pm.last_activity = jiffies; + mt76_tx(mphy, control->sta, wcid, skb); + return; + } + + qid = skb_get_queue_mapping(skb); + if (qid >= MT_TXQ_PSD) { + qid = IEEE80211_AC_BE; + skb_set_queue_mapping(skb, qid); + } + + mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); +} + +static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + + mt7921_mutex_acquire(dev); + mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, 0); + mt7921_mutex_release(dev); + + return 0; +} + +static int +mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + enum ieee80211_ampdu_mlme_action action = params->action; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct ieee80211_sta *sta = params->sta; + struct ieee80211_txq *txq = sta->txq[params->tid]; + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + u16 tid = params->tid; + u16 ssn = params->ssn; + struct mt76_txq *mtxq; + int ret = 0; + + if (!txq) + return -EINVAL; + + mtxq = (struct mt76_txq *)txq->drv_priv; + + mt7921_mutex_acquire(dev); + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, + params->buf_size); + mt7921_mcu_uni_rx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); + mt7921_mcu_uni_rx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + mt7921_mcu_uni_tx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->ampdu_state); + mt7921_mcu_uni_tx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_START: + set_bit(tid, &msta->ampdu_state); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->ampdu_state); + mt7921_mcu_uni_tx_ba(dev, params, false); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + mt7921_mutex_release(dev); + + return ret; +} + +static int +mt7921_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, + IEEE80211_STA_NONE); +} + +static int +mt7921_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, + IEEE80211_STA_NOTEXIST); +} + +static int +mt7921_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mib_stats *mib = &phy->mib; + + stats->dot11RTSSuccessCount = mib->rts_cnt; + stats->dot11RTSFailureCount = mib->rts_retries_cnt; + stats->dot11FCSErrorCount = mib->fcs_err_cnt; + stats->dot11ACKFailureCount = mib->ack_fail_cnt; + + return 0; +} + +static u64 +mt7921_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + u8 omac_idx = mvif->mt76.omac_idx; + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf; + u16 n; + + mt7921_mutex_acquire(dev); + + n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx; + /* TSF software read */ + mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE); + tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); + tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); + + mt7921_mutex_release(dev); + + return tsf.t64; +} + +static void +mt7921_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 timestamp) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + u8 omac_idx = mvif->mt76.omac_idx; + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + u16 n; + + mt7921_mutex_acquire(dev); + + n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx; + mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); + /* TSF software overwrite */ + mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_WRITE); + + mt7921_mutex_release(dev); +} + +static void +mt7921_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +{ + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = phy->dev; + + mt7921_mutex_acquire(dev); + phy->coverage_class = max_t(s16, coverage_class, 0); + mt7921_mac_set_timing(phy); + mt7921_mutex_release(dev); +} + +void mt7921_scan_work(struct work_struct *work) +{ + struct mt7921_phy *phy; + + phy = (struct mt7921_phy *)container_of(work, struct mt7921_phy, + scan_work.work); + + while (true) { + struct mt7921_mcu_rxd *rxd; + struct sk_buff *skb; + + spin_lock_bh(&phy->dev->mt76.lock); + skb = __skb_dequeue(&phy->scan_event_list); + spin_unlock_bh(&phy->dev->mt76.lock); + + if (!skb) + break; + + rxd = (struct mt7921_mcu_rxd *)skb->data; + if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) { + ieee80211_sched_scan_results(phy->mt76->hw); + } else if (test_and_clear_bit(MT76_HW_SCANNING, + &phy->mt76->state)) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + + ieee80211_scan_completed(phy->mt76->hw, &info); + } + dev_kfree_skb(skb); + } +} + +static int +mt7921_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + int err; + + mt7921_mutex_acquire(dev); + err = mt76_connac_mcu_hw_scan(mphy, vif, req); + mt7921_mutex_release(dev); + + return err; +} + +static void +mt7921_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + + mt7921_mutex_acquire(dev); + mt76_connac_mcu_cancel_hw_scan(mphy, vif); + mt7921_mutex_release(dev); +} + +static int +mt7921_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + int err; + + mt7921_mutex_acquire(dev); + + err = mt76_connac_mcu_sched_scan_req(mphy, vif, req); + if (err < 0) + goto out; + + err = mt76_connac_mcu_sched_scan_enable(mphy, vif, true); +out: + mt7921_mutex_release(dev); + + return err; +} + +static int +mt7921_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + int err; + + mt7921_mutex_acquire(dev); + err = mt76_connac_mcu_sched_scan_enable(mphy, vif, false); + mt7921_mutex_release(dev); + + return err; +} + +static int +mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + int max_nss = hweight8(hw->wiphy->available_antennas_tx); + + if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) + return -EINVAL; + + if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) + tx_ant = BIT(ffs(tx_ant) - 1) - 1; + + mt7921_mutex_acquire(dev); + + phy->mt76->antenna_mask = tx_ant; + phy->mt76->chainmask = tx_ant; + + mt76_set_stream_caps(phy->mt76, true); + mt7921_set_stream_he_caps(phy); + + mt7921_mutex_release(dev); + + return 0; +} + +static void +mt7921_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ +} + +static void mt7921_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + struct mt7921_sta_stats *stats = &msta->stats; + + if (!stats->tx_rate.legacy && !stats->tx_rate.flags) + return; + + if (stats->tx_rate.legacy) { + sinfo->txrate.legacy = stats->tx_rate.legacy; + } else { + sinfo->txrate.mcs = stats->tx_rate.mcs; + sinfo->txrate.nss = stats->tx_rate.nss; + sinfo->txrate.bw = stats->tx_rate.bw; + sinfo->txrate.he_gi = stats->tx_rate.he_gi; + sinfo->txrate.he_dcm = stats->tx_rate.he_dcm; + sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc; + } + sinfo->txrate.flags = stats->tx_rate.flags; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); +} + +#ifdef CONFIG_PM +static int mt7921_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + int err; + + cancel_delayed_work_sync(&phy->scan_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); + + cancel_delayed_work_sync(&dev->pm.ps_work); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + + mt7921_mutex_acquire(dev); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + set_bit(MT76_STATE_SUSPEND, &phy->mt76->state); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76_connac_mcu_set_suspend_iter, + &dev->mphy); + + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); + + mt7921_mutex_release(dev); + + return err; +} + +static int mt7921_resume(struct ieee80211_hw *hw) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); + int err; + + mt7921_mutex_acquire(dev); + + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); + if (err < 0) + goto out; + + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); + clear_bit(MT76_STATE_SUSPEND, &phy->mt76->state); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76_connac_mcu_set_suspend_iter, + &dev->mphy); + + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + MT7921_WATCHDOG_TIME); +out: + + mt7921_mutex_release(dev); + + return err; +} + +static void mt7921_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt76_dev *mdev = &dev->mt76; + + device_set_wakeup_enable(mdev->dev, enabled); +} + +static void mt7921_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) +{ + struct mt7921_dev *dev = mt7921_hw_dev(hw); + + mt7921_mutex_acquire(dev); + mt76_connac_mcu_update_gtk_rekey(hw, vif, data); + mt7921_mutex_release(dev); +} +#endif /* CONFIG_PM */ + +const struct ieee80211_ops mt7921_ops = { + .tx = mt7921_tx, + .start = mt7921_start, + .stop = mt7921_stop, + .add_interface = mt7921_add_interface, + .remove_interface = mt7921_remove_interface, + .config = mt7921_config, + .conf_tx = mt7921_conf_tx, + .configure_filter = mt7921_configure_filter, + .bss_info_changed = mt7921_bss_info_changed, + .sta_add = mt7921_sta_add, + .sta_remove = mt7921_sta_remove, + .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .sta_rc_update = mt7921_sta_rc_update, + .set_key = mt7921_set_key, + .ampdu_action = mt7921_ampdu_action, + .set_rts_threshold = mt7921_set_rts_threshold, + .wake_tx_queue = mt7921_wake_tx_queue, + .release_buffered_frames = mt76_release_buffered_frames, + .get_txpower = mt76_get_txpower, + .get_stats = mt7921_get_stats, + .get_tsf = mt7921_get_tsf, + .set_tsf = mt7921_set_tsf, + .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, + .set_antenna = mt7921_set_antenna, + .set_coverage_class = mt7921_set_coverage_class, + .hw_scan = mt7921_hw_scan, + .cancel_hw_scan = mt7921_cancel_hw_scan, + .sta_statistics = mt7921_sta_statistics, + .sched_scan_start = mt7921_start_sched_scan, + .sched_scan_stop = mt7921_stop_sched_scan, +#ifdef CONFIG_PM + .suspend = mt7921_suspend, + .resume = mt7921_resume, + .set_wakeup = mt7921_set_wakeup, + .set_rekey_data = mt7921_set_rekey_data, +#endif /* CONFIG_PM */ +}; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c new file mode 100644 index 000000000000..db125cd22b91 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -0,0 +1,1308 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include <linux/firmware.h> +#include <linux/fs.h> +#include "mt7921.h" +#include "mcu.h" +#include "mac.h" + +struct mt7921_patch_hdr { + char build_date[16]; + char platform[4]; + __be32 hw_sw_ver; + __be32 patch_ver; + __be16 checksum; + u16 reserved; + struct { + __be32 patch_ver; + __be32 subsys; + __be32 feature; + __be32 n_region; + __be32 crc; + u32 reserved[11]; + } desc; +} __packed; + +struct mt7921_patch_sec { + __be32 type; + __be32 offs; + __be32 size; + union { + __be32 spec[13]; + struct { + __be32 addr; + __be32 len; + __be32 sec_key_idx; + __be32 align_len; + u32 reserved[9]; + } info; + }; +} __packed; + +struct mt7921_fw_trailer { + u8 chip_id; + u8 eco_code; + u8 n_region; + u8 format_ver; + u8 format_flag; + u8 reserved[2]; + char fw_ver[10]; + char build_date[15]; + u32 crc; +} __packed; + +struct mt7921_fw_region { + __le32 decomp_crc; + __le32 decomp_len; + __le32 decomp_blk_sz; + u8 reserved[4]; + __le32 addr; + __le32 len; + u8 feature_set; + u8 reserved1[15]; +} __packed; + +#define MT_STA_BFER BIT(0) +#define MT_STA_BFEE BIT(1) + +#define FW_FEATURE_SET_ENCRYPT BIT(0) +#define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) +#define FW_FEATURE_ENCRY_MODE BIT(4) +#define FW_FEATURE_OVERRIDE_ADDR BIT(5) + +#define DL_MODE_ENCRYPT BIT(0) +#define DL_MODE_KEY_IDX GENMASK(2, 1) +#define DL_MODE_RESET_SEC_IV BIT(3) +#define DL_MODE_WORKING_PDA_CR4 BIT(4) +#define DL_CONFIG_ENCRY_MODE_SEL BIT(6) +#define DL_MODE_NEED_RSP BIT(31) + +#define FW_START_OVERRIDE BIT(0) +#define FW_START_WORKING_PDA_CR4 BIT(2) + +#define PATCH_SEC_TYPE_MASK GENMASK(15, 0) +#define PATCH_SEC_TYPE_INFO 0x2 + +#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) +#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) + +static enum mt7921_cipher_type +mt7921_mcu_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return MT_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return MT_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return MT_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return MT_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return MT_CIPHER_WAPI; + default: + return MT_CIPHER_NONE; + } +} + +static u8 mt7921_mcu_chan_bw(struct cfg80211_chan_def *chandef) +{ + static const u8 width_to_bw[] = { + [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, + [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, + [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, + [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, + [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, + [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, + [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, + [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, + }; + + if (chandef->width >= ARRAY_SIZE(width_to_bw)) + return 0; + + return width_to_bw[chandef->width]; +} + +static int +mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) +{ + struct mt7921_mcu_eeprom_info *res; + u8 *buf; + + if (!skb) + return -EINVAL; + + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + + res = (struct mt7921_mcu_eeprom_info *)skb->data; + buf = dev->eeprom.data + le32_to_cpu(res->addr); + memcpy(buf, res->data, 16); + + return 0; +} + +static int +mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq) +{ + struct mt7921_mcu_rxd *rxd; + int ret = 0; + + if (!skb) { + dev_err(mdev->dev, "Message %d (seq %d) timeout\n", + cmd, seq); + return -ETIMEDOUT; + } + + rxd = (struct mt7921_mcu_rxd *)skb->data; + if (seq != rxd->seq) + return -EAGAIN; + + switch (cmd) { + case MCU_CMD_PATCH_SEM_CONTROL: + skb_pull(skb, sizeof(*rxd) - 4); + ret = *skb->data; + break; + case MCU_EXT_CMD_GET_TEMP: + skb_pull(skb, sizeof(*rxd) + 4); + ret = le32_to_cpu(*(__le32 *)skb->data); + break; + case MCU_EXT_CMD_EFUSE_ACCESS: + ret = mt7921_mcu_parse_eeprom(mdev, skb); + break; + case MCU_UNI_CMD_DEV_INFO_UPDATE: + case MCU_UNI_CMD_BSS_INFO_UPDATE: + case MCU_UNI_CMD_STA_REC_UPDATE: + case MCU_UNI_CMD_HIF_CTRL: + case MCU_UNI_CMD_OFFLOAD: + case MCU_UNI_CMD_SUSPEND: { + struct mt7921_mcu_uni_event *event; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7921_mcu_uni_event *)skb->data; + ret = le32_to_cpu(event->status); + break; + } + case MCU_CMD_REG_READ: { + struct mt7921_mcu_reg_event *event; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7921_mcu_reg_event *)skb->data; + ret = (int)le32_to_cpu(event->val); + break; + } + default: + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + break; + } + + return ret; +} + +static int +mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *wait_seq) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + int txd_len, mcu_cmd = cmd & MCU_CMD_MASK; + enum mt76_mcuq_id txq = MT_MCUQ_WM; + struct mt7921_uni_txd *uni_txd; + struct mt7921_mcu_txd *mcu_txd; + __le32 *txd; + u32 val; + u8 seq; + + /* TODO: make dynamic based on msg type */ + mdev->mcu.timeout = 20 * HZ; + + seq = ++dev->mt76.mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mt76.mcu.msg_seq & 0xf; + + if (cmd == MCU_CMD_FW_SCATTER) { + txq = MT_MCUQ_FWDL; + goto exit; + } + + txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd); + txd = (__le32 *)skb_push(skb, txd_len); + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | + FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); + txd[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); + txd[1] = cpu_to_le32(val); + + if (cmd & MCU_UNI_PREFIX) { + uni_txd = (struct mt7921_uni_txd *)txd; + uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); + uni_txd->option = MCU_CMD_UNI_EXT_ACK; + uni_txd->cid = cpu_to_le16(mcu_cmd); + uni_txd->s2d_index = MCU_S2D_H2N; + uni_txd->pkt_type = MCU_PKT_ID; + uni_txd->seq = seq; + + goto exit; + } + + mcu_txd = (struct mt7921_mcu_txd *)txd; + mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); + mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, + MT_TX_MCU_PORT_RX_Q0)); + mcu_txd->pkt_type = MCU_PKT_ID; + mcu_txd->seq = seq; + + switch (cmd & ~MCU_CMD_MASK) { + case MCU_FW_PREFIX: + mcu_txd->set_query = MCU_Q_NA; + mcu_txd->cid = mcu_cmd; + break; + case MCU_CE_PREFIX: + if (cmd & MCU_QUERY_MASK) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + mcu_txd->cid = mcu_cmd; + break; + default: + mcu_txd->cid = MCU_CMD_EXT_CID; + if (cmd & MCU_QUERY_PREFIX || cmd == MCU_EXT_CMD_EFUSE_ACCESS) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + mcu_txd->ext_cid = mcu_cmd; + mcu_txd->ext_cid_ack = 1; + break; + } + + mcu_txd->s2d_index = MCU_S2D_H2N; + WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && + mcu_txd->set_query != MCU_Q_QUERY); + +exit: + if (wait_seq) + *wait_seq = seq; + + return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); +} + +static void +mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, + struct mt7921_mcu_peer_cap *peer, + struct rate_info *rate, u16 r) +{ + struct ieee80211_supported_band *sband; + u16 flags = 0; + u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r); + u8 gi = 0; + u8 bw = 0; + + rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r); + rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1; + + switch (peer->bw) { + case IEEE80211_STA_RX_BW_160: + gi = peer->g16; + break; + case IEEE80211_STA_RX_BW_80: + gi = peer->g8; + break; + case IEEE80211_STA_RX_BW_40: + gi = peer->g4; + break; + default: + gi = peer->g2; + break; + } + + gi = txmode >= MT_PHY_TYPE_HE_SU ? + FIELD_GET(MT_WTBL_RATE_HE_GI, gi) : + FIELD_GET(MT_WTBL_RATE_GI, gi); + + switch (txmode) { + case MT_PHY_TYPE_CCK: + case MT_PHY_TYPE_OFDM: + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + rate->legacy = sband->bitrates[rate->mcs].bitrate; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + flags |= RATE_INFO_FLAGS_MCS; + + if (gi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_VHT: + flags |= RATE_INFO_FLAGS_VHT_MCS; + + if (gi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + rate->he_gi = gi; + rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); + + flags |= RATE_INFO_FLAGS_HE_MCS; + break; + default: + break; + } + rate->flags = flags; + + bw = mt7921_mcu_chan_bw(&mphy->chandef) - FIELD_GET(MT_RA_RATE_BW, r); + + switch (bw) { + case IEEE80211_STA_RX_BW_160: + rate->bw = RATE_INFO_BW_160; + break; + case IEEE80211_STA_RX_BW_80: + rate->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_40: + rate->bw = RATE_INFO_BW_40; + break; + default: + rate->bw = RATE_INFO_BW_20; + break; + } +} + +static void +mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb, + u16 wlan_idx) +{ + struct mt7921_mcu_wlan_info_event *wtbl_info = + (struct mt7921_mcu_wlan_info_event *)(skb->data); + struct rate_info rate = {}; + u8 curr_idx = wtbl_info->rate_info.rate_idx; + u16 curr = le16_to_cpu(wtbl_info->rate_info.rate[curr_idx]); + struct mt7921_mcu_peer_cap peer = wtbl_info->peer_cap; + struct mt76_phy *mphy = &dev->mphy; + struct mt7921_sta_stats *stats; + struct mt7921_sta *msta; + struct mt76_wcid *wcid; + + if (wlan_idx >= MT76_N_WCIDS) + return; + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); + if (!wcid) { + stats->tx_rate = rate; + return; + } + + msta = container_of(wcid, struct mt7921_sta, wcid); + stats = &msta->stats; + + /* current rate */ + mt7921_mcu_tx_rate_parse(mphy, &peer, &rate, curr); + stats->tx_rate = rate; +} + +static void +mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; + + spin_lock_bh(&dev->mt76.lock); + __skb_queue_tail(&phy->scan_event_list, skb); + spin_unlock_bh(&dev->mt76.lock); + + ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, + MT7921_HW_SCAN_TIMEOUT); +} + +static void +mt7921_mcu_beacon_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt76_connac_beacon_loss_event *event; + struct mt76_phy *mphy; + u8 band_idx = 0; /* DBDC support */ + + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + event = (struct mt76_connac_beacon_loss_event *)skb->data; + if (band_idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; + else + mphy = &dev->mt76.phy; + + ieee80211_iterate_active_interfaces_atomic(mphy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76_connac_mcu_beacon_loss_iter, event); +} + +static void +mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_mcu_bss_event *event; + + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + event = (struct mt76_connac_mcu_bss_event *)skb->data; + if (event->is_absent) + ieee80211_stop_queues(mphy->hw); + else + ieee80211_wake_queues(mphy->hw); +} + +static void +mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; + struct debug_msg { + __le16 id; + u8 type; + u8 flag; + __le32 value; + __le16 len; + u8 content[512]; + } __packed * debug_msg; + u16 cur_len; + int i; + + skb_pull(skb, sizeof(*rxd)); + debug_msg = (struct debug_msg *)skb->data; + + cur_len = min_t(u16, le16_to_cpu(debug_msg->len), 512); + + if (debug_msg->type == 0x3) { + for (i = 0 ; i < cur_len; i++) + if (!debug_msg->content[i]) + debug_msg->content[i] = ' '; + + dev_dbg(dev->mt76.dev, "%s", debug_msg->content); + } +} + +static void +mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; + + switch (rxd->eid) { + case MCU_EVENT_BSS_BEACON_LOSS: + mt7921_mcu_beacon_loss_event(dev, skb); + break; + case MCU_EVENT_SCHED_SCAN_DONE: + case MCU_EVENT_SCAN_DONE: + mt7921_mcu_scan_event(dev, skb); + return; + case MCU_EVENT_BSS_ABSENCE: + mt7921_mcu_bss_event(dev, skb); + break; + case MCU_EVENT_DBG_MSG: + mt7921_mcu_debug_msg_event(dev, skb); + break; + case MCU_EVENT_COREDUMP: + mt76_connac_mcu_coredump_event(&dev->mt76, skb, + &dev->coredump); + return; + default: + break; + } + dev_kfree_skb(skb); +} + +void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; + + if (rxd->eid == 0x6) { + mt76_mcu_rx_event(&dev->mt76, skb); + return; + } + + if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || + rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || + rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || + rxd->eid == MCU_EVENT_BSS_ABSENCE || + rxd->eid == MCU_EVENT_SCAN_DONE || + rxd->eid == MCU_EVENT_DBG_MSG || + rxd->eid == MCU_EVENT_COREDUMP || + !rxd->seq) + mt7921_mcu_rx_unsolicited_event(dev, skb); + else + mt76_mcu_rx_event(&dev->mt76, skb); +} + +/** starec & wtbl **/ +static int +mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, + struct ieee80211_key_conf *key, enum set_key_cmd cmd) +{ + struct mt7921_sta_key_conf *bip = &msta->bip; + struct sta_rec_sec *sec; + struct tlv *tlv; + u32 len = sizeof(*sec); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); + + sec = (struct sta_rec_sec *)tlv; + sec->add = cmd; + + if (cmd == SET_KEY) { + struct sec_key *sec_key; + u8 cipher; + + cipher = mt7921_mcu_get_cipher(key->cipher); + if (cipher == MT_CIPHER_NONE) + return -EOPNOTSUPP; + + sec_key = &sec->key[0]; + sec_key->cipher_len = sizeof(*sec_key); + + if (cipher == MT_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MT_CIPHER_AES_CCMP; + sec_key->key_id = bip->keyidx; + sec_key->key_len = 16; + memcpy(sec_key->key, bip->key, 16); + + sec_key = &sec->key[1]; + sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; + sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_len = 16; + memcpy(sec_key->key, key->key, 16); + + sec->n_cipher = 2; + } else { + sec_key->cipher_id = cipher; + sec_key->key_id = key->keyidx; + sec_key->key_len = key->keylen; + memcpy(sec_key->key, key->key, key->keylen); + + if (cipher == MT_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec_key->key + 16, key->key + 24, 8); + memcpy(sec_key->key + 24, key->key + 16, 8); + } + + /* store key_conf for BIP batch update */ + if (cipher == MT_CIPHER_AES_CCMP) { + memcpy(bip->key, key->key, key->keylen); + bip->keyidx = key->keyidx; + } + + len -= sizeof(*sec_key); + sec->n_cipher = 1; + } + } else { + len -= sizeof(sec->key); + sec->n_cipher = 0; + } + sec->len = cpu_to_le16(len); + + return 0; +} + +int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, + struct mt7921_sta *msta, struct ieee80211_key_conf *key, + enum set_key_cmd cmd) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct sk_buff *skb; + int ret; + + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + &msta->wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = mt7921_mcu_sta_key_tlv(msta, skb, key, cmd); + if (ret) + return ret; + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD_STA_REC_UPDATE, true); +} + +int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable) +{ + struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; + + if (enable && !params->amsdu) + msta->wcid.amsdu = false; + + return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, + enable, true); +} + +int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable) +{ + struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv; + + return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, + enable, false); +} + +static int mt7921_mcu_restart(struct mt76_dev *dev) +{ + struct { + u8 power_mode; + u8 rsv[3]; + } req = { + .power_mode = 1, + }; + + return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req, + sizeof(req), false); +} + +static int mt7921_driver_own(struct mt7921_dev *dev) +{ + u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + + mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); + if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, + 0, 500)) { + dev_err(dev->mt76.dev, "Timeout for driver own\n"); + return -EIO; + } + + return 0; +} + +static int mt7921_load_patch(struct mt7921_dev *dev) +{ + const struct mt7921_patch_hdr *hdr; + const struct firmware *fw = NULL; + int i, ret, sem; + + sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); + switch (sem) { + case PATCH_IS_DL: + return 0; + case PATCH_NOT_DL_SEM_SUCCESS: + break; + default: + dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); + return -EAGAIN; + } + + ret = request_firmware(&fw, MT7921_ROM_PATCH, dev->mt76.dev); + if (ret) + goto out; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7921_patch_hdr *)(fw->data); + + dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", + be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); + + for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { + struct mt7921_patch_sec *sec; + const u8 *dl; + u32 len, addr; + + sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + + i * sizeof(*sec)); + if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != + PATCH_SEC_TYPE_INFO) { + ret = -EINVAL; + goto out; + } + + addr = be32_to_cpu(sec->info.addr); + len = be32_to_cpu(sec->info.len); + dl = fw->data + be32_to_cpu(sec->offs); + + ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, + DL_MODE_NEED_RSP); + if (ret) { + dev_err(dev->mt76.dev, "Download request failed\n"); + goto out; + } + + ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, + dl, len); + if (ret) { + dev_err(dev->mt76.dev, "Failed to send patch\n"); + goto out; + } + } + + ret = mt76_connac_mcu_start_patch(&dev->mt76); + if (ret) + dev_err(dev->mt76.dev, "Failed to start patch\n"); + +out: + sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); + switch (sem) { + case PATCH_REL_SEM_SUCCESS: + break; + default: + ret = -EAGAIN; + dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); + goto out; + } + release_firmware(fw); + + return ret; +} + +static u32 mt7921_mcu_gen_dl_mode(u8 feature_set, bool is_wa) +{ + u32 ret = 0; + + ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? + (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; + ret |= (feature_set & FW_FEATURE_ENCRY_MODE) ? + DL_CONFIG_ENCRY_MODE_SEL : 0; + ret |= FIELD_PREP(DL_MODE_KEY_IDX, + FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); + ret |= DL_MODE_NEED_RSP; + ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; + + return ret; +} + +static int +mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, + const struct mt7921_fw_trailer *hdr, + const u8 *data, bool is_wa) +{ + int i, offset = 0; + u32 override = 0, option = 0; + + for (i = 0; i < hdr->n_region; i++) { + const struct mt7921_fw_region *region; + int err; + u32 len, addr, mode; + + region = (const struct mt7921_fw_region *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); + mode = mt7921_mcu_gen_dl_mode(region->feature_set, is_wa); + len = le32_to_cpu(region->len); + addr = le32_to_cpu(region->addr); + + if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) + override = addr; + + err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, + mode); + if (err) { + dev_err(dev->mt76.dev, "Download request failed\n"); + return err; + } + + err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, + data + offset, len); + if (err) { + dev_err(dev->mt76.dev, "Failed to send firmware.\n"); + return err; + } + + offset += len; + } + + if (override) + option |= FW_START_OVERRIDE; + + if (is_wa) + option |= FW_START_WORKING_PDA_CR4; + + return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); +} + +static int mt7921_load_ram(struct mt7921_dev *dev) +{ + const struct mt7921_fw_trailer *hdr; + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, MT7921_FIRMWARE_WM, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size - + sizeof(*hdr)); + + dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false); + if (ret) { + dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); + goto out; + } + + snprintf(dev->mt76.hw->wiphy->fw_version, + sizeof(dev->mt76.hw->wiphy->fw_version), + "%.10s-%.15s", hdr->fw_ver, hdr->build_date); + +out: + release_firmware(fw); + + return ret; +} + +static int mt7921_load_firmware(struct mt7921_dev *dev) +{ + int ret; + + ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); + if (ret) { + dev_dbg(dev->mt76.dev, "Firmware is already download\n"); + return -EIO; + } + + ret = mt7921_load_patch(dev); + if (ret) + return ret; + + ret = mt7921_load_ram(dev); + if (ret) + return ret; + + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, + MT_TOP_MISC2_FW_N9_RDY, 1500)) { + dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); + + return -EIO; + } + + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); + +#ifdef CONFIG_PM + dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; +#endif /* CONFIG_PM */ + + clear_bit(MT76_STATE_PM, &dev->mphy.state); + + dev_err(dev->mt76.dev, "Firmware init done\n"); + + return 0; +} + +int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) +{ + struct { + u8 ctrl_val; + u8 pad[3]; + } data = { + .ctrl_val = ctrl + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FWLOG_2_HOST, &data, + sizeof(data), false); +} + +int mt7921_mcu_init(struct mt7921_dev *dev) +{ + static const struct mt76_mcu_ops mt7921_mcu_ops = { + .headroom = sizeof(struct mt7921_mcu_txd), + .mcu_skb_send_msg = mt7921_mcu_send_message, + .mcu_parse_response = mt7921_mcu_parse_response, + .mcu_restart = mt7921_mcu_restart, + }; + int ret; + + dev->mt76.mcu_ops = &mt7921_mcu_ops; + + ret = mt7921_driver_own(dev); + if (ret) + return ret; + + ret = mt7921_load_firmware(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + mt7921_mcu_fw_log_2_host(dev, 1); + + return 0; +} + +void mt7921_mcu_exit(struct mt7921_dev *dev) +{ + u32 reg = mt7921_reg_map_l1(dev, MT_TOP_MISC); + + __mt76_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, + FIELD_PREP(MT_TOP_MISC_FW_STATE, + FW_STATE_FW_DOWNLOAD), 1000)) { + dev_err(dev->mt76.dev, "Failed to exit mcu\n"); + return; + } + + reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + mt76_wr(dev, reg, MT_TOP_LPCR_HOST_FW_OWN); + skb_queue_purge(&dev->mt76.mcu.res_q); +} + +int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) +{ +#define WMM_AIFS_SET BIT(0) +#define WMM_CW_MIN_SET BIT(1) +#define WMM_CW_MAX_SET BIT(2) +#define WMM_TXOP_SET BIT(3) +#define WMM_PARAM_SET GENMASK(3, 0) +#define TX_CMD_MODE 1 + struct edca { + u8 queue; + u8 set; + u8 aifs; + u8 cw_min; + __le16 cw_max; + __le16 txop; + }; + struct mt7921_mcu_tx { + u8 total; + u8 action; + u8 valid; + u8 mode; + + struct edca edca[IEEE80211_NUM_ACS]; + } __packed req = { + .valid = true, + .mode = TX_CMD_MODE, + .total = IEEE80211_NUM_ACS, + }; + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + int ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; + struct edca *e = &req.edca[ac]; + + e->set = WMM_PARAM_SET; + e->queue = ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS; + e->aifs = q->aifs; + e->txop = cpu_to_le16(q->txop); + + if (q->cw_min) + e->cw_min = fls(q->cw_min); + else + e->cw_min = 5; + + if (q->cw_max) + e->cw_max = cpu_to_le16(fls(q->cw_max)); + else + e->cw_max = cpu_to_le16(10); + } + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, + sizeof(req), true); +} + +int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) +{ + struct mt7921_dev *dev = phy->dev; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + int freq1 = chandef->center_freq1; + struct { + u8 control_ch; + u8 center_ch; + u8 bw; + u8 tx_streams_num; + u8 rx_streams; /* mask or num */ + u8 switch_reason; + u8 band_idx; + u8 center_ch2; /* for 80+80 only */ + __le16 cac_case; + u8 channel_band; + u8 rsv0; + __le32 outband_freq; + u8 txpower_drop; + u8 ap_bw; + u8 ap_center_ch; + u8 rsv1[57]; + } __packed req = { + .control_ch = chandef->chan->hw_value, + .center_ch = ieee80211_frequency_to_channel(freq1), + .bw = mt7921_mcu_chan_bw(chandef), + .tx_streams_num = hweight8(phy->mt76->antenna_mask), + .rx_streams = phy->mt76->antenna_mask, + .band_idx = phy != &dev->phy, + .channel_band = chandef->chan->band, + }; + + if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; + else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && + chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) + req.switch_reason = CH_SWITCH_DFS; + else + req.switch_reason = CH_SWITCH_NORMAL; + + if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) + req.rx_streams = hweight8(req.rx_streams); + + if (chandef->width == NL80211_CHAN_WIDTH_80P80) { + int freq2 = chandef->center_freq2; + + req.center_ch2 = ieee80211_frequency_to_channel(freq2); + } + + return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); +} + +int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) +{ + struct req_hdr { + u8 buffer_mode; + u8 format; + __le16 len; + } __packed req = { + .buffer_mode = EE_MODE_EFUSE, + .format = EE_FORMAT_WHOLE, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, + &req, sizeof(req), true); +} + +int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) +{ + struct mt7921_mcu_eeprom_info req = { + .addr = cpu_to_le32(round_down(offset, 16)), + }; + struct mt7921_mcu_eeprom_info *res; + struct sk_buff *skb; + int ret; + u8 *buf; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, + sizeof(req), true, &skb); + if (ret) + return ret; + + res = (struct mt7921_mcu_eeprom_info *)skb->data; + buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); + memcpy(buf, res->data, 16); + dev_kfree_skb(skb); + + return 0; +} + +u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx) +{ + struct mt7921_mcu_wlan_info wtbl_info = { + .wlan_idx = cpu_to_le32(wlan_idx), + }; + struct sk_buff *skb; + int ret; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_WTBL, + &wtbl_info, sizeof(wtbl_info), true, + &skb); + if (ret) + return ret; + + mt7921_mcu_tx_rate_report(dev, skb, wlan_idx); + dev_kfree_skb(skb); + + return 0; +} + +int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct ps_tlv { + __le16 tag; + __le16 len; + u8 ps_state; /* 0: device awake + * 1: static power save + * 2: dynamic power saving + * 3: enter TWT power saving + * 4: leave TWT power saving + */ + u8 pad[3]; + } __packed ps; + } __packed ps_req = { + .hdr = { + .bss_idx = mvif->mt76.idx, + }, + .ps = { + .tag = cpu_to_le16(UNI_BSS_INFO_PS), + .len = cpu_to_le16(sizeof(struct ps_tlv)), + .ps_state = vif->bss_conf.ps ? 2 : 0, + }, + }; + + if (vif->type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, + &ps_req, sizeof(ps_req), true); +} + +int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, + bool enable) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct bcnft_tlv { + __le16 tag; + __le16 len; + __le16 bcn_interval; + u8 dtim_period; + u8 pad; + } __packed bcnft; + } __packed bcnft_req = { + .hdr = { + .bss_idx = mvif->mt76.idx, + }, + .bcnft = { + .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), + .len = cpu_to_le16(sizeof(struct bcnft_tlv)), + .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), + .dtim_period = vif->bss_conf.dtim_period, + }, + }; + + if (vif->type != NL80211_IFTYPE_STATION) + return 0; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, + &bcnft_req, sizeof(bcnft_req), true); +} + +int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, + bool enable) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct { + u8 bss_idx; + u8 dtim_period; + __le16 aid; + __le16 bcn_interval; + __le16 atim_window; + u8 uapsd; + u8 bmc_delivered_ac; + u8 bmc_triggered_ac; + u8 pad; + } req = { + .bss_idx = mvif->mt76.idx, + .aid = cpu_to_le16(vif->bss_conf.aid), + .dtim_period = vif->bss_conf.dtim_period, + .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), + }; + struct { + u8 bss_idx; + u8 pad[3]; + } req_hdr = { + .bss_idx = mvif->mt76.idx, + }; + int err; + + if (vif->type != NL80211_IFTYPE_STATION) + return 0; + + err = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, &req_hdr, + sizeof(req_hdr), false); + if (err < 0 || !enable) + return err; + + return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, &req, + sizeof(req), false); +} + +int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + int i; + + if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) + goto out; + + for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { + mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); + if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, + PCIE_LPCR_HOST_OWN_SYNC, 0, 50)) + break; + } + + if (i == MT7921_DRV_OWN_RETRY_COUNT) { + dev_err(dev->mt76.dev, "driver own failed\n"); + return -EIO; + } + +out: + dev->pm.last_activity = jiffies; + + return 0; +} + +int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + int i; + + if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) + return 0; + + for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { + mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); + if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, + PCIE_LPCR_HOST_OWN_SYNC, 4, 50)) + break; + } + + if (i == MT7921_DRV_OWN_RETRY_COUNT) { + dev_err(dev->mt76.dev, "firmware own failed\n"); + return -EIO; + } + + return 0; +} + +void +mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7921_phy *phy = priv; + struct mt7921_dev *dev = phy->dev; + + if (mt7921_mcu_set_bss_pm(dev, vif, dev->pm.enable)) + return; + + if (dev->pm.enable) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); + } else { + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); + } +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h new file mode 100644 index 000000000000..2fdc62367b3f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -0,0 +1,434 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7921_MCU_H +#define __MT7921_MCU_H + +#include "../mt76_connac_mcu.h" + +struct mt7921_mcu_txd { + __le32 txd[8]; + + __le16 len; + __le16 pq_id; + + u8 cid; + u8 pkt_type; + u8 set_query; /* FW don't care */ + u8 seq; + + u8 uc_d2b0_rev; + u8 ext_cid; + u8 s2d_index; + u8 ext_cid_ack; + + u32 reserved[5]; +} __packed __aligned(4); + +/** + * struct mt7921_uni_txd - mcu command descriptor for firmware v3 + * @txd: hardware descriptor + * @len: total length not including txd + * @cid: command identifier + * @pkt_type: must be 0xa0 (cmd packet by long format) + * @frag_n: fragment number + * @seq: sequence number + * @checksum: 0 mean there is no checksum + * @s2d_index: index for command source and destination + * Definition | value | note + * CMD_S2D_IDX_H2N | 0x00 | command from HOST to WM + * CMD_S2D_IDX_C2N | 0x01 | command from WA to WM + * CMD_S2D_IDX_H2C | 0x02 | command from HOST to WA + * CMD_S2D_IDX_H2N_AND_H2C | 0x03 | command from HOST to WA and WM + * + * @option: command option + * BIT[0]: UNI_CMD_OPT_BIT_ACK + * set to 1 to request a fw reply + * if UNI_CMD_OPT_BIT_0_ACK is set and UNI_CMD_OPT_BIT_2_SET_QUERY + * is set, mcu firmware will send response event EID = 0x01 + * (UNI_EVENT_ID_CMD_RESULT) to the host. + * BIT[1]: UNI_CMD_OPT_BIT_UNI_CMD + * 0: original command + * 1: unified command + * BIT[2]: UNI_CMD_OPT_BIT_SET_QUERY + * 0: QUERY command + * 1: SET command + */ +struct mt7921_uni_txd { + __le32 txd[8]; + + /* DW1 */ + __le16 len; + __le16 cid; + + /* DW2 */ + u8 reserved; + u8 pkt_type; + u8 frag_n; + u8 seq; + + /* DW3 */ + __le16 checksum; + u8 s2d_index; + u8 option; + + /* DW4 */ + u8 reserved2[4]; +} __packed __aligned(4); + +/* event table */ +enum { + MCU_EVENT_REG_ACCESS = 0x05, + MCU_EVENT_SCAN_DONE = 0x0d, + MCU_EVENT_BSS_ABSENCE = 0x11, + MCU_EVENT_BSS_BEACON_LOSS = 0x13, + MCU_EVENT_CH_PRIVILEGE = 0x18, + MCU_EVENT_SCHED_SCAN_DONE = 0x23, + MCU_EVENT_DBG_MSG = 0x27, + MCU_EVENT_COREDUMP = 0xf0, +}; + +/* ext event table */ +enum { + MCU_EXT_EVENT_RATE_REPORT = 0x87, +}; + +struct mt7921_mcu_rxd { + __le32 rxd[6]; + + __le16 len; + __le16 pkt_type_id; + + u8 eid; + u8 seq; + __le16 __rsv; + + u8 ext_eid; + u8 __rsv1[2]; + u8 s2d_index; +}; + +struct mt7921_mcu_eeprom_info { + __le32 addr; + __le32 valid; + u8 data[16]; +} __packed; + +#define MT_RA_RATE_NSS GENMASK(8, 6) +#define MT_RA_RATE_MCS GENMASK(3, 0) +#define MT_RA_RATE_TX_MODE GENMASK(12, 9) +#define MT_RA_RATE_DCM_EN BIT(4) +#define MT_RA_RATE_BW GENMASK(14, 13) + +#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) +#define MCU_PKT_ID 0xa0 + +enum { + MCU_Q_QUERY, + MCU_Q_SET, + MCU_Q_RESERVED, + MCU_Q_NA +}; + +enum { + MCU_S2D_H2N, + MCU_S2D_C2N, + MCU_S2D_H2C, + MCU_S2D_H2CN +}; + +struct mt7921_mcu_uni_event { + u8 cid; + u8 pad[3]; + __le32 status; /* 0: success, others: fail */ +} __packed; + +enum { + PATCH_NOT_DL_SEM_FAIL, + PATCH_IS_DL, + PATCH_NOT_DL_SEM_SUCCESS, + PATCH_REL_SEM_SUCCESS +}; + +enum { + FW_STATE_INITIAL, + FW_STATE_FW_DOWNLOAD, + FW_STATE_NORMAL_OPERATION, + FW_STATE_NORMAL_TRX, + FW_STATE_WACPU_RDY = 7 +}; + +enum { + EE_MODE_EFUSE, + EE_MODE_BUFFER, +}; + +enum { + EE_FORMAT_BIN, + EE_FORMAT_WHOLE, + EE_FORMAT_MULTIPLE, +}; + +enum { + MCU_PHY_STATE_TX_RATE, + MCU_PHY_STATE_RX_RATE, + MCU_PHY_STATE_RSSI, + MCU_PHY_STATE_CONTENTION_RX_RATE, + MCU_PHY_STATE_OFDMLQ_CNINFO, +}; + +#define STA_TYPE_STA BIT(0) +#define STA_TYPE_AP BIT(1) +#define STA_TYPE_ADHOC BIT(2) +#define STA_TYPE_WDS BIT(4) +#define STA_TYPE_BC BIT(5) + +#define NETWORK_INFRA BIT(16) +#define NETWORK_P2P BIT(17) +#define NETWORK_IBSS BIT(18) +#define NETWORK_WDS BIT(21) + +#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) +#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) +#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) +#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) +#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) +#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) +#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) + +struct sec_key { + u8 cipher_id; + u8 cipher_len; + u8 key_id; + u8 key_len; + u8 key[32]; +} __packed; + +struct sta_rec_sec { + __le16 tag; + __le16 len; + u8 add; + u8 n_cipher; + u8 rsv[2]; + + struct sec_key key[2]; +} __packed; + +enum mt7921_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_WEP104, + MT_CIPHER_WEP128, + MT_CIPHER_TKIP, + MT_CIPHER_AES_CCMP, + MT_CIPHER_CCMP_256, + MT_CIPHER_GCMP, + MT_CIPHER_GCMP_256, + MT_CIPHER_WAPI, + MT_CIPHER_BIP_CMAC_128, +}; + +enum { + CH_SWITCH_NORMAL = 0, + CH_SWITCH_SCAN = 3, + CH_SWITCH_MCC = 4, + CH_SWITCH_DFS = 5, + CH_SWITCH_BACKGROUND_SCAN_START = 6, + CH_SWITCH_BACKGROUND_SCAN_RUNNING = 7, + CH_SWITCH_BACKGROUND_SCAN_STOP = 8, + CH_SWITCH_SCAN_BYPASS_DPD = 9 +}; + +enum { + THERMAL_SENSOR_TEMP_QUERY, + THERMAL_SENSOR_MANUAL_CTRL, + THERMAL_SENSOR_INFO_QUERY, + THERMAL_SENSOR_TASK_CTRL, +}; + +enum { + MT_EBF = BIT(0), /* explicit beamforming */ + MT_IBF = BIT(1) /* implicit beamforming */ +}; + +#define MT7921_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_generic) + \ + sizeof(struct wtbl_rx) + \ + sizeof(struct wtbl_ht) + \ + sizeof(struct wtbl_vht) + \ + sizeof(struct wtbl_hdr_trans) +\ + sizeof(struct wtbl_ba) + \ + sizeof(struct wtbl_smps)) + +#define MT7921_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct sta_rec_basic) + \ + sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_he) + \ + sizeof(struct sta_rec_ba) + \ + sizeof(struct sta_rec_vht) + \ + sizeof(struct sta_rec_uapsd) + \ + sizeof(struct sta_rec_amsdu) + \ + sizeof(struct tlv) + \ + MT7921_WTBL_UPDATE_MAX_SIZE) + +#define MT7921_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_ba)) + +#define STA_CAP_WMM BIT(0) +#define STA_CAP_SGI_20 BIT(4) +#define STA_CAP_SGI_40 BIT(5) +#define STA_CAP_TX_STBC BIT(6) +#define STA_CAP_RX_STBC BIT(7) +#define STA_CAP_VHT_SGI_80 BIT(16) +#define STA_CAP_VHT_SGI_160 BIT(17) +#define STA_CAP_VHT_TX_STBC BIT(18) +#define STA_CAP_VHT_RX_STBC BIT(19) +#define STA_CAP_VHT_LDPC BIT(23) +#define STA_CAP_LDPC BIT(24) +#define STA_CAP_HT BIT(26) +#define STA_CAP_VHT BIT(27) +#define STA_CAP_HE BIT(28) + +struct mt7921_mcu_reg_event { + __le32 reg; + __le32 val; +} __packed; + +struct mt7921_mcu_tx_config { + u8 peer_addr[ETH_ALEN]; + u8 sw; + u8 dis_rx_hdr_tran; + + u8 aad_om; + u8 pfmu_idx; + __le16 partial_aid; + + u8 ibf; + u8 ebf; + u8 is_ht; + u8 is_vht; + + u8 mesh; + u8 baf_en; + u8 cf_ack; + u8 rdg_ba; + + u8 rdg; + u8 pm; + u8 rts; + u8 smps; + + u8 txop_ps; + u8 not_update_ipsm; + u8 skip_tx; + u8 ldpc; + + u8 qos; + u8 from_ds; + u8 to_ds; + u8 dyn_bw; + + u8 amdsu_cross_lg; + u8 check_per; + u8 gid_63; + u8 he; + + u8 vht_ibf; + u8 vht_ebf; + u8 vht_ldpc; + u8 he_ldpc; +} __packed; + +struct mt7921_mcu_sec_config { + u8 wpi_flag; + u8 rv; + u8 ikv; + u8 rkv; + + u8 rcid; + u8 rca1; + u8 rca2; + u8 even_pn; + + u8 key_id; + u8 muar_idx; + u8 cipher_suit; + u8 rsv[1]; +} __packed; + +struct mt7921_mcu_key_config { + u8 key[32]; +} __packed; + +struct mt7921_mcu_rate_info { + u8 mpdu_fail; + u8 mpdu_tx; + u8 rate_idx; + u8 rsv[1]; + __le16 rate[8]; +} __packed; + +struct mt7921_mcu_ba_config { + u8 ba_en; + u8 rsv[3]; + __le32 ba_winsize; +} __packed; + +struct mt7921_mcu_ant_id_config { + u8 ant_id[4]; +} __packed; + +struct mt7921_mcu_peer_cap { + struct mt7921_mcu_ant_id_config ant_id_config; + + u8 power_offset; + u8 bw_selector; + u8 change_bw_rate_n; + u8 bw; + u8 spe_idx; + + u8 g2; + u8 g4; + u8 g8; + u8 g16; + + u8 mmss; + u8 ampdu_factor; + u8 rsv[1]; +} __packed; + +struct mt7921_mcu_rx_cnt { + u8 rx_rcpi[4]; + u8 rx_cc[4]; + u8 rx_cc_sel; + u8 ce_rmsd; + u8 rsv[2]; +} __packed; + +struct mt7921_mcu_tx_cnt { + __le16 rate1_cnt; + __le16 rate1_fail_cnt; + __le16 rate2_cnt; + __le16 rate3_cnt; + __le16 cur_bw_tx_cnt; + __le16 cur_bw_tx_fail_cnt; + __le16 other_bw_tx_cnt; + __le16 other_bw_tx_fail_cnt; +} __packed; + +struct mt7921_mcu_wlan_info_event { + struct mt7921_mcu_tx_config tx_config; + struct mt7921_mcu_sec_config sec_config; + struct mt7921_mcu_key_config key_config; + struct mt7921_mcu_rate_info rate_info; + struct mt7921_mcu_ba_config ba_config; + struct mt7921_mcu_peer_cap peer_cap; + struct mt7921_mcu_rx_cnt rx_cnt; + struct mt7921_mcu_tx_cnt tx_cnt; +} __packed; + +struct mt7921_mcu_wlan_info { + __le32 wlan_idx; + struct mt7921_mcu_wlan_info_event event; +} __packed; +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h new file mode 100644 index 000000000000..46e6aeec35ae --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7921_H +#define __MT7921_H + +#include <linux/interrupt.h> +#include <linux/ktime.h> +#include "../mt76_connac_mcu.h" +#include "regs.h" + +#define MT7921_MAX_INTERFACES 4 +#define MT7921_MAX_WMM_SETS 4 +#define MT7921_WTBL_SIZE 20 +#define MT7921_WTBL_RESERVED (MT7921_WTBL_SIZE - 1) +#define MT7921_WTBL_STA (MT7921_WTBL_RESERVED - \ + MT7921_MAX_INTERFACES) + +#define MT7921_PM_TIMEOUT (HZ / 12) +#define MT7921_HW_SCAN_TIMEOUT (HZ / 10) +#define MT7921_WATCHDOG_TIME (HZ / 10) +#define MT7921_RESET_TIMEOUT (30 * HZ) + +#define MT7921_TX_RING_SIZE 2048 +#define MT7921_TX_MCU_RING_SIZE 256 +#define MT7921_TX_FWDL_RING_SIZE 128 + +#define MT7921_RX_RING_SIZE 1536 +#define MT7921_RX_MCU_RING_SIZE 512 + +#define MT7921_DRV_OWN_RETRY_COUNT 10 + +#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" +#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" + +#define MT7921_EEPROM_SIZE 3584 +#define MT7921_TOKEN_SIZE 8192 +#define MT7921_TOKEN_FREE_THR 64 + +#define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ +#define MT7921_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7921_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ +#define MT7921_2G_RATE_DEFAULT 0x0 /* CCK 1M */ + +#define MT7921_SKU_RATE_NUM 161 +#define MT7921_SKU_MAX_DELTA_IDX MT7921_SKU_RATE_NUM +#define MT7921_SKU_TABLE_SIZE (MT7921_SKU_RATE_NUM + 1) + +struct mt7921_vif; +struct mt7921_sta; + +enum mt7921_txq_id { + MT7921_TXQ_BAND0, + MT7921_TXQ_BAND1, + MT7921_TXQ_FWDL = 16, + MT7921_TXQ_MCU_WM, +}; + +enum mt7921_rxq_id { + MT7921_RXQ_BAND0 = 0, + MT7921_RXQ_BAND1, + MT7921_RXQ_MCU_WM = 0, +}; + +struct mt7921_sta_stats { + struct rate_info prob_rate; + struct rate_info tx_rate; + + unsigned long per; + unsigned long changed; + unsigned long jiffies; +}; + +struct mt7921_sta_key_conf { + s8 keyidx; + u8 key[16]; +}; + +struct mt7921_sta { + struct mt76_wcid wcid; /* must be first */ + + struct mt7921_vif *vif; + + struct list_head stats_list; + struct list_head poll_list; + u32 airtime_ac[8]; + + struct mt7921_sta_stats stats; + + unsigned long ampdu_state; + + struct mt7921_sta_key_conf bip; +}; + +struct mt7921_vif { + struct mt76_vif mt76; /* must be first */ + + struct mt7921_sta sta; + struct mt7921_phy *phy; + + struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; +}; + +struct mib_stats { + u16 ack_fail_cnt; + u16 fcs_err_cnt; + u16 rts_cnt; + u16 rts_retries_cnt; + u16 ba_miss_cnt; +}; + +struct mt7921_phy { + struct mt76_phy *mt76; + struct mt7921_dev *dev; + + struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; + + struct ieee80211_vif *monitor_vif; + + u32 rxfilter; + u64 omac_mask; + + u16 noise; + + s16 coverage_class; + u8 slottime; + + __le32 rx_ampdu_ts; + u32 ampdu_ref; + + struct mib_stats mib; + struct list_head stats_list; + + u8 sta_work_count; + + struct sk_buff_head scan_event_list; + struct delayed_work scan_work; +}; + +struct mt7921_dev { + union { /* must be first */ + struct mt76_dev mt76; + struct mt76_phy mphy; + }; + + const struct mt76_bus_ops *bus_ops; + struct mt7921_phy phy; + struct tasklet_struct irq_tasklet; + + u16 chainmask; + + struct work_struct init_work; + struct work_struct reset_work; + wait_queue_head_t reset_wait; + u32 reset_state; + + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + + spinlock_t token_lock; + int token_count; + struct idr token; + + u8 fw_debug; + + struct mt76_connac_pm pm; + struct mt76_connac_coredump coredump; +}; + +enum { + MT_LMAC_AC00, + MT_LMAC_AC01, + MT_LMAC_AC02, + MT_LMAC_AC03, + MT_LMAC_ALTX0 = 0x10, + MT_LMAC_BMC0, + MT_LMAC_BCN0, +}; + +static inline struct mt7921_phy * +mt7921_hw_phy(struct ieee80211_hw *hw) +{ + struct mt76_phy *phy = hw->priv; + + return phy->priv; +} + +static inline struct mt7921_dev * +mt7921_hw_dev(struct ieee80211_hw *hw) +{ + struct mt76_phy *phy = hw->priv; + + return container_of(phy->dev, struct mt7921_dev, mt76); +} + +#define mt7921_mutex_acquire(dev) \ + mt76_connac_mutex_acquire(&(dev)->mt76, &(dev)->pm) +#define mt7921_mutex_release(dev) \ + mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) + +static inline u8 mt7921_lmac_mapping(struct mt7921_dev *dev, u8 ac) +{ + /* LMAC uses the reverse order of mac80211 AC indexes */ + return 3 - ac; +} + +extern const struct ieee80211_ops mt7921_ops; +extern struct pci_driver mt7921_pci_driver; + +u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr); + +int mt7921_register_device(struct mt7921_dev *dev); +void mt7921_unregister_device(struct mt7921_dev *dev); +int mt7921_eeprom_init(struct mt7921_dev *dev); +void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy); +int mt7921_eeprom_get_target_power(struct mt7921_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx); +void mt7921_eeprom_init_sku(struct mt7921_dev *dev); +int mt7921_dma_init(struct mt7921_dev *dev); +void mt7921_dma_prefetch(struct mt7921_dev *dev); +void mt7921_dma_cleanup(struct mt7921_dev *dev); +int mt7921_mcu_init(struct mt7921_dev *dev); +int mt7921_mcu_add_bss_info(struct mt7921_phy *phy, + struct ieee80211_vif *vif, int enable); +int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, + struct mt7921_sta *msta, struct ieee80211_key_conf *key, + enum set_key_cmd cmd); +int mt7921_set_channel(struct mt7921_phy *phy); +int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd); +int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif); +int mt7921_mcu_set_eeprom(struct mt7921_dev *dev); +int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset); +int mt7921_mcu_get_rx_rate(struct mt7921_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct rate_info *rate); +int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl); +void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb); +void mt7921_mcu_exit(struct mt7921_dev *dev); + +static inline void mt7921_irq_enable(struct mt7921_dev *dev, u32 mask) +{ + mt76_set_irq_mask(&dev->mt76, 0, 0, mask); + + tasklet_schedule(&dev->irq_tasklet); +} + +static inline u32 +mt7921_reg_map_l1(struct mt7921_dev *dev, u32 addr) +{ + u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); + u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); + + mt76_rmw_field(dev, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, base); + /* use read to push write */ + mt76_rr(dev, MT_HIF_REMAP_L1); + + return MT_HIF_REMAP_BASE_L1 + offset; +} + +static inline u32 +mt7921_l1_rr(struct mt7921_dev *dev, u32 addr) +{ + return mt76_rr(dev, mt7921_reg_map_l1(dev, addr)); +} + +static inline void +mt7921_l1_wr(struct mt7921_dev *dev, u32 addr, u32 val) +{ + mt76_wr(dev, mt7921_reg_map_l1(dev, addr), val); +} + +static inline u32 +mt7921_l1_rmw(struct mt7921_dev *dev, u32 addr, u32 mask, u32 val) +{ + val |= mt7921_l1_rr(dev, addr) & ~mask; + mt7921_l1_wr(dev, addr, val); + + return val; +} + +#define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val) +#define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0) + +bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask); +void mt7921_mac_reset_counters(struct mt7921_phy *phy); +void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, bool beacon); +void mt7921_mac_set_timing(struct mt7921_phy *phy); +int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb); +void mt7921_mac_fill_rx_vector(struct mt7921_dev *dev, struct sk_buff *skb); +void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb); +int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt7921_mac_work(struct work_struct *work); +void mt7921_mac_reset_work(struct work_struct *work); +int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info); +void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); +int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc); +void mt7921_tx_token_put(struct mt7921_dev *dev); +void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); +void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); +void mt7921_stats_work(struct work_struct *work); +void mt7921_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *txwi); +void mt7921_set_stream_he_caps(struct mt7921_phy *phy); +void mt7921_update_channel(struct mt76_dev *mdev); +int mt7921_init_debugfs(struct mt7921_dev *dev); + +int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable); +int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable); +void mt7921_scan_work(struct work_struct *work); +u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx); +int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif); +int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, + bool enable); +int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, + bool enable); +int mt7921_mcu_update_arp_filter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info); +int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); +int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev); +void mt7921_pm_wake_work(struct work_struct *work); +void mt7921_pm_power_save_work(struct work_struct *work); +bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev); +int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy, + struct ieee80211_vif *vif, + bool enable); +void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); +void mt7921_coredump_work(struct work_struct *work); +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c new file mode 100644 index 000000000000..5570b4a50531 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include "mt7921.h" +#include "mac.h" +#include "mcu.h" +#include "../trace.h" + +static const struct pci_device_id mt7921_pci_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7961) }, + { }, +}; + +static void +mt7921_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + + if (q == MT_RXQ_MAIN) + mt7921_irq_enable(dev, MT_INT_RX_DONE_DATA); + else if (q == MT_RXQ_MCU_WA) + mt7921_irq_enable(dev, MT_INT_RX_DONE_WM2); + else + mt7921_irq_enable(dev, MT_INT_RX_DONE_WM); +} + +static irqreturn_t mt7921_irq_handler(int irq, void *dev_instance) +{ + struct mt7921_dev *dev = dev_instance; + + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return IRQ_NONE; + + tasklet_schedule(&dev->irq_tasklet); + + return IRQ_HANDLED; +} + +static void mt7921_irq_tasklet(unsigned long data) +{ + struct mt7921_dev *dev = (struct mt7921_dev *)data; + u32 intr, mask = 0; + + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); + + intr = mt76_rr(dev, MT_WFDMA0_HOST_INT_STA); + intr &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_WFDMA0_HOST_INT_STA, intr); + + trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); + + mask |= intr & MT_INT_RX_DONE_ALL; + if (intr & MT_INT_TX_DONE_MCU) + mask |= MT_INT_TX_DONE_MCU; + + mt76_set_irq_mask(&dev->mt76, MT_WFDMA0_HOST_INT_ENA, mask, 0); + + if (intr & MT_INT_TX_DONE_ALL) + napi_schedule(&dev->mt76.tx_napi); + + if (intr & MT_INT_RX_DONE_WM) + napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]); + + if (intr & MT_INT_RX_DONE_WM2) + napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]); + + if (intr & MT_INT_RX_DONE_DATA) + napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]); +} + +static int mt7921_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static const struct mt76_driver_ops drv_ops = { + /* txwi_size = txd size + txp size */ + .txwi_size = MT_TXD_SIZE + sizeof(struct mt7921_txp_common), + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | + MT_DRV_AMSDU_OFFLOAD, + .survey_flags = SURVEY_INFO_TIME_TX | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_BSS_RX, + .tx_prepare_skb = mt7921_tx_prepare_skb, + .tx_complete_skb = mt7921_tx_complete_skb, + .rx_skb = mt7921_queue_rx_skb, + .rx_poll_complete = mt7921_rx_poll_complete, + .sta_ps = mt7921_sta_ps, + .sta_add = mt7921_mac_sta_add, + .sta_remove = mt7921_mac_sta_remove, + .update_survey = mt7921_update_channel, + }; + struct mt7921_dev *dev; + struct mt76_dev *mdev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + goto err_free_pci_vec; + + mt76_pci_disable_aspm(pdev); + + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7921_ops, + &drv_ops); + if (!mdev) { + ret = -ENOMEM; + goto err_free_pci_vec; + } + + dev = container_of(mdev, struct mt7921_dev, mt76); + + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev); + mdev->rev = (mt7921_l1_rr(dev, MT_HW_CHIPID) << 16) | + (mt7921_l1_rr(dev, MT_HW_REV) & 0xff); + dev_err(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); + + mt7921_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + + ret = devm_request_irq(mdev->dev, pdev->irq, mt7921_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto err_free_dev; + + ret = mt7921_register_device(dev); + if (ret) + goto err_free_dev; + + return 0; + +err_free_dev: + mt76_free_device(&dev->mt76); +err_free_pci_vec: + pci_free_irq_vectors(pdev); + + return ret; +} + +static void mt7921_pci_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + + mt7921_unregister_device(dev); + devm_free_irq(&pdev->dev, pdev->irq, dev); + pci_free_irq_vectors(pdev); +} + +#ifdef CONFIG_PM +static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + bool hif_suspend; + int i, err; + + err = mt76_connac_pm_wake(&dev->mphy, &dev->pm); + if (err < 0) + return err; + + hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state); + if (hif_suspend) { + err = mt76_connac_mcu_set_hif_suspend(mdev, true); + if (err) + return err; + } + + napi_disable(&mdev->tx_napi); + mt76_worker_disable(&mdev->tx_worker); + + mt76_for_each_q_rx(mdev, i) { + napi_disable(&mdev->napi[i]); + } + tasklet_kill(&dev->irq_tasklet); + + pci_enable_wake(pdev, pci_choose_state(pdev, state), true); + + /* wait until dma is idle */ + mt76_poll(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | + MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000); + + /* put dma disabled */ + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + + /* disable interrupt */ + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); + + pci_save_state(pdev); + err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (err) + goto restore; + + err = mt7921_mcu_drv_pmctrl(dev); + if (err) + goto restore; + + return 0; + +restore: + mt76_for_each_q_rx(mdev, i) { + napi_enable(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + if (hif_suspend) + mt76_connac_mcu_set_hif_suspend(mdev, false); + + return err; +} + +static int mt7921_pci_resume(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + int i, err; + + err = mt7921_mcu_fw_pmctrl(dev); + if (err < 0) + return err; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + pci_restore_state(pdev); + + /* enable interrupt */ + mt7921_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_MCU_CMD); + + /* put dma enabled */ + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + + mt76_worker_enable(&mdev->tx_worker); + mt76_for_each_q_rx(mdev, i) { + napi_enable(&mdev->napi[i]); + napi_schedule(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + napi_schedule(&mdev->tx_napi); + + if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state)) + err = mt76_connac_mcu_set_hif_suspend(mdev, false); + + return err; +} +#endif /* CONFIG_PM */ + +struct pci_driver mt7921_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt7921_pci_device_table, + .probe = mt7921_pci_probe, + .remove = mt7921_pci_remove, +#ifdef CONFIG_PM + .suspend = mt7921_pci_suspend, + .resume = mt7921_pci_resume, +#endif /* CONFIG_PM */ +}; + +module_pci_driver(mt7921_pci_driver); + +MODULE_DEVICE_TABLE(pci, mt7921_pci_device_table); +MODULE_FIRMWARE(MT7921_FIRMWARE_WM); +MODULE_FIRMWARE(MT7921_ROM_PATCH); +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h new file mode 100644 index 000000000000..18980bb32dee --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h @@ -0,0 +1,419 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7921_REGS_H +#define __MT7921_REGS_H + +/* MCU WFDMA1 */ +#define MT_MCU_WFDMA1_BASE 0x3000 +#define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs)) + +#define MT_MCU_INT_EVENT MT_MCU_WFDMA1(0x108) +#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) +#define MT_MCU_INT_EVENT_DMA_INIT BIT(1) +#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2) +#define MT_MCU_INT_EVENT_RESET_DONE BIT(3) + +#define MT_PLE_BASE 0x8000 +#define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) + +#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) +#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) +#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) +#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc) + +#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ + ((n) << 2)) +#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) + +#define MT_MDP_BASE 0xf000 +#define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) + +#define MT_MDP_DCR0 MT_MDP(0x000) +#define MT_MDP_DCR0_DAMSDU_EN BIT(15) +#define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19) + +#define MT_MDP_DCR1 MT_MDP(0x004) +#define MT_MDP_DCR1_MAX_RX_LEN GENMASK(15, 3) + +#define MT_MDP_BNRCFR0(_band) MT_MDP(0x070 + ((_band) << 8)) +#define MT_MDP_RCFR0_MCU_RX_MGMT GENMASK(5, 4) +#define MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR GENMASK(7, 6) +#define MT_MDP_RCFR0_MCU_RX_CTL_BAR GENMASK(9, 8) + +#define MT_MDP_BNRCFR1(_band) MT_MDP(0x074 + ((_band) << 8)) +#define MT_MDP_RCFR1_MCU_RX_BYPASS GENMASK(23, 22) +#define MT_MDP_RCFR1_RX_DROPPED_UCAST GENMASK(28, 27) +#define MT_MDP_RCFR1_RX_DROPPED_MCAST GENMASK(30, 29) +#define MT_MDP_TO_HIF 0 +#define MT_MDP_TO_WM 1 + +/* TMAC: band 0(0x21000), band 1(0xa1000) */ +#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000) +#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) + +#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0) +#define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25) + +#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090) +#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094) +#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) +#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) + +#define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4) +#define MT_IFS_EIFS GENMASK(8, 0) +#define MT_IFS_RIFS GENMASK(14, 10) +#define MT_IFS_SIFS GENMASK(22, 16) +#define MT_IFS_SLOT GENMASK(30, 24) + +#define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4) +#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0) +#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) +#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) + +#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c) +#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0) + +#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00) +#define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs)) + +#define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000) +#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) +#define MT_DMA_DCR0_RXD_G5_EN BIT(23) + +/* LPON: band 0(0x24200), band 1(0xa4200) */ +#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200) +#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs)) + +#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080) +#define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, 0x084) + +#define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4) +#define MT_LPON_TCR_SW_MODE GENMASK(1, 0) +#define MT_LPON_TCR_SW_WRITE BIT(0) + +/* MIB: band 0(0x24800), band 1(0xa4800) */ +#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) +#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) + +#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) +#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) + +#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) +#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) +#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090) +#define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0) + +#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) +#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) +#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) +#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) + +#define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0) +#define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4) +#define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc) + +#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) +#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) +#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) + +#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4)) +#define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) +#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) + +#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4)) +#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0) + +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2)) +#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2)) +#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2)) +#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0)) + +#define MT_WTBLON_TOP_BASE 0x34000 +#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) +#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x0) +#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0) + +#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x030) +#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0) +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) +#define MT_WTBL_UPDATE_BUSY BIT(31) + +#define MT_WTBL_BASE 0x38000 +#define MT_WTBL_LMAC_ID GENMASK(14, 8) +#define MT_WTBL_LMAC_DW GENMASK(7, 2) +#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \ + FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \ + FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) + +/* AGG: band 0(0x20800), band 1(0xa0800) */ +#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800) +#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs)) + +#define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4) +#define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, 0x06c + (_n) * 4) +#define MT_AGG_PCR0_MM_PROT BIT(0) +#define MT_AGG_PCR0_GF_PROT BIT(1) +#define MT_AGG_PCR0_BW20_PROT BIT(2) +#define MT_AGG_PCR0_BW40_PROT BIT(4) +#define MT_AGG_PCR0_BW80_PROT BIT(6) +#define MT_AGG_PCR0_ERP_PROT GENMASK(12, 8) +#define MT_AGG_PCR0_VHT_PROT BIT(13) +#define MT_AGG_PCR0_PTA_WIN_DIS BIT(15) + +#define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23) +#define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0) + +#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084) +#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0) +#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) + +#define MT_AGG_MRCR(_band) MT_WF_AGG(_band, 0x098) +#define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12) +#define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6) +#define MT_AGG_MRCR_RTS_FAIL_LIMIT GENMASK(11, 7) +#define MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT GENMASK(28, 24) + +#define MT_AGG_ATCR1(_band) MT_WF_AGG(_band, 0x0f0) +#define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4) + +/* ARB: band 0(0x20c00), band 1(0xa0c00) */ +#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00) +#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs)) + +#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080) +#define MT_ARB_SCR_TX_DISABLE BIT(8) +#define MT_ARB_SCR_RX_DISABLE BIT(9) + +#define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4) + +/* RMAC: band 0(0x21400), band 1(0xa1400) */ +#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400) +#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs)) + +#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000) +#define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) +#define MT_WF_RFCR_DROP_FCSFAIL BIT(1) +#define MT_WF_RFCR_DROP_VERSION BIT(3) +#define MT_WF_RFCR_DROP_PROBEREQ BIT(4) +#define MT_WF_RFCR_DROP_MCAST BIT(5) +#define MT_WF_RFCR_DROP_BCAST BIT(6) +#define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) +#define MT_WF_RFCR_DROP_A3_MAC BIT(8) +#define MT_WF_RFCR_DROP_A3_BSSID BIT(9) +#define MT_WF_RFCR_DROP_A2_BSSID BIT(10) +#define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) +#define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) +#define MT_WF_RFCR_DROP_CTL_RSV BIT(13) +#define MT_WF_RFCR_DROP_CTS BIT(14) +#define MT_WF_RFCR_DROP_RTS BIT(15) +#define MT_WF_RFCR_DROP_DUPLICATE BIT(16) +#define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) +#define MT_WF_RFCR_DROP_OTHER_UC BIT(18) +#define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) +#define MT_WF_RFCR_DROP_NDPA BIT(20) +#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) + +#define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004) +#define MT_WF_RFCR1_DROP_ACK BIT(4) +#define MT_WF_RFCR1_DROP_BF_POLL BIT(5) +#define MT_WF_RFCR1_DROP_BA BIT(6) +#define MT_WF_RFCR1_DROP_CFEND BIT(7) +#define MT_WF_RFCR1_DROP_CFACK BIT(8) + +#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4) +#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) +#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) + +#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8) +#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) +#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) + +/* WFDMA0 */ +#define MT_WFDMA0_BASE 0xd4000 +#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) + +#define MT_WFDMA0_RST MT_WFDMA0(0x100) +#define MT_WFDMA0_RST_LOGIC_RST BIT(4) +#define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5) + +#define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c) +#define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) + +#define MT_MCU_CMD MT_WFDMA0(0x1f0) +#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1) +#define MT_MCU_CMD_STOP_DMA BIT(2) +#define MT_MCU_CMD_RESET_DONE BIT(3) +#define MT_MCU_CMD_RECOVERY_DONE BIT(4) +#define MT_MCU_CMD_NORMAL_STATE BIT(5) +#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) + +#define MT_WFDMA0_HOST_INT_STA MT_WFDMA0(0x200) +#define HOST_RX_DONE_INT_STS0 BIT(0) /* Rx mcu */ +#define HOST_RX_DONE_INT_STS2 BIT(2) /* Rx data */ +#define HOST_RX_DONE_INT_STS4 BIT(22) /* Rx mcu after fw downloaded */ +#define HOST_TX_DONE_INT_STS16 BIT(26) +#define HOST_TX_DONE_INT_STS17 BIT(27) /* MCU tx done*/ + +#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x204) +#define HOST_RX_DONE_INT_ENA0 BIT(0) +#define HOST_RX_DONE_INT_ENA1 BIT(1) +#define HOST_RX_DONE_INT_ENA2 BIT(2) +#define HOST_RX_DONE_INT_ENA3 BIT(3) +#define HOST_TX_DONE_INT_ENA0 BIT(4) +#define HOST_TX_DONE_INT_ENA1 BIT(5) +#define HOST_TX_DONE_INT_ENA2 BIT(6) +#define HOST_TX_DONE_INT_ENA3 BIT(7) +#define HOST_TX_DONE_INT_ENA4 BIT(8) +#define HOST_TX_DONE_INT_ENA5 BIT(9) +#define HOST_TX_DONE_INT_ENA6 BIT(10) +#define HOST_TX_DONE_INT_ENA7 BIT(11) +#define HOST_TX_DONE_INT_ENA8 BIT(12) +#define HOST_TX_DONE_INT_ENA9 BIT(13) +#define HOST_TX_DONE_INT_ENA10 BIT(14) +#define HOST_TX_DONE_INT_ENA11 BIT(15) +#define HOST_TX_DONE_INT_ENA12 BIT(16) +#define HOST_TX_DONE_INT_ENA13 BIT(17) +#define HOST_TX_DONE_INT_ENA14 BIT(18) +#define HOST_RX_COHERENT_EN BIT(20) +#define HOST_TX_COHERENT_EN BIT(21) +#define HOST_RX_DONE_INT_ENA4 BIT(22) +#define HOST_RX_DONE_INT_ENA5 BIT(23) +#define HOST_TX_DONE_INT_ENA16 BIT(26) +#define HOST_TX_DONE_INT_ENA17 BIT(27) +#define MCU2HOST_SW_INT_ENA BIT(29) +#define HOST_TX_DONE_INT_ENA18 BIT(30) + +/* WFDMA interrupt */ +#define MT_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2 +#define MT_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA0 +#define MT_INT_RX_DONE_WM2 HOST_RX_DONE_INT_ENA4 +#define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_DATA | \ + MT_INT_RX_DONE_WM | \ + MT_INT_RX_DONE_WM2) +#define MT_INT_TX_DONE_MCU_WM HOST_TX_DONE_INT_ENA17 +#define MT_INT_TX_DONE_FWDL HOST_TX_DONE_INT_ENA16 +#define MT_INT_TX_DONE_BAND0 HOST_TX_DONE_INT_ENA0 +#define MT_INT_MCU_CMD MCU2HOST_SW_INT_ENA + +#define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WM | \ + MT_INT_TX_DONE_FWDL) +#define MT_INT_TX_DONE_ALL (MT_INT_TX_DONE_MCU_WM | \ + MT_INT_TX_DONE_BAND0 | \ + GENMASK(18, 4)) + +#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) +#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY BIT(1) +#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) +#define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY BIT(3) +#define MT_WFDMA0_GLO_CFG_TX_WB_DDONE BIT(6) +#define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) +#define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN BIT(15) +#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) +#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) +#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) +#define MT_WFDMA0_GLO_CFG_CLK_GAT_DIS BIT(30) + +#define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) +#define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) +#define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE BIT(6) +#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) + +#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x520) + +#define MT_WFDMA0_TX_RING0_EXT_CTRL MT_WFDMA0(0x600) +#define MT_WFDMA0_TX_RING1_EXT_CTRL MT_WFDMA0(0x604) +#define MT_WFDMA0_TX_RING2_EXT_CTRL MT_WFDMA0(0x608) +#define MT_WFDMA0_TX_RING3_EXT_CTRL MT_WFDMA0(0x60c) +#define MT_WFDMA0_TX_RING4_EXT_CTRL MT_WFDMA0(0x610) +#define MT_WFDMA0_TX_RING5_EXT_CTRL MT_WFDMA0(0x614) +#define MT_WFDMA0_TX_RING6_EXT_CTRL MT_WFDMA0(0x618) +#define MT_WFDMA0_TX_RING16_EXT_CTRL MT_WFDMA0(0x640) +#define MT_WFDMA0_TX_RING17_EXT_CTRL MT_WFDMA0(0x644) + +#define MT_WFDMA0_RX_RING0_EXT_CTRL MT_WFDMA0(0x680) +#define MT_WFDMA0_RX_RING1_EXT_CTRL MT_WFDMA0(0x684) +#define MT_WFDMA0_RX_RING2_EXT_CTRL MT_WFDMA0(0x688) +#define MT_WFDMA0_RX_RING3_EXT_CTRL MT_WFDMA0(0x68c) +#define MT_WFDMA0_RX_RING4_EXT_CTRL MT_WFDMA0(0x690) +#define MT_WFDMA0_RX_RING5_EXT_CTRL MT_WFDMA0(0x694) + +#define MT_TX_RING_BASE MT_WFDMA0(0x300) +#define MT_RX_EVENT_RING_BASE MT_WFDMA0(0x500) + +/* WFDMA CSR */ +#define MT_WFDMA_EXT_CSR_BASE 0xd7000 +#define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs)) +#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) +#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) + +#define MT_INFRA_CFG_BASE 0xfe000 +#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs)) + +#define MT_HIF_REMAP_L1 MT_INFRA(0x260) +#define MT_HIF_REMAP_L1_MASK GENMASK(15, 0) +#define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0) +#define MT_HIF_REMAP_L1_BASE GENMASK(31, 16) +#define MT_HIF_REMAP_BASE_L1 0xe0000 + +#define MT_SWDEF_BASE 0x41f200 +#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs)) +#define MT_SWDEF_MODE MT_SWDEF(0x3c) +#define MT_SWDEF_NORMAL_MODE 0 +#define MT_SWDEF_ICAP_MODE 1 +#define MT_SWDEF_SPECTRUM_MODE 2 + +#define MT_TOP_BASE 0x18060000 +#define MT_TOP(ofs) (MT_TOP_BASE + (ofs)) + +#define MT_TOP_LPCR_HOST_BAND0 MT_TOP(0x10) +#define MT_TOP_LPCR_HOST_FW_OWN BIT(0) +#define MT_TOP_LPCR_HOST_DRV_OWN BIT(1) + +#define MT_TOP_MISC MT_TOP(0xf0) +#define MT_TOP_MISC_FW_STATE GENMASK(2, 0) + +#define MT_HW_BOUND 0x70010020 +#define MT_HW_CHIPID 0x70010200 +#define MT_HW_REV 0x70010204 + +#define MT_PCIE_MAC_BASE 0x74030000 +#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) +#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) + +#define MT_DMA_SHDL(ofs) (0xd6000 + (ofs)) +#define MT_DMASHDL_SW_CONTROL MT_DMA_SHDL(0x004) +#define MT_DMASHDL_DMASHDL_BYPASS BIT(28) +#define MT_DMASHDL_OPTIONAL MT_DMA_SHDL(0x008) +#define MT_DMASHDL_PAGE MT_DMA_SHDL(0x00c) +#define MT_DMASHDL_REFILL MT_DMA_SHDL(0x010) +#define MT_DMASHDL_PKT_MAX_SIZE MT_DMA_SHDL(0x01c) +#define MT_DMASHDL_PKT_MAX_SIZE_PLE GENMASK(11, 0) +#define MT_DMASHDL_PKT_MAX_SIZE_PSE GENMASK(27, 16) + +#define MT_DMASHDL_GROUP_QUOTA(_n) MT_DMA_SHDL(0x020 + ((_n) << 2)) +#define MT_DMASHDL_GROUP_QUOTA_MIN GENMASK(11, 0) +#define MT_DMASHDL_GROUP_QUOTA_MAX GENMASK(27, 16) + +#define MT_DMASHDL_Q_MAP(_n) MT_DMA_SHDL(0x060 + ((_n) << 2)) +#define MT_DMASHDL_Q_MAP_MASK GENMASK(3, 0) +#define MT_DMASHDL_Q_MAP_SHIFT(_n) (4 * ((_n) % 8)) + +#define MT_DMASHDL_SCHED_SET(_n) MT_DMA_SHDL(0x070 + ((_n) << 2)) + +#define MT_CONN_ON_LPCTL 0x7c060010 +#define PCIE_LPCR_HOST_OWN_SYNC BIT(2) +#define PCIE_LPCR_HOST_CLR_OWN BIT(1) +#define PCIE_LPCR_HOST_SET_OWN BIT(0) + +#define MT_CONN_ON_MISC 0x7c0600f0 +#define MT_TOP_MISC2_FW_N9_RDY GENMASK(1, 0) + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index 581eb56dc4be..cc769645afa5 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -14,18 +14,23 @@ static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED }, + [MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 }, + [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 }, [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 }, }; -void mt76_testmode_tx_pending(struct mt76_dev *dev) +void mt76_testmode_tx_pending(struct mt76_phy *phy) { - struct mt76_testmode_data *td = &dev->test; + struct mt76_testmode_data *td = &phy->test; + struct mt76_dev *dev = phy->dev; struct mt76_wcid *wcid = &dev->global_wcid; - struct mt76_phy *phy = &dev->phy; struct sk_buff *skb = td->tx_skb; struct mt76_queue *q; + u16 tx_queued_limit; int qid; if (!skb || !td->tx_pending) @@ -34,9 +39,12 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev) qid = skb_get_queue_mapping(skb); q = phy->q_tx[qid]; + tx_queued_limit = td->tx_queued_limit ? td->tx_queued_limit : 1000; + spin_lock_bh(&q->lock); - while (td->tx_pending > 0 && td->tx_queued - td->tx_done < 1000 && + while (td->tx_pending > 0 && + td->tx_queued - td->tx_done < tx_queued_limit && q->queued < q->ndesc / 2) { int ret; @@ -56,10 +64,9 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev) static int -mt76_testmode_tx_init(struct mt76_dev *dev) +mt76_testmode_tx_init(struct mt76_phy *phy) { - struct mt76_testmode_data *td = &dev->test; - struct mt76_phy *phy = &dev->phy; + struct mt76_testmode_data *td = &phy->test; struct ieee80211_tx_info *info; struct ieee80211_hdr *hdr; struct sk_buff *skb; @@ -67,6 +74,7 @@ mt76_testmode_tx_init(struct mt76_dev *dev) IEEE80211_FCTL_FROMDS; struct ieee80211_tx_rate *rate; u8 max_nss = hweight8(phy->antenna_mask); + bool ext_phy = phy != &phy->dev->phy; if (td->tx_antenna_mask) max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask)); @@ -88,6 +96,9 @@ mt76_testmode_tx_init(struct mt76_dev *dev) IEEE80211_TX_CTL_NO_ACK | IEEE80211_TX_CTL_NO_PS_BUFFER; + if (ext_phy) + info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; + if (td->tx_rate_mode > MT76_TM_TX_MODE_VHT) goto out; @@ -166,9 +177,10 @@ out: } static void -mt76_testmode_tx_start(struct mt76_dev *dev) +mt76_testmode_tx_start(struct mt76_phy *phy) { - struct mt76_testmode_data *td = &dev->test; + struct mt76_testmode_data *td = &phy->test; + struct mt76_dev *dev = phy->dev; td->tx_queued = 0; td->tx_done = 0; @@ -177,9 +189,10 @@ mt76_testmode_tx_start(struct mt76_dev *dev) } static void -mt76_testmode_tx_stop(struct mt76_dev *dev) +mt76_testmode_tx_stop(struct mt76_phy *phy) { - struct mt76_testmode_data *td = &dev->test; + struct mt76_testmode_data *td = &phy->test; + struct mt76_dev *dev = phy->dev; mt76_worker_disable(&dev->tx_worker); @@ -187,7 +200,8 @@ mt76_testmode_tx_stop(struct mt76_dev *dev) mt76_worker_enable(&dev->tx_worker); - wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, 10 * HZ); + wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, + MT76_TM_TIMEOUT * HZ); dev_kfree_skb(td->tx_skb); td->tx_skb = NULL; @@ -206,9 +220,9 @@ mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx) } static void -mt76_testmode_init_defaults(struct mt76_dev *dev) +mt76_testmode_init_defaults(struct mt76_phy *phy) { - struct mt76_testmode_data *td = &dev->test; + struct mt76_testmode_data *td = &phy->test; if (td->tx_msdu_len > 0) return; @@ -220,49 +234,50 @@ mt76_testmode_init_defaults(struct mt76_dev *dev) } static int -__mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state) +__mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state) { - enum mt76_testmode_state prev_state = dev->test.state; + enum mt76_testmode_state prev_state = phy->test.state; + struct mt76_dev *dev = phy->dev; int err; if (prev_state == MT76_TM_STATE_TX_FRAMES) - mt76_testmode_tx_stop(dev); + mt76_testmode_tx_stop(phy); if (state == MT76_TM_STATE_TX_FRAMES) { - err = mt76_testmode_tx_init(dev); + err = mt76_testmode_tx_init(phy); if (err) return err; } - err = dev->test_ops->set_state(dev, state); + err = dev->test_ops->set_state(phy, state); if (err) { if (state == MT76_TM_STATE_TX_FRAMES) - mt76_testmode_tx_stop(dev); + mt76_testmode_tx_stop(phy); return err; } if (state == MT76_TM_STATE_TX_FRAMES) - mt76_testmode_tx_start(dev); + mt76_testmode_tx_start(phy); else if (state == MT76_TM_STATE_RX_FRAMES) { - memset(&dev->test.rx_stats, 0, sizeof(dev->test.rx_stats)); + memset(&phy->test.rx_stats, 0, sizeof(phy->test.rx_stats)); } - dev->test.state = state; + phy->test.state = state; return 0; } -int mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state) +int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state) { - struct mt76_testmode_data *td = &dev->test; - struct ieee80211_hw *hw = dev->phy.hw; + struct mt76_testmode_data *td = &phy->test; + struct ieee80211_hw *hw = phy->hw; if (state == td->state && state == MT76_TM_STATE_OFF) return 0; if (state > MT76_TM_STATE_OFF && - (!test_bit(MT76_STATE_RUNNING, &dev->phy.state) || + (!test_bit(MT76_STATE_RUNNING, &phy->state) || !(hw->conf.flags & IEEE80211_CONF_MONITOR))) return -ENOTCONN; @@ -270,12 +285,12 @@ int mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state td->state != MT76_TM_STATE_IDLE) { int ret; - ret = __mt76_testmode_set_state(dev, MT76_TM_STATE_IDLE); + ret = __mt76_testmode_set_state(phy, MT76_TM_STATE_IDLE); if (ret) return ret; } - return __mt76_testmode_set_state(dev, state); + return __mt76_testmode_set_state(phy, state); } EXPORT_SYMBOL(mt76_testmode_set_state); @@ -301,8 +316,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; - struct mt76_testmode_data *td = &dev->test; + struct mt76_testmode_data *td = &phy->test; struct nlattr *tb[NUM_MT76_TM_ATTRS]; + bool ext_phy = phy != &dev->phy; u32 state; int err; int i; @@ -320,11 +336,11 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mutex); if (tb[MT76_TM_ATTR_RESET]) { - mt76_testmode_set_state(dev, MT76_TM_STATE_OFF); + mt76_testmode_set_state(phy, MT76_TM_STATE_OFF); memset(td, 0, sizeof(*td)); } - mt76_testmode_init_defaults(dev); + mt76_testmode_init_defaults(phy); if (tb[MT76_TM_ATTR_TX_COUNT]) td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]); @@ -350,12 +366,21 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_STBC], &td->tx_rate_stbc, 0, 1) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_LTF], &td->tx_ltf, 0, 2) || - mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, 1, - phy->antenna_mask) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, + 1 << (ext_phy * 2), phy->antenna_mask << (ext_phy * 2)) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_SPE_IDX], &td->tx_spe_idx, 0, 27) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE], + &td->tx_duty_cycle, 0, 99) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL], &td->tx_power_control, 0, 1)) goto out; + if (tb[MT76_TM_ATTR_TX_IPG]) + td->tx_ipg = nla_get_u32(tb[MT76_TM_ATTR_TX_IPG]); + + if (tb[MT76_TM_ATTR_TX_TIME]) + td->tx_time = nla_get_u32(tb[MT76_TM_ATTR_TX_TIME]); + if (tb[MT76_TM_ATTR_FREQ_OFFSET]) td->freq_offset = nla_get_u32(tb[MT76_TM_ATTR_FREQ_OFFSET]); @@ -382,7 +407,7 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (dev->test_ops->set_params) { - err = dev->test_ops->set_params(dev, tb, state); + err = dev->test_ops->set_params(phy, tb, state); if (err) goto out; } @@ -393,7 +418,7 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, err = 0; if (tb[MT76_TM_ATTR_STATE]) - err = mt76_testmode_set_state(dev, state); + err = mt76_testmode_set_state(phy, state); out: mutex_unlock(&dev->mutex); @@ -403,9 +428,10 @@ out: EXPORT_SYMBOL(mt76_testmode_cmd); static int -mt76_testmode_dump_stats(struct mt76_dev *dev, struct sk_buff *msg) +mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg) { - struct mt76_testmode_data *td = &dev->test; + struct mt76_testmode_data *td = &phy->test; + struct mt76_dev *dev = phy->dev; u64 rx_packets = 0; u64 rx_fcs_error = 0; int i; @@ -425,7 +451,7 @@ mt76_testmode_dump_stats(struct mt76_dev *dev, struct sk_buff *msg) return -EMSGSIZE; if (dev->test_ops->dump_stats) - return dev->test_ops->dump_stats(dev, msg); + return dev->test_ops->dump_stats(phy, msg); return 0; } @@ -435,7 +461,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; - struct mt76_testmode_data *td = &dev->test; + struct mt76_testmode_data *td = &phy->test; struct nlattr *tb[NUM_MT76_TM_ATTRS] = {}; int err = 0; void *a; @@ -461,22 +487,22 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, a = nla_nest_start(msg, MT76_TM_ATTR_STATS); if (a) { - err = mt76_testmode_dump_stats(dev, msg); + err = mt76_testmode_dump_stats(phy, msg); nla_nest_end(msg, a); } goto out; } - mt76_testmode_init_defaults(dev); + mt76_testmode_init_defaults(phy); err = -EMSGSIZE; if (nla_put_u32(msg, MT76_TM_ATTR_STATE, td->state)) goto out; - if (td->mtd_name && - (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, td->mtd_name) || - nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, td->mtd_offset))) + if (dev->test_mtd.name && + (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) || + nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset))) goto out; if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) || @@ -491,6 +517,14 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) && nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_SPE_IDX) && + nla_put_u8(msg, MT76_TM_ATTR_TX_SPE_IDX, td->tx_spe_idx)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_DUTY_CYCLE) && + nla_put_u8(msg, MT76_TM_ATTR_TX_DUTY_CYCLE, td->tx_duty_cycle)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_IPG) && + nla_put_u32(msg, MT76_TM_ATTR_TX_IPG, td->tx_ipg)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_TIME) && + nla_put_u32(msg, MT76_TM_ATTR_TX_TIME, td->tx_time)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) && nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) && diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h index 7efad685a17c..e0c706ce9b42 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/testmode.h @@ -5,6 +5,8 @@ #ifndef __MT76_TESTMODE_H #define __MT76_TESTMODE_H +#define MT76_TM_TIMEOUT 10 + /** * enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA * @@ -35,6 +37,13 @@ * @MT76_TM_ATTR_FREQ_OFFSET: RF frequency offset (u32) * * @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr) + * + * @MT76_TM_ATTR_TX_SPE_IDX: tx spatial extension index (u8) + * + * @MT76_TM_ATTR_TX_DUTY_CYCLE: packet tx duty cycle (u8) + * @MT76_TM_ATTR_TX_IPG: tx inter-packet gap, in unit of us (u32) + * @MT76_TM_ATTR_TX_TIME: packet transmission time, in unit of us (u32) + * */ enum mt76_testmode_attr { MT76_TM_ATTR_UNSPEC, @@ -63,6 +72,12 @@ enum mt76_testmode_attr { MT76_TM_ATTR_STATS, + MT76_TM_ATTR_TX_SPE_IDX, + + MT76_TM_ATTR_TX_DUTY_CYCLE, + MT76_TM_ATTR_TX_IPG, + MT76_TM_ATTR_TX_TIME, + /* keep last */ NUM_MT76_TM_ATTRS, MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1, @@ -128,12 +143,14 @@ enum mt76_testmode_rx_attr { * @MT76_TM_STATE_IDLE: test mode enabled, but idle * @MT76_TM_STATE_TX_FRAMES: send a fixed number of test frames * @MT76_TM_STATE_RX_FRAMES: receive packets and keep statistics + * @MT76_TM_STATE_TX_CONT: waveform tx without time gap */ enum mt76_testmode_state { MT76_TM_STATE_OFF, MT76_TM_STATE_IDLE, MT76_TM_STATE_TX_FRAMES, MT76_TM_STATE_RX_FRAMES, + MT76_TM_STATE_TX_CONT, /* keep last */ NUM_MT76_TM_STATES, diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 25627e70bdad..b8fe8adc43a3 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -202,16 +202,22 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *sk struct ieee80211_hw *hw; struct sk_buff_head list; + mt76_tx_check_non_aql(dev, wcid_idx, skb); + #ifdef CONFIG_NL80211_TESTMODE - if (skb == dev->test.tx_skb) { - dev->test.tx_done++; - if (dev->test.tx_queued == dev->test.tx_done) + if (mt76_is_testmode_skb(dev, skb, &hw)) { + struct mt76_phy *phy = hw->priv; + + if (skb == phy->test.tx_skb) + phy->test.tx_done++; + if (phy->test.tx_queued == phy->test.tx_done) wake_up(&dev->tx_wait); + + ieee80211_free_txskb(hw, skb); + return; } #endif - mt76_tx_check_non_aql(dev, wcid_idx, skb); - if (!skb->prev) { hw = mt76_tx_status_get_hw(dev, skb); ieee80211_free_txskb(hw, skb); @@ -261,7 +267,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, int qid = skb_get_queue_mapping(skb); bool ext_phy = phy != &dev->phy; - if (mt76_testmode_enabled(dev)) { + if (mt76_testmode_enabled(phy)) { ieee80211_free_txskb(phy->hw, skb); return; } @@ -454,7 +460,6 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) struct mt76_wcid *wcid; int ret = 0; - spin_lock_bh(&q->lock); while (1) { if (test_bit(MT76_STATE_PM, &phy->state) || test_bit(MT76_RESET, &phy->state)) { @@ -464,14 +469,9 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) if (dev->queue_ops->tx_cleanup && q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) { - spin_unlock_bh(&q->lock); dev->queue_ops->tx_cleanup(dev, q, false); - spin_lock_bh(&q->lock); } - if (mt76_txq_stopped(q)) - break; - txq = ieee80211_next_txq(phy->hw, qid); if (!txq) break; @@ -481,6 +481,8 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) if (wcid && test_bit(MT_WCID_FLAG_PS, &wcid->flags)) continue; + spin_lock_bh(&q->lock); + if (mtxq->send_bar && mtxq->aggr) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); struct ieee80211_sta *sta = txq->sta; @@ -494,10 +496,13 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) spin_lock_bh(&q->lock); } - ret += mt76_txq_send_burst(phy, q, mtxq); + if (!mt76_txq_stopped(q)) + ret += mt76_txq_send_burst(phy, q, mtxq); + + spin_unlock_bh(&q->lock); + ieee80211_return_txq(phy->hw, txq, false); } - spin_unlock_bh(&q->lock); return ret; } @@ -539,8 +544,10 @@ void mt76_tx_worker(struct mt76_worker *w) mt76_txq_schedule_all(dev->phy2); #ifdef CONFIG_NL80211_TESTMODE - if (dev->test.tx_pending) - mt76_testmode_tx_pending(dev); + if (dev->phy.test.tx_pending) + mt76_testmode_tx_pending(&dev->phy); + if (dev->phy2 && dev->phy2->test.tx_pending) + mt76_testmode_tx_pending(dev->phy2); #endif } diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index b95d093728b9..30bc54e98c58 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -612,6 +612,7 @@ static void mt76u_complete_rx(struct urb *urb) case -ECONNRESET: case -ESHUTDOWN: case -ENOENT: + case -EPROTO: return; default: dev_err_ratelimited(dev->dev, "rx urb failed: %d\n", |