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 10817f1de56SFelix Fietkau return devm_led_classdev_register(dev->dev, &dev->led_cdev); 10917f1de56SFelix Fietkau } 11017f1de56SFelix Fietkau 111551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev, 112551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 113551e1ef4SLorenzo Bianconi bool vht) 114551e1ef4SLorenzo Bianconi { 115551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 116d0ff23c1SBen Hutchings int i, nstream = hweight8(dev->antenna_mask); 117551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 118551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 119551e1ef4SLorenzo Bianconi 120551e1ef4SLorenzo Bianconi if (nstream > 1) 121551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 122551e1ef4SLorenzo Bianconi else 123551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 124551e1ef4SLorenzo Bianconi 125551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 126551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 127551e1ef4SLorenzo Bianconi 128551e1ef4SLorenzo Bianconi if (!vht) 129551e1ef4SLorenzo Bianconi return; 130551e1ef4SLorenzo Bianconi 131551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 132551e1ef4SLorenzo Bianconi if (nstream > 1) 133551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 134551e1ef4SLorenzo Bianconi else 135551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 136551e1ef4SLorenzo Bianconi 137551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 138551e1ef4SLorenzo Bianconi if (i < nstream) 139551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 140551e1ef4SLorenzo Bianconi else 141551e1ef4SLorenzo Bianconi mcs_map |= 142551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 143551e1ef4SLorenzo Bianconi } 144551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 145551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 146551e1ef4SLorenzo Bianconi } 147551e1ef4SLorenzo Bianconi 1485ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht) 1495ebdc3e0SLorenzo Bianconi { 1505ebdc3e0SLorenzo Bianconi if (dev->cap.has_2ghz) 1515ebdc3e0SLorenzo Bianconi mt76_init_stream_cap(dev, &dev->sband_2g.sband, false); 1525ebdc3e0SLorenzo Bianconi if (dev->cap.has_5ghz) 1535ebdc3e0SLorenzo Bianconi mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht); 1545ebdc3e0SLorenzo Bianconi } 1555ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 1565ebdc3e0SLorenzo Bianconi 15717f1de56SFelix Fietkau static int 15817f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, 15917f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 16017f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates, bool vht) 16117f1de56SFelix Fietkau { 16217f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 16317f1de56SFelix Fietkau struct ieee80211_sta_ht_cap *ht_cap; 16417f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 16517f1de56SFelix Fietkau void *chanlist; 16617f1de56SFelix Fietkau int size; 16717f1de56SFelix Fietkau 16817f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 16917f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 17017f1de56SFelix Fietkau if (!chanlist) 17117f1de56SFelix Fietkau return -ENOMEM; 17217f1de56SFelix Fietkau 173a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 17417f1de56SFelix Fietkau GFP_KERNEL); 17517f1de56SFelix Fietkau if (!msband->chan) 17617f1de56SFelix Fietkau return -ENOMEM; 17717f1de56SFelix Fietkau 17817f1de56SFelix Fietkau sband->channels = chanlist; 17917f1de56SFelix Fietkau sband->n_channels = n_chan; 18017f1de56SFelix Fietkau sband->bitrates = rates; 18117f1de56SFelix Fietkau sband->n_bitrates = n_rates; 18217f1de56SFelix Fietkau dev->chandef.chan = &sband->channels[0]; 1830fd0eb54SFelix Fietkau dev->chan_state = &msband->chan[0]; 18417f1de56SFelix Fietkau 18517f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 18617f1de56SFelix Fietkau ht_cap->ht_supported = true; 18717f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 18817f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 18917f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 19017f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 19117f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 19217f1de56SFelix Fietkau 19317f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 19417f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 19517f1de56SFelix Fietkau ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; 19617f1de56SFelix Fietkau 197551e1ef4SLorenzo Bianconi mt76_init_stream_cap(dev, sband, vht); 198551e1ef4SLorenzo Bianconi 19917f1de56SFelix Fietkau if (!vht) 20017f1de56SFelix Fietkau return 0; 20117f1de56SFelix Fietkau 20217f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 20317f1de56SFelix Fietkau vht_cap->vht_supported = true; 20417f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 20517f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 20649149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 207f1103fa6SRyder Lee IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | 208f1103fa6SRyder Lee IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 20949149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 21017f1de56SFelix Fietkau 21117f1de56SFelix Fietkau return 0; 21217f1de56SFelix Fietkau } 21317f1de56SFelix Fietkau 21417f1de56SFelix Fietkau static int 21517f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates, 21617f1de56SFelix Fietkau int n_rates) 21717f1de56SFelix Fietkau { 21817f1de56SFelix Fietkau dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband; 21917f1de56SFelix Fietkau 22017f1de56SFelix Fietkau return mt76_init_sband(dev, &dev->sband_2g, 22117f1de56SFelix Fietkau mt76_channels_2ghz, 22217f1de56SFelix Fietkau ARRAY_SIZE(mt76_channels_2ghz), 22317f1de56SFelix Fietkau rates, n_rates, false); 22417f1de56SFelix Fietkau } 22517f1de56SFelix Fietkau 22617f1de56SFelix Fietkau static int 22717f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates, 22817f1de56SFelix Fietkau int n_rates, bool vht) 22917f1de56SFelix Fietkau { 23017f1de56SFelix Fietkau dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband; 23117f1de56SFelix Fietkau 23217f1de56SFelix Fietkau return mt76_init_sband(dev, &dev->sband_5g, 23317f1de56SFelix Fietkau mt76_channels_5ghz, 23417f1de56SFelix Fietkau ARRAY_SIZE(mt76_channels_5ghz), 23517f1de56SFelix Fietkau rates, n_rates, vht); 23617f1de56SFelix Fietkau } 23717f1de56SFelix Fietkau 23817f1de56SFelix Fietkau static void 23917f1de56SFelix Fietkau mt76_check_sband(struct mt76_dev *dev, int band) 24017f1de56SFelix Fietkau { 24117f1de56SFelix Fietkau struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band]; 24217f1de56SFelix Fietkau bool found = false; 24317f1de56SFelix Fietkau int i; 24417f1de56SFelix Fietkau 24517f1de56SFelix Fietkau if (!sband) 24617f1de56SFelix Fietkau return; 24717f1de56SFelix Fietkau 24817f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 24917f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 25017f1de56SFelix Fietkau continue; 25117f1de56SFelix Fietkau 25217f1de56SFelix Fietkau found = true; 25317f1de56SFelix Fietkau break; 25417f1de56SFelix Fietkau } 25517f1de56SFelix Fietkau 25617f1de56SFelix Fietkau if (found) 25717f1de56SFelix Fietkau return; 25817f1de56SFelix Fietkau 25917f1de56SFelix Fietkau sband->n_channels = 0; 26017f1de56SFelix Fietkau dev->hw->wiphy->bands[band] = NULL; 26117f1de56SFelix Fietkau } 26217f1de56SFelix Fietkau 263a85b590cSFelix Fietkau struct mt76_dev * 264c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 265c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 266c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 267a85b590cSFelix Fietkau { 268a85b590cSFelix Fietkau struct ieee80211_hw *hw; 269a85b590cSFelix Fietkau struct mt76_dev *dev; 270a85b590cSFelix Fietkau 271a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 272a85b590cSFelix Fietkau if (!hw) 273a85b590cSFelix Fietkau return NULL; 274a85b590cSFelix Fietkau 275a85b590cSFelix Fietkau dev = hw->priv; 276a85b590cSFelix Fietkau dev->hw = hw; 277c0f7b25aSLorenzo Bianconi dev->dev = pdev; 278c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 279c0f7b25aSLorenzo Bianconi 280a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 281a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 282a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 283108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 28426e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 28588046b2cSFelix Fietkau skb_queue_head_init(&dev->status_list); 286a85b590cSFelix Fietkau 287c325c9c7SLorenzo Bianconi tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev); 288c325c9c7SLorenzo Bianconi 289a85b590cSFelix Fietkau return dev; 290a85b590cSFelix Fietkau } 291a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 292a85b590cSFelix Fietkau 29317f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 29417f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 29517f1de56SFelix Fietkau { 29617f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 29717f1de56SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 29817f1de56SFelix Fietkau int ret; 29917f1de56SFelix Fietkau 30017f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 30117f1de56SFelix Fietkau 30217f1de56SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 30317f1de56SFelix Fietkau 30417f1de56SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 30517f1de56SFelix Fietkau SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 30617f1de56SFelix Fietkau 30717f1de56SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 30817f1de56SFelix Fietkau 309b37b30afSKristian Evensen wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 310b37b30afSKristian Evensen 31124114a5fSLorenzo Bianconi wiphy->available_antennas_tx = dev->antenna_mask; 31224114a5fSLorenzo Bianconi wiphy->available_antennas_rx = dev->antenna_mask; 31324114a5fSLorenzo Bianconi 31417f1de56SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 31517f1de56SFelix Fietkau hw->max_tx_fragments = 16; 31617f1de56SFelix Fietkau 31717f1de56SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 31817f1de56SFelix Fietkau ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 31917f1de56SFelix Fietkau ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 32017f1de56SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 32117f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 32217f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 32317f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 32417f1de56SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 32517f1de56SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 32617f1de56SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 32717f1de56SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 328d71ef286SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 32988046b2cSFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 330f545540dSFelix Fietkau ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); 33117f1de56SFelix Fietkau 33217f1de56SFelix Fietkau wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 33317f1de56SFelix Fietkau 33417f1de56SFelix Fietkau if (dev->cap.has_2ghz) { 33517f1de56SFelix Fietkau ret = mt76_init_sband_2g(dev, rates, n_rates); 33617f1de56SFelix Fietkau if (ret) 33717f1de56SFelix Fietkau return ret; 33817f1de56SFelix Fietkau } 33917f1de56SFelix Fietkau 34017f1de56SFelix Fietkau if (dev->cap.has_5ghz) { 34117f1de56SFelix Fietkau ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht); 34217f1de56SFelix Fietkau if (ret) 34317f1de56SFelix Fietkau return ret; 34417f1de56SFelix Fietkau } 34517f1de56SFelix Fietkau 34617f1de56SFelix Fietkau wiphy_read_of_freq_limits(dev->hw->wiphy); 34717f1de56SFelix Fietkau mt76_check_sband(dev, NL80211_BAND_2GHZ); 34817f1de56SFelix Fietkau mt76_check_sband(dev, NL80211_BAND_5GHZ); 34917f1de56SFelix Fietkau 350b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 35117f1de56SFelix Fietkau ret = mt76_led_init(dev); 35217f1de56SFelix Fietkau if (ret) 35317f1de56SFelix Fietkau return ret; 354b374e868SArnd Bergmann } 35517f1de56SFelix Fietkau 35617f1de56SFelix Fietkau return ieee80211_register_hw(hw); 35717f1de56SFelix Fietkau } 35817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 35917f1de56SFelix Fietkau 36017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 36117f1de56SFelix Fietkau { 36217f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 36317f1de56SFelix Fietkau 36479d1c94cSFelix Fietkau mt76_tx_status_check(dev, NULL, true); 36517f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 36617f1de56SFelix Fietkau } 36717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 36817f1de56SFelix Fietkau 369def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 370def34a2fSLorenzo Bianconi { 371def34a2fSLorenzo Bianconi mt76_tx_free(dev); 372def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 373def34a2fSLorenzo Bianconi } 374def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 375def34a2fSLorenzo Bianconi 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 38739d501d9SStanislaw Gruszka bool mt76_has_tx_pending(struct mt76_dev *dev) 38826e40d4cSFelix Fietkau { 389af005f26SLorenzo Bianconi struct mt76_queue *q; 39026e40d4cSFelix Fietkau int i; 39126e40d4cSFelix Fietkau 39226e40d4cSFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) { 393af005f26SLorenzo Bianconi q = dev->q_tx[i].q; 394af005f26SLorenzo Bianconi if (q && q->queued) 39526e40d4cSFelix Fietkau return true; 39626e40d4cSFelix Fietkau } 39726e40d4cSFelix Fietkau 39826e40d4cSFelix Fietkau return false; 39926e40d4cSFelix Fietkau } 40039d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 40126e40d4cSFelix Fietkau 4020fd0eb54SFelix Fietkau static struct mt76_channel_state * 4030fd0eb54SFelix Fietkau mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) 4040fd0eb54SFelix Fietkau { 4050fd0eb54SFelix Fietkau struct mt76_sband *msband; 4060fd0eb54SFelix Fietkau int idx; 4070fd0eb54SFelix Fietkau 4080fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 4090fd0eb54SFelix Fietkau msband = &dev->sband_2g; 4100fd0eb54SFelix Fietkau else 4110fd0eb54SFelix Fietkau msband = &dev->sband_5g; 4120fd0eb54SFelix Fietkau 4130fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 4140fd0eb54SFelix Fietkau return &msband->chan[idx]; 4150fd0eb54SFelix Fietkau } 4160fd0eb54SFelix Fietkau 417*5ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev) 418*5ce09c1aSFelix Fietkau { 419*5ce09c1aSFelix Fietkau struct mt76_channel_state *state; 420*5ce09c1aSFelix Fietkau 421*5ce09c1aSFelix Fietkau if (dev->drv->update_survey) 422*5ce09c1aSFelix Fietkau dev->drv->update_survey(dev); 423*5ce09c1aSFelix Fietkau 424*5ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 425*5ce09c1aSFelix Fietkau state = mt76_channel_state(dev, dev->chandef.chan); 426*5ce09c1aSFelix Fietkau spin_lock_bh(&dev->rx_lock); 427*5ce09c1aSFelix Fietkau spin_lock(&dev->cc_lock); 428*5ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 429*5ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 430*5ce09c1aSFelix Fietkau spin_unlock(&dev->cc_lock); 431*5ce09c1aSFelix Fietkau spin_unlock_bh(&dev->rx_lock); 432*5ce09c1aSFelix Fietkau } 433*5ce09c1aSFelix Fietkau } 434*5ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 435*5ce09c1aSFelix Fietkau 43617f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev) 43717f1de56SFelix Fietkau { 43817f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 43917f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 44017f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 44126e40d4cSFelix Fietkau int timeout = HZ / 5; 44217f1de56SFelix Fietkau 44326e40d4cSFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); 444*5ce09c1aSFelix Fietkau mt76_update_survey(dev); 44517f1de56SFelix Fietkau 44617f1de56SFelix Fietkau dev->chandef = *chandef; 4470fd0eb54SFelix Fietkau dev->chan_state = mt76_channel_state(dev, chandef->chan); 44817f1de56SFelix Fietkau 44917f1de56SFelix Fietkau if (!offchannel) 45017f1de56SFelix Fietkau dev->main_chan = chandef->chan; 45117f1de56SFelix Fietkau 4520fd0eb54SFelix Fietkau if (chandef->chan != dev->main_chan) 4530fd0eb54SFelix Fietkau memset(dev->chan_state, 0, sizeof(*dev->chan_state)); 45417f1de56SFelix Fietkau } 45517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 45617f1de56SFelix Fietkau 45717f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 45817f1de56SFelix Fietkau struct survey_info *survey) 45917f1de56SFelix Fietkau { 46017f1de56SFelix Fietkau struct mt76_dev *dev = hw->priv; 46117f1de56SFelix Fietkau struct mt76_sband *sband; 46217f1de56SFelix Fietkau struct ieee80211_channel *chan; 46317f1de56SFelix Fietkau struct mt76_channel_state *state; 46417f1de56SFelix Fietkau int ret = 0; 46517f1de56SFelix Fietkau 46617f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 467*5ce09c1aSFelix Fietkau mt76_update_survey(dev); 46817f1de56SFelix Fietkau 46917f1de56SFelix Fietkau sband = &dev->sband_2g; 47017f1de56SFelix Fietkau if (idx >= sband->sband.n_channels) { 47117f1de56SFelix Fietkau idx -= sband->sband.n_channels; 47217f1de56SFelix Fietkau sband = &dev->sband_5g; 47317f1de56SFelix Fietkau } 47417f1de56SFelix Fietkau 47517f1de56SFelix Fietkau if (idx >= sband->sband.n_channels) 47617f1de56SFelix Fietkau return -ENOENT; 47717f1de56SFelix Fietkau 47817f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 47917f1de56SFelix Fietkau state = mt76_channel_state(dev, chan); 48017f1de56SFelix Fietkau 48117f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 48217f1de56SFelix Fietkau survey->channel = chan; 48317f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 484*5ce09c1aSFelix Fietkau if (chan == dev->main_chan) { 48517f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 48617f1de56SFelix Fietkau 487*5ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 488*5ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 489*5ce09c1aSFelix Fietkau } 490*5ce09c1aSFelix Fietkau 49117f1de56SFelix Fietkau spin_lock_bh(&dev->cc_lock); 49217f1de56SFelix Fietkau survey->time = div_u64(state->cc_active, 1000); 49317f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 494*5ce09c1aSFelix Fietkau survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 49517f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 49617f1de56SFelix Fietkau 49717f1de56SFelix Fietkau return ret; 49817f1de56SFelix Fietkau } 49917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 50017f1de56SFelix Fietkau 50130ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 50230ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 50330ce7f44SFelix Fietkau { 50430ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 50530ce7f44SFelix Fietkau int i; 50630ce7f44SFelix Fietkau 50730ce7f44SFelix Fietkau wcid->rx_check_pn = false; 50830ce7f44SFelix Fietkau 50930ce7f44SFelix Fietkau if (!key) 51030ce7f44SFelix Fietkau return; 51130ce7f44SFelix Fietkau 51201cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 51301cfc1b4SLorenzo Bianconi return; 51430ce7f44SFelix Fietkau 51501cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 51630ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 51730ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 51830ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 51930ce7f44SFelix Fietkau } 52030ce7f44SFelix Fietkau } 52130ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 52230ce7f44SFelix Fietkau 523ef836a71SStanislaw Gruszka static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) 5244e34249eSFelix Fietkau { 5254e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 5264e34249eSFelix Fietkau struct mt76_rx_status mstat; 5274e34249eSFelix Fietkau 5284e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 5294e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 5304e34249eSFelix Fietkau 5314e34249eSFelix Fietkau status->flag = mstat.flag; 5324e34249eSFelix Fietkau status->freq = mstat.freq; 5334e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 5344e34249eSFelix Fietkau status->encoding = mstat.encoding; 5354e34249eSFelix Fietkau status->bw = mstat.bw; 5364e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 5374e34249eSFelix Fietkau status->nss = mstat.nss; 5384e34249eSFelix Fietkau status->band = mstat.band; 5394e34249eSFelix Fietkau status->signal = mstat.signal; 5404e34249eSFelix Fietkau status->chains = mstat.chains; 541d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 5424e34249eSFelix Fietkau 5434e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 54413381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 54513381dcdSRyder Lee sizeof(mstat.chain_signal)); 54613381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 54713381dcdSRyder Lee sizeof(mstat.chain_signal)); 5489c68a57bSFelix Fietkau 5499c68a57bSFelix Fietkau return wcid_to_sta(mstat.wcid); 5504e34249eSFelix Fietkau } 5514e34249eSFelix Fietkau 55230ce7f44SFelix Fietkau static int 55330ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 55430ce7f44SFelix Fietkau { 55530ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 55630ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 55730ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 55830ce7f44SFelix Fietkau int ret; 55930ce7f44SFelix Fietkau 56030ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 56130ce7f44SFelix Fietkau return 0; 56230ce7f44SFelix Fietkau 56330ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 56430ce7f44SFelix Fietkau return 0; 56530ce7f44SFelix Fietkau 56630ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 56730ce7f44SFelix Fietkau /* 56830ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 56930ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 57030ce7f44SFelix Fietkau */ 57130ce7f44SFelix Fietkau hdr = (struct ieee80211_hdr *)skb->data; 57230ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 57330ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 57430ce7f44SFelix Fietkau return 0; 57530ce7f44SFelix Fietkau } 57630ce7f44SFelix Fietkau 57730ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 57830ce7f44SFelix Fietkau ret = memcmp(status->iv, wcid->rx_key_pn[status->tid], 57930ce7f44SFelix Fietkau sizeof(status->iv)); 58030ce7f44SFelix Fietkau if (ret <= 0) 58130ce7f44SFelix Fietkau return -EINVAL; /* replay */ 58230ce7f44SFelix Fietkau 58330ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv)); 58430ce7f44SFelix Fietkau 58530ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 58630ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 58730ce7f44SFelix Fietkau 58830ce7f44SFelix Fietkau return 0; 58930ce7f44SFelix Fietkau } 59030ce7f44SFelix Fietkau 591d71ef286SFelix Fietkau static void 592*5ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 593*5ce09c1aSFelix Fietkau int len) 594*5ce09c1aSFelix Fietkau { 595*5ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 596*5ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 597*5ce09c1aSFelix Fietkau u32 airtime; 598*5ce09c1aSFelix Fietkau 599*5ce09c1aSFelix Fietkau airtime = mt76_calc_rx_airtime(dev, status, len); 600*5ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 601*5ce09c1aSFelix Fietkau 602*5ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 603*5ce09c1aSFelix Fietkau return; 604*5ce09c1aSFelix Fietkau 605*5ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 606*5ce09c1aSFelix Fietkau ieee80211_sta_register_airtime(sta, status->tid, 0, airtime); 607*5ce09c1aSFelix Fietkau } 608*5ce09c1aSFelix Fietkau 609*5ce09c1aSFelix Fietkau static void 610*5ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 611*5ce09c1aSFelix Fietkau { 612*5ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 613*5ce09c1aSFelix Fietkau int wcid_idx; 614*5ce09c1aSFelix Fietkau 615*5ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 616*5ce09c1aSFelix Fietkau return; 617*5ce09c1aSFelix Fietkau 618*5ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 619*5ce09c1aSFelix Fietkau if (dev->rx_ampdu_status.wcid_idx != 0xff) 620*5ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 621*5ce09c1aSFelix Fietkau else 622*5ce09c1aSFelix Fietkau wcid = NULL; 623*5ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 624*5ce09c1aSFelix Fietkau 625*5ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 626*5ce09c1aSFelix Fietkau 627*5ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 628*5ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 629*5ce09c1aSFelix Fietkau } 630*5ce09c1aSFelix Fietkau 631*5ce09c1aSFelix Fietkau static void 632*5ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 633*5ce09c1aSFelix Fietkau { 634*5ce09c1aSFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 635*5ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 636*5ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 637*5ce09c1aSFelix Fietkau 638*5ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 639*5ce09c1aSFelix Fietkau return; 640*5ce09c1aSFelix Fietkau 641*5ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 642*5ce09c1aSFelix Fietkau if (!ether_addr_equal(hdr->addr1, dev->macaddr)) 643*5ce09c1aSFelix Fietkau return; 644*5ce09c1aSFelix Fietkau 645*5ce09c1aSFelix Fietkau wcid = NULL; 646*5ce09c1aSFelix Fietkau } 647*5ce09c1aSFelix Fietkau 648*5ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 649*5ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 650*5ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 651*5ce09c1aSFelix Fietkau 652*5ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 653*5ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 654*5ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 655*5ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 656*5ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 657*5ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 658*5ce09c1aSFelix Fietkau } 659*5ce09c1aSFelix Fietkau 660*5ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 661*5ce09c1aSFelix Fietkau return; 662*5ce09c1aSFelix Fietkau } 663*5ce09c1aSFelix Fietkau 664*5ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 665*5ce09c1aSFelix Fietkau } 666*5ce09c1aSFelix Fietkau 667*5ce09c1aSFelix Fietkau static void 668ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 669d71ef286SFelix Fietkau { 670d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 671d71ef286SFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 672d71ef286SFelix Fietkau struct ieee80211_sta *sta; 673d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 674d71ef286SFelix Fietkau bool ps; 67590fdc171SFelix Fietkau int i; 676d71ef286SFelix Fietkau 67736d91096SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { 67836d91096SFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL); 67936d91096SFelix Fietkau if (sta) 68036d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 68136d91096SFelix Fietkau } 68236d91096SFelix Fietkau 683*5ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 684*5ce09c1aSFelix Fietkau 685d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 686d71ef286SFelix Fietkau return; 687d71ef286SFelix Fietkau 688d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 689d71ef286SFelix Fietkau 69002e5a769SFelix Fietkau if (status->signal <= 0) 69102e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 69202e5a769SFelix Fietkau 693ef13edc0SFelix Fietkau wcid->inactive_count = 0; 694ef13edc0SFelix Fietkau 695d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 696d71ef286SFelix Fietkau return; 697d71ef286SFelix Fietkau 698d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 699d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 700d71ef286SFelix Fietkau return; 701d71ef286SFelix Fietkau } 702d71ef286SFelix Fietkau 703d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 704d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 705d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 706d71ef286SFelix Fietkau return; 707d71ef286SFelix Fietkau 708d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 709d71ef286SFelix Fietkau 710d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 711d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 712d71ef286SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, status->tid); 713d71ef286SFelix Fietkau 714d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 715d71ef286SFelix Fietkau return; 716d71ef286SFelix Fietkau 71711b2a25fSFelix Fietkau if (ps) 718d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 71911b2a25fSFelix Fietkau else 720d71ef286SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 721d71ef286SFelix Fietkau 722d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 7239f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 72490fdc171SFelix Fietkau 72590fdc171SFelix Fietkau if (ps) 72690fdc171SFelix Fietkau return; 72790fdc171SFelix Fietkau 72890fdc171SFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 72990fdc171SFelix Fietkau struct mt76_txq *mtxq; 73090fdc171SFelix Fietkau 73190fdc171SFelix Fietkau if (!sta->txq[i]) 73290fdc171SFelix Fietkau continue; 73390fdc171SFelix Fietkau 73490fdc171SFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 73590fdc171SFelix Fietkau if (!skb_queue_empty(&mtxq->retry_q)) 73690fdc171SFelix Fietkau ieee80211_schedule_txq(dev->hw, sta->txq[i]); 73790fdc171SFelix Fietkau } 738d71ef286SFelix Fietkau } 739d71ef286SFelix Fietkau 7409d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 74181e850efSLorenzo Bianconi struct napi_struct *napi) 74217f1de56SFelix Fietkau { 7439c68a57bSFelix Fietkau struct ieee80211_sta *sta; 7449d9d738bSFelix Fietkau struct sk_buff *skb; 7459d9d738bSFelix Fietkau 746c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 7479d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 74830ce7f44SFelix Fietkau if (mt76_check_ccmp_pn(skb)) { 74930ce7f44SFelix Fietkau dev_kfree_skb(skb); 75030ce7f44SFelix Fietkau continue; 75130ce7f44SFelix Fietkau } 75230ce7f44SFelix Fietkau 7539d9d738bSFelix Fietkau sta = mt76_rx_convert(skb); 7549d9d738bSFelix Fietkau ieee80211_rx_napi(dev->hw, sta, skb, napi); 7559d9d738bSFelix Fietkau } 756c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 7579d9d738bSFelix Fietkau } 7589d9d738bSFelix Fietkau 75981e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 76081e850efSLorenzo Bianconi struct napi_struct *napi) 7619d9d738bSFelix Fietkau { 762aee5b8cfSFelix Fietkau struct sk_buff_head frames; 76317f1de56SFelix Fietkau struct sk_buff *skb; 76417f1de56SFelix Fietkau 765aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 766aee5b8cfSFelix Fietkau 767d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 768ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 769aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 770d71ef286SFelix Fietkau } 771aee5b8cfSFelix Fietkau 77281e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 7734e34249eSFelix Fietkau } 77481e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 775723b90dcSFelix Fietkau 776e28487eaSFelix Fietkau static int 777e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, 778e28487eaSFelix Fietkau struct ieee80211_sta *sta) 779e28487eaSFelix Fietkau { 780e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 781e28487eaSFelix Fietkau int ret; 782e28487eaSFelix Fietkau int i; 783e28487eaSFelix Fietkau 784e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 785e28487eaSFelix Fietkau 786e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 787e28487eaSFelix Fietkau if (ret) 788e28487eaSFelix Fietkau goto out; 789e28487eaSFelix Fietkau 790e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 791e28487eaSFelix Fietkau struct mt76_txq *mtxq; 792e28487eaSFelix Fietkau 793e28487eaSFelix Fietkau if (!sta->txq[i]) 794e28487eaSFelix Fietkau continue; 795e28487eaSFelix Fietkau 796e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 797e28487eaSFelix Fietkau mtxq->wcid = wcid; 798e28487eaSFelix Fietkau 799e28487eaSFelix Fietkau mt76_txq_init(dev, sta->txq[i]); 800e28487eaSFelix Fietkau } 801e28487eaSFelix Fietkau 802ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 803e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 804e28487eaSFelix Fietkau 805e28487eaSFelix Fietkau out: 806e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 807e28487eaSFelix Fietkau 808e28487eaSFelix Fietkau return ret; 809e28487eaSFelix Fietkau } 810e28487eaSFelix Fietkau 81113f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 812723b90dcSFelix Fietkau struct ieee80211_sta *sta) 813723b90dcSFelix Fietkau { 814723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 81513f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 816723b90dcSFelix Fietkau 817723b90dcSFelix Fietkau rcu_assign_pointer(dev->wcid[idx], NULL); 818723b90dcSFelix Fietkau synchronize_rcu(); 819723b90dcSFelix Fietkau 82058bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 82158bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 82258bab0d4SFelix Fietkau 823e28487eaSFelix Fietkau if (dev->drv->sta_remove) 824e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 825e28487eaSFelix Fietkau 826723b90dcSFelix Fietkau mt76_tx_status_check(dev, wcid, true); 827723b90dcSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 828723b90dcSFelix Fietkau mt76_txq_remove(dev, sta->txq[i]); 829723b90dcSFelix Fietkau mt76_wcid_free(dev->wcid_mask, idx); 83013f61dfcSLorenzo Bianconi } 83113f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 832e28487eaSFelix Fietkau 83313f61dfcSLorenzo Bianconi static void 83413f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 83513f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 83613f61dfcSLorenzo Bianconi { 83713f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 83813f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 839723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 840723b90dcSFelix Fietkau } 841e28487eaSFelix Fietkau 842e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 843e28487eaSFelix Fietkau struct ieee80211_sta *sta, 844e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 845e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 846e28487eaSFelix Fietkau { 847e28487eaSFelix Fietkau struct mt76_dev *dev = hw->priv; 848e28487eaSFelix Fietkau 849e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 850e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 851e28487eaSFelix Fietkau return mt76_sta_add(dev, vif, sta); 852e28487eaSFelix Fietkau 8539c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 8549c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 8559c193de5SFelix Fietkau dev->drv->sta_assoc) 8569c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 8579c193de5SFelix Fietkau 858e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 859e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 860e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 861e28487eaSFelix Fietkau 862e28487eaSFelix Fietkau return 0; 863e28487eaSFelix Fietkau } 864e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 8659313faacSFelix Fietkau 8669313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 8679313faacSFelix Fietkau int *dbm) 8689313faacSFelix Fietkau { 8699313faacSFelix Fietkau struct mt76_dev *dev = hw->priv; 870d0ff23c1SBen Hutchings int n_chains = hweight8(dev->antenna_mask); 8719313faacSFelix Fietkau 872cee646d6SFelix Fietkau *dbm = DIV_ROUND_UP(dev->txpower_cur, 2); 8739313faacSFelix Fietkau 8749313faacSFelix Fietkau /* convert from per-chain power to combined 875c19b0ca5SLorenzo Bianconi * output power 8769313faacSFelix Fietkau */ 877c19b0ca5SLorenzo Bianconi switch (n_chains) { 878c19b0ca5SLorenzo Bianconi case 4: 879c19b0ca5SLorenzo Bianconi *dbm += 6; 880c19b0ca5SLorenzo Bianconi break; 881c19b0ca5SLorenzo Bianconi case 3: 882c19b0ca5SLorenzo Bianconi *dbm += 4; 883c19b0ca5SLorenzo Bianconi break; 884c19b0ca5SLorenzo Bianconi case 2: 8859313faacSFelix Fietkau *dbm += 3; 886c19b0ca5SLorenzo Bianconi break; 887c19b0ca5SLorenzo Bianconi default: 888c19b0ca5SLorenzo Bianconi break; 889c19b0ca5SLorenzo Bianconi } 8909313faacSFelix Fietkau 8919313faacSFelix Fietkau return 0; 8929313faacSFelix Fietkau } 8939313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 894e7173858SFelix Fietkau 895e7173858SFelix Fietkau static void 896e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 897e7173858SFelix Fietkau { 898e7173858SFelix Fietkau if (vif->csa_active && ieee80211_csa_is_complete(vif)) 899e7173858SFelix Fietkau ieee80211_csa_finish(vif); 900e7173858SFelix Fietkau } 901e7173858SFelix Fietkau 902e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 903e7173858SFelix Fietkau { 904e7173858SFelix Fietkau if (!dev->csa_complete) 905e7173858SFelix Fietkau return; 906e7173858SFelix Fietkau 907e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 908e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 909e7173858SFelix Fietkau __mt76_csa_finish, dev); 910e7173858SFelix Fietkau 911e7173858SFelix Fietkau dev->csa_complete = 0; 912e7173858SFelix Fietkau } 913e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 914e7173858SFelix Fietkau 915e7173858SFelix Fietkau static void 916e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 917e7173858SFelix Fietkau { 918e7173858SFelix Fietkau struct mt76_dev *dev = priv; 919e7173858SFelix Fietkau 920e7173858SFelix Fietkau if (!vif->csa_active) 921e7173858SFelix Fietkau return; 922e7173858SFelix Fietkau 923e7173858SFelix Fietkau dev->csa_complete |= ieee80211_csa_is_complete(vif); 924e7173858SFelix Fietkau } 925e7173858SFelix Fietkau 926e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 927e7173858SFelix Fietkau { 928e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 929e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 930e7173858SFelix Fietkau __mt76_csa_check, dev); 931e7173858SFelix Fietkau } 932e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 93387d53103SStanislaw Gruszka 93487d53103SStanislaw Gruszka int 93587d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 93687d53103SStanislaw Gruszka { 93787d53103SStanislaw Gruszka return 0; 93887d53103SStanislaw Gruszka } 93987d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 940eadfd98fSLorenzo Bianconi 941eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 942eadfd98fSLorenzo Bianconi { 943eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 944eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 945eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 946eadfd98fSLorenzo Bianconi 947eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 948eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 949eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 950eadfd98fSLorenzo Bianconi 951eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 952eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 953eadfd98fSLorenzo Bianconi hdr[2] = 0; 954eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 955eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 956eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 957eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 958eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 959eadfd98fSLorenzo Bianconi 960eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 961eadfd98fSLorenzo Bianconi } 962eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 963d2679d65SLorenzo Bianconi 964d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 965d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 966d2679d65SLorenzo Bianconi int idx, bool cck) 967d2679d65SLorenzo Bianconi { 968d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 969d2679d65SLorenzo Bianconi 970d2679d65SLorenzo Bianconi if (cck) { 971d2679d65SLorenzo Bianconi if (sband == &dev->sband_5g.sband) 972d2679d65SLorenzo Bianconi return 0; 973d2679d65SLorenzo Bianconi 974d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 975d2679d65SLorenzo Bianconi } else if (sband == &dev->sband_2g.sband) { 976d2679d65SLorenzo Bianconi offset = 4; 977d2679d65SLorenzo Bianconi } 978d2679d65SLorenzo Bianconi 979d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 980d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 981d2679d65SLorenzo Bianconi return i; 982d2679d65SLorenzo Bianconi } 983d2679d65SLorenzo Bianconi 984d2679d65SLorenzo Bianconi return 0; 985d2679d65SLorenzo Bianconi } 986d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 9878b8ab5c2SLorenzo Bianconi 9888b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 9898b8ab5c2SLorenzo Bianconi const u8 *mac) 9908b8ab5c2SLorenzo Bianconi { 9918b8ab5c2SLorenzo Bianconi struct mt76_dev *dev = hw->priv; 9928b8ab5c2SLorenzo Bianconi 9938b8ab5c2SLorenzo Bianconi set_bit(MT76_SCANNING, &dev->state); 9948b8ab5c2SLorenzo Bianconi } 9958b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 9968b8ab5c2SLorenzo Bianconi 9978b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 9988b8ab5c2SLorenzo Bianconi { 9998b8ab5c2SLorenzo Bianconi struct mt76_dev *dev = hw->priv; 10008b8ab5c2SLorenzo Bianconi 10018b8ab5c2SLorenzo Bianconi clear_bit(MT76_SCANNING, &dev->state); 10028b8ab5c2SLorenzo Bianconi } 10038b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1004