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
mt76x02_led_set_config(struct mt76_phy * mphy,u8 delay_on,u8 delay_off)90cbb3ec25SBjoern A. Zeeb mt76x02_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off)
916c92544dSBjoern A. Zeeb {
92cbb3ec25SBjoern 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
100cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_S0(mphy->leds.pin), val);
101cbb3ec25SBjoern A. Zeeb mt76_wr(dev, MT_LED_S1(mphy->leds.pin), val);
1026c92544dSBjoern A. Zeeb
103cbb3ec25SBjoern A. Zeeb val = MT_LED_CTRL_REPLAY(mphy->leds.pin) |
104cbb3ec25SBjoern A. Zeeb MT_LED_CTRL_KICK(mphy->leds.pin);
105cbb3ec25SBjoern A. Zeeb if (mphy->leds.al)
106cbb3ec25SBjoern 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
mt76x02_led_set_blink(struct led_classdev * led_cdev,unsigned long * delay_on,unsigned long * delay_off)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 {
115cbb3ec25SBjoern A. Zeeb struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy,
116cbb3ec25SBjoern 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
122cbb3ec25SBjoern 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
mt76x02_led_set_brightness(struct led_classdev * led_cdev,enum led_brightness brightness)1286c92544dSBjoern A. Zeeb mt76x02_led_set_brightness(struct led_classdev *led_cdev,
1296c92544dSBjoern A. Zeeb enum led_brightness brightness)
1306c92544dSBjoern A. Zeeb {
131cbb3ec25SBjoern A. Zeeb struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy,
132cbb3ec25SBjoern A. Zeeb leds.cdev);
1336c92544dSBjoern A. Zeeb
1346c92544dSBjoern A. Zeeb if (!brightness)
135cbb3ec25SBjoern A. Zeeb mt76x02_led_set_config(mphy, 0, 0xff);
1366c92544dSBjoern A. Zeeb else
137cbb3ec25SBjoern A. Zeeb mt76x02_led_set_config(mphy, 0xff, 0);
1386c92544dSBjoern A. Zeeb }
1396c92544dSBjoern A. Zeeb
mt76x02_init_device(struct mt76x02_dev * dev)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)) {
169cbb3ec25SBjoern A. Zeeb dev->mphy.leds.cdev.brightness_set =
1706c92544dSBjoern A. Zeeb mt76x02_led_set_brightness;
171cbb3ec25SBjoern 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
mt76x02_configure_filter(struct ieee80211_hw * hw,unsigned int changed_flags,unsigned int * total_flags,u64 multicast)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
mt76x02_sta_add(struct mt76_dev * mdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)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
mt76x02_sta_remove(struct mt76_dev * mdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)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
mt76x02_vif_init(struct mt76x02_dev * dev,struct ieee80211_vif * vif,unsigned int idx)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);
290*8ba4d145SBjoern A. Zeeb mt76_wcid_init(&mvif->group_wcid, 0);
2916c92544dSBjoern A. Zeeb
2926c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)vif->txq->drv_priv;
2936c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->mt76.wcid[MT_VIF_WCID(idx)], &mvif->group_wcid);
2946c92544dSBjoern A. Zeeb mtxq->wcid = MT_VIF_WCID(idx);
2956c92544dSBjoern A. Zeeb }
2966c92544dSBjoern A. Zeeb
2976c92544dSBjoern A. Zeeb int
mt76x02_add_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)2986c92544dSBjoern A. Zeeb mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
2996c92544dSBjoern A. Zeeb {
3006c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
3016c92544dSBjoern A. Zeeb unsigned int idx = 0;
3026c92544dSBjoern A. Zeeb
3036c92544dSBjoern A. Zeeb /* Allow to change address in HW if we create first interface. */
3046c92544dSBjoern A. Zeeb if (!dev->mt76.vif_mask &&
3056c92544dSBjoern A. Zeeb (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) ||
3066c92544dSBjoern A. Zeeb memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1)))
3076c92544dSBjoern A. Zeeb mt76x02_mac_setaddr(dev, vif->addr);
3086c92544dSBjoern A. Zeeb
3096c92544dSBjoern A. Zeeb if (vif->addr[0] & BIT(1))
3106c92544dSBjoern A. Zeeb idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
3116c92544dSBjoern A. Zeeb
3126c92544dSBjoern A. Zeeb /*
3136c92544dSBjoern A. Zeeb * Client mode typically only has one configurable BSSID register,
3146c92544dSBjoern A. Zeeb * which is used for bssidx=0. This is linked to the MAC address.
3156c92544dSBjoern A. Zeeb * Since mac80211 allows changing interface types, and we cannot
3166c92544dSBjoern A. Zeeb * force the use of the primary MAC address for a station mode
3176c92544dSBjoern A. Zeeb * interface, we need some other way of configuring a per-interface
3186c92544dSBjoern A. Zeeb * remote BSSID.
3196c92544dSBjoern A. Zeeb * The hardware provides an AP-Client feature, where bssidx 0-7 are
3206c92544dSBjoern A. Zeeb * used for AP mode and bssidx 8-15 for client mode.
3216c92544dSBjoern A. Zeeb * We shift the station interface bss index by 8 to force the
3226c92544dSBjoern A. Zeeb * hardware to recognize the BSSID.
3236c92544dSBjoern A. Zeeb * The resulting bssidx mismatch for unicast frames is ignored by hw.
3246c92544dSBjoern A. Zeeb */
3256c92544dSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION)
3266c92544dSBjoern A. Zeeb idx += 8;
3276c92544dSBjoern A. Zeeb
3286c92544dSBjoern A. Zeeb /* vif is already set or idx is 8 for AP/Mesh/... */
3296c92544dSBjoern A. Zeeb if (dev->mt76.vif_mask & BIT_ULL(idx) ||
3306c92544dSBjoern A. Zeeb (vif->type != NL80211_IFTYPE_STATION && idx > 7))
3316c92544dSBjoern A. Zeeb return -EBUSY;
3326c92544dSBjoern A. Zeeb
3336c92544dSBjoern A. Zeeb dev->mt76.vif_mask |= BIT_ULL(idx);
3346c92544dSBjoern A. Zeeb
3356c92544dSBjoern A. Zeeb mt76x02_vif_init(dev, vif, idx);
3366c92544dSBjoern A. Zeeb return 0;
3376c92544dSBjoern A. Zeeb }
3386c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_add_interface);
3396c92544dSBjoern A. Zeeb
mt76x02_remove_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)3406c92544dSBjoern A. Zeeb void mt76x02_remove_interface(struct ieee80211_hw *hw,
3416c92544dSBjoern A. Zeeb struct ieee80211_vif *vif)
3426c92544dSBjoern A. Zeeb {
3436c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
3446c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
3456c92544dSBjoern A. Zeeb
3466c92544dSBjoern A. Zeeb dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx);
3476c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->mt76.wcid[mvif->group_wcid.idx], NULL);
348*8ba4d145SBjoern A. Zeeb mt76_wcid_cleanup(&dev->mt76, &mvif->group_wcid);
3496c92544dSBjoern A. Zeeb }
3506c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_remove_interface);
3516c92544dSBjoern A. Zeeb
mt76x02_ampdu_action(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_ampdu_params * params)3526c92544dSBjoern A. Zeeb int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
3536c92544dSBjoern A. Zeeb struct ieee80211_ampdu_params *params)
3546c92544dSBjoern A. Zeeb {
3556c92544dSBjoern A. Zeeb enum ieee80211_ampdu_mlme_action action = params->action;
3566c92544dSBjoern A. Zeeb struct ieee80211_sta *sta = params->sta;
3576c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
3586c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
3596c92544dSBjoern A. Zeeb struct ieee80211_txq *txq = sta->txq[params->tid];
3606c92544dSBjoern A. Zeeb u16 tid = params->tid;
3616c92544dSBjoern A. Zeeb u16 ssn = params->ssn;
3626c92544dSBjoern A. Zeeb struct mt76_txq *mtxq;
3636c92544dSBjoern A. Zeeb int ret = 0;
3646c92544dSBjoern A. Zeeb
3656c92544dSBjoern A. Zeeb if (!txq)
3666c92544dSBjoern A. Zeeb return -EINVAL;
3676c92544dSBjoern A. Zeeb
3686c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)txq->drv_priv;
3696c92544dSBjoern A. Zeeb
3706c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex);
3716c92544dSBjoern A. Zeeb switch (action) {
3726c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_RX_START:
3736c92544dSBjoern A. Zeeb mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid,
3746c92544dSBjoern A. Zeeb ssn, params->buf_size);
3756c92544dSBjoern A. Zeeb mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
3766c92544dSBjoern A. Zeeb break;
3776c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_RX_STOP:
3786c92544dSBjoern A. Zeeb mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
3796c92544dSBjoern A. Zeeb mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
3806c92544dSBjoern A. Zeeb BIT(16 + tid));
3816c92544dSBjoern A. Zeeb break;
3826c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_OPERATIONAL:
3836c92544dSBjoern A. Zeeb mtxq->aggr = true;
3846c92544dSBjoern A. Zeeb mtxq->send_bar = false;
3856c92544dSBjoern A. Zeeb ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
3866c92544dSBjoern A. Zeeb break;
3876c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH:
3886c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
3896c92544dSBjoern A. Zeeb mtxq->aggr = false;
3906c92544dSBjoern A. Zeeb break;
3916c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_START:
3926c92544dSBjoern A. Zeeb mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
3936c92544dSBjoern A. Zeeb ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
3946c92544dSBjoern A. Zeeb break;
3956c92544dSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_CONT:
3966c92544dSBjoern A. Zeeb mtxq->aggr = false;
3976c92544dSBjoern A. Zeeb ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
3986c92544dSBjoern A. Zeeb break;
3996c92544dSBjoern A. Zeeb }
4006c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex);
4016c92544dSBjoern A. Zeeb
4026c92544dSBjoern A. Zeeb return ret;
4036c92544dSBjoern A. Zeeb }
4046c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_ampdu_action);
4056c92544dSBjoern A. Zeeb
mt76x02_set_key(struct ieee80211_hw * hw,enum set_key_cmd cmd,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)4066c92544dSBjoern A. Zeeb int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
4076c92544dSBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta,
4086c92544dSBjoern A. Zeeb struct ieee80211_key_conf *key)
4096c92544dSBjoern A. Zeeb {
4106c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
4116c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
4126c92544dSBjoern A. Zeeb struct mt76x02_sta *msta;
4136c92544dSBjoern A. Zeeb struct mt76_wcid *wcid;
4146c92544dSBjoern A. Zeeb int idx = key->keyidx;
4156c92544dSBjoern A. Zeeb int ret;
4166c92544dSBjoern A. Zeeb
4176c92544dSBjoern A. Zeeb /* fall back to sw encryption for unsupported ciphers */
4186c92544dSBjoern A. Zeeb switch (key->cipher) {
4196c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP40:
4206c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP104:
4216c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_TKIP:
4226c92544dSBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP:
4236c92544dSBjoern A. Zeeb break;
4246c92544dSBjoern A. Zeeb default:
4256c92544dSBjoern A. Zeeb return -EOPNOTSUPP;
4266c92544dSBjoern A. Zeeb }
4276c92544dSBjoern A. Zeeb
4286c92544dSBjoern A. Zeeb /*
4296c92544dSBjoern A. Zeeb * The hardware does not support per-STA RX GTK, fall back
4306c92544dSBjoern A. Zeeb * to software mode for these.
4316c92544dSBjoern A. Zeeb */
4326c92544dSBjoern A. Zeeb if ((vif->type == NL80211_IFTYPE_ADHOC ||
4336c92544dSBjoern A. Zeeb vif->type == NL80211_IFTYPE_MESH_POINT) &&
4346c92544dSBjoern A. Zeeb (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
4356c92544dSBjoern A. Zeeb key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
4366c92544dSBjoern A. Zeeb !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
4376c92544dSBjoern A. Zeeb return -EOPNOTSUPP;
4386c92544dSBjoern A. Zeeb
4396c92544dSBjoern A. Zeeb /*
4406c92544dSBjoern A. Zeeb * In USB AP mode, broadcast/multicast frames are setup in beacon
4416c92544dSBjoern A. Zeeb * data registers and sent via HW beacons engine, they require to
4426c92544dSBjoern A. Zeeb * be already encrypted.
4436c92544dSBjoern A. Zeeb */
4446c92544dSBjoern A. Zeeb if (mt76_is_usb(&dev->mt76) &&
4456c92544dSBjoern A. Zeeb vif->type == NL80211_IFTYPE_AP &&
4466c92544dSBjoern A. Zeeb !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
4476c92544dSBjoern A. Zeeb return -EOPNOTSUPP;
4486c92544dSBjoern A. Zeeb
4496c92544dSBjoern A. Zeeb /* MT76x0 GTK offloading does not work with more than one VIF */
4506c92544dSBjoern A. Zeeb if (is_mt76x0(dev) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
4516c92544dSBjoern A. Zeeb return -EOPNOTSUPP;
4526c92544dSBjoern A. Zeeb
4536c92544dSBjoern A. Zeeb msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL;
4546c92544dSBjoern A. Zeeb wcid = msta ? &msta->wcid : &mvif->group_wcid;
4556c92544dSBjoern A. Zeeb
456cbb3ec25SBjoern A. Zeeb if (cmd != SET_KEY) {
4576c92544dSBjoern A. Zeeb if (idx == wcid->hw_key_idx) {
4586c92544dSBjoern A. Zeeb wcid->hw_key_idx = -1;
4596c92544dSBjoern A. Zeeb wcid->sw_iv = false;
4606c92544dSBjoern A. Zeeb }
4616c92544dSBjoern A. Zeeb
462cbb3ec25SBjoern A. Zeeb return 0;
463cbb3ec25SBjoern A. Zeeb }
464cbb3ec25SBjoern A. Zeeb
465cbb3ec25SBjoern A. Zeeb key->hw_key_idx = wcid->idx;
466cbb3ec25SBjoern A. Zeeb wcid->hw_key_idx = idx;
467cbb3ec25SBjoern A. Zeeb if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
468cbb3ec25SBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
469cbb3ec25SBjoern A. Zeeb wcid->sw_iv = true;
4706c92544dSBjoern A. Zeeb }
4716c92544dSBjoern A. Zeeb mt76_wcid_key_setup(&dev->mt76, wcid, key);
4726c92544dSBjoern A. Zeeb
4736c92544dSBjoern A. Zeeb if (!msta) {
4746c92544dSBjoern A. Zeeb if (key || wcid->hw_key_idx == idx) {
4756c92544dSBjoern A. Zeeb ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key);
4766c92544dSBjoern A. Zeeb if (ret)
4776c92544dSBjoern A. Zeeb return ret;
4786c92544dSBjoern A. Zeeb }
4796c92544dSBjoern A. Zeeb
4806c92544dSBjoern A. Zeeb return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key);
4816c92544dSBjoern A. Zeeb }
4826c92544dSBjoern A. Zeeb
4836c92544dSBjoern A. Zeeb return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key);
4846c92544dSBjoern A. Zeeb }
4856c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_key);
4866c92544dSBjoern A. Zeeb
mt76x02_conf_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,unsigned int link_id,u16 queue,const struct ieee80211_tx_queue_params * params)4876c92544dSBjoern A. Zeeb int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
4886c92544dSBjoern A. Zeeb unsigned int link_id, u16 queue,
4896c92544dSBjoern A. Zeeb const struct ieee80211_tx_queue_params *params)
4906c92544dSBjoern A. Zeeb {
4916c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
4926c92544dSBjoern A. Zeeb u8 cw_min = 5, cw_max = 10, qid;
4936c92544dSBjoern A. Zeeb u32 val;
4946c92544dSBjoern A. Zeeb
4956c92544dSBjoern A. Zeeb qid = dev->mphy.q_tx[queue]->hw_idx;
4966c92544dSBjoern A. Zeeb
4976c92544dSBjoern A. Zeeb if (params->cw_min)
4986c92544dSBjoern A. Zeeb cw_min = fls(params->cw_min);
4996c92544dSBjoern A. Zeeb if (params->cw_max)
5006c92544dSBjoern A. Zeeb cw_max = fls(params->cw_max);
5016c92544dSBjoern A. Zeeb
5026c92544dSBjoern A. Zeeb val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) |
5036c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
5046c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
5056c92544dSBjoern A. Zeeb FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
5066c92544dSBjoern A. Zeeb mt76_wr(dev, MT_EDCA_CFG_AC(qid), val);
5076c92544dSBjoern A. Zeeb
5086c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_TXOP(qid));
5096c92544dSBjoern A. Zeeb val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
5106c92544dSBjoern A. Zeeb val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
5116c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_TXOP(qid), val);
5126c92544dSBjoern A. Zeeb
5136c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_AIFSN);
5146c92544dSBjoern A. Zeeb val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
5156c92544dSBjoern A. Zeeb val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
5166c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_AIFSN, val);
5176c92544dSBjoern A. Zeeb
5186c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_CWMIN);
5196c92544dSBjoern A. Zeeb val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
5206c92544dSBjoern A. Zeeb val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
5216c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_CWMIN, val);
5226c92544dSBjoern A. Zeeb
5236c92544dSBjoern A. Zeeb val = mt76_rr(dev, MT_WMM_CWMAX);
5246c92544dSBjoern A. Zeeb val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
5256c92544dSBjoern A. Zeeb val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
5266c92544dSBjoern A. Zeeb mt76_wr(dev, MT_WMM_CWMAX, val);
5276c92544dSBjoern A. Zeeb
5286c92544dSBjoern A. Zeeb return 0;
5296c92544dSBjoern A. Zeeb }
5306c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_conf_tx);
5316c92544dSBjoern A. Zeeb
mt76x02_set_tx_ackto(struct mt76x02_dev * dev)5326c92544dSBjoern A. Zeeb void mt76x02_set_tx_ackto(struct mt76x02_dev *dev)
5336c92544dSBjoern A. Zeeb {
5346c92544dSBjoern A. Zeeb u8 ackto, sifs, slottime = dev->slottime;
5356c92544dSBjoern A. Zeeb
5366c92544dSBjoern A. Zeeb /* As defined by IEEE 802.11-2007 17.3.8.6 */
5376c92544dSBjoern A. Zeeb slottime += 3 * dev->coverage_class;
5386c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG,
5396c92544dSBjoern A. Zeeb MT_BKOFF_SLOT_CFG_SLOTTIME, slottime);
5406c92544dSBjoern A. Zeeb
5416c92544dSBjoern A. Zeeb sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG,
5426c92544dSBjoern A. Zeeb MT_XIFS_TIME_CFG_OFDM_SIFS);
5436c92544dSBjoern A. Zeeb
5446c92544dSBjoern A. Zeeb ackto = slottime + sifs;
5456c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG,
5466c92544dSBjoern A. Zeeb MT_TX_TIMEOUT_CFG_ACKTO, ackto);
5476c92544dSBjoern A. Zeeb }
5486c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto);
5496c92544dSBjoern A. Zeeb
mt76x02_set_coverage_class(struct ieee80211_hw * hw,s16 coverage_class)5506c92544dSBjoern A. Zeeb void mt76x02_set_coverage_class(struct ieee80211_hw *hw,
5516c92544dSBjoern A. Zeeb s16 coverage_class)
5526c92544dSBjoern A. Zeeb {
5536c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
5546c92544dSBjoern A. Zeeb
5556c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex);
5566c92544dSBjoern A. Zeeb dev->coverage_class = max_t(s16, coverage_class, 0);
5576c92544dSBjoern A. Zeeb mt76x02_set_tx_ackto(dev);
5586c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex);
5596c92544dSBjoern A. Zeeb }
5606c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class);
5616c92544dSBjoern A. Zeeb
mt76x02_set_rts_threshold(struct ieee80211_hw * hw,u32 val)5626c92544dSBjoern A. Zeeb int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
5636c92544dSBjoern A. Zeeb {
5646c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
5656c92544dSBjoern A. Zeeb
5666c92544dSBjoern A. Zeeb if (val != ~0 && val > 0xffff)
5676c92544dSBjoern A. Zeeb return -EINVAL;
5686c92544dSBjoern A. Zeeb
5696c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex);
5706c92544dSBjoern A. Zeeb mt76x02_mac_set_rts_thresh(dev, val);
5716c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex);
5726c92544dSBjoern A. Zeeb
5736c92544dSBjoern A. Zeeb return 0;
5746c92544dSBjoern A. Zeeb }
5756c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_set_rts_threshold);
5766c92544dSBjoern A. Zeeb
mt76x02_sta_rate_tbl_update(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)5776c92544dSBjoern A. Zeeb void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
5786c92544dSBjoern A. Zeeb struct ieee80211_vif *vif,
5796c92544dSBjoern A. Zeeb struct ieee80211_sta *sta)
5806c92544dSBjoern A. Zeeb {
5816c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
5826c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
5836c92544dSBjoern A. Zeeb struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates);
5846c92544dSBjoern A. Zeeb struct ieee80211_tx_rate rate = {};
5856c92544dSBjoern A. Zeeb
5866c92544dSBjoern A. Zeeb if (!rates)
5876c92544dSBjoern A. Zeeb return;
5886c92544dSBjoern A. Zeeb
5896c92544dSBjoern A. Zeeb rate.idx = rates->rate[0].idx;
5906c92544dSBjoern A. Zeeb rate.flags = rates->rate[0].flags;
5916c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate);
5926c92544dSBjoern A. Zeeb }
5936c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update);
5946c92544dSBjoern A. Zeeb
mt76x02_remove_hdr_pad(struct sk_buff * skb,int len)5956c92544dSBjoern A. Zeeb void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len)
5966c92544dSBjoern A. Zeeb {
5976c92544dSBjoern A. Zeeb int hdrlen;
5986c92544dSBjoern A. Zeeb
5996c92544dSBjoern A. Zeeb if (!len)
6006c92544dSBjoern A. Zeeb return;
6016c92544dSBjoern A. Zeeb
6026c92544dSBjoern A. Zeeb hdrlen = ieee80211_get_hdrlen_from_skb(skb);
6036c92544dSBjoern A. Zeeb memmove(skb->data + len, skb->data, hdrlen);
6046c92544dSBjoern A. Zeeb skb_pull(skb, len);
6056c92544dSBjoern A. Zeeb }
6066c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad);
6076c92544dSBjoern A. Zeeb
mt76x02_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)6086c92544dSBjoern A. Zeeb void mt76x02_sw_scan_complete(struct ieee80211_hw *hw,
6096c92544dSBjoern A. Zeeb struct ieee80211_vif *vif)
6106c92544dSBjoern A. Zeeb {
6116c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
6126c92544dSBjoern A. Zeeb
6136c92544dSBjoern A. Zeeb clear_bit(MT76_SCANNING, &dev->mphy.state);
6146c92544dSBjoern A. Zeeb if (dev->cal.gain_init_done) {
6156c92544dSBjoern A. Zeeb /* Restore AGC gain and resume calibration after scanning. */
6166c92544dSBjoern A. Zeeb dev->cal.low_gain = -1;
6176c92544dSBjoern A. Zeeb ieee80211_queue_delayed_work(hw, &dev->cal_work, 0);
6186c92544dSBjoern A. Zeeb }
6196c92544dSBjoern A. Zeeb }
6206c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete);
6216c92544dSBjoern A. Zeeb
mt76x02_sta_ps(struct mt76_dev * mdev,struct ieee80211_sta * sta,bool ps)6226c92544dSBjoern A. Zeeb void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
6236c92544dSBjoern A. Zeeb bool ps)
6246c92544dSBjoern A. Zeeb {
6256c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
6266c92544dSBjoern A. Zeeb struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
6276c92544dSBjoern A. Zeeb int idx = msta->wcid.idx;
6286c92544dSBjoern A. Zeeb
6296c92544dSBjoern A. Zeeb mt76_stop_tx_queues(&dev->mphy, sta, true);
6306c92544dSBjoern A. Zeeb if (mt76_is_mmio(mdev))
6316c92544dSBjoern A. Zeeb mt76x02_mac_wcid_set_drop(dev, idx, ps);
6326c92544dSBjoern A. Zeeb }
6336c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_sta_ps);
6346c92544dSBjoern A. Zeeb
mt76x02_bss_info_changed(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * info,u64 changed)6356c92544dSBjoern A. Zeeb void mt76x02_bss_info_changed(struct ieee80211_hw *hw,
6366c92544dSBjoern A. Zeeb struct ieee80211_vif *vif,
6376c92544dSBjoern A. Zeeb struct ieee80211_bss_conf *info,
6386c92544dSBjoern A. Zeeb u64 changed)
6396c92544dSBjoern A. Zeeb {
6406c92544dSBjoern A. Zeeb struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
6416c92544dSBjoern A. Zeeb struct mt76x02_dev *dev = hw->priv;
6426c92544dSBjoern A. Zeeb
6436c92544dSBjoern A. Zeeb mutex_lock(&dev->mt76.mutex);
6446c92544dSBjoern A. Zeeb
6456c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BSSID)
6466c92544dSBjoern A. Zeeb mt76x02_mac_set_bssid(dev, mvif->idx, info->bssid);
6476c92544dSBjoern A. Zeeb
6486c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
6496c92544dSBjoern A. Zeeb mt76x02_mac_set_tx_protection(dev, info->use_cts_prot,
6506c92544dSBjoern A. Zeeb info->ht_operation_mode);
6516c92544dSBjoern A. Zeeb
6526c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_INT) {
6536c92544dSBjoern A. Zeeb mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
6546c92544dSBjoern A. Zeeb MT_BEACON_TIME_CFG_INTVAL,
6556c92544dSBjoern A. Zeeb info->beacon_int << 4);
6566c92544dSBjoern A. Zeeb dev->mt76.beacon_int = info->beacon_int;
6576c92544dSBjoern A. Zeeb }
6586c92544dSBjoern A. Zeeb
6596c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_ENABLED)
6606c92544dSBjoern A. Zeeb mt76x02_mac_set_beacon_enable(dev, vif, info->enable_beacon);
6616c92544dSBjoern A. Zeeb
6626c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_PREAMBLE)
6636c92544dSBjoern A. Zeeb mt76x02_mac_set_short_preamble(dev, info->use_short_preamble);
6646c92544dSBjoern A. Zeeb
6656c92544dSBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_SLOT) {
6666c92544dSBjoern A. Zeeb int slottime = info->use_short_slot ? 9 : 20;
6676c92544dSBjoern A. Zeeb
6686c92544dSBjoern A. Zeeb dev->slottime = slottime;
6696c92544dSBjoern A. Zeeb mt76x02_set_tx_ackto(dev);
6706c92544dSBjoern A. Zeeb }
6716c92544dSBjoern A. Zeeb
6726c92544dSBjoern A. Zeeb mutex_unlock(&dev->mt76.mutex);
6736c92544dSBjoern A. Zeeb }
6746c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_bss_info_changed);
6756c92544dSBjoern A. Zeeb
mt76x02_config_mac_addr_list(struct mt76x02_dev * dev)6766c92544dSBjoern A. Zeeb void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev)
6776c92544dSBjoern A. Zeeb {
6786c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = mt76_hw(dev);
6796c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy;
6806c92544dSBjoern A. Zeeb int i;
6816c92544dSBjoern A. Zeeb
6826c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) {
6836c92544dSBjoern A. Zeeb u8 *addr = dev->macaddr_list[i].addr;
6846c92544dSBjoern A. Zeeb
6856c92544dSBjoern A. Zeeb memcpy(addr, dev->mphy.macaddr, ETH_ALEN);
6866c92544dSBjoern A. Zeeb
6876c92544dSBjoern A. Zeeb if (!i)
6886c92544dSBjoern A. Zeeb continue;
6896c92544dSBjoern A. Zeeb
6906c92544dSBjoern A. Zeeb addr[0] |= BIT(1);
6916c92544dSBjoern A. Zeeb addr[0] ^= ((i - 1) << 2);
6926c92544dSBjoern A. Zeeb }
6936c92544dSBjoern A. Zeeb wiphy->addresses = dev->macaddr_list;
6946c92544dSBjoern A. Zeeb wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list);
6956c92544dSBjoern A. Zeeb }
6966c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list);
6976c92544dSBjoern A. Zeeb
698*8ba4d145SBjoern A. Zeeb MODULE_DESCRIPTION("MediaTek MT76x02 helpers");
6996c92544dSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
700