1*6c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC 2*6c92544dSBjoern A. Zeeb /* 3*6c92544dSBjoern A. Zeeb * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> 4*6c92544dSBjoern A. Zeeb * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 5*6c92544dSBjoern A. Zeeb */ 6*6c92544dSBjoern A. Zeeb 7*6c92544dSBjoern A. Zeeb #include <linux/module.h> 8*6c92544dSBjoern A. Zeeb #include "mt76x02.h" 9*6c92544dSBjoern A. Zeeb 10*6c92544dSBjoern A. Zeeb #define MT76x02_CCK_RATE(_idx, _rate) { \ 11*6c92544dSBjoern A. Zeeb .bitrate = _rate, \ 12*6c92544dSBjoern A. Zeeb .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ 13*6c92544dSBjoern A. Zeeb .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ 14*6c92544dSBjoern A. Zeeb .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \ 15*6c92544dSBjoern A. Zeeb } 16*6c92544dSBjoern A. Zeeb 17*6c92544dSBjoern A. Zeeb struct ieee80211_rate mt76x02_rates[] = { 18*6c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(0, 10), 19*6c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(1, 20), 20*6c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(2, 55), 21*6c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(3, 110), 22*6c92544dSBjoern A. Zeeb OFDM_RATE(0, 60), 23*6c92544dSBjoern A. Zeeb OFDM_RATE(1, 90), 24*6c92544dSBjoern A. Zeeb OFDM_RATE(2, 120), 25*6c92544dSBjoern A. Zeeb OFDM_RATE(3, 180), 26*6c92544dSBjoern A. Zeeb OFDM_RATE(4, 240), 27*6c92544dSBjoern A. Zeeb OFDM_RATE(5, 360), 28*6c92544dSBjoern A. Zeeb OFDM_RATE(6, 480), 29*6c92544dSBjoern A. Zeeb OFDM_RATE(7, 540), 30*6c92544dSBjoern A. Zeeb }; 31*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_rates); 32*6c92544dSBjoern A. Zeeb 33*6c92544dSBjoern A. Zeeb static const struct ieee80211_iface_limit mt76x02_if_limits[] = { 34*6c92544dSBjoern A. Zeeb { 35*6c92544dSBjoern A. Zeeb .max = 1, 36*6c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_ADHOC) 37*6c92544dSBjoern A. Zeeb }, { 38*6c92544dSBjoern A. Zeeb .max = 8, 39*6c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION) | 40*6c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 41*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) | 42*6c92544dSBjoern A. Zeeb #endif 43*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) | 44*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) | 45*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) 46*6c92544dSBjoern A. Zeeb }, 47*6c92544dSBjoern A. Zeeb }; 48*6c92544dSBjoern A. Zeeb 49*6c92544dSBjoern A. Zeeb static const struct ieee80211_iface_limit mt76x02u_if_limits[] = { 50*6c92544dSBjoern A. Zeeb { 51*6c92544dSBjoern A. Zeeb .max = 1, 52*6c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_ADHOC) 53*6c92544dSBjoern A. Zeeb }, { 54*6c92544dSBjoern A. Zeeb .max = 2, 55*6c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION) | 56*6c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 57*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) | 58*6c92544dSBjoern A. Zeeb #endif 59*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) | 60*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) | 61*6c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) 62*6c92544dSBjoern A. Zeeb }, 63*6c92544dSBjoern A. Zeeb }; 64*6c92544dSBjoern A. Zeeb 65*6c92544dSBjoern A. Zeeb static const struct ieee80211_iface_combination mt76x02_if_comb[] = { 66*6c92544dSBjoern A. Zeeb { 67*6c92544dSBjoern A. Zeeb .limits = mt76x02_if_limits, 68*6c92544dSBjoern A. Zeeb .n_limits = ARRAY_SIZE(mt76x02_if_limits), 69*6c92544dSBjoern A. Zeeb .max_interfaces = 8, 70*6c92544dSBjoern A. Zeeb .num_different_channels = 1, 71*6c92544dSBjoern A. Zeeb .beacon_int_infra_match = true, 72*6c92544dSBjoern A. Zeeb .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 73*6c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_20) | 74*6c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_40) | 75*6c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_80), 76*6c92544dSBjoern A. Zeeb } 77*6c92544dSBjoern A. Zeeb }; 78*6c92544dSBjoern A. Zeeb 79*6c92544dSBjoern A. Zeeb static const struct ieee80211_iface_combination mt76x02u_if_comb[] = { 80*6c92544dSBjoern A. Zeeb { 81*6c92544dSBjoern A. Zeeb .limits = mt76x02u_if_limits, 82*6c92544dSBjoern A. Zeeb .n_limits = ARRAY_SIZE(mt76x02u_if_limits), 83*6c92544dSBjoern A. Zeeb .max_interfaces = 2, 84*6c92544dSBjoern A. Zeeb .num_different_channels = 1, 85*6c92544dSBjoern A. Zeeb .beacon_int_infra_match = true, 86*6c92544dSBjoern A. Zeeb } 87*6c92544dSBjoern A. Zeeb }; 88*6c92544dSBjoern A. Zeeb 89*6c92544dSBjoern A. Zeeb static void 90*6c92544dSBjoern A. Zeeb mt76x02_led_set_config(struct mt76_dev *mdev, u8 delay_on, 91*6c92544dSBjoern A. Zeeb u8 delay_off) 92*6c92544dSBjoern A. Zeeb { 93*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, 94*6c92544dSBjoern A. Zeeb mt76); 95*6c92544dSBjoern A. Zeeb u32 val; 96*6c92544dSBjoern A. Zeeb 97*6c92544dSBjoern A. Zeeb val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xff) | 98*6c92544dSBjoern A. Zeeb FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | 99*6c92544dSBjoern A. Zeeb FIELD_PREP(MT_LED_STATUS_ON, delay_on); 100*6c92544dSBjoern A. Zeeb 101*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_LED_S0(mdev->led_pin), val); 102*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_LED_S1(mdev->led_pin), val); 103*6c92544dSBjoern A. Zeeb 104*6c92544dSBjoern A. Zeeb val = MT_LED_CTRL_REPLAY(mdev->led_pin) | 105*6c92544dSBjoern A. Zeeb MT_LED_CTRL_KICK(mdev->led_pin); 106*6c92544dSBjoern A. Zeeb if (mdev->led_al) 107*6c92544dSBjoern A. Zeeb val |= MT_LED_CTRL_POLARITY(mdev->led_pin); 108*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_LED_CTRL, val); 109*6c92544dSBjoern A. Zeeb } 110*6c92544dSBjoern A. Zeeb 111*6c92544dSBjoern A. Zeeb static int 112*6c92544dSBjoern A. Zeeb mt76x02_led_set_blink(struct led_classdev *led_cdev, 113*6c92544dSBjoern A. Zeeb unsigned long *delay_on, 114*6c92544dSBjoern A. Zeeb unsigned long *delay_off) 115*6c92544dSBjoern A. Zeeb { 116*6c92544dSBjoern A. Zeeb struct mt76_dev *mdev = container_of(led_cdev, struct mt76_dev, 117*6c92544dSBjoern A. Zeeb led_cdev); 118*6c92544dSBjoern A. Zeeb u8 delta_on, delta_off; 119*6c92544dSBjoern A. Zeeb 120*6c92544dSBjoern A. Zeeb delta_off = max_t(u8, *delay_off / 10, 1); 121*6c92544dSBjoern A. Zeeb delta_on = max_t(u8, *delay_on / 10, 1); 122*6c92544dSBjoern A. Zeeb 123*6c92544dSBjoern A. Zeeb mt76x02_led_set_config(mdev, delta_on, delta_off); 124*6c92544dSBjoern A. Zeeb 125*6c92544dSBjoern A. Zeeb return 0; 126*6c92544dSBjoern A. Zeeb } 127*6c92544dSBjoern A. Zeeb 128*6c92544dSBjoern A. Zeeb static void 129*6c92544dSBjoern A. Zeeb mt76x02_led_set_brightness(struct led_classdev *led_cdev, 130*6c92544dSBjoern A. Zeeb enum led_brightness brightness) 131*6c92544dSBjoern A. Zeeb { 132*6c92544dSBjoern A. Zeeb struct mt76_dev *mdev = container_of(led_cdev, struct mt76_dev, 133*6c92544dSBjoern A. Zeeb led_cdev); 134*6c92544dSBjoern A. Zeeb 135*6c92544dSBjoern A. Zeeb if (!brightness) 136*6c92544dSBjoern A. Zeeb mt76x02_led_set_config(mdev, 0, 0xff); 137*6c92544dSBjoern A. Zeeb else 138*6c92544dSBjoern A. Zeeb mt76x02_led_set_config(mdev, 0xff, 0); 139*6c92544dSBjoern A. Zeeb } 140*6c92544dSBjoern A. Zeeb 141*6c92544dSBjoern A. Zeeb int mt76x02_init_device(struct mt76x02_dev *dev) 142*6c92544dSBjoern A. Zeeb { 143*6c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mt76_hw(dev); 144*6c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy; 145*6c92544dSBjoern A. Zeeb 146*6c92544dSBjoern A. Zeeb INIT_DELAYED_WORK(&dev->mphy.mac_work, mt76x02_mac_work); 147*6c92544dSBjoern A. Zeeb 148*6c92544dSBjoern A. Zeeb hw->queues = 4; 149*6c92544dSBjoern A. Zeeb hw->max_rates = 1; 150*6c92544dSBjoern A. Zeeb hw->max_report_rates = 7; 151*6c92544dSBjoern A. Zeeb hw->max_rate_tries = 1; 152*6c92544dSBjoern A. Zeeb hw->extra_tx_headroom = 2; 153*6c92544dSBjoern A. Zeeb 154*6c92544dSBjoern A. Zeeb if (mt76_is_usb(&dev->mt76)) { 155*6c92544dSBjoern A. Zeeb hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + 156*6c92544dSBjoern A. Zeeb MT_DMA_HDR_LEN; 157*6c92544dSBjoern A. Zeeb wiphy->iface_combinations = mt76x02u_if_comb; 158*6c92544dSBjoern A. Zeeb wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02u_if_comb); 159*6c92544dSBjoern A. Zeeb } else { 160*6c92544dSBjoern A. Zeeb INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); 161*6c92544dSBjoern A. Zeeb 162*6c92544dSBjoern A. Zeeb mt76x02_dfs_init_detector(dev); 163*6c92544dSBjoern A. Zeeb 164*6c92544dSBjoern A. Zeeb wiphy->reg_notifier = mt76x02_regd_notifier; 165*6c92544dSBjoern A. Zeeb wiphy->iface_combinations = mt76x02_if_comb; 166*6c92544dSBjoern A. Zeeb wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb); 167*6c92544dSBjoern A. Zeeb 168*6c92544dSBjoern A. Zeeb /* init led callbacks */ 169*6c92544dSBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) { 170*6c92544dSBjoern A. Zeeb dev->mt76.led_cdev.brightness_set = 171*6c92544dSBjoern A. Zeeb mt76x02_led_set_brightness; 172*6c92544dSBjoern A. Zeeb dev->mt76.led_cdev.blink_set = mt76x02_led_set_blink; 173*6c92544dSBjoern A. Zeeb } 174*6c92544dSBjoern A. Zeeb } 175*6c92544dSBjoern A. Zeeb 176*6c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 177*6c92544dSBjoern A. Zeeb 178*6c92544dSBjoern A. Zeeb hw->sta_data_size = sizeof(struct mt76x02_sta); 179*6c92544dSBjoern A. Zeeb hw->vif_data_size = sizeof(struct mt76x02_vif); 180*6c92544dSBjoern A. Zeeb 181*6c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 182*6c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 183*6c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); 184*6c92544dSBjoern A. Zeeb 185*6c92544dSBjoern A. Zeeb dev->mt76.global_wcid.idx = 255; 186*6c92544dSBjoern A. Zeeb dev->mt76.global_wcid.hw_key_idx = -1; 187*6c92544dSBjoern A. Zeeb dev->slottime = 9; 188*6c92544dSBjoern A. Zeeb 189*6c92544dSBjoern A. Zeeb if (is_mt76x2(dev)) { 190*6c92544dSBjoern A. Zeeb dev->mphy.sband_2g.sband.ht_cap.cap |= 191*6c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_LDPC_CODING; 192*6c92544dSBjoern A. Zeeb dev->mphy.sband_5g.sband.ht_cap.cap |= 193*6c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_LDPC_CODING; 194*6c92544dSBjoern A. Zeeb dev->mphy.chainmask = 0x202; 195*6c92544dSBjoern A. Zeeb dev->mphy.antenna_mask = 3; 196*6c92544dSBjoern A. Zeeb } else { 197*6c92544dSBjoern A. Zeeb dev->mphy.chainmask = 0x101; 198*6c92544dSBjoern A. Zeeb dev->mphy.antenna_mask = 1; 199*6c92544dSBjoern A. Zeeb } 200*6c92544dSBjoern A. Zeeb 201*6c92544dSBjoern A. Zeeb return 0; 202*6c92544dSBjoern A. Zeeb } 203*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_init_device); 204*6c92544dSBjoern A. Zeeb 205*6c92544dSBjoern A. Zeeb void mt76x02_configure_filter(struct ieee80211_hw *hw, 206*6c92544dSBjoern A. Zeeb unsigned int changed_flags, 207*6c92544dSBjoern A. Zeeb unsigned int *total_flags, u64 multicast) 208*6c92544dSBjoern A. Zeeb { 209*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 210*6c92544dSBjoern A. Zeeb u32 flags = 0; 211*6c92544dSBjoern A. Zeeb 212*6c92544dSBjoern A. Zeeb #define MT76_FILTER(_flag, _hw) do { \ 213*6c92544dSBjoern A. Zeeb flags |= *total_flags & FIF_##_flag; \ 214*6c92544dSBjoern A. Zeeb dev->mt76.rxfilter &= ~(_hw); \ 215*6c92544dSBjoern A. Zeeb dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 216*6c92544dSBjoern A. Zeeb } while (0) 217*6c92544dSBjoern A. Zeeb 218*6c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 219*6c92544dSBjoern A. Zeeb 220*6c92544dSBjoern A. Zeeb dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; 221*6c92544dSBjoern A. Zeeb 222*6c92544dSBjoern A. Zeeb MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); 223*6c92544dSBjoern A. Zeeb MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); 224*6c92544dSBjoern A. Zeeb MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | 225*6c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CTS | 226*6c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CFEND | 227*6c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CFACK | 228*6c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_BA | 229*6c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CTRL_RSV); 230*6c92544dSBjoern A. Zeeb MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); 231*6c92544dSBjoern A. Zeeb 232*6c92544dSBjoern A. Zeeb *total_flags = flags; 233*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); 234*6c92544dSBjoern A. Zeeb 235*6c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 236*6c92544dSBjoern A. Zeeb } 237*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_configure_filter); 238*6c92544dSBjoern A. Zeeb 239*6c92544dSBjoern A. Zeeb int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 240*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 241*6c92544dSBjoern A. Zeeb { 242*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 243*6c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 244*6c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 245*6c92544dSBjoern A. Zeeb int idx = 0; 246*6c92544dSBjoern A. Zeeb 247*6c92544dSBjoern A. Zeeb memset(msta, 0, sizeof(*msta)); 248*6c92544dSBjoern A. Zeeb 249*6c92544dSBjoern A. Zeeb idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT76x02_N_WCIDS); 250*6c92544dSBjoern A. Zeeb if (idx < 0) 251*6c92544dSBjoern A. Zeeb return -ENOSPC; 252*6c92544dSBjoern A. Zeeb 253*6c92544dSBjoern A. Zeeb msta->vif = mvif; 254*6c92544dSBjoern A. Zeeb msta->wcid.sta = 1; 255*6c92544dSBjoern A. Zeeb msta->wcid.idx = idx; 256*6c92544dSBjoern A. Zeeb msta->wcid.hw_key_idx = -1; 257*6c92544dSBjoern A. Zeeb mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); 258*6c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_drop(dev, idx, false); 259*6c92544dSBjoern A. Zeeb ewma_pktlen_init(&msta->pktlen); 260*6c92544dSBjoern A. Zeeb 261*6c92544dSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_AP) 262*6c92544dSBjoern A. Zeeb set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); 263*6c92544dSBjoern A. Zeeb 264*6c92544dSBjoern A. Zeeb return 0; 265*6c92544dSBjoern A. Zeeb } 266*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_add); 267*6c92544dSBjoern A. Zeeb 268*6c92544dSBjoern A. Zeeb void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 269*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 270*6c92544dSBjoern A. Zeeb { 271*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 272*6c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 273*6c92544dSBjoern A. Zeeb int idx = wcid->idx; 274*6c92544dSBjoern A. Zeeb 275*6c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_drop(dev, idx, true); 276*6c92544dSBjoern A. Zeeb mt76x02_mac_wcid_setup(dev, idx, 0, NULL); 277*6c92544dSBjoern A. Zeeb } 278*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_remove); 279*6c92544dSBjoern A. Zeeb 280*6c92544dSBjoern A. Zeeb static void 281*6c92544dSBjoern A. Zeeb mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, 282*6c92544dSBjoern A. Zeeb unsigned int idx) 283*6c92544dSBjoern A. Zeeb { 284*6c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 285*6c92544dSBjoern A. Zeeb struct mt76_txq *mtxq; 286*6c92544dSBjoern A. Zeeb 287*6c92544dSBjoern A. Zeeb memset(mvif, 0, sizeof(*mvif)); 288*6c92544dSBjoern A. Zeeb 289*6c92544dSBjoern A. Zeeb mvif->idx = idx; 290*6c92544dSBjoern A. Zeeb mvif->group_wcid.idx = MT_VIF_WCID(idx); 291*6c92544dSBjoern A. Zeeb mvif->group_wcid.hw_key_idx = -1; 292*6c92544dSBjoern A. Zeeb mt76_packet_id_init(&mvif->group_wcid); 293*6c92544dSBjoern A. Zeeb 294*6c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)vif->txq->drv_priv; 295*6c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->mt76.wcid[MT_VIF_WCID(idx)], &mvif->group_wcid); 296*6c92544dSBjoern A. Zeeb mtxq->wcid = MT_VIF_WCID(idx); 297*6c92544dSBjoern A. Zeeb } 298*6c92544dSBjoern A. Zeeb 299*6c92544dSBjoern A. Zeeb int 300*6c92544dSBjoern A. Zeeb mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 301*6c92544dSBjoern A. Zeeb { 302*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 303*6c92544dSBjoern A. Zeeb unsigned int idx = 0; 304*6c92544dSBjoern A. Zeeb 305*6c92544dSBjoern A. Zeeb /* Allow to change address in HW if we create first interface. */ 306*6c92544dSBjoern A. Zeeb if (!dev->mt76.vif_mask && 307*6c92544dSBjoern A. Zeeb (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) || 308*6c92544dSBjoern A. Zeeb memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1))) 309*6c92544dSBjoern A. Zeeb mt76x02_mac_setaddr(dev, vif->addr); 310*6c92544dSBjoern A. Zeeb 311*6c92544dSBjoern A. Zeeb if (vif->addr[0] & BIT(1)) 312*6c92544dSBjoern A. Zeeb idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7); 313*6c92544dSBjoern A. Zeeb 314*6c92544dSBjoern A. Zeeb /* 315*6c92544dSBjoern A. Zeeb * Client mode typically only has one configurable BSSID register, 316*6c92544dSBjoern A. Zeeb * which is used for bssidx=0. This is linked to the MAC address. 317*6c92544dSBjoern A. Zeeb * Since mac80211 allows changing interface types, and we cannot 318*6c92544dSBjoern A. Zeeb * force the use of the primary MAC address for a station mode 319*6c92544dSBjoern A. Zeeb * interface, we need some other way of configuring a per-interface 320*6c92544dSBjoern A. Zeeb * remote BSSID. 321*6c92544dSBjoern A. Zeeb * The hardware provides an AP-Client feature, where bssidx 0-7 are 322*6c92544dSBjoern A. Zeeb * used for AP mode and bssidx 8-15 for client mode. 323*6c92544dSBjoern A. Zeeb * We shift the station interface bss index by 8 to force the 324*6c92544dSBjoern A. Zeeb * hardware to recognize the BSSID. 325*6c92544dSBjoern A. Zeeb * The resulting bssidx mismatch for unicast frames is ignored by hw. 326*6c92544dSBjoern A. Zeeb */ 327*6c92544dSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION) 328*6c92544dSBjoern A. Zeeb idx += 8; 329*6c92544dSBjoern A. Zeeb 330*6c92544dSBjoern A. Zeeb /* vif is already set or idx is 8 for AP/Mesh/... */ 331*6c92544dSBjoern A. Zeeb if (dev->mt76.vif_mask & BIT_ULL(idx) || 332*6c92544dSBjoern A. Zeeb (vif->type != NL80211_IFTYPE_STATION && idx > 7)) 333*6c92544dSBjoern A. Zeeb return -EBUSY; 334*6c92544dSBjoern A. Zeeb 335*6c92544dSBjoern A. Zeeb dev->mt76.vif_mask |= BIT_ULL(idx); 336*6c92544dSBjoern A. Zeeb 337*6c92544dSBjoern A. Zeeb mt76x02_vif_init(dev, vif, idx); 338*6c92544dSBjoern A. Zeeb return 0; 339*6c92544dSBjoern A. Zeeb } 340*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_add_interface); 341*6c92544dSBjoern A. Zeeb 342*6c92544dSBjoern A. Zeeb void mt76x02_remove_interface(struct ieee80211_hw *hw, 343*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif) 344*6c92544dSBjoern A. Zeeb { 345*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 346*6c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 347*6c92544dSBjoern A. Zeeb 348*6c92544dSBjoern A. Zeeb dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx); 349*6c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->mt76.wcid[mvif->group_wcid.idx], NULL); 350*6c92544dSBjoern A. Zeeb mt76_packet_id_flush(&dev->mt76, &mvif->group_wcid); 351*6c92544dSBjoern A. Zeeb } 352*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_remove_interface); 353*6c92544dSBjoern A. Zeeb 354*6c92544dSBjoern A. Zeeb int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 355*6c92544dSBjoern A. Zeeb struct ieee80211_ampdu_params *params) 356*6c92544dSBjoern A. Zeeb { 357*6c92544dSBjoern A. Zeeb enum ieee80211_ampdu_mlme_action action = params->action; 358*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta = params->sta; 359*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 360*6c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 361*6c92544dSBjoern A. Zeeb struct ieee80211_txq *txq = sta->txq[params->tid]; 362*6c92544dSBjoern A. Zeeb u16 tid = params->tid; 363*6c92544dSBjoern A. Zeeb u16 ssn = params->ssn; 364*6c92544dSBjoern A. Zeeb struct mt76_txq *mtxq; 365*6c92544dSBjoern A. Zeeb int ret = 0; 366*6c92544dSBjoern A. Zeeb 367*6c92544dSBjoern A. Zeeb if (!txq) 368*6c92544dSBjoern A. Zeeb return -EINVAL; 369*6c92544dSBjoern A. Zeeb 370*6c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)txq->drv_priv; 371*6c92544dSBjoern A. Zeeb 372*6c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 373*6c92544dSBjoern A. Zeeb switch (action) { 374*6c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_RX_START: 375*6c92544dSBjoern A. Zeeb mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, 376*6c92544dSBjoern A. Zeeb ssn, params->buf_size); 377*6c92544dSBjoern A. Zeeb mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); 378*6c92544dSBjoern A. Zeeb break; 379*6c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_RX_STOP: 380*6c92544dSBjoern A. Zeeb mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 381*6c92544dSBjoern A. Zeeb mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, 382*6c92544dSBjoern A. Zeeb BIT(16 + tid)); 383*6c92544dSBjoern A. Zeeb break; 384*6c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_OPERATIONAL: 385*6c92544dSBjoern A. Zeeb mtxq->aggr = true; 386*6c92544dSBjoern A. Zeeb mtxq->send_bar = false; 387*6c92544dSBjoern A. Zeeb ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); 388*6c92544dSBjoern A. Zeeb break; 389*6c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH: 390*6c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 391*6c92544dSBjoern A. Zeeb mtxq->aggr = false; 392*6c92544dSBjoern A. Zeeb break; 393*6c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_START: 394*6c92544dSBjoern A. Zeeb mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); 395*6c92544dSBjoern A. Zeeb ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 396*6c92544dSBjoern A. Zeeb break; 397*6c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_CONT: 398*6c92544dSBjoern A. Zeeb mtxq->aggr = false; 399*6c92544dSBjoern A. Zeeb ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 400*6c92544dSBjoern A. Zeeb break; 401*6c92544dSBjoern A. Zeeb } 402*6c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 403*6c92544dSBjoern A. Zeeb 404*6c92544dSBjoern A. Zeeb return ret; 405*6c92544dSBjoern A. Zeeb } 406*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); 407*6c92544dSBjoern A. Zeeb 408*6c92544dSBjoern A. Zeeb int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 409*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta, 410*6c92544dSBjoern A. Zeeb struct ieee80211_key_conf *key) 411*6c92544dSBjoern A. Zeeb { 412*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 413*6c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 414*6c92544dSBjoern A. Zeeb struct mt76x02_sta *msta; 415*6c92544dSBjoern A. Zeeb struct mt76_wcid *wcid; 416*6c92544dSBjoern A. Zeeb int idx = key->keyidx; 417*6c92544dSBjoern A. Zeeb int ret; 418*6c92544dSBjoern A. Zeeb 419*6c92544dSBjoern A. Zeeb /* fall back to sw encryption for unsupported ciphers */ 420*6c92544dSBjoern A. Zeeb switch (key->cipher) { 421*6c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP40: 422*6c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP104: 423*6c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_TKIP: 424*6c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP: 425*6c92544dSBjoern A. Zeeb break; 426*6c92544dSBjoern A. Zeeb default: 427*6c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 428*6c92544dSBjoern A. Zeeb } 429*6c92544dSBjoern A. Zeeb 430*6c92544dSBjoern A. Zeeb /* 431*6c92544dSBjoern A. Zeeb * The hardware does not support per-STA RX GTK, fall back 432*6c92544dSBjoern A. Zeeb * to software mode for these. 433*6c92544dSBjoern A. Zeeb */ 434*6c92544dSBjoern A. Zeeb if ((vif->type == NL80211_IFTYPE_ADHOC || 435*6c92544dSBjoern A. Zeeb vif->type == NL80211_IFTYPE_MESH_POINT) && 436*6c92544dSBjoern A. Zeeb (key->cipher == WLAN_CIPHER_SUITE_TKIP || 437*6c92544dSBjoern A. Zeeb key->cipher == WLAN_CIPHER_SUITE_CCMP) && 438*6c92544dSBjoern A. Zeeb !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 439*6c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 440*6c92544dSBjoern A. Zeeb 441*6c92544dSBjoern A. Zeeb /* 442*6c92544dSBjoern A. Zeeb * In USB AP mode, broadcast/multicast frames are setup in beacon 443*6c92544dSBjoern A. Zeeb * data registers and sent via HW beacons engine, they require to 444*6c92544dSBjoern A. Zeeb * be already encrypted. 445*6c92544dSBjoern A. Zeeb */ 446*6c92544dSBjoern A. Zeeb if (mt76_is_usb(&dev->mt76) && 447*6c92544dSBjoern A. Zeeb vif->type == NL80211_IFTYPE_AP && 448*6c92544dSBjoern A. Zeeb !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 449*6c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 450*6c92544dSBjoern A. Zeeb 451*6c92544dSBjoern A. Zeeb /* MT76x0 GTK offloading does not work with more than one VIF */ 452*6c92544dSBjoern A. Zeeb if (is_mt76x0(dev) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 453*6c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 454*6c92544dSBjoern A. Zeeb 455*6c92544dSBjoern A. Zeeb msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL; 456*6c92544dSBjoern A. Zeeb wcid = msta ? &msta->wcid : &mvif->group_wcid; 457*6c92544dSBjoern A. Zeeb 458*6c92544dSBjoern A. Zeeb if (cmd == SET_KEY) { 459*6c92544dSBjoern A. Zeeb key->hw_key_idx = wcid->idx; 460*6c92544dSBjoern A. Zeeb wcid->hw_key_idx = idx; 461*6c92544dSBjoern A. Zeeb if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { 462*6c92544dSBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 463*6c92544dSBjoern A. Zeeb wcid->sw_iv = true; 464*6c92544dSBjoern A. Zeeb } 465*6c92544dSBjoern A. Zeeb } else { 466*6c92544dSBjoern A. Zeeb if (idx == wcid->hw_key_idx) { 467*6c92544dSBjoern A. Zeeb wcid->hw_key_idx = -1; 468*6c92544dSBjoern A. Zeeb wcid->sw_iv = false; 469*6c92544dSBjoern A. Zeeb } 470*6c92544dSBjoern A. Zeeb 471*6c92544dSBjoern A. Zeeb key = NULL; 472*6c92544dSBjoern A. Zeeb } 473*6c92544dSBjoern A. Zeeb mt76_wcid_key_setup(&dev->mt76, wcid, key); 474*6c92544dSBjoern A. Zeeb 475*6c92544dSBjoern A. Zeeb if (!msta) { 476*6c92544dSBjoern A. Zeeb if (key || wcid->hw_key_idx == idx) { 477*6c92544dSBjoern A. Zeeb ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key); 478*6c92544dSBjoern A. Zeeb if (ret) 479*6c92544dSBjoern A. Zeeb return ret; 480*6c92544dSBjoern A. Zeeb } 481*6c92544dSBjoern A. Zeeb 482*6c92544dSBjoern A. Zeeb return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key); 483*6c92544dSBjoern A. Zeeb } 484*6c92544dSBjoern A. Zeeb 485*6c92544dSBjoern A. Zeeb return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key); 486*6c92544dSBjoern A. Zeeb } 487*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_key); 488*6c92544dSBjoern A. Zeeb 489*6c92544dSBjoern A. Zeeb int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 490*6c92544dSBjoern A. Zeeb unsigned int link_id, u16 queue, 491*6c92544dSBjoern A. Zeeb const struct ieee80211_tx_queue_params *params) 492*6c92544dSBjoern A. Zeeb { 493*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 494*6c92544dSBjoern A. Zeeb u8 cw_min = 5, cw_max = 10, qid; 495*6c92544dSBjoern A. Zeeb u32 val; 496*6c92544dSBjoern A. Zeeb 497*6c92544dSBjoern A. Zeeb qid = dev->mphy.q_tx[queue]->hw_idx; 498*6c92544dSBjoern A. Zeeb 499*6c92544dSBjoern A. Zeeb if (params->cw_min) 500*6c92544dSBjoern A. Zeeb cw_min = fls(params->cw_min); 501*6c92544dSBjoern A. Zeeb if (params->cw_max) 502*6c92544dSBjoern A. Zeeb cw_max = fls(params->cw_max); 503*6c92544dSBjoern A. Zeeb 504*6c92544dSBjoern A. Zeeb val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) | 505*6c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | 506*6c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | 507*6c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); 508*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); 509*6c92544dSBjoern A. Zeeb 510*6c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_TXOP(qid)); 511*6c92544dSBjoern A. Zeeb val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid)); 512*6c92544dSBjoern A. Zeeb val |= params->txop << MT_WMM_TXOP_SHIFT(qid); 513*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_TXOP(qid), val); 514*6c92544dSBjoern A. Zeeb 515*6c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_AIFSN); 516*6c92544dSBjoern A. Zeeb val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid)); 517*6c92544dSBjoern A. Zeeb val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid); 518*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_AIFSN, val); 519*6c92544dSBjoern A. Zeeb 520*6c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_CWMIN); 521*6c92544dSBjoern A. Zeeb val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid)); 522*6c92544dSBjoern A. Zeeb val |= cw_min << MT_WMM_CWMIN_SHIFT(qid); 523*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_CWMIN, val); 524*6c92544dSBjoern A. Zeeb 525*6c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_CWMAX); 526*6c92544dSBjoern A. Zeeb val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid)); 527*6c92544dSBjoern A. Zeeb val |= cw_max << MT_WMM_CWMAX_SHIFT(qid); 528*6c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_CWMAX, val); 529*6c92544dSBjoern A. Zeeb 530*6c92544dSBjoern A. Zeeb return 0; 531*6c92544dSBjoern A. Zeeb } 532*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_conf_tx); 533*6c92544dSBjoern A. Zeeb 534*6c92544dSBjoern A. Zeeb void mt76x02_set_tx_ackto(struct mt76x02_dev *dev) 535*6c92544dSBjoern A. Zeeb { 536*6c92544dSBjoern A. Zeeb u8 ackto, sifs, slottime = dev->slottime; 537*6c92544dSBjoern A. Zeeb 538*6c92544dSBjoern A. Zeeb /* As defined by IEEE 802.11-2007 17.3.8.6 */ 539*6c92544dSBjoern A. Zeeb slottime += 3 * dev->coverage_class; 540*6c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, 541*6c92544dSBjoern A. Zeeb MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); 542*6c92544dSBjoern A. Zeeb 543*6c92544dSBjoern A. Zeeb sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, 544*6c92544dSBjoern A. Zeeb MT_XIFS_TIME_CFG_OFDM_SIFS); 545*6c92544dSBjoern A. Zeeb 546*6c92544dSBjoern A. Zeeb ackto = slottime + sifs; 547*6c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG, 548*6c92544dSBjoern A. Zeeb MT_TX_TIMEOUT_CFG_ACKTO, ackto); 549*6c92544dSBjoern A. Zeeb } 550*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto); 551*6c92544dSBjoern A. Zeeb 552*6c92544dSBjoern A. Zeeb void mt76x02_set_coverage_class(struct ieee80211_hw *hw, 553*6c92544dSBjoern A. Zeeb s16 coverage_class) 554*6c92544dSBjoern A. Zeeb { 555*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 556*6c92544dSBjoern A. Zeeb 557*6c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 558*6c92544dSBjoern A. Zeeb dev->coverage_class = max_t(s16, coverage_class, 0); 559*6c92544dSBjoern A. Zeeb mt76x02_set_tx_ackto(dev); 560*6c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 561*6c92544dSBjoern A. Zeeb } 562*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class); 563*6c92544dSBjoern A. Zeeb 564*6c92544dSBjoern A. Zeeb int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 565*6c92544dSBjoern A. Zeeb { 566*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 567*6c92544dSBjoern A. Zeeb 568*6c92544dSBjoern A. Zeeb if (val != ~0 && val > 0xffff) 569*6c92544dSBjoern A. Zeeb return -EINVAL; 570*6c92544dSBjoern A. Zeeb 571*6c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 572*6c92544dSBjoern A. Zeeb mt76x02_mac_set_rts_thresh(dev, val); 573*6c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 574*6c92544dSBjoern A. Zeeb 575*6c92544dSBjoern A. Zeeb return 0; 576*6c92544dSBjoern A. Zeeb } 577*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_rts_threshold); 578*6c92544dSBjoern A. Zeeb 579*6c92544dSBjoern A. Zeeb void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, 580*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, 581*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 582*6c92544dSBjoern A. Zeeb { 583*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 584*6c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 585*6c92544dSBjoern A. Zeeb struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); 586*6c92544dSBjoern A. Zeeb struct ieee80211_tx_rate rate = {}; 587*6c92544dSBjoern A. Zeeb 588*6c92544dSBjoern A. Zeeb if (!rates) 589*6c92544dSBjoern A. Zeeb return; 590*6c92544dSBjoern A. Zeeb 591*6c92544dSBjoern A. Zeeb rate.idx = rates->rate[0].idx; 592*6c92544dSBjoern A. Zeeb rate.flags = rates->rate[0].flags; 593*6c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate); 594*6c92544dSBjoern A. Zeeb } 595*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); 596*6c92544dSBjoern A. Zeeb 597*6c92544dSBjoern A. Zeeb void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) 598*6c92544dSBjoern A. Zeeb { 599*6c92544dSBjoern A. Zeeb int hdrlen; 600*6c92544dSBjoern A. Zeeb 601*6c92544dSBjoern A. Zeeb if (!len) 602*6c92544dSBjoern A. Zeeb return; 603*6c92544dSBjoern A. Zeeb 604*6c92544dSBjoern A. Zeeb hdrlen = ieee80211_get_hdrlen_from_skb(skb); 605*6c92544dSBjoern A. Zeeb memmove(skb->data + len, skb->data, hdrlen); 606*6c92544dSBjoern A. Zeeb skb_pull(skb, len); 607*6c92544dSBjoern A. Zeeb } 608*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); 609*6c92544dSBjoern A. Zeeb 610*6c92544dSBjoern A. Zeeb void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, 611*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif) 612*6c92544dSBjoern A. Zeeb { 613*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 614*6c92544dSBjoern A. Zeeb 615*6c92544dSBjoern A. Zeeb clear_bit(MT76_SCANNING, &dev->mphy.state); 616*6c92544dSBjoern A. Zeeb if (dev->cal.gain_init_done) { 617*6c92544dSBjoern A. Zeeb /* Restore AGC gain and resume calibration after scanning. */ 618*6c92544dSBjoern A. Zeeb dev->cal.low_gain = -1; 619*6c92544dSBjoern A. Zeeb ieee80211_queue_delayed_work(hw, &dev->cal_work, 0); 620*6c92544dSBjoern A. Zeeb } 621*6c92544dSBjoern A. Zeeb } 622*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete); 623*6c92544dSBjoern A. Zeeb 624*6c92544dSBjoern A. Zeeb void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, 625*6c92544dSBjoern A. Zeeb bool ps) 626*6c92544dSBjoern A. Zeeb { 627*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 628*6c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 629*6c92544dSBjoern A. Zeeb int idx = msta->wcid.idx; 630*6c92544dSBjoern A. Zeeb 631*6c92544dSBjoern A. Zeeb mt76_stop_tx_queues(&dev->mphy, sta, true); 632*6c92544dSBjoern A. Zeeb if (mt76_is_mmio(mdev)) 633*6c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_drop(dev, idx, ps); 634*6c92544dSBjoern A. Zeeb } 635*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_ps); 636*6c92544dSBjoern A. Zeeb 637*6c92544dSBjoern A. Zeeb void mt76x02_bss_info_changed(struct ieee80211_hw *hw, 638*6c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, 639*6c92544dSBjoern A. Zeeb struct ieee80211_bss_conf *info, 640*6c92544dSBjoern A. Zeeb u64 changed) 641*6c92544dSBjoern A. Zeeb { 642*6c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 643*6c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 644*6c92544dSBjoern A. Zeeb 645*6c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 646*6c92544dSBjoern A. Zeeb 647*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BSSID) 648*6c92544dSBjoern A. Zeeb mt76x02_mac_set_bssid(dev, mvif->idx, info->bssid); 649*6c92544dSBjoern A. Zeeb 650*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) 651*6c92544dSBjoern A. Zeeb mt76x02_mac_set_tx_protection(dev, info->use_cts_prot, 652*6c92544dSBjoern A. Zeeb info->ht_operation_mode); 653*6c92544dSBjoern A. Zeeb 654*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_INT) { 655*6c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_BEACON_TIME_CFG, 656*6c92544dSBjoern A. Zeeb MT_BEACON_TIME_CFG_INTVAL, 657*6c92544dSBjoern A. Zeeb info->beacon_int << 4); 658*6c92544dSBjoern A. Zeeb dev->mt76.beacon_int = info->beacon_int; 659*6c92544dSBjoern A. Zeeb } 660*6c92544dSBjoern A. Zeeb 661*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_ENABLED) 662*6c92544dSBjoern A. Zeeb mt76x02_mac_set_beacon_enable(dev, vif, info->enable_beacon); 663*6c92544dSBjoern A. Zeeb 664*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_PREAMBLE) 665*6c92544dSBjoern A. Zeeb mt76x02_mac_set_short_preamble(dev, info->use_short_preamble); 666*6c92544dSBjoern A. Zeeb 667*6c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_SLOT) { 668*6c92544dSBjoern A. Zeeb int slottime = info->use_short_slot ? 9 : 20; 669*6c92544dSBjoern A. Zeeb 670*6c92544dSBjoern A. Zeeb dev->slottime = slottime; 671*6c92544dSBjoern A. Zeeb mt76x02_set_tx_ackto(dev); 672*6c92544dSBjoern A. Zeeb } 673*6c92544dSBjoern A. Zeeb 674*6c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 675*6c92544dSBjoern A. Zeeb } 676*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_bss_info_changed); 677*6c92544dSBjoern A. Zeeb 678*6c92544dSBjoern A. Zeeb void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev) 679*6c92544dSBjoern A. Zeeb { 680*6c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mt76_hw(dev); 681*6c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy; 682*6c92544dSBjoern A. Zeeb int i; 683*6c92544dSBjoern A. Zeeb 684*6c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { 685*6c92544dSBjoern A. Zeeb u8 *addr = dev->macaddr_list[i].addr; 686*6c92544dSBjoern A. Zeeb 687*6c92544dSBjoern A. Zeeb memcpy(addr, dev->mphy.macaddr, ETH_ALEN); 688*6c92544dSBjoern A. Zeeb 689*6c92544dSBjoern A. Zeeb if (!i) 690*6c92544dSBjoern A. Zeeb continue; 691*6c92544dSBjoern A. Zeeb 692*6c92544dSBjoern A. Zeeb addr[0] |= BIT(1); 693*6c92544dSBjoern A. Zeeb addr[0] ^= ((i - 1) << 2); 694*6c92544dSBjoern A. Zeeb } 695*6c92544dSBjoern A. Zeeb wiphy->addresses = dev->macaddr_list; 696*6c92544dSBjoern A. Zeeb wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); 697*6c92544dSBjoern A. Zeeb } 698*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list); 699*6c92544dSBjoern A. Zeeb 700*6c92544dSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL"); 701