10e3d6777SRyder Lee // SPDX-License-Identifier: ISC 217f1de56SFelix Fietkau /* 317f1de56SFelix Fietkau * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 417f1de56SFelix Fietkau */ 517f1de56SFelix Fietkau #include <linux/of.h> 617f1de56SFelix Fietkau #include "mt76.h" 717f1de56SFelix Fietkau 817f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) { \ 917f1de56SFelix Fietkau .band = NL80211_BAND_2GHZ, \ 1017f1de56SFelix Fietkau .center_freq = (_freq), \ 1117f1de56SFelix Fietkau .hw_value = (_idx), \ 1217f1de56SFelix Fietkau .max_power = 30, \ 1317f1de56SFelix Fietkau } 1417f1de56SFelix Fietkau 1517f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) { \ 1617f1de56SFelix Fietkau .band = NL80211_BAND_5GHZ, \ 1717f1de56SFelix Fietkau .center_freq = (_freq), \ 1817f1de56SFelix Fietkau .hw_value = (_idx), \ 1917f1de56SFelix Fietkau .max_power = 30, \ 2017f1de56SFelix Fietkau } 2117f1de56SFelix Fietkau 2217f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = { 2317f1de56SFelix Fietkau CHAN2G(1, 2412), 2417f1de56SFelix Fietkau CHAN2G(2, 2417), 2517f1de56SFelix Fietkau CHAN2G(3, 2422), 2617f1de56SFelix Fietkau CHAN2G(4, 2427), 2717f1de56SFelix Fietkau CHAN2G(5, 2432), 2817f1de56SFelix Fietkau CHAN2G(6, 2437), 2917f1de56SFelix Fietkau CHAN2G(7, 2442), 3017f1de56SFelix Fietkau CHAN2G(8, 2447), 3117f1de56SFelix Fietkau CHAN2G(9, 2452), 3217f1de56SFelix Fietkau CHAN2G(10, 2457), 3317f1de56SFelix Fietkau CHAN2G(11, 2462), 3417f1de56SFelix Fietkau CHAN2G(12, 2467), 3517f1de56SFelix Fietkau CHAN2G(13, 2472), 3617f1de56SFelix Fietkau CHAN2G(14, 2484), 3717f1de56SFelix Fietkau }; 3817f1de56SFelix Fietkau 3917f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = { 4017f1de56SFelix Fietkau CHAN5G(36, 5180), 4117f1de56SFelix Fietkau CHAN5G(40, 5200), 4217f1de56SFelix Fietkau CHAN5G(44, 5220), 4317f1de56SFelix Fietkau CHAN5G(48, 5240), 4417f1de56SFelix Fietkau 4517f1de56SFelix Fietkau CHAN5G(52, 5260), 4617f1de56SFelix Fietkau CHAN5G(56, 5280), 4717f1de56SFelix Fietkau CHAN5G(60, 5300), 4817f1de56SFelix Fietkau CHAN5G(64, 5320), 4917f1de56SFelix Fietkau 5017f1de56SFelix Fietkau CHAN5G(100, 5500), 5117f1de56SFelix Fietkau CHAN5G(104, 5520), 5217f1de56SFelix Fietkau CHAN5G(108, 5540), 5317f1de56SFelix Fietkau CHAN5G(112, 5560), 5417f1de56SFelix Fietkau CHAN5G(116, 5580), 5517f1de56SFelix Fietkau CHAN5G(120, 5600), 5617f1de56SFelix Fietkau CHAN5G(124, 5620), 5717f1de56SFelix Fietkau CHAN5G(128, 5640), 5817f1de56SFelix Fietkau CHAN5G(132, 5660), 5917f1de56SFelix Fietkau CHAN5G(136, 5680), 6017f1de56SFelix Fietkau CHAN5G(140, 5700), 6117f1de56SFelix Fietkau 6217f1de56SFelix Fietkau CHAN5G(149, 5745), 6317f1de56SFelix Fietkau CHAN5G(153, 5765), 6417f1de56SFelix Fietkau CHAN5G(157, 5785), 6517f1de56SFelix Fietkau CHAN5G(161, 5805), 6617f1de56SFelix Fietkau CHAN5G(165, 5825), 6717f1de56SFelix Fietkau }; 6817f1de56SFelix Fietkau 6917f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { 7017f1de56SFelix Fietkau { .throughput = 0 * 1024, .blink_time = 334 }, 7117f1de56SFelix Fietkau { .throughput = 1 * 1024, .blink_time = 260 }, 7217f1de56SFelix Fietkau { .throughput = 5 * 1024, .blink_time = 220 }, 7317f1de56SFelix Fietkau { .throughput = 10 * 1024, .blink_time = 190 }, 7417f1de56SFelix Fietkau { .throughput = 20 * 1024, .blink_time = 170 }, 7517f1de56SFelix Fietkau { .throughput = 50 * 1024, .blink_time = 150 }, 7617f1de56SFelix Fietkau { .throughput = 70 * 1024, .blink_time = 130 }, 7717f1de56SFelix Fietkau { .throughput = 100 * 1024, .blink_time = 110 }, 7817f1de56SFelix Fietkau { .throughput = 200 * 1024, .blink_time = 80 }, 7917f1de56SFelix Fietkau { .throughput = 300 * 1024, .blink_time = 50 }, 8017f1de56SFelix Fietkau }; 8117f1de56SFelix Fietkau 8217f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev) 8317f1de56SFelix Fietkau { 8417f1de56SFelix Fietkau struct device_node *np = dev->dev->of_node; 8517f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 8617f1de56SFelix Fietkau int led_pin; 8717f1de56SFelix Fietkau 8817f1de56SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 8917f1de56SFelix Fietkau return 0; 9017f1de56SFelix Fietkau 9117f1de56SFelix Fietkau snprintf(dev->led_name, sizeof(dev->led_name), 9217f1de56SFelix Fietkau "mt76-%s", wiphy_name(hw->wiphy)); 9317f1de56SFelix Fietkau 9417f1de56SFelix Fietkau dev->led_cdev.name = dev->led_name; 9517f1de56SFelix Fietkau dev->led_cdev.default_trigger = 9617f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw, 9717f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO, 9817f1de56SFelix Fietkau mt76_tpt_blink, 9917f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink)); 10017f1de56SFelix Fietkau 10117f1de56SFelix Fietkau np = of_get_child_by_name(np, "led"); 10217f1de56SFelix Fietkau if (np) { 10317f1de56SFelix Fietkau if (!of_property_read_u32(np, "led-sources", &led_pin)) 10417f1de56SFelix Fietkau dev->led_pin = led_pin; 10517f1de56SFelix Fietkau dev->led_al = of_property_read_bool(np, "led-active-low"); 10617f1de56SFelix Fietkau } 10717f1de56SFelix Fietkau 10836f7e2b2SFelix Fietkau return led_classdev_register(dev->dev, &dev->led_cdev); 10936f7e2b2SFelix Fietkau } 11036f7e2b2SFelix Fietkau 11136f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev) 11236f7e2b2SFelix Fietkau { 11336f7e2b2SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 11436f7e2b2SFelix Fietkau return; 11536f7e2b2SFelix Fietkau 11636f7e2b2SFelix Fietkau led_classdev_unregister(&dev->led_cdev); 11717f1de56SFelix Fietkau } 11817f1de56SFelix Fietkau 119551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev, 120551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 121551e1ef4SLorenzo Bianconi bool vht) 122551e1ef4SLorenzo Bianconi { 123551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 124d0ff23c1SBen Hutchings int i, nstream = hweight8(dev->antenna_mask); 125551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 126551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 127551e1ef4SLorenzo Bianconi 128551e1ef4SLorenzo Bianconi if (nstream > 1) 129551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 130551e1ef4SLorenzo Bianconi else 131551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 132551e1ef4SLorenzo Bianconi 133551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 134551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 135551e1ef4SLorenzo Bianconi 136551e1ef4SLorenzo Bianconi if (!vht) 137551e1ef4SLorenzo Bianconi return; 138551e1ef4SLorenzo Bianconi 139551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 140551e1ef4SLorenzo Bianconi if (nstream > 1) 141551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 142551e1ef4SLorenzo Bianconi else 143551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 144551e1ef4SLorenzo Bianconi 145551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 146551e1ef4SLorenzo Bianconi if (i < nstream) 147551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 148551e1ef4SLorenzo Bianconi else 149551e1ef4SLorenzo Bianconi mcs_map |= 150551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 151551e1ef4SLorenzo Bianconi } 152551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 153551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 154551e1ef4SLorenzo Bianconi } 155551e1ef4SLorenzo Bianconi 1565ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht) 1575ebdc3e0SLorenzo Bianconi { 1585ebdc3e0SLorenzo Bianconi if (dev->cap.has_2ghz) 1595ebdc3e0SLorenzo Bianconi mt76_init_stream_cap(dev, &dev->sband_2g.sband, false); 1605ebdc3e0SLorenzo Bianconi if (dev->cap.has_5ghz) 1615ebdc3e0SLorenzo Bianconi mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht); 1625ebdc3e0SLorenzo Bianconi } 1635ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 1645ebdc3e0SLorenzo Bianconi 16517f1de56SFelix Fietkau static int 16617f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, 16717f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 16817f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates, bool vht) 16917f1de56SFelix Fietkau { 17017f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 17117f1de56SFelix Fietkau struct ieee80211_sta_ht_cap *ht_cap; 17217f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 17317f1de56SFelix Fietkau void *chanlist; 17417f1de56SFelix Fietkau int size; 17517f1de56SFelix Fietkau 17617f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 17717f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 17817f1de56SFelix Fietkau if (!chanlist) 17917f1de56SFelix Fietkau return -ENOMEM; 18017f1de56SFelix Fietkau 181a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 18217f1de56SFelix Fietkau GFP_KERNEL); 18317f1de56SFelix Fietkau if (!msband->chan) 18417f1de56SFelix Fietkau return -ENOMEM; 18517f1de56SFelix Fietkau 18617f1de56SFelix Fietkau sband->channels = chanlist; 18717f1de56SFelix Fietkau sband->n_channels = n_chan; 18817f1de56SFelix Fietkau sband->bitrates = rates; 18917f1de56SFelix Fietkau sband->n_bitrates = n_rates; 19017f1de56SFelix Fietkau dev->chandef.chan = &sband->channels[0]; 1910fd0eb54SFelix Fietkau dev->chan_state = &msband->chan[0]; 19217f1de56SFelix Fietkau 19317f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 19417f1de56SFelix Fietkau ht_cap->ht_supported = true; 19517f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 19617f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 19717f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 19817f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 19917f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 20017f1de56SFelix Fietkau 20117f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 20217f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 20317f1de56SFelix Fietkau ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; 20417f1de56SFelix Fietkau 205551e1ef4SLorenzo Bianconi mt76_init_stream_cap(dev, sband, vht); 206551e1ef4SLorenzo Bianconi 20717f1de56SFelix Fietkau if (!vht) 20817f1de56SFelix Fietkau return 0; 20917f1de56SFelix Fietkau 21017f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 21117f1de56SFelix Fietkau vht_cap->vht_supported = true; 21217f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 21317f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 21449149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 215f1103fa6SRyder Lee IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | 216f1103fa6SRyder Lee IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 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; 278*e5443256SFelix Fietkau int i; 279a85b590cSFelix Fietkau 280a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 281a85b590cSFelix Fietkau if (!hw) 282a85b590cSFelix Fietkau return NULL; 283a85b590cSFelix Fietkau 284a85b590cSFelix Fietkau dev = hw->priv; 285a85b590cSFelix Fietkau dev->hw = hw; 286c0f7b25aSLorenzo Bianconi dev->dev = pdev; 287c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 288c0f7b25aSLorenzo Bianconi 289a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 290a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 291a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 292108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 29326e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 29488046b2cSFelix Fietkau skb_queue_head_init(&dev->status_list); 295a85b590cSFelix Fietkau 296*e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 297*e5443256SFelix Fietkau 298*e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 299*e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]); 300*e5443256SFelix Fietkau 301c325c9c7SLorenzo Bianconi tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev); 302c325c9c7SLorenzo Bianconi 303a85b590cSFelix Fietkau return dev; 304a85b590cSFelix Fietkau } 305a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 306a85b590cSFelix Fietkau 30717f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 30817f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 30917f1de56SFelix Fietkau { 31017f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 31117f1de56SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 31217f1de56SFelix Fietkau int ret; 31317f1de56SFelix Fietkau 31417f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 31517f1de56SFelix Fietkau 31617f1de56SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 31717f1de56SFelix Fietkau SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 31817f1de56SFelix Fietkau 31917f1de56SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 32017f1de56SFelix Fietkau 321b37b30afSKristian Evensen wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 32255857ab8SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 323b37b30afSKristian Evensen 32424114a5fSLorenzo Bianconi wiphy->available_antennas_tx = dev->antenna_mask; 32524114a5fSLorenzo Bianconi wiphy->available_antennas_rx = dev->antenna_mask; 32624114a5fSLorenzo Bianconi 32717f1de56SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 32817f1de56SFelix Fietkau hw->max_tx_fragments = 16; 32917f1de56SFelix Fietkau 33017f1de56SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 33117f1de56SFelix Fietkau ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 33217f1de56SFelix Fietkau ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 33317f1de56SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 33417f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 33517f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 33617f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 33717f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 33817f1de56SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 33917f1de56SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 34017f1de56SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 341d71ef286SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 34288046b2cSFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 343f545540dSFelix Fietkau ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); 34419d0affaSLorenzo Bianconi ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 34517f1de56SFelix Fietkau 34617f1de56SFelix Fietkau wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 3470eb8c104SLorenzo Bianconi wiphy->interface_modes = 3480eb8c104SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 3490eb8c104SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 3500eb8c104SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 3510eb8c104SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 3520eb8c104SLorenzo Bianconi #endif 3530eb8c104SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 35417f1de56SFelix Fietkau 35517f1de56SFelix Fietkau if (dev->cap.has_2ghz) { 35617f1de56SFelix Fietkau ret = mt76_init_sband_2g(dev, rates, n_rates); 35717f1de56SFelix Fietkau if (ret) 35817f1de56SFelix Fietkau return ret; 35917f1de56SFelix Fietkau } 36017f1de56SFelix Fietkau 36117f1de56SFelix Fietkau if (dev->cap.has_5ghz) { 36217f1de56SFelix Fietkau ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht); 36317f1de56SFelix Fietkau if (ret) 36417f1de56SFelix Fietkau return ret; 36517f1de56SFelix Fietkau } 36617f1de56SFelix Fietkau 36717f1de56SFelix Fietkau wiphy_read_of_freq_limits(dev->hw->wiphy); 36817f1de56SFelix Fietkau mt76_check_sband(dev, NL80211_BAND_2GHZ); 36917f1de56SFelix Fietkau mt76_check_sband(dev, NL80211_BAND_5GHZ); 37017f1de56SFelix Fietkau 371b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 37217f1de56SFelix Fietkau ret = mt76_led_init(dev); 37317f1de56SFelix Fietkau if (ret) 37417f1de56SFelix Fietkau return ret; 375b374e868SArnd Bergmann } 37617f1de56SFelix Fietkau 37717f1de56SFelix Fietkau return ieee80211_register_hw(hw); 37817f1de56SFelix Fietkau } 37917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 38017f1de56SFelix Fietkau 38117f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 38217f1de56SFelix Fietkau { 38317f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 38417f1de56SFelix Fietkau 385d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) 38636f7e2b2SFelix Fietkau mt76_led_cleanup(dev); 38779d1c94cSFelix Fietkau mt76_tx_status_check(dev, NULL, true); 38817f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 38917f1de56SFelix Fietkau } 39017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 39117f1de56SFelix Fietkau 392def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 393def34a2fSLorenzo Bianconi { 394def34a2fSLorenzo Bianconi mt76_tx_free(dev); 395def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 396def34a2fSLorenzo Bianconi } 397def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 398def34a2fSLorenzo Bianconi 39917f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 40017f1de56SFelix Fietkau { 40117f1de56SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &dev->state)) { 40217f1de56SFelix Fietkau dev_kfree_skb(skb); 40317f1de56SFelix Fietkau return; 40417f1de56SFelix Fietkau } 40517f1de56SFelix Fietkau 40617f1de56SFelix Fietkau __skb_queue_tail(&dev->rx_skb[q], skb); 40717f1de56SFelix Fietkau } 40817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 40917f1de56SFelix Fietkau 41039d501d9SStanislaw Gruszka bool mt76_has_tx_pending(struct mt76_dev *dev) 41126e40d4cSFelix Fietkau { 412af005f26SLorenzo Bianconi struct mt76_queue *q; 41326e40d4cSFelix Fietkau int i; 41426e40d4cSFelix Fietkau 41526e40d4cSFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) { 416af005f26SLorenzo Bianconi q = dev->q_tx[i].q; 417af005f26SLorenzo Bianconi if (q && q->queued) 41826e40d4cSFelix Fietkau return true; 41926e40d4cSFelix Fietkau } 42026e40d4cSFelix Fietkau 42126e40d4cSFelix Fietkau return false; 42226e40d4cSFelix Fietkau } 42339d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 42426e40d4cSFelix Fietkau 4250fd0eb54SFelix Fietkau static struct mt76_channel_state * 4260fd0eb54SFelix Fietkau mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) 4270fd0eb54SFelix Fietkau { 4280fd0eb54SFelix Fietkau struct mt76_sband *msband; 4290fd0eb54SFelix Fietkau int idx; 4300fd0eb54SFelix Fietkau 4310fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 4320fd0eb54SFelix Fietkau msband = &dev->sband_2g; 4330fd0eb54SFelix Fietkau else 4340fd0eb54SFelix Fietkau msband = &dev->sband_5g; 4350fd0eb54SFelix Fietkau 4360fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 4370fd0eb54SFelix Fietkau return &msband->chan[idx]; 4380fd0eb54SFelix Fietkau } 4390fd0eb54SFelix Fietkau 4405ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev) 4415ce09c1aSFelix Fietkau { 442aec65e48SFelix Fietkau struct mt76_channel_state *state = dev->chan_state; 443aec65e48SFelix Fietkau ktime_t cur_time; 444aec65e48SFelix Fietkau 445aec65e48SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &dev->state)) 446aec65e48SFelix Fietkau return; 447aec65e48SFelix Fietkau 4485ce09c1aSFelix Fietkau if (dev->drv->update_survey) 4495ce09c1aSFelix Fietkau dev->drv->update_survey(dev); 4505ce09c1aSFelix Fietkau 451aec65e48SFelix Fietkau cur_time = ktime_get_boottime(); 452aec65e48SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(cur_time, 453aec65e48SFelix Fietkau dev->survey_time)); 454aec65e48SFelix Fietkau dev->survey_time = cur_time; 455aec65e48SFelix Fietkau 4565ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 457237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 4585ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 4595ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 460237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock); 4615ce09c1aSFelix Fietkau } 4625ce09c1aSFelix Fietkau } 4635ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 4645ce09c1aSFelix Fietkau 46517f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev) 46617f1de56SFelix Fietkau { 46717f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 46817f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 46917f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 47026e40d4cSFelix Fietkau int timeout = HZ / 5; 47117f1de56SFelix Fietkau 47226e40d4cSFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); 4735ce09c1aSFelix Fietkau mt76_update_survey(dev); 47417f1de56SFelix Fietkau 47517f1de56SFelix Fietkau dev->chandef = *chandef; 4760fd0eb54SFelix Fietkau dev->chan_state = mt76_channel_state(dev, chandef->chan); 47717f1de56SFelix Fietkau 47817f1de56SFelix Fietkau if (!offchannel) 47917f1de56SFelix Fietkau dev->main_chan = chandef->chan; 48017f1de56SFelix Fietkau 4810fd0eb54SFelix Fietkau if (chandef->chan != dev->main_chan) 4820fd0eb54SFelix Fietkau memset(dev->chan_state, 0, sizeof(*dev->chan_state)); 48317f1de56SFelix Fietkau } 48417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 48517f1de56SFelix Fietkau 48617f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 48717f1de56SFelix Fietkau struct survey_info *survey) 48817f1de56SFelix Fietkau { 48917f1de56SFelix Fietkau struct mt76_dev *dev = hw->priv; 49017f1de56SFelix Fietkau struct mt76_sband *sband; 49117f1de56SFelix Fietkau struct ieee80211_channel *chan; 49217f1de56SFelix Fietkau struct mt76_channel_state *state; 49317f1de56SFelix Fietkau int ret = 0; 49417f1de56SFelix Fietkau 495237312c5SLorenzo Bianconi mutex_lock(&dev->mutex); 49617f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 4975ce09c1aSFelix Fietkau mt76_update_survey(dev); 49817f1de56SFelix Fietkau 49917f1de56SFelix Fietkau sband = &dev->sband_2g; 50017f1de56SFelix Fietkau if (idx >= sband->sband.n_channels) { 50117f1de56SFelix Fietkau idx -= sband->sband.n_channels; 50217f1de56SFelix Fietkau sband = &dev->sband_5g; 50317f1de56SFelix Fietkau } 50417f1de56SFelix Fietkau 505237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) { 506237312c5SLorenzo Bianconi ret = -ENOENT; 507237312c5SLorenzo Bianconi goto out; 508237312c5SLorenzo Bianconi } 50917f1de56SFelix Fietkau 51017f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 51117f1de56SFelix Fietkau state = mt76_channel_state(dev, chan); 51217f1de56SFelix Fietkau 51317f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 51417f1de56SFelix Fietkau survey->channel = chan; 51517f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 516ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags; 5175ce09c1aSFelix Fietkau if (chan == dev->main_chan) { 51817f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 51917f1de56SFelix Fietkau 5205ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 5215ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 5225ce09c1aSFelix Fietkau } 5235ce09c1aSFelix Fietkau 52417f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 5256bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000); 526237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000); 527237312c5SLorenzo Bianconi 528237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 529237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 530ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000); 53117f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 53217f1de56SFelix Fietkau 533237312c5SLorenzo Bianconi out: 534237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex); 535237312c5SLorenzo Bianconi 53617f1de56SFelix Fietkau return ret; 53717f1de56SFelix Fietkau } 53817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 53917f1de56SFelix Fietkau 54030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 54130ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 54230ce7f44SFelix Fietkau { 54330ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 54430ce7f44SFelix Fietkau int i; 54530ce7f44SFelix Fietkau 54630ce7f44SFelix Fietkau wcid->rx_check_pn = false; 54730ce7f44SFelix Fietkau 54830ce7f44SFelix Fietkau if (!key) 54930ce7f44SFelix Fietkau return; 55030ce7f44SFelix Fietkau 55101cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 55201cfc1b4SLorenzo Bianconi return; 55330ce7f44SFelix Fietkau 55401cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 55530ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 55630ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 55730ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 55830ce7f44SFelix Fietkau } 55930ce7f44SFelix Fietkau } 56030ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 56130ce7f44SFelix Fietkau 562ef836a71SStanislaw Gruszka static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) 5634e34249eSFelix Fietkau { 5644e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 5654e34249eSFelix Fietkau struct mt76_rx_status mstat; 5664e34249eSFelix Fietkau 5674e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 5684e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 5694e34249eSFelix Fietkau 5704e34249eSFelix Fietkau status->flag = mstat.flag; 5714e34249eSFelix Fietkau status->freq = mstat.freq; 5724e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 5734e34249eSFelix Fietkau status->encoding = mstat.encoding; 5744e34249eSFelix Fietkau status->bw = mstat.bw; 5754e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 5764e34249eSFelix Fietkau status->nss = mstat.nss; 5774e34249eSFelix Fietkau status->band = mstat.band; 5784e34249eSFelix Fietkau status->signal = mstat.signal; 5794e34249eSFelix Fietkau status->chains = mstat.chains; 580d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 5814e34249eSFelix Fietkau 5824e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 58313381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 58413381dcdSRyder Lee sizeof(mstat.chain_signal)); 58513381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 58613381dcdSRyder Lee sizeof(mstat.chain_signal)); 5879c68a57bSFelix Fietkau 5889c68a57bSFelix Fietkau return wcid_to_sta(mstat.wcid); 5894e34249eSFelix Fietkau } 5904e34249eSFelix Fietkau 59130ce7f44SFelix Fietkau static int 59230ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 59330ce7f44SFelix Fietkau { 59430ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 59530ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 59630ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 59730ce7f44SFelix Fietkau int ret; 59830ce7f44SFelix Fietkau 59930ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 60030ce7f44SFelix Fietkau return 0; 60130ce7f44SFelix Fietkau 60230ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 60330ce7f44SFelix Fietkau return 0; 60430ce7f44SFelix Fietkau 60530ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 60630ce7f44SFelix Fietkau /* 60730ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 60830ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 60930ce7f44SFelix Fietkau */ 61030ce7f44SFelix Fietkau hdr = (struct ieee80211_hdr *)skb->data; 61130ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 61230ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 61330ce7f44SFelix Fietkau return 0; 61430ce7f44SFelix Fietkau } 61530ce7f44SFelix Fietkau 61630ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 61730ce7f44SFelix Fietkau ret = memcmp(status->iv, wcid->rx_key_pn[status->tid], 61830ce7f44SFelix Fietkau sizeof(status->iv)); 61930ce7f44SFelix Fietkau if (ret <= 0) 62030ce7f44SFelix Fietkau return -EINVAL; /* replay */ 62130ce7f44SFelix Fietkau 62230ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv)); 62330ce7f44SFelix Fietkau 62430ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 62530ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 62630ce7f44SFelix Fietkau 62730ce7f44SFelix Fietkau return 0; 62830ce7f44SFelix Fietkau } 62930ce7f44SFelix Fietkau 630d71ef286SFelix Fietkau static void 6315ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 6325ce09c1aSFelix Fietkau int len) 6335ce09c1aSFelix Fietkau { 6345ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 6355ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 6365ce09c1aSFelix Fietkau u32 airtime; 6375ce09c1aSFelix Fietkau 6385ce09c1aSFelix Fietkau airtime = mt76_calc_rx_airtime(dev, status, len); 639237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock); 6405ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 641237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock); 6425ce09c1aSFelix Fietkau 6435ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 6445ce09c1aSFelix Fietkau return; 6455ce09c1aSFelix Fietkau 6465ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 6475ce09c1aSFelix Fietkau ieee80211_sta_register_airtime(sta, status->tid, 0, airtime); 6485ce09c1aSFelix Fietkau } 6495ce09c1aSFelix Fietkau 6505ce09c1aSFelix Fietkau static void 6515ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 6525ce09c1aSFelix Fietkau { 6535ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 6545ce09c1aSFelix Fietkau int wcid_idx; 6555ce09c1aSFelix Fietkau 6565ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 6575ce09c1aSFelix Fietkau return; 6585ce09c1aSFelix Fietkau 6595ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 660bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid)) 6615ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 6625ce09c1aSFelix Fietkau else 6635ce09c1aSFelix Fietkau wcid = NULL; 6645ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 6655ce09c1aSFelix Fietkau 6665ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 6675ce09c1aSFelix Fietkau 6685ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 6695ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 6705ce09c1aSFelix Fietkau } 6715ce09c1aSFelix Fietkau 6725ce09c1aSFelix Fietkau static void 6735ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 6745ce09c1aSFelix Fietkau { 6755ce09c1aSFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 6765ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 6775ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 6785ce09c1aSFelix Fietkau 6795ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 6805ce09c1aSFelix Fietkau return; 6815ce09c1aSFelix Fietkau 6825ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 6835ce09c1aSFelix Fietkau if (!ether_addr_equal(hdr->addr1, dev->macaddr)) 6845ce09c1aSFelix Fietkau return; 6855ce09c1aSFelix Fietkau 6865ce09c1aSFelix Fietkau wcid = NULL; 6875ce09c1aSFelix Fietkau } 6885ce09c1aSFelix Fietkau 6895ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 6905ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 6915ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 6925ce09c1aSFelix Fietkau 6935ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 6945ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 6955ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 6965ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 6975ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 6985ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 6995ce09c1aSFelix Fietkau } 7005ce09c1aSFelix Fietkau 7015ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 7025ce09c1aSFelix Fietkau return; 7035ce09c1aSFelix Fietkau } 7045ce09c1aSFelix Fietkau 7055ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 7065ce09c1aSFelix Fietkau } 7075ce09c1aSFelix Fietkau 7085ce09c1aSFelix Fietkau static void 709ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 710d71ef286SFelix Fietkau { 711d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 712d71ef286SFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 713d71ef286SFelix Fietkau struct ieee80211_sta *sta; 714d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 715d71ef286SFelix Fietkau bool ps; 71690fdc171SFelix Fietkau int i; 717d71ef286SFelix Fietkau 71836d91096SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { 71936d91096SFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL); 72036d91096SFelix Fietkau if (sta) 72136d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 72236d91096SFelix Fietkau } 72336d91096SFelix Fietkau 7245ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 7255ce09c1aSFelix Fietkau 726d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 727d71ef286SFelix Fietkau return; 728d71ef286SFelix Fietkau 729d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 730d71ef286SFelix Fietkau 73102e5a769SFelix Fietkau if (status->signal <= 0) 73202e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 73302e5a769SFelix Fietkau 734ef13edc0SFelix Fietkau wcid->inactive_count = 0; 735ef13edc0SFelix Fietkau 736d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 737d71ef286SFelix Fietkau return; 738d71ef286SFelix Fietkau 739d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 740d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 741d71ef286SFelix Fietkau return; 742d71ef286SFelix Fietkau } 743d71ef286SFelix Fietkau 744d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 745d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 746d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 747d71ef286SFelix Fietkau return; 748d71ef286SFelix Fietkau 749d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 750d71ef286SFelix Fietkau 751d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 752d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 753d71ef286SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, status->tid); 754d71ef286SFelix Fietkau 755d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 756d71ef286SFelix Fietkau return; 757d71ef286SFelix Fietkau 75811b2a25fSFelix Fietkau if (ps) 759d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 76011b2a25fSFelix Fietkau else 761d71ef286SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 762d71ef286SFelix Fietkau 763d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 7649f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 76590fdc171SFelix Fietkau 76690fdc171SFelix Fietkau if (ps) 76790fdc171SFelix Fietkau return; 76890fdc171SFelix Fietkau 76990fdc171SFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 77090fdc171SFelix Fietkau struct mt76_txq *mtxq; 77190fdc171SFelix Fietkau 77290fdc171SFelix Fietkau if (!sta->txq[i]) 77390fdc171SFelix Fietkau continue; 77490fdc171SFelix Fietkau 77590fdc171SFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 77690fdc171SFelix Fietkau if (!skb_queue_empty(&mtxq->retry_q)) 77790fdc171SFelix Fietkau ieee80211_schedule_txq(dev->hw, sta->txq[i]); 77890fdc171SFelix Fietkau } 779d71ef286SFelix Fietkau } 780d71ef286SFelix Fietkau 7819d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 78281e850efSLorenzo Bianconi struct napi_struct *napi) 78317f1de56SFelix Fietkau { 7849c68a57bSFelix Fietkau struct ieee80211_sta *sta; 7859d9d738bSFelix Fietkau struct sk_buff *skb; 7869d9d738bSFelix Fietkau 787c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 7889d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 78930ce7f44SFelix Fietkau if (mt76_check_ccmp_pn(skb)) { 79030ce7f44SFelix Fietkau dev_kfree_skb(skb); 79130ce7f44SFelix Fietkau continue; 79230ce7f44SFelix Fietkau } 79330ce7f44SFelix Fietkau 7949d9d738bSFelix Fietkau sta = mt76_rx_convert(skb); 7959d9d738bSFelix Fietkau ieee80211_rx_napi(dev->hw, sta, skb, napi); 7969d9d738bSFelix Fietkau } 797c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 7989d9d738bSFelix Fietkau } 7999d9d738bSFelix Fietkau 80081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 80181e850efSLorenzo Bianconi struct napi_struct *napi) 8029d9d738bSFelix Fietkau { 803aee5b8cfSFelix Fietkau struct sk_buff_head frames; 80417f1de56SFelix Fietkau struct sk_buff *skb; 80517f1de56SFelix Fietkau 806aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 807aee5b8cfSFelix Fietkau 808d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 809ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 810aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 811d71ef286SFelix Fietkau } 812aee5b8cfSFelix Fietkau 81381e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 8144e34249eSFelix Fietkau } 81581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 816723b90dcSFelix Fietkau 817e28487eaSFelix Fietkau static int 818e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, 819e28487eaSFelix Fietkau struct ieee80211_sta *sta) 820e28487eaSFelix Fietkau { 821e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 822e28487eaSFelix Fietkau int ret; 823e28487eaSFelix Fietkau int i; 824e28487eaSFelix Fietkau 825e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 826e28487eaSFelix Fietkau 827e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 828e28487eaSFelix Fietkau if (ret) 829e28487eaSFelix Fietkau goto out; 830e28487eaSFelix Fietkau 831e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 832e28487eaSFelix Fietkau struct mt76_txq *mtxq; 833e28487eaSFelix Fietkau 834e28487eaSFelix Fietkau if (!sta->txq[i]) 835e28487eaSFelix Fietkau continue; 836e28487eaSFelix Fietkau 837e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 838e28487eaSFelix Fietkau mtxq->wcid = wcid; 839e28487eaSFelix Fietkau 840e28487eaSFelix Fietkau mt76_txq_init(dev, sta->txq[i]); 841e28487eaSFelix Fietkau } 842e28487eaSFelix Fietkau 843ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 844e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 845e28487eaSFelix Fietkau 846e28487eaSFelix Fietkau out: 847e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 848e28487eaSFelix Fietkau 849e28487eaSFelix Fietkau return ret; 850e28487eaSFelix Fietkau } 851e28487eaSFelix Fietkau 85213f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 853723b90dcSFelix Fietkau struct ieee80211_sta *sta) 854723b90dcSFelix Fietkau { 855723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 85613f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 857723b90dcSFelix Fietkau 858723b90dcSFelix Fietkau rcu_assign_pointer(dev->wcid[idx], NULL); 859723b90dcSFelix Fietkau synchronize_rcu(); 860723b90dcSFelix Fietkau 86158bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 86258bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 86358bab0d4SFelix Fietkau 864e28487eaSFelix Fietkau if (dev->drv->sta_remove) 865e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 866e28487eaSFelix Fietkau 867723b90dcSFelix Fietkau mt76_tx_status_check(dev, wcid, true); 868723b90dcSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 869723b90dcSFelix Fietkau mt76_txq_remove(dev, sta->txq[i]); 870723b90dcSFelix Fietkau mt76_wcid_free(dev->wcid_mask, idx); 87113f61dfcSLorenzo Bianconi } 87213f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 873e28487eaSFelix Fietkau 87413f61dfcSLorenzo Bianconi static void 87513f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 87613f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 87713f61dfcSLorenzo Bianconi { 87813f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 87913f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 880723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 881723b90dcSFelix Fietkau } 882e28487eaSFelix Fietkau 883e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 884e28487eaSFelix Fietkau struct ieee80211_sta *sta, 885e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 886e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 887e28487eaSFelix Fietkau { 888e28487eaSFelix Fietkau struct mt76_dev *dev = hw->priv; 889e28487eaSFelix Fietkau 890e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 891e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 892e28487eaSFelix Fietkau return mt76_sta_add(dev, vif, sta); 893e28487eaSFelix Fietkau 8949c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 8959c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 8969c193de5SFelix Fietkau dev->drv->sta_assoc) 8979c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 8989c193de5SFelix Fietkau 899e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 900e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 901e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 902e28487eaSFelix Fietkau 903e28487eaSFelix Fietkau return 0; 904e28487eaSFelix Fietkau } 905e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 9069313faacSFelix Fietkau 9079313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 9089313faacSFelix Fietkau int *dbm) 9099313faacSFelix Fietkau { 9109313faacSFelix Fietkau struct mt76_dev *dev = hw->priv; 911d0ff23c1SBen Hutchings int n_chains = hweight8(dev->antenna_mask); 9129313faacSFelix Fietkau 913cee646d6SFelix Fietkau *dbm = DIV_ROUND_UP(dev->txpower_cur, 2); 9149313faacSFelix Fietkau 9159313faacSFelix Fietkau /* convert from per-chain power to combined 916c19b0ca5SLorenzo Bianconi * output power 9179313faacSFelix Fietkau */ 918c19b0ca5SLorenzo Bianconi switch (n_chains) { 919c19b0ca5SLorenzo Bianconi case 4: 920c19b0ca5SLorenzo Bianconi *dbm += 6; 921c19b0ca5SLorenzo Bianconi break; 922c19b0ca5SLorenzo Bianconi case 3: 923c19b0ca5SLorenzo Bianconi *dbm += 4; 924c19b0ca5SLorenzo Bianconi break; 925c19b0ca5SLorenzo Bianconi case 2: 9269313faacSFelix Fietkau *dbm += 3; 927c19b0ca5SLorenzo Bianconi break; 928c19b0ca5SLorenzo Bianconi default: 929c19b0ca5SLorenzo Bianconi break; 930c19b0ca5SLorenzo Bianconi } 9319313faacSFelix Fietkau 9329313faacSFelix Fietkau return 0; 9339313faacSFelix Fietkau } 9349313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 935e7173858SFelix Fietkau 936e7173858SFelix Fietkau static void 937e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 938e7173858SFelix Fietkau { 939e7173858SFelix Fietkau if (vif->csa_active && ieee80211_csa_is_complete(vif)) 940e7173858SFelix Fietkau ieee80211_csa_finish(vif); 941e7173858SFelix Fietkau } 942e7173858SFelix Fietkau 943e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 944e7173858SFelix Fietkau { 945e7173858SFelix Fietkau if (!dev->csa_complete) 946e7173858SFelix Fietkau return; 947e7173858SFelix Fietkau 948e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 949e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 950e7173858SFelix Fietkau __mt76_csa_finish, dev); 951e7173858SFelix Fietkau 952e7173858SFelix Fietkau dev->csa_complete = 0; 953e7173858SFelix Fietkau } 954e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 955e7173858SFelix Fietkau 956e7173858SFelix Fietkau static void 957e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 958e7173858SFelix Fietkau { 959e7173858SFelix Fietkau struct mt76_dev *dev = priv; 960e7173858SFelix Fietkau 961e7173858SFelix Fietkau if (!vif->csa_active) 962e7173858SFelix Fietkau return; 963e7173858SFelix Fietkau 964e7173858SFelix Fietkau dev->csa_complete |= ieee80211_csa_is_complete(vif); 965e7173858SFelix Fietkau } 966e7173858SFelix Fietkau 967e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 968e7173858SFelix Fietkau { 969e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 970e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 971e7173858SFelix Fietkau __mt76_csa_check, dev); 972e7173858SFelix Fietkau } 973e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 97487d53103SStanislaw Gruszka 97587d53103SStanislaw Gruszka int 97687d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 97787d53103SStanislaw Gruszka { 97887d53103SStanislaw Gruszka return 0; 97987d53103SStanislaw Gruszka } 98087d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 981eadfd98fSLorenzo Bianconi 982eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 983eadfd98fSLorenzo Bianconi { 984eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 985eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 986eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 987eadfd98fSLorenzo Bianconi 988eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 989eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 990eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 991eadfd98fSLorenzo Bianconi 992eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 993eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 994eadfd98fSLorenzo Bianconi hdr[2] = 0; 995eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 996eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 997eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 998eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 999eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 1000eadfd98fSLorenzo Bianconi 1001eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 1002eadfd98fSLorenzo Bianconi } 1003eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 1004d2679d65SLorenzo Bianconi 1005d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 1006d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 1007d2679d65SLorenzo Bianconi int idx, bool cck) 1008d2679d65SLorenzo Bianconi { 1009d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 1010d2679d65SLorenzo Bianconi 1011d2679d65SLorenzo Bianconi if (cck) { 1012d2679d65SLorenzo Bianconi if (sband == &dev->sband_5g.sband) 1013d2679d65SLorenzo Bianconi return 0; 1014d2679d65SLorenzo Bianconi 1015d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 1016d2679d65SLorenzo Bianconi } else if (sband == &dev->sband_2g.sband) { 1017d2679d65SLorenzo Bianconi offset = 4; 1018d2679d65SLorenzo Bianconi } 1019d2679d65SLorenzo Bianconi 1020d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 1021d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 1022d2679d65SLorenzo Bianconi return i; 1023d2679d65SLorenzo Bianconi } 1024d2679d65SLorenzo Bianconi 1025d2679d65SLorenzo Bianconi return 0; 1026d2679d65SLorenzo Bianconi } 1027d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 10288b8ab5c2SLorenzo Bianconi 10298b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 10308b8ab5c2SLorenzo Bianconi const u8 *mac) 10318b8ab5c2SLorenzo Bianconi { 10328b8ab5c2SLorenzo Bianconi struct mt76_dev *dev = hw->priv; 10338b8ab5c2SLorenzo Bianconi 10348b8ab5c2SLorenzo Bianconi set_bit(MT76_SCANNING, &dev->state); 10358b8ab5c2SLorenzo Bianconi } 10368b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 10378b8ab5c2SLorenzo Bianconi 10388b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 10398b8ab5c2SLorenzo Bianconi { 10408b8ab5c2SLorenzo Bianconi struct mt76_dev *dev = hw->priv; 10418b8ab5c2SLorenzo Bianconi 10428b8ab5c2SLorenzo Bianconi clear_bit(MT76_SCANNING, &dev->state); 10438b8ab5c2SLorenzo Bianconi } 10448b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1045e49c76d4SLorenzo Bianconi 1046e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 1047e49c76d4SLorenzo Bianconi { 1048e49c76d4SLorenzo Bianconi struct mt76_dev *dev = hw->priv; 1049e49c76d4SLorenzo Bianconi 1050e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex); 1051e49c76d4SLorenzo Bianconi *tx_ant = dev->antenna_mask; 1052e49c76d4SLorenzo Bianconi *rx_ant = dev->antenna_mask; 1053e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex); 1054e49c76d4SLorenzo Bianconi 1055e49c76d4SLorenzo Bianconi return 0; 1056e49c76d4SLorenzo Bianconi } 1057e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna); 1058