diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7921/mcu.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 203 |
1 files changed, 110 insertions, 93 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 67dc4b4cc094..c2c4dc196802 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -88,28 +88,28 @@ struct mt7921_fw_region { #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 +static enum mcu_cipher_type mt7921_mcu_get_cipher(int cipher) { switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; + return MCU_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; + return MCU_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; + return MCU_CIPHER_TKIP; case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; + return MCU_CIPHER_BIP_CMAC_128; case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; + return MCU_CIPHER_AES_CCMP; case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; + return MCU_CIPHER_CCMP_256; case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; + return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; + return MCU_CIPHER_GCMP_256; case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; + return MCU_CIPHER_WAPI; default: return MT_CIPHER_NONE; } @@ -399,43 +399,6 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, } 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 mt76_phy *mphy = &dev->mphy; - struct mt7921_sta_stats *stats; - struct rate_info rate = {}; - struct mt7921_sta *msta; - struct mt76_wcid *wcid; - u8 idx; - - if (wlan_idx >= MT76_N_WCIDS) - return; - - wtbl_info = (struct mt7921_mcu_wlan_info_event *)skb->data; - idx = wtbl_info->rate_info.rate_idx; - if (idx >= ARRAY_SIZE(wtbl_info->rate_info.rate)) - return; - - rcu_read_lock(); - - wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); - if (!wcid) - goto out; - - msta = container_of(wcid, struct mt7921_sta, wcid); - stats = &msta->stats; - - /* current rate */ - mt7921_mcu_tx_rate_parse(mphy, &wtbl_info->peer_cap, &rate, - le16_to_cpu(wtbl_info->rate_info.rate[idx])); - stats->tx_rate = rate; -out: - rcu_read_unlock(); -} - -static void mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; @@ -450,22 +413,33 @@ mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) } static void -mt7921_mcu_beacon_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) +mt7921_mcu_connection_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_connection_loss(vif); +} + +static void +mt7921_mcu_connection_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 */ + struct mt76_phy *mphy = &dev->mt76.phy; 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); + mt7921_mcu_connection_loss_iter, event); } static void @@ -524,13 +498,56 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) } static void +mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_mcu_tx_done_event *event; + struct mt7921_sta *msta; + struct mt7921_phy *mphy = &dev->phy; + struct mt7921_mcu_peer_cap peer; + struct ieee80211_sta *sta; + LIST_HEAD(list); + + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + event = (struct mt7921_mcu_tx_done_event *)skb->data; + + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&mphy->stats_list, &list); + + while (!list_empty(&list)) { + msta = list_first_entry(&list, struct mt7921_sta, stats_list); + list_del_init(&msta->stats_list); + + if (msta->wcid.idx != event->wlan_idx) + continue; + + spin_unlock_bh(&dev->sta_poll_lock); + + sta = wcid_to_sta(&msta->wcid); + + /* peer config based on IEEE SPEC */ + memset(&peer, 0x0, sizeof(peer)); + peer.bw = event->bw; + peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); + peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); + peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); + peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); + mt7921_mcu_tx_rate_parse(mphy->mt76, &peer, + &msta->stats.tx_rate, event->tx_rate); + + spin_lock_bh(&dev->sta_poll_lock); + break; + } + spin_unlock_bh(&dev->sta_poll_lock); +} + +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); + mt7921_mcu_connection_loss_event(dev, skb); break; case MCU_EVENT_SCHED_SCAN_DONE: case MCU_EVENT_SCAN_DONE: @@ -549,6 +566,9 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) case MCU_EVENT_LP_INFO: mt7921_mcu_low_power_event(dev, skb); break; + case MCU_EVENT_TX_DONE: + mt7921_mcu_tx_done_event(dev, skb); + break; default: break; } @@ -569,6 +589,7 @@ void mt7921_mcu_rx_event(struct mt7921_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_TX_DONE || rxd->eid == MCU_EVENT_DBG_MSG || rxd->eid == MCU_EVENT_COREDUMP || rxd->eid == MCU_EVENT_LP_INFO || @@ -604,14 +625,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, 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; + if (cipher == MCU_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MCU_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_id = MCU_CIPHER_BIP_CMAC_128; sec_key->cipher_len = sizeof(*sec_key); sec_key->key_len = 16; memcpy(sec_key->key, key->key, 16); @@ -623,14 +644,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, sec_key->key_len = key->keylen; memcpy(sec_key->key, key->key, key->keylen); - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MCU_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) { + if (cipher == MCU_CIPHER_AES_CCMP) { memcpy(bip->key, key->key, key->keylen); bip->keyidx = key->keyidx; } @@ -934,8 +955,6 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) 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; @@ -969,7 +988,7 @@ int mt7921_run_firmware(struct mt7921_dev *dev) set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt7921_mcu_fw_log_2_host(dev, 1); - return 0; + return mt76_connac_mcu_get_nic_capability(&dev->mphy); } int mt7921_mcu_init(struct mt7921_dev *dev) @@ -1136,26 +1155,6 @@ int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) 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; @@ -1268,8 +1267,9 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, sizeof(req), false); } -int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, bool enable) +int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, bool enable, + enum mt76_sta_info_state state) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; int rssi = -ewma_rssi_read(&mvif->rssi); @@ -1278,27 +1278,25 @@ int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, .vif = vif, .enable = enable, .cmd = MCU_UNI_CMD_STA_REC_UPDATE, + .state = state, + .offload_fw = true, .rcpi = to_rcpi(rssi), }; struct mt7921_sta *msta; msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL; info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; + info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; - return mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info); + return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); } -int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) +int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int i, err = 0; - mutex_lock(&pm->mutex); - - if (!test_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, @@ -1319,6 +1317,22 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) pm->stats.doze_time += pm->stats.last_wake_event - pm->stats.last_doze_event; out: + return err; +} + +int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int err = 0; + + mutex_lock(&pm->mutex); + + if (!test_bit(MT76_STATE_PM, &mphy->state)) + goto out; + + err = __mt7921_mcu_drv_pmctrl(dev); +out: mutex_unlock(&pm->mutex); if (err) @@ -1368,6 +1382,7 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt7921_phy *phy = priv; struct mt7921_dev *dev = phy->dev; + struct ieee80211_hw *hw = mt76_hw(dev); int ret; if (dev->pm.enable) @@ -1380,9 +1395,11 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (dev->pm.enable) { vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + ieee80211_hw_set(hw, CONNECTION_MONITOR); mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); } else { vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); } } |