diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mac80211.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mac80211.c | 233 |
1 files changed, 190 insertions, 43 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 62807dc311c1..6de13d641438 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -178,14 +178,19 @@ static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { { .start_freq = 5350, .end_freq = 5470, }, { .start_freq = 5470, .end_freq = 5725, }, { .start_freq = 5725, .end_freq = 5950, }, + { .start_freq = 5945, .end_freq = 6165, }, + { .start_freq = 6165, .end_freq = 6405, }, + { .start_freq = 6405, .end_freq = 6525, }, + { .start_freq = 6525, .end_freq = 6705, }, + { .start_freq = 6705, .end_freq = 6865, }, + { .start_freq = 6865, .end_freq = 7125, }, }; -const struct cfg80211_sar_capa mt76_sar_capa = { +static const struct cfg80211_sar_capa mt76_sar_capa = { .type = NL80211_SAR_TYPE_POWER, .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), .freq_ranges = &mt76_sar_freq_ranges[0], }; -EXPORT_SYMBOL_GPL(mt76_sar_capa); static int mt76_led_init(struct mt76_dev *dev) { @@ -211,6 +216,7 @@ static int mt76_led_init(struct mt76_dev *dev) if (!of_property_read_u32(np, "led-sources", &led_pin)) dev->led_pin = led_pin; dev->led_al = of_property_read_bool(np, "led-active-low"); + of_node_put(np); } return led_classdev_register(dev->dev, &dev->led_cdev); @@ -249,6 +255,8 @@ static void mt76_init_stream_cap(struct mt76_phy *phy, vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; else vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; + vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; for (i = 0; i < 8; i++) { if (i < nstream) @@ -259,6 +267,9 @@ static void mt76_init_stream_cap(struct mt76_phy *phy, } vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW)) + vht_cap->vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); } void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) @@ -324,8 +335,6 @@ mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_SHORT_GI_80 | - IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | - IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); return 0; @@ -393,7 +402,7 @@ mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, phy->hw->wiphy->bands[band] = NULL; } -static void +static int mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) { struct mt76_dev *dev = phy->dev; @@ -411,8 +420,15 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); - wiphy->available_antennas_tx = dev->phy.antenna_mask; - wiphy->available_antennas_rx = dev->phy.antenna_mask; + wiphy->available_antennas_tx = phy->antenna_mask; + wiphy->available_antennas_rx = phy->antenna_mask; + + wiphy->sar_capa = &mt76_sar_capa; + phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, + sizeof(struct mt76_freq_range_power), + GFP_KERNEL); + if (!phy->frp) + return -ENOMEM; hw->txq_data_size = sizeof(struct mt76_txq); hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; @@ -432,11 +448,13 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + + return 0; } struct mt76_phy * mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, - const struct ieee80211_ops *ops) + const struct ieee80211_ops *ops, u8 band_idx) { struct ieee80211_hw *hw; unsigned int phy_size; @@ -451,6 +469,7 @@ mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, phy->dev = dev; phy->hw = hw; phy->priv = hw->priv + phy_size; + phy->band_idx = band_idx; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->interface_modes = @@ -472,7 +491,9 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht, { int ret; - mt76_phy_init(phy, phy->hw); + ret = mt76_phy_init(phy, phy->hw); + if (ret) + return ret; if (phy->cap.has_2ghz) { ret = mt76_init_sband_2g(phy, rates, n_rates); @@ -501,7 +522,7 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht, if (ret) return ret; - phy->dev->phy2 = phy; + phy->dev->phys[phy->band_idx] = phy; return 0; } @@ -513,7 +534,7 @@ void mt76_unregister_phy(struct mt76_phy *phy) mt76_tx_status_check(dev, true); ieee80211_unregister_hw(phy->hw); - dev->phy2 = NULL; + dev->phys[phy->band_idx] = NULL; } EXPORT_SYMBOL_GPL(mt76_unregister_phy); @@ -535,10 +556,13 @@ mt76_alloc_device(struct device *pdev, unsigned int size, dev->hw = hw; dev->dev = pdev; dev->drv = drv_ops; + dev->dma_dev = pdev; phy = &dev->phy; phy->dev = dev; phy->hw = hw; + phy->band_idx = MT_BAND0; + dev->phys[phy->band_idx] = phy; spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); @@ -569,6 +593,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, INIT_LIST_HEAD(&dev->wcid_list); INIT_LIST_HEAD(&dev->txwi_cache); + dev->token_size = dev->drv->token_size; for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) skb_queue_head_init(&dev->rx_skb[i]); @@ -591,7 +616,9 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, int ret; dev_set_drvdata(dev->dev, dev); - mt76_phy_init(phy, hw); + ret = mt76_phy_init(phy, hw); + if (ret) + return ret; if (phy->cap.has_2ghz) { ret = mt76_init_sband_2g(phy, rates, n_rates); @@ -717,7 +744,7 @@ static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy); + struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx); if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { dev_kfree_skb(skb); @@ -811,6 +838,10 @@ void mt76_set_channel(struct mt76_phy *phy) wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); mt76_update_survey(phy); + if (phy->chandef.chan->center_freq != chandef->chan->center_freq || + phy->chandef.width != chandef->width) + phy->dfs_state = MT_DFS_STATE_UNKNOWN; + phy->chandef = *chandef; phy->chan_state = mt76_channel_state(phy, chandef->chan); @@ -916,6 +947,36 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, } EXPORT_SYMBOL(mt76_wcid_key_setup); +static int +mt76_rx_signal(struct mt76_rx_status *status) +{ + s8 *chain_signal = status->chain_signal; + int signal = -128; + u8 chains; + + for (chains = status->chains; chains; chains >>= 1, chain_signal++) { + int cur, diff; + + cur = *chain_signal; + if (!(chains & BIT(0)) || + cur > 0) + continue; + + if (cur > signal) + swap(cur, signal); + + diff = signal - cur; + if (diff == 0) + signal += 3; + else if (diff <= 2) + signal += 2; + else if (diff <= 6) + signal += 1; + } + + return signal; +} + static void mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_hw **hw, @@ -944,6 +1005,9 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, status->ampdu_reference = mstat.ampdu_ref; status->device_timestamp = mstat.timestamp; status->mactime = mstat.timestamp; + status->signal = mt76_rx_signal(&mstat); + if (status->signal <= -128) + status->flag |= RX_FLAG_NO_SIGNAL_VAL; if (ieee80211_is_beacon(hdr->frame_control) || ieee80211_is_probe_resp(hdr->frame_control)) @@ -956,10 +1020,10 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, sizeof(mstat.chain_signal)); *sta = wcid_to_sta(mstat.wcid); - *hw = mt76_phy_hw(dev, mstat.ext_phy); + *hw = mt76_phy_hw(dev, mstat.phy_idx); } -static int +static void mt76_check_ccmp_pn(struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -969,10 +1033,13 @@ mt76_check_ccmp_pn(struct sk_buff *skb) int ret; if (!(status->flag & RX_FLAG_DECRYPTED)) - return 0; + return; + + if (status->flag & RX_FLAG_ONLY_MONITOR) + return; if (!wcid || !wcid->rx_check_pn) - return 0; + return; security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; if (status->flag & RX_FLAG_8023) @@ -986,7 +1053,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) */ if (ieee80211_is_frag(hdr) && !ieee80211_is_first_frag(hdr->frame_control)) - return 0; + return; } /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): @@ -1003,15 +1070,15 @@ skip_hdr_check: BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], sizeof(status->iv)); - if (ret <= 0) - return -EINVAL; /* replay */ + if (ret <= 0) { + status->flag |= RX_FLAG_ONLY_MONITOR; + return; + } memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); if (status->flag & RX_FLAG_IV_STRIPPED) status->flag |= RX_FLAG_PN_VALIDATED; - - return 0; } static void @@ -1116,7 +1183,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; bool ps; - hw = mt76_phy_hw(dev, status->ext_phy); + hw = mt76_phy_hw(dev, status->phy_idx); if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && !(status->flag & RX_FLAG_8023)) { sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); @@ -1163,10 +1230,12 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) if (ps) set_bit(MT_WCID_FLAG_PS, &wcid->flags); - else - clear_bit(MT_WCID_FLAG_PS, &wcid->flags); dev->drv->sta_ps(dev, sta, ps); + + if (!ps) + clear_bit(MT_WCID_FLAG_PS, &wcid->flags); + ieee80211_sta_ps_transition(sta, ps); } @@ -1182,11 +1251,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, while ((skb = __skb_dequeue(frames)) != NULL) { struct sk_buff *nskb = skb_shinfo(skb)->frag_list; - if (mt76_check_ccmp_pn(skb)) { - dev_kfree_skb(skb); - continue; - } - + mt76_check_ccmp_pn(skb); skb_shinfo(skb)->frag_list = NULL; mt76_rx_convert(dev, skb, &hw, &sta); ieee80211_rx_list(hw, sta, skb, &list); @@ -1232,10 +1297,11 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); static int -mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool ext_phy) +mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + struct mt76_dev *dev = phy->dev; int ret; int i; @@ -1252,13 +1318,13 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, continue; mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; - mtxq->wcid = wcid; + mtxq->wcid = wcid->idx; } ewma_signal_init(&wcid->rssi); - if (ext_phy) + if (phy->band_idx == MT_BAND1) mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); - wcid->ext_phy = ext_phy; + wcid->phy_idx = phy->band_idx; rcu_assign_pointer(dev->wcid[wcid->idx], wcid); mt76_packet_id_init(wcid); @@ -1303,11 +1369,10 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; - bool ext_phy = phy != &dev->phy; if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) - return mt76_sta_add(dev, vif, sta, ext_phy); + return mt76_sta_add(phy, vif, sta); if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && @@ -1330,7 +1395,9 @@ void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; mutex_lock(&dev->mutex); + spin_lock_bh(&dev->status_lock); rcu_assign_pointer(dev->wcid[wcid->idx], NULL); + spin_unlock_bh(&dev->status_lock); mutex_unlock(&dev->mutex); } EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); @@ -1348,10 +1415,63 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76_get_txpower); +int mt76_init_sar_power(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar) +{ + struct mt76_phy *phy = hw->priv; + const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; + int i; + + if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) + return -EINVAL; + + for (i = 0; i < sar->num_sub_specs; i++) { + u32 index = sar->sub_specs[i].freq_range_index; + /* SAR specifies power limitaton in 0.25dbm */ + s32 power = sar->sub_specs[i].power >> 1; + + if (power > 127 || power < -127) + power = 127; + + phy->frp[index].range = &capa->freq_ranges[index]; + phy->frp[index].power = power; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_init_sar_power); + +int mt76_get_sar_power(struct mt76_phy *phy, + struct ieee80211_channel *chan, + int power) +{ + const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; + int freq, i; + + if (!capa || !phy->frp) + return power; + + if (power > 127 || power < -127) + power = 127; + + freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); + for (i = 0 ; i < capa->num_freq_ranges; i++) { + if (phy->frp[i].range && + freq >= phy->frp[i].range->start_freq && + freq < phy->frp[i].range->end_freq) { + power = min_t(int, phy->frp[i].power, power); + break; + } + } + + return power; +} +EXPORT_SYMBOL_GPL(mt76_get_sar_power); + static void __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) ieee80211_csa_finish(vif); } @@ -1373,7 +1493,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt76_dev *dev = priv; - if (!vif->csa_active) + if (!vif->bss_conf.csa_active) return; dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); @@ -1474,7 +1594,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base) + int ring_base, u32 flags) { struct mt76_queue *hwq; int err; @@ -1483,6 +1603,8 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, if (!hwq) return ERR_PTR(-ENOMEM); + hwq->flags = flags; + err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); if (err < 0) return ERR_PTR(err); @@ -1494,7 +1616,6 @@ EXPORT_SYMBOL_GPL(mt76_init_queue); u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) { int offset = 0; - struct ieee80211_rate *rate; if (phy->chandef.chan->band != NL80211_BAND_2GHZ) offset = 4; @@ -1503,9 +1624,11 @@ u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) if (rateidx < 0) rateidx = 0; - rate = &mt76_rates[offset + rateidx]; + rateidx += offset; + if (rateidx >= ARRAY_SIZE(mt76_rates)) + rateidx = offset; - return rate->hw_value; + return mt76_rates[rateidx].hw_value; } EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); @@ -1536,3 +1659,27 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, wi->worker_stat_count = ei - wi->initial_stat_idx; } EXPORT_SYMBOL_GPL(mt76_ethtool_worker); + +enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) +{ + struct ieee80211_hw *hw = phy->hw; + struct mt76_dev *dev = phy->dev; + + if (dev->region == NL80211_DFS_UNSET || + test_bit(MT76_SCANNING, &phy->state)) + return MT_DFS_STATE_DISABLED; + + if (!hw->conf.radar_enabled) { + if ((hw->conf.flags & IEEE80211_CONF_MONITOR) && + (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) + return MT_DFS_STATE_ACTIVE; + + return MT_DFS_STATE_DISABLED; + } + + if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP)) + return MT_DFS_STATE_CAC; + + return MT_DFS_STATE_ACTIVE; +} +EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); |