xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt76x02_util.c (revision 8ba4d145d351db26e07695b8e90697398c5dfec2)
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