117f1de56SFelix Fietkau /* 217f1de56SFelix Fietkau * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 317f1de56SFelix Fietkau * 417f1de56SFelix Fietkau * Permission to use, copy, modify, and/or distribute this software for any 517f1de56SFelix Fietkau * purpose with or without fee is hereby granted, provided that the above 617f1de56SFelix Fietkau * copyright notice and this permission notice appear in all copies. 717f1de56SFelix Fietkau * 817f1de56SFelix Fietkau * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 917f1de56SFelix Fietkau * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1017f1de56SFelix Fietkau * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1117f1de56SFelix Fietkau * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1217f1de56SFelix Fietkau * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1317f1de56SFelix Fietkau * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1417f1de56SFelix Fietkau * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1517f1de56SFelix Fietkau */ 1617f1de56SFelix Fietkau #include <linux/of.h> 1717f1de56SFelix Fietkau #include "mt76.h" 1817f1de56SFelix Fietkau 1917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) { \ 2017f1de56SFelix Fietkau .band = NL80211_BAND_2GHZ, \ 2117f1de56SFelix Fietkau .center_freq = (_freq), \ 2217f1de56SFelix Fietkau .hw_value = (_idx), \ 2317f1de56SFelix Fietkau .max_power = 30, \ 2417f1de56SFelix Fietkau } 2517f1de56SFelix Fietkau 2617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) { \ 2717f1de56SFelix Fietkau .band = NL80211_BAND_5GHZ, \ 2817f1de56SFelix Fietkau .center_freq = (_freq), \ 2917f1de56SFelix Fietkau .hw_value = (_idx), \ 3017f1de56SFelix Fietkau .max_power = 30, \ 3117f1de56SFelix Fietkau } 3217f1de56SFelix Fietkau 3317f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = { 3417f1de56SFelix Fietkau CHAN2G(1, 2412), 3517f1de56SFelix Fietkau CHAN2G(2, 2417), 3617f1de56SFelix Fietkau CHAN2G(3, 2422), 3717f1de56SFelix Fietkau CHAN2G(4, 2427), 3817f1de56SFelix Fietkau CHAN2G(5, 2432), 3917f1de56SFelix Fietkau CHAN2G(6, 2437), 4017f1de56SFelix Fietkau CHAN2G(7, 2442), 4117f1de56SFelix Fietkau CHAN2G(8, 2447), 4217f1de56SFelix Fietkau CHAN2G(9, 2452), 4317f1de56SFelix Fietkau CHAN2G(10, 2457), 4417f1de56SFelix Fietkau CHAN2G(11, 2462), 4517f1de56SFelix Fietkau CHAN2G(12, 2467), 4617f1de56SFelix Fietkau CHAN2G(13, 2472), 4717f1de56SFelix Fietkau CHAN2G(14, 2484), 4817f1de56SFelix Fietkau }; 4917f1de56SFelix Fietkau 5017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = { 5117f1de56SFelix Fietkau CHAN5G(36, 5180), 5217f1de56SFelix Fietkau CHAN5G(40, 5200), 5317f1de56SFelix Fietkau CHAN5G(44, 5220), 5417f1de56SFelix Fietkau CHAN5G(48, 5240), 5517f1de56SFelix Fietkau 5617f1de56SFelix Fietkau CHAN5G(52, 5260), 5717f1de56SFelix Fietkau CHAN5G(56, 5280), 5817f1de56SFelix Fietkau CHAN5G(60, 5300), 5917f1de56SFelix Fietkau CHAN5G(64, 5320), 6017f1de56SFelix Fietkau 6117f1de56SFelix Fietkau CHAN5G(100, 5500), 6217f1de56SFelix Fietkau CHAN5G(104, 5520), 6317f1de56SFelix Fietkau CHAN5G(108, 5540), 6417f1de56SFelix Fietkau CHAN5G(112, 5560), 6517f1de56SFelix Fietkau CHAN5G(116, 5580), 6617f1de56SFelix Fietkau CHAN5G(120, 5600), 6717f1de56SFelix Fietkau CHAN5G(124, 5620), 6817f1de56SFelix Fietkau CHAN5G(128, 5640), 6917f1de56SFelix Fietkau CHAN5G(132, 5660), 7017f1de56SFelix Fietkau CHAN5G(136, 5680), 7117f1de56SFelix Fietkau CHAN5G(140, 5700), 7217f1de56SFelix Fietkau 7317f1de56SFelix Fietkau CHAN5G(149, 5745), 7417f1de56SFelix Fietkau CHAN5G(153, 5765), 7517f1de56SFelix Fietkau CHAN5G(157, 5785), 7617f1de56SFelix Fietkau CHAN5G(161, 5805), 7717f1de56SFelix Fietkau CHAN5G(165, 5825), 7817f1de56SFelix Fietkau }; 7917f1de56SFelix Fietkau 8017f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { 8117f1de56SFelix Fietkau { .throughput = 0 * 1024, .blink_time = 334 }, 8217f1de56SFelix Fietkau { .throughput = 1 * 1024, .blink_time = 260 }, 8317f1de56SFelix Fietkau { .throughput = 5 * 1024, .blink_time = 220 }, 8417f1de56SFelix Fietkau { .throughput = 10 * 1024, .blink_time = 190 }, 8517f1de56SFelix Fietkau { .throughput = 20 * 1024, .blink_time = 170 }, 8617f1de56SFelix Fietkau { .throughput = 50 * 1024, .blink_time = 150 }, 8717f1de56SFelix Fietkau { .throughput = 70 * 1024, .blink_time = 130 }, 8817f1de56SFelix Fietkau { .throughput = 100 * 1024, .blink_time = 110 }, 8917f1de56SFelix Fietkau { .throughput = 200 * 1024, .blink_time = 80 }, 9017f1de56SFelix Fietkau { .throughput = 300 * 1024, .blink_time = 50 }, 9117f1de56SFelix Fietkau }; 9217f1de56SFelix Fietkau 9317f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev) 9417f1de56SFelix Fietkau { 9517f1de56SFelix Fietkau struct device_node *np = dev->dev->of_node; 9617f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 9717f1de56SFelix Fietkau int led_pin; 9817f1de56SFelix Fietkau 9917f1de56SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 10017f1de56SFelix Fietkau return 0; 10117f1de56SFelix Fietkau 10217f1de56SFelix Fietkau snprintf(dev->led_name, sizeof(dev->led_name), 10317f1de56SFelix Fietkau "mt76-%s", wiphy_name(hw->wiphy)); 10417f1de56SFelix Fietkau 10517f1de56SFelix Fietkau dev->led_cdev.name = dev->led_name; 10617f1de56SFelix Fietkau dev->led_cdev.default_trigger = 10717f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw, 10817f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO, 10917f1de56SFelix Fietkau mt76_tpt_blink, 11017f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink)); 11117f1de56SFelix Fietkau 11217f1de56SFelix Fietkau np = of_get_child_by_name(np, "led"); 11317f1de56SFelix Fietkau if (np) { 11417f1de56SFelix Fietkau if (!of_property_read_u32(np, "led-sources", &led_pin)) 11517f1de56SFelix Fietkau dev->led_pin = led_pin; 11617f1de56SFelix Fietkau dev->led_al = of_property_read_bool(np, "led-active-low"); 11717f1de56SFelix Fietkau } 11817f1de56SFelix Fietkau 11917f1de56SFelix Fietkau return devm_led_classdev_register(dev->dev, &dev->led_cdev); 12017f1de56SFelix Fietkau } 12117f1de56SFelix Fietkau 122551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev, 123551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 124551e1ef4SLorenzo Bianconi bool vht) 125551e1ef4SLorenzo Bianconi { 126551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 127d0ff23c1SBen Hutchings int i, nstream = hweight8(dev->antenna_mask); 128551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 129551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 130551e1ef4SLorenzo Bianconi 131551e1ef4SLorenzo Bianconi if (nstream > 1) 132551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 133551e1ef4SLorenzo Bianconi else 134551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 135551e1ef4SLorenzo Bianconi 136551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 137551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 138551e1ef4SLorenzo Bianconi 139551e1ef4SLorenzo Bianconi if (!vht) 140551e1ef4SLorenzo Bianconi return; 141551e1ef4SLorenzo Bianconi 142551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 143551e1ef4SLorenzo Bianconi if (nstream > 1) 144551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 145551e1ef4SLorenzo Bianconi else 146551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 147551e1ef4SLorenzo Bianconi 148551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 149551e1ef4SLorenzo Bianconi if (i < nstream) 150551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 151551e1ef4SLorenzo Bianconi else 152551e1ef4SLorenzo Bianconi mcs_map |= 153551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 154551e1ef4SLorenzo Bianconi } 155551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 156551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 157551e1ef4SLorenzo Bianconi } 158551e1ef4SLorenzo Bianconi 1595ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht) 1605ebdc3e0SLorenzo Bianconi { 1615ebdc3e0SLorenzo Bianconi if (dev->cap.has_2ghz) 1625ebdc3e0SLorenzo Bianconi mt76_init_stream_cap(dev, &dev->sband_2g.sband, false); 1635ebdc3e0SLorenzo Bianconi if (dev->cap.has_5ghz) 1645ebdc3e0SLorenzo Bianconi mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht); 1655ebdc3e0SLorenzo Bianconi } 1665ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 1675ebdc3e0SLorenzo Bianconi 16817f1de56SFelix Fietkau static int 16917f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, 17017f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 17117f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates, bool vht) 17217f1de56SFelix Fietkau { 17317f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 17417f1de56SFelix Fietkau struct ieee80211_sta_ht_cap *ht_cap; 17517f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 17617f1de56SFelix Fietkau void *chanlist; 17717f1de56SFelix Fietkau int size; 17817f1de56SFelix Fietkau 17917f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 18017f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 18117f1de56SFelix Fietkau if (!chanlist) 18217f1de56SFelix Fietkau return -ENOMEM; 18317f1de56SFelix Fietkau 184a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 18517f1de56SFelix Fietkau GFP_KERNEL); 18617f1de56SFelix Fietkau if (!msband->chan) 18717f1de56SFelix Fietkau return -ENOMEM; 18817f1de56SFelix Fietkau 18917f1de56SFelix Fietkau sband->channels = chanlist; 19017f1de56SFelix Fietkau sband->n_channels = n_chan; 19117f1de56SFelix Fietkau sband->bitrates = rates; 19217f1de56SFelix Fietkau sband->n_bitrates = n_rates; 19317f1de56SFelix Fietkau dev->chandef.chan = &sband->channels[0]; 19417f1de56SFelix Fietkau 19517f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 19617f1de56SFelix Fietkau ht_cap->ht_supported = true; 19717f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 19817f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 19917f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 20017f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 20117f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 20217f1de56SFelix Fietkau 20317f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 20417f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 20517f1de56SFelix Fietkau ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; 20617f1de56SFelix Fietkau 207551e1ef4SLorenzo Bianconi mt76_init_stream_cap(dev, sband, vht); 208551e1ef4SLorenzo Bianconi 20917f1de56SFelix Fietkau if (!vht) 21017f1de56SFelix Fietkau return 0; 21117f1de56SFelix Fietkau 21217f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 21317f1de56SFelix Fietkau vht_cap->vht_supported = true; 21417f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 21517f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 21649149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 21749149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 21817f1de56SFelix Fietkau 21917f1de56SFelix Fietkau return 0; 22017f1de56SFelix Fietkau } 22117f1de56SFelix Fietkau 22217f1de56SFelix Fietkau static int 22317f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates, 22417f1de56SFelix Fietkau int n_rates) 22517f1de56SFelix Fietkau { 22617f1de56SFelix Fietkau dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband; 22717f1de56SFelix Fietkau 22817f1de56SFelix Fietkau return mt76_init_sband(dev, &dev->sband_2g, 22917f1de56SFelix Fietkau mt76_channels_2ghz, 23017f1de56SFelix Fietkau ARRAY_SIZE(mt76_channels_2ghz), 23117f1de56SFelix Fietkau rates, n_rates, false); 23217f1de56SFelix Fietkau } 23317f1de56SFelix Fietkau 23417f1de56SFelix Fietkau static int 23517f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates, 23617f1de56SFelix Fietkau int n_rates, bool vht) 23717f1de56SFelix Fietkau { 23817f1de56SFelix Fietkau dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband; 23917f1de56SFelix Fietkau 24017f1de56SFelix Fietkau return mt76_init_sband(dev, &dev->sband_5g, 24117f1de56SFelix Fietkau mt76_channels_5ghz, 24217f1de56SFelix Fietkau ARRAY_SIZE(mt76_channels_5ghz), 24317f1de56SFelix Fietkau rates, n_rates, vht); 24417f1de56SFelix Fietkau } 24517f1de56SFelix Fietkau 24617f1de56SFelix Fietkau static void 24717f1de56SFelix Fietkau mt76_check_sband(struct mt76_dev *dev, int band) 24817f1de56SFelix Fietkau { 24917f1de56SFelix Fietkau struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band]; 25017f1de56SFelix Fietkau bool found = false; 25117f1de56SFelix Fietkau int i; 25217f1de56SFelix Fietkau 25317f1de56SFelix Fietkau if (!sband) 25417f1de56SFelix Fietkau return; 25517f1de56SFelix Fietkau 25617f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 25717f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 25817f1de56SFelix Fietkau continue; 25917f1de56SFelix Fietkau 26017f1de56SFelix Fietkau found = true; 26117f1de56SFelix Fietkau break; 26217f1de56SFelix Fietkau } 26317f1de56SFelix Fietkau 26417f1de56SFelix Fietkau if (found) 26517f1de56SFelix Fietkau return; 26617f1de56SFelix Fietkau 26717f1de56SFelix Fietkau sband->n_channels = 0; 26817f1de56SFelix Fietkau dev->hw->wiphy->bands[band] = NULL; 26917f1de56SFelix Fietkau } 27017f1de56SFelix Fietkau 271a85b590cSFelix Fietkau struct mt76_dev * 272c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 273c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 274c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 275a85b590cSFelix Fietkau { 276a85b590cSFelix Fietkau struct ieee80211_hw *hw; 277a85b590cSFelix Fietkau struct mt76_dev *dev; 278a85b590cSFelix Fietkau 279a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 280a85b590cSFelix Fietkau if (!hw) 281a85b590cSFelix Fietkau return NULL; 282a85b590cSFelix Fietkau 283a85b590cSFelix Fietkau dev = hw->priv; 284a85b590cSFelix Fietkau dev->hw = hw; 285c0f7b25aSLorenzo Bianconi dev->dev = pdev; 286c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 287c0f7b25aSLorenzo Bianconi 288a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 289a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 290a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 291108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 29226e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 29388046b2cSFelix Fietkau skb_queue_head_init(&dev->status_list); 294a85b590cSFelix Fietkau 295a85b590cSFelix Fietkau return dev; 296a85b590cSFelix Fietkau } 297a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 298a85b590cSFelix Fietkau 29917f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 30017f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 30117f1de56SFelix Fietkau { 30217f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 30317f1de56SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 30417f1de56SFelix Fietkau int ret; 30517f1de56SFelix Fietkau 30617f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 30717f1de56SFelix Fietkau 30817f1de56SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 30917f1de56SFelix Fietkau 31017f1de56SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 31117f1de56SFelix Fietkau SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 31217f1de56SFelix Fietkau 31317f1de56SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 31417f1de56SFelix Fietkau 315b37b30afSKristian Evensen wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 316b37b30afSKristian Evensen 31724114a5fSLorenzo Bianconi wiphy->available_antennas_tx = dev->antenna_mask; 31824114a5fSLorenzo Bianconi wiphy->available_antennas_rx = dev->antenna_mask; 31924114a5fSLorenzo Bianconi 32017f1de56SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 32117f1de56SFelix Fietkau hw->max_tx_fragments = 16; 32217f1de56SFelix Fietkau 32317f1de56SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 32417f1de56SFelix Fietkau ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 32517f1de56SFelix Fietkau ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 32617f1de56SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 32717f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 32817f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 32917f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 33017f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 33117f1de56SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 33217f1de56SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 33317f1de56SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 334d71ef286SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 33588046b2cSFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 336f545540dSFelix Fietkau ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); 33717f1de56SFelix Fietkau 33817f1de56SFelix Fietkau wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 33917f1de56SFelix Fietkau 34017f1de56SFelix Fietkau if (dev->cap.has_2ghz) { 34117f1de56SFelix Fietkau ret = mt76_init_sband_2g(dev, rates, n_rates); 34217f1de56SFelix Fietkau if (ret) 34317f1de56SFelix Fietkau return ret; 34417f1de56SFelix Fietkau } 34517f1de56SFelix Fietkau 34617f1de56SFelix Fietkau if (dev->cap.has_5ghz) { 34717f1de56SFelix Fietkau ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht); 34817f1de56SFelix Fietkau if (ret) 34917f1de56SFelix Fietkau return ret; 35017f1de56SFelix Fietkau } 35117f1de56SFelix Fietkau 35217f1de56SFelix Fietkau wiphy_read_of_freq_limits(dev->hw->wiphy); 35317f1de56SFelix Fietkau mt76_check_sband(dev, NL80211_BAND_2GHZ); 35417f1de56SFelix Fietkau mt76_check_sband(dev, NL80211_BAND_5GHZ); 35517f1de56SFelix Fietkau 356b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 35717f1de56SFelix Fietkau ret = mt76_led_init(dev); 35817f1de56SFelix Fietkau if (ret) 35917f1de56SFelix Fietkau return ret; 360b374e868SArnd Bergmann } 36117f1de56SFelix Fietkau 36217f1de56SFelix Fietkau return ieee80211_register_hw(hw); 36317f1de56SFelix Fietkau } 36417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 36517f1de56SFelix Fietkau 36617f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 36717f1de56SFelix Fietkau { 36817f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 36917f1de56SFelix Fietkau 37079d1c94cSFelix Fietkau mt76_tx_status_check(dev, NULL, true); 37117f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 37217f1de56SFelix Fietkau mt76_tx_free(dev); 37317f1de56SFelix Fietkau } 37417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 37517f1de56SFelix Fietkau 37617f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 37717f1de56SFelix Fietkau { 37817f1de56SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &dev->state)) { 37917f1de56SFelix Fietkau dev_kfree_skb(skb); 38017f1de56SFelix Fietkau return; 38117f1de56SFelix Fietkau } 38217f1de56SFelix Fietkau 38317f1de56SFelix Fietkau __skb_queue_tail(&dev->rx_skb[q], skb); 38417f1de56SFelix Fietkau } 38517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 38617f1de56SFelix Fietkau 38726e40d4cSFelix Fietkau static bool mt76_has_tx_pending(struct mt76_dev *dev) 38826e40d4cSFelix Fietkau { 389*af005f26SLorenzo Bianconi struct mt76_queue *q; 39026e40d4cSFelix Fietkau int i; 39126e40d4cSFelix Fietkau 39226e40d4cSFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) { 393*af005f26SLorenzo Bianconi q = dev->q_tx[i].q; 394*af005f26SLorenzo Bianconi if (q && q->queued) 39526e40d4cSFelix Fietkau return true; 39626e40d4cSFelix Fietkau } 39726e40d4cSFelix Fietkau 39826e40d4cSFelix Fietkau return false; 39926e40d4cSFelix Fietkau } 40026e40d4cSFelix Fietkau 40117f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev) 40217f1de56SFelix Fietkau { 40317f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 40417f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 40517f1de56SFelix Fietkau struct mt76_channel_state *state; 40617f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 40726e40d4cSFelix Fietkau int timeout = HZ / 5; 40817f1de56SFelix Fietkau 40989bc67e3SFelix Fietkau if (offchannel) 41089bc67e3SFelix Fietkau set_bit(MT76_OFFCHANNEL, &dev->state); 41189bc67e3SFelix Fietkau else 41289bc67e3SFelix Fietkau clear_bit(MT76_OFFCHANNEL, &dev->state); 41389bc67e3SFelix Fietkau 41426e40d4cSFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); 41526e40d4cSFelix Fietkau 41617f1de56SFelix Fietkau if (dev->drv->update_survey) 41717f1de56SFelix Fietkau dev->drv->update_survey(dev); 41817f1de56SFelix Fietkau 41917f1de56SFelix Fietkau dev->chandef = *chandef; 42017f1de56SFelix Fietkau 42117f1de56SFelix Fietkau if (!offchannel) 42217f1de56SFelix Fietkau dev->main_chan = chandef->chan; 42317f1de56SFelix Fietkau 42417f1de56SFelix Fietkau if (chandef->chan != dev->main_chan) { 42517f1de56SFelix Fietkau state = mt76_channel_state(dev, chandef->chan); 42617f1de56SFelix Fietkau memset(state, 0, sizeof(*state)); 42717f1de56SFelix Fietkau } 42817f1de56SFelix Fietkau } 42917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 43017f1de56SFelix Fietkau 43117f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 43217f1de56SFelix Fietkau struct survey_info *survey) 43317f1de56SFelix Fietkau { 43417f1de56SFelix Fietkau struct mt76_dev *dev = hw->priv; 43517f1de56SFelix Fietkau struct mt76_sband *sband; 43617f1de56SFelix Fietkau struct ieee80211_channel *chan; 43717f1de56SFelix Fietkau struct mt76_channel_state *state; 43817f1de56SFelix Fietkau int ret = 0; 43917f1de56SFelix Fietkau 44017f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 44117f1de56SFelix Fietkau dev->drv->update_survey(dev); 44217f1de56SFelix Fietkau 44317f1de56SFelix Fietkau sband = &dev->sband_2g; 44417f1de56SFelix Fietkau if (idx >= sband->sband.n_channels) { 44517f1de56SFelix Fietkau idx -= sband->sband.n_channels; 44617f1de56SFelix Fietkau sband = &dev->sband_5g; 44717f1de56SFelix Fietkau } 44817f1de56SFelix Fietkau 44917f1de56SFelix Fietkau if (idx >= sband->sband.n_channels) 45017f1de56SFelix Fietkau return -ENOENT; 45117f1de56SFelix Fietkau 45217f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 45317f1de56SFelix Fietkau state = mt76_channel_state(dev, chan); 45417f1de56SFelix Fietkau 45517f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 45617f1de56SFelix Fietkau survey->channel = chan; 45717f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 45817f1de56SFelix Fietkau if (chan == dev->main_chan) 45917f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 46017f1de56SFelix Fietkau 46117f1de56SFelix Fietkau spin_lock_bh(&dev->cc_lock); 46217f1de56SFelix Fietkau survey->time = div_u64(state->cc_active, 1000); 46317f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 46417f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 46517f1de56SFelix Fietkau 46617f1de56SFelix Fietkau return ret; 46717f1de56SFelix Fietkau } 46817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 46917f1de56SFelix Fietkau 47030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 47130ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 47230ce7f44SFelix Fietkau { 47330ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 47430ce7f44SFelix Fietkau int i; 47530ce7f44SFelix Fietkau 47630ce7f44SFelix Fietkau wcid->rx_check_pn = false; 47730ce7f44SFelix Fietkau 47830ce7f44SFelix Fietkau if (!key) 47930ce7f44SFelix Fietkau return; 48030ce7f44SFelix Fietkau 48130ce7f44SFelix Fietkau if (key->cipher == WLAN_CIPHER_SUITE_CCMP) 48230ce7f44SFelix Fietkau wcid->rx_check_pn = true; 48330ce7f44SFelix Fietkau 48430ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 48530ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 48630ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 48730ce7f44SFelix Fietkau } 48830ce7f44SFelix Fietkau } 48930ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 49030ce7f44SFelix Fietkau 49182e1dd0fSStanislaw Gruszka struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) 4924e34249eSFelix Fietkau { 4934e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 4944e34249eSFelix Fietkau struct mt76_rx_status mstat; 4954e34249eSFelix Fietkau 4964e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *) skb->cb); 4974e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 4984e34249eSFelix Fietkau 4994e34249eSFelix Fietkau status->flag = mstat.flag; 5004e34249eSFelix Fietkau status->freq = mstat.freq; 5014e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 5024e34249eSFelix Fietkau status->encoding = mstat.encoding; 5034e34249eSFelix Fietkau status->bw = mstat.bw; 5044e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 5054e34249eSFelix Fietkau status->nss = mstat.nss; 5064e34249eSFelix Fietkau status->band = mstat.band; 5074e34249eSFelix Fietkau status->signal = mstat.signal; 5084e34249eSFelix Fietkau status->chains = mstat.chains; 5094e34249eSFelix Fietkau 5104e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 5114e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(status->chain_signal) != sizeof(mstat.chain_signal)); 5124e34249eSFelix Fietkau memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal)); 5139c68a57bSFelix Fietkau 5149c68a57bSFelix Fietkau return wcid_to_sta(mstat.wcid); 5154e34249eSFelix Fietkau } 51682e1dd0fSStanislaw Gruszka EXPORT_SYMBOL(mt76_rx_convert); 5174e34249eSFelix Fietkau 51830ce7f44SFelix Fietkau static int 51930ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 52030ce7f44SFelix Fietkau { 52130ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; 52230ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 52330ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 52430ce7f44SFelix Fietkau int ret; 52530ce7f44SFelix Fietkau 52630ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 52730ce7f44SFelix Fietkau return 0; 52830ce7f44SFelix Fietkau 52930ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 53030ce7f44SFelix Fietkau return 0; 53130ce7f44SFelix Fietkau 53230ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 53330ce7f44SFelix Fietkau /* 53430ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 53530ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 53630ce7f44SFelix Fietkau */ 53730ce7f44SFelix Fietkau hdr = (struct ieee80211_hdr *) skb->data; 53830ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 53930ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 54030ce7f44SFelix Fietkau return 0; 54130ce7f44SFelix Fietkau } 54230ce7f44SFelix Fietkau 54330ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 54430ce7f44SFelix Fietkau ret = memcmp(status->iv, wcid->rx_key_pn[status->tid], 54530ce7f44SFelix Fietkau sizeof(status->iv)); 54630ce7f44SFelix Fietkau if (ret <= 0) 54730ce7f44SFelix Fietkau return -EINVAL; /* replay */ 54830ce7f44SFelix Fietkau 54930ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv)); 55030ce7f44SFelix Fietkau 55130ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 55230ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 55330ce7f44SFelix Fietkau 55430ce7f44SFelix Fietkau return 0; 55530ce7f44SFelix Fietkau } 55630ce7f44SFelix Fietkau 557d71ef286SFelix Fietkau static void 558ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 559d71ef286SFelix Fietkau { 560d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; 561d71ef286SFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 562d71ef286SFelix Fietkau struct ieee80211_sta *sta; 563d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 564d71ef286SFelix Fietkau bool ps; 565d71ef286SFelix Fietkau 56636d91096SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { 56736d91096SFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL); 56836d91096SFelix Fietkau if (sta) 56936d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv; 57036d91096SFelix Fietkau } 57136d91096SFelix Fietkau 572d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 573d71ef286SFelix Fietkau return; 574d71ef286SFelix Fietkau 575d71ef286SFelix Fietkau sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv); 576d71ef286SFelix Fietkau 57702e5a769SFelix Fietkau if (status->signal <= 0) 57802e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 57902e5a769SFelix Fietkau 580ef13edc0SFelix Fietkau wcid->inactive_count = 0; 581ef13edc0SFelix Fietkau 582d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 583d71ef286SFelix Fietkau return; 584d71ef286SFelix Fietkau 585d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 586d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 587d71ef286SFelix Fietkau return; 588d71ef286SFelix Fietkau } 589d71ef286SFelix Fietkau 590d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 591d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 592d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 593d71ef286SFelix Fietkau return; 594d71ef286SFelix Fietkau 595d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 596d71ef286SFelix Fietkau 597d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 598d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 599d71ef286SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, status->tid); 600d71ef286SFelix Fietkau 601d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 602d71ef286SFelix Fietkau return; 603d71ef286SFelix Fietkau 60411b2a25fSFelix Fietkau if (ps) 605d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 60611b2a25fSFelix Fietkau else 607d71ef286SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 608d71ef286SFelix Fietkau 609d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 6109f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 611d71ef286SFelix Fietkau } 612d71ef286SFelix Fietkau 6139d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 61481e850efSLorenzo Bianconi struct napi_struct *napi) 61517f1de56SFelix Fietkau { 6169c68a57bSFelix Fietkau struct ieee80211_sta *sta; 6179d9d738bSFelix Fietkau struct sk_buff *skb; 6189d9d738bSFelix Fietkau 619c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 6209d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 62130ce7f44SFelix Fietkau if (mt76_check_ccmp_pn(skb)) { 62230ce7f44SFelix Fietkau dev_kfree_skb(skb); 62330ce7f44SFelix Fietkau continue; 62430ce7f44SFelix Fietkau } 62530ce7f44SFelix Fietkau 6269d9d738bSFelix Fietkau sta = mt76_rx_convert(skb); 6279d9d738bSFelix Fietkau ieee80211_rx_napi(dev->hw, sta, skb, napi); 6289d9d738bSFelix Fietkau } 629c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 6309d9d738bSFelix Fietkau } 6319d9d738bSFelix Fietkau 63281e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 63381e850efSLorenzo Bianconi struct napi_struct *napi) 6349d9d738bSFelix Fietkau { 635aee5b8cfSFelix Fietkau struct sk_buff_head frames; 63617f1de56SFelix Fietkau struct sk_buff *skb; 63717f1de56SFelix Fietkau 638aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 639aee5b8cfSFelix Fietkau 640d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 641ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 642aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 643d71ef286SFelix Fietkau } 644aee5b8cfSFelix Fietkau 64581e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 6464e34249eSFelix Fietkau } 64781e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 648723b90dcSFelix Fietkau 649e28487eaSFelix Fietkau static int 650e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, 651e28487eaSFelix Fietkau struct ieee80211_sta *sta) 652e28487eaSFelix Fietkau { 653e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 654e28487eaSFelix Fietkau int ret; 655e28487eaSFelix Fietkau int i; 656e28487eaSFelix Fietkau 657e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 658e28487eaSFelix Fietkau 659e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 660e28487eaSFelix Fietkau if (ret) 661e28487eaSFelix Fietkau goto out; 662e28487eaSFelix Fietkau 663e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 664e28487eaSFelix Fietkau struct mt76_txq *mtxq; 665e28487eaSFelix Fietkau 666e28487eaSFelix Fietkau if (!sta->txq[i]) 667e28487eaSFelix Fietkau continue; 668e28487eaSFelix Fietkau 669e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 670e28487eaSFelix Fietkau mtxq->wcid = wcid; 671e28487eaSFelix Fietkau 672e28487eaSFelix Fietkau mt76_txq_init(dev, sta->txq[i]); 673e28487eaSFelix Fietkau } 674e28487eaSFelix Fietkau 675ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 676e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 677e28487eaSFelix Fietkau 678e28487eaSFelix Fietkau out: 679e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 680e28487eaSFelix Fietkau 681e28487eaSFelix Fietkau return ret; 682e28487eaSFelix Fietkau } 683e28487eaSFelix Fietkau 68413f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 685723b90dcSFelix Fietkau struct ieee80211_sta *sta) 686723b90dcSFelix Fietkau { 687723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 68813f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 689723b90dcSFelix Fietkau 690723b90dcSFelix Fietkau rcu_assign_pointer(dev->wcid[idx], NULL); 691723b90dcSFelix Fietkau synchronize_rcu(); 692723b90dcSFelix Fietkau 693e28487eaSFelix Fietkau if (dev->drv->sta_remove) 694e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 695e28487eaSFelix Fietkau 696723b90dcSFelix Fietkau mt76_tx_status_check(dev, wcid, true); 697723b90dcSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 698723b90dcSFelix Fietkau mt76_txq_remove(dev, sta->txq[i]); 699723b90dcSFelix Fietkau mt76_wcid_free(dev->wcid_mask, idx); 70013f61dfcSLorenzo Bianconi } 70113f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 702e28487eaSFelix Fietkau 70313f61dfcSLorenzo Bianconi static void 70413f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 70513f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 70613f61dfcSLorenzo Bianconi { 70713f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 70813f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 709723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 710723b90dcSFelix Fietkau } 711e28487eaSFelix Fietkau 712e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 713e28487eaSFelix Fietkau struct ieee80211_sta *sta, 714e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 715e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 716e28487eaSFelix Fietkau { 717e28487eaSFelix Fietkau struct mt76_dev *dev = hw->priv; 718e28487eaSFelix Fietkau 719e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 720e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 721e28487eaSFelix Fietkau return mt76_sta_add(dev, vif, sta); 722e28487eaSFelix Fietkau 7239c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 7249c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 7259c193de5SFelix Fietkau dev->drv->sta_assoc) 7269c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 7279c193de5SFelix Fietkau 728e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 729e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 730e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 731e28487eaSFelix Fietkau 732e28487eaSFelix Fietkau return 0; 733e28487eaSFelix Fietkau } 734e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 7359313faacSFelix Fietkau 7369313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 7379313faacSFelix Fietkau int *dbm) 7389313faacSFelix Fietkau { 7399313faacSFelix Fietkau struct mt76_dev *dev = hw->priv; 740d0ff23c1SBen Hutchings int n_chains = hweight8(dev->antenna_mask); 7419313faacSFelix Fietkau 7429313faacSFelix Fietkau *dbm = dev->txpower_cur / 2; 7439313faacSFelix Fietkau 7449313faacSFelix Fietkau /* convert from per-chain power to combined 7459313faacSFelix Fietkau * output on 2x2 devices 7469313faacSFelix Fietkau */ 7479313faacSFelix Fietkau if (n_chains > 1) 7489313faacSFelix Fietkau *dbm += 3; 7499313faacSFelix Fietkau 7509313faacSFelix Fietkau return 0; 7519313faacSFelix Fietkau } 7529313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 753e7173858SFelix Fietkau 754e7173858SFelix Fietkau static void 755e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 756e7173858SFelix Fietkau { 757e7173858SFelix Fietkau if (vif->csa_active && ieee80211_csa_is_complete(vif)) 758e7173858SFelix Fietkau ieee80211_csa_finish(vif); 759e7173858SFelix Fietkau } 760e7173858SFelix Fietkau 761e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 762e7173858SFelix Fietkau { 763e7173858SFelix Fietkau if (!dev->csa_complete) 764e7173858SFelix Fietkau return; 765e7173858SFelix Fietkau 766e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 767e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 768e7173858SFelix Fietkau __mt76_csa_finish, dev); 769e7173858SFelix Fietkau 770e7173858SFelix Fietkau dev->csa_complete = 0; 771e7173858SFelix Fietkau } 772e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 773e7173858SFelix Fietkau 774e7173858SFelix Fietkau static void 775e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 776e7173858SFelix Fietkau { 777e7173858SFelix Fietkau struct mt76_dev *dev = priv; 778e7173858SFelix Fietkau 779e7173858SFelix Fietkau if (!vif->csa_active) 780e7173858SFelix Fietkau return; 781e7173858SFelix Fietkau 782e7173858SFelix Fietkau dev->csa_complete |= ieee80211_csa_is_complete(vif); 783e7173858SFelix Fietkau } 784e7173858SFelix Fietkau 785e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 786e7173858SFelix Fietkau { 787e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 788e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 789e7173858SFelix Fietkau __mt76_csa_check, dev); 790e7173858SFelix Fietkau } 791e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 792