16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC 26c92544dSBjoern A. Zeeb /* 36c92544dSBjoern A. Zeeb * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> 46c92544dSBjoern A. Zeeb * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 56c92544dSBjoern A. Zeeb */ 66c92544dSBjoern A. Zeeb 76c92544dSBjoern A. Zeeb #include <linux/module.h> 86c92544dSBjoern A. Zeeb #include "mt76x02.h" 96c92544dSBjoern A. Zeeb 106c92544dSBjoern A. Zeeb #define MT76x02_CCK_RATE(_idx, _rate) { \ 116c92544dSBjoern A. Zeeb .bitrate = _rate, \ 126c92544dSBjoern A. Zeeb .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ 136c92544dSBjoern A. Zeeb .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ 146c92544dSBjoern A. Zeeb .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \ 156c92544dSBjoern A. Zeeb } 166c92544dSBjoern A. Zeeb 176c92544dSBjoern A. Zeeb struct ieee80211_rate mt76x02_rates[] = { 186c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(0, 10), 196c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(1, 20), 206c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(2, 55), 216c92544dSBjoern A. Zeeb MT76x02_CCK_RATE(3, 110), 226c92544dSBjoern A. Zeeb OFDM_RATE(0, 60), 236c92544dSBjoern A. Zeeb OFDM_RATE(1, 90), 246c92544dSBjoern A. Zeeb OFDM_RATE(2, 120), 256c92544dSBjoern A. Zeeb OFDM_RATE(3, 180), 266c92544dSBjoern A. Zeeb OFDM_RATE(4, 240), 276c92544dSBjoern A. Zeeb OFDM_RATE(5, 360), 286c92544dSBjoern A. Zeeb OFDM_RATE(6, 480), 296c92544dSBjoern A. Zeeb OFDM_RATE(7, 540), 306c92544dSBjoern A. Zeeb }; 316c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_rates); 326c92544dSBjoern A. Zeeb 336c92544dSBjoern A. Zeeb static const struct ieee80211_iface_limit mt76x02_if_limits[] = { 346c92544dSBjoern A. Zeeb { 356c92544dSBjoern A. Zeeb .max = 1, 366c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_ADHOC) 376c92544dSBjoern A. Zeeb }, { 386c92544dSBjoern A. Zeeb .max = 8, 396c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION) | 406c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 416c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) | 426c92544dSBjoern A. Zeeb #endif 436c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) | 446c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) | 456c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) 466c92544dSBjoern A. Zeeb }, 476c92544dSBjoern A. Zeeb }; 486c92544dSBjoern A. Zeeb 496c92544dSBjoern A. Zeeb static const struct ieee80211_iface_limit mt76x02u_if_limits[] = { 506c92544dSBjoern A. Zeeb { 516c92544dSBjoern A. Zeeb .max = 1, 526c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_ADHOC) 536c92544dSBjoern A. Zeeb }, { 546c92544dSBjoern A. Zeeb .max = 2, 556c92544dSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION) | 566c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 576c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) | 586c92544dSBjoern A. Zeeb #endif 596c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) | 606c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) | 616c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) 626c92544dSBjoern A. Zeeb }, 636c92544dSBjoern A. Zeeb }; 646c92544dSBjoern A. Zeeb 656c92544dSBjoern A. Zeeb static const struct ieee80211_iface_combination mt76x02_if_comb[] = { 666c92544dSBjoern A. Zeeb { 676c92544dSBjoern A. Zeeb .limits = mt76x02_if_limits, 686c92544dSBjoern A. Zeeb .n_limits = ARRAY_SIZE(mt76x02_if_limits), 696c92544dSBjoern A. Zeeb .max_interfaces = 8, 706c92544dSBjoern A. Zeeb .num_different_channels = 1, 716c92544dSBjoern A. Zeeb .beacon_int_infra_match = true, 726c92544dSBjoern A. Zeeb .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 736c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_20) | 746c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_40) | 756c92544dSBjoern A. Zeeb BIT(NL80211_CHAN_WIDTH_80), 766c92544dSBjoern A. Zeeb } 776c92544dSBjoern A. Zeeb }; 786c92544dSBjoern A. Zeeb 796c92544dSBjoern A. Zeeb static const struct ieee80211_iface_combination mt76x02u_if_comb[] = { 806c92544dSBjoern A. Zeeb { 816c92544dSBjoern A. Zeeb .limits = mt76x02u_if_limits, 826c92544dSBjoern A. Zeeb .n_limits = ARRAY_SIZE(mt76x02u_if_limits), 836c92544dSBjoern A. Zeeb .max_interfaces = 2, 846c92544dSBjoern A. Zeeb .num_different_channels = 1, 856c92544dSBjoern A. Zeeb .beacon_int_infra_match = true, 866c92544dSBjoern A. Zeeb } 876c92544dSBjoern A. Zeeb }; 886c92544dSBjoern A. Zeeb 896c92544dSBjoern A. Zeeb static void 90*cbb3ec25SBjoern A. Zeeb mt76x02_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off) 916c92544dSBjoern A. Zeeb { 92*cbb3ec25SBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, 936c92544dSBjoern A. Zeeb mt76); 946c92544dSBjoern A. Zeeb u32 val; 956c92544dSBjoern A. Zeeb 966c92544dSBjoern A. Zeeb val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xff) | 976c92544dSBjoern A. Zeeb FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | 986c92544dSBjoern A. Zeeb FIELD_PREP(MT_LED_STATUS_ON, delay_on); 996c92544dSBjoern A. Zeeb 100*cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_S0(mphy->leds.pin), val); 101*cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_S1(mphy->leds.pin), val); 1026c92544dSBjoern A. Zeeb 103*cbb3ec25SBjoern A. Zeeb val = MT_LED_CTRL_REPLAY(mphy->leds.pin) | 104*cbb3ec25SBjoern A. Zeeb MT_LED_CTRL_KICK(mphy->leds.pin); 105*cbb3ec25SBjoern A. Zeeb if (mphy->leds.al) 106*cbb3ec25SBjoern A. Zeeb val |= MT_LED_CTRL_POLARITY(mphy->leds.pin); 1076c92544dSBjoern A. Zeeb mt76_wr(dev, MT_LED_CTRL, val); 1086c92544dSBjoern A. Zeeb } 1096c92544dSBjoern A. Zeeb 1106c92544dSBjoern A. Zeeb static int 1116c92544dSBjoern A. Zeeb mt76x02_led_set_blink(struct led_classdev *led_cdev, 1126c92544dSBjoern A. Zeeb unsigned long *delay_on, 1136c92544dSBjoern A. Zeeb unsigned long *delay_off) 1146c92544dSBjoern A. Zeeb { 115*cbb3ec25SBjoern A. Zeeb struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, 116*cbb3ec25SBjoern A. Zeeb leds.cdev); 1176c92544dSBjoern A. Zeeb u8 delta_on, delta_off; 1186c92544dSBjoern A. Zeeb 1196c92544dSBjoern A. Zeeb delta_off = max_t(u8, *delay_off / 10, 1); 1206c92544dSBjoern A. Zeeb delta_on = max_t(u8, *delay_on / 10, 1); 1216c92544dSBjoern A. Zeeb 122*cbb3ec25SBjoern A. Zeeb mt76x02_led_set_config(mphy, delta_on, delta_off); 1236c92544dSBjoern A. Zeeb 1246c92544dSBjoern A. Zeeb return 0; 1256c92544dSBjoern A. Zeeb } 1266c92544dSBjoern A. Zeeb 1276c92544dSBjoern A. Zeeb static void 1286c92544dSBjoern A. Zeeb mt76x02_led_set_brightness(struct led_classdev *led_cdev, 1296c92544dSBjoern A. Zeeb enum led_brightness brightness) 1306c92544dSBjoern A. Zeeb { 131*cbb3ec25SBjoern A. Zeeb struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, 132*cbb3ec25SBjoern A. Zeeb leds.cdev); 1336c92544dSBjoern A. Zeeb 1346c92544dSBjoern A. Zeeb if (!brightness) 135*cbb3ec25SBjoern A. Zeeb mt76x02_led_set_config(mphy, 0, 0xff); 1366c92544dSBjoern A. Zeeb else 137*cbb3ec25SBjoern A. Zeeb mt76x02_led_set_config(mphy, 0xff, 0); 1386c92544dSBjoern A. Zeeb } 1396c92544dSBjoern A. Zeeb 1406c92544dSBjoern A. Zeeb int mt76x02_init_device(struct mt76x02_dev *dev) 1416c92544dSBjoern A. Zeeb { 1426c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mt76_hw(dev); 1436c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy; 1446c92544dSBjoern A. Zeeb 1456c92544dSBjoern A. Zeeb INIT_DELAYED_WORK(&dev->mphy.mac_work, mt76x02_mac_work); 1466c92544dSBjoern A. Zeeb 1476c92544dSBjoern A. Zeeb hw->queues = 4; 1486c92544dSBjoern A. Zeeb hw->max_rates = 1; 1496c92544dSBjoern A. Zeeb hw->max_report_rates = 7; 1506c92544dSBjoern A. Zeeb hw->max_rate_tries = 1; 1516c92544dSBjoern A. Zeeb hw->extra_tx_headroom = 2; 1526c92544dSBjoern A. Zeeb 1536c92544dSBjoern A. Zeeb if (mt76_is_usb(&dev->mt76)) { 1546c92544dSBjoern A. Zeeb hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + 1556c92544dSBjoern A. Zeeb MT_DMA_HDR_LEN; 1566c92544dSBjoern A. Zeeb wiphy->iface_combinations = mt76x02u_if_comb; 1576c92544dSBjoern A. Zeeb wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02u_if_comb); 1586c92544dSBjoern A. Zeeb } else { 1596c92544dSBjoern A. Zeeb INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); 1606c92544dSBjoern A. Zeeb 1616c92544dSBjoern A. Zeeb mt76x02_dfs_init_detector(dev); 1626c92544dSBjoern A. Zeeb 1636c92544dSBjoern A. Zeeb wiphy->reg_notifier = mt76x02_regd_notifier; 1646c92544dSBjoern A. Zeeb wiphy->iface_combinations = mt76x02_if_comb; 1656c92544dSBjoern A. Zeeb wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb); 1666c92544dSBjoern A. Zeeb 1676c92544dSBjoern A. Zeeb /* init led callbacks */ 1686c92544dSBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) { 169*cbb3ec25SBjoern A. Zeeb dev->mphy.leds.cdev.brightness_set = 1706c92544dSBjoern A. Zeeb mt76x02_led_set_brightness; 171*cbb3ec25SBjoern A. Zeeb dev->mphy.leds.cdev.blink_set = mt76x02_led_set_blink; 1726c92544dSBjoern A. Zeeb } 1736c92544dSBjoern A. Zeeb } 1746c92544dSBjoern A. Zeeb 1756c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 1766c92544dSBjoern A. Zeeb 1776c92544dSBjoern A. Zeeb hw->sta_data_size = sizeof(struct mt76x02_sta); 1786c92544dSBjoern A. Zeeb hw->vif_data_size = sizeof(struct mt76x02_vif); 1796c92544dSBjoern A. Zeeb 1806c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 1816c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 1826c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); 1836c92544dSBjoern A. Zeeb 1846c92544dSBjoern A. Zeeb dev->mt76.global_wcid.idx = 255; 1856c92544dSBjoern A. Zeeb dev->mt76.global_wcid.hw_key_idx = -1; 1866c92544dSBjoern A. Zeeb dev->slottime = 9; 1876c92544dSBjoern A. Zeeb 1886c92544dSBjoern A. Zeeb if (is_mt76x2(dev)) { 1896c92544dSBjoern A. Zeeb dev->mphy.sband_2g.sband.ht_cap.cap |= 1906c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_LDPC_CODING; 1916c92544dSBjoern A. Zeeb dev->mphy.sband_5g.sband.ht_cap.cap |= 1926c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_LDPC_CODING; 1936c92544dSBjoern A. Zeeb dev->mphy.chainmask = 0x202; 1946c92544dSBjoern A. Zeeb dev->mphy.antenna_mask = 3; 1956c92544dSBjoern A. Zeeb } else { 1966c92544dSBjoern A. Zeeb dev->mphy.chainmask = 0x101; 1976c92544dSBjoern A. Zeeb dev->mphy.antenna_mask = 1; 1986c92544dSBjoern A. Zeeb } 1996c92544dSBjoern A. Zeeb 2006c92544dSBjoern A. Zeeb return 0; 2016c92544dSBjoern A. Zeeb } 2026c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_init_device); 2036c92544dSBjoern A. Zeeb 2046c92544dSBjoern A. Zeeb void mt76x02_configure_filter(struct ieee80211_hw *hw, 2056c92544dSBjoern A. Zeeb unsigned int changed_flags, 2066c92544dSBjoern A. Zeeb unsigned int *total_flags, u64 multicast) 2076c92544dSBjoern A. Zeeb { 2086c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 2096c92544dSBjoern A. Zeeb u32 flags = 0; 2106c92544dSBjoern A. Zeeb 2116c92544dSBjoern A. Zeeb #define MT76_FILTER(_flag, _hw) do { \ 2126c92544dSBjoern A. Zeeb flags |= *total_flags & FIF_##_flag; \ 2136c92544dSBjoern A. Zeeb dev->mt76.rxfilter &= ~(_hw); \ 2146c92544dSBjoern A. Zeeb dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 2156c92544dSBjoern A. Zeeb } while (0) 2166c92544dSBjoern A. Zeeb 2176c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 2186c92544dSBjoern A. Zeeb 2196c92544dSBjoern A. Zeeb dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; 2206c92544dSBjoern A. Zeeb 2216c92544dSBjoern A. Zeeb MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); 2226c92544dSBjoern A. Zeeb MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); 2236c92544dSBjoern A. Zeeb MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | 2246c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CTS | 2256c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CFEND | 2266c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CFACK | 2276c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_BA | 2286c92544dSBjoern A. Zeeb MT_RX_FILTR_CFG_CTRL_RSV); 2296c92544dSBjoern A. Zeeb MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); 2306c92544dSBjoern A. Zeeb 2316c92544dSBjoern A. Zeeb *total_flags = flags; 2326c92544dSBjoern A. Zeeb mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); 2336c92544dSBjoern A. Zeeb 2346c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 2356c92544dSBjoern A. Zeeb } 2366c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_configure_filter); 2376c92544dSBjoern A. Zeeb 2386c92544dSBjoern A. Zeeb int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 2396c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 2406c92544dSBjoern A. Zeeb { 2416c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 2426c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 2436c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 2446c92544dSBjoern A. Zeeb int idx = 0; 2456c92544dSBjoern A. Zeeb 2466c92544dSBjoern A. Zeeb memset(msta, 0, sizeof(*msta)); 2476c92544dSBjoern A. Zeeb 2486c92544dSBjoern A. Zeeb idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT76x02_N_WCIDS); 2496c92544dSBjoern A. Zeeb if (idx < 0) 2506c92544dSBjoern A. Zeeb return -ENOSPC; 2516c92544dSBjoern A. Zeeb 2526c92544dSBjoern A. Zeeb msta->vif = mvif; 2536c92544dSBjoern A. Zeeb msta->wcid.sta = 1; 2546c92544dSBjoern A. Zeeb msta->wcid.idx = idx; 2556c92544dSBjoern A. Zeeb msta->wcid.hw_key_idx = -1; 2566c92544dSBjoern A. Zeeb mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); 2576c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_drop(dev, idx, false); 2586c92544dSBjoern A. Zeeb ewma_pktlen_init(&msta->pktlen); 2596c92544dSBjoern A. Zeeb 2606c92544dSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_AP) 2616c92544dSBjoern A. Zeeb set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); 2626c92544dSBjoern A. Zeeb 2636c92544dSBjoern A. Zeeb return 0; 2646c92544dSBjoern A. Zeeb } 2656c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_add); 2666c92544dSBjoern A. Zeeb 2676c92544dSBjoern A. Zeeb void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 2686c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 2696c92544dSBjoern A. Zeeb { 2706c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 2716c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 2726c92544dSBjoern A. Zeeb int idx = wcid->idx; 2736c92544dSBjoern A. Zeeb 2746c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_drop(dev, idx, true); 2756c92544dSBjoern A. Zeeb mt76x02_mac_wcid_setup(dev, idx, 0, NULL); 2766c92544dSBjoern A. Zeeb } 2776c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_remove); 2786c92544dSBjoern A. Zeeb 2796c92544dSBjoern A. Zeeb static void 2806c92544dSBjoern A. Zeeb mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, 2816c92544dSBjoern A. Zeeb unsigned int idx) 2826c92544dSBjoern A. Zeeb { 2836c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 2846c92544dSBjoern A. Zeeb struct mt76_txq *mtxq; 2856c92544dSBjoern A. Zeeb 2866c92544dSBjoern A. Zeeb memset(mvif, 0, sizeof(*mvif)); 2876c92544dSBjoern A. Zeeb 2886c92544dSBjoern A. Zeeb mvif->idx = idx; 2896c92544dSBjoern A. Zeeb mvif->group_wcid.idx = MT_VIF_WCID(idx); 2906c92544dSBjoern A. Zeeb mvif->group_wcid.hw_key_idx = -1; 2916c92544dSBjoern A. Zeeb mt76_packet_id_init(&mvif->group_wcid); 2926c92544dSBjoern A. Zeeb 2936c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)vif->txq->drv_priv; 2946c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->mt76.wcid[MT_VIF_WCID(idx)], &mvif->group_wcid); 2956c92544dSBjoern A. Zeeb mtxq->wcid = MT_VIF_WCID(idx); 2966c92544dSBjoern A. Zeeb } 2976c92544dSBjoern A. Zeeb 2986c92544dSBjoern A. Zeeb int 2996c92544dSBjoern A. Zeeb mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 3006c92544dSBjoern A. Zeeb { 3016c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 3026c92544dSBjoern A. Zeeb unsigned int idx = 0; 3036c92544dSBjoern A. Zeeb 3046c92544dSBjoern A. Zeeb /* Allow to change address in HW if we create first interface. */ 3056c92544dSBjoern A. Zeeb if (!dev->mt76.vif_mask && 3066c92544dSBjoern A. Zeeb (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) || 3076c92544dSBjoern A. Zeeb memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1))) 3086c92544dSBjoern A. Zeeb mt76x02_mac_setaddr(dev, vif->addr); 3096c92544dSBjoern A. Zeeb 3106c92544dSBjoern A. Zeeb if (vif->addr[0] & BIT(1)) 3116c92544dSBjoern A. Zeeb idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7); 3126c92544dSBjoern A. Zeeb 3136c92544dSBjoern A. Zeeb /* 3146c92544dSBjoern A. Zeeb * Client mode typically only has one configurable BSSID register, 3156c92544dSBjoern A. Zeeb * which is used for bssidx=0. This is linked to the MAC address. 3166c92544dSBjoern A. Zeeb * Since mac80211 allows changing interface types, and we cannot 3176c92544dSBjoern A. Zeeb * force the use of the primary MAC address for a station mode 3186c92544dSBjoern A. Zeeb * interface, we need some other way of configuring a per-interface 3196c92544dSBjoern A. Zeeb * remote BSSID. 3206c92544dSBjoern A. Zeeb * The hardware provides an AP-Client feature, where bssidx 0-7 are 3216c92544dSBjoern A. Zeeb * used for AP mode and bssidx 8-15 for client mode. 3226c92544dSBjoern A. Zeeb * We shift the station interface bss index by 8 to force the 3236c92544dSBjoern A. Zeeb * hardware to recognize the BSSID. 3246c92544dSBjoern A. Zeeb * The resulting bssidx mismatch for unicast frames is ignored by hw. 3256c92544dSBjoern A. Zeeb */ 3266c92544dSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION) 3276c92544dSBjoern A. Zeeb idx += 8; 3286c92544dSBjoern A. Zeeb 3296c92544dSBjoern A. Zeeb /* vif is already set or idx is 8 for AP/Mesh/... */ 3306c92544dSBjoern A. Zeeb if (dev->mt76.vif_mask & BIT_ULL(idx) || 3316c92544dSBjoern A. Zeeb (vif->type != NL80211_IFTYPE_STATION && idx > 7)) 3326c92544dSBjoern A. Zeeb return -EBUSY; 3336c92544dSBjoern A. Zeeb 3346c92544dSBjoern A. Zeeb dev->mt76.vif_mask |= BIT_ULL(idx); 3356c92544dSBjoern A. Zeeb 3366c92544dSBjoern A. Zeeb mt76x02_vif_init(dev, vif, idx); 3376c92544dSBjoern A. Zeeb return 0; 3386c92544dSBjoern A. Zeeb } 3396c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_add_interface); 3406c92544dSBjoern A. Zeeb 3416c92544dSBjoern A. Zeeb void mt76x02_remove_interface(struct ieee80211_hw *hw, 3426c92544dSBjoern A. Zeeb struct ieee80211_vif *vif) 3436c92544dSBjoern A. Zeeb { 3446c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 3456c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 3466c92544dSBjoern A. Zeeb 3476c92544dSBjoern A. Zeeb dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx); 3486c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->mt76.wcid[mvif->group_wcid.idx], NULL); 3496c92544dSBjoern A. Zeeb mt76_packet_id_flush(&dev->mt76, &mvif->group_wcid); 3506c92544dSBjoern A. Zeeb } 3516c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_remove_interface); 3526c92544dSBjoern A. Zeeb 3536c92544dSBjoern A. Zeeb int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 3546c92544dSBjoern A. Zeeb struct ieee80211_ampdu_params *params) 3556c92544dSBjoern A. Zeeb { 3566c92544dSBjoern A. Zeeb enum ieee80211_ampdu_mlme_action action = params->action; 3576c92544dSBjoern A. Zeeb struct ieee80211_sta *sta = params->sta; 3586c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 3596c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 3606c92544dSBjoern A. Zeeb struct ieee80211_txq *txq = sta->txq[params->tid]; 3616c92544dSBjoern A. Zeeb u16 tid = params->tid; 3626c92544dSBjoern A. Zeeb u16 ssn = params->ssn; 3636c92544dSBjoern A. Zeeb struct mt76_txq *mtxq; 3646c92544dSBjoern A. Zeeb int ret = 0; 3656c92544dSBjoern A. Zeeb 3666c92544dSBjoern A. Zeeb if (!txq) 3676c92544dSBjoern A. Zeeb return -EINVAL; 3686c92544dSBjoern A. Zeeb 3696c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)txq->drv_priv; 3706c92544dSBjoern A. Zeeb 3716c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 3726c92544dSBjoern A. Zeeb switch (action) { 3736c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_RX_START: 3746c92544dSBjoern A. Zeeb mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, 3756c92544dSBjoern A. Zeeb ssn, params->buf_size); 3766c92544dSBjoern A. Zeeb mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); 3776c92544dSBjoern A. Zeeb break; 3786c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_RX_STOP: 3796c92544dSBjoern A. Zeeb mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 3806c92544dSBjoern A. Zeeb mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, 3816c92544dSBjoern A. Zeeb BIT(16 + tid)); 3826c92544dSBjoern A. Zeeb break; 3836c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_OPERATIONAL: 3846c92544dSBjoern A. Zeeb mtxq->aggr = true; 3856c92544dSBjoern A. Zeeb mtxq->send_bar = false; 3866c92544dSBjoern A. Zeeb ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); 3876c92544dSBjoern A. Zeeb break; 3886c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH: 3896c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 3906c92544dSBjoern A. Zeeb mtxq->aggr = false; 3916c92544dSBjoern A. Zeeb break; 3926c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_START: 3936c92544dSBjoern A. Zeeb mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); 3946c92544dSBjoern A. Zeeb ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 3956c92544dSBjoern A. Zeeb break; 3966c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_CONT: 3976c92544dSBjoern A. Zeeb mtxq->aggr = false; 3986c92544dSBjoern A. Zeeb ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 3996c92544dSBjoern A. Zeeb break; 4006c92544dSBjoern A. Zeeb } 4016c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 4026c92544dSBjoern A. Zeeb 4036c92544dSBjoern A. Zeeb return ret; 4046c92544dSBjoern A. Zeeb } 4056c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); 4066c92544dSBjoern A. Zeeb 4076c92544dSBjoern A. Zeeb int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 4086c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta, 4096c92544dSBjoern A. Zeeb struct ieee80211_key_conf *key) 4106c92544dSBjoern A. Zeeb { 4116c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 4126c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 4136c92544dSBjoern A. Zeeb struct mt76x02_sta *msta; 4146c92544dSBjoern A. Zeeb struct mt76_wcid *wcid; 4156c92544dSBjoern A. Zeeb int idx = key->keyidx; 4166c92544dSBjoern A. Zeeb int ret; 4176c92544dSBjoern A. Zeeb 4186c92544dSBjoern A. Zeeb /* fall back to sw encryption for unsupported ciphers */ 4196c92544dSBjoern A. Zeeb switch (key->cipher) { 4206c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP40: 4216c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP104: 4226c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_TKIP: 4236c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP: 4246c92544dSBjoern A. Zeeb break; 4256c92544dSBjoern A. Zeeb default: 4266c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 4276c92544dSBjoern A. Zeeb } 4286c92544dSBjoern A. Zeeb 4296c92544dSBjoern A. Zeeb /* 4306c92544dSBjoern A. Zeeb * The hardware does not support per-STA RX GTK, fall back 4316c92544dSBjoern A. Zeeb * to software mode for these. 4326c92544dSBjoern A. Zeeb */ 4336c92544dSBjoern A. Zeeb if ((vif->type == NL80211_IFTYPE_ADHOC || 4346c92544dSBjoern A. Zeeb vif->type == NL80211_IFTYPE_MESH_POINT) && 4356c92544dSBjoern A. Zeeb (key->cipher == WLAN_CIPHER_SUITE_TKIP || 4366c92544dSBjoern A. Zeeb key->cipher == WLAN_CIPHER_SUITE_CCMP) && 4376c92544dSBjoern A. Zeeb !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 4386c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 4396c92544dSBjoern A. Zeeb 4406c92544dSBjoern A. Zeeb /* 4416c92544dSBjoern A. Zeeb * In USB AP mode, broadcast/multicast frames are setup in beacon 4426c92544dSBjoern A. Zeeb * data registers and sent via HW beacons engine, they require to 4436c92544dSBjoern A. Zeeb * be already encrypted. 4446c92544dSBjoern A. Zeeb */ 4456c92544dSBjoern A. Zeeb if (mt76_is_usb(&dev->mt76) && 4466c92544dSBjoern A. Zeeb vif->type == NL80211_IFTYPE_AP && 4476c92544dSBjoern A. Zeeb !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 4486c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 4496c92544dSBjoern A. Zeeb 4506c92544dSBjoern A. Zeeb /* MT76x0 GTK offloading does not work with more than one VIF */ 4516c92544dSBjoern A. Zeeb if (is_mt76x0(dev) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 4526c92544dSBjoern A. Zeeb return -EOPNOTSUPP; 4536c92544dSBjoern A. Zeeb 4546c92544dSBjoern A. Zeeb msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL; 4556c92544dSBjoern A. Zeeb wcid = msta ? &msta->wcid : &mvif->group_wcid; 4566c92544dSBjoern A. Zeeb 457*cbb3ec25SBjoern A. Zeeb if (cmd != SET_KEY) { 4586c92544dSBjoern A. Zeeb if (idx == wcid->hw_key_idx) { 4596c92544dSBjoern A. Zeeb wcid->hw_key_idx = -1; 4606c92544dSBjoern A. Zeeb wcid->sw_iv = false; 4616c92544dSBjoern A. Zeeb } 4626c92544dSBjoern A. Zeeb 463*cbb3ec25SBjoern A. Zeeb return 0; 464*cbb3ec25SBjoern A. Zeeb } 465*cbb3ec25SBjoern A. Zeeb 466*cbb3ec25SBjoern A. Zeeb key->hw_key_idx = wcid->idx; 467*cbb3ec25SBjoern A. Zeeb wcid->hw_key_idx = idx; 468*cbb3ec25SBjoern A. Zeeb if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { 469*cbb3ec25SBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 470*cbb3ec25SBjoern A. Zeeb wcid->sw_iv = true; 4716c92544dSBjoern A. Zeeb } 4726c92544dSBjoern A. Zeeb mt76_wcid_key_setup(&dev->mt76, wcid, key); 4736c92544dSBjoern A. Zeeb 4746c92544dSBjoern A. Zeeb if (!msta) { 4756c92544dSBjoern A. Zeeb if (key || wcid->hw_key_idx == idx) { 4766c92544dSBjoern A. Zeeb ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key); 4776c92544dSBjoern A. Zeeb if (ret) 4786c92544dSBjoern A. Zeeb return ret; 4796c92544dSBjoern A. Zeeb } 4806c92544dSBjoern A. Zeeb 4816c92544dSBjoern A. Zeeb return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key); 4826c92544dSBjoern A. Zeeb } 4836c92544dSBjoern A. Zeeb 4846c92544dSBjoern A. Zeeb return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key); 4856c92544dSBjoern A. Zeeb } 4866c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_key); 4876c92544dSBjoern A. Zeeb 4886c92544dSBjoern A. Zeeb int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4896c92544dSBjoern A. Zeeb unsigned int link_id, u16 queue, 4906c92544dSBjoern A. Zeeb const struct ieee80211_tx_queue_params *params) 4916c92544dSBjoern A. Zeeb { 4926c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 4936c92544dSBjoern A. Zeeb u8 cw_min = 5, cw_max = 10, qid; 4946c92544dSBjoern A. Zeeb u32 val; 4956c92544dSBjoern A. Zeeb 4966c92544dSBjoern A. Zeeb qid = dev->mphy.q_tx[queue]->hw_idx; 4976c92544dSBjoern A. Zeeb 4986c92544dSBjoern A. Zeeb if (params->cw_min) 4996c92544dSBjoern A. Zeeb cw_min = fls(params->cw_min); 5006c92544dSBjoern A. Zeeb if (params->cw_max) 5016c92544dSBjoern A. Zeeb cw_max = fls(params->cw_max); 5026c92544dSBjoern A. Zeeb 5036c92544dSBjoern A. Zeeb val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) | 5046c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | 5056c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | 5066c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); 5076c92544dSBjoern A. Zeeb mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); 5086c92544dSBjoern A. Zeeb 5096c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_TXOP(qid)); 5106c92544dSBjoern A. Zeeb val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid)); 5116c92544dSBjoern A. Zeeb val |= params->txop << MT_WMM_TXOP_SHIFT(qid); 5126c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_TXOP(qid), val); 5136c92544dSBjoern A. Zeeb 5146c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_AIFSN); 5156c92544dSBjoern A. Zeeb val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid)); 5166c92544dSBjoern A. Zeeb val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid); 5176c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_AIFSN, val); 5186c92544dSBjoern A. Zeeb 5196c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_CWMIN); 5206c92544dSBjoern A. Zeeb val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid)); 5216c92544dSBjoern A. Zeeb val |= cw_min << MT_WMM_CWMIN_SHIFT(qid); 5226c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_CWMIN, val); 5236c92544dSBjoern A. Zeeb 5246c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_CWMAX); 5256c92544dSBjoern A. Zeeb val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid)); 5266c92544dSBjoern A. Zeeb val |= cw_max << MT_WMM_CWMAX_SHIFT(qid); 5276c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_CWMAX, val); 5286c92544dSBjoern A. Zeeb 5296c92544dSBjoern A. Zeeb return 0; 5306c92544dSBjoern A. Zeeb } 5316c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_conf_tx); 5326c92544dSBjoern A. Zeeb 5336c92544dSBjoern A. Zeeb void mt76x02_set_tx_ackto(struct mt76x02_dev *dev) 5346c92544dSBjoern A. Zeeb { 5356c92544dSBjoern A. Zeeb u8 ackto, sifs, slottime = dev->slottime; 5366c92544dSBjoern A. Zeeb 5376c92544dSBjoern A. Zeeb /* As defined by IEEE 802.11-2007 17.3.8.6 */ 5386c92544dSBjoern A. Zeeb slottime += 3 * dev->coverage_class; 5396c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, 5406c92544dSBjoern A. Zeeb MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); 5416c92544dSBjoern A. Zeeb 5426c92544dSBjoern A. Zeeb sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, 5436c92544dSBjoern A. Zeeb MT_XIFS_TIME_CFG_OFDM_SIFS); 5446c92544dSBjoern A. Zeeb 5456c92544dSBjoern A. Zeeb ackto = slottime + sifs; 5466c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG, 5476c92544dSBjoern A. Zeeb MT_TX_TIMEOUT_CFG_ACKTO, ackto); 5486c92544dSBjoern A. Zeeb } 5496c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto); 5506c92544dSBjoern A. Zeeb 5516c92544dSBjoern A. Zeeb void mt76x02_set_coverage_class(struct ieee80211_hw *hw, 5526c92544dSBjoern A. Zeeb s16 coverage_class) 5536c92544dSBjoern A. Zeeb { 5546c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 5556c92544dSBjoern A. Zeeb 5566c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 5576c92544dSBjoern A. Zeeb dev->coverage_class = max_t(s16, coverage_class, 0); 5586c92544dSBjoern A. Zeeb mt76x02_set_tx_ackto(dev); 5596c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 5606c92544dSBjoern A. Zeeb } 5616c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class); 5626c92544dSBjoern A. Zeeb 5636c92544dSBjoern A. Zeeb int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 5646c92544dSBjoern A. Zeeb { 5656c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 5666c92544dSBjoern A. Zeeb 5676c92544dSBjoern A. Zeeb if (val != ~0 && val > 0xffff) 5686c92544dSBjoern A. Zeeb return -EINVAL; 5696c92544dSBjoern A. Zeeb 5706c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 5716c92544dSBjoern A. Zeeb mt76x02_mac_set_rts_thresh(dev, val); 5726c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 5736c92544dSBjoern A. Zeeb 5746c92544dSBjoern A. Zeeb return 0; 5756c92544dSBjoern A. Zeeb } 5766c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_rts_threshold); 5776c92544dSBjoern A. Zeeb 5786c92544dSBjoern A. Zeeb void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, 5796c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, 5806c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 5816c92544dSBjoern A. Zeeb { 5826c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 5836c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 5846c92544dSBjoern A. Zeeb struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); 5856c92544dSBjoern A. Zeeb struct ieee80211_tx_rate rate = {}; 5866c92544dSBjoern A. Zeeb 5876c92544dSBjoern A. Zeeb if (!rates) 5886c92544dSBjoern A. Zeeb return; 5896c92544dSBjoern A. Zeeb 5906c92544dSBjoern A. Zeeb rate.idx = rates->rate[0].idx; 5916c92544dSBjoern A. Zeeb rate.flags = rates->rate[0].flags; 5926c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate); 5936c92544dSBjoern A. Zeeb } 5946c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); 5956c92544dSBjoern A. Zeeb 5966c92544dSBjoern A. Zeeb void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) 5976c92544dSBjoern A. Zeeb { 5986c92544dSBjoern A. Zeeb int hdrlen; 5996c92544dSBjoern A. Zeeb 6006c92544dSBjoern A. Zeeb if (!len) 6016c92544dSBjoern A. Zeeb return; 6026c92544dSBjoern A. Zeeb 6036c92544dSBjoern A. Zeeb hdrlen = ieee80211_get_hdrlen_from_skb(skb); 6046c92544dSBjoern A. Zeeb memmove(skb->data + len, skb->data, hdrlen); 6056c92544dSBjoern A. Zeeb skb_pull(skb, len); 6066c92544dSBjoern A. Zeeb } 6076c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); 6086c92544dSBjoern A. Zeeb 6096c92544dSBjoern A. Zeeb void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, 6106c92544dSBjoern A. Zeeb struct ieee80211_vif *vif) 6116c92544dSBjoern A. Zeeb { 6126c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 6136c92544dSBjoern A. Zeeb 6146c92544dSBjoern A. Zeeb clear_bit(MT76_SCANNING, &dev->mphy.state); 6156c92544dSBjoern A. Zeeb if (dev->cal.gain_init_done) { 6166c92544dSBjoern A. Zeeb /* Restore AGC gain and resume calibration after scanning. */ 6176c92544dSBjoern A. Zeeb dev->cal.low_gain = -1; 6186c92544dSBjoern A. Zeeb ieee80211_queue_delayed_work(hw, &dev->cal_work, 0); 6196c92544dSBjoern A. Zeeb } 6206c92544dSBjoern A. Zeeb } 6216c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete); 6226c92544dSBjoern A. Zeeb 6236c92544dSBjoern A. Zeeb void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, 6246c92544dSBjoern A. Zeeb bool ps) 6256c92544dSBjoern A. Zeeb { 6266c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); 6276c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; 6286c92544dSBjoern A. Zeeb int idx = msta->wcid.idx; 6296c92544dSBjoern A. Zeeb 6306c92544dSBjoern A. Zeeb mt76_stop_tx_queues(&dev->mphy, sta, true); 6316c92544dSBjoern A. Zeeb if (mt76_is_mmio(mdev)) 6326c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_drop(dev, idx, ps); 6336c92544dSBjoern A. Zeeb } 6346c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_ps); 6356c92544dSBjoern A. Zeeb 6366c92544dSBjoern A. Zeeb void mt76x02_bss_info_changed(struct ieee80211_hw *hw, 6376c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, 6386c92544dSBjoern A. Zeeb struct ieee80211_bss_conf *info, 6396c92544dSBjoern A. Zeeb u64 changed) 6406c92544dSBjoern A. Zeeb { 6416c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 6426c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv; 6436c92544dSBjoern A. Zeeb 6446c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex); 6456c92544dSBjoern A. Zeeb 6466c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BSSID) 6476c92544dSBjoern A. Zeeb mt76x02_mac_set_bssid(dev, mvif->idx, info->bssid); 6486c92544dSBjoern A. Zeeb 6496c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) 6506c92544dSBjoern A. Zeeb mt76x02_mac_set_tx_protection(dev, info->use_cts_prot, 6516c92544dSBjoern A. Zeeb info->ht_operation_mode); 6526c92544dSBjoern A. Zeeb 6536c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_INT) { 6546c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_BEACON_TIME_CFG, 6556c92544dSBjoern A. Zeeb MT_BEACON_TIME_CFG_INTVAL, 6566c92544dSBjoern A. Zeeb info->beacon_int << 4); 6576c92544dSBjoern A. Zeeb dev->mt76.beacon_int = info->beacon_int; 6586c92544dSBjoern A. Zeeb } 6596c92544dSBjoern A. Zeeb 6606c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_ENABLED) 6616c92544dSBjoern A. Zeeb mt76x02_mac_set_beacon_enable(dev, vif, info->enable_beacon); 6626c92544dSBjoern A. Zeeb 6636c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_PREAMBLE) 6646c92544dSBjoern A. Zeeb mt76x02_mac_set_short_preamble(dev, info->use_short_preamble); 6656c92544dSBjoern A. Zeeb 6666c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_SLOT) { 6676c92544dSBjoern A. Zeeb int slottime = info->use_short_slot ? 9 : 20; 6686c92544dSBjoern A. Zeeb 6696c92544dSBjoern A. Zeeb dev->slottime = slottime; 6706c92544dSBjoern A. Zeeb mt76x02_set_tx_ackto(dev); 6716c92544dSBjoern A. Zeeb } 6726c92544dSBjoern A. Zeeb 6736c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex); 6746c92544dSBjoern A. Zeeb } 6756c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_bss_info_changed); 6766c92544dSBjoern A. Zeeb 6776c92544dSBjoern A. Zeeb void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev) 6786c92544dSBjoern A. Zeeb { 6796c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mt76_hw(dev); 6806c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy; 6816c92544dSBjoern A. Zeeb int i; 6826c92544dSBjoern A. Zeeb 6836c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { 6846c92544dSBjoern A. Zeeb u8 *addr = dev->macaddr_list[i].addr; 6856c92544dSBjoern A. Zeeb 6866c92544dSBjoern A. Zeeb memcpy(addr, dev->mphy.macaddr, ETH_ALEN); 6876c92544dSBjoern A. Zeeb 6886c92544dSBjoern A. Zeeb if (!i) 6896c92544dSBjoern A. Zeeb continue; 6906c92544dSBjoern A. Zeeb 6916c92544dSBjoern A. Zeeb addr[0] |= BIT(1); 6926c92544dSBjoern A. Zeeb addr[0] ^= ((i - 1) << 2); 6936c92544dSBjoern A. Zeeb } 6946c92544dSBjoern A. Zeeb wiphy->addresses = dev->macaddr_list; 6956c92544dSBjoern A. Zeeb wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); 6966c92544dSBjoern A. Zeeb } 6976c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list); 6986c92544dSBjoern A. Zeeb 6996c92544dSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL"); 700