10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
2108a4861SStanislaw Gruszka /*
3108a4861SStanislaw Gruszka * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
4108a4861SStanislaw Gruszka * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
5108a4861SStanislaw Gruszka */
6108a4861SStanislaw Gruszka
7db6bb5c6SFelix Fietkau #include <linux/module.h>
87a07adcdSLorenzo Bianconi #include "mt76x02.h"
9108a4861SStanislaw Gruszka
1054b8fdebSLorenzo Bianconi #define MT76x02_CCK_RATE(_idx, _rate) { \
1158b5eb8cSLorenzo Bianconi .bitrate = _rate, \
1258b5eb8cSLorenzo Bianconi .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
13ff97c52aSRyder Lee .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
14ff97c52aSRyder Lee .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \
1558b5eb8cSLorenzo Bianconi }
1658b5eb8cSLorenzo Bianconi
1758b5eb8cSLorenzo Bianconi struct ieee80211_rate mt76x02_rates[] = {
1854b8fdebSLorenzo Bianconi MT76x02_CCK_RATE(0, 10),
1954b8fdebSLorenzo Bianconi MT76x02_CCK_RATE(1, 20),
2054b8fdebSLorenzo Bianconi MT76x02_CCK_RATE(2, 55),
2154b8fdebSLorenzo Bianconi MT76x02_CCK_RATE(3, 110),
2258b5eb8cSLorenzo Bianconi OFDM_RATE(0, 60),
2358b5eb8cSLorenzo Bianconi OFDM_RATE(1, 90),
2458b5eb8cSLorenzo Bianconi OFDM_RATE(2, 120),
2558b5eb8cSLorenzo Bianconi OFDM_RATE(3, 180),
2658b5eb8cSLorenzo Bianconi OFDM_RATE(4, 240),
2758b5eb8cSLorenzo Bianconi OFDM_RATE(5, 360),
2858b5eb8cSLorenzo Bianconi OFDM_RATE(6, 480),
2958b5eb8cSLorenzo Bianconi OFDM_RATE(7, 540),
3058b5eb8cSLorenzo Bianconi };
3158b5eb8cSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_rates);
3258b5eb8cSLorenzo Bianconi
335cbace02SLorenzo Bianconi static const struct ieee80211_iface_limit mt76x02_if_limits[] = {
345cbace02SLorenzo Bianconi {
355cbace02SLorenzo Bianconi .max = 1,
365cbace02SLorenzo Bianconi .types = BIT(NL80211_IFTYPE_ADHOC)
375cbace02SLorenzo Bianconi }, {
385cbace02SLorenzo Bianconi .max = 8,
395cbace02SLorenzo Bianconi .types = BIT(NL80211_IFTYPE_STATION) |
405cbace02SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
415cbace02SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) |
425cbace02SLorenzo Bianconi #endif
4350eb0a88SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) |
4450eb0a88SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) |
455cbace02SLorenzo Bianconi BIT(NL80211_IFTYPE_AP)
465cbace02SLorenzo Bianconi },
475cbace02SLorenzo Bianconi };
485cbace02SLorenzo Bianconi
49f110d1d5SLorenzo Bianconi static const struct ieee80211_iface_limit mt76x02u_if_limits[] = {
50f110d1d5SLorenzo Bianconi {
51f110d1d5SLorenzo Bianconi .max = 1,
52f110d1d5SLorenzo Bianconi .types = BIT(NL80211_IFTYPE_ADHOC)
53f110d1d5SLorenzo Bianconi }, {
54f110d1d5SLorenzo Bianconi .max = 2,
55f110d1d5SLorenzo Bianconi .types = BIT(NL80211_IFTYPE_STATION) |
56f110d1d5SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
57f110d1d5SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) |
58f110d1d5SLorenzo Bianconi #endif
5950eb0a88SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) |
6050eb0a88SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) |
61f110d1d5SLorenzo Bianconi BIT(NL80211_IFTYPE_AP)
62f110d1d5SLorenzo Bianconi },
63f110d1d5SLorenzo Bianconi };
64f110d1d5SLorenzo Bianconi
655cbace02SLorenzo Bianconi static const struct ieee80211_iface_combination mt76x02_if_comb[] = {
665cbace02SLorenzo Bianconi {
675cbace02SLorenzo Bianconi .limits = mt76x02_if_limits,
685cbace02SLorenzo Bianconi .n_limits = ARRAY_SIZE(mt76x02_if_limits),
695cbace02SLorenzo Bianconi .max_interfaces = 8,
705cbace02SLorenzo Bianconi .num_different_channels = 1,
715cbace02SLorenzo Bianconi .beacon_int_infra_match = true,
725cbace02SLorenzo Bianconi .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
735cbace02SLorenzo Bianconi BIT(NL80211_CHAN_WIDTH_20) |
745cbace02SLorenzo Bianconi BIT(NL80211_CHAN_WIDTH_40) |
755cbace02SLorenzo Bianconi BIT(NL80211_CHAN_WIDTH_80),
765cbace02SLorenzo Bianconi }
775cbace02SLorenzo Bianconi };
785cbace02SLorenzo Bianconi
79f110d1d5SLorenzo Bianconi static const struct ieee80211_iface_combination mt76x02u_if_comb[] = {
80f110d1d5SLorenzo Bianconi {
81f110d1d5SLorenzo Bianconi .limits = mt76x02u_if_limits,
82f110d1d5SLorenzo Bianconi .n_limits = ARRAY_SIZE(mt76x02u_if_limits),
83f110d1d5SLorenzo Bianconi .max_interfaces = 2,
84f110d1d5SLorenzo Bianconi .num_different_channels = 1,
85f110d1d5SLorenzo Bianconi .beacon_int_infra_match = true,
86f110d1d5SLorenzo Bianconi }
87f110d1d5SLorenzo Bianconi };
88f110d1d5SLorenzo Bianconi
895c9decdfSLorenzo Bianconi static void
mt76x02_led_set_config(struct mt76_phy * mphy,u8 delay_on,u8 delay_off)903abd46ddSLorenzo Bianconi mt76x02_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off)
915c9decdfSLorenzo Bianconi {
923abd46ddSLorenzo Bianconi struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev,
935c9decdfSLorenzo Bianconi mt76);
945c9decdfSLorenzo Bianconi u32 val;
955c9decdfSLorenzo Bianconi
96d1ff4a3cSLorenzo Bianconi val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xff) |
97d1ff4a3cSLorenzo Bianconi FIELD_PREP(MT_LED_STATUS_OFF, delay_off) |
98d1ff4a3cSLorenzo Bianconi FIELD_PREP(MT_LED_STATUS_ON, delay_on);
995c9decdfSLorenzo Bianconi
1003abd46ddSLorenzo Bianconi mt76_wr(dev, MT_LED_S0(mphy->leds.pin), val);
1013abd46ddSLorenzo Bianconi mt76_wr(dev, MT_LED_S1(mphy->leds.pin), val);
1025c9decdfSLorenzo Bianconi
1033abd46ddSLorenzo Bianconi val = MT_LED_CTRL_REPLAY(mphy->leds.pin) |
1043abd46ddSLorenzo Bianconi MT_LED_CTRL_KICK(mphy->leds.pin);
1053abd46ddSLorenzo Bianconi if (mphy->leds.al)
1063abd46ddSLorenzo Bianconi val |= MT_LED_CTRL_POLARITY(mphy->leds.pin);
1075c9decdfSLorenzo Bianconi mt76_wr(dev, MT_LED_CTRL, val);
1085c9decdfSLorenzo Bianconi }
1095c9decdfSLorenzo Bianconi
1105c9decdfSLorenzo Bianconi static int
mt76x02_led_set_blink(struct led_classdev * led_cdev,unsigned long * delay_on,unsigned long * delay_off)1115c9decdfSLorenzo Bianconi mt76x02_led_set_blink(struct led_classdev *led_cdev,
1125c9decdfSLorenzo Bianconi unsigned long *delay_on,
1135c9decdfSLorenzo Bianconi unsigned long *delay_off)
1145c9decdfSLorenzo Bianconi {
1153abd46ddSLorenzo Bianconi struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy,
116a00b7910SLorenzo Bianconi leds.cdev);
1175c9decdfSLorenzo Bianconi u8 delta_on, delta_off;
1185c9decdfSLorenzo Bianconi
1195c9decdfSLorenzo Bianconi delta_off = max_t(u8, *delay_off / 10, 1);
1205c9decdfSLorenzo Bianconi delta_on = max_t(u8, *delay_on / 10, 1);
1215c9decdfSLorenzo Bianconi
1223abd46ddSLorenzo Bianconi mt76x02_led_set_config(mphy, delta_on, delta_off);
1235c9decdfSLorenzo Bianconi
1245c9decdfSLorenzo Bianconi return 0;
1255c9decdfSLorenzo Bianconi }
1265c9decdfSLorenzo Bianconi
1275c9decdfSLorenzo Bianconi static void
mt76x02_led_set_brightness(struct led_classdev * led_cdev,enum led_brightness brightness)1285c9decdfSLorenzo Bianconi mt76x02_led_set_brightness(struct led_classdev *led_cdev,
1295c9decdfSLorenzo Bianconi enum led_brightness brightness)
1305c9decdfSLorenzo Bianconi {
1313abd46ddSLorenzo Bianconi struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy,
132a00b7910SLorenzo Bianconi leds.cdev);
1335c9decdfSLorenzo Bianconi
1345c9decdfSLorenzo Bianconi if (!brightness)
1353abd46ddSLorenzo Bianconi mt76x02_led_set_config(mphy, 0, 0xff);
1365c9decdfSLorenzo Bianconi else
1373abd46ddSLorenzo Bianconi mt76x02_led_set_config(mphy, 0xff, 0);
1385c9decdfSLorenzo Bianconi }
1395c9decdfSLorenzo Bianconi
mt76x02_init_device(struct mt76x02_dev * dev)140633f77b5SLorenzo Bianconi int mt76x02_init_device(struct mt76x02_dev *dev)
1415cbace02SLorenzo Bianconi {
1425cbace02SLorenzo Bianconi struct ieee80211_hw *hw = mt76_hw(dev);
1435cbace02SLorenzo Bianconi struct wiphy *wiphy = hw->wiphy;
1445cbace02SLorenzo Bianconi
145a782f8bfSLorenzo Bianconi INIT_DELAYED_WORK(&dev->mphy.mac_work, mt76x02_mac_work);
1465cbace02SLorenzo Bianconi
1475cbace02SLorenzo Bianconi hw->queues = 4;
1485cbace02SLorenzo Bianconi hw->max_rates = 1;
1495cbace02SLorenzo Bianconi hw->max_report_rates = 7;
1505cbace02SLorenzo Bianconi hw->max_rate_tries = 1;
1515cbace02SLorenzo Bianconi hw->extra_tx_headroom = 2;
1525cbace02SLorenzo Bianconi
15361c51a74SLorenzo Bianconi if (mt76_is_usb(&dev->mt76)) {
1545cbace02SLorenzo Bianconi hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) +
1555cbace02SLorenzo Bianconi MT_DMA_HDR_LEN;
156f110d1d5SLorenzo Bianconi wiphy->iface_combinations = mt76x02u_if_comb;
157f110d1d5SLorenzo Bianconi wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02u_if_comb);
1585cbace02SLorenzo Bianconi } else {
159c1e0d2beSLorenzo Bianconi INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work);
160c1e0d2beSLorenzo Bianconi
161801ccc8aSLorenzo Bianconi mt76x02_dfs_init_detector(dev);
162801ccc8aSLorenzo Bianconi
163801ccc8aSLorenzo Bianconi wiphy->reg_notifier = mt76x02_regd_notifier;
1645cbace02SLorenzo Bianconi wiphy->iface_combinations = mt76x02_if_comb;
1655cbace02SLorenzo Bianconi wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb);
166e7173858SFelix Fietkau
1675c9decdfSLorenzo Bianconi /* init led callbacks */
1685c9decdfSLorenzo Bianconi if (IS_ENABLED(CONFIG_MT76_LEDS)) {
1693abd46ddSLorenzo Bianconi dev->mphy.leds.cdev.brightness_set =
1705c9decdfSLorenzo Bianconi mt76x02_led_set_brightness;
1713abd46ddSLorenzo Bianconi dev->mphy.leds.cdev.blink_set = mt76x02_led_set_blink;
1725c9decdfSLorenzo Bianconi }
1735cbace02SLorenzo Bianconi }
1745cbace02SLorenzo Bianconi
1752bd7f3d2SStanislaw Gruszka wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
1762bd7f3d2SStanislaw Gruszka
1775cbace02SLorenzo Bianconi hw->sta_data_size = sizeof(struct mt76x02_sta);
1785cbace02SLorenzo Bianconi hw->vif_data_size = sizeof(struct mt76x02_vif);
1795cbace02SLorenzo Bianconi
1805cbace02SLorenzo Bianconi ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
181e22d0b89SFelix Fietkau ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
1827af1ae62SFelix Fietkau ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
1835cbace02SLorenzo Bianconi
1845cbace02SLorenzo Bianconi dev->mt76.global_wcid.idx = 255;
1855cbace02SLorenzo Bianconi dev->mt76.global_wcid.hw_key_idx = -1;
1865cbace02SLorenzo Bianconi dev->slottime = 9;
1875cbace02SLorenzo Bianconi
1885cbace02SLorenzo Bianconi if (is_mt76x2(dev)) {
18996747a51SFelix Fietkau dev->mphy.sband_2g.sband.ht_cap.cap |=
1905cbace02SLorenzo Bianconi IEEE80211_HT_CAP_LDPC_CODING;
19196747a51SFelix Fietkau dev->mphy.sband_5g.sband.ht_cap.cap |=
1925cbace02SLorenzo Bianconi IEEE80211_HT_CAP_LDPC_CODING;
193b9027e08SLorenzo Bianconi dev->mphy.chainmask = 0x202;
194beaaeb6bSFelix Fietkau dev->mphy.antenna_mask = 3;
1955cbace02SLorenzo Bianconi } else {
196b9027e08SLorenzo Bianconi dev->mphy.chainmask = 0x101;
197beaaeb6bSFelix Fietkau dev->mphy.antenna_mask = 1;
1985cbace02SLorenzo Bianconi }
199633f77b5SLorenzo Bianconi
200633f77b5SLorenzo Bianconi return 0;
2015cbace02SLorenzo Bianconi }
2025cbace02SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_init_device);
2035cbace02SLorenzo Bianconi
mt76x02_configure_filter(struct ieee80211_hw * hw,unsigned int changed_flags,unsigned int * total_flags,u64 multicast)204108a4861SStanislaw Gruszka void mt76x02_configure_filter(struct ieee80211_hw *hw,
205108a4861SStanislaw Gruszka unsigned int changed_flags,
206108a4861SStanislaw Gruszka unsigned int *total_flags, u64 multicast)
207108a4861SStanislaw Gruszka {
208d87cf75fSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
209108a4861SStanislaw Gruszka u32 flags = 0;
210108a4861SStanislaw Gruszka
211108a4861SStanislaw Gruszka #define MT76_FILTER(_flag, _hw) do { \
212108a4861SStanislaw Gruszka flags |= *total_flags & FIF_##_flag; \
213d87cf75fSLorenzo Bianconi dev->mt76.rxfilter &= ~(_hw); \
214d87cf75fSLorenzo Bianconi dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \
215108a4861SStanislaw Gruszka } while (0)
216108a4861SStanislaw Gruszka
217d87cf75fSLorenzo Bianconi mutex_lock(&dev->mt76.mutex);
218108a4861SStanislaw Gruszka
219d87cf75fSLorenzo Bianconi dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
220108a4861SStanislaw Gruszka
221108a4861SStanislaw Gruszka MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
222108a4861SStanislaw Gruszka MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
223108a4861SStanislaw Gruszka MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
224108a4861SStanislaw Gruszka MT_RX_FILTR_CFG_CTS |
225108a4861SStanislaw Gruszka MT_RX_FILTR_CFG_CFEND |
226108a4861SStanislaw Gruszka MT_RX_FILTR_CFG_CFACK |
227108a4861SStanislaw Gruszka MT_RX_FILTR_CFG_BA |
228108a4861SStanislaw Gruszka MT_RX_FILTR_CFG_CTRL_RSV);
229108a4861SStanislaw Gruszka MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);
230108a4861SStanislaw Gruszka
231108a4861SStanislaw Gruszka *total_flags = flags;
232d87cf75fSLorenzo Bianconi mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
233108a4861SStanislaw Gruszka
234d87cf75fSLorenzo Bianconi mutex_unlock(&dev->mt76.mutex);
235108a4861SStanislaw Gruszka }
236108a4861SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_configure_filter);
237108a4861SStanislaw Gruszka
mt76x02_sta_add(struct mt76_dev * mdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)238e28487eaSFelix Fietkau int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
239624400e4SStanislaw Gruszka struct ieee80211_sta *sta)
240624400e4SStanislaw Gruszka {
241e28487eaSFelix Fietkau struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
242624400e4SStanislaw Gruszka struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
243624400e4SStanislaw Gruszka struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
244624400e4SStanislaw Gruszka int idx = 0;
245624400e4SStanislaw Gruszka
24600496042SFelix Fietkau memset(msta, 0, sizeof(*msta));
24700496042SFelix Fietkau
248238f5d6fSFelix Fietkau idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT76x02_N_WCIDS);
249e28487eaSFelix Fietkau if (idx < 0)
250e28487eaSFelix Fietkau return -ENOSPC;
251624400e4SStanislaw Gruszka
252624400e4SStanislaw Gruszka msta->vif = mvif;
253624400e4SStanislaw Gruszka msta->wcid.sta = 1;
254624400e4SStanislaw Gruszka msta->wcid.idx = idx;
255624400e4SStanislaw Gruszka msta->wcid.hw_key_idx = -1;
2568d66af49SLorenzo Bianconi mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
2578d66af49SLorenzo Bianconi mt76x02_mac_wcid_set_drop(dev, idx, false);
258355f8d00SFelix Fietkau ewma_pktlen_init(&msta->pktlen);
259624400e4SStanislaw Gruszka
260624400e4SStanislaw Gruszka if (vif->type == NL80211_IFTYPE_AP)
261624400e4SStanislaw Gruszka set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
262624400e4SStanislaw Gruszka
263e28487eaSFelix Fietkau return 0;
264624400e4SStanislaw Gruszka }
265624400e4SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_sta_add);
266624400e4SStanislaw Gruszka
mt76x02_sta_remove(struct mt76_dev * mdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)267e28487eaSFelix Fietkau void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
268624400e4SStanislaw Gruszka struct ieee80211_sta *sta)
269624400e4SStanislaw Gruszka {
270e28487eaSFelix Fietkau struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
271723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
272723b90dcSFelix Fietkau int idx = wcid->idx;
273624400e4SStanislaw Gruszka
2748d66af49SLorenzo Bianconi mt76x02_mac_wcid_set_drop(dev, idx, true);
2758d66af49SLorenzo Bianconi mt76x02_mac_wcid_setup(dev, idx, 0, NULL);
276624400e4SStanislaw Gruszka }
277624400e4SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_sta_remove);
278624400e4SStanislaw Gruszka
279f9a043c5SStanislaw Gruszka static void
mt76x02_vif_init(struct mt76x02_dev * dev,struct ieee80211_vif * vif,unsigned int idx)280f9a043c5SStanislaw Gruszka mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
281cab12953SStanislaw Gruszka unsigned int idx)
282cab12953SStanislaw Gruszka {
283cab12953SStanislaw Gruszka struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
28454f1bf8aSFelix Fietkau struct mt76_txq *mtxq;
285cab12953SStanislaw Gruszka
28600496042SFelix Fietkau memset(mvif, 0, sizeof(*mvif));
28700496042SFelix Fietkau
288cab12953SStanislaw Gruszka mvif->idx = idx;
289cab12953SStanislaw Gruszka mvif->group_wcid.idx = MT_VIF_WCID(idx);
290cab12953SStanislaw Gruszka mvif->group_wcid.hw_key_idx = -1;
291*d2defcddSFelix Fietkau mt76_wcid_init(&mvif->group_wcid);
292bd1e3e7bSLorenzo Bianconi
29354f1bf8aSFelix Fietkau mtxq = (struct mt76_txq *)vif->txq->drv_priv;
29451fb1278SFelix Fietkau rcu_assign_pointer(dev->mt76.wcid[MT_VIF_WCID(idx)], &mvif->group_wcid);
29551fb1278SFelix Fietkau mtxq->wcid = MT_VIF_WCID(idx);
296cab12953SStanislaw Gruszka }
297cab12953SStanislaw Gruszka
298212926ebSStanislaw Gruszka int
mt76x02_add_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)299212926ebSStanislaw Gruszka mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
300212926ebSStanislaw Gruszka {
301d87cf75fSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
302212926ebSStanislaw Gruszka unsigned int idx = 0;
303212926ebSStanislaw Gruszka
3043fd0824aSFelix Fietkau /* Allow to change address in HW if we create first interface. */
3052ab33b8dSFelix Fietkau if (!dev->mt76.vif_mask &&
30698df2baeSLorenzo Bianconi (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) ||
30798df2baeSLorenzo Bianconi memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1)))
3083fd0824aSFelix Fietkau mt76x02_mac_setaddr(dev, vif->addr);
3093fd0824aSFelix Fietkau
310212926ebSStanislaw Gruszka if (vif->addr[0] & BIT(1))
31198df2baeSLorenzo Bianconi idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
312212926ebSStanislaw Gruszka
313212926ebSStanislaw Gruszka /*
314212926ebSStanislaw Gruszka * Client mode typically only has one configurable BSSID register,
315212926ebSStanislaw Gruszka * which is used for bssidx=0. This is linked to the MAC address.
316212926ebSStanislaw Gruszka * Since mac80211 allows changing interface types, and we cannot
317212926ebSStanislaw Gruszka * force the use of the primary MAC address for a station mode
318212926ebSStanislaw Gruszka * interface, we need some other way of configuring a per-interface
319212926ebSStanislaw Gruszka * remote BSSID.
320212926ebSStanislaw Gruszka * The hardware provides an AP-Client feature, where bssidx 0-7 are
321212926ebSStanislaw Gruszka * used for AP mode and bssidx 8-15 for client mode.
322212926ebSStanislaw Gruszka * We shift the station interface bss index by 8 to force the
323212926ebSStanislaw Gruszka * hardware to recognize the BSSID.
324212926ebSStanislaw Gruszka * The resulting bssidx mismatch for unicast frames is ignored by hw.
325212926ebSStanislaw Gruszka */
326212926ebSStanislaw Gruszka if (vif->type == NL80211_IFTYPE_STATION)
327212926ebSStanislaw Gruszka idx += 8;
328212926ebSStanislaw Gruszka
3297d288640SMarkus Theil /* vif is already set or idx is 8 for AP/Mesh/... */
330b619e013SEvelyn Tsai if (dev->mt76.vif_mask & BIT_ULL(idx) ||
3317d288640SMarkus Theil (vif->type != NL80211_IFTYPE_STATION && idx > 7))
33206662264SStanislaw Gruszka return -EBUSY;
33306662264SStanislaw Gruszka
334b619e013SEvelyn Tsai dev->mt76.vif_mask |= BIT_ULL(idx);
33506662264SStanislaw Gruszka
336212926ebSStanislaw Gruszka mt76x02_vif_init(dev, vif, idx);
337212926ebSStanislaw Gruszka return 0;
338212926ebSStanislaw Gruszka }
339212926ebSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_add_interface);
340212926ebSStanislaw Gruszka
mt76x02_remove_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)3410cd47baeSStanislaw Gruszka void mt76x02_remove_interface(struct ieee80211_hw *hw,
3420cd47baeSStanislaw Gruszka struct ieee80211_vif *vif)
3430cd47baeSStanislaw Gruszka {
344d87cf75fSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
34506662264SStanislaw Gruszka struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
3460cd47baeSStanislaw Gruszka
347b619e013SEvelyn Tsai dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx);
34851fb1278SFelix Fietkau rcu_assign_pointer(dev->mt76.wcid[mvif->group_wcid.idx], NULL);
349*d2defcddSFelix Fietkau mt76_wcid_cleanup(&dev->mt76, &mvif->group_wcid);
3500cd47baeSStanislaw Gruszka }
3510cd47baeSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_remove_interface);
3520cd47baeSStanislaw Gruszka
mt76x02_ampdu_action(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_ampdu_params * params)35322c575c4SStanislaw Gruszka int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
35422c575c4SStanislaw Gruszka struct ieee80211_ampdu_params *params)
35522c575c4SStanislaw Gruszka {
35622c575c4SStanislaw Gruszka enum ieee80211_ampdu_mlme_action action = params->action;
35722c575c4SStanislaw Gruszka struct ieee80211_sta *sta = params->sta;
358d87cf75fSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
35922c575c4SStanislaw Gruszka struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
36022c575c4SStanislaw Gruszka struct ieee80211_txq *txq = sta->txq[params->tid];
36122c575c4SStanislaw Gruszka u16 tid = params->tid;
3625eedd2a5SStanislaw Gruszka u16 ssn = params->ssn;
36322c575c4SStanislaw Gruszka struct mt76_txq *mtxq;
36405d6c8cfSMarkus Theil int ret = 0;
36522c575c4SStanislaw Gruszka
36622c575c4SStanislaw Gruszka if (!txq)
36722c575c4SStanislaw Gruszka return -EINVAL;
36822c575c4SStanislaw Gruszka
36922c575c4SStanislaw Gruszka mtxq = (struct mt76_txq *)txq->drv_priv;
37022c575c4SStanislaw Gruszka
3711a817fa7SFelix Fietkau mutex_lock(&dev->mt76.mutex);
37222c575c4SStanislaw Gruszka switch (action) {
37322c575c4SStanislaw Gruszka case IEEE80211_AMPDU_RX_START:
374d87cf75fSLorenzo Bianconi mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid,
3755eedd2a5SStanislaw Gruszka ssn, params->buf_size);
376d87cf75fSLorenzo Bianconi mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
37722c575c4SStanislaw Gruszka break;
37822c575c4SStanislaw Gruszka case IEEE80211_AMPDU_RX_STOP:
379d87cf75fSLorenzo Bianconi mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
380d87cf75fSLorenzo Bianconi mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
381d87cf75fSLorenzo Bianconi BIT(16 + tid));
38222c575c4SStanislaw Gruszka break;
38322c575c4SStanislaw Gruszka case IEEE80211_AMPDU_TX_OPERATIONAL:
38422c575c4SStanislaw Gruszka mtxq->aggr = true;
38522c575c4SStanislaw Gruszka mtxq->send_bar = false;
38622c575c4SStanislaw Gruszka ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
38722c575c4SStanislaw Gruszka break;
38822c575c4SStanislaw Gruszka case IEEE80211_AMPDU_TX_STOP_FLUSH:
38922c575c4SStanislaw Gruszka case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
39022c575c4SStanislaw Gruszka mtxq->aggr = false;
39122c575c4SStanislaw Gruszka break;
39222c575c4SStanislaw Gruszka case IEEE80211_AMPDU_TX_START:
3935eedd2a5SStanislaw Gruszka mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
39405d6c8cfSMarkus Theil ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
39505d6c8cfSMarkus Theil break;
39622c575c4SStanislaw Gruszka case IEEE80211_AMPDU_TX_STOP_CONT:
39722c575c4SStanislaw Gruszka mtxq->aggr = false;
39822c575c4SStanislaw Gruszka ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
39922c575c4SStanislaw Gruszka break;
40022c575c4SStanislaw Gruszka }
4011a817fa7SFelix Fietkau mutex_unlock(&dev->mt76.mutex);
40222c575c4SStanislaw Gruszka
40305d6c8cfSMarkus Theil return ret;
40422c575c4SStanislaw Gruszka }
40522c575c4SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_ampdu_action);
40622c575c4SStanislaw Gruszka
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)40760c26859SStanislaw Gruszka int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
40860c26859SStanislaw Gruszka struct ieee80211_vif *vif, struct ieee80211_sta *sta,
40960c26859SStanislaw Gruszka struct ieee80211_key_conf *key)
41060c26859SStanislaw Gruszka {
411d87cf75fSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
41260c26859SStanislaw Gruszka struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
41360c26859SStanislaw Gruszka struct mt76x02_sta *msta;
41460c26859SStanislaw Gruszka struct mt76_wcid *wcid;
41560c26859SStanislaw Gruszka int idx = key->keyidx;
41660c26859SStanislaw Gruszka int ret;
41760c26859SStanislaw Gruszka
41860c26859SStanislaw Gruszka /* fall back to sw encryption for unsupported ciphers */
41960c26859SStanislaw Gruszka switch (key->cipher) {
42060c26859SStanislaw Gruszka case WLAN_CIPHER_SUITE_WEP40:
42160c26859SStanislaw Gruszka case WLAN_CIPHER_SUITE_WEP104:
42260c26859SStanislaw Gruszka case WLAN_CIPHER_SUITE_TKIP:
42360c26859SStanislaw Gruszka case WLAN_CIPHER_SUITE_CCMP:
42460c26859SStanislaw Gruszka break;
42560c26859SStanislaw Gruszka default:
42660c26859SStanislaw Gruszka return -EOPNOTSUPP;
42760c26859SStanislaw Gruszka }
42860c26859SStanislaw Gruszka
42960c26859SStanislaw Gruszka /*
43060c26859SStanislaw Gruszka * The hardware does not support per-STA RX GTK, fall back
43160c26859SStanislaw Gruszka * to software mode for these.
43260c26859SStanislaw Gruszka */
43360c26859SStanislaw Gruszka if ((vif->type == NL80211_IFTYPE_ADHOC ||
43460c26859SStanislaw Gruszka vif->type == NL80211_IFTYPE_MESH_POINT) &&
43560c26859SStanislaw Gruszka (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
43660c26859SStanislaw Gruszka key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
43760c26859SStanislaw Gruszka !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
43860c26859SStanislaw Gruszka return -EOPNOTSUPP;
43960c26859SStanislaw Gruszka
440b98558e2SStanislaw Gruszka /*
441b98558e2SStanislaw Gruszka * In USB AP mode, broadcast/multicast frames are setup in beacon
442b98558e2SStanislaw Gruszka * data registers and sent via HW beacons engine, they require to
443b98558e2SStanislaw Gruszka * be already encrypted.
444b98558e2SStanislaw Gruszka */
44561c51a74SLorenzo Bianconi if (mt76_is_usb(&dev->mt76) &&
446b98558e2SStanislaw Gruszka vif->type == NL80211_IFTYPE_AP &&
447b98558e2SStanislaw Gruszka !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
448b98558e2SStanislaw Gruszka return -EOPNOTSUPP;
449b98558e2SStanislaw Gruszka
4504b36cc6bSDavid Bauer /* MT76x0 GTK offloading does not work with more than one VIF */
4514b36cc6bSDavid Bauer if (is_mt76x0(dev) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
4524b36cc6bSDavid Bauer return -EOPNOTSUPP;
4534b36cc6bSDavid Bauer
45460c26859SStanislaw Gruszka msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL;
45560c26859SStanislaw Gruszka wcid = msta ? &msta->wcid : &mvif->group_wcid;
45660c26859SStanislaw Gruszka
457e6db67faSFelix Fietkau if (cmd != SET_KEY) {
45860c26859SStanislaw Gruszka if (idx == wcid->hw_key_idx) {
45960c26859SStanislaw Gruszka wcid->hw_key_idx = -1;
460f2f6a47bSFelix Fietkau wcid->sw_iv = false;
46160c26859SStanislaw Gruszka }
46260c26859SStanislaw Gruszka
463e6db67faSFelix Fietkau return 0;
464e6db67faSFelix Fietkau }
465e6db67faSFelix Fietkau
466e6db67faSFelix Fietkau key->hw_key_idx = wcid->idx;
467e6db67faSFelix Fietkau wcid->hw_key_idx = idx;
468e6db67faSFelix Fietkau if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
469e6db67faSFelix Fietkau key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
470e6db67faSFelix Fietkau wcid->sw_iv = true;
47160c26859SStanislaw Gruszka }
472d87cf75fSLorenzo Bianconi mt76_wcid_key_setup(&dev->mt76, wcid, key);
47360c26859SStanislaw Gruszka
47460c26859SStanislaw Gruszka if (!msta) {
47560c26859SStanislaw Gruszka if (key || wcid->hw_key_idx == idx) {
4768d66af49SLorenzo Bianconi ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key);
47760c26859SStanislaw Gruszka if (ret)
47860c26859SStanislaw Gruszka return ret;
47960c26859SStanislaw Gruszka }
48060c26859SStanislaw Gruszka
4818d66af49SLorenzo Bianconi return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key);
48260c26859SStanislaw Gruszka }
48360c26859SStanislaw Gruszka
4848d66af49SLorenzo Bianconi return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key);
48560c26859SStanislaw Gruszka }
48660c26859SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_set_key);
48760c26859SStanislaw Gruszka
mt76x02_conf_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,unsigned int link_id,u16 queue,const struct ieee80211_tx_queue_params * params)48810337263SStanislaw Gruszka int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
489b3e2130bSJohannes Berg unsigned int link_id, u16 queue,
490b3e2130bSJohannes Berg const struct ieee80211_tx_queue_params *params)
49110337263SStanislaw Gruszka {
492d87cf75fSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
49310337263SStanislaw Gruszka u8 cw_min = 5, cw_max = 10, qid;
49410337263SStanislaw Gruszka u32 val;
49510337263SStanislaw Gruszka
49691990519SLorenzo Bianconi qid = dev->mphy.q_tx[queue]->hw_idx;
49710337263SStanislaw Gruszka
49810337263SStanislaw Gruszka if (params->cw_min)
49910337263SStanislaw Gruszka cw_min = fls(params->cw_min);
50010337263SStanislaw Gruszka if (params->cw_max)
50110337263SStanislaw Gruszka cw_max = fls(params->cw_max);
50210337263SStanislaw Gruszka
50310337263SStanislaw Gruszka val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) |
50410337263SStanislaw Gruszka FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
50510337263SStanislaw Gruszka FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
50610337263SStanislaw Gruszka FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
507d87cf75fSLorenzo Bianconi mt76_wr(dev, MT_EDCA_CFG_AC(qid), val);
50810337263SStanislaw Gruszka
509d87cf75fSLorenzo Bianconi val = mt76_rr(dev, MT_WMM_TXOP(qid));
51010337263SStanislaw Gruszka val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
51110337263SStanislaw Gruszka val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
512d87cf75fSLorenzo Bianconi mt76_wr(dev, MT_WMM_TXOP(qid), val);
51310337263SStanislaw Gruszka
514d87cf75fSLorenzo Bianconi val = mt76_rr(dev, MT_WMM_AIFSN);
51510337263SStanislaw Gruszka val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
51610337263SStanislaw Gruszka val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
517d87cf75fSLorenzo Bianconi mt76_wr(dev, MT_WMM_AIFSN, val);
51810337263SStanislaw Gruszka
519d87cf75fSLorenzo Bianconi val = mt76_rr(dev, MT_WMM_CWMIN);
52010337263SStanislaw Gruszka val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
52110337263SStanislaw Gruszka val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
522d87cf75fSLorenzo Bianconi mt76_wr(dev, MT_WMM_CWMIN, val);
52310337263SStanislaw Gruszka
524d87cf75fSLorenzo Bianconi val = mt76_rr(dev, MT_WMM_CWMAX);
52510337263SStanislaw Gruszka val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
52610337263SStanislaw Gruszka val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
527d87cf75fSLorenzo Bianconi mt76_wr(dev, MT_WMM_CWMAX, val);
52810337263SStanislaw Gruszka
52910337263SStanislaw Gruszka return 0;
53010337263SStanislaw Gruszka }
53110337263SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_conf_tx);
53210337263SStanislaw Gruszka
mt76x02_set_tx_ackto(struct mt76x02_dev * dev)53336704051SLorenzo Bianconi void mt76x02_set_tx_ackto(struct mt76x02_dev *dev)
53436704051SLorenzo Bianconi {
53536704051SLorenzo Bianconi u8 ackto, sifs, slottime = dev->slottime;
53636704051SLorenzo Bianconi
53736704051SLorenzo Bianconi /* As defined by IEEE 802.11-2007 17.3.8.6 */
53836704051SLorenzo Bianconi slottime += 3 * dev->coverage_class;
53936704051SLorenzo Bianconi mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG,
54036704051SLorenzo Bianconi MT_BKOFF_SLOT_CFG_SLOTTIME, slottime);
54136704051SLorenzo Bianconi
54236704051SLorenzo Bianconi sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG,
54336704051SLorenzo Bianconi MT_XIFS_TIME_CFG_OFDM_SIFS);
54436704051SLorenzo Bianconi
54536704051SLorenzo Bianconi ackto = slottime + sifs;
54636704051SLorenzo Bianconi mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG,
54736704051SLorenzo Bianconi MT_TX_TIMEOUT_CFG_ACKTO, ackto);
54836704051SLorenzo Bianconi }
54936704051SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto);
55036704051SLorenzo Bianconi
mt76x02_set_coverage_class(struct ieee80211_hw * hw,s16 coverage_class)55136704051SLorenzo Bianconi void mt76x02_set_coverage_class(struct ieee80211_hw *hw,
55236704051SLorenzo Bianconi s16 coverage_class)
55336704051SLorenzo Bianconi {
55436704051SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
55536704051SLorenzo Bianconi
55636704051SLorenzo Bianconi mutex_lock(&dev->mt76.mutex);
557bae76a1eSLorenzo Bianconi dev->coverage_class = max_t(s16, coverage_class, 0);
55836704051SLorenzo Bianconi mt76x02_set_tx_ackto(dev);
55936704051SLorenzo Bianconi mutex_unlock(&dev->mt76.mutex);
56036704051SLorenzo Bianconi }
56136704051SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class);
56236704051SLorenzo Bianconi
mt76x02_set_rts_threshold(struct ieee80211_hw * hw,u32 val)563317ed42bSLorenzo Bianconi int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
564317ed42bSLorenzo Bianconi {
565317ed42bSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
566317ed42bSLorenzo Bianconi
567317ed42bSLorenzo Bianconi if (val != ~0 && val > 0xffff)
568317ed42bSLorenzo Bianconi return -EINVAL;
569317ed42bSLorenzo Bianconi
570074b145aSKalle Valo mutex_lock(&dev->mt76.mutex);
57120ce270eSStanislaw Gruszka mt76x02_mac_set_rts_thresh(dev, val);
572074b145aSKalle Valo mutex_unlock(&dev->mt76.mutex);
573317ed42bSLorenzo Bianconi
574317ed42bSLorenzo Bianconi return 0;
575317ed42bSLorenzo Bianconi }
576317ed42bSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_set_rts_threshold);
577317ed42bSLorenzo Bianconi
mt76x02_sta_rate_tbl_update(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)5785327b5eaSStanislaw Gruszka void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
5795327b5eaSStanislaw Gruszka struct ieee80211_vif *vif,
5805327b5eaSStanislaw Gruszka struct ieee80211_sta *sta)
5815327b5eaSStanislaw Gruszka {
5828d66af49SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
5835327b5eaSStanislaw Gruszka struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
5845327b5eaSStanislaw Gruszka struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates);
5855327b5eaSStanislaw Gruszka struct ieee80211_tx_rate rate = {};
5865327b5eaSStanislaw Gruszka
5875327b5eaSStanislaw Gruszka if (!rates)
5885327b5eaSStanislaw Gruszka return;
5895327b5eaSStanislaw Gruszka
5905327b5eaSStanislaw Gruszka rate.idx = rates->rate[0].idx;
5915327b5eaSStanislaw Gruszka rate.flags = rates->rate[0].flags;
5925327b5eaSStanislaw Gruszka mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate);
5935327b5eaSStanislaw Gruszka }
5945327b5eaSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update);
5955327b5eaSStanislaw Gruszka
mt76x02_remove_hdr_pad(struct sk_buff * skb,int len)5960e59cba8SStanislaw Gruszka void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len)
5970e59cba8SStanislaw Gruszka {
5980e59cba8SStanislaw Gruszka int hdrlen;
5990e59cba8SStanislaw Gruszka
6000e59cba8SStanislaw Gruszka if (!len)
6010e59cba8SStanislaw Gruszka return;
6020e59cba8SStanislaw Gruszka
6030e59cba8SStanislaw Gruszka hdrlen = ieee80211_get_hdrlen_from_skb(skb);
6040e59cba8SStanislaw Gruszka memmove(skb->data + len, skb->data, hdrlen);
6050e59cba8SStanislaw Gruszka skb_pull(skb, len);
6060e59cba8SStanislaw Gruszka }
6070e59cba8SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad);
6080e59cba8SStanislaw Gruszka
mt76x02_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)609c2756a1cSLorenzo Bianconi void mt76x02_sw_scan_complete(struct ieee80211_hw *hw,
610c2756a1cSLorenzo Bianconi struct ieee80211_vif *vif)
611c2756a1cSLorenzo Bianconi {
612c2756a1cSLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
613c2756a1cSLorenzo Bianconi
614011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &dev->mphy.state);
6154784a3ccSStanislaw Gruszka if (dev->cal.gain_init_done) {
6164784a3ccSStanislaw Gruszka /* Restore AGC gain and resume calibration after scanning. */
6174784a3ccSStanislaw Gruszka dev->cal.low_gain = -1;
618f1b8ee35SStanislaw Gruszka ieee80211_queue_delayed_work(hw, &dev->cal_work, 0);
619c2756a1cSLorenzo Bianconi }
6204784a3ccSStanislaw Gruszka }
621c2756a1cSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete);
622c2756a1cSLorenzo Bianconi
mt76x02_sta_ps(struct mt76_dev * mdev,struct ieee80211_sta * sta,bool ps)623f7c8a0f2SLorenzo Bianconi void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
624f7c8a0f2SLorenzo Bianconi bool ps)
625f7c8a0f2SLorenzo Bianconi {
626f7c8a0f2SLorenzo Bianconi struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
627f7c8a0f2SLorenzo Bianconi struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
628f7c8a0f2SLorenzo Bianconi int idx = msta->wcid.idx;
629f7c8a0f2SLorenzo Bianconi
63091990519SLorenzo Bianconi mt76_stop_tx_queues(&dev->mphy, sta, true);
63161c51a74SLorenzo Bianconi if (mt76_is_mmio(mdev))
632f7c8a0f2SLorenzo Bianconi mt76x02_mac_wcid_set_drop(dev, idx, ps);
633f7c8a0f2SLorenzo Bianconi }
634f7c8a0f2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_sta_ps);
635f7c8a0f2SLorenzo Bianconi
mt76x02_bss_info_changed(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * info,u64 changed)636cc726268SLorenzo Bianconi void mt76x02_bss_info_changed(struct ieee80211_hw *hw,
637cc726268SLorenzo Bianconi struct ieee80211_vif *vif,
638cc726268SLorenzo Bianconi struct ieee80211_bss_conf *info,
6397b7090b4SJohannes Berg u64 changed)
640cc726268SLorenzo Bianconi {
641cc726268SLorenzo Bianconi struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
642cc726268SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
643cc726268SLorenzo Bianconi
644cc726268SLorenzo Bianconi mutex_lock(&dev->mt76.mutex);
645cc726268SLorenzo Bianconi
646cc726268SLorenzo Bianconi if (changed & BSS_CHANGED_BSSID)
647cc726268SLorenzo Bianconi mt76x02_mac_set_bssid(dev, mvif->idx, info->bssid);
648cc726268SLorenzo Bianconi
64926a7b547SStanislaw Gruszka if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
65026a7b547SStanislaw Gruszka mt76x02_mac_set_tx_protection(dev, info->use_cts_prot,
65126a7b547SStanislaw Gruszka info->ht_operation_mode);
65226a7b547SStanislaw Gruszka
653cc726268SLorenzo Bianconi if (changed & BSS_CHANGED_BEACON_INT) {
654cc726268SLorenzo Bianconi mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
655cc726268SLorenzo Bianconi MT_BEACON_TIME_CFG_INTVAL,
656cc726268SLorenzo Bianconi info->beacon_int << 4);
6573041c445SLorenzo Bianconi dev->mt76.beacon_int = info->beacon_int;
658cc726268SLorenzo Bianconi }
659cc726268SLorenzo Bianconi
660ed55c9b9SFelix Fietkau if (changed & BSS_CHANGED_BEACON_ENABLED)
661ed55c9b9SFelix Fietkau mt76x02_mac_set_beacon_enable(dev, vif, info->enable_beacon);
662ed55c9b9SFelix Fietkau
663cc726268SLorenzo Bianconi if (changed & BSS_CHANGED_ERP_PREAMBLE)
664cc726268SLorenzo Bianconi mt76x02_mac_set_short_preamble(dev, info->use_short_preamble);
665cc726268SLorenzo Bianconi
666cc726268SLorenzo Bianconi if (changed & BSS_CHANGED_ERP_SLOT) {
667cc726268SLorenzo Bianconi int slottime = info->use_short_slot ? 9 : 20;
668cc726268SLorenzo Bianconi
669cc726268SLorenzo Bianconi dev->slottime = slottime;
670cc726268SLorenzo Bianconi mt76x02_set_tx_ackto(dev);
671cc726268SLorenzo Bianconi }
672cc726268SLorenzo Bianconi
673cc726268SLorenzo Bianconi mutex_unlock(&dev->mt76.mutex);
674cc726268SLorenzo Bianconi }
675cc726268SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_bss_info_changed);
676cc726268SLorenzo Bianconi
mt76x02_config_mac_addr_list(struct mt76x02_dev * dev)677269906acSLorenzo Bianconi void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev)
678269906acSLorenzo Bianconi {
679269906acSLorenzo Bianconi struct ieee80211_hw *hw = mt76_hw(dev);
680269906acSLorenzo Bianconi struct wiphy *wiphy = hw->wiphy;
681269906acSLorenzo Bianconi int i;
682269906acSLorenzo Bianconi
683269906acSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) {
684269906acSLorenzo Bianconi u8 *addr = dev->macaddr_list[i].addr;
685269906acSLorenzo Bianconi
68698df2baeSLorenzo Bianconi memcpy(addr, dev->mphy.macaddr, ETH_ALEN);
687269906acSLorenzo Bianconi
688269906acSLorenzo Bianconi if (!i)
689269906acSLorenzo Bianconi continue;
690269906acSLorenzo Bianconi
691269906acSLorenzo Bianconi addr[0] |= BIT(1);
692269906acSLorenzo Bianconi addr[0] ^= ((i - 1) << 2);
693269906acSLorenzo Bianconi }
694269906acSLorenzo Bianconi wiphy->addresses = dev->macaddr_list;
695269906acSLorenzo Bianconi wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list);
696269906acSLorenzo Bianconi }
697269906acSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list);
698a6daf796SLorenzo Bianconi
699108a4861SStanislaw Gruszka MODULE_LICENSE("Dual BSD/GPL");
700