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; 124beaaeb6bSFelix Fietkau int i, nstream = hweight8(dev->phy.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) 15996747a51SFelix Fietkau mt76_init_stream_cap(dev, &dev->phy.sband_2g.sband, false); 1605ebdc3e0SLorenzo Bianconi if (dev->cap.has_5ghz) 16196747a51SFelix Fietkau mt76_init_stream_cap(dev, &dev->phy.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 19117f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 19217f1de56SFelix Fietkau ht_cap->ht_supported = true; 19317f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 19417f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 19517f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 19617f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 19717f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 19817f1de56SFelix Fietkau 19917f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 20017f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 20117f1de56SFelix Fietkau ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; 20217f1de56SFelix Fietkau 203551e1ef4SLorenzo Bianconi mt76_init_stream_cap(dev, sband, vht); 204551e1ef4SLorenzo Bianconi 20517f1de56SFelix Fietkau if (!vht) 20617f1de56SFelix Fietkau return 0; 20717f1de56SFelix Fietkau 20817f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 20917f1de56SFelix Fietkau vht_cap->vht_supported = true; 21017f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 21117f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 21249149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 213f1103fa6SRyder Lee IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | 214f1103fa6SRyder Lee IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 21549149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 21617f1de56SFelix Fietkau 21717f1de56SFelix Fietkau return 0; 21817f1de56SFelix Fietkau } 21917f1de56SFelix Fietkau 22017f1de56SFelix Fietkau static int 22117f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates, 22217f1de56SFelix Fietkau int n_rates) 22317f1de56SFelix Fietkau { 22496747a51SFelix Fietkau dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband; 22517f1de56SFelix Fietkau 22696747a51SFelix Fietkau return mt76_init_sband(dev, &dev->phy.sband_2g, 22717f1de56SFelix Fietkau mt76_channels_2ghz, 22817f1de56SFelix Fietkau ARRAY_SIZE(mt76_channels_2ghz), 22917f1de56SFelix Fietkau rates, n_rates, false); 23017f1de56SFelix Fietkau } 23117f1de56SFelix Fietkau 23217f1de56SFelix Fietkau static int 23317f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates, 23417f1de56SFelix Fietkau int n_rates, bool vht) 23517f1de56SFelix Fietkau { 23696747a51SFelix Fietkau dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband; 23717f1de56SFelix Fietkau 23896747a51SFelix Fietkau return mt76_init_sband(dev, &dev->phy.sband_5g, 23917f1de56SFelix Fietkau mt76_channels_5ghz, 24017f1de56SFelix Fietkau ARRAY_SIZE(mt76_channels_5ghz), 24117f1de56SFelix Fietkau rates, n_rates, vht); 24217f1de56SFelix Fietkau } 24317f1de56SFelix Fietkau 24417f1de56SFelix Fietkau static void 245c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 246c89d3625SFelix Fietkau enum nl80211_band band) 24717f1de56SFelix Fietkau { 248c89d3625SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 24917f1de56SFelix Fietkau bool found = false; 25017f1de56SFelix Fietkau int i; 25117f1de56SFelix Fietkau 25217f1de56SFelix Fietkau if (!sband) 25317f1de56SFelix Fietkau return; 25417f1de56SFelix Fietkau 25517f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 25617f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 25717f1de56SFelix Fietkau continue; 25817f1de56SFelix Fietkau 25917f1de56SFelix Fietkau found = true; 26017f1de56SFelix Fietkau break; 26117f1de56SFelix Fietkau } 26217f1de56SFelix Fietkau 263c89d3625SFelix Fietkau if (found) { 264c89d3625SFelix Fietkau phy->chandef.chan = &sband->channels[0]; 265c89d3625SFelix Fietkau phy->chan_state = &msband->chan[0]; 26617f1de56SFelix Fietkau return; 267c89d3625SFelix Fietkau } 26817f1de56SFelix Fietkau 26917f1de56SFelix Fietkau sband->n_channels = 0; 270c89d3625SFelix Fietkau phy->hw->wiphy->bands[band] = NULL; 27117f1de56SFelix Fietkau } 27217f1de56SFelix Fietkau 273c89d3625SFelix Fietkau static void 274c89d3625SFelix Fietkau mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) 275c89d3625SFelix Fietkau { 276c89d3625SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 277c89d3625SFelix Fietkau 278c89d3625SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 279c89d3625SFelix Fietkau SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 280c89d3625SFelix Fietkau 281c89d3625SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 282fecde5daSLorenzo Bianconi wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; 283c89d3625SFelix Fietkau 284c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 285c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 286c89d3625SFelix Fietkau 287c89d3625SFelix Fietkau wiphy->available_antennas_tx = dev->phy.antenna_mask; 288c89d3625SFelix Fietkau wiphy->available_antennas_rx = dev->phy.antenna_mask; 289c89d3625SFelix Fietkau 290c89d3625SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 291c9619dfaSShayne Chen 292c9619dfaSShayne Chen if (!hw->max_tx_fragments) 293c89d3625SFelix Fietkau hw->max_tx_fragments = 16; 294c89d3625SFelix Fietkau 295c89d3625SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 296c89d3625SFelix Fietkau ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 297c89d3625SFelix Fietkau ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 298c89d3625SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 299c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 300c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 301c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 302c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 303c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 304c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 305c89d3625SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 306c89d3625SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 307c89d3625SFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 308c89d3625SFelix Fietkau ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); 309c89d3625SFelix Fietkau 310c89d3625SFelix Fietkau wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 311c89d3625SFelix Fietkau wiphy->interface_modes = 312c89d3625SFelix Fietkau BIT(NL80211_IFTYPE_STATION) | 313c89d3625SFelix Fietkau BIT(NL80211_IFTYPE_AP) | 314c89d3625SFelix Fietkau #ifdef CONFIG_MAC80211_MESH 315c89d3625SFelix Fietkau BIT(NL80211_IFTYPE_MESH_POINT) | 316c89d3625SFelix Fietkau #endif 317c89d3625SFelix Fietkau BIT(NL80211_IFTYPE_ADHOC); 318c89d3625SFelix Fietkau } 319c89d3625SFelix Fietkau 320c89d3625SFelix Fietkau struct mt76_phy * 321c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 322c89d3625SFelix Fietkau const struct ieee80211_ops *ops) 323c89d3625SFelix Fietkau { 324c89d3625SFelix Fietkau struct ieee80211_hw *hw; 325c89d3625SFelix Fietkau struct mt76_phy *phy; 326c89d3625SFelix Fietkau unsigned int phy_size, chan_size; 327c89d3625SFelix Fietkau unsigned int size_2g, size_5g; 328c89d3625SFelix Fietkau void *priv; 329c89d3625SFelix Fietkau 330c89d3625SFelix Fietkau phy_size = ALIGN(sizeof(*phy), 8); 331c89d3625SFelix Fietkau chan_size = sizeof(dev->phy.sband_2g.chan[0]); 332c89d3625SFelix Fietkau size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8); 333c89d3625SFelix Fietkau size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8); 334c89d3625SFelix Fietkau 335c89d3625SFelix Fietkau size += phy_size + size_2g + size_5g; 336c89d3625SFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 337c89d3625SFelix Fietkau if (!hw) 338c89d3625SFelix Fietkau return NULL; 339c89d3625SFelix Fietkau 340c89d3625SFelix Fietkau phy = hw->priv; 341c89d3625SFelix Fietkau phy->dev = dev; 342c89d3625SFelix Fietkau phy->hw = hw; 343c89d3625SFelix Fietkau 344c89d3625SFelix Fietkau mt76_phy_init(dev, hw); 345c89d3625SFelix Fietkau 346c89d3625SFelix Fietkau priv = hw->priv + phy_size; 347c89d3625SFelix Fietkau 348c89d3625SFelix Fietkau phy->sband_2g = dev->phy.sband_2g; 349c89d3625SFelix Fietkau phy->sband_2g.chan = priv; 350c89d3625SFelix Fietkau priv += size_2g; 351c89d3625SFelix Fietkau 352c89d3625SFelix Fietkau phy->sband_5g = dev->phy.sband_5g; 353c89d3625SFelix Fietkau phy->sband_5g.chan = priv; 354c89d3625SFelix Fietkau priv += size_5g; 355c89d3625SFelix Fietkau 356c89d3625SFelix Fietkau phy->priv = priv; 357c89d3625SFelix Fietkau 358c89d3625SFelix Fietkau hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 359c89d3625SFelix Fietkau hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 360c89d3625SFelix Fietkau 361c89d3625SFelix Fietkau mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 362c89d3625SFelix Fietkau mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 363c89d3625SFelix Fietkau 364c89d3625SFelix Fietkau return phy; 365c89d3625SFelix Fietkau } 366c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy); 367c89d3625SFelix Fietkau 368c89d3625SFelix Fietkau int 369c89d3625SFelix Fietkau mt76_register_phy(struct mt76_phy *phy) 370c89d3625SFelix Fietkau { 371c89d3625SFelix Fietkau int ret; 372c89d3625SFelix Fietkau 373c89d3625SFelix Fietkau ret = ieee80211_register_hw(phy->hw); 374c89d3625SFelix Fietkau if (ret) 375c89d3625SFelix Fietkau return ret; 376c89d3625SFelix Fietkau 377c89d3625SFelix Fietkau phy->dev->phy2 = phy; 378c89d3625SFelix Fietkau return 0; 379c89d3625SFelix Fietkau } 380c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy); 381c89d3625SFelix Fietkau 382c89d3625SFelix Fietkau void 383c89d3625SFelix Fietkau mt76_unregister_phy(struct mt76_phy *phy) 384c89d3625SFelix Fietkau { 385c89d3625SFelix Fietkau struct mt76_dev *dev = phy->dev; 386c89d3625SFelix Fietkau 387c89d3625SFelix Fietkau dev->phy2 = NULL; 388c89d3625SFelix Fietkau mt76_tx_status_check(dev, NULL, true); 389c89d3625SFelix Fietkau ieee80211_unregister_hw(phy->hw); 390c89d3625SFelix Fietkau } 391c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy); 392c89d3625SFelix Fietkau 393a85b590cSFelix Fietkau struct mt76_dev * 394c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 395c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 396c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 397a85b590cSFelix Fietkau { 398a85b590cSFelix Fietkau struct ieee80211_hw *hw; 399ac24dd35SFelix Fietkau struct mt76_phy *phy; 400a85b590cSFelix Fietkau struct mt76_dev *dev; 401e5443256SFelix Fietkau int i; 402a85b590cSFelix Fietkau 403a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 404a85b590cSFelix Fietkau if (!hw) 405a85b590cSFelix Fietkau return NULL; 406a85b590cSFelix Fietkau 407a85b590cSFelix Fietkau dev = hw->priv; 408a85b590cSFelix Fietkau dev->hw = hw; 409c0f7b25aSLorenzo Bianconi dev->dev = pdev; 410c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 411c0f7b25aSLorenzo Bianconi 412ac24dd35SFelix Fietkau phy = &dev->phy; 413ac24dd35SFelix Fietkau phy->dev = dev; 414ac24dd35SFelix Fietkau phy->hw = hw; 415ac24dd35SFelix Fietkau 416a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 417a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 418a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 419108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 42026e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 42188046b2cSFelix Fietkau skb_queue_head_init(&dev->status_list); 422a85b590cSFelix Fietkau 423e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 424e5443256SFelix Fietkau 425e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 426e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]); 427e5443256SFelix Fietkau 428c325c9c7SLorenzo Bianconi tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev); 429c325c9c7SLorenzo Bianconi 430a85b590cSFelix Fietkau return dev; 431a85b590cSFelix Fietkau } 432a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 433a85b590cSFelix Fietkau 43417f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 43517f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 43617f1de56SFelix Fietkau { 43717f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 438c89d3625SFelix Fietkau struct mt76_phy *phy = &dev->phy; 43917f1de56SFelix Fietkau int ret; 44017f1de56SFelix Fietkau 44117f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 442c89d3625SFelix Fietkau mt76_phy_init(dev, hw); 44317f1de56SFelix Fietkau 44417f1de56SFelix Fietkau if (dev->cap.has_2ghz) { 44517f1de56SFelix Fietkau ret = mt76_init_sband_2g(dev, rates, n_rates); 44617f1de56SFelix Fietkau if (ret) 44717f1de56SFelix Fietkau return ret; 44817f1de56SFelix Fietkau } 44917f1de56SFelix Fietkau 45017f1de56SFelix Fietkau if (dev->cap.has_5ghz) { 45117f1de56SFelix Fietkau ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht); 45217f1de56SFelix Fietkau if (ret) 45317f1de56SFelix Fietkau return ret; 45417f1de56SFelix Fietkau } 45517f1de56SFelix Fietkau 456c89d3625SFelix Fietkau wiphy_read_of_freq_limits(hw->wiphy); 457c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 458c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 45917f1de56SFelix Fietkau 460b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 46117f1de56SFelix Fietkau ret = mt76_led_init(dev); 46217f1de56SFelix Fietkau if (ret) 46317f1de56SFelix Fietkau return ret; 464b374e868SArnd Bergmann } 46517f1de56SFelix Fietkau 46617f1de56SFelix Fietkau return ieee80211_register_hw(hw); 46717f1de56SFelix Fietkau } 46817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 46917f1de56SFelix Fietkau 47017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 47117f1de56SFelix Fietkau { 47217f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 47317f1de56SFelix Fietkau 474d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) 47536f7e2b2SFelix Fietkau mt76_led_cleanup(dev); 47679d1c94cSFelix Fietkau mt76_tx_status_check(dev, NULL, true); 47717f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 47817f1de56SFelix Fietkau } 47917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 48017f1de56SFelix Fietkau 481def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 482def34a2fSLorenzo Bianconi { 483def34a2fSLorenzo Bianconi mt76_tx_free(dev); 484def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 485def34a2fSLorenzo Bianconi } 486def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 487def34a2fSLorenzo Bianconi 48817f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 48917f1de56SFelix Fietkau { 490011849e0SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 491011849e0SFelix Fietkau struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy); 492011849e0SFelix Fietkau 493011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 49417f1de56SFelix Fietkau dev_kfree_skb(skb); 49517f1de56SFelix Fietkau return; 49617f1de56SFelix Fietkau } 49717f1de56SFelix Fietkau 49817f1de56SFelix Fietkau __skb_queue_tail(&dev->rx_skb[q], skb); 49917f1de56SFelix Fietkau } 50017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 50117f1de56SFelix Fietkau 5025a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy) 50326e40d4cSFelix Fietkau { 5045a95ca41SFelix Fietkau struct mt76_dev *dev = phy->dev; 505af005f26SLorenzo Bianconi struct mt76_queue *q; 5065a95ca41SFelix Fietkau int i, offset; 50726e40d4cSFelix Fietkau 5085a95ca41SFelix Fietkau offset = __MT_TXQ_MAX * (phy != &dev->phy); 5095a95ca41SFelix Fietkau 5105a95ca41SFelix Fietkau for (i = 0; i < __MT_TXQ_MAX; i++) { 5115a95ca41SFelix Fietkau q = dev->q_tx[offset + i].q; 512af005f26SLorenzo Bianconi if (q && q->queued) 51326e40d4cSFelix Fietkau return true; 51426e40d4cSFelix Fietkau } 51526e40d4cSFelix Fietkau 51626e40d4cSFelix Fietkau return false; 51726e40d4cSFelix Fietkau } 51839d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 51926e40d4cSFelix Fietkau 5200fd0eb54SFelix Fietkau static struct mt76_channel_state * 52196747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 5220fd0eb54SFelix Fietkau { 5230fd0eb54SFelix Fietkau struct mt76_sband *msband; 5240fd0eb54SFelix Fietkau int idx; 5250fd0eb54SFelix Fietkau 5260fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 52796747a51SFelix Fietkau msband = &phy->sband_2g; 5280fd0eb54SFelix Fietkau else 52996747a51SFelix Fietkau msband = &phy->sband_5g; 5300fd0eb54SFelix Fietkau 5310fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 5320fd0eb54SFelix Fietkau return &msband->chan[idx]; 5330fd0eb54SFelix Fietkau } 5340fd0eb54SFelix Fietkau 53596747a51SFelix Fietkau static void 53696747a51SFelix Fietkau mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 53796747a51SFelix Fietkau { 53896747a51SFelix Fietkau struct mt76_channel_state *state = phy->chan_state; 53996747a51SFelix Fietkau 54096747a51SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(time, 54196747a51SFelix Fietkau phy->survey_time)); 54296747a51SFelix Fietkau phy->survey_time = time; 54396747a51SFelix Fietkau } 54496747a51SFelix Fietkau 5455ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev) 5465ce09c1aSFelix Fietkau { 547aec65e48SFelix Fietkau ktime_t cur_time; 548aec65e48SFelix Fietkau 5495ce09c1aSFelix Fietkau if (dev->drv->update_survey) 5505ce09c1aSFelix Fietkau dev->drv->update_survey(dev); 5515ce09c1aSFelix Fietkau 552aec65e48SFelix Fietkau cur_time = ktime_get_boottime(); 55396747a51SFelix Fietkau mt76_update_survey_active_time(&dev->phy, cur_time); 55496747a51SFelix Fietkau if (dev->phy2) 55596747a51SFelix Fietkau mt76_update_survey_active_time(dev->phy2, cur_time); 556aec65e48SFelix Fietkau 5575ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 55896747a51SFelix Fietkau struct mt76_channel_state *state = dev->phy.chan_state; 55996747a51SFelix Fietkau 560237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 5615ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 5625ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 563237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock); 5645ce09c1aSFelix Fietkau } 5655ce09c1aSFelix Fietkau } 5665ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 5675ce09c1aSFelix Fietkau 56896747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy) 56917f1de56SFelix Fietkau { 57096747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 57196747a51SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 57217f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 57317f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 57426e40d4cSFelix Fietkau int timeout = HZ / 5; 57517f1de56SFelix Fietkau 5765a95ca41SFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 5775ce09c1aSFelix Fietkau mt76_update_survey(dev); 57817f1de56SFelix Fietkau 57996747a51SFelix Fietkau phy->chandef = *chandef; 58096747a51SFelix Fietkau phy->chan_state = mt76_channel_state(phy, chandef->chan); 58117f1de56SFelix Fietkau 58217f1de56SFelix Fietkau if (!offchannel) 58396747a51SFelix Fietkau phy->main_chan = chandef->chan; 58417f1de56SFelix Fietkau 58596747a51SFelix Fietkau if (chandef->chan != phy->main_chan) 58696747a51SFelix Fietkau memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 58717f1de56SFelix Fietkau } 58817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 58917f1de56SFelix Fietkau 59017f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 59117f1de56SFelix Fietkau struct survey_info *survey) 59217f1de56SFelix Fietkau { 59396747a51SFelix Fietkau struct mt76_phy *phy = hw->priv; 59496747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 59517f1de56SFelix Fietkau struct mt76_sband *sband; 59617f1de56SFelix Fietkau struct ieee80211_channel *chan; 59717f1de56SFelix Fietkau struct mt76_channel_state *state; 59817f1de56SFelix Fietkau int ret = 0; 59917f1de56SFelix Fietkau 600237312c5SLorenzo Bianconi mutex_lock(&dev->mutex); 60117f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 6025ce09c1aSFelix Fietkau mt76_update_survey(dev); 60317f1de56SFelix Fietkau 60496747a51SFelix Fietkau sband = &phy->sband_2g; 60517f1de56SFelix Fietkau if (idx >= sband->sband.n_channels) { 60617f1de56SFelix Fietkau idx -= sband->sband.n_channels; 60796747a51SFelix Fietkau sband = &phy->sband_5g; 60817f1de56SFelix Fietkau } 60917f1de56SFelix Fietkau 610237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) { 611237312c5SLorenzo Bianconi ret = -ENOENT; 612237312c5SLorenzo Bianconi goto out; 613237312c5SLorenzo Bianconi } 61417f1de56SFelix Fietkau 61517f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 61696747a51SFelix Fietkau state = mt76_channel_state(phy, chan); 61717f1de56SFelix Fietkau 61817f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 61917f1de56SFelix Fietkau survey->channel = chan; 62017f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 621ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags; 622e5051965SFelix Fietkau if (state->noise) 623e5051965SFelix Fietkau survey->filled |= SURVEY_INFO_NOISE_DBM; 624e5051965SFelix Fietkau 62596747a51SFelix Fietkau if (chan == phy->main_chan) { 62617f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 62717f1de56SFelix Fietkau 6285ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 6295ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 6305ce09c1aSFelix Fietkau } 6315ce09c1aSFelix Fietkau 63217f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 6336bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000); 634237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000); 635e5051965SFelix Fietkau survey->noise = state->noise; 636237312c5SLorenzo Bianconi 637237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 638237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 639ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000); 64017f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 64117f1de56SFelix Fietkau 642237312c5SLorenzo Bianconi out: 643237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex); 644237312c5SLorenzo Bianconi 64517f1de56SFelix Fietkau return ret; 64617f1de56SFelix Fietkau } 64717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 64817f1de56SFelix Fietkau 64930ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 65030ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 65130ce7f44SFelix Fietkau { 65230ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 65330ce7f44SFelix Fietkau int i; 65430ce7f44SFelix Fietkau 65530ce7f44SFelix Fietkau wcid->rx_check_pn = false; 65630ce7f44SFelix Fietkau 65730ce7f44SFelix Fietkau if (!key) 65830ce7f44SFelix Fietkau return; 65930ce7f44SFelix Fietkau 66001cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 66101cfc1b4SLorenzo Bianconi return; 66230ce7f44SFelix Fietkau 66301cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 66430ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 66530ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 66630ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 66730ce7f44SFelix Fietkau } 66830ce7f44SFelix Fietkau } 66930ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 67030ce7f44SFelix Fietkau 671bfc394ddSFelix Fietkau static void 672bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 673bfc394ddSFelix Fietkau struct ieee80211_hw **hw, 674bfc394ddSFelix Fietkau struct ieee80211_sta **sta) 6754e34249eSFelix Fietkau { 676bfc394ddSFelix Fietkau 6774e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 6784e34249eSFelix Fietkau struct mt76_rx_status mstat; 6794e34249eSFelix Fietkau 6804e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 6814e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 6824e34249eSFelix Fietkau 6834e34249eSFelix Fietkau status->flag = mstat.flag; 6844e34249eSFelix Fietkau status->freq = mstat.freq; 6854e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 6864e34249eSFelix Fietkau status->encoding = mstat.encoding; 6874e34249eSFelix Fietkau status->bw = mstat.bw; 6884e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 6894e34249eSFelix Fietkau status->nss = mstat.nss; 6904e34249eSFelix Fietkau status->band = mstat.band; 6914e34249eSFelix Fietkau status->signal = mstat.signal; 6924e34249eSFelix Fietkau status->chains = mstat.chains; 693d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 6944e34249eSFelix Fietkau 6954e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 69613381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 69713381dcdSRyder Lee sizeof(mstat.chain_signal)); 69813381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 69913381dcdSRyder Lee sizeof(mstat.chain_signal)); 7009c68a57bSFelix Fietkau 701bfc394ddSFelix Fietkau *sta = wcid_to_sta(mstat.wcid); 702bfc394ddSFelix Fietkau *hw = mt76_phy_hw(dev, mstat.ext_phy); 7034e34249eSFelix Fietkau } 7044e34249eSFelix Fietkau 70530ce7f44SFelix Fietkau static int 70630ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 70730ce7f44SFelix Fietkau { 70830ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 70930ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 71030ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 71130ce7f44SFelix Fietkau int ret; 71230ce7f44SFelix Fietkau 71330ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 71430ce7f44SFelix Fietkau return 0; 71530ce7f44SFelix Fietkau 71630ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 71730ce7f44SFelix Fietkau return 0; 71830ce7f44SFelix Fietkau 71930ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 72030ce7f44SFelix Fietkau /* 72130ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 72230ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 72330ce7f44SFelix Fietkau */ 72430ce7f44SFelix Fietkau hdr = (struct ieee80211_hdr *)skb->data; 72530ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 72630ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 72730ce7f44SFelix Fietkau return 0; 72830ce7f44SFelix Fietkau } 72930ce7f44SFelix Fietkau 73030ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 73130ce7f44SFelix Fietkau ret = memcmp(status->iv, wcid->rx_key_pn[status->tid], 73230ce7f44SFelix Fietkau sizeof(status->iv)); 73330ce7f44SFelix Fietkau if (ret <= 0) 73430ce7f44SFelix Fietkau return -EINVAL; /* replay */ 73530ce7f44SFelix Fietkau 73630ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv)); 73730ce7f44SFelix Fietkau 73830ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 73930ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 74030ce7f44SFelix Fietkau 74130ce7f44SFelix Fietkau return 0; 74230ce7f44SFelix Fietkau } 74330ce7f44SFelix Fietkau 744d71ef286SFelix Fietkau static void 7455ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 7465ce09c1aSFelix Fietkau int len) 7475ce09c1aSFelix Fietkau { 7485ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 749*85b7a5d0SLorenzo Bianconi struct ieee80211_rx_status info = { 750*85b7a5d0SLorenzo Bianconi .enc_flags = status->enc_flags, 751*85b7a5d0SLorenzo Bianconi .rate_idx = status->rate_idx, 752*85b7a5d0SLorenzo Bianconi .encoding = status->encoding, 753*85b7a5d0SLorenzo Bianconi .band = status->band, 754*85b7a5d0SLorenzo Bianconi .nss = status->nss, 755*85b7a5d0SLorenzo Bianconi .bw = status->bw, 756*85b7a5d0SLorenzo Bianconi }; 7575ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 7585ce09c1aSFelix Fietkau u32 airtime; 7595ce09c1aSFelix Fietkau 760*85b7a5d0SLorenzo Bianconi airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 761237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock); 7625ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 763237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock); 7645ce09c1aSFelix Fietkau 7655ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 7665ce09c1aSFelix Fietkau return; 7675ce09c1aSFelix Fietkau 7685ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 7695ce09c1aSFelix Fietkau ieee80211_sta_register_airtime(sta, status->tid, 0, airtime); 7705ce09c1aSFelix Fietkau } 7715ce09c1aSFelix Fietkau 7725ce09c1aSFelix Fietkau static void 7735ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 7745ce09c1aSFelix Fietkau { 7755ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 7765ce09c1aSFelix Fietkau int wcid_idx; 7775ce09c1aSFelix Fietkau 7785ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 7795ce09c1aSFelix Fietkau return; 7805ce09c1aSFelix Fietkau 7815ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 782bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid)) 7835ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 7845ce09c1aSFelix Fietkau else 7855ce09c1aSFelix Fietkau wcid = NULL; 7865ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 7875ce09c1aSFelix Fietkau 7885ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 7895ce09c1aSFelix Fietkau 7905ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 7915ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 7925ce09c1aSFelix Fietkau } 7935ce09c1aSFelix Fietkau 7945ce09c1aSFelix Fietkau static void 7955ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 7965ce09c1aSFelix Fietkau { 7975ce09c1aSFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 7985ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 7995ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 8005ce09c1aSFelix Fietkau 8015ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 8025ce09c1aSFelix Fietkau return; 8035ce09c1aSFelix Fietkau 8045ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 8055ce09c1aSFelix Fietkau if (!ether_addr_equal(hdr->addr1, dev->macaddr)) 8065ce09c1aSFelix Fietkau return; 8075ce09c1aSFelix Fietkau 8085ce09c1aSFelix Fietkau wcid = NULL; 8095ce09c1aSFelix Fietkau } 8105ce09c1aSFelix Fietkau 8115ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 8125ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 8135ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 8145ce09c1aSFelix Fietkau 8155ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 8165ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 8175ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 8185ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 8195ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 8205ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 8215ce09c1aSFelix Fietkau } 8225ce09c1aSFelix Fietkau 8235ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 8245ce09c1aSFelix Fietkau return; 8255ce09c1aSFelix Fietkau } 8265ce09c1aSFelix Fietkau 8275ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 8285ce09c1aSFelix Fietkau } 8295ce09c1aSFelix Fietkau 8305ce09c1aSFelix Fietkau static void 831ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 832d71ef286SFelix Fietkau { 833d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 834d71ef286SFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 835d71ef286SFelix Fietkau struct ieee80211_sta *sta; 836bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 837d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 838d71ef286SFelix Fietkau bool ps; 83990fdc171SFelix Fietkau int i; 840d71ef286SFelix Fietkau 841bfc394ddSFelix Fietkau hw = mt76_phy_hw(dev, status->ext_phy); 84236d91096SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { 843bfc394ddSFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 84436d91096SFelix Fietkau if (sta) 84536d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 84636d91096SFelix Fietkau } 84736d91096SFelix Fietkau 8485ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 8495ce09c1aSFelix Fietkau 850d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 851d71ef286SFelix Fietkau return; 852d71ef286SFelix Fietkau 853d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 854d71ef286SFelix Fietkau 85502e5a769SFelix Fietkau if (status->signal <= 0) 85602e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 85702e5a769SFelix Fietkau 858ef13edc0SFelix Fietkau wcid->inactive_count = 0; 859ef13edc0SFelix Fietkau 860d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 861d71ef286SFelix Fietkau return; 862d71ef286SFelix Fietkau 863d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 864d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 865d71ef286SFelix Fietkau return; 866d71ef286SFelix Fietkau } 867d71ef286SFelix Fietkau 868d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 869d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 870d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 871d71ef286SFelix Fietkau return; 872d71ef286SFelix Fietkau 873d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 874d71ef286SFelix Fietkau 875d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 876d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 877d71ef286SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, status->tid); 878d71ef286SFelix Fietkau 879d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 880d71ef286SFelix Fietkau return; 881d71ef286SFelix Fietkau 88211b2a25fSFelix Fietkau if (ps) 883d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 88411b2a25fSFelix Fietkau else 885d71ef286SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 886d71ef286SFelix Fietkau 887d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 8889f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 88990fdc171SFelix Fietkau 89090fdc171SFelix Fietkau if (ps) 89190fdc171SFelix Fietkau return; 89290fdc171SFelix Fietkau 89390fdc171SFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 89490fdc171SFelix Fietkau struct mt76_txq *mtxq; 89590fdc171SFelix Fietkau 89690fdc171SFelix Fietkau if (!sta->txq[i]) 89790fdc171SFelix Fietkau continue; 89890fdc171SFelix Fietkau 89990fdc171SFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 90090fdc171SFelix Fietkau if (!skb_queue_empty(&mtxq->retry_q)) 901bfc394ddSFelix Fietkau ieee80211_schedule_txq(hw, sta->txq[i]); 90290fdc171SFelix Fietkau } 903d71ef286SFelix Fietkau } 904d71ef286SFelix Fietkau 9059d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 90681e850efSLorenzo Bianconi struct napi_struct *napi) 90717f1de56SFelix Fietkau { 9089c68a57bSFelix Fietkau struct ieee80211_sta *sta; 909bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 9109d9d738bSFelix Fietkau struct sk_buff *skb; 9119d9d738bSFelix Fietkau 912c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 9139d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 91430ce7f44SFelix Fietkau if (mt76_check_ccmp_pn(skb)) { 91530ce7f44SFelix Fietkau dev_kfree_skb(skb); 91630ce7f44SFelix Fietkau continue; 91730ce7f44SFelix Fietkau } 91830ce7f44SFelix Fietkau 919bfc394ddSFelix Fietkau mt76_rx_convert(dev, skb, &hw, &sta); 920bfc394ddSFelix Fietkau ieee80211_rx_napi(hw, sta, skb, napi); 9219d9d738bSFelix Fietkau } 922c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 9239d9d738bSFelix Fietkau } 9249d9d738bSFelix Fietkau 92581e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 92681e850efSLorenzo Bianconi struct napi_struct *napi) 9279d9d738bSFelix Fietkau { 928aee5b8cfSFelix Fietkau struct sk_buff_head frames; 92917f1de56SFelix Fietkau struct sk_buff *skb; 93017f1de56SFelix Fietkau 931aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 932aee5b8cfSFelix Fietkau 933d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 934ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 935aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 936d71ef286SFelix Fietkau } 937aee5b8cfSFelix Fietkau 93881e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 9394e34249eSFelix Fietkau } 94081e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 941723b90dcSFelix Fietkau 942e28487eaSFelix Fietkau static int 943e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, 944426e8e41SFelix Fietkau struct ieee80211_sta *sta, bool ext_phy) 945e28487eaSFelix Fietkau { 946e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 947e28487eaSFelix Fietkau int ret; 948e28487eaSFelix Fietkau int i; 949e28487eaSFelix Fietkau 950e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 951e28487eaSFelix Fietkau 952e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 953e28487eaSFelix Fietkau if (ret) 954e28487eaSFelix Fietkau goto out; 955e28487eaSFelix Fietkau 956e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 957e28487eaSFelix Fietkau struct mt76_txq *mtxq; 958e28487eaSFelix Fietkau 959e28487eaSFelix Fietkau if (!sta->txq[i]) 960e28487eaSFelix Fietkau continue; 961e28487eaSFelix Fietkau 962e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 963e28487eaSFelix Fietkau mtxq->wcid = wcid; 964e28487eaSFelix Fietkau 965e28487eaSFelix Fietkau mt76_txq_init(dev, sta->txq[i]); 966e28487eaSFelix Fietkau } 967e28487eaSFelix Fietkau 968ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 969426e8e41SFelix Fietkau if (ext_phy) 970426e8e41SFelix Fietkau mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 971c7d2d631SFelix Fietkau wcid->ext_phy = ext_phy; 972e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 973e28487eaSFelix Fietkau 974e28487eaSFelix Fietkau out: 975e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 976e28487eaSFelix Fietkau 977e28487eaSFelix Fietkau return ret; 978e28487eaSFelix Fietkau } 979e28487eaSFelix Fietkau 98013f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 981723b90dcSFelix Fietkau struct ieee80211_sta *sta) 982723b90dcSFelix Fietkau { 983723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 98413f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 985723b90dcSFelix Fietkau 986723b90dcSFelix Fietkau rcu_assign_pointer(dev->wcid[idx], NULL); 987723b90dcSFelix Fietkau synchronize_rcu(); 988723b90dcSFelix Fietkau 98958bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 99058bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 99158bab0d4SFelix Fietkau 992e28487eaSFelix Fietkau if (dev->drv->sta_remove) 993e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 994e28487eaSFelix Fietkau 995723b90dcSFelix Fietkau mt76_tx_status_check(dev, wcid, true); 996723b90dcSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 997723b90dcSFelix Fietkau mt76_txq_remove(dev, sta->txq[i]); 998426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_mask, idx); 999426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 100013f61dfcSLorenzo Bianconi } 100113f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 1002e28487eaSFelix Fietkau 100313f61dfcSLorenzo Bianconi static void 100413f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 100513f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 100613f61dfcSLorenzo Bianconi { 100713f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 100813f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 1009723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 1010723b90dcSFelix Fietkau } 1011e28487eaSFelix Fietkau 1012e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1013e28487eaSFelix Fietkau struct ieee80211_sta *sta, 1014e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 1015e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 1016e28487eaSFelix Fietkau { 1017426e8e41SFelix Fietkau struct mt76_phy *phy = hw->priv; 1018426e8e41SFelix Fietkau struct mt76_dev *dev = phy->dev; 1019426e8e41SFelix Fietkau bool ext_phy = phy != &dev->phy; 1020e28487eaSFelix Fietkau 1021e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 1022e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 1023426e8e41SFelix Fietkau return mt76_sta_add(dev, vif, sta, ext_phy); 1024e28487eaSFelix Fietkau 10259c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 10269c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 10279c193de5SFelix Fietkau dev->drv->sta_assoc) 10289c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 10299c193de5SFelix Fietkau 1030e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 1031e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 1032e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 1033e28487eaSFelix Fietkau 1034e28487eaSFelix Fietkau return 0; 1035e28487eaSFelix Fietkau } 1036e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 10379313faacSFelix Fietkau 10389313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 10399313faacSFelix Fietkau int *dbm) 10409313faacSFelix Fietkau { 1041beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1042beaaeb6bSFelix Fietkau int n_chains = hweight8(phy->antenna_mask); 10439313faacSFelix Fietkau 1044beaaeb6bSFelix Fietkau *dbm = DIV_ROUND_UP(phy->txpower_cur, 2); 10459313faacSFelix Fietkau 10469313faacSFelix Fietkau /* convert from per-chain power to combined 1047c19b0ca5SLorenzo Bianconi * output power 10489313faacSFelix Fietkau */ 1049c19b0ca5SLorenzo Bianconi switch (n_chains) { 1050c19b0ca5SLorenzo Bianconi case 4: 1051c19b0ca5SLorenzo Bianconi *dbm += 6; 1052c19b0ca5SLorenzo Bianconi break; 1053c19b0ca5SLorenzo Bianconi case 3: 1054c19b0ca5SLorenzo Bianconi *dbm += 4; 1055c19b0ca5SLorenzo Bianconi break; 1056c19b0ca5SLorenzo Bianconi case 2: 10579313faacSFelix Fietkau *dbm += 3; 1058c19b0ca5SLorenzo Bianconi break; 1059c19b0ca5SLorenzo Bianconi default: 1060c19b0ca5SLorenzo Bianconi break; 1061c19b0ca5SLorenzo Bianconi } 10629313faacSFelix Fietkau 10639313faacSFelix Fietkau return 0; 10649313faacSFelix Fietkau } 10659313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 1066e7173858SFelix Fietkau 1067e7173858SFelix Fietkau static void 1068e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 1069e7173858SFelix Fietkau { 1070e7173858SFelix Fietkau if (vif->csa_active && ieee80211_csa_is_complete(vif)) 1071e7173858SFelix Fietkau ieee80211_csa_finish(vif); 1072e7173858SFelix Fietkau } 1073e7173858SFelix Fietkau 1074e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 1075e7173858SFelix Fietkau { 1076e7173858SFelix Fietkau if (!dev->csa_complete) 1077e7173858SFelix Fietkau return; 1078e7173858SFelix Fietkau 1079e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1080e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1081e7173858SFelix Fietkau __mt76_csa_finish, dev); 1082e7173858SFelix Fietkau 1083e7173858SFelix Fietkau dev->csa_complete = 0; 1084e7173858SFelix Fietkau } 1085e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 1086e7173858SFelix Fietkau 1087e7173858SFelix Fietkau static void 1088e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 1089e7173858SFelix Fietkau { 1090e7173858SFelix Fietkau struct mt76_dev *dev = priv; 1091e7173858SFelix Fietkau 1092e7173858SFelix Fietkau if (!vif->csa_active) 1093e7173858SFelix Fietkau return; 1094e7173858SFelix Fietkau 1095e7173858SFelix Fietkau dev->csa_complete |= ieee80211_csa_is_complete(vif); 1096e7173858SFelix Fietkau } 1097e7173858SFelix Fietkau 1098e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 1099e7173858SFelix Fietkau { 1100e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1101e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1102e7173858SFelix Fietkau __mt76_csa_check, dev); 1103e7173858SFelix Fietkau } 1104e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 110587d53103SStanislaw Gruszka 110687d53103SStanislaw Gruszka int 110787d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 110887d53103SStanislaw Gruszka { 110987d53103SStanislaw Gruszka return 0; 111087d53103SStanislaw Gruszka } 111187d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 1112eadfd98fSLorenzo Bianconi 1113eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 1114eadfd98fSLorenzo Bianconi { 1115eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 1116eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 1117eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 1118eadfd98fSLorenzo Bianconi 1119eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 1120eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 1121eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 1122eadfd98fSLorenzo Bianconi 1123eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 1124eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 1125eadfd98fSLorenzo Bianconi hdr[2] = 0; 1126eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 1127eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 1128eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 1129eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 1130eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 1131eadfd98fSLorenzo Bianconi 1132eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 1133eadfd98fSLorenzo Bianconi } 1134eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 1135d2679d65SLorenzo Bianconi 1136d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 1137d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 1138d2679d65SLorenzo Bianconi int idx, bool cck) 1139d2679d65SLorenzo Bianconi { 1140d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 1141d2679d65SLorenzo Bianconi 1142d2679d65SLorenzo Bianconi if (cck) { 114396747a51SFelix Fietkau if (sband == &dev->phy.sband_5g.sband) 1144d2679d65SLorenzo Bianconi return 0; 1145d2679d65SLorenzo Bianconi 1146d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 114796747a51SFelix Fietkau } else if (sband == &dev->phy.sband_2g.sband) { 1148d2679d65SLorenzo Bianconi offset = 4; 1149d2679d65SLorenzo Bianconi } 1150d2679d65SLorenzo Bianconi 1151d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 1152d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 1153d2679d65SLorenzo Bianconi return i; 1154d2679d65SLorenzo Bianconi } 1155d2679d65SLorenzo Bianconi 1156d2679d65SLorenzo Bianconi return 0; 1157d2679d65SLorenzo Bianconi } 1158d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 11598b8ab5c2SLorenzo Bianconi 11608b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 11618b8ab5c2SLorenzo Bianconi const u8 *mac) 11628b8ab5c2SLorenzo Bianconi { 1163011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 11648b8ab5c2SLorenzo Bianconi 1165011849e0SFelix Fietkau set_bit(MT76_SCANNING, &phy->state); 11668b8ab5c2SLorenzo Bianconi } 11678b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 11688b8ab5c2SLorenzo Bianconi 11698b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 11708b8ab5c2SLorenzo Bianconi { 1171011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 11728b8ab5c2SLorenzo Bianconi 1173011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &phy->state); 11748b8ab5c2SLorenzo Bianconi } 11758b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1176e49c76d4SLorenzo Bianconi 1177e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 1178e49c76d4SLorenzo Bianconi { 1179beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1180beaaeb6bSFelix Fietkau struct mt76_dev *dev = phy->dev; 1181e49c76d4SLorenzo Bianconi 1182e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex); 1183beaaeb6bSFelix Fietkau *tx_ant = phy->antenna_mask; 1184beaaeb6bSFelix Fietkau *rx_ant = phy->antenna_mask; 1185e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex); 1186e49c76d4SLorenzo Bianconi 1187e49c76d4SLorenzo Bianconi return 0; 1188e49c76d4SLorenzo Bianconi } 1189e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna); 1190