diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2021-10-20 19:08:25 +0300 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2021-10-20 19:08:25 +0300 |
commit | 9bc0b1aa8b7e54d62082749fc5404660690d17ce (patch) | |
tree | e479cb7e124984eb647c84b3442d135c5541b85f /drivers | |
parent | 2ad96cb5b4f45f666e2f911e990cbbb957a51d93 (diff) | |
parent | ff8c049891688131682ac0b7fb0ef55595b19898 (diff) | |
download | linux-9bc0b1aa8b7e54d62082749fc5404660690d17ce.tar.xz |
Merge tag 'mt76-for-kvalo-2021-10-20' of https://github.com/nbd168/wireless
mt76 patches for 5.16
* various bugfixes
* endian fixes
* mt7921 aspm support
* cleanup
* mt7921 testmode support
* rate handling fixes
* tx status fixes/improvements
* mt7921 power management improvements
* mt7915 LED support
* DBDC fixes
* mt7921 6GHz support
* support for eeprom data in DT
* mt7915 TWT support
* mt7915 txbf + MU-MIMO improvements
# gpg: Signature made Wed 20 Oct 2021 12:24:46 PM EEST
# gpg: using DSA key D77D141D02A76EF5
# gpg: Good signature from "Felix Fietkau <nbd@nbd.name>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 75D1 1A7D 91A7 710F 4900 42EF D77D 141D 02A7 6EF5
Diffstat (limited to 'drivers')
70 files changed, 6109 insertions, 2539 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 94efe3c29053..79ab850a45a2 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -14,7 +14,7 @@ mt76-$(CONFIG_PCI) += pci.o mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o mt76-usb-y := usb.o usb_trace.o -mt76-sdio-y := sdio.o +mt76-sdio-y := sdio.o sdio_txrx.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index fa48cc3a7a8f..b8bcf22a07fd 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -56,14 +56,14 @@ int mt76_queues_read(struct seq_file *s, void *data) struct mt76_dev *dev = dev_get_drvdata(s->private); int i; + seq_puts(s, " queue | hw-queued | head | tail |\n"); for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) { struct mt76_queue *q = dev->phy.q_tx[i]; if (!q) continue; - seq_printf(s, - "%d: queued=%d head=%d tail=%d\n", + seq_printf(s, " %9d | %9d | %9d | %9d |\n", i, q->queued, q->head, q->tail); } @@ -76,12 +76,13 @@ static int mt76_rx_queues_read(struct seq_file *s, void *data) struct mt76_dev *dev = dev_get_drvdata(s->private); int i, queued; + seq_puts(s, " queue | hw-queued | head | tail |\n"); mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued; - seq_printf(s, "%d: queued=%d head=%d tail=%d\n", - i, queued, q->head, q->tail); + seq_printf(s, " %9d | %9d | %9d | %9d |\n", + i, q->queued, q->head, q->tail); } return 0; @@ -116,18 +117,21 @@ static int mt76_read_rate_txpower(struct seq_file *s, void *data) return 0; } -struct dentry *mt76_register_debugfs(struct mt76_dev *dev) +struct dentry * +mt76_register_debugfs_fops(struct mt76_phy *phy, + const struct file_operations *ops) { + const struct file_operations *fops = ops ? ops : &fops_regval; + struct mt76_dev *dev = phy->dev; struct dentry *dir; - dir = debugfs_create_dir("mt76", dev->hw->wiphy->debugfsdir); + dir = debugfs_create_dir("mt76", phy->hw->wiphy->debugfsdir); if (!dir) return NULL; debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin); debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg); - debugfs_create_file_unsafe("regval", 0600, dir, dev, - &fops_regval); + debugfs_create_file_unsafe("regval", 0600, dir, dev, fops); debugfs_create_file_unsafe("napi_threaded", 0600, dir, dev, &fops_napi_threaded); debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom); @@ -140,4 +144,4 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) return dir; } -EXPORT_SYMBOL_GPL(mt76_register_debugfs); +EXPORT_SYMBOL_GPL(mt76_register_debugfs_fops); diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 3b47e85e95e7..e65b2262e692 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -15,6 +15,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) struct device_node *np = dev->dev->of_node; struct mtd_info *mtd; const __be32 *list; + const void *data; const char *part; phandle phandle; int size; @@ -24,6 +25,16 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!np) return -ENOENT; + data = of_get_property(np, "mediatek,eeprom-data", &size); + if (data) { + if (size > len) + return -EINVAL; + + memcpy(eep, data, size); + + return 0; + } + list = of_get_property(np, "mediatek,mtd-eeprom", &size); if (!list) return -ENOENT; @@ -285,6 +296,9 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, case NL80211_BAND_5GHZ: band = '5'; break; + case NL80211_BAND_6GHZ: + band = '6'; + break; default: return target_power; } diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d03aedc3286b..62807dc311c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -20,6 +20,13 @@ .max_power = 30, \ } +#define CHAN6G(_idx, _freq) { \ + .band = NL80211_BAND_6GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + static const struct ieee80211_channel mt76_channels_2ghz[] = { CHAN2G(1, 2412), CHAN2G(2, 2417), @@ -70,6 +77,72 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = { CHAN5G(173, 5865), }; +static const struct ieee80211_channel mt76_channels_6ghz[] = { + /* UNII-5 */ + CHAN6G(1, 5955), + CHAN6G(5, 5975), + CHAN6G(9, 5995), + CHAN6G(13, 6015), + CHAN6G(17, 6035), + CHAN6G(21, 6055), + CHAN6G(25, 6075), + CHAN6G(29, 6095), + CHAN6G(33, 6115), + CHAN6G(37, 6135), + CHAN6G(41, 6155), + CHAN6G(45, 6175), + CHAN6G(49, 6195), + CHAN6G(53, 6215), + CHAN6G(57, 6235), + CHAN6G(61, 6255), + CHAN6G(65, 6275), + CHAN6G(69, 6295), + CHAN6G(73, 6315), + CHAN6G(77, 6335), + CHAN6G(81, 6355), + CHAN6G(85, 6375), + CHAN6G(89, 6395), + CHAN6G(93, 6415), + /* UNII-6 */ + CHAN6G(97, 6435), + CHAN6G(101, 6455), + CHAN6G(105, 6475), + CHAN6G(109, 6495), + CHAN6G(113, 6515), + CHAN6G(117, 6535), + /* UNII-7 */ + CHAN6G(121, 6555), + CHAN6G(125, 6575), + CHAN6G(129, 6595), + CHAN6G(133, 6615), + CHAN6G(137, 6635), + CHAN6G(141, 6655), + CHAN6G(145, 6675), + CHAN6G(149, 6695), + CHAN6G(153, 6715), + CHAN6G(157, 6735), + CHAN6G(161, 6755), + CHAN6G(165, 6775), + CHAN6G(169, 6795), + CHAN6G(173, 6815), + CHAN6G(177, 6835), + CHAN6G(181, 6855), + CHAN6G(185, 6875), + /* UNII-8 */ + CHAN6G(189, 6895), + CHAN6G(193, 6915), + CHAN6G(197, 6935), + CHAN6G(201, 6955), + CHAN6G(205, 6975), + CHAN6G(209, 6995), + CHAN6G(213, 7015), + CHAN6G(217, 7035), + CHAN6G(221, 7055), + CHAN6G(225, 7075), + CHAN6G(229, 7095), + CHAN6G(233, 7115), +}; + static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, { .throughput = 1 * 1024, .blink_time = 260 }, @@ -99,6 +172,21 @@ struct ieee80211_rate mt76_rates[] = { }; EXPORT_SYMBOL_GPL(mt76_rates); +static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { + { .start_freq = 2402, .end_freq = 2494, }, + { .start_freq = 5150, .end_freq = 5350, }, + { .start_freq = 5350, .end_freq = 5470, }, + { .start_freq = 5470, .end_freq = 5725, }, + { .start_freq = 5725, .end_freq = 5950, }, +}; + +const struct cfg80211_sar_capa mt76_sar_capa = { + .type = NL80211_SAR_TYPE_POWER, + .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), + .freq_ranges = &mt76_sar_freq_ranges[0], +}; +EXPORT_SYMBOL_GPL(mt76_sar_capa); + static int mt76_led_init(struct mt76_dev *dev) { struct device_node *np = dev->dev->of_node; @@ -179,13 +267,16 @@ void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); if (phy->cap.has_5ghz) mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); + if (phy->cap.has_6ghz) + mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht); } EXPORT_SYMBOL_GPL(mt76_set_stream_caps); static int mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, const struct ieee80211_channel *chan, int n_chan, - struct ieee80211_rate *rates, int n_rates, bool vht) + struct ieee80211_rate *rates, int n_rates, + bool ht, bool vht) { struct ieee80211_supported_band *sband = &msband->sband; struct ieee80211_sta_vht_cap *vht_cap; @@ -209,6 +300,9 @@ mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, sband->bitrates = rates; sband->n_bitrates = n_rates; + if (!ht) + return 0; + ht_cap = &sband->ht_cap; ht_cap->ht_supported = true; ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | @@ -245,7 +339,7 @@ mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz), rates, - n_rates, false); + n_rates, true, false); } static int @@ -256,7 +350,18 @@ mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz), rates, - n_rates, vht); + n_rates, true, vht); +} + +static int +mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates, + int n_rates) +{ + phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband; + + return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz, + ARRAY_SIZE(mt76_channels_6ghz), rates, + n_rates, false, false); } static void @@ -322,12 +427,8 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); - - if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) { - ieee80211_hw_set(hw, TX_AMSDU); - ieee80211_hw_set(hw, TX_FRAG_LIST); - } - + ieee80211_hw_set(hw, TX_AMSDU); + ieee80211_hw_set(hw, TX_FRAG_LIST); ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); @@ -385,9 +486,16 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht, return ret; } + if (phy->cap.has_6ghz) { + ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); + if (ret) + return ret; + } + wiphy_read_of_freq_limits(phy->hw->wiphy); mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); + mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ); ret = ieee80211_register_hw(phy->hw); if (ret) @@ -403,7 +511,7 @@ void mt76_unregister_phy(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; - mt76_tx_status_check(dev, NULL, true); + mt76_tx_status_check(dev, true); ieee80211_unregister_hw(phy->hw); dev->phy2 = NULL; } @@ -435,9 +543,9 @@ mt76_alloc_device(struct device *pdev, unsigned int size, spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); spin_lock_init(&dev->cc_lock); + spin_lock_init(&dev->status_lock); mutex_init(&dev->mutex); init_waitqueue_head(&dev->tx_wait); - skb_queue_head_init(&dev->status_list); skb_queue_head_init(&dev->mcu.res_q); init_waitqueue_head(&dev->mcu.wait); @@ -458,6 +566,8 @@ mt76_alloc_device(struct device *pdev, unsigned int size, spin_lock_init(&dev->token_lock); idr_init(&dev->token); + INIT_LIST_HEAD(&dev->wcid_list); + INIT_LIST_HEAD(&dev->txwi_cache); for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) @@ -495,9 +605,16 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, return ret; } + if (phy->cap.has_6ghz) { + ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); + if (ret) + return ret; + } + wiphy_read_of_freq_limits(hw->wiphy); mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); + mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); if (IS_ENABLED(CONFIG_MT76_LEDS)) { ret = mt76_led_init(dev); @@ -522,7 +639,7 @@ void mt76_unregister_device(struct mt76_dev *dev) if (IS_ENABLED(CONFIG_MT76_LEDS)) mt76_led_cleanup(dev); - mt76_tx_status_check(dev, NULL, true); + mt76_tx_status_check(dev, true); ieee80211_unregister_hw(hw); } EXPORT_SYMBOL_GPL(mt76_unregister_device); @@ -642,6 +759,8 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) if (c->band == NL80211_BAND_2GHZ) msband = &phy->sband_2g; + else if (c->band == NL80211_BAND_6GHZ) + msband = &phy->sband_6g; else msband = &phy->sband_5g; @@ -717,10 +836,16 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, if (idx == 0 && dev->drv->update_survey) mt76_update_survey(phy); - sband = &phy->sband_2g; - if (idx >= sband->sband.n_channels) { - idx -= sband->sband.n_channels; + if (idx >= phy->sband_2g.sband.n_channels + + phy->sband_5g.sband.n_channels) { + idx -= (phy->sband_2g.sband.n_channels + + phy->sband_5g.sband.n_channels); + sband = &phy->sband_6g; + } else if (idx >= phy->sband_2g.sband.n_channels) { + idx -= phy->sband_2g.sband.n_channels; sband = &phy->sband_5g; + } else { + sband = &phy->sband_2g; } if (idx >= sband->sband.n_channels) { @@ -777,10 +902,17 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, return; wcid->rx_check_pn = true; + + /* data frame */ for (i = 0; i < IEEE80211_NUM_TIDS; i++) { ieee80211_get_key_rx_seq(key, i, &seq); memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); } + + /* robust management frame */ + ieee80211_get_key_rx_seq(key, -1, &seq); + memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); + } EXPORT_SYMBOL(mt76_wcid_key_setup); @@ -790,6 +922,7 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_sta **sta) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct mt76_rx_status mstat; mstat = *((struct mt76_rx_status *)skb->cb); @@ -812,6 +945,10 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, status->device_timestamp = mstat.timestamp; status->mactime = mstat.timestamp; + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) + status->boottime_ns = ktime_get_boottime_ns(); + BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); BUILD_BUG_ON(sizeof(status->chain_signal) != sizeof(mstat.chain_signal)); @@ -828,7 +965,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_wcid *wcid = status->wcid; struct ieee80211_hdr *hdr; - u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; + int security_idx; int ret; if (!(status->flag & RX_FLAG_DECRYPTED)) @@ -837,24 +974,39 @@ mt76_check_ccmp_pn(struct sk_buff *skb) if (!wcid || !wcid->rx_check_pn) return 0; + security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; + if (status->flag & RX_FLAG_8023) + goto skip_hdr_check; + + hdr = mt76_skb_get_hdr(skb); if (!(status->flag & RX_FLAG_IV_STRIPPED)) { /* * Validate the first fragment both here and in mac80211 * All further fragments will be validated by mac80211 only. */ - hdr = mt76_skb_get_hdr(skb); if (ieee80211_is_frag(hdr) && !ieee80211_is_first_frag(hdr->frame_control)) return 0; } + /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): + * + * the recipient shall maintain a single replay counter for received + * individually addressed robust Management frames that are received + * with the To DS subfield equal to 0, [...] + */ + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_has_tods(hdr->frame_control)) + security_idx = IEEE80211_NUM_TIDS; + +skip_hdr_check: BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); - ret = memcmp(status->iv, wcid->rx_key_pn[tidno], + ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], sizeof(status->iv)); if (ret <= 0) return -EINVAL; /* replay */ - memcpy(wcid->rx_key_pn[tidno], status->iv, sizeof(status->iv)); + memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); if (status->flag & RX_FLAG_IV_STRIPPED) status->flag |= RX_FLAG_PN_VALIDATED; @@ -1109,6 +1261,7 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, wcid->ext_phy = ext_phy; rcu_assign_pointer(dev->wcid[wcid->idx], wcid); + mt76_packet_id_init(wcid); out: mutex_unlock(&dev->mutex); @@ -1127,7 +1280,8 @@ void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, if (dev->drv->sta_remove) dev->drv->sta_remove(dev, vif, sta); - mt76_tx_status_check(dev, wcid, true); + mt76_packet_id_flush(dev, wcid); + mt76_wcid_mask_clear(dev->wcid_mask, idx); mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); } @@ -1270,7 +1424,7 @@ int mt76_get_rate(struct mt76_dev *dev, int i, offset = 0, len = sband->n_bitrates; if (cck) { - if (sband == &dev->phy.sband_5g.sband) + if (sband != &dev->phy.sband_2g.sband) return 0; idx &= ~BIT(2); /* short preamble */ @@ -1336,3 +1490,49 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, return hwq; } EXPORT_SYMBOL_GPL(mt76_init_queue); + +u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) +{ + int offset = 0; + struct ieee80211_rate *rate; + + if (phy->chandef.chan->band != NL80211_BAND_2GHZ) + offset = 4; + + /* pick the lowest rate for hidden nodes */ + if (rateidx < 0) + rateidx = 0; + + rate = &mt76_rates[offset + rateidx]; + + return rate->hw_value; +} +EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); + +void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, + struct mt76_sta_stats *stats) +{ + int i, ei = wi->initial_stat_idx; + u64 *data = wi->data; + + wi->sta_count++; + + data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB]; + data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU]; + + for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++) + data[ei++] += stats->tx_bw[i]; + + for (i = 0; i < 12; i++) + data[ei++] += stats->tx_mcs[i]; + + wi->worker_stat_count = ei - wi->initial_stat_idx; +} +EXPORT_SYMBOL_GPL(mt76_ethtool_worker); diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index d3a5e2c4f12a..3f94c37251df 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -106,13 +106,13 @@ out: } EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg); -int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, - int len) +int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, + int len, int max_len) { int err, cur_len; while (len > 0) { - cur_len = min_t(int, 4096 - dev->mcu_ops->headroom, len); + cur_len = min_t(int, max_len, len); err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false); if (err) @@ -129,4 +129,4 @@ int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, return 0; } -EXPORT_SYMBOL_GPL(mt76_mcu_send_firmware); +EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 25c5ceef5257..e2da720a91b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -29,6 +29,7 @@ struct mt76_dev; struct mt76_phy; struct mt76_wcid; +struct mt76s_intr; struct mt76_reg_pair { u32 reg; @@ -244,6 +245,8 @@ struct mt76_wcid { struct ewma_signal rssi; int inactive_count; + struct rate_info rate; + u16 idx; u8 hw_key_idx; u8 hw_key_idx2; @@ -253,13 +256,14 @@ struct mt76_wcid { u8 amsdu:1; u8 rx_check_pn; - u8 rx_key_pn[IEEE80211_NUM_TIDS][6]; + u8 rx_key_pn[IEEE80211_NUM_TIDS + 1][6]; u16 cipher; u32 tx_info; bool sw_iv; - u8 packet_id; + struct list_head list; + struct idr pktid; }; struct mt76_txq { @@ -305,8 +309,13 @@ struct mt76_rx_tid { #define MT_PACKET_ID_NO_SKB 1 #define MT_PACKET_ID_FIRST 2 #define MT_PACKET_ID_HAS_RATE BIT(7) - -#define MT_TX_STATUS_SKB_TIMEOUT HZ +/* This is timer for when to give up when waiting for TXS callback, + * with starting time being the time at which the DMA_DONE callback + * was seen (so, we know packet was processed then, it should not take + * long after that for firmware to send the TXS callback if it is going + * to do so.) + */ +#define MT_TX_STATUS_SKB_TIMEOUT (HZ / 4) struct mt76_tx_cb { unsigned long jiffies; @@ -344,7 +353,6 @@ struct mt76_hw_cap { #define MT_DRV_SW_RX_AIRTIME BIT(2) #define MT_DRV_RX_DMA_HDR BIT(3) #define MT_DRV_HW_MGMT_TXQ BIT(4) -#define MT_DRV_AMSDU_OFFLOAD BIT(5) struct mt76_driver_ops { u32 drv_flags; @@ -498,13 +506,18 @@ struct mt76_sdio { struct sdio_func *func; void *intr_data; + u8 hw_ver; + wait_queue_head_t wait; struct { int pse_data_quota; int ple_data_quota; int pse_mcu_quota; + int pse_page_size; int deficit; } sched; + + int (*parse_irq)(struct mt76_dev *dev, struct mt76s_intr *intr); }; struct mt76_mmio { @@ -545,6 +558,11 @@ struct mt76_rx_status { s8 chain_signal[IEEE80211_MAX_CHAINS]; }; +struct mt76_freq_range_power { + const struct cfg80211_sar_freq_ranges *range; + s8 power; +}; + struct mt76_testmode_ops { int (*set_state)(struct mt76_phy *phy, enum mt76_testmode_state state); int (*set_params)(struct mt76_phy *phy, struct nlattr **tb, @@ -617,6 +635,7 @@ struct mt76_phy { struct mt76_hw_cap cap; struct mt76_sband sband_2g; struct mt76_sband sband_5g; + struct mt76_sband sband_6g; u8 macaddr[ETH_ALEN]; @@ -636,6 +655,8 @@ struct mt76_phy { struct sk_buff **tail; u16 seqno; } rx_amsdu[__MT_RXQ_MAX]; + + struct mt76_freq_range_power *frp; }; struct mt76_dev { @@ -683,7 +704,8 @@ struct mt76_dev { int token_count; wait_queue_head_t tx_wait; - struct sk_buff_head status_list; + /* spinclock used to protect wcid pktid linked list */ + spinlock_t status_lock; u32 wcid_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)]; u32 wcid_phy_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)]; @@ -692,6 +714,7 @@ struct mt76_dev { struct mt76_wcid global_wcid; struct mt76_wcid __rcu *wcid[MT76_N_WCIDS]; + struct list_head wcid_list; u32 rev; @@ -753,6 +776,22 @@ enum mt76_phy_type { MT_PHY_TYPE_HE_EXT_SU, MT_PHY_TYPE_HE_TB, MT_PHY_TYPE_HE_MU, + __MT_PHY_TYPE_HE_MAX, +}; + +struct mt76_sta_stats { + u64 tx_mode[__MT_PHY_TYPE_HE_MAX]; + u64 tx_bw[4]; /* 20, 40, 80, 160 */ + u64 tx_nss[4]; /* 1, 2, 3, 4 */ + u64 tx_mcs[16]; /* mcs idx */ +}; + +struct mt76_ethtool_worker_info { + u64 *data; + int idx; + int initial_stat_idx; + int worker_stat_count; + int sta_count; }; #define CCK_RATE(_idx, _rate) { \ @@ -769,6 +808,7 @@ enum mt76_phy_type { } extern struct ieee80211_rate mt76_rates[12]; +extern const struct cfg80211_sar_capa mt76_sar_capa; #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) #define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) @@ -869,7 +909,13 @@ struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, int mt76_register_phy(struct mt76_phy *phy, bool vht, struct ieee80211_rate *rates, int n_rates); -struct dentry *mt76_register_debugfs(struct mt76_dev *dev); +struct dentry *mt76_register_debugfs_fops(struct mt76_phy *phy, + const struct file_operations *ops); +static inline struct dentry *mt76_register_debugfs(struct mt76_dev *dev) +{ + return mt76_register_debugfs_fops(&dev->phy, NULL); +} + int mt76_queues_read(struct seq_file *s, void *data); void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len); @@ -881,6 +927,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, int ring_base); +u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx); static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, int n_desc, int ring_base) { @@ -1077,9 +1124,9 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key); void mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list) - __acquires(&dev->status_list.lock); + __acquires(&dev->status_lock); void mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) - __releases(&dev->status_list.lock); + __releases(&dev->status_lock); int mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb); @@ -1096,8 +1143,7 @@ mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb) __mt76_tx_complete_skb(dev, wcid, skb, NULL); } -void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, - bool flush); +void mt76_tx_status_check(struct mt76_dev *dev, bool flush); int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, @@ -1203,6 +1249,8 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len, return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout); } +void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, + struct mt76_sta_stats *stats); int mt76_skb_adjust_pad(struct sk_buff *skb, int pad); int mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, @@ -1220,8 +1268,27 @@ void mt76u_queues_deinit(struct mt76_dev *dev); int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, const struct mt76_bus_ops *bus_ops); -int mt76s_alloc_queues(struct mt76_dev *dev); +int mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid); +int mt76s_alloc_tx(struct mt76_dev *dev); void mt76s_deinit(struct mt76_dev *dev); +void mt76s_sdio_irq(struct sdio_func *func); +void mt76s_txrx_worker(struct mt76_sdio *sdio); +bool mt76s_txqs_empty(struct mt76_dev *dev); +int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func, + int hw_ver); +u32 mt76s_rr(struct mt76_dev *dev, u32 offset); +void mt76s_wr(struct mt76_dev *dev, u32 offset, u32 val); +u32 mt76s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val); +u32 mt76s_read_pcr(struct mt76_dev *dev); +void mt76s_write_copy(struct mt76_dev *dev, u32 offset, + const void *data, int len); +void mt76s_read_copy(struct mt76_dev *dev, u32 offset, + void *data, int len); +int mt76s_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, + int len); +int mt76s_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int len); struct sk_buff * mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, @@ -1233,8 +1300,17 @@ int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data, int len, bool wait_resp, struct sk_buff **ret); int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp, struct sk_buff **ret); -int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, - int len); +int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, + int len, int max_len); +static inline int +mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, + int len) +{ + int max_len = 4096 - dev->mcu_ops->headroom; + + return __mt76_mcu_send_firmware(dev, cmd, data, len, max_len); +} + static inline int mt76_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, int len, bool wait_resp) @@ -1293,14 +1369,22 @@ mt76_token_put(struct mt76_dev *dev, int token) return txwi; } -static inline int -mt76_get_next_pkt_id(struct mt76_wcid *wcid) +static inline void mt76_packet_id_init(struct mt76_wcid *wcid) { - wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; - if (wcid->packet_id == MT_PACKET_ID_NO_ACK || - wcid->packet_id == MT_PACKET_ID_NO_SKB) - wcid->packet_id = MT_PACKET_ID_FIRST; + INIT_LIST_HEAD(&wcid->list); + idr_init(&wcid->pktid); +} - return wcid->packet_id; +static inline void +mt76_packet_id_flush(struct mt76_dev *dev, struct mt76_wcid *wcid) +{ + struct sk_buff_head list; + + mt76_tx_status_lock(dev, &list); + mt76_tx_status_skb_get(dev, wcid, -1, &list); + mt76_tx_status_unlock(dev, &list); + + idr_destroy(&wcid->pktid); } + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 3972c56136a2..fe03e31989bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1458,7 +1458,7 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev) mt76_queue_rx_reset(dev, i); } - mt76_tx_status_check(&dev->mt76, NULL, true); + mt76_tx_status_check(&dev->mt76, true); mt7603_dma_sched_reset(dev); @@ -1471,17 +1471,20 @@ skip_dma_reset: mutex_unlock(&dev->mt76.mutex); mt76_worker_enable(&dev->mt76.tx_worker); - napi_enable(&dev->mt76.tx_napi); - napi_schedule(&dev->mt76.tx_napi); tasklet_enable(&dev->mt76.pre_tbtt_tasklet); mt7603_beacon_set_timer(dev, -1, beacon_int); + local_bh_disable(); + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); + napi_enable(&dev->mt76.napi[0]); napi_schedule(&dev->mt76.napi[0]); napi_enable(&dev->mt76.napi[1]); napi_schedule(&dev->mt76.napi[1]); + local_bh_enable(); ieee80211_wake_queues(dev->mt76.hw); mt76_txq_schedule_all(&dev->mphy); @@ -1814,7 +1817,7 @@ void mt7603_mac_work(struct work_struct *work) bool reset = false; int i, idx; - mt76_tx_status_check(&dev->mt76, NULL, false); + mt76_tx_status_check(&dev->mt76, false); mutex_lock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 8edea1e7a602..7ac4cd247a73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -69,6 +69,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; + mt76_packet_id_init(&mvif->sta.wcid); eth_broadcast_addr(bc_addr); mt7603_wtbl_init(dev, idx, mvif->idx, bc_addr); @@ -107,6 +108,8 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mutex_lock(&dev->mt76.mutex); dev->mt76.vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); + + mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid); } void mt7603_init_edcca(struct mt7603_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c index aa6cb668b012..3d94cdb4314a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c @@ -28,7 +28,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index 83f9861ff522..2b97b9dde477 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -17,4 +17,4 @@ mt7615e-$(CONFIG_MT7622_WMAC) += soc.o mt7663-usb-sdio-common-y := usb_sdio.o mt7663u-y := usb.o usb_mcu.o -mt7663s-y := sdio.o sdio_mcu.o sdio_txrx.o +mt7663s-y := sdio.o sdio_mcu.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index cb4659771fd9..6fd6f067da49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -3,6 +3,33 @@ #include "mt7615.h" static int +mt7615_reg_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + mt7615_mutex_acquire(dev); + mt76_wr(dev, dev->mt76.debugfs_reg, val); + mt7615_mutex_release(dev); + + return 0; +} + +static int +mt7615_reg_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + mt7615_mutex_acquire(dev); + *val = mt76_rr(dev, dev->mt76.debugfs_reg); + mt7615_mutex_release(dev); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7615_reg_get, mt7615_reg_set, + "0x%08llx\n"); + +static int mt7615_radar_pattern_set(void *data, u64 val) { struct mt7615_dev *dev = data; @@ -506,7 +533,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) { struct dentry *dir; - dir = mt76_register_debugfs(&dev->mt76); + dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval); if (!dir) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 2f1ac644e018..47f23ac905a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -49,12 +49,14 @@ int mt7615_thermal_init(struct mt7615_dev *dev) { struct wiphy *wiphy = mt76_hw(dev)->wiphy; struct device *hwmon; + const char *name; if (!IS_REACHABLE(CONFIG_HWMON)) return 0; - hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, - wiphy_name(wiphy), dev, + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7615_%s", + wiphy_name(wiphy)); + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, dev, mt7615_hwmon_groups); if (IS_ERR(hwmon)) return PTR_ERR(hwmon); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index ff3f85e4087c..423f69015e3e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -755,12 +755,15 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, if (info->flags & IEEE80211_TX_CTL_NO_ACK) txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK); - txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) | - FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) | - FIELD_PREP(MT_TXD7_SPE_IDX, 0x18); - if (!is_mmio) - txwi[8] = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | - FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); + val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) | + FIELD_PREP(MT_TXD7_SPE_IDX, 0x18); + txwi[7] = cpu_to_le32(val); + if (!is_mmio) { + val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | + FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); + txwi[8] = cpu_to_le32(val); + } return 0; } @@ -1494,32 +1497,41 @@ out: } static void -mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token) +mt7615_txwi_free(struct mt7615_dev *dev, struct mt76_txwi_cache *txwi) { struct mt76_dev *mdev = &dev->mt76; - struct mt76_txwi_cache *txwi; __le32 *txwi_data; u32 val; u8 wcid; - trace_mac_tx_free(dev, token); - txwi = mt76_token_put(mdev, token); - if (!txwi) - return; + mt7615_txp_skb_unmap(mdev, txwi); + if (!txwi->skb) + goto out; txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi); val = le32_to_cpu(txwi_data[1]); wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val); + mt76_tx_complete_skb(mdev, wcid, txwi->skb); - mt7615_txp_skb_unmap(mdev, txwi); - if (txwi->skb) { - mt76_tx_complete_skb(mdev, wcid, txwi->skb); - txwi->skb = NULL; - } - +out: + txwi->skb = NULL; mt76_put_txwi(mdev, txwi); } +static void +mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token) +{ + struct mt76_dev *mdev = &dev->mt76; + struct mt76_txwi_cache *txwi; + + trace_mac_tx_free(dev, token); + txwi = mt76_token_put(mdev, token); + if (!txwi) + return; + + mt7615_txwi_free(dev, txwi); +} + static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data; @@ -2014,7 +2026,7 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mutex_release(phy->dev); - mt76_tx_status_check(mphy->dev, NULL, false); + mt76_tx_status_check(mphy->dev, false); timeout = mt7615_get_macwork_timeout(phy->dev); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout); @@ -2026,16 +2038,8 @@ void mt7615_tx_token_put(struct mt7615_dev *dev) int id; spin_lock_bh(&dev->mt76.token_lock); - idr_for_each_entry(&dev->mt76.token, txwi, id) { - mt7615_txp_skb_unmap(&dev->mt76, txwi); - if (txwi->skb) { - struct ieee80211_hw *hw; - - hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); - ieee80211_free_txskb(hw, txwi->skb); - } - mt76_put_txwi(&dev->mt76, txwi); - } + idr_for_each_entry(&dev->mt76.token, txwi, id) + mt7615_txwi_free(dev, txwi); spin_unlock_bh(&dev->mt76.token_lock); idr_destroy(&dev->mt76.token); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index dada43d6d879..343e157261ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -231,6 +231,8 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, mvif->sta.wcid.idx = idx; mvif->sta.wcid.ext_phy = mvif->mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; + mt76_packet_id_init(&mvif->sta.wcid); + mt7615_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -281,6 +283,8 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); + + mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid); } static void mt7615_init_dfs_state(struct mt7615_phy *phy) @@ -567,8 +571,8 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, mt7615_mcu_add_bss_info(phy, vif, NULL, true); mt7615_mcu_sta_add(phy, vif, NULL, true); - if (vif->p2p) - mt7615_mcu_set_p2p_oppps(hw, vif); + if (mt7615_firmware_offload(dev) && vif->p2p) + mt76_connac_mcu_set_p2p_oppps(hw, vif); } if (changed & (BSS_CHANGED_BEACON | @@ -858,8 +862,6 @@ mt7615_get_stats(struct ieee80211_hw *hw, stats->dot11FCSErrorCount = mib->fcs_err_cnt; stats->dot11ACKFailureCount = mib->ack_fail_cnt; - memset(mib, 0, sizeof(*mib)); - mt7615_mutex_release(phy->dev); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index f8a09692d3e4..2cb3969e6432 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -808,7 +808,8 @@ mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) static int mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) + struct ieee80211_sta *sta, struct mt7615_phy *phy, + bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA; @@ -821,6 +822,7 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MONITOR: break; case NL80211_IFTYPE_STATION: /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ @@ -840,14 +842,19 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } bss = (struct bss_info_basic *)tlv; - memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); - bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); bss->network_type = cpu_to_le32(type); - bss->dtim_period = vif->bss_conf.dtim_period; bss->bmc_tx_wlan_idx = wlan_idx; bss->wmm_idx = mvif->mt76.wmm_idx; bss->active = enable; + if (vif->type != NL80211_IFTYPE_MONITOR) { + memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); + bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + bss->dtim_period = vif->bss_conf.dtim_period; + } else { + memcpy(bss->bssid, phy->mt76->macaddr, ETH_ALEN); + } + return 0; } @@ -863,6 +870,7 @@ mt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); switch (vif->type) { + case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: if (vif->p2p) @@ -929,7 +937,7 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (enable) mt7615_mcu_bss_omac_tlv(skb, vif); - mt7615_mcu_bss_basic_tlv(skb, vif, sta, enable); + mt7615_mcu_bss_basic_tlv(skb, vif, sta, phy, enable); if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START && mvif->mt76.omac_idx < REPEATER_BSSID_START) @@ -2761,53 +2769,3 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_ROC, &req, sizeof(req), false); } - -int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow; - struct mt7615_dev *dev = mt7615_hw_dev(hw); - struct { - __le32 ct_win; - u8 bss_idx; - u8 rsv[3]; - } __packed req = { - .ct_win = cpu_to_le32(ct_window), - .bss_idx = mvif->mt76.idx, - }; - - if (!mt7615_firmware_offload(dev)) - return -ENOTSUPP; - - return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS, &req, - sizeof(req), false); -} - -u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset) -{ - struct { - __le32 addr; - __le32 val; - } __packed req = { - .addr = cpu_to_le32(offset), - }; - - return mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, &req, sizeof(req), - true); -} -EXPORT_SYMBOL_GPL(mt7615_mcu_reg_rr); - -void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val) -{ - struct { - __le32 addr; - __le32 val; - } __packed req = { - .addr = cpu_to_le32(offset), - .val = cpu_to_le32(val), - }; - - mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, &req, sizeof(req), false); -} -EXPORT_SYMBOL_GPL(mt7615_mcu_reg_wr); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index d0c64a9b09cf..6ff6d5800918 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -107,6 +107,18 @@ struct mt7615_wtbl_rate_desc { struct mt7615_sta *sta; }; +struct mt7663s_intr { + u32 isr; + struct { + u32 wtqcr[8]; + } tx; + struct { + u16 num[2]; + u16 len[2][16]; + } rx; + u32 rec_mb[2]; +} __packed; + struct mt7615_sta { struct mt76_wcid wcid; /* must be first */ @@ -541,8 +553,6 @@ int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); -int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration); @@ -555,8 +565,6 @@ int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy, int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable); int __mt7663_load_firmware(struct mt7615_dev *dev); -u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset); -void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val); void mt7615_coredump_work(struct work_struct *work); void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en); @@ -573,10 +581,6 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev); int mt7663u_mcu_init(struct mt7615_dev *dev); /* sdio */ -u32 mt7663s_read_pcr(struct mt7615_dev *dev); int mt7663s_mcu_init(struct mt7615_dev *dev); -void mt7663s_txrx_worker(struct mt76_worker *w); -void mt7663s_rx_work(struct work_struct *work); -void mt7663s_sdio_irq(struct sdio_func *func); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 11f169cdd603..b808248943ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -39,7 +39,7 @@ static int mt7615_pci_probe(struct pci_dev *pdev, if (ret < 0) return ret; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) goto error; @@ -164,12 +164,14 @@ static int mt7615_pci_resume(struct pci_dev *pdev) dev_err(mdev->dev, "PDMA engine must be reinitialized\n"); mt76_worker_enable(&mdev->tx_worker); + local_bh_disable(); mt76_for_each_q_rx(mdev, i) { napi_enable(&mdev->napi[i]); napi_schedule(&mdev->napi[i]); } napi_enable(&mdev->tx_napi); napi_schedule(&mdev->tx_napi); + local_bh_enable(); if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index da87c02a73eb..5ee52cd70a4b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -198,7 +198,7 @@ void mt7615_dma_reset(struct mt7615_dev *dev) mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_reset(dev, i); - mt76_tx_status_check(&dev->mt76, NULL, true); + mt76_tx_status_check(&dev->mt76, true); mt7615_dma_start(dev); } @@ -326,6 +326,8 @@ void mt7615_mac_reset_work(struct work_struct *work) clear_bit(MT76_RESET, &phy2->mt76->state); mt76_worker_enable(&dev->mt76.tx_worker); + + local_bh_disable(); napi_enable(&dev->mt76.tx_napi); napi_schedule(&dev->mt76.tx_napi); @@ -334,6 +336,7 @@ void mt7615_mac_reset_work(struct work_struct *work) napi_enable(&dev->mt76.napi[1]); napi_schedule(&dev->mt76.napi[1]); + local_bh_enable(); ieee80211_wake_queues(mt76_hw(dev)); if (ext_phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index 305bb8597531..31c4a76b7f91 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -14,8 +14,8 @@ #include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_func.h> +#include "../sdio.h" #include "mt7615.h" -#include "sdio.h" #include "mac.h" #include "mcu.h" @@ -24,200 +24,19 @@ static const struct sdio_device_id mt7663s_table[] = { { } /* Terminating entry */ }; -static u32 mt7663s_read_whisr(struct mt76_dev *dev) +static void mt7663s_txrx_worker(struct mt76_worker *w) { - return sdio_readl(dev->sdio.func, MCR_WHISR, NULL); -} - -u32 mt7663s_read_pcr(struct mt7615_dev *dev) -{ - struct mt76_sdio *sdio = &dev->mt76.sdio; - - return sdio_readl(sdio->func, MCR_WHLPCR, NULL); -} - -static u32 mt7663s_read_mailbox(struct mt76_dev *dev, u32 offset) -{ - struct sdio_func *func = dev->sdio.func; - u32 val = ~0, status; - int err; - - sdio_claim_host(func); - - sdio_writel(func, offset, MCR_H2DSM0R, &err); - if (err < 0) { - dev_err(dev->dev, "failed setting address [err=%d]\n", err); - goto out; - } - - sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err); - if (err < 0) { - dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); - goto out; - } - - err = readx_poll_timeout(mt7663s_read_whisr, dev, status, - status & H2D_SW_INT_READ, 0, 1000000); - if (err < 0) { - dev_err(dev->dev, "query whisr timeout\n"); - goto out; - } - - sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err); - if (err < 0) { - dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); - goto out; - } - - val = sdio_readl(func, MCR_H2DSM0R, &err); - if (err < 0) { - dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); - goto out; - } - - if (val != offset) { - dev_err(dev->dev, "register mismatch\n"); - val = ~0; - goto out; - } - - val = sdio_readl(func, MCR_D2HRM1R, &err); - if (err < 0) - dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err); - -out: - sdio_release_host(func); - - return val; -} - -static void mt7663s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val) -{ - struct sdio_func *func = dev->sdio.func; - u32 status; - int err; - - sdio_claim_host(func); - - sdio_writel(func, offset, MCR_H2DSM0R, &err); - if (err < 0) { - dev_err(dev->dev, "failed setting address [err=%d]\n", err); - goto out; - } - - sdio_writel(func, val, MCR_H2DSM1R, &err); - if (err < 0) { - dev_err(dev->dev, - "failed setting write value [err=%d]\n", err); - goto out; - } - - sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err); - if (err < 0) { - dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); - goto out; - } - - err = readx_poll_timeout(mt7663s_read_whisr, dev, status, - status & H2D_SW_INT_WRITE, 0, 1000000); - if (err < 0) { - dev_err(dev->dev, "query whisr timeout\n"); - goto out; - } - - sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err); - if (err < 0) { - dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); - goto out; - } - - val = sdio_readl(func, MCR_H2DSM0R, &err); - if (err < 0) { - dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); - goto out; - } - - if (val != offset) - dev_err(dev->dev, "register mismatch\n"); - -out: - sdio_release_host(func); -} - -static u32 mt7663s_rr(struct mt76_dev *dev, u32 offset) -{ - if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) - return dev->mcu_ops->mcu_rr(dev, offset); - else - return mt7663s_read_mailbox(dev, offset); -} - -static void mt7663s_wr(struct mt76_dev *dev, u32 offset, u32 val) -{ - if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) - dev->mcu_ops->mcu_wr(dev, offset, val); - else - mt7663s_write_mailbox(dev, offset, val); -} + struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, + txrx_worker); + struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); -static u32 mt7663s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) -{ - val |= mt7663s_rr(dev, offset) & ~mask; - mt7663s_wr(dev, offset, val); - - return val; -} - -static void mt7663s_write_copy(struct mt76_dev *dev, u32 offset, - const void *data, int len) -{ - const u32 *val = data; - int i; - - for (i = 0; i < len / sizeof(u32); i++) { - mt7663s_wr(dev, offset, val[i]); - offset += sizeof(u32); - } -} - -static void mt7663s_read_copy(struct mt76_dev *dev, u32 offset, - void *data, int len) -{ - u32 *val = data; - int i; - - for (i = 0; i < len / sizeof(u32); i++) { - val[i] = mt7663s_rr(dev, offset); - offset += sizeof(u32); - } -} - -static int mt7663s_wr_rp(struct mt76_dev *dev, u32 base, - const struct mt76_reg_pair *data, - int len) -{ - int i; - - for (i = 0; i < len; i++) { - mt7663s_wr(dev, data->reg, data->value); - data++; - } - - return 0; -} - -static int mt7663s_rd_rp(struct mt76_dev *dev, u32 base, - struct mt76_reg_pair *data, - int len) -{ - int i; - - for (i = 0; i < len; i++) { - data->value = mt7663s_rr(dev, data->reg); - data++; + if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { + queue_work(mdev->wq, &dev->pm.wake_work); + return; } - - return 0; + mt76s_txrx_worker(sdio); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static void mt7663s_init_work(struct work_struct *work) @@ -231,64 +50,24 @@ static void mt7663s_init_work(struct work_struct *work) mt7615_init_work(dev); } -static int mt7663s_hw_init(struct mt7615_dev *dev, struct sdio_func *func) +static int mt7663s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr) { - u32 status, ctrl; - int ret; - - sdio_claim_host(func); - - ret = sdio_enable_func(func); - if (ret < 0) - goto release; + struct mt76_sdio *sdio = &dev->sdio; + struct mt7663s_intr *irq_data = sdio->intr_data; + int i, err; - /* Get ownership from the device */ - sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR, - MCR_WHLPCR, &ret); - if (ret < 0) - goto disable_func; - - ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, - status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); - if (ret < 0) { - dev_err(dev->mt76.dev, "Cannot get ownership from device"); - goto disable_func; - } - - ret = sdio_set_block_size(func, 512); - if (ret < 0) - goto disable_func; - - /* Enable interrupt */ - sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret); - if (ret < 0) - goto disable_func; - - ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN; - sdio_writel(func, ctrl, MCR_WHIER, &ret); - if (ret < 0) - goto disable_func; - - /* set WHISR as read clear and Rx aggregation number as 16 */ - ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16); - sdio_writel(func, ctrl, MCR_WHCR, &ret); - if (ret < 0) - goto disable_func; - - ret = sdio_claim_irq(func, mt7663s_sdio_irq); - if (ret < 0) - goto disable_func; + err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data)); + if (err) + return err; - sdio_release_host(func); + intr->isr = irq_data->isr; + intr->rec_mb = irq_data->rec_mb; + intr->tx.wtqcr = irq_data->tx.wtqcr; + intr->rx.num = irq_data->rx.num; + for (i = 0; i < 2 ; i++) + intr->rx.len[i] = irq_data->rx.len[i]; return 0; - -disable_func: - sdio_disable_func(func); -release: - sdio_release_host(func); - - return ret; } static int mt7663s_probe(struct sdio_func *func, @@ -307,13 +86,13 @@ static int mt7663s_probe(struct sdio_func *func, .update_survey = mt7615_update_channel, }; static const struct mt76_bus_ops mt7663s_ops = { - .rr = mt7663s_rr, - .rmw = mt7663s_rmw, - .wr = mt7663s_wr, - .write_copy = mt7663s_write_copy, - .read_copy = mt7663s_read_copy, - .wr_rp = mt7663s_wr_rp, - .rd_rp = mt7663s_rd_rp, + .rr = mt76s_rr, + .rmw = mt76s_rmw, + .wr = mt76s_wr, + .write_copy = mt76s_write_copy, + .read_copy = mt76s_read_copy, + .wr_rp = mt76s_wr_rp, + .rd_rp = mt76s_rd_rp, .type = MT76_BUS_SDIO, }; struct ieee80211_ops *ops; @@ -341,7 +120,7 @@ static int mt7663s_probe(struct sdio_func *func, if (ret < 0) goto error; - ret = mt7663s_hw_init(dev, func); + ret = mt76s_hw_init(mdev, func, MT76_CONNAC_SDIO); if (ret) goto error; @@ -349,8 +128,9 @@ static int mt7663s_probe(struct sdio_func *func, (mt76_rr(dev, MT_HW_REV) & 0xff); dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + mdev->sdio.parse_irq = mt7663s_parse_intr; mdev->sdio.intr_data = devm_kmalloc(mdev->dev, - sizeof(struct mt76s_intr), + sizeof(struct mt7663s_intr), GFP_KERNEL); if (!mdev->sdio.intr_data) { ret = -ENOMEM; @@ -367,7 +147,11 @@ static int mt7663s_probe(struct sdio_func *func, } } - ret = mt76s_alloc_queues(&dev->mt76); + ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN); + if (ret) + goto error; + + ret = mt76s_alloc_tx(mdev); if (ret) goto error; @@ -432,7 +216,7 @@ static int mt7663s_suspend(struct device *dev) cancel_work_sync(&mdev->mt76.sdio.stat_work); clear_bit(MT76_READING_STATS, &mdev->mphy.state); - mt76_tx_status_check(&mdev->mt76, NULL, true); + mt76_tx_status_check(&mdev->mt76, true); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index 45c1cd3b9f49..dc9a2f0b45a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -10,11 +10,11 @@ #include <linux/module.h> #include <linux/iopoll.h> +#include "../sdio.h" #include "mt7615.h" #include "mac.h" #include "mcu.h" #include "regs.h" -#include "sdio.h" static int mt7663s_mcu_init_sched(struct mt7615_dev *dev) { @@ -27,6 +27,7 @@ static int mt7663s_mcu_init_sched(struct mt7615_dev *dev) MT_HIF1_MIN_QUOTA); sdio->sched.ple_data_quota = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + sdio->sched.pse_page_size = MT_PSE_PAGE_SZ; txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT, MT_PP_TXDWCNT_TX1_ADD_DW_CNT); sdio->sched.deficit = txdwcnt << 2; @@ -63,7 +64,7 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); - ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); if (ret < 0) { dev_err(dev->mt76.dev, "Cannot get ownership from device"); @@ -111,7 +112,7 @@ static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); - ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); if (ret < 0) { dev_err(dev->mt76.dev, "Cannot set ownership to device"); @@ -137,8 +138,8 @@ int mt7663s_mcu_init(struct mt7615_dev *dev) .mcu_skb_send_msg = mt7663s_mcu_send_message, .mcu_parse_response = mt7615_mcu_parse_response, .mcu_restart = mt7615_mcu_restart, - .mcu_rr = mt7615_mcu_reg_rr, - .mcu_wr = mt7615_mcu_reg_wr, + .mcu_rr = mt76_connac_mcu_reg_rr, + .mcu_wr = mt76_connac_mcu_reg_wr, }; struct mt7615_mcu_ops *mcu_ops; int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index 996d48cca18a..bd2939ebcbf4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -169,7 +169,7 @@ bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update) mt7615_mac_sta_poll(dev); mt7615_mutex_release(dev); - return 0; + return false; } EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index f49d97d0a1c5..e7f01c2978a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -85,9 +85,14 @@ struct mt76_connac_coredump { extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; +static inline bool is_mt7922(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7922; +} + static inline bool is_mt7921(struct mt76_dev *dev) { - return mt76_chip(dev) == 0x7961; + return mt76_chip(dev) == 0x7961 || is_mt7922(dev); } static inline bool is_mt7663(struct mt76_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 5c3a81e5f559..32e25180fc1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -74,7 +74,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_init_download); int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy) { - struct mt76_dev *dev = phy->dev; + int len, i, n_max_channels, n_2ch = 0, n_5ch = 0, n_6ch = 0; struct mt76_connac_mcu_channel_domain { u8 alpha2[4]; /* regulatory_request.alpha2 */ u8 bw_2g; /* BW_20_40M 0 @@ -84,25 +84,29 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy) * BW_20_40_80_8080M 4 */ u8 bw_5g; - __le16 pad; + u8 bw_6g; + u8 pad; u8 n_2ch; u8 n_5ch; - __le16 pad2; + u8 n_6ch; + u8 pad2; } __packed hdr = { .bw_2g = 0, - .bw_5g = 3, + .bw_5g = 3, /* BW_20_40_80_160M */ + .bw_6g = 3, }; struct mt76_connac_mcu_chan { __le16 hw_value; __le16 pad; __le32 flags; } __packed channel; - int len, i, n_max_channels, n_2ch = 0, n_5ch = 0; + struct mt76_dev *dev = phy->dev; struct ieee80211_channel *chan; struct sk_buff *skb; n_max_channels = phy->sband_2g.sband.n_channels + - phy->sband_5g.sband.n_channels; + phy->sband_5g.sband.n_channels + + phy->sband_6g.sband.n_channels; len = sizeof(hdr) + n_max_channels * sizeof(channel); skb = mt76_mcu_msg_alloc(dev, NULL, len); @@ -135,11 +139,24 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy) skb_put_data(skb, &channel, sizeof(channel)); n_5ch++; } + for (i = 0; i < phy->sband_6g.sband.n_channels; i++) { + chan = &phy->sband_6g.sband.channels[i]; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + channel.hw_value = cpu_to_le16(chan->hw_value); + channel.flags = cpu_to_le32(chan->flags); + channel.pad = 0; + + skb_put_data(skb, &channel, sizeof(channel)); + n_6ch++; + } BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(hdr.alpha2)); memcpy(hdr.alpha2, dev->alpha2, sizeof(dev->alpha2)); hdr.n_2ch = n_2ch; hdr.n_5ch = n_5ch; + hdr.n_6ch = n_6ch; memcpy(__skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); @@ -689,9 +706,9 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, if (ht_cap->ht_supported) mode |= PHY_TYPE_BIT_HT; - if (he_cap->has_he) + if (he_cap && he_cap->has_he) mode |= PHY_TYPE_BIT_HE; - } else if (band == NL80211_BAND_5GHZ) { + } else if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) { mode |= PHY_TYPE_BIT_OFDM; if (ht_cap->ht_supported) @@ -700,7 +717,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, if (vht_cap->vht_supported) mode |= PHY_TYPE_BIT_VHT; - if (he_cap->has_he) + if (he_cap && he_cap->has_he) mode |= PHY_TYPE_BIT_HE; } @@ -719,6 +736,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, struct sta_rec_state *state; struct sta_rec_phy *phy; struct tlv *tlv; + u16 supp_rates; /* starec ht */ if (sta->ht_cap.ht_supported) { @@ -748,12 +766,22 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, if (!is_mt7921(dev)) return; - if (sta->ht_cap.ht_supported) + if (sta->ht_cap.ht_supported || sta->he_cap.has_he) mt76_connac_mcu_sta_amsdu_tlv(skb, sta, vif); /* starec he */ - if (sta->he_cap.has_he) + if (sta->he_cap.has_he) { mt76_connac_mcu_sta_he_tlv(skb, sta); + if (band == NL80211_BAND_6GHZ && + sta_state == MT76_STA_INFO_STATE_ASSOC) { + struct sta_rec_he_6g_capa *he_6g_capa; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, + sizeof(*he_6g_capa)); + he_6g_capa = (struct sta_rec_he_6g_capa *)tlv; + he_6g_capa->capa = sta->he_6ghz_capa.capa; + } + } tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); phy = (struct sta_rec_phy *)tlv; @@ -767,7 +795,15 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); ra_info = (struct sta_rec_ra_info *)tlv; - ra_info->legacy = cpu_to_le16((u16)sta->supp_rates[band]); + + supp_rates = sta->supp_rates[band]; + if (band == NL80211_BAND_2GHZ) + supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) | + FIELD_PREP(RA_LEGACY_CCK, supp_rates & 0xf); + else + supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates); + + ra_info->legacy = cpu_to_le16(supp_rates); if (sta->ht_cap.ht_supported) memcpy(ra_info->rx_mcs_bitmask, sta->ht_cap.mcs.rx_mask, @@ -1145,7 +1181,7 @@ mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, if (he_cap->has_he) mode |= PHY_MODE_AX_24G; - } else if (band == NL80211_BAND_5GHZ) { + } else if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) { mode |= PHY_MODE_A; if (ht_cap->ht_supported) @@ -1154,8 +1190,12 @@ mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, if (vht_cap->vht_supported) mode |= PHY_MODE_AC; - if (he_cap->has_he) - mode |= PHY_MODE_AX_5G; + if (he_cap->has_he) { + if (band == NL80211_BAND_6GHZ) + mode |= PHY_MODE_AX_6G; + else + mode |= PHY_MODE_AX_5G; + } } return mode; @@ -1252,7 +1292,8 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, u8 short_st; u8 ht_op_info; u8 sco; - u8 pad[3]; + u8 band; + u8 pad[2]; } __packed rlm; } __packed rlm_req = { .hdr = { @@ -1268,13 +1309,19 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, .ht_op_info = 4, /* set HT 40M allowed */ .rx_streams = phy->chainmask, .short_st = true, + .band = band, }, }; int err, conn_type; - u8 idx; + u8 idx, basic_phy; idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; basic_req.basic.hw_bss_idx = idx; + if (band == NL80211_BAND_6GHZ) + basic_req.basic.phymode_ext = BIT(0); + + basic_phy = mt76_connac_get_phy_mode_v2(phy, vif, band, NULL); + basic_req.basic.nonht_basic_phy = cpu_to_le16(basic_phy); switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: @@ -1445,7 +1492,17 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, else chan = &req->channels[i]; - chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; + switch (scan_list[i]->band) { + case NL80211_BAND_2GHZ: + chan->band = 1; + break; + case NL80211_BAND_6GHZ: + chan->band = 3; + break; + default: + chan->band = 2; + break; + } chan->channel_num = scan_list[i]->hw_value; } req->channel_type = sreq->n_channels ? 4 : 0; @@ -1531,8 +1588,10 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, get_random_mask_addr(addr, sreq->mac_addr, sreq->mac_addr_mask); } - if (is_mt7921(phy->dev)) + if (is_mt7921(phy->dev)) { req->mt7921.bss_idx = mvif->idx; + req->mt7921.delay = cpu_to_le32(sreq->delay); + } req->ssids_num = sreq->n_ssids; for (i = 0; i < req->ssids_num; i++) { @@ -1554,7 +1613,18 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, req->channels_num = min_t(u8, sreq->n_channels, 64); for (i = 0; i < req->channels_num; i++) { chan = &req->channels[i]; - chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; + + switch (scan_list[i]->band) { + case NL80211_BAND_2GHZ: + chan->band = 1; + break; + case NL80211_BAND_6GHZ: + chan->band = 3; + break; + default: + chan->band = 2; + break; + } chan->channel_num = scan_list[i]->hw_value; } @@ -1652,6 +1722,61 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event); +static void mt76_connac_mcu_parse_tx_resource(struct mt76_dev *dev, + struct sk_buff *skb) +{ + struct mt76_sdio *sdio = &dev->sdio; + struct mt76_connac_tx_resource { + __le32 version; + __le32 pse_data_quota; + __le32 pse_mcu_quota; + __le32 ple_data_quota; + __le32 ple_mcu_quota; + __le16 pse_page_size; + __le16 ple_page_size; + u8 pp_padding; + u8 pad[3]; + } __packed * tx_res; + + tx_res = (struct mt76_connac_tx_resource *)skb->data; + sdio->sched.pse_data_quota = le32_to_cpu(tx_res->pse_data_quota); + sdio->sched.pse_mcu_quota = le32_to_cpu(tx_res->pse_mcu_quota); + sdio->sched.ple_data_quota = le32_to_cpu(tx_res->ple_data_quota); + sdio->sched.pse_page_size = le16_to_cpu(tx_res->pse_page_size); + sdio->sched.deficit = tx_res->pp_padding; +} + +static void mt76_connac_mcu_parse_phy_cap(struct mt76_dev *dev, + struct sk_buff *skb) +{ + struct mt76_connac_phy_cap { + u8 ht; + u8 vht; + u8 _5g; + u8 max_bw; + u8 nss; + u8 dbdc; + u8 tx_ldpc; + u8 rx_ldpc; + u8 tx_stbc; + u8 rx_stbc; + u8 hw_path; + u8 he; + } __packed * cap; + + enum { + WF0_24G, + WF0_5G + }; + + cap = (struct mt76_connac_phy_cap *)skb->data; + + dev->phy.antenna_mask = BIT(cap->nss) - 1; + dev->phy.chainmask = dev->phy.antenna_mask; + dev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G); + dev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G); +} + int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy) { struct mt76_connac_cap_hdr { @@ -1694,6 +1819,17 @@ int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy) case MT_NIC_CAP_6G: phy->cap.has_6ghz = skb->data[0]; break; + case MT_NIC_CAP_MAC_ADDR: + memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN); + break; + case MT_NIC_CAP_PHY: + mt76_connac_mcu_parse_phy_cap(phy->dev, skb); + break; + case MT_NIC_CAP_TX_RESOURCE: + if (mt76_is_sdio(phy->dev)) + mt76_connac_mcu_parse_tx_resource(phy->dev, + skb); + break; default: break; } @@ -1749,6 +1885,70 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, } } +static s8 mt76_connac_get_sar_power(struct mt76_phy *phy, + struct ieee80211_channel *chan, + s8 target_power) +{ + const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; + struct mt76_freq_range_power *frp = phy->frp; + int freq, i; + + if (!capa || !frp) + return target_power; + + freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); + for (i = 0 ; i < capa->num_freq_ranges; i++) { + if (frp[i].range && + freq >= frp[i].range->start_freq && + freq < frp[i].range->end_freq) { + target_power = min_t(s8, frp[i].power, target_power); + break; + } + } + + return target_power; +} + +static s8 mt76_connac_get_ch_power(struct mt76_phy *phy, + struct ieee80211_channel *chan, + s8 target_power) +{ + struct mt76_dev *dev = phy->dev; + struct ieee80211_supported_band *sband; + int i; + + switch (chan->band) { + case NL80211_BAND_2GHZ: + sband = &phy->sband_2g.sband; + break; + case NL80211_BAND_5GHZ: + sband = &phy->sband_5g.sband; + break; + case NL80211_BAND_6GHZ: + sband = &phy->sband_6g.sband; + break; + default: + return target_power; + } + + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *ch = &sband->channels[i]; + + if (ch->hw_value == chan->hw_value) { + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) { + int power = 2 * ch->max_reg_power; + + if (is_mt7663(dev) && (power > 63 || power < -64)) + power = 63; + target_power = min_t(s8, power, target_power); + } + break; + } + } + + return target_power; +} + static int mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, enum nl80211_band band) @@ -1768,6 +1968,24 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, 142, 144, 149, 151, 153, 155, 157, 159, 161, 165 }; + static const u8 chan_list_6ghz[] = { + 1, 3, 5, 7, 9, 11, 13, + 15, 17, 19, 21, 23, 25, 27, + 29, 33, 35, 37, 39, 41, 43, + 45, 47, 49, 51, 53, 55, 57, + 59, 61, 65, 67, 69, 71, 73, + 75, 77, 79, 81, 83, 85, 87, + 89, 91, 93, 97, 99, 101, 103, + 105, 107, 109, 111, 113, 115, 117, + 119, 121, 123, 125, 129, 131, 133, + 135, 137, 139, 141, 143, 145, 147, + 149, 151, 153, 155, 157, 161, 163, + 165, 167, 169, 171, 173, 175, 177, + 179, 181, 183, 185, 187, 189, 193, + 195, 197, 199, 201, 203, 205, 207, + 209, 211, 213, 215, 217, 219, 221, + 225, 227, 229, 233 + }; int i, n_chan, batch_size, idx = 0, tx_power, last_ch; struct mt76_connac_sku_tlv sku_tlbv; struct mt76_power_limits limits; @@ -1781,6 +1999,9 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, if (band == NL80211_BAND_2GHZ) { n_chan = ARRAY_SIZE(chan_list_2ghz); ch_list = chan_list_2ghz; + } else if (band == NL80211_BAND_6GHZ) { + n_chan = ARRAY_SIZE(chan_list_6ghz); + ch_list = chan_list_6ghz; } else { n_chan = ARRAY_SIZE(chan_list_5ghz); ch_list = chan_list_5ghz; @@ -1789,13 +2010,13 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, if (!phy->cap.has_5ghz) last_ch = chan_list_2ghz[n_chan - 1]; + else if (phy->cap.has_6ghz) + last_ch = chan_list_6ghz[n_chan - 1]; else last_ch = chan_list_5ghz[n_chan - 1]; for (i = 0; i < batch_size; i++) { - struct mt76_connac_tx_power_limit_tlv tx_power_tlv = { - .band = band == NL80211_BAND_2GHZ ? 1 : 2, - }; + struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {}; int j, err, msg_len, num_ch; struct sk_buff *skb; @@ -1811,14 +2032,32 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2)); tx_power_tlv.n_chan = num_ch; + switch (band) { + case NL80211_BAND_2GHZ: + tx_power_tlv.band = 1; + break; + case NL80211_BAND_6GHZ: + tx_power_tlv.band = 3; + break; + default: + tx_power_tlv.band = 2; + break; + } + for (j = 0; j < num_ch; j++, idx++) { struct ieee80211_channel chan = { .hw_value = ch_list[idx], .band = band, }; + s8 reg_power, sar_power; + + reg_power = mt76_connac_get_ch_power(phy, &chan, + tx_power); + sar_power = mt76_connac_get_sar_power(phy, &chan, + reg_power); mt76_get_rate_power_limits(phy, &chan, &limits, - tx_power); + sar_power); tx_power_tlv.last_msg = ch_list[idx] == last_ch; sku_tlbv.channel = ch_list[idx]; @@ -1855,6 +2094,12 @@ int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy) if (err < 0) return err; } + if (phy->cap.has_6ghz) { + err = mt76_connac_mcu_rate_txpower_band(phy, + NL80211_BAND_6GHZ); + if (err < 0) + return err; + } return 0; } @@ -1902,6 +2147,26 @@ int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_arp_filter); +int mt76_connac_mcu_set_p2p_oppps(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow; + struct mt76_phy *phy = hw->priv; + struct { + __le32 ct_win; + u8 bss_idx; + u8 rsv[3]; + } __packed req = { + .ct_win = cpu_to_le32(ct_window), + .bss_idx = mvif->idx, + }; + + return mt76_mcu_send_msg(phy->dev, MCU_CMD_SET_P2P_OPPPS, &req, + sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_p2p_oppps); + #ifdef CONFIG_PM const struct wiphy_wowlan_support mt76_connac_wowlan_support = { @@ -1929,19 +2194,22 @@ mt76_connac_mcu_key_iter(struct ieee80211_hw *hw, key->cipher != WLAN_CIPHER_SUITE_TKIP) return; - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1); + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) cipher = BIT(3); - } else { - gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2); + else cipher = BIT(4); - } /* we are assuming here to have a single pairwise key */ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) + gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1); + else + gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2); + gtk_tlv->pairwise_cipher = cpu_to_le32(cipher); - gtk_tlv->group_cipher = cpu_to_le32(cipher); gtk_tlv->keyid = key->keyidx; + } else { + gtk_tlv->group_cipher = cpu_to_le32(cipher); } } @@ -2210,6 +2478,33 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_iter); +u32 mt76_connac_mcu_reg_rr(struct mt76_dev *dev, u32 offset) +{ + struct { + __le32 addr; + __le32 val; + } __packed req = { + .addr = cpu_to_le32(offset), + }; + + return mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, &req, sizeof(req), + true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_rr); + +void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val) +{ + struct { + __le32 addr; + __le32 val; + } __packed req = { + .addr = cpu_to_le32(offset), + .val = cpu_to_le32(val), + }; + + mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, &req, sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_wr); #endif /* CONFIG_PM */ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 1c73beb22677..b89faab04996 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -124,6 +124,8 @@ struct sta_rec_state { u8 rsv[1]; } __packed; +#define RA_LEGACY_OFDM GENMASK(13, 6) +#define RA_LEGACY_CCK GENMASK(3, 0) #define HT_MCS_MASK_NUM 10 struct sta_rec_ra_info { __le16 tag; @@ -143,6 +145,13 @@ struct sta_rec_phy { u8 rsv[2]; } __packed; +struct sta_rec_he_6g_capa { + __le16 tag; + __le16 len; + __le16 capa; + u8 rsv[2]; +} __packed; + /* wtbl_rec */ struct wtbl_req_hdr { @@ -301,6 +310,7 @@ struct wtbl_raw { sizeof(struct sta_rec_vht) + \ sizeof(struct sta_rec_uapsd) + \ sizeof(struct sta_rec_amsdu) + \ + sizeof(struct sta_rec_he_6g_capa) + \ sizeof(struct tlv) + \ MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) @@ -327,6 +337,7 @@ enum { STA_REC_MUEDCA, STA_REC_BFEE, STA_REC_PHY = 0x15, + STA_REC_HE_6G = 0x17, STA_REC_MAX_NUM }; @@ -548,6 +559,7 @@ enum { /* offload mcu commands */ enum { + MCU_CMD_TEST_CTRL = MCU_CE_PREFIX | 0x01, MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, MCU_CMD_SET_PS_PROFILE = MCU_CE_PREFIX | 0x05, MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, @@ -560,6 +572,7 @@ enum { MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, MCU_CMD_GET_NIC_CAPAB = MCU_CE_PREFIX | 0x8a, + MCU_CMD_SET_MU_EDCA_PARMS = MCU_CE_PREFIX | 0xb0, MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0, MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0, MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca, @@ -656,10 +669,14 @@ struct mt76_connac_bss_basic_tlv { * bit(3): GN * bit(4): AN * bit(5): AC + * bit(6): AX2 + * bit(7): AX5 + * bit(8): AX6 */ __le16 sta_idx; - u8 nonht_basic_phy; - u8 pad[3]; + __le16 nonht_basic_phy; + u8 phymode_ext; /* bit(0) AX_6G */ + u8 pad[1]; } __packed; struct mt76_connac_bss_qos_tlv { @@ -802,7 +819,9 @@ struct mt76_connac_sched_scan_req { } mt7663; struct { u8 bss_idx; - u8 pad2[19]; + u8 pad1[3]; + __le32 delay; + u8 pad2[12]; u8 random_mac[ETH_ALEN]; u8 pad3[38]; } mt7921; @@ -844,14 +863,14 @@ struct mt76_connac_gtk_rekey_tlv { * 2: rekey update */ u8 keyid; - u8 pad[2]; + u8 option; /* 1: rekey data update without enabling offload */ + u8 pad[1]; __le32 proto; /* WPA-RSN-WAPI-OPSN */ __le32 pairwise_cipher; __le32 group_cipher; __le32 key_mgmt; /* NONE-PSK-IEEE802.1X */ __le32 mgmt_group_cipher; - u8 option; /* 1: rekey data update without enabling offload */ - u8 reserverd[3]; + u8 reserverd[4]; } __packed; #define MT76_CONNAC_WOW_MASK_MAX_LEN 16 @@ -961,7 +980,7 @@ struct mt76_connac_tx_power_limit_tlv { __le16 len; /* DW1 - cmd hint */ u8 n_chan; /* # channel */ - u8 band; /* 2.4GHz - 5GHz */ + u8 band; /* 2.4GHz - 5GHz - 6GHz */ u8 last_msg; u8 pad1; /* DW3 */ @@ -1093,4 +1112,8 @@ int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable); void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, struct mt76_connac_coredump *coredump); int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy); +int mt76_connac_mcu_set_p2p_oppps(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +u32 mt76_connac_mcu_reg_rr(struct mt76_dev *dev, u32 offset); +void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val); #endif /* __MT76_CONNAC_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index cea24213186c..da2ca2563ac9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -201,7 +201,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev, t->stbc[6] = t->stbc[7] = s6_to_s8(val >> 8); /* vht mcs 8, 9 5GHz */ - val = mt76x02_eeprom_get(dev, 0x132); + val = mt76x02_eeprom_get(dev, 0x12c); t->vht[8] = s6_to_s8(val); t->vht[9] = s6_to_s8(val >> 8); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index b795e7245c07..f19228fc5a70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -176,7 +176,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -276,6 +276,7 @@ static int mt76x0e_resume(struct pci_dev *pdev) mt76_worker_enable(&mdev->tx_worker); + local_bh_disable(); mt76_for_each_q_rx(mdev, i) { mt76_queue_rx_reset(dev, i); napi_enable(&mdev->napi[i]); @@ -284,6 +285,7 @@ static int mt76x0e_resume(struct pci_dev *pdev) napi_enable(&mdev->tx_napi); napi_schedule(&mdev->tx_napi); + local_bh_enable(); return mt76x0e_init_hardware(dev, true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index c32e6dc68773..a404fd7ea968 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -176,7 +176,7 @@ void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop) mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); } -static __le16 +static u16 mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val) { @@ -222,14 +222,14 @@ mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev, rateval |= MT_RXWI_RATE_SGI; *nss_val = nss; - return cpu_to_le16(rateval); + return rateval; } void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate) { s8 max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); - __le16 rateval; + u16 rateval; u32 tx_info; s8 nss; @@ -342,7 +342,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct ieee80211_key_conf *key = info->control.hw_key; u32 wcid_tx_info; u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); - u16 txwi_flags = 0; + u16 txwi_flags = 0, rateval; u8 nss; s8 txpwr_adj, max_txpwr_adj; u8 ccmp_pn[8], nstreams = dev->mphy.chainmask & 0xf; @@ -380,14 +380,15 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, if (wcid && (rate->idx < 0 || !rate->count)) { wcid_tx_info = wcid->tx_info; - txwi->rate = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info); + rateval = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info); max_txpwr_adj = FIELD_GET(MT_WCID_TX_INFO_TXPWR_ADJ, wcid_tx_info); nss = FIELD_GET(MT_WCID_TX_INFO_NSS, wcid_tx_info); } else { - txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss); + rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss); max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); } + txwi->rate = cpu_to_le16(rateval); txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->txpower_conf, max_txpwr_adj); @@ -1185,7 +1186,7 @@ void mt76x02_mac_work(struct work_struct *work) mutex_unlock(&dev->mt76.mutex); - mt76_tx_status_check(&dev->mt76, NULL, false); + mt76_tx_status_check(&dev->mt76, false); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index b50084bbe83d..ec0de691129a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -53,7 +53,7 @@ static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t) mt76_skb_set_moredata(data.tail[i], false); } - spin_lock_bh(&q->lock); + spin_lock(&q->lock); while ((skb = __skb_dequeue(&data.q)) != NULL) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; @@ -61,7 +61,7 @@ static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t) mt76_tx_queue_skb(dev, q, skb, &mvif->group_wcid, NULL); } - spin_unlock_bh(&q->lock); + spin_unlock(&q->lock); } static void mt76x02e_pre_tbtt_enable(struct mt76x02_dev *dev, bool en) @@ -472,7 +472,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) mt76_queue_rx_reset(dev, i); } - mt76_tx_status_check(&dev->mt76, NULL, true); + mt76_tx_status_check(&dev->mt76, true); mt76x02_mac_start(dev); @@ -491,15 +491,17 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) clear_bit(MT76_RESET, &dev->mphy.state); mt76_worker_enable(&dev->mt76.tx_worker); + tasklet_enable(&dev->mt76.pre_tbtt_tasklet); + + local_bh_disable(); napi_enable(&dev->mt76.tx_napi); napi_schedule(&dev->mt76.tx_napi); - tasklet_enable(&dev->mt76.pre_tbtt_tasklet); - mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); } + local_bh_enable(); if (restart) { set_bit(MT76_RESTART, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index ccdbab341271..1f17d86ff755 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -287,6 +287,8 @@ mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, mvif->idx = idx; mvif->group_wcid.idx = MT_VIF_WCID(idx); mvif->group_wcid.hw_key_idx = -1; + mt76_packet_id_init(&mvif->group_wcid); + mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = &mvif->group_wcid; } @@ -341,6 +343,7 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw, struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; dev->mt76.vif_mask &= ~BIT(mvif->idx); + mt76_packet_id_flush(&dev->mt76, &mvif->group_wcid); } EXPORT_SYMBOL_GPL(mt76x02_remove_interface); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index adf288e50e21..8a22ee581674 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -47,7 +47,7 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -149,12 +149,15 @@ mt76x2e_resume(struct pci_dev *pdev) pci_restore_state(pdev); mt76_worker_enable(&mdev->tx_worker); + + local_bh_disable(); mt76_for_each_q_rx(mdev, i) { napi_enable(&mdev->napi[i]); napi_schedule(&mdev->napi[i]); } napi_enable(&mdev->tx_napi); napi_schedule(&mdev->tx_napi); + local_bh_enable(); return mt76x2_resume_device(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 64048243e34b..4b7f38fcbe64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -7,6 +7,13 @@ /** global debugfs **/ +struct hw_queue_map { + const char *name; + u8 index; + u8 pid; + u8 qid; +}; + static int mt7915_implicit_txbf_set(void *data, u64 val) { @@ -113,13 +120,10 @@ static void mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, struct seq_file *file) { - struct mt7915_dev *dev = file->private; + struct mt7915_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; int bound[15], range[4], i, n; - if (!phy) - return; - /* Tx ampdu stat */ for (i = 0; i < ARRAY_SIZE(range); i++) range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i)); @@ -146,56 +150,46 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, static void mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) { - struct mt7915_dev *dev = s->private; - bool ext_phy = phy != &dev->phy; static const char * const bw[] = { "BW20", "BW40", "BW80", "BW160" }; - int cnt; - - if (!phy) - return; + struct mib_stats *mib = &phy->mib; /* Tx Beamformer monitor */ seq_puts(s, "\nTx Beamformer applied PPDU counts: "); - cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy)); - seq_printf(s, "iBF: %ld, eBF: %ld\n", - FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt), - FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt)); + seq_printf(s, "iBF: %d, eBF: %d\n", + mib->tx_bf_ibf_ppdu_cnt, + mib->tx_bf_ebf_ppdu_cnt); /* Tx Beamformer Rx feedback monitor */ seq_puts(s, "Tx Beamformer Rx feedback statistics: "); - cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy)); - seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld, ", - FIELD_GET(MT_ETBF_RX_FB_ALL, cnt), - FIELD_GET(MT_ETBF_RX_FB_HE, cnt), - FIELD_GET(MT_ETBF_RX_FB_VHT, cnt), - FIELD_GET(MT_ETBF_RX_FB_HT, cnt)); - cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy)); - seq_printf(s, "%s, NC: %ld, NR: %ld\n", - bw[FIELD_GET(MT_ETBF_RX_FB_BW, cnt)], - FIELD_GET(MT_ETBF_RX_FB_NC, cnt), - FIELD_GET(MT_ETBF_RX_FB_NR, cnt)); + seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", + mib->tx_bf_rx_fb_all_cnt, + mib->tx_bf_rx_fb_he_cnt, + mib->tx_bf_rx_fb_vht_cnt, + mib->tx_bf_rx_fb_ht_cnt); + + seq_printf(s, "%s, NC: %d, NR: %d\n", + bw[mib->tx_bf_rx_fb_bw], + mib->tx_bf_rx_fb_nc_cnt, + mib->tx_bf_rx_fb_nr_cnt); /* Tx Beamformee Rx NDPA & Tx feedback report */ - cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy)); - seq_printf(s, "Tx Beamformee successful feedback frames: %ld\n", - FIELD_GET(MT_ETBF_TX_FB_CPL, cnt)); - seq_printf(s, "Tx Beamformee feedback triggered counts: %ld\n", - FIELD_GET(MT_ETBF_TX_FB_TRI, cnt)); + seq_printf(s, "Tx Beamformee successful feedback frames: %d\n", + mib->tx_bf_fb_cpl_cnt); + seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n", + mib->tx_bf_fb_trig_cnt); /* Tx SU & MU counters */ - cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy)); - seq_printf(s, "Tx multi-user Beamforming counts: %ld\n", - FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt)); - cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy)); - seq_printf(s, "Tx multi-user MPDU counts: %d\n", cnt); - cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy)); - seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", cnt); - cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy)); - seq_printf(s, "Tx single-user successful MPDU counts: %d\n", cnt); + seq_printf(s, "Tx multi-user Beamforming counts: %d\n", + mib->tx_bf_cnt); + seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt); + seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", + mib->tx_mu_acked_mpdu_cnt); + seq_printf(s, "Tx single-user successful MPDU counts: %d\n", + mib->tx_su_acked_mpdu_cnt); seq_puts(s, "\n"); } @@ -203,91 +197,189 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) static int mt7915_tx_stats_show(struct seq_file *file, void *data) { - struct mt7915_dev *dev = file->private; - int stat[8], i, n; + struct mt7915_phy *phy = file->private; + struct mt7915_dev *dev = phy->dev; + struct mib_stats *mib = &phy->mib; + int i; - mt7915_ampdu_stat_read_phy(&dev->phy, file); - mt7915_txbf_stat_read_phy(&dev->phy, file); + mutex_lock(&dev->mt76.mutex); - mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file); - mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file); + mt7915_ampdu_stat_read_phy(phy, file); + mt7915_mac_update_stats(phy); + mt7915_txbf_stat_read_phy(phy, file); /* Tx amsdu info */ seq_puts(file, "Tx MSDU statistics:\n"); - for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { - stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); - n += stat[i]; - } - - for (i = 0; i < ARRAY_SIZE(stat); i++) { - seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ", - i + 1, stat[i]); - if (n != 0) - seq_printf(file, "(%d%%)\n", stat[i] * 100 / n); + for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { + seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ", + i + 1, mib->tx_amsdu[i]); + if (mib->tx_amsdu_cnt) + seq_printf(file, "(%3d%%)\n", + mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt); else seq_puts(file, "\n"); } + mutex_unlock(&dev->mt76.mutex); + return 0; } DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats); -static int -mt7915_queues_acq(struct seq_file *s, void *data) +static void +mt7915_hw_queue_read(struct seq_file *s, u32 base, u32 size, + const struct hw_queue_map *map) { - struct mt7915_dev *dev = dev_get_drvdata(s->private); - int i; + struct mt7915_phy *phy = s->private; + struct mt7915_dev *dev = phy->dev; + u32 i, val; - for (i = 0; i < 16; i++) { - int j, acs = i / 4, index = i % 4; - u32 ctrl, val, qlen = 0; + val = mt76_rr(dev, base + MT_FL_Q_EMPTY); + for (i = 0; i < size; i++) { + u32 ctrl, head, tail, queued; - val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); - ctrl = BIT(31) | BIT(15) | (acs << 8); + if (val & BIT(map[i].index)) + continue; - for (j = 0; j < 32; j++) { - if (val & BIT(j)) - continue; + ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24); + mt76_wr(dev, base + MT_FL_Q0_CTRL, ctrl); - mt76_wr(dev, MT_PLE_FL_Q0_CTRL, - ctrl | (j + (index << 5))); - qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, - GENMASK(11, 0)); - } - seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); + head = mt76_get_field(dev, base + MT_FL_Q2_CTRL, + GENMASK(11, 0)); + tail = mt76_get_field(dev, base + MT_FL_Q2_CTRL, + GENMASK(27, 16)); + queued = mt76_get_field(dev, base + MT_FL_Q3_CTRL, + GENMASK(11, 0)); + + seq_printf(s, "\t%s: ", map[i].name); + seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n", + queued, head, tail); } +} + +static void +mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = msta->vif->phy->dev; + struct seq_file *s = data; + u8 ac; + + for (ac = 0; ac < 4; ac++) { + u32 qlen, ctrl, val; + u32 idx = msta->wcid.idx >> 5; + u8 offs = msta->wcid.idx & GENMASK(4, 0); + + ctrl = BIT(31) | BIT(11) | (ac << 24); + val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx)); + + if (val & BIT(offs)) + continue; + + mt76_wr(dev, MT_PLE_BASE + MT_FL_Q0_CTRL, ctrl | msta->wcid.idx); + qlen = mt76_get_field(dev, MT_PLE_BASE + MT_FL_Q3_CTRL, + GENMASK(11, 0)); + seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n", + sta->addr, msta->wcid.idx, msta->vif->wmm_idx, + ac, qlen); + } +} + +static int +mt7915_hw_queues_show(struct seq_file *file, void *data) +{ + struct mt7915_phy *phy = file->private; + struct mt7915_dev *dev = phy->dev; + static const struct hw_queue_map ple_queue_map[] = { + { "CPU_Q0", 0, 1, MT_CTX0 }, + { "CPU_Q1", 1, 1, MT_CTX0 + 1 }, + { "CPU_Q2", 2, 1, MT_CTX0 + 2 }, + { "CPU_Q3", 3, 1, MT_CTX0 + 3 }, + { "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 }, + { "BMC_Q0", 9, 2, MT_LMAC_BMC0 }, + { "BCN_Q0", 10, 2, MT_LMAC_BCN0 }, + { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 }, + { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 }, + { "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 }, + { "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 }, + { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 }, + }; + static const struct hw_queue_map pse_queue_map[] = { + { "CPU Q0", 0, 1, MT_CTX0 }, + { "CPU Q1", 1, 1, MT_CTX0 + 1 }, + { "CPU Q2", 2, 1, MT_CTX0 + 2 }, + { "CPU Q3", 3, 1, MT_CTX0 + 3 }, + { "HIF_Q0", 8, 0, MT_HIF0 }, + { "HIF_Q1", 9, 0, MT_HIF0 + 1 }, + { "HIF_Q2", 10, 0, MT_HIF0 + 2 }, + { "HIF_Q3", 11, 0, MT_HIF0 + 3 }, + { "HIF_Q4", 12, 0, MT_HIF0 + 4 }, + { "HIF_Q5", 13, 0, MT_HIF0 + 5 }, + { "LMAC_Q", 16, 2, 0 }, + { "MDP_TXQ", 17, 2, 1 }, + { "MDP_RXQ", 18, 2, 2 }, + { "SEC_TXQ", 19, 2, 3 }, + { "SEC_RXQ", 20, 2, 4 }, + }; + u32 val, head, tail; + + /* ple queue */ + val = mt76_rr(dev, MT_PLE_FREEPG_CNT); + head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0)); + tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16)); + seq_puts(file, "PLE page info:\n"); + seq_printf(file, + "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n", + val, head, tail); + + val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP); + head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0)); + tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16)); + seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", + val, head, tail); + + seq_puts(file, "PLE non-empty queue info:\n"); + mt7915_hw_queue_read(file, MT_PLE_BASE, ARRAY_SIZE(ple_queue_map), + &ple_queue_map[0]); + + /* iterate per-sta ple queue */ + ieee80211_iterate_stations_atomic(phy->mt76->hw, + mt7915_sta_hw_queue_read, file); + /* pse queue */ + seq_puts(file, "PSE non-empty queue info:\n"); + mt7915_hw_queue_read(file, MT_PSE_BASE, ARRAY_SIZE(pse_queue_map), + &pse_queue_map[0]); return 0; } +DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues); + static int -mt7915_queues_read(struct seq_file *s, void *data) +mt7915_xmit_queues_show(struct seq_file *file, void *data) { - struct mt7915_dev *dev = dev_get_drvdata(s->private); - struct mt76_phy *mphy_ext = dev->mt76.phy2; - struct mt76_queue *ext_q = mphy_ext ? mphy_ext->q_tx[MT_TXQ_BE] : NULL; + struct mt7915_phy *phy = file->private; + struct mt7915_dev *dev = phy->dev; struct { struct mt76_queue *q; char *queue; } queue_map[] = { - { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" }, - { ext_q, "WFDMA1" }, - { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" }, - { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" }, - { dev->mt76.q_mcu[MT_MCUQ_WA], "MCUWA" }, - { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" }, + { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" }, + { dev->mt76.q_mcu[MT_MCUQ_WM], " MCUWM" }, + { dev->mt76.q_mcu[MT_MCUQ_WA], " MCUWA" }, + { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" }, }; int i; + seq_puts(file, " queue | hw-queued | head | tail |\n"); for (i = 0; i < ARRAY_SIZE(queue_map); i++) { struct mt76_queue *q = queue_map[i].q; if (!q) continue; - seq_printf(s, - "%s: queued=%d head=%d tail=%d\n", + seq_printf(file, " %s | %9d | %9d | %9d |\n", queue_map[i].queue, q->queued, q->head, q->tail); } @@ -295,8 +387,10 @@ mt7915_queues_read(struct seq_file *s, void *data) return 0; } -static void -mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) +DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); + +static int +mt7915_rate_txpower_show(struct seq_file *file, void *data) { static const char * const sku_group_name[] = { "CCK", "OFDM", "HT20", "HT40", @@ -304,14 +398,11 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) "RU26", "RU52", "RU106", "RU242/SU20", "RU484/SU40", "RU996/SU80", "RU2x996/SU160" }; + struct mt7915_phy *phy = file->private; s8 txpower[MT7915_SKU_RATE_NUM], *buf; int i; - if (!phy) - return; - - seq_printf(s, "\nBand %d\n", phy != &phy->dev->phy); - + seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy); mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower)); for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { u8 mcs_num = mt7915_sku_group_len[i]; @@ -319,45 +410,70 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) mcs_num = 10; - mt76_seq_puts_array(s, sku_group_name[i], buf, mcs_num); + mt76_seq_puts_array(file, sku_group_name[i], buf, mcs_num); buf += mt7915_sku_group_len[i]; } + + return 0; } +DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower); + static int -mt7915_read_rate_txpower(struct seq_file *s, void *data) +mt7915_twt_stats(struct seq_file *s, void *data) { struct mt7915_dev *dev = dev_get_drvdata(s->private); + struct mt7915_twt_flow *iter; - mt7915_puts_rate_txpower(s, &dev->phy); - mt7915_puts_rate_txpower(s, mt7915_ext_phy(dev)); + rcu_read_lock(); + + seq_puts(s, " wcid | id | flags | exp | mantissa"); + seq_puts(s, " | duration | tsf |\n"); + list_for_each_entry_rcu(iter, &dev->twt_list, list) + seq_printf(s, + "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n", + iter->wcid, iter->id, + iter->sched ? 's' : 'u', + iter->protection ? 'p' : '-', + iter->trigger ? 't' : '-', + iter->flowtype ? '-' : 'a', + iter->exp, iter->mantissa, + iter->duration, iter->tsf); + + rcu_read_unlock(); return 0; } -int mt7915_init_debugfs(struct mt7915_dev *dev) +int mt7915_init_debugfs(struct mt7915_phy *phy) { + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; struct dentry *dir; - dir = mt76_register_debugfs(&dev->mt76); + dir = mt76_register_debugfs_fops(phy->mt76, NULL); if (!dir) return -ENOMEM; - debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, - mt7915_queues_read); - debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, - mt7915_queues_acq); - debugfs_create_file("tx_stats", 0400, dir, dev, &mt7915_tx_stats_fops); + debugfs_create_file("hw-queues", 0400, dir, phy, + &mt7915_hw_queues_fops); + debugfs_create_file("xmit-queues", 0400, dir, phy, + &mt7915_xmit_queues_fops); + debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops); debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); debugfs_create_file("implicit_txbf", 0600, dir, dev, &fops_implicit_txbf); - debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); - /* test knobs */ - debugfs_create_file("radar_trigger", 0200, dir, dev, - &fops_radar_trigger); + debugfs_create_file("txpower_sku", 0400, dir, phy, + &mt7915_rate_txpower_fops); + debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, + mt7915_twt_stats); debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); - debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir, - mt7915_read_rate_txpower); + if (!dev->dbdc_support || ext_phy) { + debugfs_create_u32("dfs_hw_pattern", 0400, dir, + &dev->hw_pattern); + debugfs_create_file("radar_trigger", 0200, dir, dev, + &fops_radar_trigger); + } return 0; } @@ -365,12 +481,14 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) #ifdef CONFIG_MAC80211_DEBUGFS /** per-station debugfs **/ -/* usage: <tx mode> <ldpc> <stbc> <bw> <gi> <nss> <mcs> */ static int mt7915_sta_fixed_rate_set(void *data, u64 rate) { struct ieee80211_sta *sta = data; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + /* usage: <he ltf> <tx mode> <ldpc> <stbc> <bw> <gi> <nss> <mcs> + * <tx mode>: see enum mt76_phy_type + */ return mt7915_mcu_set_fixed_rate(msta->vif->phy->dev, sta, rate); } @@ -378,55 +496,22 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL, mt7915_sta_fixed_rate_set, "%llx\n"); static int -mt7915_sta_stats_show(struct seq_file *s, void *data) +mt7915_queues_show(struct seq_file *s, void *data) { struct ieee80211_sta *sta = s->private; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct mt7915_sta_stats *stats = &msta->stats; - struct rate_info *rate = &stats->prob_rate; - static const char * const bw[] = { - "BW20", "BW5", "BW10", "BW40", - "BW80", "BW160", "BW_HE_RU" - }; - if (!rate->legacy && !rate->flags) - return 0; - - seq_puts(s, "Probing rate - "); - if (rate->flags & RATE_INFO_FLAGS_MCS) - seq_puts(s, "HT "); - else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) - seq_puts(s, "VHT "); - else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) - seq_puts(s, "HE "); - else - seq_printf(s, "Bitrate %d\n", rate->legacy); - - if (rate->flags) { - seq_printf(s, "%s NSS%d MCS%d ", - bw[rate->bw], rate->nss, rate->mcs); - - if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) - seq_puts(s, "SGI "); - else if (rate->he_gi) - seq_puts(s, "HE GI "); - - if (rate->he_dcm) - seq_puts(s, "DCM "); - } - - seq_printf(s, "\nPPDU PER: %ld.%1ld%%\n", - stats->per / 10, stats->per % 10); + mt7915_sta_hw_queue_read(s, sta); return 0; } -DEFINE_SHOW_ATTRIBUTE(mt7915_sta_stats); +DEFINE_SHOW_ATTRIBUTE(mt7915_queues); void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); - debugfs_create_file("stats", 0400, dir, sta, &mt7915_sta_stats_fops); + debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops); } + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 4798d6344305..4fa8e7ba93e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -42,13 +42,17 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; -static ssize_t mt7915_thermal_show_temp(struct device *dev, +static ssize_t mt7915_thermal_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mt7915_phy *phy = dev_get_drvdata(dev); + int i = to_sensor_dev_attr(attr)->index; int temperature; + if (i) + return sprintf(buf, "%u\n", phy->throttle_temp[i - 1] * 1000); + temperature = mt7915_mcu_get_temperature(phy); if (temperature < 0) return temperature; @@ -57,11 +61,34 @@ static ssize_t mt7915_thermal_show_temp(struct device *dev, return sprintf(buf, "%u\n", temperature * 1000); } -static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7915_thermal_show_temp, - NULL, 0); +static ssize_t mt7915_thermal_temp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mt7915_phy *phy = dev_get_drvdata(dev); + int ret, i = to_sensor_dev_attr(attr)->index; + long val; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + mutex_lock(&phy->dev->mt76.mutex); + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 60, 130); + phy->throttle_temp[i - 1] = val; + mutex_unlock(&phy->dev->mt76.mutex); + + return count; +} + +static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7915_thermal_temp, 0); +static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7915_thermal_temp, 1); +static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7915_thermal_temp, 2); static struct attribute *mt7915_hwmon_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, NULL, }; ATTRIBUTE_GROUPS(mt7915_hwmon); @@ -96,6 +123,9 @@ mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, if (state > MT7915_THERMAL_THROTTLE_MAX) return -EINVAL; + if (phy->throttle_temp[0] > phy->throttle_temp[1]) + return 0; + if (state == phy->throttle_state) return 0; @@ -130,9 +160,12 @@ static int mt7915_thermal_init(struct mt7915_phy *phy) struct wiphy *wiphy = phy->mt76->hw->wiphy; struct thermal_cooling_device *cdev; struct device *hwmon; + const char *name; - cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy, - &mt7915_thermal_ops); + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7915_%s", + wiphy_name(wiphy)); + + cdev = thermal_cooling_device_register(name, phy, &mt7915_thermal_ops); if (!IS_ERR(cdev)) { if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, "cooling_device") < 0) @@ -144,15 +177,76 @@ static int mt7915_thermal_init(struct mt7915_phy *phy) if (!IS_REACHABLE(CONFIG_HWMON)) return 0; - hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, - wiphy_name(wiphy), phy, + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, mt7915_hwmon_groups); if (IS_ERR(hwmon)) return PTR_ERR(hwmon); + /* initialize critical/maximum high temperature */ + phy->throttle_temp[0] = 110; + phy->throttle_temp[1] = 120; + + return 0; +} + +static void mt7915_led_set_config(struct led_classdev *led_cdev, + u8 delay_on, u8 delay_off) +{ + struct mt7915_dev *dev; + struct mt76_dev *mt76; + u32 val; + + mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); + dev = container_of(mt76, struct mt7915_dev, mt76); + + /* select TX blink mode, 2: only data frames */ + mt76_rmw_field(dev, MT_TMAC_TCR0(0), MT_TMAC_TCR0_TX_BLINK, 2); + + /* enable LED */ + mt76_wr(dev, MT_LED_EN(0), 1); + + /* set LED Tx blink on/off time */ + val = FIELD_PREP(MT_LED_TX_BLINK_ON_MASK, delay_on) | + FIELD_PREP(MT_LED_TX_BLINK_OFF_MASK, delay_off); + mt76_wr(dev, MT_LED_TX_BLINK(0), val); + + /* control LED */ + val = MT_LED_CTRL_BLINK_MODE | MT_LED_CTRL_KICK; + if (dev->mt76.led_al) + val |= MT_LED_CTRL_POLARITY; + + mt76_wr(dev, MT_LED_CTRL(0), val); + mt76_clear(dev, MT_LED_CTRL(0), MT_LED_CTRL_KICK); +} + +static int mt7915_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + u16 delta_on = 0, delta_off = 0; + +#define HW_TICK 10 +#define TO_HW_TICK(_t) (((_t) > HW_TICK) ? ((_t) / HW_TICK) : HW_TICK) + + if (*delay_on) + delta_on = TO_HW_TICK(*delay_on); + if (*delay_off) + delta_off = TO_HW_TICK(*delay_off); + + mt7915_led_set_config(led_cdev, delta_on, delta_off); + return 0; } +static void mt7915_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + if (!brightness) + mt7915_led_set_config(led_cdev, 0, 0xff); + else + mt7915_led_set_config(led_cdev, 0xff, 0); +} + static void mt7915_init_txpower(struct mt7915_dev *dev, struct ieee80211_supported_band *sband) @@ -232,7 +326,12 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) wiphy->reg_notifier = mt7915_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_COLOR); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); @@ -287,9 +386,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); - mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); - - mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536); + mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 0x680); /* disable rx rate report by default due to hw issues */ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); } @@ -298,7 +395,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev) { int i; - mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); + mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 0x400); /* enable hardware de-agg */ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); @@ -307,6 +404,11 @@ static void mt7915_mac_init(struct mt7915_dev *dev) MT_WTBL_UPDATE_ADM_COUNT_CLEAR); for (i = 0; i < 2; i++) mt7915_mac_init_band(dev, i); + + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + i = dev->mt76.led_pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2; + mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4); + } } static int mt7915_txbf_init(struct mt7915_dev *dev) @@ -350,7 +452,6 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev) mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask; mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1; - INIT_LIST_HEAD(&phy->stats_list); INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work); mt7915_eeprom_parse_band_config(phy); @@ -374,6 +475,10 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev) if (ret) goto error; + ret = mt7915_init_debugfs(phy); + if (ret) + goto error; + return 0; error: @@ -480,7 +585,7 @@ static int mt7915_init_hardware(struct mt7915_dev *dev) } /* Beacon and mgmt frames should occupy wcid 0 */ - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1); + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); if (idx) return -ENOSPC; @@ -525,7 +630,6 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap, int vif, int nss) { struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; - struct ieee80211_he_mcs_nss_supp *mcs = &he_cap->he_mcs_nss_supp; u8 c; #ifdef CONFIG_MAC80211_MESH @@ -577,8 +681,11 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap, elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; - /* num_snd_dim */ - c = (nss - 1) | (max_t(int, le16_to_cpu(mcs->tx_mcs_160), 1) << 3); + /* num_snd_dim + * for mt7915, max supported nss is 2 for bw > 80MHz + */ + c = (nss - 1) | + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; elem->phy_cap_info[5] |= c; c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | @@ -613,12 +720,19 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, { int i, idx = 0, nss = hweight8(phy->mt76->chainmask); u16 mcs_map = 0; + u16 mcs_map_160 = 0; for (i = 0; i < 8; i++) { if (i < nss) mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2)); else mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + + /* Can do 1/2 of NSS streams in 160Mhz mode. */ + if (i < nss / 2) + mcs_map_160 |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2)); + else + mcs_map_160 |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); } for (i = 0; i < NUM_NL80211_IFTYPES; i++) { @@ -667,6 +781,8 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, switch (i) { case NL80211_IFTYPE_AP: + he_cap_elem->mac_cap_info[0] |= + IEEE80211_HE_MAC_CAP0_TWT_RES; he_cap_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[4] |= @@ -677,7 +793,11 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; break; case NL80211_IFTYPE_STATION: he_cap_elem->mac_cap_info[1] |= @@ -720,10 +840,10 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map); - he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map); - he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map); - he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map); - he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map); + he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map_160); + he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map_160); + he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map_160); + he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map_160); mt7915_set_stream_he_txbf_caps(he_cap, i, nss); @@ -787,11 +907,11 @@ int mt7915_register_device(struct mt7915_dev *dev) dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; - INIT_LIST_HEAD(&dev->phy.stats_list); INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work); INIT_LIST_HEAD(&dev->sta_rc_list); INIT_LIST_HEAD(&dev->sta_poll_list); + INIT_LIST_HEAD(&dev->twt_list); spin_lock_init(&dev->sta_poll_lock); init_waitqueue_head(&dev->reset_wait); @@ -816,6 +936,12 @@ int mt7915_register_device(struct mt7915_dev *dev) dev->mt76.test_ops = &mt7915_testmode_ops; #endif + /* init led callbacks */ + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + dev->mt76.led_cdev.brightness_set = mt7915_led_set_brightness; + dev->mt76.led_cdev.blink_set = mt7915_led_set_blink; + } + ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) @@ -831,7 +957,7 @@ int mt7915_register_device(struct mt7915_dev *dev) if (ret) return ret; - return mt7915_init_debugfs(dev); + return mt7915_init_debugfs(&dev->phy); } void mt7915_unregister_device(struct mt7915_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 2462704094b0..21e6ef07814c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -6,6 +6,7 @@ #include "mt7915.h" #include "../dma.h" #include "mac.h" +#include "mcu.h" #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) @@ -88,15 +89,14 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask) 0, 5000); } -static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid) +static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw) { mt76_wr(dev, MT_WTBLON_TOP_WDUCR, FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); - return MT_WTBL_LMAC_OFFS(wcid, 0); + return MT_WTBL_LMAC_OFFS(wcid, dw); } -/* TODO: use txfree airtime info to avoid runtime accessing in the long run */ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) { static const u8 ac_to_tid[] = { @@ -107,6 +107,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) }; struct ieee80211_sta *sta; struct mt7915_sta *msta; + struct rate_info *rate; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); int i; @@ -119,8 +120,9 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) while (true) { bool clear = false; - u32 addr; + u32 addr, val; u16 idx; + u8 bw; spin_lock_bh(&dev->sta_poll_lock); if (list_empty(&sta_poll_list)) { @@ -133,7 +135,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) spin_unlock_bh(&dev->sta_poll_lock); idx = msta->wcid.idx; - addr = mt7915_mac_wtbl_lmac_addr(dev, idx) + 20 * 4; + addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20); for (i = 0; i < IEEE80211_NUM_ACS; i++) { u32 tx_last = msta->airtime_ac[i]; @@ -174,6 +176,43 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); } + + /* + * We don't support reading GI info from txs packets. + * For accurate tx status reporting and AQL improvement, + * we need to make sure that flags match so polling GI + * from per-sta counters directly. + */ + rate = &msta->wcid.rate; + addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 7); + val = mt76_rr(dev, addr); + + switch (rate->bw) { + case RATE_INFO_BW_160: + bw = IEEE80211_STA_RX_BW_160; + break; + case RATE_INFO_BW_80: + bw = IEEE80211_STA_RX_BW_80; + break; + case RATE_INFO_BW_40: + bw = IEEE80211_STA_RX_BW_40; + break; + default: + bw = IEEE80211_STA_RX_BW_20; + break; + } + + if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { + u8 offs = 24 + 2 * bw; + + rate->he_gi = (val & (0x3 << offs)) >> offs; + } else if (rate->flags & + (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) { + if (val & BIT(12 + bw)) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + else + rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; + } } rcu_read_unlock(); @@ -229,11 +268,50 @@ mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, } static void +mt7915_mac_decode_he_mu_radiotap(struct sk_buff *skb, + struct mt76_rx_status *status, + __le32 *rxv) +{ + static const struct ieee80211_radiotap_he_mu mu_known = { + .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) | + HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) | + HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) | + HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN), + .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), + }; + struct ieee80211_radiotap_he_mu *he_mu = NULL; + + he_mu = skb_push(skb, sizeof(mu_known)); + memcpy(he_mu, &mu_known, sizeof(mu_known)); + +#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f) + + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx); + if (status->he_dcm) + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm); + + he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) | + MU_PREP(FLAGS2_SIG_B_SYMS_USERS, + le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER)); + + he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0); + + if (status->bw >= RATE_INFO_BW_40) { + he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN); + he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1); + } + + if (status->bw >= RATE_INFO_BW_80) { + he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2); + he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3); + } +} + +static void mt7915_mac_decode_he_radiotap(struct sk_buff *skb, struct mt76_rx_status *status, __le32 *rxv, u32 phy) { - /* TODO: struct ieee80211_radiotap_he_mu */ static const struct ieee80211_radiotap_he known = { .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | HE_BITS(DATA1_DATA_DCM_KNOWN) | @@ -241,6 +319,7 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, HE_BITS(DATA1_CODING_KNOWN) | HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | HE_BITS(DATA1_DOPPLER_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN) | HE_BITS(DATA1_BSS_COLOR_KNOWN), .data2 = HE_BITS(DATA2_GI_KNOWN) | HE_BITS(DATA2_TXBF_KNOWN) | @@ -255,9 +334,12 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); + he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | le16_encode_bits(ltf_size, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) + he->data5 |= HE_BITS(DATA5_TXBF); he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); @@ -265,12 +347,10 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, case MT_PHY_TYPE_HE_SU: he->data1 |= HE_BITS(DATA1_FORMAT_SU) | HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN); + HE_BITS(DATA1_BEAM_CHANGE_KNOWN); he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); break; case MT_PHY_TYPE_HE_EXT_SU: he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | @@ -280,23 +360,20 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, break; case MT_PHY_TYPE_HE_MU: he->data1 |= HE_BITS(DATA1_FORMAT_MU) | - HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN); + HE_BITS(DATA1_UL_DL_KNOWN); he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); + he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]); mt7915_mac_decode_he_radiotap_ru(status, he, rxv); break; case MT_PHY_TYPE_HE_TB: he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN) | HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | HE_BITS(DATA1_SPTL_REUSE4_KNOWN); - he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | - HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | + he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); @@ -610,8 +687,11 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) status->flag |= RX_FLAG_8023; } - if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) + if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) { mt7915_mac_decode_he_radiotap(skb, status, rxv, mode); + if (status->flag & RX_FLAG_RADIOTAP_HE_MU) + mt7915_mac_decode_he_mu_radiotap(skb, status, rxv); + } if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; @@ -825,17 +905,19 @@ mt7915_mac_write_txwi_8023(struct mt7915_dev *dev, __le32 *txwi, static void mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct ieee80211_key_conf *key) + struct sk_buff *skb, struct ieee80211_key_conf *key, + bool *mcast) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - bool multicast = is_multicast_ether_addr(hdr->addr1); u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; __le16 fc = hdr->frame_control; u8 fc_type, fc_stype; u32 val; + *mcast = is_multicast_ether_addr(hdr->addr1); + if (ieee80211_is_action(fc) && mgmt->u.action.category == WLAN_CATEGORY_BACK && mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { @@ -861,15 +943,16 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi, val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | - FIELD_PREP(MT_TXD2_MULTICAST, multicast); + FIELD_PREP(MT_TXD2_MULTICAST, *mcast); - if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && + if (key && *mcast && ieee80211_is_robust_mgmt_frame(skb) && key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { val |= MT_TXD2_BIP; txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); } - if (!ieee80211_is_data(fc) || multicast) + if (!ieee80211_is_data(fc) || *mcast || + info->flags & IEEE80211_TX_CTL_USE_MINRATE) val |= MT_TXD2_FIX_RATE; txwi[2] |= cpu_to_le32(val); @@ -899,6 +982,51 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi, txwi[7] |= cpu_to_le32(val); } +static u16 +mt7915_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif, + bool beacon, bool mcast) +{ + u8 mode = 0, band = mphy->chandef.chan->band; + int rateidx = 0, mcast_rate; + + if (beacon) { + struct cfg80211_bitrate_mask *mask; + + mask = &vif->bss_conf.beacon_tx_rate; + if (hweight16(mask->control[band].he_mcs[0]) == 1) { + rateidx = ffs(mask->control[band].he_mcs[0]) - 1; + mode = MT_PHY_TYPE_HE_SU; + goto out; + } else if (hweight16(mask->control[band].vht_mcs[0]) == 1) { + rateidx = ffs(mask->control[band].vht_mcs[0]) - 1; + mode = MT_PHY_TYPE_VHT; + goto out; + } else if (hweight8(mask->control[band].ht_mcs[0]) == 1) { + rateidx = ffs(mask->control[band].ht_mcs[0]) - 1; + mode = MT_PHY_TYPE_HT; + goto out; + } else if (hweight32(mask->control[band].legacy) == 1) { + rateidx = ffs(mask->control[band].legacy) - 1; + goto legacy; + } + } + + mcast_rate = vif->bss_conf.mcast_rate[band]; + if (mcast && mcast_rate > 0) + rateidx = mcast_rate - 1; + else + rateidx = ffs(vif->bss_conf.basic_rates) - 1; + +legacy: + rateidx = mt76_calculate_default_rate(mphy, rateidx); + mode = rateidx >> 8; + rateidx &= GENMASK(7, 0); + +out: + return FIELD_PREP(MT_TX_RATE_IDX, rateidx) | + FIELD_PREP(MT_TX_RATE_MODE, mode); +} + void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, bool beacon) @@ -909,6 +1037,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + bool mcast = false; u16 tx_count = 15; u32 val; @@ -939,7 +1068,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txwi[0] = cpu_to_le32(val); - val = MT_TXD1_LONG_FORMAT | + val = MT_TXD1_LONG_FORMAT | MT_TXD1_VTA | FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); @@ -971,19 +1100,14 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, if (is_8023) mt7915_mac_write_txwi_8023(dev, txwi, skb, wcid); else - mt7915_mac_write_txwi_80211(dev, txwi, skb, key); + mt7915_mac_write_txwi_80211(dev, txwi, skb, key, &mcast); if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { - u16 rate; + u16 rate = mt7915_mac_tx_rate_val(mphy, vif, beacon, mcast); /* hardware won't add HTC for mgmt/ctrl frame */ txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); - if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) - rate = MT7915_5G_RATE_DEFAULT; - else - rate = MT7915_2G_RATE_DEFAULT; - val = MT_TXD6_FIXED_BW | FIELD_PREP(MT_TXD6_TX_RATE, rate); txwi[6] |= cpu_to_le32(val); @@ -1016,6 +1140,17 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid) wcid = &dev->mt76.global_wcid; + if (sta) { + struct mt7915_sta *msta; + + msta = (struct mt7915_sta *)sta->drv_priv; + + if (time_after(jiffies, msta->jiffies + HZ / 4)) { + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + msta->jiffies = jiffies; + } + } + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, @@ -1162,7 +1297,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl)); for (i = 0; i < count; i++) { u32 msdu, info = le32_to_cpu(free->info[i]); - u8 stat; /* * 1'b1: new wcid pair. @@ -1170,7 +1304,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) */ if (info & MT_TX_FREE_PAIR) { struct mt7915_sta *msta; - struct mt7915_phy *phy; struct mt76_wcid *wcid; u16 idx; @@ -1182,10 +1315,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) continue; msta = container_of(wcid, struct mt7915_sta, wcid); - phy = msta->vif->phy; spin_lock_bh(&dev->sta_poll_lock); - if (list_empty(&msta->stats_list)) - list_add_tail(&msta->stats_list, &phy->stats_list); if (list_empty(&msta->poll_list)) list_add_tail(&msta->poll_list, &dev->sta_poll_list); spin_unlock_bh(&dev->sta_poll_lock); @@ -1193,8 +1323,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) } msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); - stat = FIELD_GET(MT_TX_FREE_STATUS, info); - txwi = mt76_token_release(mdev, msdu, &wake); if (!txwi) continue; @@ -1219,20 +1347,27 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) static bool mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, - __le32 *txs_data) + __le32 *txs_data, struct mt76_sta_stats *stats) { + struct ieee80211_supported_band *sband; struct mt76_dev *mdev = &dev->mt76; + struct mt76_phy *mphy; struct ieee80211_tx_info *info; struct sk_buff_head list; + struct rate_info rate = {}; struct sk_buff *skb; + bool cck = false; + u32 txrate, txs, mode; mt76_tx_status_lock(mdev, &list); skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); if (!skb) - goto out; + goto out_no_skb; + + txs = le32_to_cpu(txs_data[0]); info = IEEE80211_SKB_CB(skb); - if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK))) + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) info->flags |= IEEE80211_TX_STAT_ACK; info->status.ampdu_len = 1; @@ -1240,9 +1375,92 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, IEEE80211_TX_STAT_ACK); info->status.rates[0].idx = -1; - mt76_tx_status_skb_done(mdev, skb, &list); + + txrate = FIELD_GET(MT_TXS0_TX_RATE, txs); + + rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); + rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; + + if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss)) + stats->tx_nss[rate.nss - 1]++; + if (rate.mcs < ARRAY_SIZE(stats->tx_mcs)) + stats->tx_mcs[rate.mcs]++; + + mode = FIELD_GET(MT_TX_RATE_MODE, txrate); + switch (mode) { + case MT_PHY_TYPE_CCK: + cck = true; + fallthrough; + case MT_PHY_TYPE_OFDM: + mphy = &dev->mphy; + if (wcid->ext_phy && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck); + rate.legacy = sband->bitrates[rate.mcs].bitrate; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + rate.mcs += (rate.nss - 1) * 8; + if (rate.mcs > 31) + goto out; + + rate.flags = RATE_INFO_FLAGS_MCS; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_VHT: + if (rate.mcs > 9) + goto out; + + rate.flags = RATE_INFO_FLAGS_VHT_MCS; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (rate.mcs > 11) + goto out; + + rate.he_gi = wcid->rate.he_gi; + rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); + rate.flags = RATE_INFO_FLAGS_HE_MCS; + break; + default: + goto out; + } + + stats->tx_mode[mode]++; + + switch (FIELD_GET(MT_TXS0_BW, txs)) { + case IEEE80211_STA_RX_BW_160: + rate.bw = RATE_INFO_BW_160; + stats->tx_bw[3]++; + break; + case IEEE80211_STA_RX_BW_80: + rate.bw = RATE_INFO_BW_80; + stats->tx_bw[2]++; + break; + case IEEE80211_STA_RX_BW_40: + rate.bw = RATE_INFO_BW_40; + stats->tx_bw[1]++; + break; + default: + rate.bw = RATE_INFO_BW_20; + stats->tx_bw[0]++; + break; + } + wcid->rate = rate; out: + mt76_tx_status_skb_done(mdev, skb, &list); + +out_no_skb: mt76_tx_status_unlock(mdev, &list); return !!skb; @@ -1279,12 +1497,13 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) if (!wcid) goto out; - mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data); + msta = container_of(wcid, struct mt7915_sta, wcid); + + mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats); if (!wcid->sta) goto out; - msta = container_of(wcid, struct mt7915_sta, wcid); spin_lock_bh(&dev->sta_poll_lock); if (list_empty(&msta->poll_list)) list_add_tail(&msta->poll_list, &dev->sta_poll_list); @@ -1333,15 +1552,11 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { - struct mt7915_dev *dev; - if (!e->txwi) { dev_kfree_skb_any(e->skb); return; } - dev = container_of(mdev, struct mt7915_dev, mt76); - /* error path */ if (e->skb == DMA_DUMMY_DATA) { struct mt76_txwi_cache *t; @@ -1403,17 +1618,12 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy) FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); - int sifs, offset; + int offset; bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; - if (is_5ghz) - sifs = 16; - else - sifs = 10; - if (ext_phy) { coverage_class = max_t(s16, dev->phy.coverage_class, coverage_class); @@ -1435,11 +1645,14 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy) mt76_wr(dev, MT_TMAC_CDTR(ext_phy), cck + reg_offset); mt76_wr(dev, MT_TMAC_ODTR(ext_phy), ofdm + reg_offset); mt76_wr(dev, MT_TMAC_ICR0(ext_phy), - FIELD_PREP(MT_IFS_EIFS, 360) | + FIELD_PREP(MT_IFS_EIFS_OFDM, is_5ghz ? 84 : 78) | FIELD_PREP(MT_IFS_RIFS, 2) | - FIELD_PREP(MT_IFS_SIFS, sifs) | + FIELD_PREP(MT_IFS_SIFS, 10) | FIELD_PREP(MT_IFS_SLOT, phy->slottime)); + mt76_wr(dev, MT_TMAC_ICR1(ext_phy), + FIELD_PREP(MT_IFS_EIFS_CCK, 314)); + if (phy->slottime < 20 || is_5ghz) val = MT7915_CFEND_RATE_DEFAULT; else @@ -1580,7 +1793,7 @@ mt7915_dma_reset(struct mt7915_dev *dev) mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_reset(dev, i); - mt76_tx_status_check(&dev->mt76, NULL, true); + mt76_tx_status_check(&dev->mt76, true); /* re-init prefetch settings after reset */ mt7915_dma_prefetch(dev); @@ -1668,6 +1881,7 @@ void mt7915_mac_reset_work(struct work_struct *work) if (phy2) clear_bit(MT76_RESET, &phy2->mt76->state); + local_bh_disable(); napi_enable(&dev->mt76.napi[0]); napi_schedule(&dev->mt76.napi[0]); @@ -1676,6 +1890,8 @@ void mt7915_mac_reset_work(struct work_struct *work) napi_enable(&dev->mt76.napi[2]); napi_schedule(&dev->mt76.napi[2]); + local_bh_enable(); + tasklet_schedule(&dev->irq_tasklet); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); @@ -1702,17 +1918,117 @@ void mt7915_mac_reset_work(struct work_struct *work) MT7915_WATCHDOG_TIME); } -static void -mt7915_mac_update_stats(struct mt7915_phy *phy) +void mt7915_mac_update_stats(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; bool ext_phy = phy != &dev->phy; - int i, aggr0, aggr1; + int i, aggr0, aggr1, cnt; mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(ext_phy), MT_MIB_SDR3_FCS_ERR_MASK); + cnt = mt76_rr(dev, MT_MIB_SDR4(ext_phy)); + mib->rx_fifo_full_cnt += FIELD_GET(MT_MIB_SDR4_RX_FIFO_FULL_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR5(ext_phy)); + mib->rx_mpdu_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_SDR6(ext_phy)); + mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR7(ext_phy)); + mib->rx_vector_mismatch_cnt += FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR8(ext_phy)); + mib->rx_delimiter_fail_cnt += FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR11(ext_phy)); + mib->rx_len_mismatch_cnt += FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR12(ext_phy)); + mib->tx_ampdu_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_SDR13(ext_phy)); + mib->tx_stop_q_empty_cnt += FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR14(ext_phy)); + mib->tx_mpdu_attempts_cnt += FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR15(ext_phy)); + mib->tx_mpdu_success_cnt += FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR22(ext_phy)); + mib->rx_ampdu_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_SDR23(ext_phy)); + mib->rx_ampdu_bytes_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_SDR24(ext_phy)); + mib->rx_ampdu_valid_subframe_cnt += FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR25(ext_phy)); + mib->rx_ampdu_valid_subframe_bytes_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_SDR27(ext_phy)); + mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR28(ext_phy)); + mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR29(ext_phy)); + mib->rx_pfdrop_cnt += FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR30(ext_phy)); + mib->rx_vec_queue_overflow_drop_cnt += + FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR31(ext_phy)); + mib->rx_ba_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_SDR32(ext_phy)); + mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR33(ext_phy)); + mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR33_TX_PKT_IBF_CNT_MASK, cnt); + + cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy)); + mib->tx_bf_cnt += FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt); + + cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy)); + mib->tx_mu_mpdu_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy)); + mib->tx_mu_acked_mpdu_cnt += cnt; + + cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy)); + mib->tx_su_acked_mpdu_cnt += cnt; + + cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy)); + mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt); + mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt); + + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy)); + mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, cnt); + mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, cnt); + mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, cnt); + mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, cnt); + + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy)); + mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt); + mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt); + mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt); + + cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy)); + mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_ETBF_TX_FB_CPL, cnt); + mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_ETBF_TX_FB_TRI, cnt); + + for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { + cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + mib->tx_amsdu[i] += cnt; + mib->tx_amsdu_cnt += cnt; + } + aggr0 = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { u32 val; @@ -1737,30 +2053,6 @@ mt7915_mac_update_stats(struct mt7915_phy *phy) } } -static void -mt7915_mac_sta_stats_work(struct mt7915_phy *phy) -{ - struct mt7915_dev *dev = phy->dev; - struct mt7915_sta *msta; - LIST_HEAD(list); - - spin_lock_bh(&dev->sta_poll_lock); - list_splice_init(&phy->stats_list, &list); - - while (!list_empty(&list)) { - msta = list_first_entry(&list, struct mt7915_sta, stats_list); - list_del_init(&msta->stats_list); - spin_unlock_bh(&dev->sta_poll_lock); - - /* use MT_TX_FREE_RATE to report Tx rate for further devices */ - mt7915_mcu_get_tx_rate(dev, RATE_CTRL_RU_INFO, msta->wcid.idx); - - spin_lock_bh(&dev->sta_poll_lock); - } - - spin_unlock_bh(&dev->sta_poll_lock); -} - void mt7915_mac_sta_rc_work(struct work_struct *work) { struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work); @@ -1776,8 +2068,8 @@ void mt7915_mac_sta_rc_work(struct work_struct *work) while (!list_empty(&list)) { msta = list_first_entry(&list, struct mt7915_sta, rc_list); list_del_init(&msta->rc_list); - changed = msta->stats.changed; - msta->stats.changed = 0; + changed = msta->changed; + msta->changed = 0; spin_unlock_bh(&dev->sta_poll_lock); sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); @@ -1817,14 +2109,9 @@ void mt7915_mac_work(struct work_struct *work) mt7915_mac_update_stats(phy); } - if (++phy->sta_work_count == 10) { - phy->sta_work_count = 0; - mt7915_mac_sta_stats_work(phy); - } - mutex_unlock(&mphy->dev->mutex); - mt76_tx_status_check(mphy->dev, NULL, false); + mt76_tx_status_check(mphy->dev, false); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7915_WATCHDOG_TIME); @@ -1961,3 +2248,182 @@ stop: mt7915_dfs_stop_radar_detector(phy); return 0; } + +static int +mt7915_mac_twt_duration_align(int duration) +{ + return duration << 8; +} + +static u64 +mt7915_mac_twt_sched_list_add(struct mt7915_dev *dev, + struct mt7915_twt_flow *flow) +{ + struct mt7915_twt_flow *iter, *iter_next; + u32 duration = flow->duration << 8; + u64 start_tsf; + + iter = list_first_entry_or_null(&dev->twt_list, + struct mt7915_twt_flow, list); + if (!iter || !iter->sched || iter->start_tsf > duration) { + /* add flow as first entry in the list */ + list_add(&flow->list, &dev->twt_list); + return 0; + } + + list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) { + start_tsf = iter->start_tsf + + mt7915_mac_twt_duration_align(iter->duration); + if (list_is_last(&iter->list, &dev->twt_list)) + break; + + if (!iter_next->sched || + iter_next->start_tsf > start_tsf + duration) { + list_add(&flow->list, &iter->list); + goto out; + } + } + + /* add flow as last entry in the list */ + list_add_tail(&flow->list, &dev->twt_list); +out: + return start_tsf; +} + +static int mt7915_mac_check_twt_req(struct ieee80211_twt_setup *twt) +{ + struct ieee80211_twt_params *twt_agrt; + u64 interval, duration; + u16 mantissa; + u8 exp; + + /* only individual agreement supported */ + if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) + return -EOPNOTSUPP; + + /* only 256us unit supported */ + if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) + return -EOPNOTSUPP; + + twt_agrt = (struct ieee80211_twt_params *)twt->params; + + /* explicit agreement not supported */ + if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT))) + return -EOPNOTSUPP; + + exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, + le16_to_cpu(twt_agrt->req_type)); + mantissa = le16_to_cpu(twt_agrt->mantissa); + duration = twt_agrt->min_twt_dur << 8; + + interval = (u64)mantissa << exp; + if (interval < duration) + return -EOPNOTSUPP; + + return 0; +} + +void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct ieee80211_twt_setup *twt) +{ + enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct ieee80211_twt_params *twt_agrt = (void *)twt->params; + u16 req_type = le16_to_cpu(twt_agrt->req_type); + enum ieee80211_twt_setup_cmd sta_setup_cmd; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_twt_flow *flow; + int flowid, table_id; + u8 exp; + + if (mt7915_mac_check_twt_req(twt)) + goto out; + + mutex_lock(&dev->mt76.mutex); + + if (dev->twt.n_agrt == MT7915_MAX_TWT_AGRT) + goto unlock; + + if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) + goto unlock; + + flowid = ffs(~msta->twt.flowid_mask) - 1; + le16p_replace_bits(&twt_agrt->req_type, flowid, + IEEE80211_TWT_REQTYPE_FLOWID); + + table_id = ffs(~dev->twt.table_mask) - 1; + exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type); + sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type); + + flow = &msta->twt.flow[flowid]; + memset(flow, 0, sizeof(*flow)); + INIT_LIST_HEAD(&flow->list); + flow->wcid = msta->wcid.idx; + flow->table_id = table_id; + flow->id = flowid; + flow->duration = twt_agrt->min_twt_dur; + flow->mantissa = twt_agrt->mantissa; + flow->exp = exp; + flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION); + flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE); + flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER); + + if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST || + sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) { + u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp; + u64 flow_tsf, curr_tsf; + u32 rem; + + flow->sched = true; + flow->start_tsf = mt7915_mac_twt_sched_list_add(dev, flow); + curr_tsf = __mt7915_get_tsf(hw, msta->vif); + div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem); + flow_tsf = curr_tsf + interval - rem; + twt_agrt->twt = cpu_to_le64(flow_tsf); + } else { + list_add_tail(&flow->list, &dev->twt_list); + } + flow->tsf = le64_to_cpu(twt_agrt->twt); + + if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD)) + goto unlock; + + setup_cmd = TWT_SETUP_CMD_ACCEPT; + dev->twt.table_mask |= BIT(table_id); + msta->twt.flowid_mask |= BIT(flowid); + dev->twt.n_agrt++; + +unlock: + mutex_unlock(&dev->mt76.mutex); +out: + le16p_replace_bits(&twt_agrt->req_type, setup_cmd, + IEEE80211_TWT_REQTYPE_SETUP_CMD); + twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) | + (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED); +} + +void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev, + struct mt7915_sta *msta, + u8 flowid) +{ + struct mt7915_twt_flow *flow; + + lockdep_assert_held(&dev->mt76.mutex); + + if (flowid >= ARRAY_SIZE(msta->twt.flow)) + return; + + if (!(msta->twt.flowid_mask & BIT(flowid))) + return; + + flow = &msta->twt.flow[flowid]; + if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, + MCU_TWT_AGRT_DELETE)) + return; + + list_del_init(&flow->list); + msta->twt.flowid_mask &= ~BIT(flowid); + dev->twt.table_mask &= ~BIT(flow->table_id); + dev->twt.n_agrt--; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index eb1885f4bd8e..7a2c740d1464 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -117,6 +117,7 @@ enum rx_pkt_type { #define MT_PRXV_TX_DCM BIT(4) #define MT_PRXV_TX_ER_SU_106T BIT(5) #define MT_PRXV_NSTS GENMASK(9, 7) +#define MT_PRXV_TXBF BIT(10) #define MT_PRXV_HT_AD_CODE BIT(11) #define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28) #define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) @@ -133,7 +134,14 @@ enum rx_pkt_type { #define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) #define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) #define MT_CRXV_HE_PE_DISAMBIG BIT(23) +#define MT_CRXV_HE_NUM_USER GENMASK(30, 24) #define MT_CRXV_HE_UPLINK BIT(31) +#define MT_CRXV_HE_RU0 GENMASK(7, 0) +#define MT_CRXV_HE_RU1 GENMASK(15, 8) +#define MT_CRXV_HE_RU2 GENMASK(23, 16) +#define MT_CRXV_HE_RU3 GENMASK(31, 24) + +#define MT_CRXV_HE_MU_AID GENMASK(30, 20) #define MT_CRXV_HE_SR_MASK GENMASK(11, 8) #define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) @@ -272,7 +280,8 @@ enum tx_mcu_port_q_idx { #define MT_TX_RATE_MODE GENMASK(9, 6) #define MT_TX_RATE_SU_EXT_TONE BIT(5) #define MT_TX_RATE_DCM BIT(4) -#define MT_TX_RATE_IDX GENMASK(3, 0) +/* VHT/HE only use bits 0-3 */ +#define MT_TX_RATE_IDX GENMASK(5, 0) #define MT_TXP_MAX_BUF_NUM 6 diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index c25f8da590dd..8be78917dee9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -215,7 +215,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mvif->phy = phy; mvif->band_idx = ext_phy; - if (ext_phy) + if (dev->mt76.phy2) mvif->wmm_idx = ext_phy * (MT7915_MAX_WMM_SETS / 2) + mvif->idx % (MT7915_MAX_WMM_SETS / 2); else @@ -231,12 +231,13 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, idx = MT7915_WTBL_RESERVED - mvif->idx; INIT_LIST_HEAD(&mvif->sta.rc_list); - INIT_LIST_HEAD(&mvif->sta.stats_list); INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.ext_phy = mvif->band_idx; mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_packet_id_init(&mvif->sta.wcid); + mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -252,6 +253,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; mt7915_init_bitrate_mask(vif); + memset(&mvif->cap, -1, sizeof(mvif->cap)); out: mutex_unlock(&dev->mt76.mutex); @@ -291,6 +293,8 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw, if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); + + mt76_packet_id_flush(&dev->mt76, &msta->wcid); } static void mt7915_init_dfs_state(struct mt7915_phy *phy) @@ -538,6 +542,29 @@ static void mt7915_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&dev->mt76.mutex); } +static void +mt7915_update_bss_color(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_he_bss_color *bss_color) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + + switch (vif->type) { + case NL80211_IFTYPE_AP: { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + + if (mvif->omac_idx > HW_BSSID_MAX) + return; + fallthrough; + } + case NL80211_IFTYPE_STATION: + mt7915_mcu_update_bss_color(dev, vif, bss_color); + break; + default: + break; + } +} + static void mt7915_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -586,6 +613,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_HE_OBSS_PD) mt7915_mcu_add_obss_spr(dev, vif, info->he_obss_pd.enable); + if (changed & BSS_CHANGED_HE_BSS_COLOR) + mt7915_update_bss_color(hw, vif, &info->he_bss_color); + if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) mt7915_mcu_add_beacon(hw, vif, info->enable_beacon); @@ -613,19 +643,18 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; int ret, idx; - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1); + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); if (idx < 0) return -ENOSPC; INIT_LIST_HEAD(&msta->rc_list); - INIT_LIST_HEAD(&msta->stats_list); INIT_LIST_HEAD(&msta->poll_list); msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.ext_phy = mvif->band_idx; msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta->stats.jiffies = jiffies; + msta->jiffies = jiffies; mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -634,7 +663,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (ret) return ret; - return mt7915_mcu_add_sta_adv(dev, vif, sta, true); + return mt7915_mcu_add_rate_ctrl(dev, vif, sta); } void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -642,18 +671,19 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + int i; - mt7915_mcu_add_sta_adv(dev, vif, sta, false); mt7915_mcu_add_sta(dev, vif, sta, false); mt7915_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) + mt7915_mac_twt_teardown_flow(dev, msta, i); + spin_lock_bh(&dev->sta_poll_lock); if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); - if (!list_empty(&msta->stats_list)) - list_del_init(&msta->stats_list); if (!list_empty(&msta->rc_list)) list_del_init(&msta->rc_list); spin_unlock_bh(&dev->sta_poll_lock); @@ -781,22 +811,19 @@ mt7915_get_stats(struct ieee80211_hw *hw, struct mib_stats *mib = &phy->mib; mutex_lock(&dev->mt76.mutex); + stats->dot11RTSSuccessCount = mib->rts_cnt; stats->dot11RTSFailureCount = mib->rts_retries_cnt; stats->dot11FCSErrorCount = mib->fcs_err_cnt; stats->dot11ACKFailureCount = mib->ack_fail_cnt; - memset(mib, 0, sizeof(*mib)); - mutex_unlock(&dev->mt76.mutex); return 0; } -static u64 -mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif) { - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); bool band = phy != &dev->phy; @@ -806,7 +833,7 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } tsf; u16 n; - mutex_lock(&dev->mt76.mutex); + lockdep_assert_held(&dev->mt76.mutex); n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; /* TSF software read */ @@ -815,9 +842,21 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); + return tsf.t64; +} + +static u64 +mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + u64 ret; + + mutex_lock(&dev->mt76.mutex); + ret = __mt7915_get_tsf(hw, mvif); mutex_unlock(&dev->mt76.mutex); - return tsf.t64; + return ret; } static void @@ -926,7 +965,7 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw, { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct mt7915_sta_stats *stats = &msta->stats; + struct rate_info *txrate = &msta->wcid.rate; struct rate_info rxrate = {}; if (!mt7915_mcu_get_rx_rate(phy, vif, sta, &rxrate)) { @@ -934,20 +973,20 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); } - if (!stats->tx_rate.legacy && !stats->tx_rate.flags) + if (!txrate->legacy && !txrate->flags) return; - if (stats->tx_rate.legacy) { - sinfo->txrate.legacy = stats->tx_rate.legacy; + if (txrate->legacy) { + sinfo->txrate.legacy = txrate->legacy; } else { - sinfo->txrate.mcs = stats->tx_rate.mcs; - sinfo->txrate.nss = stats->tx_rate.nss; - sinfo->txrate.bw = stats->tx_rate.bw; - sinfo->txrate.he_gi = stats->tx_rate.he_gi; - sinfo->txrate.he_dcm = stats->tx_rate.he_dcm; - sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc; + sinfo->txrate.mcs = txrate->mcs; + sinfo->txrate.nss = txrate->nss; + sinfo->txrate.bw = txrate->bw; + sinfo->txrate.he_gi = txrate->he_gi; + sinfo->txrate.he_dcm = txrate->he_dcm; + sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; } - sinfo->txrate.flags = stats->tx_rate.flags; + sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } @@ -959,7 +998,7 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) u32 *changed = data; spin_lock_bh(&dev->sta_poll_lock); - msta->stats.changed |= *changed; + msta->changed |= *changed; if (list_empty(&msta->rc_list)) list_add_tail(&msta->rc_list, &dev->sta_rc_list); spin_unlock_bh(&dev->sta_poll_lock); @@ -1032,6 +1071,240 @@ static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw, mt7915_mcu_sta_update_hdr_trans(dev, vif, sta); } +static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = { + "tx_ampdu_cnt", + "tx_stop_q_empty_cnt", + "tx_mpdu_attempts", + "tx_mpdu_success", + "tx_rwp_fail_cnt", + "tx_rwp_need_cnt", + "tx_pkt_ebf_cnt", + "tx_pkt_ibf_cnt", + "tx_ampdu_len:0-1", + "tx_ampdu_len:2-10", + "tx_ampdu_len:11-19", + "tx_ampdu_len:20-28", + "tx_ampdu_len:29-37", + "tx_ampdu_len:38-46", + "tx_ampdu_len:47-55", + "tx_ampdu_len:56-79", + "tx_ampdu_len:80-103", + "tx_ampdu_len:104-127", + "tx_ampdu_len:128-151", + "tx_ampdu_len:152-175", + "tx_ampdu_len:176-199", + "tx_ampdu_len:200-223", + "tx_ampdu_len:224-247", + "ba_miss_count", + "tx_beamformer_ppdu_iBF", + "tx_beamformer_ppdu_eBF", + "tx_beamformer_rx_feedback_all", + "tx_beamformer_rx_feedback_he", + "tx_beamformer_rx_feedback_vht", + "tx_beamformer_rx_feedback_ht", + "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */ + "tx_beamformer_rx_feedback_nc", + "tx_beamformer_rx_feedback_nr", + "tx_beamformee_ok_feedback_pkts", + "tx_beamformee_feedback_trig", + "tx_mu_beamforming", + "tx_mu_mpdu", + "tx_mu_successful_mpdu", + "tx_su_successful_mpdu", + "tx_msdu_pack_1", + "tx_msdu_pack_2", + "tx_msdu_pack_3", + "tx_msdu_pack_4", + "tx_msdu_pack_5", + "tx_msdu_pack_6", + "tx_msdu_pack_7", + "tx_msdu_pack_8", + + /* rx counters */ + "rx_fifo_full_cnt", + "rx_mpdu_cnt", + "channel_idle_cnt", + "rx_vector_mismatch_cnt", + "rx_delimiter_fail_cnt", + "rx_len_mismatch_cnt", + "rx_ampdu_cnt", + "rx_ampdu_bytes_cnt", + "rx_ampdu_valid_subframe_cnt", + "rx_ampdu_valid_subframe_b_cnt", + "rx_pfdrop_cnt", + "rx_vec_queue_overflow_drop_cnt", + "rx_ba_cnt", + + /* per vif counters */ + "v_tx_mode_cck", + "v_tx_mode_ofdm", + "v_tx_mode_ht", + "v_tx_mode_ht_gf", + "v_tx_mode_vht", + "v_tx_mode_he_su", + "v_tx_mode_he_ext_su", + "v_tx_mode_he_tb", + "v_tx_mode_he_mu", + "v_tx_bw_20", + "v_tx_bw_40", + "v_tx_bw_80", + "v_tx_bw_160", + "v_tx_mcs_0", + "v_tx_mcs_1", + "v_tx_mcs_2", + "v_tx_mcs_3", + "v_tx_mcs_4", + "v_tx_mcs_5", + "v_tx_mcs_6", + "v_tx_mcs_7", + "v_tx_mcs_8", + "v_tx_mcs_9", + "v_tx_mcs_10", + "v_tx_mcs_11", +}; + +#define MT7915_SSTATS_LEN ARRAY_SIZE(mt7915_gstrings_stats) + +/* Ethtool related API */ +static +void mt7915_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data) +{ + if (sset == ETH_SS_STATS) + memcpy(data, *mt7915_gstrings_stats, + sizeof(mt7915_gstrings_stats)); +} + +static +int mt7915_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset) +{ + if (sset == ETH_SS_STATS) + return MT7915_SSTATS_LEN; + + return 0; +} + +static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) +{ + struct mt76_ethtool_worker_info *wi = wi_data; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + if (msta->vif->idx != wi->idx) + return; + + mt76_ethtool_worker(wi, &msta->stats); +} + +static +void mt7915_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt76_ethtool_worker_info wi = { + .data = data, + .idx = mvif->idx, + }; + struct mib_stats *mib = &phy->mib; + /* See mt7915_ampdu_stat_read_phy, etc */ + bool ext_phy = phy != &dev->phy; + int i, n, ei = 0; + + mutex_lock(&dev->mt76.mutex); + + mt7915_mac_update_stats(phy); + + data[ei++] = mib->tx_ampdu_cnt; + data[ei++] = mib->tx_stop_q_empty_cnt; + data[ei++] = mib->tx_mpdu_attempts_cnt; + data[ei++] = mib->tx_mpdu_success_cnt; + data[ei++] = mib->tx_rwp_fail_cnt; + data[ei++] = mib->tx_rwp_need_cnt; + data[ei++] = mib->tx_pkt_ebf_cnt; + data[ei++] = mib->tx_pkt_ibf_cnt; + + /* Tx ampdu stat */ + n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; + for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) + data[ei++] = dev->mt76.aggr_stats[i + n]; + + data[ei++] = phy->mib.ba_miss_cnt; + + /* Tx Beamformer monitor */ + data[ei++] = mib->tx_bf_ibf_ppdu_cnt; + data[ei++] = mib->tx_bf_ebf_ppdu_cnt; + + /* Tx Beamformer Rx feedback monitor */ + data[ei++] = mib->tx_bf_rx_fb_all_cnt; + data[ei++] = mib->tx_bf_rx_fb_he_cnt; + data[ei++] = mib->tx_bf_rx_fb_vht_cnt; + data[ei++] = mib->tx_bf_rx_fb_ht_cnt; + + data[ei++] = mib->tx_bf_rx_fb_bw; + data[ei++] = mib->tx_bf_rx_fb_nc_cnt; + data[ei++] = mib->tx_bf_rx_fb_nr_cnt; + + /* Tx Beamformee Rx NDPA & Tx feedback report */ + data[ei++] = mib->tx_bf_fb_cpl_cnt; + data[ei++] = mib->tx_bf_fb_trig_cnt; + + /* Tx SU & MU counters */ + data[ei++] = mib->tx_bf_cnt; + data[ei++] = mib->tx_mu_mpdu_cnt; + data[ei++] = mib->tx_mu_acked_mpdu_cnt; + data[ei++] = mib->tx_su_acked_mpdu_cnt; + + /* Tx amsdu info (pack-count histogram) */ + for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) + data[ei++] = mib->tx_amsdu[i]; + + /* rx counters */ + data[ei++] = mib->rx_fifo_full_cnt; + data[ei++] = mib->rx_mpdu_cnt; + data[ei++] = mib->channel_idle_cnt; + data[ei++] = mib->rx_vector_mismatch_cnt; + data[ei++] = mib->rx_delimiter_fail_cnt; + data[ei++] = mib->rx_len_mismatch_cnt; + data[ei++] = mib->rx_ampdu_cnt; + data[ei++] = mib->rx_ampdu_bytes_cnt; + data[ei++] = mib->rx_ampdu_valid_subframe_cnt; + data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt; + data[ei++] = mib->rx_pfdrop_cnt; + data[ei++] = mib->rx_vec_queue_overflow_drop_cnt; + data[ei++] = mib->rx_ba_cnt; + + /* Add values for all stations owned by this vif */ + wi.initial_stat_idx = ei; + ieee80211_iterate_stations_atomic(hw, mt7915_ethtool_worker, &wi); + + mutex_unlock(&dev->mt76.mutex); + + if (wi.sta_count == 0) + return; + + ei += wi.worker_stat_count; + if (ei != MT7915_SSTATS_LEN) + dev_err(dev->mt76.dev, "ei: %d MT7915_SSTATS_LEN: %d", + ei, (int)MT7915_SSTATS_LEN); +} + +static void +mt7915_twt_teardown_request(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 flowid) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + + mutex_lock(&dev->mt76.mutex); + mt7915_mac_twt_teardown_flow(dev, msta, flowid); + mutex_unlock(&dev->mt76.mutex); +} + const struct ieee80211_ops mt7915_ops = { .tx = mt7915_tx, .start = mt7915_start, @@ -1056,6 +1329,9 @@ const struct ieee80211_ops mt7915_ops = { .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7915_channel_switch_beacon, .get_stats = mt7915_get_stats, + .get_et_sset_count = mt7915_get_et_sset_count, + .get_et_stats = mt7915_get_et_stats, + .get_et_strings = mt7915_get_et_strings, .get_tsf = mt7915_get_tsf, .set_tsf = mt7915_set_tsf, .offset_tsf = mt7915_offset_tsf, @@ -1067,6 +1343,8 @@ const struct ieee80211_ops mt7915_ops = { .sta_statistics = mt7915_sta_statistics, .sta_set_4addr = mt7915_sta_set_4addr, .sta_set_decap_offload = mt7915_sta_set_decap_offload, + .add_twt_setup = mt7915_mac_add_twt_setup, + .twt_teardown_request = mt7915_twt_teardown_request, CFG80211_TESTMODE_CMD(mt76_testmode_cmd) CFG80211_TESTMODE_DUMP(mt76_testmode_dump) #ifdef CONFIG_MAC80211_DEBUGFS diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 43960770a9af..b4cc4cb35762 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -416,7 +416,7 @@ exit: return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0); } -static void +static int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) { struct { @@ -429,7 +429,7 @@ mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) }, }; - mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); + return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } static void @@ -488,152 +488,6 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) dev->hw_pattern++; } -static int -mt7915_mcu_tx_rate_parse(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra, - struct rate_info *rate, u16 r) -{ - struct ieee80211_supported_band *sband; - u16 ru_idx = le16_to_cpu(ra->ru_idx); - bool cck = false; - - rate->mcs = FIELD_GET(MT_RA_RATE_MCS, r); - rate->nss = FIELD_GET(MT_RA_RATE_NSS, r) + 1; - - switch (FIELD_GET(MT_RA_RATE_TX_MODE, r)) { - case MT_PHY_TYPE_CCK: - cck = true; - fallthrough; - case MT_PHY_TYPE_OFDM: - if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) - sband = &mphy->sband_5g.sband; - else - sband = &mphy->sband_2g.sband; - - rate->mcs = mt76_get_rate(mphy->dev, sband, rate->mcs, cck); - rate->legacy = sband->bitrates[rate->mcs].bitrate; - break; - case MT_PHY_TYPE_HT: - case MT_PHY_TYPE_HT_GF: - rate->mcs += (rate->nss - 1) * 8; - if (rate->mcs > 31) - return -EINVAL; - - rate->flags = RATE_INFO_FLAGS_MCS; - if (ra->gi) - rate->flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case MT_PHY_TYPE_VHT: - if (rate->mcs > 9) - return -EINVAL; - - rate->flags = RATE_INFO_FLAGS_VHT_MCS; - if (ra->gi) - rate->flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case MT_PHY_TYPE_HE_SU: - case MT_PHY_TYPE_HE_EXT_SU: - case MT_PHY_TYPE_HE_TB: - case MT_PHY_TYPE_HE_MU: - if (ra->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11) - return -EINVAL; - - rate->he_gi = ra->gi; - rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); - rate->flags = RATE_INFO_FLAGS_HE_MCS; - break; - default: - return -EINVAL; - } - - if (ru_idx) { - switch (ru_idx) { - case 1 ... 2: - rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_996; - break; - case 3 ... 6: - rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_484; - break; - case 7 ... 14: - rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_242; - break; - default: - rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_106; - break; - } - rate->bw = RATE_INFO_BW_HE_RU; - } else { - u8 bw = mt7915_mcu_chan_bw(&mphy->chandef) - - FIELD_GET(MT_RA_RATE_BW, r); - - switch (bw) { - case IEEE80211_STA_RX_BW_160: - rate->bw = RATE_INFO_BW_160; - break; - case IEEE80211_STA_RX_BW_80: - rate->bw = RATE_INFO_BW_80; - break; - case IEEE80211_STA_RX_BW_40: - rate->bw = RATE_INFO_BW_40; - break; - default: - rate->bw = RATE_INFO_BW_20; - break; - } - } - - return 0; -} - -static void -mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) -{ - struct mt7915_mcu_ra_info *ra = (struct mt7915_mcu_ra_info *)skb->data; - struct rate_info rate = {}, prob_rate = {}; - u16 probe = le16_to_cpu(ra->prob_up_rate); - u16 attempts = le16_to_cpu(ra->attempts); - u16 curr = le16_to_cpu(ra->curr_rate); - u16 wcidx = le16_to_cpu(ra->wlan_idx); - struct ieee80211_tx_status status = {}; - struct mt76_phy *mphy = &dev->mphy; - struct mt7915_sta_stats *stats; - struct mt7915_sta *msta; - struct mt76_wcid *wcid; - - if (wcidx >= MT76_N_WCIDS) - return; - - wcid = rcu_dereference(dev->mt76.wcid[wcidx]); - if (!wcid) - return; - - msta = container_of(wcid, struct mt7915_sta, wcid); - stats = &msta->stats; - - if (msta->wcid.ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; - - /* current rate */ - if (!mt7915_mcu_tx_rate_parse(mphy, ra, &rate, curr)) - stats->tx_rate = rate; - - /* probing rate */ - if (!mt7915_mcu_tx_rate_parse(mphy, ra, &prob_rate, probe)) - stats->prob_rate = prob_rate; - - if (attempts) { - u16 success = le16_to_cpu(ra->success); - - stats->per = 1000 * (attempts - success) / attempts; - } - - status.sta = wcid_to_sta(wcid); - if (!status.sta) - return; - - status.rate = &stats->tx_rate; - ieee80211_tx_status_ext(mphy->hw, &status); -} - static void mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) { @@ -658,6 +512,15 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) } static void +mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + if (!vif->color_change_active) + return; + + ieee80211_color_change_finish(vif); +} + +static void mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; @@ -672,12 +535,14 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) case MCU_EXT_EVENT_CSA_NOTIFY: mt7915_mcu_rx_csa_notify(dev, skb); break; - case MCU_EXT_EVENT_RATE_REPORT: - mt7915_mcu_tx_rate_report(dev, skb); - break; case MCU_EXT_EVENT_FW_LOG_2_HOST: mt7915_mcu_rx_log_message(dev, skb); break; + case MCU_EXT_EVENT_BCC_NOTIFY: + ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7915_mcu_cca_finish, dev); + break; default: break; } @@ -706,7 +571,7 @@ void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || - rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || + rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY || !rxd->seq) mt7915_mcu_rx_unsolicited_event(dev, skb); else @@ -721,7 +586,7 @@ mt7915_mcu_alloc_sta_req(struct mt7915_dev *dev, struct mt7915_vif *mvif, .bss_idx = mvif->idx, .wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0, .wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0, - .muar_idx = msta ? mvif->omac_idx : 0, + .muar_idx = msta && msta->wcid.sta ? mvif->omac_idx : 0xe, .is_tlv_append = 1, }; struct sk_buff *skb; @@ -757,7 +622,7 @@ mt7915_mcu_alloc_wtbl_req(struct mt7915_dev *dev, struct mt7915_sta *msta, } if (sta_hdr) - sta_hdr->len = cpu_to_le16(sizeof(hdr)); + le16_add_cpu(&sta_hdr->len, sizeof(hdr)); return skb_put_data(nskb, &hdr, sizeof(hdr)); } @@ -923,12 +788,15 @@ static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, struct mt7915_he_obss_narrow_bw_ru_data *data = _data; const struct element *elem; + rcu_read_lock(); elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY); - if (!elem || elem->datalen < 10 || + if (!elem || elem->datalen <= 10 || !(elem->data[10] & WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) data->tolerated = false; + + rcu_read_unlock(); } static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, @@ -1201,7 +1069,7 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb, u8 cipher; cipher = mt7915_mcu_get_cipher(key->cipher); - if (cipher == MT_CIPHER_NONE) + if (cipher == MCU_CIPHER_NONE) return -EOPNOTSUPP; sec_key = &sec->key[0]; @@ -1317,7 +1185,7 @@ mt7915_mcu_wtbl_ba_tlv(struct sk_buff *skb, ba->rst_ba_sb = 1; } - if (enable && tx) + if (enable) ba->ba_winsize = cpu_to_le16(params->buf_size); } @@ -1469,17 +1337,21 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } static void -mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + struct ieee80211_vif *vif) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; - struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_he_cap_elem *elem = &sta->he_cap.he_cap_elem; enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band; const u16 *mcs_mask = msta->vif->bitrate_mask.control[band].he_mcs; struct sta_rec_he *he; struct tlv *tlv; u32 cap = 0; + if (!sta->he_cap.has_he) + return; + tlv = mt7915_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); he = (struct sta_rec_he *)tlv; @@ -1504,8 +1376,8 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; - if (elem->phy_cap_info[1] & - IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) + if (mvif->cap.ldpc && (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) cap |= STA_REC_HE_CAP_LDPC; if (elem->phy_cap_info[1] & @@ -1525,6 +1397,10 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; if (elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB) + cap |= STA_REC_HE_CAP_TRIG_CQI_FK; + + if (elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; @@ -1549,10 +1425,6 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; if (elem->phy_cap_info[9] & - IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK) - cap |= STA_REC_HE_CAP_TRIG_CQI_FK; - - if (elem->phy_cap_info[9] & IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; @@ -1640,19 +1512,45 @@ mt7915_mcu_sta_uapsd_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, } static void -mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + struct ieee80211_vif *vif) { - struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; - struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_he_cap_elem *elem = &sta->he_cap.he_cap_elem; struct sta_rec_muru *muru; struct tlv *tlv; + if (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP) + return; + + if (!sta->vht_cap.vht_supported) + return; + tlv = mt7915_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); muru = (struct sta_rec_muru *)tlv; - muru->cfg.ofdma_dl_en = true; - muru->cfg.mimo_dl_en = true; + muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer || + mvif->cap.vht_mu_ebfer || + mvif->cap.vht_mu_ebfee; + + muru->mimo_dl.vht_mu_bfee = + !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); + + if (!sta->he_cap.has_he) + return; + + muru->mimo_dl.partial_bw_dl_mimo = + HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); + + muru->cfg.mimo_ul_en = true; + muru->mimo_ul.full_ul_mimo = + HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); + muru->mimo_ul.partial_ul_mimo = + HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); + + muru->cfg.ofdma_dl_en = true; muru->ofdma_dl.punc_pream_rx = HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); muru->ofdma_dl.he_20m_in_40m_2g = @@ -1661,9 +1559,6 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); muru->ofdma_dl.he_80m_in_160m = HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); - muru->ofdma_dl.lt16_sigb = 0; - muru->ofdma_dl.rx_su_comp_sigb = 0; - muru->ofdma_dl.rx_su_non_comp_sigb = 0; muru->ofdma_ul.t_frame_dur = HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); @@ -1671,18 +1566,18 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]); muru->ofdma_ul.uo_ra = HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]); - muru->ofdma_ul.he_2x996_tone = 0; - muru->ofdma_ul.rx_t_frame_11ac = 0; +} - muru->mimo_dl.vht_mu_bfee = - !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); - muru->mimo_dl.partial_bw_dl_mimo = - HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); +static void +mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct sta_rec_ht *ht; + struct tlv *tlv; - muru->mimo_ul.full_ul_mimo = - HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); - muru->mimo_ul.partial_ul_mimo = - HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); + tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); + + ht = (struct sta_rec_ht *)tlv; + ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); } static void @@ -1691,6 +1586,9 @@ mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) struct sta_rec_vht *vht; struct tlv *tlv; + if (!sta->vht_cap.vht_supported) + return; + tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); vht = (struct sta_rec_vht *)tlv; @@ -1700,12 +1598,17 @@ mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) } static void -mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct sta_rec_amsdu *amsdu; struct tlv *tlv; + if (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP) + return; + if (!sta->max_amsdu_len) return; @@ -1718,44 +1621,6 @@ mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) msta->wcid.amsdu = true; } -static bool -mt7915_hw_amsdu_supported(struct ieee80211_vif *vif) -{ - switch (vif->type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_STATION: - return true; - default: - return false; - } -} - -static void -mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, - struct ieee80211_sta *sta, struct ieee80211_vif *vif) -{ - struct tlv *tlv; - - /* starec ht */ - if (sta->ht_cap.ht_supported) { - struct sta_rec_ht *ht; - - tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); - ht = (struct sta_rec_ht *)tlv; - ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); - - if (mt7915_hw_amsdu_supported(vif)) - mt7915_mcu_sta_amsdu_tlv(skb, sta); - } - - /* starec he */ - if (sta->he_cap.has_he) - mt7915_mcu_sta_he_tlv(skb, sta); - - /* starec uapsd */ - mt7915_mcu_sta_uapsd_tlv(skb, sta, vif); -} - static void mt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv) @@ -1766,15 +1631,15 @@ mt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), wtbl_tlv, sta_wtbl); smps = (struct wtbl_smps *)tlv; - - if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) - smps->smps = true; + smps->smps = (sta->smps_mode == IEEE80211_SMPS_DYNAMIC); } static void -mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, - void *sta_wtbl, void *wtbl_tlv) +mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *sta_wtbl, + void *wtbl_tlv) { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct wtbl_ht *ht = NULL; struct tlv *tlv; @@ -1783,7 +1648,8 @@ mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), wtbl_tlv, sta_wtbl); ht = (struct wtbl_ht *)tlv; - ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING); + ht->ldpc = mvif->cap.ldpc && + (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING); ht->af = sta->ht_cap.ampdu_factor; ht->mm = sta->ht_cap.ampdu_density; ht->ht = true; @@ -1797,7 +1663,8 @@ mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), wtbl_tlv, sta_wtbl); vht = (struct wtbl_vht *)tlv; - vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + vht->ldpc = mvif->cap.ldpc && + (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); vht->vht = true; af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, @@ -1838,6 +1705,32 @@ mt7915_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } } +static int +mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *tlv; + + msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, + tlv, &skb); + if (IS_ERR(wtbl_hdr)) + return PTR_ERR(wtbl_hdr); + + mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, tlv, wtbl_hdr); + mt7915_mcu_wtbl_hdr_trans_tlv(skb, vif, sta, tlv, wtbl_hdr); + + if (sta) + mt7915_mcu_wtbl_ht_tlv(skb, vif, sta, tlv, wtbl_hdr); + + return 0; +} + int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1887,10 +1780,48 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, MCU_EXT_CMD(STA_REC_UPDATE), true); } +static inline bool +mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool bfee) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int tx_ant = hweight8(phy->mt76->chainmask) - 1; + + if (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP) + return false; + + if (!bfee && tx_ant < 2) + return false; + + if (sta->he_cap.has_he) { + struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem; + + if (bfee) + return mvif->cap.he_su_ebfee && + HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); + else + return mvif->cap.he_su_ebfer && + HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); + } + + if (sta->vht_cap.vht_supported) { + u32 cap = sta->vht_cap.cap; + + if (bfee) + return mvif->cap.vht_su_ebfee && + (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); + else + return mvif->cap.vht_su_ebfer && + (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); + } + + return false; +} + static void mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf) { - bf->bf_cap = MT_EBF; bf->sounding_phy = MT_PHY_TYPE_OFDM; bf->ndp_rate = 0; /* mcs0 */ bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ @@ -1905,9 +1836,8 @@ mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy, u8 n = 0; bf->tx_mode = MT_PHY_TYPE_HT; - bf->bf_cap = MT_IBF; - if (mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF && + if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) && (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK, mcs->tx_params); @@ -1918,8 +1848,8 @@ mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy, else if (mcs->rx_mask[1]) n = 1; - bf->nr = hweight8(phy->mt76->chainmask) - 1; - bf->nc = min_t(u8, bf->nr, n); + bf->nrow = hweight8(phy->mt76->chainmask) - 1; + bf->ncol = min_t(u8, bf->nrow, n); bf->ibf_ncol = n; } @@ -1936,23 +1866,23 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy, bf->tx_mode = MT_PHY_TYPE_VHT; if (explicit) { - u8 bfee_nr, bfer_nr; + u8 sts, snd_dim; mt7915_mcu_sta_sounding_rate(bf); - bfee_nr = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, - pc->cap); - bfer_nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, + + sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, + pc->cap); + snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, vc->cap); - bf->nr = min_t(u8, min_t(u8, bfer_nr, bfee_nr), tx_ant); - bf->nc = min_t(u8, nss_mcs, bf->nr); - bf->ibf_ncol = bf->nc; + bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant); + bf->ncol = min_t(u8, nss_mcs, bf->nrow); + bf->ibf_ncol = bf->ncol; if (sta->bandwidth == IEEE80211_STA_RX_BW_160) - bf->nr = 1; + bf->nrow = 1; } else { - bf->bf_cap = MT_IBF; - bf->nr = tx_ant; - bf->nc = min_t(u8, nss_mcs, bf->nr); + bf->nrow = tx_ant; + bf->ncol = min_t(u8, nss_mcs, bf->nrow); bf->ibf_ncol = nss_mcs; if (sta->bandwidth == IEEE80211_STA_RX_BW_160) @@ -1970,21 +1900,23 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem; u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80); u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - u8 bfee_nr, bfer_nr; + u8 snd_dim, sts; bf->tx_mode = MT_PHY_TYPE_HE_SU; + mt7915_mcu_sta_sounding_rate(bf); + bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB, pe->phy_cap_info[6]); bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB, pe->phy_cap_info[6]); - bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, + snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, ve->phy_cap_info[5]); - bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, - pe->phy_cap_info[4]); - bf->nr = min_t(u8, bfer_nr, bfee_nr); - bf->nc = min_t(u8, nss_mcs, bf->nr); - bf->ibf_ncol = bf->nc; + sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, + pe->phy_cap_info[4]); + bf->nrow = min_t(u8, snd_dim, sts); + bf->ncol = min_t(u8, nss_mcs, bf->nrow); + bf->ibf_ncol = bf->ncol; if (sta->bandwidth != IEEE80211_STA_RX_BW_160) return; @@ -1995,7 +1927,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - bf->nc_bw160 = nss_mcs; + bf->ncol_bw160 = nss_mcs; } if (pe->phy_cap_info[0] & @@ -2003,25 +1935,27 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - if (bf->nc_bw160) - bf->nc_bw160 = min_t(u8, bf->nc_bw160, nss_mcs); + if (bf->ncol_bw160) + bf->ncol_bw160 = min_t(u8, bf->ncol_bw160, nss_mcs); else - bf->nc_bw160 = nss_mcs; + bf->ncol_bw160 = nss_mcs; } - bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, + snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, ve->phy_cap_info[5]); - bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, - pe->phy_cap_info[4]); + sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, + pe->phy_cap_info[4]); - bf->nr_bw160 = min_t(int, bfer_nr, bfee_nr); + bf->nrow_bw160 = min_t(int, snd_dim, sts); } static void -mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, struct mt7915_phy *phy, - bool enable, bool explicit) +mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_phy *phy = + mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; int tx_ant = hweight8(phy->mt76->chainmask) - 1; struct sta_rec_bf *bf; struct tlv *tlv; @@ -2031,43 +1965,42 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ }; + bool ebf; -#define MT_BFER_FREE cpu_to_le16(GENMASK(15, 0)) + ebf = mt7915_is_ebf_supported(phy, vif, sta, false); + if (!ebf && !dev->ibf) + return; tlv = mt7915_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf)); bf = (struct sta_rec_bf *)tlv; - if (!enable) { - bf->pfmu = MT_BFER_FREE; - return; - } - /* he: eBF only, in accordance with spec * vht: support eBF and iBF * ht: iBF only, since mac80211 lacks of eBF support */ - if (sta->he_cap.has_he && explicit) + if (sta->he_cap.has_he && ebf) mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); else if (sta->vht_cap.vht_supported) - mt7915_mcu_sta_bfer_vht(sta, phy, bf, explicit); + mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf); else if (sta->ht_cap.ht_supported) mt7915_mcu_sta_bfer_ht(sta, phy, bf); else return; + bf->bf_cap = ebf ? ebf : dev->ibf << 1; bf->bw = sta->bandwidth; bf->ibf_dbw = sta->bandwidth; bf->ibf_nrow = tx_ant; - if (!explicit && sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->nc) + if (!ebf && sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol) bf->ibf_timeout = 0x48; else bf->ibf_timeout = 0x18; - if (explicit && bf->nr != tx_ant) - bf->mem_20m = matrix[tx_ant][bf->nc]; + if (ebf && bf->nrow != tx_ant) + bf->mem_20m = matrix[tx_ant][bf->ncol]; else - bf->mem_20m = matrix[bf->nr][bf->nc]; + bf->mem_20m = matrix[bf->nrow][bf->ncol]; switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_160: @@ -2084,13 +2017,19 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, } static void -mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, - struct mt7915_phy *phy) +mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_phy *phy = + mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; int tx_ant = hweight8(phy->mt76->chainmask) - 1; struct sta_rec_bfee *bfee; struct tlv *tlv; - u8 nr = 0; + u8 nrow = 0; + + if (!mt7915_is_ebf_supported(phy, vif, sta, true)) + return; tlv = mt7915_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee)); bfee = (struct sta_rec_bfee *)tlv; @@ -2098,97 +2037,17 @@ mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, if (sta->he_cap.has_he) { struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem; - nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, - pe->phy_cap_info[5]); + nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, + pe->phy_cap_info[5]); } else if (sta->vht_cap.vht_supported) { struct ieee80211_sta_vht_cap *pc = &sta->vht_cap; - nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, - pc->cap); + nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, + pc->cap); } /* reply with identity matrix to avoid 2x2 BF negative gain */ - bfee->fb_identity_matrix = !!(nr == 1 && tx_ant == 2); -} - -static int -mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) -{ - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct mt7915_phy *phy; - struct sk_buff *skb; - int r, len; - bool ebfee = 0, ebf = 0; - - if (vif->type != NL80211_IFTYPE_STATION && - vif->type != NL80211_IFTYPE_AP) - return 0; - - phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; - - if (sta->he_cap.has_he) { - struct ieee80211_he_cap_elem *pe; - const struct ieee80211_he_cap_elem *ve; - const struct ieee80211_sta_he_cap *vc; - - pe = &sta->he_cap.he_cap_elem; - vc = mt7915_get_he_phy_cap(phy, vif); - ve = &vc->he_cap_elem; - - ebfee = !!(HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) && - HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4])); - ebf = !!(HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) && - HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])); - } else if (sta->vht_cap.vht_supported) { - struct ieee80211_sta_vht_cap *pc; - struct ieee80211_sta_vht_cap *vc; - - pc = &sta->vht_cap; - vc = &phy->mt76->sband_5g.sband.vht_cap; - - ebfee = !!((pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && - (vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)); - ebf = !!((vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && - (pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)); - } - - /* must keep each tag independent */ - - /* starec bf */ - if (ebf || dev->ibf) { - len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bf); - - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable, ebf); - - r = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD(STA_REC_UPDATE), true); - if (r) - return r; - } - - /* starec bfee */ - if (ebfee) { - len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bfee); - - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - mt7915_mcu_sta_bfee_tlv(skb, sta, phy); - - r = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD(STA_REC_UPDATE), true); - if (r) - return r; - } - - return 0; + bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); } static void @@ -2248,7 +2107,8 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_TX_STBC; if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) cap |= STA_CAP_RX_STBC; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) + if (mvif->cap.ldpc && + (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) cap |= STA_CAP_LDPC; mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mcs_mask); @@ -2273,7 +2133,8 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_VHT_TX_STBC; if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) cap |= STA_CAP_VHT_RX_STBC; - if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) + if (mvif->cap.ldpc && + (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) cap |= STA_CAP_VHT_LDPC; mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mcs_mask); @@ -2322,7 +2183,7 @@ int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (IS_ERR(skb)) return PTR_ERR(skb); - mt7915_mcu_sta_he_tlv(skb, sta); + mt7915_mcu_sta_he_tlv(skb, sta, vif); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); @@ -2334,7 +2195,7 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, { #define MT_STA_BSS_GROUP 1 struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_sta *msta; struct { __le32 action; u8 wlan_idx_lo; @@ -2345,75 +2206,24 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, u8 rsv1[8]; } __packed req = { .action = cpu_to_le32(MT_STA_BSS_GROUP), - .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), - .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), .val = cpu_to_le32(mvif->idx % 16), }; + msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; + req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx); + req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx); + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req, sizeof(req), true); } -static int -mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct sk_buff *skb; - int ret; - - if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) - return 0; - - ret = mt7915_mcu_add_group(dev, vif, sta); - if (ret) - return ret; - - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, - MT7915_STA_UPDATE_MAX_SIZE); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - /* wait until TxBF and MU ready to update stare vht */ - - /* starec muru */ - mt7915_mcu_sta_muru_tlv(skb, sta); - /* starec vht */ - mt7915_mcu_sta_vht_tlv(skb, sta); - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD(STA_REC_UPDATE), true); -} - -int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) -{ - int ret; - - if (!sta) - return 0; - - /* must keep the order */ - ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); - if (ret || !enable) - return ret; - - ret = mt7915_mcu_add_mu(dev, vif, sta); - if (ret) - return ret; - - return mt7915_mcu_add_rate_ctrl(dev, vif, sta); -} - int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct wtbl_req_hdr *wtbl_hdr; struct mt7915_sta *msta; - struct tlv *sta_wtbl; struct sk_buff *skb; + int ret; msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; @@ -2422,24 +2232,42 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (IS_ERR(skb)) return PTR_ERR(skb); + /* starec basic */ mt7915_mcu_sta_basic_tlv(skb, vif, sta, enable); - if (enable && sta) - mt7915_mcu_sta_tlv(dev, skb, sta, vif); + if (!enable) + goto out; - sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + /* tag order is in accordance with firmware dependency. */ + if (sta && sta->ht_cap.ht_supported) { + /* starec bfer */ + mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta); + /* starec ht */ + mt7915_mcu_sta_ht_tlv(skb, sta); + /* starec vht */ + mt7915_mcu_sta_vht_tlv(skb, sta); + /* starec uapsd */ + mt7915_mcu_sta_uapsd_tlv(skb, sta, vif); + } - wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, - sta_wtbl, &skb); - if (IS_ERR(wtbl_hdr)) - return PTR_ERR(wtbl_hdr); + ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta); + if (ret) + return ret; - if (enable) { - mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); - mt7915_mcu_wtbl_hdr_trans_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); - if (sta) - mt7915_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); + if (sta && sta->ht_cap.ht_supported) { + /* starec amsdu */ + mt7915_mcu_sta_amsdu_tlv(skb, vif, sta); + /* starec he */ + mt7915_mcu_sta_he_tlv(skb, sta, vif); + /* starec muru */ + mt7915_mcu_sta_muru_tlv(skb, sta, vif); + /* starec bfee */ + mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta); } + ret = mt7915_mcu_add_group(dev, vif, sta); + if (ret) + return ret; +out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); } @@ -2464,10 +2292,9 @@ int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, if (!rate) { ra->field = cpu_to_le32(RATE_PARAM_AUTO); goto out; - } else { - ra->field = cpu_to_le32(RATE_PARAM_FIXED); } + ra->field = cpu_to_le32(RATE_PARAM_FIXED); ra->phy.type = FIELD_GET(RATE_CFG_PHY_TYPE, rate); ra->phy.bw = FIELD_GET(RATE_CFG_BW, rate); ra->phy.nss = FIELD_GET(RATE_CFG_NSS, rate); @@ -2480,10 +2307,12 @@ int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, ra->phy.ldpc = FIELD_GET(RATE_CFG_LDPC, rate) * 7; /* HT/VHT - SGI: 1, LGI: 0; HE - SGI: 0, MGI: 1, LGI: 2 */ - if (ra->phy.type > MT_PHY_TYPE_VHT) - ra->phy.sgi = ra->phy.mcs * 85; - else - ra->phy.sgi = ra->phy.mcs * 15; + if (ra->phy.type > MT_PHY_TYPE_VHT) { + ra->phy.he_ltf = FIELD_GET(RATE_CFG_HE_LTF, rate) * 85; + ra->phy.sgi = FIELD_GET(RATE_CFG_GI, rate) * 85; + } else { + ra->phy.sgi = FIELD_GET(RATE_CFG_GI, rate) * 15; + } out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, @@ -2534,25 +2363,28 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, } static void -mt7915_mcu_beacon_csa(struct sk_buff *rskb, struct sk_buff *skb, - struct bss_info_bcn *bcn, - struct ieee80211_mutable_offsets *offs) +mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, + struct sk_buff *skb, struct bss_info_bcn *bcn, + struct ieee80211_mutable_offsets *offs) { - if (offs->cntdwn_counter_offs[0]) { - struct tlv *tlv; - struct bss_info_bcn_csa *csa; + struct bss_info_bcn_cntdwn *info; + struct tlv *tlv; + int sub_tag; - tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CSA, - sizeof(*csa), &bcn->sub_ntlv, - &bcn->len); - csa = (struct bss_info_bcn_csa *)tlv; - csa->cnt = skb->data[offs->cntdwn_counter_offs[0]]; - } + if (!offs->cntdwn_counter_offs[0]) + return; + + sub_tag = vif->csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC; + tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info), + &bcn->sub_ntlv, &bcn->len); + info = (struct bss_info_bcn_cntdwn *)tlv; + info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; } static void -mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, - struct sk_buff *skb, struct bss_info_bcn *bcn, +mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct sk_buff *rskb, struct sk_buff *skb, + struct bss_info_bcn *bcn, struct ieee80211_mutable_offsets *offs) { struct mt76_wcid *wcid = &dev->mt76.global_wcid; @@ -2568,8 +2400,14 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); cont->tim_ofs = cpu_to_le16(offs->tim_offset); - if (offs->cntdwn_counter_offs[0]) - cont->csa_ofs = cpu_to_le16(offs->cntdwn_counter_offs[0] - 4); + if (offs->cntdwn_counter_offs[0]) { + u16 offset = offs->cntdwn_counter_offs[0]; + + if (vif->csa_active) + cont->csa_ofs = cpu_to_le16(offset - 4); + if (vif->color_change_active) + cont->bcc_ofs = cpu_to_le16(offset - 3); + } buf = (u8 *)tlv + sizeof(*cont); mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL, @@ -2577,6 +2415,83 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } +static void +mt7915_mcu_beacon_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct sk_buff *skb) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_vif_cap *vc = &mvif->cap; + const struct ieee80211_he_cap_elem *he; + const struct ieee80211_vht_cap *vht; + const struct ieee80211_ht_cap *ht; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + const u8 *ie; + u32 len, bc; + + /* Check missing configuration options to allow AP mode in mac80211 + * to remain in sync with hostapd settings, and get a subset of + * beacon and hardware capabilities. + */ + if (WARN_ON_ONCE(skb->len <= (mgmt->u.beacon.variable - skb->data))) + return; + + memset(vc, 0, sizeof(*vc)); + + len = skb->len - (mgmt->u.beacon.variable - skb->data); + + ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, mgmt->u.beacon.variable, + len); + if (ie && ie[1] >= sizeof(*ht)) { + ht = (void *)(ie + 2); + bc = le32_to_cpu(ht->cap_info); + + vc->ldpc |= !!(bc & IEEE80211_HT_CAP_LDPC_CODING); + } + + ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, mgmt->u.beacon.variable, + len); + if (ie && ie[1] >= sizeof(*vht)) { + u32 pc = phy->mt76->sband_5g.sband.vht_cap.cap; + + vht = (void *)(ie + 2); + bc = le32_to_cpu(vht->vht_cap_info); + + vc->ldpc |= !!(bc & IEEE80211_VHT_CAP_RXLDPC); + vc->vht_su_ebfer = + (bc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && + (pc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); + vc->vht_su_ebfee = + (bc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) && + (pc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); + vc->vht_mu_ebfer = + (bc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) && + (pc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); + vc->vht_mu_ebfee = + (bc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && + (pc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); + } + + ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, + mgmt->u.beacon.variable, len); + if (ie && ie[1] >= sizeof(*he) + 1) { + const struct ieee80211_sta_he_cap *pc = + mt7915_get_he_phy_cap(phy, vif); + const struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; + + he = (void *)(ie + 3); + + vc->he_su_ebfer = + HE_PHY(CAP3_SU_BEAMFORMER, he->phy_cap_info[3]) && + HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); + vc->he_su_ebfee = + HE_PHY(CAP4_SU_BEAMFORMEE, he->phy_cap_info[4]) && + HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); + vc->he_mu_ebfer = + HE_PHY(CAP4_MU_BEAMFORMER, he->phy_cap_info[4]) && + HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4]); + } +} + int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int en) { @@ -2617,9 +2532,11 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; } - /* TODO: subtag - bss color count & 11v MBSSID */ - mt7915_mcu_beacon_csa(rskb, skb, bcn, &offs); - mt7915_mcu_beacon_cont(dev, rskb, skb, bcn, &offs); + mt7915_mcu_beacon_check_caps(phy, vif, skb); + + /* TODO: subtag - 11v MBSSID */ + mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs); + mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs); dev_kfree_skb(skb); out: @@ -2770,8 +2687,8 @@ static int mt7915_load_patch(struct mt7915_dev *dev) goto out; } - ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), - dl, len); + ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), + dl, len, 4096); if (ret) { dev_err(dev->mt76.dev, "Failed to send patch\n"); goto out; @@ -2790,7 +2707,7 @@ out: default: ret = -EAGAIN; dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); - goto out; + break; } release_firmware(fw); @@ -2839,8 +2756,8 @@ mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, return err; } - err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), - data + offset, len); + err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), + data + offset, len, 4096); if (err) { dev_err(dev->mt76.dev, "Failed to send firmware.\n"); return err; @@ -2990,6 +2907,62 @@ static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled) sizeof(req), false); } +int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val) +{ + struct { + __le32 cmd; + u8 val[4]; + } __packed req = { + .cmd = cpu_to_le32(cmd), + }; + + put_unaligned_le32(val, req.val); + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req, + sizeof(req), false); +} + +static int +mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) +{ +#define RX_AIRTIME_FEATURE_CTRL 1 +#define RX_AIRTIME_BITWISE_CTRL 2 +#define RX_AIRTIME_CLEAR_EN 1 + struct { + __le16 field; + __le16 sub_field; + __le32 set_status; + __le32 get_status; + u8 _rsv[12]; + + bool airtime_en; + bool mibtime_en; + bool earlyend_en; + u8 _rsv1[9]; + + bool airtime_clear; + bool mibtime_clear; + u8 _rsv2[98]; + } __packed req = { + .field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL), + .sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN), + .airtime_clear = true, + }; + int ret; + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req, + sizeof(req), true); + if (ret) + return ret; + + req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL); + req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN); + req.airtime_en = true; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req, + sizeof(req), true); +} + int mt7915_mcu_init(struct mt7915_dev *dev) { static const struct mt76_mcu_ops mt7915_mcu_ops = { @@ -3011,11 +2984,25 @@ int mt7915_mcu_init(struct mt7915_dev *dev) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); - mt7915_mcu_fw_log_2_host(dev, 0); - mt7915_mcu_set_mwds(dev, 1); - mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_RED, 0, 0); + ret = mt7915_mcu_fw_log_2_host(dev, 0); + if (ret) + return ret; - return 0; + ret = mt7915_mcu_set_mwds(dev, 1); + if (ret) + return ret; + + ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE, + MURU_PLATFORM_TYPE_PERF_LEVEL_2); + if (ret) + return ret; + + ret = mt7915_mcu_init_rx_airtime(dev); + if (ret) + return ret; + + return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), + MCU_WA_PARAM_RED, 0, 0); } void mt7915_mcu_exit(struct mt7915_dev *dev) @@ -3391,20 +3378,20 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev) { -#define TOTAL_PAGE_MASK GENMASK(7, 5) +#define MAX_PAGE_IDX_MASK GENMASK(7, 5) #define PAGE_IDX_MASK GENMASK(4, 2) #define PER_PAGE_SIZE 0x400 struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER }; - u8 total = MT7915_EEPROM_SIZE / PER_PAGE_SIZE; + u8 total = DIV_ROUND_UP(MT7915_EEPROM_SIZE, PER_PAGE_SIZE); u8 *eep = (u8 *)dev->mt76.eeprom.data; int eep_len; int i; - for (i = 0; i <= total; i++, eep += eep_len) { + for (i = 0; i < total; i++, eep += eep_len) { struct sk_buff *skb; int ret; - if (i == total) + if (i == total - 1 && !!(MT7915_EEPROM_SIZE % PER_PAGE_SIZE)) eep_len = MT7915_EEPROM_SIZE % PER_PAGE_SIZE; else eep_len = PER_PAGE_SIZE; @@ -3414,7 +3401,7 @@ static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev) if (!skb) return -ENOMEM; - req.format = FIELD_PREP(TOTAL_PAGE_MASK, total) | + req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) | FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE; req.len = cpu_to_le16(eep_len); @@ -3481,7 +3468,7 @@ static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx, u8 idx; u8 rsv[4]; __le32 len; - } req; + } req = {}; struct sk_buff *skb; skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len); @@ -3691,10 +3678,6 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) }; int level; -#define TRIGGER_TEMPERATURE 122 -#define RESTORE_TEMPERATURE 116 -#define SUSTAIN_PERIOD 10 - if (!state) { req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE; goto out; @@ -3707,7 +3690,7 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) req.ctrl.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG; req.ctrl.duty.duty_level = level; req.ctrl.duty.duty_cycle = state; - state = state * 4 / 5; + state /= 2; ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), &req, sizeof(req.ctrl), false); @@ -3715,15 +3698,12 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) return ret; } - /* currently use fixed values for throttling, and would be better - * to implement thermal zone for dynamic trip in the long run. - */ - /* set high-temperature trigger threshold */ req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE; - req.trigger_temp = cpu_to_le32(TRIGGER_TEMPERATURE); - req.restore_temp = cpu_to_le32(RESTORE_TEMPERATURE); - req.sustain_time = cpu_to_le16(SUSTAIN_PERIOD); + /* add a safety margin ~10 */ + req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10); + req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]); + req.sustain_time = cpu_to_le16(10); out: req.ctrl.type.protect_type = 1; @@ -3733,24 +3713,6 @@ out: &req, sizeof(req), false); } -int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) -{ - struct { - __le32 cmd; - __le16 wlan_idx; - __le16 ru_idx; - __le16 direction; - __le16 dump_group; - } req = { - .cmd = cpu_to_le32(cmd), - .wlan_idx = cpu_to_le16(wlan_idx), - .dump_group = cpu_to_le16(1), - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RATE_CTRL), &req, - sizeof(req), false); -} - int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; @@ -4069,3 +4031,75 @@ out: return ret; } + +int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct cfg80211_he_bss_color *he_bss_color) +{ + int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct bss_info_color *bss_color; + struct sk_buff *skb; + struct tlv *tlv; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR, sizeof(*bss_color)); + bss_color = (struct bss_info_color *)tlv; + bss_color->disable = !he_bss_color->enabled; + bss_color->color = he_bss_color->color; + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(BSS_INFO_UPDATE), true); +} + +#define TWT_AGRT_TRIGGER BIT(0) +#define TWT_AGRT_ANNOUNCE BIT(1) +#define TWT_AGRT_PROTECT BIT(2) + +int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, + struct mt7915_vif *mvif, + struct mt7915_twt_flow *flow, + int cmd) +{ + struct { + u8 tbl_idx; + u8 cmd; + u8 own_mac_idx; + u8 flowid; /* 0xff for group id */ + __le16 peer_id; /* specify the peer_id (msb=0) + * or group_id (msb=1) + */ + u8 duration; /* 256 us */ + u8 bss_idx; + __le64 start_tsf; + __le16 mantissa; + u8 exponent; + u8 is_ap; + u8 agrt_params; + u8 rsv[23]; + } __packed req = { + .tbl_idx = flow->table_id, + .cmd = cmd, + .own_mac_idx = mvif->omac_idx, + .flowid = flow->id, + .peer_id = cpu_to_le16(flow->wcid), + .duration = flow->duration, + .bss_idx = mvif->idx, + .start_tsf = cpu_to_le64(flow->tsf), + .mantissa = flow->mantissa, + .exponent = flow->exp, + .is_ap = true, + }; + + if (flow->protection) + req.agrt_params |= TWT_AGRT_PROTECT; + if (!flow->flowtype) + req.agrt_params |= TWT_AGRT_ANNOUNCE; + if (flow->trigger) + req.agrt_params |= TWT_AGRT_TRIGGER; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE), + &req, sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index e68a562cc5b4..d66918d914da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -43,7 +43,7 @@ enum { MCU_EXT_EVENT_ASSERT_DUMP = 0x23, MCU_EXT_EVENT_RDD_REPORT = 0x3a, MCU_EXT_EVENT_CSA_NOTIFY = 0x4f, - MCU_EXT_EVENT_RATE_REPORT = 0x87, + MCU_EXT_EVENT_BCC_NOTIFY = 0x75, }; enum { @@ -164,41 +164,6 @@ struct mt7915_mcu_eeprom_info { u8 data[16]; } __packed; -struct mt7915_mcu_ra_info { - struct mt7915_mcu_rxd rxd; - - __le32 event_id; - __le16 wlan_idx; - __le16 ru_idx; - __le16 direction; - __le16 dump_group; - - __le32 suggest_rate; - __le32 min_rate; /* for dynamic sounding */ - __le32 max_rate; /* for dynamic sounding */ - __le32 init_rate_down_rate; - - __le16 curr_rate; - __le16 init_rate_down_total; - __le16 init_rate_down_succ; - __le16 success; - __le16 attempts; - - __le16 prev_rate; - __le16 prob_up_rate; - u8 no_rate_up_cnt; - u8 ppdu_cnt; - u8 gi; - - u8 try_up_fail; - u8 try_up_total; - u8 suggest_wf; - u8 try_up_check; - u8 prob_up_period; - u8 prob_down_pending; -} __packed; - - struct mt7915_mcu_phy_rx_info { u8 category; u8 rate; @@ -210,12 +175,6 @@ struct mt7915_mcu_phy_rx_info { u8 bw; }; -#define MT_RA_RATE_NSS GENMASK(8, 6) -#define MT_RA_RATE_MCS GENMASK(3, 0) -#define MT_RA_RATE_TX_MODE GENMASK(12, 9) -#define MT_RA_RATE_DCM_EN BIT(4) -#define MT_RA_RATE_BW GENMASK(14, 13) - struct mt7915_mcu_mib { __le32 band; __le32 offs; @@ -312,15 +271,17 @@ enum { MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, MCU_EXT_CMD_RX_HDR_TRANS = 0x47, MCU_EXT_CMD_MUAR_UPDATE = 0x48, + MCU_EXT_CMD_RX_AIRTIME_CTRL = 0x4a, MCU_EXT_CMD_SET_RX_PATH = 0x4e, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, MCU_EXT_CMD_GET_MIB_INFO = 0x5a, MCU_EXT_CMD_MWDS_SUPPORT = 0x80, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, - MCU_EXT_CMD_RATE_CTRL = 0x87, + MCU_EXT_CMD_TWT_AGRT_UPDATE = 0x94, MCU_EXT_CMD_FW_DBG_CTRL = 0x95, MCU_EXT_CMD_SET_RDD_TH = 0x9d, + MCU_EXT_CMD_MURU_CTRL = 0x9f, MCU_EXT_CMD_SET_SPR = 0xa8, MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab, MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac, @@ -328,6 +289,14 @@ enum { }; enum { + MCU_TWT_AGRT_ADD, + MCU_TWT_AGRT_MODIFY, + MCU_TWT_AGRT_DELETE, + MCU_TWT_AGRT_TEARDOWN, + MCU_TWT_AGRT_GET_TSF, +}; + +enum { MCU_WA_PARAM_CMD_QUERY, MCU_WA_PARAM_CMD_SET, MCU_WA_PARAM_CMD_CAPABILITY, @@ -545,6 +514,14 @@ struct bss_info_hw_amsdu { u8 rsv; } __packed; +struct bss_info_color { + __le16 tag; + __le16 len; + u8 disable; + u8 color; + u8 rsv[2]; +} __packed; + struct bss_info_he { __le16 tag; __le16 len; @@ -563,14 +540,7 @@ struct bss_info_bcn { __le16 sub_ntlv; } __packed __aligned(4); -struct bss_info_bcn_csa { - __le16 tag; - __le16 len; - u8 cnt; - u8 rsv[3]; -} __packed __aligned(4); - -struct bss_info_bcn_bcc { +struct bss_info_bcn_cntdwn { __le16 tag; __le16 len; u8 cnt; @@ -716,6 +686,7 @@ struct wtbl_ba { __le16 sn; u8 ba_en; u8 ba_winsize_idx; + /* originator & recipient */ __le16 ba_winsize; /* recipient only */ u8 peer_addr[ETH_ALEN]; @@ -989,6 +960,7 @@ struct sta_rec_ra_fixed { #define RATE_CFG_STBC GENMASK(19, 16) #define RATE_CFG_LDPC GENMASK(23, 20) #define RATE_CFG_PHY_TYPE GENMASK(27, 24) +#define RATE_CFG_HE_LTF GENMASK(31, 28) struct sta_rec_bf { __le16 tag; @@ -1002,8 +974,8 @@ struct sta_rec_bf { u8 ndp_rate; u8 rept_poll_rate; u8 tx_mode; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT ... */ - u8 nc; - u8 nr; + u8 ncol; + u8 nrow; u8 bw; /* 0: 20M, 1: 40M, 2: 80M, 3: 160M */ u8 mem_total; @@ -1023,8 +995,8 @@ struct sta_rec_bf { u8 ibf_dbw; u8 ibf_ncol; u8 ibf_nrow; - u8 nr_bw160; - u8 nc_bw160; + u8 nrow_bw160; + u8 ncol_bw160; u8 ru_start_idx; u8 ru_end_idx; @@ -1036,7 +1008,7 @@ struct sta_rec_bf { bool codebook75_mu; u8 he_ltf; - u8 rsv[2]; + u8 rsv[3]; } __packed; struct sta_rec_bfee { @@ -1116,16 +1088,21 @@ enum { }; enum { - MT_EBF = BIT(0), /* explicit beamforming */ - MT_IBF = BIT(1) /* implicit beamforming */ -}; - -enum { MT_BF_SOUNDING_ON = 1, MT_BF_TYPE_UPDATE = 20, MT_BF_MODULE_UPDATE = 25 }; +enum { + MURU_SET_ARB_OP_MODE = 14, + MURU_SET_PLATFORM_TYPE = 25, +}; + +enum { + MURU_PLATFORM_TYPE_PERF_LEVEL_1 = 1, + MURU_PLATFORM_TYPE_PERF_LEVEL_2, +}; + #define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ sizeof(struct wtbl_generic) + \ sizeof(struct wtbl_rx) + \ @@ -1137,12 +1114,15 @@ enum { #define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ + sizeof(struct sta_rec_bf) + \ sizeof(struct sta_rec_ht) + \ sizeof(struct sta_rec_he) + \ sizeof(struct sta_rec_ba) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct sta_rec_uapsd) + \ sizeof(struct sta_rec_amsdu) + \ + sizeof(struct sta_rec_muru) + \ + sizeof(struct sta_rec_bfee) + \ sizeof(struct tlv) + \ MT7915_WTBL_UPDATE_MAX_SIZE) @@ -1157,8 +1137,7 @@ enum { sizeof(struct bss_info_ext_bss)) #define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \ - sizeof(struct bss_info_bcn_csa) + \ - sizeof(struct bss_info_bcn_bcc) + \ + sizeof(struct bss_info_bcn_cntdwn) + \ sizeof(struct bss_info_bcn_mbss) + \ sizeof(struct bss_info_bcn_cont)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index af712a936ef6..7bbb38e7116a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -92,8 +92,7 @@ static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) } if ((addr >= 0x18000000 && addr < 0x18c00000) || - (addr >= 0x70000000 && addr < 0x78000000) || - (addr >= 0x7c000000 && addr < 0x7c400000)) + (addr >= 0x70000000 && addr < 0x78000000)) return mt7915_reg_map_l1(dev, addr); return mt7915_reg_map_l2(dev, addr); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 3f613fae6218..fff15f6b9cad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -36,13 +36,14 @@ #define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ -#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ -#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */ #define MT7915_THERMAL_THROTTLE_MAX 100 #define MT7915_SKU_RATE_NUM 161 +#define MT7915_MAX_TWT_AGRT 16 +#define MT7915_MAX_STA_TWT_AGRT 8 + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -64,35 +65,59 @@ enum mt7915_rxq_id { MT7915_RXQ_MCU_WA_EXT, }; -struct mt7915_sta_stats { - struct rate_info prob_rate; - struct rate_info tx_rate; - - unsigned long per; - unsigned long changed; - unsigned long jiffies; -}; - struct mt7915_sta_key_conf { s8 keyidx; u8 key[16]; }; +struct mt7915_twt_flow { + struct list_head list; + u64 start_tsf; + u64 tsf; + u32 duration; + u16 wcid; + __le16 mantissa; + u8 exp; + u8 table_id; + u8 id; + u8 protection:1; + u8 flowtype:1; + u8 trigger:1; + u8 sched:1; +}; + struct mt7915_sta { struct mt76_wcid wcid; /* must be first */ struct mt7915_vif *vif; - struct list_head stats_list; struct list_head poll_list; struct list_head rc_list; u32 airtime_ac[8]; - struct mt7915_sta_stats stats; - + unsigned long changed; + unsigned long jiffies; unsigned long ampdu_state; + struct mt76_sta_stats stats; + struct mt7915_sta_key_conf bip; + + struct { + u8 flowid_mask; + struct mt7915_twt_flow flow[MT7915_MAX_STA_TWT_AGRT]; + } twt; +}; + +struct mt7915_vif_cap { + bool ldpc:1; + bool vht_su_ebfer:1; + bool vht_su_ebfee:1; + bool vht_mu_ebfer:1; + bool vht_mu_ebfee:1; + bool he_su_ebfer:1; + bool he_su_ebfee:1; + bool he_mu_ebfer:1; }; struct mt7915_vif { @@ -101,6 +126,7 @@ struct mt7915_vif { u8 band_idx; u8 wmm_idx; + struct mt7915_vif_cap cap; struct mt7915_sta sta; struct mt7915_phy *phy; @@ -108,12 +134,58 @@ struct mt7915_vif { struct cfg80211_bitrate_mask bitrate_mask; }; +/* per-phy stats. */ struct mib_stats { u32 ack_fail_cnt; u32 fcs_err_cnt; u32 rts_cnt; u32 rts_retries_cnt; u32 ba_miss_cnt; + u32 tx_bf_cnt; + u32 tx_mu_mpdu_cnt; + u32 tx_mu_acked_mpdu_cnt; + u32 tx_su_acked_mpdu_cnt; + u32 tx_bf_ibf_ppdu_cnt; + u32 tx_bf_ebf_ppdu_cnt; + + u32 tx_bf_rx_fb_all_cnt; + u32 tx_bf_rx_fb_he_cnt; + u32 tx_bf_rx_fb_vht_cnt; + u32 tx_bf_rx_fb_ht_cnt; + + u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */ + u32 tx_bf_rx_fb_nc_cnt; + u32 tx_bf_rx_fb_nr_cnt; + u32 tx_bf_fb_cpl_cnt; + u32 tx_bf_fb_trig_cnt; + + u32 tx_ampdu_cnt; + u32 tx_stop_q_empty_cnt; + u32 tx_mpdu_attempts_cnt; + u32 tx_mpdu_success_cnt; + u32 tx_pkt_ebf_cnt; + u32 tx_pkt_ibf_cnt; + + u32 tx_rwp_fail_cnt; + u32 tx_rwp_need_cnt; + + /* rx stats */ + u32 rx_fifo_full_cnt; + u32 channel_idle_cnt; + u32 rx_vector_mismatch_cnt; + u32 rx_delimiter_fail_cnt; + u32 rx_len_mismatch_cnt; + u32 rx_mpdu_cnt; + u32 rx_ampdu_cnt; + u32 rx_ampdu_bytes_cnt; + u32 rx_ampdu_valid_subframe_cnt; + u32 rx_ampdu_valid_subframe_bytes_cnt; + u32 rx_pfdrop_cnt; + u32 rx_vec_queue_overflow_drop_cnt; + u32 rx_ba_cnt; + + u32 tx_amsdu[8]; + u32 tx_amsdu_cnt; }; struct mt7915_hif { @@ -134,6 +206,7 @@ struct mt7915_phy { struct thermal_cooling_device *cdev; u8 throttle_state; + u32 throttle_temp[2]; /* 0: critical high, 1: maximum */ u32 rxfilter; u64 omac_mask; @@ -151,9 +224,6 @@ struct mt7915_phy { struct mib_stats mib; struct mt76_channel_state state_ts; - struct list_head stats_list; - - u8 sta_work_count; #ifdef CONFIG_NL80211_TESTMODE struct { @@ -193,6 +263,7 @@ struct mt7915_dev { struct list_head sta_rc_list; struct list_head sta_poll_list; + struct list_head twt_list; spinlock_t sta_poll_lock; u32 hw_pattern; @@ -203,6 +274,11 @@ struct mt7915_dev { bool ibf; void *cal; + + struct { + u8 table_mask; + u8 n_agrt; + } twt; }; enum { @@ -220,13 +296,17 @@ enum { }; enum { - MT_LMAC_AC00, + MT_CTX0, + MT_HIF0 = 0x0, + + MT_LMAC_AC00 = 0x0, MT_LMAC_AC01, MT_LMAC_AC02, MT_LMAC_AC03, MT_LMAC_ALTX0 = 0x10, MT_LMAC_BMC0, MT_LMAC_BCN0, + MT_LMAC_PSMP0, }; enum { @@ -250,13 +330,6 @@ enum mt7915_rdd_cmd { RDD_IRQ_OFF, }; -enum { - RATE_CTRL_RU_INFO, - RATE_CTRL_FIXED_RATE_INFO, - RATE_CTRL_DUMP_INFO, - RATE_CTRL_MU_INFO, -}; - static inline struct mt7915_phy * mt7915_hw_phy(struct ieee80211_hw *hw) { @@ -294,7 +367,7 @@ extern const struct ieee80211_ops mt7915_ops; extern const struct mt76_testmode_ops mt7915_testmode_ops; u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr); - +u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif); int mt7915_register_device(struct mt7915_dev *dev); void mt7915_unregister_device(struct mt7915_dev *dev); int mt7915_eeprom_init(struct mt7915_dev *dev); @@ -307,14 +380,16 @@ int mt7915_dma_init(struct mt7915_dev *dev); void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev); int mt7915_mcu_init(struct mt7915_dev *dev); +int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, + struct mt7915_vif *mvif, + struct mt7915_twt_flow *flow, + int cmd); int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool enable); int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, int enable); int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable); -int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable); int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); @@ -327,6 +402,8 @@ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct mt7915_sta *msta, struct ieee80211_key_conf *key, enum set_key_cmd cmd); +int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct cfg80211_he_bss_color *he_bss_color); int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int enable); int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, @@ -362,12 +439,12 @@ int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, const struct mt7915_dfs_pulse *pulse); int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, const struct mt7915_dfs_pattern *pattern); +int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val); int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev); int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy); int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch); int mt7915_mcu_get_temperature(struct mt7915_phy *phy); int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state); -int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate); int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd, @@ -418,7 +495,14 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt7915_mac_work(struct work_struct *work); void mt7915_mac_reset_work(struct work_struct *work); void mt7915_mac_sta_rc_work(struct work_struct *work); +void mt7915_mac_update_stats(struct mt7915_phy *phy); int mt7915_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, int irq); +void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev, + struct mt7915_sta *msta, + u8 flowid); +void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct ieee80211_twt_setup *twt); int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, @@ -435,7 +519,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); void mt7915_set_stream_he_caps(struct mt7915_phy *phy); void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy); void mt7915_update_channel(struct mt76_phy *mphy); -int mt7915_init_debugfs(struct mt7915_dev *dev); +int mt7915_init_debugfs(struct mt7915_phy *phy); #ifdef CONFIG_MAC80211_DEBUGFS void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 340b364da5f0..0af4cdb897b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -222,8 +222,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev, static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), - .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | - MT_DRV_AMSDU_OFFLOAD, + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, @@ -251,7 +250,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index a213b5cb82f8..a2e98788f421 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -22,15 +22,22 @@ #define MT_PLE_BASE 0x8000 #define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) -#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) -#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) -#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) -#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc) - -#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ +#define MT_FL_Q_EMPTY 0x0b0 +#define MT_FL_Q0_CTRL 0x1b0 +#define MT_FL_Q2_CTRL 0x1b8 +#define MT_FL_Q3_CTRL 0x1bc + +#define MT_PLE_FREEPG_CNT MT_PLE(0x100) +#define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(0x104) +#define MT_PLE_PG_HIF_GROUP MT_PLE(0x110) +#define MT_PLE_HIF_PG_INFO MT_PLE(0x114) +#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x500 + 0x40 * (ac) + \ ((n) << 2)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) +#define MT_PSE_BASE 0xc000 +#define MT_PSE(ofs) (MT_PSE_BASE + (ofs)) + #define MT_MDP_BASE 0xf000 #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) @@ -57,6 +64,7 @@ #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) #define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0) +#define MT_TMAC_TCR0_TX_BLINK GENMASK(7, 6) #define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25) #define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090) @@ -72,11 +80,14 @@ #define MT_TMAC_TRCR0_I2T_CHK GENMASK(24, 16) #define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4) -#define MT_IFS_EIFS GENMASK(8, 0) +#define MT_IFS_EIFS_OFDM GENMASK(8, 0) #define MT_IFS_RIFS GENMASK(14, 10) #define MT_IFS_SIFS GENMASK(22, 16) #define MT_IFS_SLOT GENMASK(30, 24) +#define MT_TMAC_ICR1(_band) MT_WF_TMAC(_band, 0x0b4) +#define MT_IFS_EIFS_CCK GENMASK(8, 0) + #define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4) #define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0) #define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) @@ -128,15 +139,120 @@ #define MT_LPON_TCR_SW_READ GENMASK(1, 0) /* MIB: band 0(0x24800), band 1(0xa4800) */ +/* These counters are (mostly?) clear-on-read. So, some should not + * be read at all in case firmware is already reading them. These + * are commented with 'DNR' below. The DNR stats will be read by querying + * the firmware API for the appropriate message. For counters the driver + * does read, the driver should accumulate the counters. + */ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) +#define MT_MIB_SDR0(_band) MT_WF_MIB(_band, 0x010) +#define MT_MIB_SDR0_BERACON_TX_CNT_MASK GENMASK(15, 0) + #define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) #define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) +#define MT_MIB_SDR4(_band) MT_WF_MIB(_band, 0x018) +#define MT_MIB_SDR4_RX_FIFO_FULL_MASK GENMASK(15, 0) + +/* rx mpdu counter, full 32 bits */ +#define MT_MIB_SDR5(_band) MT_WF_MIB(_band, 0x01c) + +#define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020) +#define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0) + +#define MT_MIB_SDR7(_band) MT_WF_MIB(_band, 0x024) +#define MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK GENMASK(15, 0) + +#define MT_MIB_SDR8(_band) MT_WF_MIB(_band, 0x028) +#define MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK GENMASK(15, 0) + +/* aka CCA_NAV_TX_TIME */ +#define MT_MIB_SDR9_DNR(_band) MT_WF_MIB(_band, 0x02c) +#define MT_MIB_SDR9_CCA_BUSY_TIME_MASK GENMASK(23, 0) + +#define MT_MIB_SDR10_DNR(_band) MT_WF_MIB(_band, 0x030) +#define MT_MIB_SDR10_MRDY_COUNT_MASK GENMASK(25, 0) + +#define MT_MIB_SDR11(_band) MT_WF_MIB(_band, 0x034) +#define MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK GENMASK(15, 0) + +/* tx ampdu cnt, full 32 bits */ +#define MT_MIB_SDR12(_band) MT_WF_MIB(_band, 0x038) + +#define MT_MIB_SDR13(_band) MT_WF_MIB(_band, 0x03c) +#define MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK GENMASK(15, 0) + +/* counts all mpdus in ampdu, regardless of success */ +#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x040) +#define MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK GENMASK(23, 0) + +/* counts all successfully tx'd mpdus in ampdu */ +#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x044) +#define MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK GENMASK(23, 0) + +/* in units of 'us' */ +#define MT_MIB_SDR16_DNR(_band) MT_WF_MIB(_band, 0x048) +#define MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK GENMASK(23, 0) + +#define MT_MIB_SDR17_DNR(_band) MT_WF_MIB(_band, 0x04c) +#define MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK GENMASK(23, 0) + +#define MT_MIB_SDR18(_band) MT_WF_MIB(_band, 0x050) +#define MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK GENMASK(23, 0) + +/* units are us */ +#define MT_MIB_SDR19_DNR(_band) MT_WF_MIB(_band, 0x054) +#define MT_MIB_SDR19_CCK_MDRDY_TIME_MASK GENMASK(23, 0) + +#define MT_MIB_SDR20_DNR(_band) MT_WF_MIB(_band, 0x058) +#define MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK GENMASK(23, 0) + +#define MT_MIB_SDR21_DNR(_band) MT_WF_MIB(_band, 0x05c) +#define MT_MIB_SDR20_GREEN_MDRDY_TIME_MASK GENMASK(23, 0) + +/* rx ampdu count, 32-bit */ +#define MT_MIB_SDR22(_band) MT_WF_MIB(_band, 0x060) + +/* rx ampdu bytes count, 32-bit */ +#define MT_MIB_SDR23(_band) MT_WF_MIB(_band, 0x064) + +/* rx ampdu valid subframe count */ +#define MT_MIB_SDR24(_band) MT_WF_MIB(_band, 0x068) +#define MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK GENMASK(23, 0) + +/* rx ampdu valid subframe bytes count, 32bits */ +#define MT_MIB_SDR25(_band) MT_WF_MIB(_band, 0x06c) + +/* remaining windows protected stats */ +#define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x074) +#define MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK GENMASK(15, 0) + +#define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x078) +#define MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK GENMASK(15, 0) + +#define MT_MIB_SDR29(_band) MT_WF_MIB(_band, 0x07c) +#define MT_MIB_SDR29_RX_PFDROP_CNT_MASK GENMASK(7, 0) + +#define MT_MIB_SDR30(_band) MT_WF_MIB(_band, 0x080) +#define MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK GENMASK(15, 0) + +/* rx blockack count, 32 bits */ +#define MT_MIB_SDR31(_band) MT_WF_MIB(_band, 0x084) + +#define MT_MIB_SDR32(_band) MT_WF_MIB(_band, 0x088) +#define MT_MIB_SDR32_TX_PKT_EBF_CNT_MASK GENMASK(15, 0) + +#define MT_MIB_SDR33(_band) MT_WF_MIB(_band, 0x08c) +#define MT_MIB_SDR33_TX_PKT_IBF_CNT_MASK GENMASK(15, 0) + #define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090) #define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0) +/* 36, 37 both DNR */ + #define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0) #define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4) #define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc) @@ -248,7 +364,6 @@ #define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) #define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) -#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) /* WFDMA0 */ #define MT_WFDMA0_BASE 0xd4000 @@ -420,6 +535,20 @@ #define MT_SWDEF_ICAP_MODE 1 #define MT_SWDEF_SPECTRUM_MODE 2 +#define MT_LED_TOP_BASE 0x18013000 +#define MT_LED_PHYS(_n) (MT_LED_TOP_BASE + (_n)) + +#define MT_LED_CTRL(_n) MT_LED_PHYS(0x00 + ((_n) * 4)) +#define MT_LED_CTRL_KICK BIT(7) +#define MT_LED_CTRL_BLINK_MODE BIT(2) +#define MT_LED_CTRL_POLARITY BIT(1) + +#define MT_LED_TX_BLINK(_n) MT_LED_PHYS(0x10 + ((_n) * 4)) +#define MT_LED_TX_BLINK_ON_MASK GENMASK(7, 0) +#define MT_LED_TX_BLINK_OFF_MASK GENMASK(15, 8) + +#define MT_LED_EN(_n) MT_LED_PHYS(0x40 + ((_n) * 4)) + #define MT_TOP_BASE 0x18060000 #define MT_TOP(ofs) (MT_TOP_BASE + (ofs)) @@ -430,6 +559,10 @@ #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) +#define MT_LED_GPIO_MUX2 0x70005058 /* GPIO 18 */ +#define MT_LED_GPIO_MUX3 0x7000505C /* GPIO 26 */ +#define MT_LED_GPIO_SEL_MASK GENMASK(11, 8) + #define MT_HW_BOUND 0x70010020 #define MT_HW_CHIPID 0x70010200 #define MT_HW_REV 0x70010204 diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index b220b334906b..89aae323d29e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -166,6 +166,22 @@ mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs) } static int +mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu) +{ + struct mt7915_dev *dev = phy->dev; + u32 op_mode; + + if (!enable) + op_mode = TAM_ARB_OP_MODE_NORMAL; + else if (mu) + op_mode = TAM_ARB_OP_MODE_TEST; + else + op_mode = TAM_ARB_OP_MODE_FORCE_SU; + + return mt7915_mcu_set_muru_ctrl(dev, MURU_SET_ARB_OP_MODE, op_mode); +} + +static int mt7915_tm_set_wmm_qid(struct mt7915_dev *dev, u8 qid, u8 aifs, u8 cw_min, u16 cw_max, u16 txop) { @@ -397,6 +413,10 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en) mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en); mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en); + mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, en); + + if (!en) + mt7915_tm_set_tam_arb(phy, en, 0); } static void @@ -438,6 +458,9 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) } } + mt7915_tm_set_tam_arb(phy, en, + td->tx_rate_mode == MT76_TM_TX_MODE_HE_MU); + /* if all three params are set, duty_cycle will be ignored */ if (duty_cycle && tx_time && !ipg) { ipg = tx_time * 100 / duty_cycle - tx_time; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h index 397a6b5532bc..5573ac309363 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h @@ -96,4 +96,10 @@ enum { RF_OPER_WIFI_SPECTRUM, }; +enum { + TAM_ARB_OP_MODE_NORMAL = 1, + TAM_ARB_OP_MODE_TEST, + TAM_ARB_OP_MODE_FORCE_SU = 5, +}; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig index 001f2b9cec26..ce3a06227901 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig @@ -1,11 +1,25 @@ # SPDX-License-Identifier: ISC -config MT7921E - tristate "MediaTek MT7921E (PCIe) support" +config MT7921_COMMON + tristate select MT76_CONNAC_LIB select WANT_DEV_COREDUMP + +config MT7921E + tristate "MediaTek MT7921E (PCIe) support" + select MT7921_COMMON depends on MAC80211 depends on PCI help This adds support for MT7921E 802.11ax 2x2:2SS wireless devices. To compile this driver as a module, choose M here. + +config MT7921S + tristate "MediaTek MT7921S (SDIO) support" + select MT76_SDIO + select MT7921_COMMON + depends on MAC80211 + help + This adds support for MT7921S 802.11ax 2x2:2SS wireless devices. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 0ebb59966a08..1187acedfeda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -1,7 +1,12 @@ # SPDX-License-Identifier: ISC +obj-$(CONFIG_MT7921_COMMON) += mt7921-common.o obj-$(CONFIG_MT7921E) += mt7921e.o +obj-$(CONFIG_MT7921S) += mt7921s.o CFLAGS_trace.o := -I$(src) -mt7921e-y := pci.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o trace.o +mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o trace.o +mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o +mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o +mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 77468bdae460..7cdfdf83529f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -5,6 +5,32 @@ #include "eeprom.h" static int +mt7921_reg_set(void *data, u64 val) +{ + struct mt7921_dev *dev = data; + + mt7921_mutex_acquire(dev); + mt76_wr(dev, dev->mt76.debugfs_reg, val); + mt7921_mutex_release(dev); + + return 0; +} + +static int +mt7921_reg_get(void *data, u64 *val) +{ + struct mt7921_dev *dev = data; + + mt7921_mutex_acquire(dev); + *val = mt76_rr(dev, dev->mt76.debugfs_reg); + mt7921_mutex_release(dev); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7921_reg_get, mt7921_reg_set, + "0x%08llx\n"); +static int mt7921_fw_debug_set(void *data, u64 val) { struct mt7921_dev *dev = data; @@ -42,6 +68,8 @@ mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy, if (!phy) return; + mt7921_mac_update_mib_stats(phy); + /* Tx ampdu stat */ for (i = 0; i < ARRAY_SIZE(range); i++) range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i)); @@ -67,26 +95,27 @@ static int mt7921_tx_stats_show(struct seq_file *file, void *data) { struct mt7921_dev *dev = file->private; - int stat[8], i, n; + struct mt7921_phy *phy = &dev->phy; + struct mib_stats *mib = &phy->mib; + int i; - mt7921_ampdu_stat_read_phy(&dev->phy, file); + mt7921_mutex_acquire(dev); - /* Tx amsdu info */ - seq_puts(file, "Tx MSDU stat:\n"); - for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { - stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); - n += stat[i]; - } + mt7921_ampdu_stat_read_phy(phy, file); - for (i = 0; i < ARRAY_SIZE(stat); i++) { - seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ", - i + 1, stat[i]); - if (n != 0) - seq_printf(file, "(%d%%)\n", stat[i] * 100 / n); + seq_puts(file, "Tx MSDU stat:\n"); + for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { + seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ", + i + 1, mib->tx_amsdu[i]); + if (mib->tx_amsdu_cnt) + seq_printf(file, "(%3d%%)\n", + mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt); else seq_puts(file, "\n"); } + mt7921_mutex_release(dev); + return 0; } @@ -98,6 +127,8 @@ mt7921_queues_acq(struct seq_file *s, void *data) struct mt7921_dev *dev = dev_get_drvdata(s->private); int i; + mt7921_mutex_acquire(dev); + for (i = 0; i < 16; i++) { int j, acs = i / 4, index = i % 4; u32 ctrl, val, qlen = 0; @@ -117,6 +148,8 @@ mt7921_queues_acq(struct seq_file *s, void *data) seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); } + mt7921_mutex_release(dev); + return 0; } @@ -229,30 +262,38 @@ mt7921_txpwr(struct seq_file *s, void *data) return 0; } +static void +mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7921_dev *dev = priv; + + mt7921_mcu_set_beacon_filter(dev, vif, dev->pm.enable); +} + static int mt7921_pm_set(void *data, u64 val) { struct mt7921_dev *dev = data; struct mt76_connac_pm *pm = &dev->pm; - struct mt76_phy *mphy = dev->phy.mt76; - - if (val == pm->enable) - return 0; mt7921_mutex_acquire(dev); + if (val == pm->enable) + goto out; + if (!pm->enable) { pm->stats.last_wake_event = jiffies; pm->stats.last_doze_event = jiffies; } pm->enable = val; - ieee80211_iterate_active_interfaces(mphy->hw, + ieee80211_iterate_active_interfaces(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, - mt7921_pm_interface_iter, mphy->priv); + mt7921_pm_interface_iter, dev); mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); +out: mt7921_mutex_release(dev); return 0; @@ -369,11 +410,25 @@ static int mt7921_chip_reset(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7921_chip_reset, "%lld\n"); +static int +mt7921s_sched_quota_read(struct seq_file *s, void *data) +{ + struct mt7921_dev *dev = dev_get_drvdata(s->private); + struct mt76_sdio *sdio = &dev->mt76.sdio; + + seq_printf(s, "pse_data_quota\t%d\n", sdio->sched.pse_data_quota); + seq_printf(s, "ple_data_quota\t%d\n", sdio->sched.ple_data_quota); + seq_printf(s, "pse_mcu_quota\t%d\n", sdio->sched.pse_mcu_quota); + seq_printf(s, "sched_deficit\t%d\n", sdio->sched.deficit); + + return 0; +} + int mt7921_init_debugfs(struct mt7921_dev *dev) { struct dentry *dir; - dir = mt76_register_debugfs(&dev->mt76); + dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval); if (!dir) return -ENOMEM; @@ -392,6 +447,8 @@ int mt7921_init_debugfs(struct mt7921_dev *dev) debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir, mt7921_pm_stats); debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds); - + if (mt76_is_sdio(&dev->mt76)) + debugfs_create_devm_seqfile(dev->mt76.dev, "sched-quota", dir, + mt7921s_sched_quota_read); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 7d7d43a5422f..cdff1fd52d93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -19,46 +19,6 @@ int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc) return 0; } -void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); - __le32 *rxd = (__le32 *)skb->data; - enum rx_pkt_type type; - u16 flag; - - type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); - flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0])); - - if (type == PKT_TYPE_RX_EVENT && flag == 0x1) - type = PKT_TYPE_NORMAL_MCU; - - switch (type) { - case PKT_TYPE_TXRX_NOTIFY: - mt7921_mac_tx_free(dev, skb); - break; - case PKT_TYPE_RX_EVENT: - mt7921_mcu_rx_event(dev, skb); - break; - case PKT_TYPE_NORMAL_MCU: - case PKT_TYPE_NORMAL: - if (!mt7921_mac_fill_rx(dev, skb)) { - mt76_rx(&dev->mt76, q, skb); - return; - } - fallthrough; - default: - dev_kfree_skb(skb); - break; - } -} - -void mt7921_tx_cleanup(struct mt7921_dev *dev) -{ - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false); -} - static int mt7921_poll_tx(struct napi_struct *napi, int budget) { struct mt7921_dev *dev; @@ -71,7 +31,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget) return 0; } - mt7921_tx_cleanup(dev); + mt7921_mcu_tx_cleanup(dev); if (napi_complete(napi)) mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL); mt76_connac_pm_unref(&dev->mphy, &dev->pm); @@ -125,36 +85,37 @@ static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr) u32 mapped; u32 size; } fixed_map[] = { - { 0x00400000, 0x80000, 0x10000}, /* WF_MCU_SYSRAM */ - { 0x00410000, 0x90000, 0x10000}, /* WF_MCU_SYSRAM (configure register) */ - { 0x40000000, 0x70000, 0x10000}, /* WF_UMAC_SYSRAM */ + { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ + { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ + { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ + { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ + { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ + { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ + { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ + { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ + { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ + { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) */ + { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ { 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */ { 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */ { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */ { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ - { 0x7c060000, 0xe0000, 0x10000}, /* CONN_INFRA, conn_host_csr_top */ + { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */ { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */ { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */ - { 0x820cc000, 0x0e000, 0x2000 }, /* WF_UMAC_TOP (PP) */ + { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */ + { 0x820cd000, 0x0f000, 0x1000 }, /* WF_MDP_TOP */ { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */ { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */ - { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ - { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ - { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ - { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ - { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ - { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ - { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ - { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ @@ -306,7 +267,7 @@ static int mt7921_dma_reset(struct mt7921_dev *dev, bool force) mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_reset(dev, &dev->mt76.q_rx[i]); - mt76_tx_status_check(&dev->mt76, NULL, true); + mt76_tx_status_check(&dev->mt76, true); return mt7921_dma_enable(dev); } @@ -383,6 +344,9 @@ int mt7921_dma_init(struct mt7921_dev *dev) struct mt76_bus_ops *bus_ops; int ret; + dev->phy.dev = dev; + dev->phy.mt76 = &dev->mt76.phy; + dev->mt76.phy.priv = &dev->phy; dev->bus_ops = dev->mt76.bus; bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), GFP_KERNEL); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c deleted file mode 100644 index 691d14a1a7bf..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: ISC -/* Copyright (C) 2020 MediaTek Inc. */ - -#include "mt7921.h" -#include "eeprom.h" - -static u32 mt7921_eeprom_read(struct mt7921_dev *dev, u32 offset) -{ - u8 *data = dev->mt76.eeprom.data; - - if (data[offset] == 0xff) - mt7921_mcu_get_eeprom(dev, offset); - - return data[offset]; -} - -static int mt7921_eeprom_load(struct mt7921_dev *dev) -{ - int ret; - - ret = mt76_eeprom_init(&dev->mt76, MT7921_EEPROM_SIZE); - if (ret < 0) - return ret; - - memset(dev->mt76.eeprom.data, -1, MT7921_EEPROM_SIZE); - - return 0; -} - -static int mt7921_check_eeprom(struct mt7921_dev *dev) -{ - u8 *eeprom = dev->mt76.eeprom.data; - u16 val; - - mt7921_eeprom_read(dev, MT_EE_CHIP_ID); - val = get_unaligned_le16(eeprom); - - switch (val) { - case 0x7961: - return 0; - default: - return -EINVAL; - } -} - -void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy) -{ - struct mt7921_dev *dev = phy->dev; - u32 val; - - val = mt7921_eeprom_read(dev, MT_EE_WIFI_CONF); - val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val); - - switch (val) { - case MT_EE_5GHZ: - phy->mt76->cap.has_5ghz = true; - break; - case MT_EE_2GHZ: - phy->mt76->cap.has_2ghz = true; - break; - default: - phy->mt76->cap.has_2ghz = true; - phy->mt76->cap.has_5ghz = true; - break; - } -} - -static void mt7921_eeprom_parse_hw_cap(struct mt7921_dev *dev) -{ - u8 tx_mask; - - mt7921_eeprom_parse_band_config(&dev->phy); - - /* TODO: read NSS with MCU_CMD_NIC_CAPV2 */ - tx_mask = 2; - dev->chainmask = BIT(tx_mask) - 1; - dev->mphy.antenna_mask = dev->chainmask; - dev->mphy.chainmask = dev->mphy.antenna_mask; -} - -int mt7921_eeprom_init(struct mt7921_dev *dev) -{ - int ret; - - ret = mt7921_eeprom_load(dev); - if (ret < 0) - return ret; - - ret = mt7921_check_eeprom(dev); - if (ret) - return ret; - - mt7921_eeprom_parse_hw_cap(dev); - memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, - ETH_ALEN); - - mt76_eeprom_override(&dev->mphy); - - return 0; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index a9ce10b98827..87265045e2dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -41,7 +41,7 @@ mt7921_regd_notifier(struct wiphy *wiphy, mt7921_mutex_release(dev); } -static void +static int mt7921_init_wiphy(struct ieee80211_hw *hw) { struct mt7921_phy *phy = mt7921_hw_phy(hw); @@ -75,6 +75,14 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) wiphy->max_sched_scan_reqs = 1; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; wiphy->reg_notifier = mt7921_regd_notifier; + wiphy->sar_capa = &mt76_sar_capa; + + phy->mt76->frp = devm_kcalloc(dev->mt76.dev, + wiphy->sar_capa->num_freq_ranges, + sizeof(struct mt76_freq_range_power), + GFP_KERNEL); + if (!phy->mt76->frp) + return -ENOMEM; wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; @@ -92,6 +100,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, CONNECTION_MONITOR); hw->max_tx_fragments = 4; + + return 0; } static void @@ -106,6 +116,10 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band) mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); + /* enable MIB tx-rx time reporting */ + mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN); + mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN); + mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536); /* disable rx rate report by default due to hw issues */ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); @@ -127,35 +141,53 @@ int mt7921_mac_init(struct mt7921_dev *dev) for (i = 0; i < 2; i++) mt7921_mac_init_band(dev, i); + dev->mt76.rxfilter = mt76_rr(dev, MT_WF_RFCR(0)); + return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); } +EXPORT_SYMBOL_GPL(mt7921_mac_init); -static int mt7921_init_hardware(struct mt7921_dev *dev) +static int __mt7921_init_hardware(struct mt7921_dev *dev) { - int ret, idx; - - ret = mt7921_dma_init(dev); - if (ret) - return ret; - - set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + int ret; /* force firmware operation mode into normal state, * which should be set before firmware download stage. */ mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE); - ret = mt7921_mcu_init(dev); if (ret) - return ret; + goto out; - ret = mt7921_eeprom_init(dev); - if (ret < 0) - return ret; + mt76_eeprom_override(&dev->mphy); ret = mt7921_mcu_set_eeprom(dev); if (ret) + goto out; + + ret = mt7921_mac_init(dev); +out: + return ret; +} + +static int mt7921_init_hardware(struct mt7921_dev *dev) +{ + int ret, idx, i; + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + for (i = 0; i < MT7921_MCU_INIT_RETRY_COUNT; i++) { + ret = __mt7921_init_hardware(dev); + if (!ret) + break; + + mt7921_init_reset(dev); + } + + if (i == MT7921_MCU_INIT_RETRY_COUNT) { + dev_err(dev->mt76.dev, "hardware init failed\n"); return ret; + } /* Beacon and mgmt frames should occupy wcid 0 */ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1); @@ -167,7 +199,7 @@ static int mt7921_init_hardware(struct mt7921_dev *dev) dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); - return mt7921_mac_init(dev); + return 0; } int mt7921_register_device(struct mt7921_dev *dev) @@ -185,8 +217,9 @@ int mt7921_register_device(struct mt7921_dev *dev) spin_lock_init(&dev->pm.wake.lock); mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); + if (mt76_is_sdio(&dev->mt76)) + init_waitqueue_head(&dev->mt76.sdio.wait); spin_lock_init(&dev->pm.txq_lock); - INIT_LIST_HEAD(&dev->phy.stats_list); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work); INIT_DELAYED_WORK(&dev->coredump.work, mt7921_coredump_work); @@ -200,14 +233,24 @@ int mt7921_register_device(struct mt7921_dev *dev) dev->pm.idle_timeout = MT7921_PM_TIMEOUT; dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; - dev->pm.enable = true; - dev->pm.ds_enable = true; + + /* TODO: mt7921s run sleep mode on default */ + if (mt76_is_mmio(&dev->mt76)) { + dev->pm.enable = true; + dev->pm.ds_enable = true; + } + + if (mt76_is_sdio(&dev->mt76)) + hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE; ret = mt7921_init_hardware(dev); if (ret) return ret; - mt7921_init_wiphy(hw); + ret = mt7921_init_wiphy(hw); + if (ret) + return ret; + dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; @@ -244,14 +287,4 @@ int mt7921_register_device(struct mt7921_dev *dev) return 0; } - -void mt7921_unregister_device(struct mt7921_dev *dev) -{ - mt76_unregister_device(&dev->mt76); - mt7921_tx_token_put(dev); - mt7921_dma_cleanup(dev); - mt7921_mcu_exit(dev); - - tasklet_disable(&dev->irq_tasklet); - mt76_free_device(&dev->mt76); -} +EXPORT_SYMBOL_GPL(mt7921_register_device); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 7fe2e3a50428..db3302b1576a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -39,6 +39,7 @@ static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev, void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { } +EXPORT_SYMBOL_GPL(mt7921_sta_ps); bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask) { @@ -49,7 +50,7 @@ bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask) 0, 5000); } -static void mt7921_mac_sta_poll(struct mt7921_dev *dev) +void mt7921_mac_sta_poll(struct mt7921_dev *dev) { static const u8 ac_to_tid[] = { [IEEE80211_AC_BE] = 0, @@ -61,18 +62,18 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev) struct mt7921_sta *msta; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); + struct rate_info *rate; int i; spin_lock_bh(&dev->sta_poll_lock); list_splice_init(&dev->sta_poll_list, &sta_poll_list); spin_unlock_bh(&dev->sta_poll_lock); - rcu_read_lock(); - while (true) { bool clear = false; - u32 addr; + u32 addr, val; u16 idx; + u8 bw; spin_lock_bh(&dev->sta_poll_lock); if (list_empty(&sta_poll_list)) { @@ -85,7 +86,7 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev) spin_unlock_bh(&dev->sta_poll_lock); idx = msta->wcid.idx; - addr = MT_WTBL_LMAC_OFFS(idx, 0) + 20 * 4; + addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET); for (i = 0; i < IEEE80211_NUM_ACS; i++) { u32 tx_last = msta->airtime_ac[i]; @@ -126,10 +127,46 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev) ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); } - } - rcu_read_unlock(); + /* We don't support reading GI info from txs packets. + * For accurate tx status reporting and AQL improvement, + * we need to make sure that flags match so polling GI + * from per-sta counters directly. + */ + rate = &msta->wcid.rate; + addr = mt7921_mac_wtbl_lmac_addr(idx, + MT_WTBL_TXRX_CAP_RATE_OFFSET); + val = mt76_rr(dev, addr); + + switch (rate->bw) { + case RATE_INFO_BW_160: + bw = IEEE80211_STA_RX_BW_160; + break; + case RATE_INFO_BW_80: + bw = IEEE80211_STA_RX_BW_80; + break; + case RATE_INFO_BW_40: + bw = IEEE80211_STA_RX_BW_40; + break; + default: + bw = IEEE80211_STA_RX_BW_20; + break; + } + + if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { + u8 offs = MT_WTBL_TXRX_RATE_G2_HE + 2 * bw; + + rate->he_gi = (val & (0x3 << offs)) >> offs; + } else if (rate->flags & + (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) { + if (val & BIT(MT_WTBL_TXRX_RATE_G2 + bw)) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + else + rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; + } + } } +EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll); static void mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, @@ -181,11 +218,55 @@ mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, } static void +mt7921_mac_decode_he_mu_radiotap(struct sk_buff *skb, + struct mt76_rx_status *status, + __le32 *rxv) +{ + static const struct ieee80211_radiotap_he_mu mu_known = { + .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) | + HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) | + HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) | + HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN) | + HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN), + .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN) | + HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN), + }; + struct ieee80211_radiotap_he_mu *he_mu; + + he_mu = skb_push(skb, sizeof(mu_known)); + memcpy(he_mu, &mu_known, sizeof(mu_known)); + +#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f) + + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx); + if (status->he_dcm) + he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm); + + he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) | + MU_PREP(FLAGS2_SIG_B_SYMS_USERS, + le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER)); + + he_mu->ru_ch1[0] = FIELD_GET(MT_CRXV_HE_RU0, le32_to_cpu(rxv[3])); + + if (status->bw >= RATE_INFO_BW_40) { + he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN); + he_mu->ru_ch2[0] = + FIELD_GET(MT_CRXV_HE_RU1, le32_to_cpu(rxv[3])); + } + + if (status->bw >= RATE_INFO_BW_80) { + he_mu->ru_ch1[1] = + FIELD_GET(MT_CRXV_HE_RU2, le32_to_cpu(rxv[3])); + he_mu->ru_ch2[1] = + FIELD_GET(MT_CRXV_HE_RU3, le32_to_cpu(rxv[3])); + } +} + +static void mt7921_mac_decode_he_radiotap(struct sk_buff *skb, struct mt76_rx_status *status, __le32 *rxv, u32 phy) { - /* TODO: struct ieee80211_radiotap_he_mu */ static const struct ieee80211_radiotap_he known = { .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | HE_BITS(DATA1_DATA_DCM_KNOWN) | @@ -193,6 +274,7 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb, HE_BITS(DATA1_CODING_KNOWN) | HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | HE_BITS(DATA1_DOPPLER_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN) | HE_BITS(DATA1_BSS_COLOR_KNOWN), .data2 = HE_BITS(DATA2_GI_KNOWN) | HE_BITS(DATA2_TXBF_KNOWN) | @@ -207,9 +289,12 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb, he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); + he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | le16_encode_bits(ltf_size, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) + he->data5 |= HE_BITS(DATA5_TXBF); he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); @@ -217,8 +302,7 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb, case MT_PHY_TYPE_HE_SU: he->data1 |= HE_BITS(DATA1_FORMAT_SU) | HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN); + HE_BITS(DATA1_BEAM_CHANGE_KNOWN); he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); @@ -232,17 +316,15 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb, break; case MT_PHY_TYPE_HE_MU: he->data1 |= HE_BITS(DATA1_FORMAT_MU) | - HE_BITS(DATA1_UL_DL_KNOWN) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN); + HE_BITS(DATA1_UL_DL_KNOWN); he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); - he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); + he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]); mt7921_mac_decode_he_radiotap_ru(status, he, rxv); break; case MT_PHY_TYPE_HE_TB: he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | - HE_BITS(DATA1_SPTL_REUSE_KNOWN) | HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | HE_BITS(DATA1_SPTL_REUSE4_KNOWN); @@ -271,7 +353,14 @@ mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy, return; } - status->band = chfreq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + if (chfreq > 180) { + status->band = NL80211_BAND_6GHZ; + chfreq = (chfreq - 181) * 4 + 1; + } else if (chfreq > 14) { + status->band = NL80211_BAND_5GHZ; + } else { + status->band = NL80211_BAND_2GHZ; + } status->freq = ieee80211_channel_to_frequency(chfreq, status->band); } @@ -306,7 +395,8 @@ mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb) mt7921_mac_rssi_iter, skb); } -int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) +static int +mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) { u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -356,10 +446,17 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) mt7921_get_status_freq_info(dev, mphy, status, chfreq); - if (status->band == NL80211_BAND_5GHZ) + switch (status->band) { + case NL80211_BAND_5GHZ: sband = &mphy->sband_5g.sband; - else + break; + case NL80211_BAND_6GHZ: + sband = &mphy->sband_6g.sband; + break; + default: sband = &mphy->sband_2g.sband; + break; + } if (!sband->channels) return -EINVAL; @@ -606,9 +703,13 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) mt7921_mac_assoc_rssi(dev, skb); - if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) + if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) { mt7921_mac_decode_he_radiotap(skb, status, rxv, mode); + if (status->flag & RX_FLAG_RADIOTAP_HE_MU) + mt7921_mac_decode_he_mu_radiotap(skb, status, rxv); + } + if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; @@ -702,7 +803,8 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); } - if (!ieee80211_is_data(fc) || multicast) + if (!ieee80211_is_data(fc) || multicast || + info->flags & IEEE80211_TX_CTL_USE_MINRATE) val |= MT_TXD2_FIX_RATE; txwi[2] |= cpu_to_le32(val); @@ -732,31 +834,17 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, txwi[7] |= cpu_to_le32(val); } -static void mt7921_update_txs(struct mt76_wcid *wcid, __le32 *txwi) -{ - struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid); - u32 pid, frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]); - - if (!(frame_type & (IEEE80211_FTYPE_DATA >> 2))) - return; - - if (time_is_after_eq_jiffies(msta->next_txs_ts)) - return; - - msta->next_txs_ts = jiffies + msecs_to_jiffies(250); - pid = mt76_get_next_pkt_id(wcid); - txwi[5] |= cpu_to_le32(MT_TXD5_TX_STATUS_MCU | - FIELD_PREP(MT_TXD5_PID, pid)); -} - void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, bool beacon) + struct ieee80211_key_conf *key, int pid, + bool beacon) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->mphy; u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; + bool is_mmio = mt76_is_mmio(&dev->mt76); + u32 sz_txd = is_mmio ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; u16 tx_count = 15; u32 val; @@ -772,15 +860,15 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_BCN0; } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { - p_fmt = MT_TX_TYPE_CT; + p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = MT_LMAC_ALTX0; } else { - p_fmt = MT_TX_TYPE_CT; + p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = wmm_idx * MT7921_MAX_WMM_SETS + mt7921_lmac_mapping(dev, skb_get_queue_mapping(skb)); } - val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txwi[0] = cpu_to_le32(val); @@ -800,7 +888,12 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[3] = cpu_to_le32(val); txwi[4] = 0; - txwi[5] = 0; + + val = FIELD_PREP(MT_TXD5_PID, pid); + if (pid >= MT_PACKET_ID_FIRST) + val |= MT_TXD5_TX_STATUS_HOST; + txwi[5] = cpu_to_le32(val); + txwi[6] = 0; txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; @@ -810,105 +903,32 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, mt7921_mac_write_txwi_80211(dev, txwi, skb, key); if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { - u16 rate; + int rateidx = ffs(vif->bss_conf.basic_rates) - 1; + u16 rate, mode; /* hardware won't add HTC for mgmt/ctrl frame */ txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); - if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) - rate = MT7921_5G_RATE_DEFAULT; - else - rate = MT7921_2G_RATE_DEFAULT; + rate = mt76_calculate_default_rate(mphy, rateidx); + mode = rate >> 8; + rate &= GENMASK(7, 0); + rate |= FIELD_PREP(MT_TX_RATE_MODE, mode); val = MT_TXD6_FIXED_BW | FIELD_PREP(MT_TXD6_TX_RATE, rate); txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } - - mt7921_update_txs(wcid, txwi); -} - -static void -mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info, - void *txp_ptr, u32 id) -{ - struct mt7921_hw_txp *txp = txp_ptr; - struct mt7921_txp_ptr *ptr = &txp->ptr[0]; - int i, nbuf = tx_info->nbuf - 1; - - tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); - tx_info->nbuf = 1; - - txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); - - for (i = 0; i < nbuf; i++) { - u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; - u32 addr = tx_info->buf[i + 1].addr; - - if (i == nbuf - 1) - len |= MT_TXD_LEN_LAST; - - if (i & 1) { - ptr->buf1 = cpu_to_le32(addr); - ptr->len1 = cpu_to_le16(len); - ptr++; - } else { - ptr->buf0 = cpu_to_le32(addr); - ptr->len0 = cpu_to_le16(len); - } - } } +EXPORT_SYMBOL_GPL(mt7921_mac_write_txwi); -int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, - enum mt76_txq_id qid, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, - struct mt76_tx_info *tx_info) -{ - struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); - struct ieee80211_key_conf *key = info->control.hw_key; - struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb); - struct mt76_txwi_cache *t; - struct mt7921_txp_common *txp; - int id; - u8 *txwi = (u8 *)txwi_ptr; - - if (unlikely(tx_info->skb->len <= ETH_HLEN)) - return -EINVAL; - - if (!wcid) - wcid = &dev->mt76.global_wcid; - - cb->wcid = wcid->idx; - - t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); - t->skb = tx_info->skb; - - id = mt76_token_consume(mdev, &t); - if (id < 0) - return id; - - mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, - false); - - txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); - memset(txp, 0, sizeof(struct mt7921_txp_common)); - mt7921_write_hw_txp(dev, tx_info, txp, id); - - tx_info->skb = DMA_DUMMY_DATA; - - return 0; -} - -static void -mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) +void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) { struct mt7921_sta *msta; u16 fc, tid; u32 val; - if (!sta || !sta->ht_cap.ht_supported) + if (!sta || !(sta->ht_cap.ht_supported || sta->he_cap.has_he)) return; tid = FIELD_GET(MT_TXD1_TID, le32_to_cpu(txwi[1])); @@ -925,203 +945,209 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) if (!test_and_set_bit(tid, &msta->ampdu_state)) ieee80211_start_tx_ba_session(sta, tid, 0); } +EXPORT_SYMBOL_GPL(mt7921_tx_check_aggr); -static void -mt7921_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, - struct ieee80211_sta *sta, u8 stat, - struct list_head *free_list) +static bool +mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, + __le32 *txs_data) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_status status = { - .sta = sta, - .info = info, - .skb = skb, - .free_list = free_list, - }; - struct ieee80211_hw *hw; + struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid); + struct mt76_sta_stats *stats = &msta->stats; + struct ieee80211_supported_band *sband; + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_tx_info *info; + struct rate_info rate = {}; + struct sk_buff_head list; + u32 txrate, txs, mode; + struct sk_buff *skb; + bool cck = false; + + mt76_tx_status_lock(mdev, &list); + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (!skb) + goto out; - if (sta) { - struct mt7921_sta *msta; + info = IEEE80211_SKB_CB(skb); + txs = le32_to_cpu(txs_data[0]); + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) + info->flags |= IEEE80211_TX_STAT_ACK; - msta = (struct mt7921_sta *)sta->drv_priv; - status.rate = &msta->stats.tx_rate; - } + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & + IEEE80211_TX_STAT_ACK); - hw = mt76_tx_status_get_hw(mdev, skb); + info->status.rates[0].idx = -1; - if (info->flags & IEEE80211_TX_CTL_AMPDU) - info->flags |= IEEE80211_TX_STAT_AMPDU; + if (!wcid->sta) + goto out; - if (stat) - ieee80211_tx_info_clear_status(info); + txrate = FIELD_GET(MT_TXS0_TX_RATE, txs); - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; + rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); + rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; - info->status.tx_time = 0; - ieee80211_tx_status_ext(hw, &status); -} + if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss)) + stats->tx_nss[rate.nss - 1]++; + if (rate.mcs < ARRAY_SIZE(stats->tx_mcs)) + stats->tx_mcs[rate.mcs]++; -void mt7921_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *t) -{ - struct mt7921_txp_common *txp; - int i; + mode = FIELD_GET(MT_TX_RATE_MODE, txrate); + switch (mode) { + case MT_PHY_TYPE_CCK: + cck = true; + fallthrough; + case MT_PHY_TYPE_OFDM: + if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ) + sband = &dev->mphy.sband_5g.sband; + else + sband = &dev->mphy.sband_2g.sband; - txp = mt7921_txwi_to_txp(dev, t); + rate.mcs = mt76_get_rate(dev->mphy.dev, sband, rate.mcs, cck); + rate.legacy = sband->bitrates[rate.mcs].bitrate; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + rate.mcs += (rate.nss - 1) * 8; + if (rate.mcs > 31) + goto out; + + rate.flags = RATE_INFO_FLAGS_MCS; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_VHT: + if (rate.mcs > 9) + goto out; - for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) { - struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i]; - bool last; - u16 len; + rate.flags = RATE_INFO_FLAGS_VHT_MCS; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (rate.mcs > 11) + goto out; - len = le16_to_cpu(ptr->len0); - last = len & MT_TXD_LEN_LAST; - len &= MT_TXD_LEN_MASK; - dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, - DMA_TO_DEVICE); - if (last) - break; + rate.he_gi = wcid->rate.he_gi; + rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); + rate.flags = RATE_INFO_FLAGS_HE_MCS; + break; + default: + goto out; + } + stats->tx_mode[mode]++; - len = le16_to_cpu(ptr->len1); - last = len & MT_TXD_LEN_LAST; - len &= MT_TXD_LEN_MASK; - dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, - DMA_TO_DEVICE); - if (last) - break; + switch (FIELD_GET(MT_TXS0_BW, txs)) { + case IEEE80211_STA_RX_BW_160: + rate.bw = RATE_INFO_BW_160; + stats->tx_bw[3]++; + break; + case IEEE80211_STA_RX_BW_80: + rate.bw = RATE_INFO_BW_80; + stats->tx_bw[2]++; + break; + case IEEE80211_STA_RX_BW_40: + rate.bw = RATE_INFO_BW_40; + stats->tx_bw[1]++; + break; + default: + rate.bw = RATE_INFO_BW_20; + stats->tx_bw[0]++; + break; } -} + wcid->rate = rate; -void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) -{ - struct mt7921_tx_free *free = (struct mt7921_tx_free *)skb->data; - struct mt76_dev *mdev = &dev->mt76; - struct mt76_txwi_cache *txwi; - struct ieee80211_sta *sta = NULL; - LIST_HEAD(free_list); - struct sk_buff *tmp; - bool wake = false; - u8 i, count; - - /* clean DMA queues and unmap buffers first */ - mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); - mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false); - - /* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE, - * to the time ack is received or dropped by hw (air + hw queue time). - * Should avoid accessing WTBL to get Tx airtime, and use it instead. - */ - count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl)); - for (i = 0; i < count; i++) { - u32 msdu, info = le32_to_cpu(free->info[i]); - u8 stat; - - /* 1'b1: new wcid pair. - * 1'b0: msdu_id with the same 'wcid pair' as above. - */ - if (info & MT_TX_FREE_PAIR) { - struct mt7921_sta *msta; - struct mt7921_phy *phy; - struct mt76_wcid *wcid; - u16 idx; - - count++; - idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info); - wcid = rcu_dereference(dev->mt76.wcid[idx]); - sta = wcid_to_sta(wcid); - if (!sta) - continue; +out: + if (skb) + mt76_tx_status_skb_done(mdev, skb, &list); + mt76_tx_status_unlock(mdev, &list); - msta = container_of(wcid, struct mt7921_sta, wcid); - phy = msta->vif->phy; - spin_lock_bh(&dev->sta_poll_lock); - if (list_empty(&msta->stats_list)) - list_add_tail(&msta->stats_list, &phy->stats_list); - if (list_empty(&msta->poll_list)) - list_add_tail(&msta->poll_list, &dev->sta_poll_list); - spin_unlock_bh(&dev->sta_poll_lock); - continue; - } + return !!skb; +} - msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); - stat = FIELD_GET(MT_TX_FREE_STATUS, info); +static void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data) +{ + struct mt7921_sta *msta = NULL; + struct mt76_wcid *wcid; + __le32 *txs_data = data; + u16 wcidx; + u32 txs; + u8 pid; - txwi = mt76_token_release(mdev, msdu, &wake); - if (!txwi) - continue; + txs = le32_to_cpu(txs_data[0]); + if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) + return; - mt7921_txp_skb_unmap(mdev, txwi); - if (txwi->skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb); - void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi); + txs = le32_to_cpu(txs_data[2]); + wcidx = FIELD_GET(MT_TXS2_WCID, txs); - if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7921_tx_check_aggr(sta, txwi_ptr); + txs = le32_to_cpu(txs_data[3]); + pid = FIELD_GET(MT_TXS3_PID, txs); - if (sta && !info->tx_time_est) { - struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; - int pending; + if (pid < MT_PACKET_ID_FIRST) + return; - pending = atomic_dec_return(&wcid->non_aql_packets); - if (pending < 0) - atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); - } + if (wcidx >= MT7921_WTBL_SIZE) + return; - mt7921_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list); - txwi->skb = NULL; - } + rcu_read_lock(); - mt76_put_txwi(mdev, txwi); - } + wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + if (!wcid) + goto out; - if (wake) - mt76_set_tx_blocked(&dev->mt76, false); + mt7921_mac_add_txs_skb(dev, wcid, pid, txs_data); - napi_consume_skb(skb, 1); + if (!wcid->sta) + goto out; - list_for_each_entry_safe(skb, tmp, &free_list, list) { - skb_list_del_init(skb); - napi_consume_skb(skb, 1); - } + msta = container_of(wcid, struct mt7921_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); - mt7921_mac_sta_poll(dev); - mt76_worker_schedule(&dev->mt76.tx_worker); +out: + rcu_read_unlock(); } -void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) +void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) { - struct mt7921_dev *dev; - - if (!e->txwi) { - dev_kfree_skb_any(e->skb); - return; - } - - dev = container_of(mdev, struct mt7921_dev, mt76); - - /* error path */ - if (e->skb == DMA_DUMMY_DATA) { - struct mt76_txwi_cache *t; - struct mt7921_txp_common *txp; - u16 token; - - txp = mt7921_txwi_to_txp(mdev, e->txwi); - token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID; - t = mt76_token_put(mdev, token); - e->skb = t ? t->skb : NULL; - } + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + __le32 *end = (__le32 *)&skb->data[skb->len]; + enum rx_pkt_type type; + u16 flag; - if (e->skb) { - struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb); - struct mt76_wcid *wcid; + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0])); - wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]); + if (type == PKT_TYPE_RX_EVENT && flag == 0x1) + type = PKT_TYPE_NORMAL_MCU; - mt7921_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0, - NULL); + switch (type) { + case PKT_TYPE_RX_EVENT: + mt7921_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_TXS: + for (rxd += 2; rxd + 8 <= end; rxd += 8) + mt7921_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; + case PKT_TYPE_NORMAL_MCU: + case PKT_TYPE_NORMAL: + if (!mt7921_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + fallthrough; + default: + dev_kfree_skb(skb); + break; } } +EXPORT_SYMBOL_GPL(mt7921_queue_rx_skb); void mt7921_mac_reset_counters(struct mt7921_phy *phy) { @@ -1154,17 +1180,12 @@ void mt7921_mac_set_timing(struct mt7921_phy *phy) FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); - int sifs, offset; - bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; + bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ; + int sifs = is_2ghz ? 10 : 16, offset; if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; - if (is_5ghz) - sifs = 16; - else - sifs = 10; - mt76_set(dev, MT_ARB_SCR(0), MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); udelay(1); @@ -1181,7 +1202,7 @@ void mt7921_mac_set_timing(struct mt7921_phy *phy) FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, phy->slottime)); - if (phy->slottime < 20 || is_5ghz) + if (phy->slottime < 20 || !is_2ghz) val = MT7921_CFEND_RATE_DEFAULT; else val = MT7921_CFEND_RATE_11B; @@ -1242,27 +1263,7 @@ void mt7921_update_channel(struct mt76_phy *mphy) mt76_connac_power_save_sched(mphy, &dev->pm); } - -void mt7921_tx_token_put(struct mt7921_dev *dev) -{ - struct mt76_txwi_cache *txwi; - int id; - - spin_lock_bh(&dev->mt76.token_lock); - idr_for_each_entry(&dev->mt76.token, txwi, id) { - mt7921_txp_skb_unmap(&dev->mt76, txwi); - if (txwi->skb) { - struct ieee80211_hw *hw; - - hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); - ieee80211_free_txskb(hw, txwi->skb); - } - mt76_put_txwi(&dev->mt76, txwi); - dev->mt76.token_count--; - } - spin_unlock_bh(&dev->mt76.token_lock); - idr_destroy(&dev->mt76.token); -} +EXPORT_SYMBOL_GPL(mt7921_update_channel); static void mt7921_vif_connect_iter(void *priv, u8 *mac, @@ -1278,69 +1279,6 @@ mt7921_vif_connect_iter(void *priv, u8 *mac, mt7921_mcu_set_tx(dev, vif); } -static int -mt7921_mac_reset(struct mt7921_dev *dev) -{ - int i, err; - - mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); - - mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); - - set_bit(MT76_RESET, &dev->mphy.state); - set_bit(MT76_MCU_RESET, &dev->mphy.state); - wake_up(&dev->mt76.mcu.wait); - skb_queue_purge(&dev->mt76.mcu.res_q); - - mt76_txq_schedule_all(&dev->mphy); - - mt76_worker_disable(&dev->mt76.tx_worker); - napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]); - napi_disable(&dev->mt76.napi[MT_RXQ_MCU]); - napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]); - napi_disable(&dev->mt76.tx_napi); - - mt7921_tx_token_put(dev); - idr_init(&dev->mt76.token); - - mt7921_wpdma_reset(dev, true); - - mt76_for_each_q_rx(&dev->mt76, i) { - napi_enable(&dev->mt76.napi[i]); - napi_schedule(&dev->mt76.napi[i]); - } - - clear_bit(MT76_MCU_RESET, &dev->mphy.state); - - mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, - MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | - MT_INT_MCU_CMD); - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); - - err = mt7921_run_firmware(dev); - if (err) - goto out; - - err = mt7921_mcu_set_eeprom(dev); - if (err) - goto out; - - err = mt7921_mac_init(dev); - if (err) - goto out; - - err = __mt7921_start(&dev->phy); -out: - clear_bit(MT76_RESET, &dev->mphy.state); - - napi_enable(&dev->mt76.tx_napi); - napi_schedule(&dev->mt76.tx_napi); - mt76_worker_enable(&dev->mt76.tx_worker); - - return err; -} - /* system error recovery */ void mt7921_mac_reset_work(struct work_struct *work) { @@ -1359,12 +1297,9 @@ void mt7921_mac_reset_work(struct work_struct *work) cancel_work_sync(&pm->wake_work); mutex_lock(&dev->mt76.mutex); - for (i = 0; i < 10; i++) { - __mt7921_mcu_drv_pmctrl(dev); - - if (!mt7921_mac_reset(dev)) + for (i = 0; i < 10; i++) + if (!mt7921_dev_reset(dev)) break; - } mutex_unlock(&dev->mt76.mutex); if (i == 10) @@ -1399,12 +1334,12 @@ void mt7921_reset(struct mt76_dev *mdev) queue_work(dev->mt76.wq, &dev->reset_work); } -static void -mt7921_mac_update_mib_stats(struct mt7921_phy *phy) +void mt7921_mac_update_mib_stats(struct mt7921_phy *phy) { struct mt7921_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; int i, aggr0 = 0, aggr1; + u32 val; mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(0), MT_MIB_SDR3_FCS_ERR_MASK); @@ -1417,8 +1352,37 @@ mt7921_mac_update_mib_stats(struct mt7921_phy *phy) mib->rts_retries_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR1(0), MT_MIB_RTS_FAIL_COUNT_MASK); + mib->tx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR12(0)); + mib->tx_mpdu_attempts_cnt += mt76_rr(dev, MT_MIB_SDR14(0)); + mib->tx_mpdu_success_cnt += mt76_rr(dev, MT_MIB_SDR15(0)); + + val = mt76_rr(dev, MT_MIB_SDR32(0)); + mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR9_EBF_CNT_MASK, val); + mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR9_IBF_CNT_MASK, val); + + val = mt76_rr(dev, MT_ETBF_TX_APP_CNT(0)); + mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, val); + mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, val); + + val = mt76_rr(dev, MT_ETBF_RX_FB_CNT(0)); + mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, val); + mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, val); + mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, val); + mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, val); + + mib->rx_mpdu_cnt += mt76_rr(dev, MT_MIB_SDR5(0)); + mib->rx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR22(0)); + mib->rx_ampdu_bytes_cnt += mt76_rr(dev, MT_MIB_SDR23(0)); + mib->rx_ba_cnt += mt76_rr(dev, MT_MIB_SDR31(0)); + + for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { + val = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + mib->tx_amsdu[i] += val; + mib->tx_amsdu_cnt += val; + } + for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { - u32 val, val2; + u32 val2; val = mt76_rr(dev, MT_TX_AGG_CNT(0, i)); val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i)); @@ -1449,6 +1413,8 @@ void mt7921_mac_work(struct work_struct *work) } mt7921_mutex_release(phy->dev); + + mt76_tx_status_check(mphy->dev, false); ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, MT7921_WATCHDOG_TIME); } @@ -1463,12 +1429,18 @@ void mt7921_pm_wake_work(struct work_struct *work) mphy = dev->phy.mt76; if (!mt7921_mcu_drv_pmctrl(dev)) { + struct mt76_dev *mdev = &dev->mt76; int i; - mt76_for_each_q_rx(&dev->mt76, i) - napi_schedule(&dev->mt76.napi[i]); - mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); - mt7921_tx_cleanup(dev); + if (mt76_is_sdio(mdev)) { + mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); + mt76_worker_schedule(&mdev->sdio.txrx_worker); + } else { + mt76_for_each_q_rx(mdev, i) + napi_schedule(&mdev->napi[i]); + mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); + mt7921_mcu_tx_cleanup(dev); + } if (test_bit(MT76_STATE_RUNNING, &mphy->state)) ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7921_WATCHDOG_TIME); @@ -1506,34 +1478,6 @@ out: queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); } -int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy, - struct ieee80211_vif *vif, - bool enable) -{ - struct mt7921_dev *dev = phy->dev; - bool ext_phy = phy != &dev->phy; - int err; - - if (!dev->pm.enable) - return -EOPNOTSUPP; - - err = mt7921_mcu_set_bss_pm(dev, vif, enable); - if (err) - return err; - - if (enable) { - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; - mt76_set(dev, MT_WF_RFCR(ext_phy), - MT_WF_RFCR_DROP_OTHER_BEACON); - } else { - vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; - mt76_clear(dev, MT_WF_RFCR(ext_phy), - MT_WF_RFCR_DROP_OTHER_BEACON); - } - - return 0; -} - void mt7921_coredump_work(struct work_struct *work) { struct mt7921_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 3af67fac213d..544a1c33126a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -116,6 +116,7 @@ enum rx_pkt_type { #define MT_PRXV_TX_DCM BIT(4) #define MT_PRXV_TX_ER_SU_106T BIT(5) #define MT_PRXV_NSTS GENMASK(9, 7) +#define MT_PRXV_TXBF BIT(10) #define MT_PRXV_HT_AD_CODE BIT(11) #define MT_PRXV_FRAME_MODE GENMASK(14, 12) #define MT_PRXV_SGI GENMASK(16, 15) @@ -138,8 +139,15 @@ enum rx_pkt_type { #define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) #define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) #define MT_CRXV_HE_PE_DISAMBIG BIT(23) +#define MT_CRXV_HE_NUM_USER GENMASK(30, 24) #define MT_CRXV_HE_UPLINK BIT(31) +#define MT_CRXV_HE_RU0 GENMASK(7, 0) +#define MT_CRXV_HE_RU1 GENMASK(15, 8) +#define MT_CRXV_HE_RU2 GENMASK(23, 16) +#define MT_CRXV_HE_RU3 GENMASK(31, 24) +#define MT_CRXV_HE_MU_AID GENMASK(30, 20) + #define MT_CRXV_HE_SR_MASK GENMASK(11, 8) #define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) #define MT_CRXV_HE_SR2_MASK GENMASK(20, 17) @@ -191,6 +199,10 @@ enum tx_mcu_port_q_idx { #define MT_TXD_SIZE (8 * 4) +#define MT_SDIO_TXD_SIZE (MT_TXD_SIZE + 8 * 4) +#define MT_SDIO_TAIL_SIZE 8 +#define MT_SDIO_HDR_SIZE 4 + #define MT_TXD0_Q_IDX GENMASK(31, 25) #define MT_TXD0_PKT_FMT GENMASK(24, 23) #define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) @@ -309,6 +321,15 @@ struct mt7921_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) +#define MT_TXS0_BW GENMASK(30, 29) +#define MT_TXS0_TXS_FORMAT GENMASK(24, 23) +#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) +#define MT_TXS0_TX_RATE GENMASK(13, 0) + +#define MT_TXS2_WCID GENMASK(25, 16) + +#define MT_TXS3_PID GENMASK(31, 24) + static inline struct mt7921_txp_common * mt7921_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) { @@ -350,4 +371,15 @@ struct mt7921_txp_common { }; }; +#define MT_WTBL_TXRX_CAP_RATE_OFFSET 7 +#define MT_WTBL_TXRX_RATE_G2_HE 24 +#define MT_WTBL_TXRX_RATE_G2 12 + +#define MT_WTBL_AC0_CTT_OFFSET 20 + +static inline u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset) +{ + return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4; +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 63ec140c9c37..35a490c049e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -72,7 +72,7 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; - else if (band == NL80211_BAND_5GHZ) + else he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; @@ -93,7 +93,7 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; - else if (band == NL80211_BAND_5GHZ) + else he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; @@ -142,6 +142,32 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, he_cap_elem->phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US; } + + if (band == NL80211_BAND_6GHZ) { + struct ieee80211_supported_band *sband = + &phy->mt76->sband_5g.sband; + struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap; + struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; + u32 exp; + u16 cap; + + cap = u16_encode_bits(ht_cap->ampdu_density, + IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); + exp = u32_get_bits(vht_cap->cap, + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); + cap |= u16_encode_bits(exp, + IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); + exp = u32_get_bits(vht_cap->cap, + IEEE80211_VHT_CAP_MAX_MPDU_MASK); + cap |= u16_encode_bits(exp, + IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); + if (vht_cap->cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN) + cap |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS; + if (vht_cap->cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN) + cap |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; + + data->he_6ghz_capa.capa = cpu_to_le16(cap); + } idx++; } @@ -170,6 +196,15 @@ void mt7921_set_stream_he_caps(struct mt7921_phy *phy) band = &phy->mt76->sband_5g.sband; band->iftype_data = data; band->n_iftype_data = n; + + if (phy->mt76->cap.has_6ghz) { + data = phy->iftype[NL80211_BAND_6GHZ]; + n = mt7921_init_he_caps(phy, NL80211_BAND_6GHZ, data); + + band = &phy->mt76->sband_6g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } } } @@ -202,6 +237,7 @@ int __mt7921_start(struct mt7921_phy *phy) return 0; } +EXPORT_SYMBOL_GPL(__mt7921_start); static int mt7921_start(struct ieee80211_hw *hw) { @@ -243,10 +279,6 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, mt7921_mutex_acquire(dev); - if (vif->type == NL80211_IFTYPE_MONITOR && - is_zero_ether_addr(vif->addr)) - phy->monitor_vif = vif; - mvif->mt76.idx = ffs(~dev->mt76.vif_mask) - 1; if (mvif->mt76.idx >= MT7921_MAX_INTERFACES) { ret = -ENOSPC; @@ -268,12 +300,13 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, idx = MT7921_WTBL_RESERVED - mvif->mt76.idx; - INIT_LIST_HEAD(&mvif->sta.stats_list); INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.ext_phy = mvif->mt76.band_idx; mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_packet_id_init(&mvif->sta.wcid); + mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -306,9 +339,6 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw, struct mt7921_phy *phy = mt7921_hw_phy(hw); int idx = msta->wcid.idx; - if (vif == phy->monitor_vif) - phy->monitor_vif = NULL; - mt7921_mutex_acquire(dev); mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, false); @@ -323,6 +353,8 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw, if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); + + mt76_packet_id_flush(&dev->mt76, &msta->wcid); } static int mt7921_set_channel(struct mt7921_phy *phy) @@ -533,36 +565,6 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw, mt7921_mutex_release(dev); } -static int -mt7921_bss_bcnft_apply(struct mt7921_dev *dev, struct ieee80211_vif *vif, - bool assoc) -{ - int ret; - - if (!dev->pm.enable) - return 0; - - if (assoc) { - ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true); - if (ret) - return ret; - - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; - mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); - - return 0; - } - - ret = mt7921_mcu_set_bss_pm(dev, vif, false); - if (ret) - return ret; - - vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; - mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); - - return 0; -} - static void mt7921_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -592,7 +594,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_ASSOC); - mt7921_bss_bcnft_apply(dev, vif, info->assoc); + if (dev->pm.enable) + mt7921_mcu_set_beacon_filter(dev, vif, info->assoc); } if (changed & BSS_CHANGED_ARP_FILTER) { @@ -617,14 +620,13 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; - INIT_LIST_HEAD(&msta->stats_list); INIT_LIST_HEAD(&msta->poll_list); msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.ext_phy = mvif->mt76.band_idx; msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta->stats.jiffies = jiffies; + msta->last_txs = jiffies; ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) @@ -645,6 +647,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, return 0; } +EXPORT_SYMBOL_GPL(mt7921_mac_sta_add); void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -666,6 +669,7 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7921_mutex_release(dev); } +EXPORT_SYMBOL_GPL(mt7921_mac_sta_assoc); void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -693,12 +697,11 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, spin_lock_bh(&dev->sta_poll_lock); if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); - if (!list_empty(&msta->stats_list)) - list_del_init(&msta->stats_list); spin_unlock_bh(&dev->sta_poll_lock); mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } +EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove); void mt7921_tx_worker(struct mt76_worker *w) { @@ -853,13 +856,175 @@ mt7921_get_stats(struct ieee80211_hw *hw, stats->dot11FCSErrorCount = mib->fcs_err_cnt; stats->dot11ACKFailureCount = mib->ack_fail_cnt; - memset(mib, 0, sizeof(*mib)); - mt7921_mutex_release(phy->dev); return 0; } +static const char mt7921_gstrings_stats[][ETH_GSTRING_LEN] = { + /* tx counters */ + "tx_ampdu_cnt", + "tx_mpdu_attempts", + "tx_mpdu_success", + "tx_pkt_ebf_cnt", + "tx_pkt_ibf_cnt", + "tx_ampdu_len:0-1", + "tx_ampdu_len:2-10", + "tx_ampdu_len:11-19", + "tx_ampdu_len:20-28", + "tx_ampdu_len:29-37", + "tx_ampdu_len:38-46", + "tx_ampdu_len:47-55", + "tx_ampdu_len:56-79", + "tx_ampdu_len:80-103", + "tx_ampdu_len:104-127", + "tx_ampdu_len:128-151", + "tx_ampdu_len:152-175", + "tx_ampdu_len:176-199", + "tx_ampdu_len:200-223", + "tx_ampdu_len:224-247", + "ba_miss_count", + "tx_beamformer_ppdu_iBF", + "tx_beamformer_ppdu_eBF", + "tx_beamformer_rx_feedback_all", + "tx_beamformer_rx_feedback_he", + "tx_beamformer_rx_feedback_vht", + "tx_beamformer_rx_feedback_ht", + "tx_msdu_pack_1", + "tx_msdu_pack_2", + "tx_msdu_pack_3", + "tx_msdu_pack_4", + "tx_msdu_pack_5", + "tx_msdu_pack_6", + "tx_msdu_pack_7", + "tx_msdu_pack_8", + /* rx counters */ + "rx_mpdu_cnt", + "rx_ampdu_cnt", + "rx_ampdu_bytes_cnt", + "rx_ba_cnt", + /* per vif counters */ + "v_tx_mode_cck", + "v_tx_mode_ofdm", + "v_tx_mode_ht", + "v_tx_mode_ht_gf", + "v_tx_mode_vht", + "v_tx_mode_he_su", + "v_tx_mode_he_ext_su", + "v_tx_mode_he_tb", + "v_tx_mode_he_mu", + "v_tx_bw_20", + "v_tx_bw_40", + "v_tx_bw_80", + "v_tx_bw_160", + "v_tx_mcs_0", + "v_tx_mcs_1", + "v_tx_mcs_2", + "v_tx_mcs_3", + "v_tx_mcs_4", + "v_tx_mcs_5", + "v_tx_mcs_6", + "v_tx_mcs_7", + "v_tx_mcs_8", + "v_tx_mcs_9", + "v_tx_mcs_10", + "v_tx_mcs_11", +}; + +static void +mt7921_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 sset, u8 *data) +{ + if (sset != ETH_SS_STATS) + return; + + memcpy(data, *mt7921_gstrings_stats, sizeof(mt7921_gstrings_stats)); +} + +static int +mt7921_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int sset) +{ + return sset == ETH_SS_STATS ? ARRAY_SIZE(mt7921_gstrings_stats) : 0; +} + +static void +mt7921_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) +{ + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + struct mt76_ethtool_worker_info *wi = wi_data; + + if (msta->vif->mt76.idx != wi->idx) + return; + + mt76_ethtool_worker(wi, &msta->stats); +} + +static +void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data) +{ + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = phy->dev; + struct mib_stats *mib = &phy->mib; + struct mt76_ethtool_worker_info wi = { + .data = data, + .idx = mvif->mt76.idx, + }; + int i, ei = 0; + + mt7921_mutex_acquire(dev); + + mt7921_mac_update_mib_stats(phy); + + data[ei++] = mib->tx_ampdu_cnt; + data[ei++] = mib->tx_mpdu_attempts_cnt; + data[ei++] = mib->tx_mpdu_success_cnt; + data[ei++] = mib->tx_pkt_ebf_cnt; + data[ei++] = mib->tx_pkt_ibf_cnt; + + /* Tx ampdu stat */ + for (i = 0; i < 15; i++) + data[ei++] = dev->mt76.aggr_stats[i]; + + data[ei++] = phy->mib.ba_miss_cnt; + + /* Tx Beamformer monitor */ + data[ei++] = mib->tx_bf_ibf_ppdu_cnt; + data[ei++] = mib->tx_bf_ebf_ppdu_cnt; + + /* Tx Beamformer Rx feedback monitor */ + data[ei++] = mib->tx_bf_rx_fb_all_cnt; + data[ei++] = mib->tx_bf_rx_fb_he_cnt; + data[ei++] = mib->tx_bf_rx_fb_vht_cnt; + data[ei++] = mib->tx_bf_rx_fb_ht_cnt; + + /* Tx amsdu info (pack-count histogram) */ + for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) + data[ei++] = mib->tx_amsdu[i]; + + /* rx counters */ + data[ei++] = mib->rx_mpdu_cnt; + data[ei++] = mib->rx_ampdu_cnt; + data[ei++] = mib->rx_ampdu_bytes_cnt; + data[ei++] = mib->rx_ba_cnt; + + /* Add values for all stations owned by this vif */ + wi.initial_stat_idx = ei; + ieee80211_iterate_stations_atomic(hw, mt7921_ethtool_worker, &wi); + + mt7921_mutex_release(dev); + + if (!wi.sta_count) + return; + + ei += wi.worker_stat_count; + if (ei != ARRAY_SIZE(mt7921_gstrings_stats)) + dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %lu", + ei, ARRAY_SIZE(mt7921_gstrings_stats)); +} + static u64 mt7921_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1048,22 +1213,22 @@ static void mt7921_sta_statistics(struct ieee80211_hw *hw, struct station_info *sinfo) { struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; - struct mt7921_sta_stats *stats = &msta->stats; + struct rate_info *txrate = &msta->wcid.rate; - if (!stats->tx_rate.legacy && !stats->tx_rate.flags) + if (!txrate->legacy && !txrate->flags) return; - if (stats->tx_rate.legacy) { - sinfo->txrate.legacy = stats->tx_rate.legacy; + if (txrate->legacy) { + sinfo->txrate.legacy = txrate->legacy; } else { - sinfo->txrate.mcs = stats->tx_rate.mcs; - sinfo->txrate.nss = stats->tx_rate.nss; - sinfo->txrate.bw = stats->tx_rate.bw; - sinfo->txrate.he_gi = stats->tx_rate.he_gi; - sinfo->txrate.he_dcm = stats->tx_rate.he_dcm; - sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc; + sinfo->txrate.mcs = txrate->mcs; + sinfo->txrate.nss = txrate->nss; + sinfo->txrate.bw = txrate->bw; + sinfo->txrate.he_gi = txrate->he_gi; + sinfo->txrate.he_dcm = txrate->he_dcm; + sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; } - sinfo->txrate.flags = stats->tx_rate.flags; + sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } @@ -1172,6 +1337,43 @@ static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw, MCU_UNI_CMD_STA_REC_UPDATE); } +static int mt7921_set_sar_specs(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar) +{ + const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt76_freq_range_power *data, *frp; + struct mt76_phy *mphy = hw->priv; + int err; + u32 i; + + if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) + return -EINVAL; + + mt7921_mutex_acquire(dev); + + data = mphy->frp; + + for (i = 0; i < sar->num_sub_specs; i++) { + u32 index = sar->sub_specs[i].freq_range_index; + /* SAR specifies power limitaton in 0.25dbm */ + s32 power = sar->sub_specs[i].power >> 1; + + if (power > 127 || power < -127) + power = 127; + + frp = &data[index]; + frp->range = &capa->freq_ranges[index]; + frp->power = power; + } + + err = mt76_connac_mcu_set_rate_txpower(mphy); + + mt7921_mutex_release(dev); + + return err; +} + const struct ieee80211_ops mt7921_ops = { .tx = mt7921_tx, .start = mt7921_start, @@ -1192,6 +1394,9 @@ const struct ieee80211_ops mt7921_ops = { .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt76_get_txpower, .get_stats = mt7921_get_stats, + .get_et_sset_count = mt7921_get_et_sset_count, + .get_et_strings = mt7921_get_et_strings, + .get_et_stats = mt7921_get_et_stats, .get_tsf = mt7921_get_tsf, .set_tsf = mt7921_set_tsf, .get_survey = mt76_get_survey, @@ -1203,6 +1408,8 @@ const struct ieee80211_ops mt7921_ops = { .sta_statistics = mt7921_sta_statistics, .sched_scan_start = mt7921_start_sched_scan, .sched_scan_stop = mt7921_stop_sched_scan, + CFG80211_TESTMODE_CMD(mt7921_testmode_cmd) + CFG80211_TESTMODE_DUMP(mt7921_testmode_dump) #ifdef CONFIG_PM .suspend = mt7921_suspend, .resume = mt7921_resume, @@ -1210,4 +1417,9 @@ const struct ieee80211_ops mt7921_ops = { .set_rekey_data = mt7921_set_rekey_data, #endif /* CONFIG_PM */ .flush = mt7921_flush, + .set_sar_specs = mt7921_set_sar_specs, }; +EXPORT_SYMBOL_GPL(mt7921_ops); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 9fbaacc67cfa..6ada1ebe7d68 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -82,9 +82,17 @@ struct mt7921_fw_region { #define FW_START_OVERRIDE BIT(0) #define FW_START_WORKING_PDA_CR4 BIT(2) +#define PATCH_SEC_NOT_SUPPORT GENMASK(31, 0) #define PATCH_SEC_TYPE_MASK GENMASK(15, 0) #define PATCH_SEC_TYPE_INFO 0x2 +#define PATCH_SEC_ENC_TYPE_MASK GENMASK(31, 24) +#define PATCH_SEC_ENC_TYPE_PLAIN 0x00 +#define PATCH_SEC_ENC_TYPE_AES 0x01 +#define PATCH_SEC_ENC_TYPE_SCRAMBLE 0x02 +#define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0) +#define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0) + #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) @@ -152,11 +160,11 @@ mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb) return 0; } -static int -mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, - struct sk_buff *skb, int seq) +int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq) { struct mt7921_mcu_rxd *rxd; + int mcu_cmd = cmd & MCU_CMD_MASK; int ret = 0; if (!skb) { @@ -194,6 +202,9 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, skb_pull(skb, sizeof(*rxd)); event = (struct mt7921_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); + /* skip invalid event */ + if (mcu_cmd != event->cid) + ret = -EAGAIN; break; } case MCU_CMD_REG_READ: { @@ -211,14 +222,13 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, return ret; } +EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response); -static int -mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, - int cmd, int *wait_seq) +int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *wait_seq) { struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); int txd_len, mcu_cmd = cmd & MCU_CMD_MASK; - enum mt76_mcuq_id txq = MT_MCUQ_WM; struct mt7921_uni_txd *uni_txd; struct mt7921_mcu_txd *mcu_txd; __le32 *txd; @@ -240,10 +250,8 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, if (!seq) seq = ++dev->mt76.mcu.msg_seq & 0xf; - if (cmd == MCU_CMD_FW_SCATTER) { - txq = MT_MCUQ_FWDL; + if (cmd == MCU_CMD_FW_SCATTER) goto exit; - } txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd); txd = (__le32 *)skb_push(skb, txd_len); @@ -307,96 +315,9 @@ exit: if (wait_seq) *wait_seq = seq; - return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); -} - -static void -mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, - struct mt7921_mcu_peer_cap *peer, - struct rate_info *rate, u16 r) -{ - struct ieee80211_supported_band *sband; - u16 flags = 0; - u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r); - u8 gi = 0; - u8 bw = 0; - - rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r); - rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1; - - switch (peer->bw) { - case IEEE80211_STA_RX_BW_160: - gi = peer->g16; - break; - case IEEE80211_STA_RX_BW_80: - gi = peer->g8; - break; - case IEEE80211_STA_RX_BW_40: - gi = peer->g4; - break; - default: - gi = peer->g2; - break; - } - - gi = txmode >= MT_PHY_TYPE_HE_SU ? - FIELD_GET(MT_WTBL_RATE_HE_GI, gi) : - FIELD_GET(MT_WTBL_RATE_GI, gi); - - switch (txmode) { - case MT_PHY_TYPE_CCK: - case MT_PHY_TYPE_OFDM: - if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) - sband = &mphy->sband_5g.sband; - else - sband = &mphy->sband_2g.sband; - - rate->legacy = sband->bitrates[rate->mcs].bitrate; - break; - case MT_PHY_TYPE_HT: - case MT_PHY_TYPE_HT_GF: - flags |= RATE_INFO_FLAGS_MCS; - - if (gi) - flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case MT_PHY_TYPE_VHT: - flags |= RATE_INFO_FLAGS_VHT_MCS; - - if (gi) - flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case MT_PHY_TYPE_HE_SU: - case MT_PHY_TYPE_HE_EXT_SU: - case MT_PHY_TYPE_HE_TB: - case MT_PHY_TYPE_HE_MU: - rate->he_gi = gi; - rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); - - flags |= RATE_INFO_FLAGS_HE_MCS; - break; - default: - break; - } - rate->flags = flags; - - bw = mt7921_mcu_chan_bw(&mphy->chandef) - FIELD_GET(MT_RA_RATE_BW, r); - - switch (bw) { - case IEEE80211_STA_RX_BW_160: - rate->bw = RATE_INFO_BW_160; - break; - case IEEE80211_STA_RX_BW_80: - rate->bw = RATE_INFO_BW_80; - break; - case IEEE80211_STA_RX_BW_40: - rate->bw = RATE_INFO_BW_40; - break; - default: - rate->bw = RATE_INFO_BW_20; - break; - } + return 0; } +EXPORT_SYMBOL_GPL(mt7921_mcu_fill_message); static void mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) @@ -498,49 +419,6 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) } static void -mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) -{ - struct mt7921_mcu_tx_done_event *event; - struct mt7921_sta *msta; - struct mt7921_phy *mphy = &dev->phy; - struct mt7921_mcu_peer_cap peer; - struct ieee80211_sta *sta; - LIST_HEAD(list); - - skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); - event = (struct mt7921_mcu_tx_done_event *)skb->data; - - spin_lock_bh(&dev->sta_poll_lock); - list_splice_init(&mphy->stats_list, &list); - - while (!list_empty(&list)) { - msta = list_first_entry(&list, struct mt7921_sta, stats_list); - list_del_init(&msta->stats_list); - - if (msta->wcid.idx != event->wlan_idx) - continue; - - spin_unlock_bh(&dev->sta_poll_lock); - - sta = wcid_to_sta(&msta->wcid); - - /* peer config based on IEEE SPEC */ - memset(&peer, 0x0, sizeof(peer)); - peer.bw = event->bw; - peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); - peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); - peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); - peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); - mt7921_mcu_tx_rate_parse(mphy->mt76, &peer, - &msta->stats.tx_rate, event->tx_rate); - - spin_lock_bh(&dev->sta_poll_lock); - break; - } - spin_unlock_bh(&dev->sta_poll_lock); -} - -static void mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; @@ -560,15 +438,13 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) mt7921_mcu_debug_msg_event(dev, skb); break; case MCU_EVENT_COREDUMP: + dev->fw_assert = true; mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump); return; case MCU_EVENT_LP_INFO: mt7921_mcu_low_power_event(dev, skb); break; - case MCU_EVENT_TX_DONE: - mt7921_mcu_tx_done_event(dev, skb); - break; default: break; } @@ -577,7 +453,12 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) { - struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; + struct mt7921_mcu_rxd *rxd; + + if (skb_linearize(skb)) + return; + + rxd = (struct mt7921_mcu_rxd *)skb->data; if (rxd->eid == 0x6) { mt76_mcu_rx_event(&dev->mt76, skb); @@ -619,7 +500,7 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, u8 cipher; cipher = mt7921_mcu_get_cipher(key->cipher); - if (cipher == MT_CIPHER_NONE) + if (cipher == MCU_CIPHER_NONE) return -EOPNOTSUPP; sec_key = &sec->key[0]; @@ -712,7 +593,7 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, enable, false); } -static int mt7921_mcu_restart(struct mt76_dev *dev) +int mt7921_mcu_restart(struct mt76_dev *dev) { struct { u8 power_mode; @@ -724,26 +605,55 @@ static int mt7921_mcu_restart(struct mt76_dev *dev) return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req, sizeof(req), false); } +EXPORT_SYMBOL_GPL(mt7921_mcu_restart); -static int mt7921_driver_own(struct mt7921_dev *dev) +static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info) { - u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + u32 mode = DL_MODE_NEED_RSP; - mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); - if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, - 0, 500)) { - dev_err(dev->mt76.dev, "Timeout for driver own\n"); - return -EIO; + if (info == PATCH_SEC_NOT_SUPPORT) + return mode; + + switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { + case PATCH_SEC_ENC_TYPE_PLAIN: + break; + case PATCH_SEC_ENC_TYPE_AES: + mode |= DL_MODE_ENCRYPT; + mode |= FIELD_PREP(DL_MODE_KEY_IDX, + (info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX; + mode |= DL_MODE_RESET_SEC_IV; + break; + case PATCH_SEC_ENC_TYPE_SCRAMBLE: + mode |= DL_MODE_ENCRYPT; + mode |= DL_CONFIG_ENCRY_MODE_SEL; + mode |= DL_MODE_RESET_SEC_IV; + break; + default: + dev_err(dev->mt76.dev, "Encryption type not support!\n"); } - return 0; + return mode; +} + +static char *mt7921_patch_name(struct mt7921_dev *dev) +{ + char *ret; + + if (is_mt7922(&dev->mt76)) + ret = MT7922_ROM_PATCH; + else + ret = MT7921_ROM_PATCH; + + return ret; } static int mt7921_load_patch(struct mt7921_dev *dev) { const struct mt7921_patch_hdr *hdr; const struct firmware *fw = NULL; - int i, ret, sem; + int i, ret, sem, max_len; + + max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096; sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); switch (sem) { @@ -756,7 +666,7 @@ static int mt7921_load_patch(struct mt7921_dev *dev) return -EAGAIN; } - ret = request_firmware(&fw, MT7921_ROM_PATCH, dev->mt76.dev); + ret = request_firmware(&fw, mt7921_patch_name(dev), dev->mt76.dev); if (ret) goto out; @@ -774,7 +684,8 @@ static int mt7921_load_patch(struct mt7921_dev *dev) for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { struct mt7921_patch_sec *sec; const u8 *dl; - u32 len, addr; + u32 len, addr, mode; + u32 sec_info = 0; sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); @@ -787,16 +698,18 @@ static int mt7921_load_patch(struct mt7921_dev *dev) addr = be32_to_cpu(sec->info.addr); len = be32_to_cpu(sec->info.len); dl = fw->data + be32_to_cpu(sec->offs); + sec_info = be32_to_cpu(sec->info.sec_key_idx); + mode = mt7921_get_data_mode(dev, sec_info); ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, - DL_MODE_NEED_RSP); + mode); if (ret) { dev_err(dev->mt76.dev, "Download request failed\n"); goto out; } - ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, - dl, len); + ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, + dl, len, max_len); if (ret) { dev_err(dev->mt76.dev, "Failed to send patch\n"); goto out; @@ -815,7 +728,7 @@ out: default: ret = -EAGAIN; dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); - goto out; + break; } release_firmware(fw); @@ -843,9 +756,11 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, const struct mt7921_fw_trailer *hdr, const u8 *data, bool is_wa) { - int i, offset = 0; + int i, offset = 0, max_len; u32 override = 0, option = 0; + max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096; + for (i = 0; i < hdr->n_region; i++) { const struct mt7921_fw_region *region; int err; @@ -867,8 +782,8 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, return err; } - err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, - data + offset, len); + err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, + data + offset, len, max_len); if (err) { dev_err(dev->mt76.dev, "Failed to send firmware.\n"); return err; @@ -886,13 +801,25 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); } +static char *mt7921_ram_name(struct mt7921_dev *dev) +{ + char *ret; + + if (is_mt7922(&dev->mt76)) + ret = MT7922_FIRMWARE_WM; + else + ret = MT7921_FIRMWARE_WM; + + return ret; +} + static int mt7921_load_ram(struct mt7921_dev *dev) { const struct mt7921_fw_trailer *hdr; const struct firmware *fw; int ret; - ret = request_firmware(&fw, MT7921_FIRMWARE_WM, dev->mt76.dev); + ret = request_firmware(&fw, mt7921_ram_name(dev), dev->mt76.dev); if (ret) return ret; @@ -929,7 +856,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) int ret; ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); - if (ret) { + if (ret && mt76_is_mmio(&dev->mt76)) { dev_dbg(dev->mt76.dev, "Firmware is already download\n"); goto fw_loaded; } @@ -950,7 +877,6 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) } fw_loaded: - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); #ifdef CONFIG_PM dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; @@ -978,39 +904,24 @@ int mt7921_run_firmware(struct mt7921_dev *dev) { int err; - err = mt7921_driver_own(dev); + err = mt7921_load_firmware(dev); if (err) return err; - err = mt7921_load_firmware(dev); + err = mt76_connac_mcu_get_nic_capability(&dev->mphy); if (err) return err; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); - mt7921_mcu_fw_log_2_host(dev, 1); - - return mt76_connac_mcu_get_nic_capability(&dev->mphy); -} - -int mt7921_mcu_init(struct mt7921_dev *dev) -{ - static const struct mt76_mcu_ops mt7921_mcu_ops = { - .headroom = sizeof(struct mt7921_mcu_txd), - .mcu_skb_send_msg = mt7921_mcu_send_message, - .mcu_parse_response = mt7921_mcu_parse_response, - .mcu_restart = mt7921_mcu_restart, - }; - - dev->mt76.mcu_ops = &mt7921_mcu_ops; - - return mt7921_run_firmware(dev); + return mt7921_mcu_fw_log_2_host(dev, 1); } +EXPORT_SYMBOL_GPL(mt7921_run_firmware); void mt7921_mcu_exit(struct mt7921_dev *dev) { - mt7921_wfsys_reset(dev); skb_queue_purge(&dev->mt76.mcu.res_q); } +EXPORT_SYMBOL_GPL(mt7921_mcu_exit); int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) { @@ -1041,7 +952,30 @@ int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) .total = IEEE80211_NUM_ACS, }; struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; - int ac; + struct mu_edca { + u8 cw_min; + u8 cw_max; + u8 aifsn; + u8 acm; + u8 timer; + u8 padding[3]; + }; + struct mt7921_mcu_mu_tx { + u8 ver; + u8 pad0; + __le16 len; + u8 bss_idx; + u8 qos; + u8 wmm_idx; + u8 pad1; + struct mu_edca edca[IEEE80211_NUM_ACS]; + u8 pad3[32]; + } __packed req_mu = { + .bss_idx = mvif->mt76.idx, + .qos = vif->bss_conf.qos, + .wmm_idx = mvif->mt76.wmm_idx, + }; + int ac, ret; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; @@ -1062,8 +996,34 @@ int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif) else e->cw_max = cpu_to_le16(10); } - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, - sizeof(req), true); + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, + sizeof(req), true); + if (ret) + return ret; + + if (!vif->bss_conf.he_support) + return 0; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct ieee80211_he_mu_edca_param_ac_rec *q; + struct mu_edca *e; + int to_aci[] = {1, 0, 2, 3}; + + if (!mvif->queue_params[ac].mu_edca) + break; + + q = &mvif->queue_params[ac].mu_edca_param_rec; + e = &(req_mu.edca[to_aci[ac]]); + + e->cw_min = q->ecw_min_max & 0xf; + e->cw_max = (q->ecw_min_max & 0xf0) >> 4; + e->aifsn = q->aifsn; + e->timer = q->mu_edca_timer; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_MU_EDCA_PARMS, &req_mu, + sizeof(req_mu), false); } int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) @@ -1095,9 +1055,13 @@ int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd) .tx_streams_num = hweight8(phy->mt76->antenna_mask), .rx_streams = phy->mt76->antenna_mask, .band_idx = phy != &dev->phy, - .channel_band = chandef->chan->band, }; + if (chandef->chan->band == NL80211_BAND_6GHZ) + req.channel_band = 2; + else + req.channel_band = chandef->chan->band; + if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && @@ -1132,6 +1096,7 @@ int mt7921_mcu_set_eeprom(struct mt7921_dev *dev) return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, &req, sizeof(req), true); } +EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom); int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) { @@ -1193,8 +1158,9 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) &ps_req, sizeof(ps_req), true); } -int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, - bool enable) +static int +mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, + bool enable) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; struct { @@ -1228,8 +1194,9 @@ int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, &bcnft_req, sizeof(bcnft_req), true); } -int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, - bool enable) +static int +mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, + bool enable) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; struct { @@ -1292,35 +1259,6 @@ int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); } -int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) -{ - struct mt76_phy *mphy = &dev->mt76.phy; - struct mt76_connac_pm *pm = &dev->pm; - int i, err = 0; - - for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { - mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); - if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, - PCIE_LPCR_HOST_OWN_SYNC, 0, 50)) - break; - } - - if (i == MT7921_DRV_OWN_RETRY_COUNT) { - dev_err(dev->mt76.dev, "driver own failed\n"); - err = -EIO; - goto out; - } - - mt7921_wpdma_reinit_cond(dev); - clear_bit(MT76_STATE_PM, &mphy->state); - - pm->stats.last_wake_event = jiffies; - pm->stats.doze_time += pm->stats.last_wake_event - - pm->stats.last_doze_event; -out: - return err; -} - int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; @@ -1341,34 +1279,20 @@ out: return err; } +EXPORT_SYMBOL_GPL(mt7921_mcu_drv_pmctrl); int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; - int i, err = 0; + int err = 0; mutex_lock(&pm->mutex); if (mt76_connac_skip_fw_pmctrl(mphy, pm)) goto out; - for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { - mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); - if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, - PCIE_LPCR_HOST_OWN_SYNC, 4, 50)) - break; - } - - if (i == MT7921_DRV_OWN_RETRY_COUNT) { - dev_err(dev->mt76.dev, "firmware own failed\n"); - clear_bit(MT76_STATE_PM, &mphy->state); - err = -EIO; - } - - pm->stats.last_doze_event = jiffies; - pm->stats.awake_time += pm->stats.last_doze_event - - pm->stats.last_wake_event; + err = __mt7921_mcu_fw_pmctrl(dev); out: mutex_unlock(&pm->mutex); @@ -1377,32 +1301,36 @@ out: return err; } +EXPORT_SYMBOL_GPL(mt7921_mcu_fw_pmctrl); -void -mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, + struct ieee80211_vif *vif, + bool enable) { - struct mt7921_phy *phy = priv; - struct mt7921_dev *dev = phy->dev; struct ieee80211_hw *hw = mt76_hw(dev); - int ret; - - if (dev->pm.enable) - ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true); - else - ret = mt7921_mcu_set_bss_pm(dev, vif, false); + int err; - if (ret) - return; + if (enable) { + err = mt7921_mcu_uni_bss_bcnft(dev, vif, true); + if (err) + return err; - if (dev->pm.enable) { vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; ieee80211_hw_set(hw, CONNECTION_MONITOR); mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); - } else { - vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; - __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); - mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); + + return 0; } + + err = mt7921_mcu_set_bss_pm(dev, vif, false); + if (err) + return err; + + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); + mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); + + return 0; } int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index de3c091f6736..edc0c73f8c01 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -259,25 +259,6 @@ struct mt7921_mcu_ant_id_config { u8 ant_id[4]; } __packed; -struct mt7921_mcu_peer_cap { - struct mt7921_mcu_ant_id_config ant_id_config; - - u8 power_offset; - u8 bw_selector; - u8 change_bw_rate_n; - u8 bw; - u8 spe_idx; - - u8 g2; - u8 g4; - u8 g8; - u8 g16; - - u8 mmss; - u8 ampdu_factor; - u8 rsv[1]; -} __packed; - struct mt7921_txpwr_req { u8 ver; u8 action; @@ -293,31 +274,29 @@ struct mt7921_txpwr_event { struct mt7921_txpwr txpwr; } __packed; -struct mt7921_mcu_tx_done_event { - u8 pid; - u8 status; - u16 seq; - - u8 wlan_idx; - u8 tx_cnt; - u16 tx_rate; - - u8 flag; - u8 tid; - u8 rsp_rate; - u8 mcs; - - u8 bw; - u8 tx_pwr; - u8 reason; - u8 rsv0[1]; +enum { + TM_SWITCH_MODE, + TM_SET_AT_CMD, + TM_QUERY_AT_CMD, +}; - u32 delay; - u32 timestamp; - u32 applied_flag; +enum { + MT7921_TM_NORMAL, + MT7921_TM_TESTMODE, + MT7921_TM_ICAP, + MT7921_TM_ICAP_OVERLAP, + MT7921_TM_WIFISPECTRUM, +}; - u8 txs[28]; +struct mt7921_rftest_cmd { + u8 action; + u8 rsv[3]; + __le32 param0; + __le32 param1; +} __packed; - u8 rsv1[32]; +struct mt7921_rftest_evt { + __le32 param0; + __le32 param1; } __packed; #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 2d8bd6bfc820..e9c7c3a19507 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -29,22 +29,47 @@ #define MT7921_RX_MCU_RING_SIZE 512 #define MT7921_DRV_OWN_RETRY_COUNT 10 +#define MT7921_MCU_INIT_RETRY_COUNT 10 #define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" #define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" +#define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin" +#define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin" + #define MT7921_EEPROM_SIZE 3584 #define MT7921_TOKEN_SIZE 8192 #define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7921_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ -#define MT7921_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ -#define MT7921_2G_RATE_DEFAULT 0x0 /* CCK 1M */ #define MT7921_SKU_RATE_NUM 161 #define MT7921_SKU_MAX_DELTA_IDX MT7921_SKU_RATE_NUM #define MT7921_SKU_TABLE_SIZE (MT7921_SKU_RATE_NUM + 1) +#define MT7921_SDIO_HDR_TX_BYTES GENMASK(15, 0) +#define MT7921_SDIO_HDR_PKT_TYPE GENMASK(17, 16) + +enum mt7921_sdio_pkt_type { + MT7921_SDIO_TXD, + MT7921_SDIO_DATA, + MT7921_SDIO_CMD, + MT7921_SDIO_FWDL, +}; + +struct mt7921_sdio_intr { + u32 isr; + struct { + u32 wtqcr[16]; + } tx; + struct { + u16 num[2]; + u16 len0[16]; + u16 len1[128]; + } rx; + u32 rec_mb[2]; +} __packed; + #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) #define to_rcpi(rssi) (2 * (rssi) + 220) @@ -64,15 +89,6 @@ enum mt7921_rxq_id { MT7921_RXQ_MCU_WM = 0, }; -struct mt7921_sta_stats { - struct rate_info prob_rate; - struct rate_info tx_rate; - - unsigned long per; - unsigned long changed; - unsigned long jiffies; -}; - struct mt7921_sta_key_conf { s8 keyidx; u8 key[16]; @@ -83,17 +99,14 @@ struct mt7921_sta { struct mt7921_vif *vif; - struct list_head stats_list; struct list_head poll_list; u32 airtime_ac[8]; - struct mt7921_sta_stats stats; - + unsigned long last_txs; unsigned long ampdu_state; + struct mt76_sta_stats stats; struct mt7921_sta_key_conf bip; - - unsigned long next_txs_ts; }; DECLARE_EWMA(rssi, 10, 8); @@ -117,15 +130,34 @@ struct mib_stats { u32 rts_cnt; u32 rts_retries_cnt; u32 ba_miss_cnt; + + u32 tx_bf_ibf_ppdu_cnt; + u32 tx_bf_ebf_ppdu_cnt; + u32 tx_bf_rx_fb_all_cnt; + u32 tx_bf_rx_fb_he_cnt; + u32 tx_bf_rx_fb_vht_cnt; + u32 tx_bf_rx_fb_ht_cnt; + + u32 tx_ampdu_cnt; + u32 tx_mpdu_attempts_cnt; + u32 tx_mpdu_success_cnt; + u32 tx_pkt_ebf_cnt; + u32 tx_pkt_ibf_cnt; + + u32 rx_mpdu_cnt; + u32 rx_ampdu_cnt; + u32 rx_ampdu_bytes_cnt; + u32 rx_ba_cnt; + + u32 tx_amsdu[8]; + u32 tx_amsdu_cnt; }; struct mt7921_phy { struct mt76_phy *mt76; struct mt7921_dev *dev; - struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; - - struct ieee80211_vif *monitor_vif; + struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES]; u32 rxfilter; u64 omac_mask; @@ -139,7 +171,6 @@ struct mt7921_phy { u32 ampdu_ref; struct mib_stats mib; - struct list_head stats_list; u8 sta_work_count; @@ -147,6 +178,19 @@ struct mt7921_phy { struct delayed_work scan_work; }; +#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev)) +#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev)) +#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev)) +#define __mt7921_mcu_drv_pmctrl(dev) ((dev)->hif_ops->drv_own(dev)) +#define __mt7921_mcu_fw_pmctrl(dev) ((dev)->hif_ops->fw_own(dev)) +struct mt7921_hif_ops { + int (*init_reset)(struct mt7921_dev *dev); + int (*reset)(struct mt7921_dev *dev); + int (*mcu_init)(struct mt7921_dev *dev); + int (*drv_own)(struct mt7921_dev *dev); + int (*fw_own)(struct mt7921_dev *dev); +}; + struct mt7921_dev { union { /* must be first */ struct mt76_dev mt76; @@ -157,11 +201,10 @@ struct mt7921_dev { struct mt7921_phy phy; struct tasklet_struct irq_tasklet; - u16 chainmask; - struct work_struct reset_work; bool hw_full_reset:1; bool hw_init_done:1; + bool fw_assert:1; struct list_head sta_poll_list; spinlock_t sta_poll_lock; @@ -170,6 +213,7 @@ struct mt7921_dev { struct mt76_connac_pm pm; struct mt76_connac_coredump coredump; + const struct mt7921_hif_ops *hif_ops; }; enum { @@ -247,18 +291,11 @@ u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr); int __mt7921_start(struct mt7921_phy *phy); int mt7921_register_device(struct mt7921_dev *dev); void mt7921_unregister_device(struct mt7921_dev *dev); -int mt7921_eeprom_init(struct mt7921_dev *dev); -void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy); -int mt7921_eeprom_get_target_power(struct mt7921_dev *dev, - struct ieee80211_channel *chan, - u8 chain_idx); -void mt7921_eeprom_init_sku(struct mt7921_dev *dev); int mt7921_dma_init(struct mt7921_dev *dev); int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force); int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev); void mt7921_dma_cleanup(struct mt7921_dev *dev); int mt7921_run_firmware(struct mt7921_dev *dev); -int mt7921_mcu_init(struct mt7921_dev *dev); int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, struct mt7921_sta *msta, struct ieee80211_key_conf *key, enum set_key_cmd cmd); @@ -324,16 +361,27 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev) return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); } +static inline void mt7921_mcu_tx_cleanup(struct mt7921_dev *dev) +{ + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false); +} + +static inline void mt7921_skb_add_sdio_hdr(struct sk_buff *skb, + enum mt7921_sdio_pkt_type type) +{ + u32 hdr; + + hdr = FIELD_PREP(MT7921_SDIO_HDR_TX_BYTES, skb->len + sizeof(hdr)) | + FIELD_PREP(MT7921_SDIO_HDR_PKT_TYPE, type); + + put_unaligned_le32(hdr, skb_push(skb, sizeof(hdr))); +} + int mt7921_mac_init(struct mt7921_dev *dev); bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask); void mt7921_mac_reset_counters(struct mt7921_phy *phy); -void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, bool beacon); void mt7921_mac_set_timing(struct mt7921_phy *phy); -int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb); -void mt7921_mac_fill_rx_vector(struct mt7921_dev *dev, struct sk_buff *skb); -void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb); int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -342,27 +390,28 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7921_mac_work(struct work_struct *work); void mt7921_mac_reset_work(struct work_struct *work); +void mt7921_mac_update_mib_stats(struct mt7921_phy *phy); void mt7921_reset(struct mt76_dev *mdev); -void mt7921_tx_cleanup(struct mt7921_dev *dev); -int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, - enum mt76_txq_id qid, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, - struct mt76_tx_info *tx_info); +int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info); void mt7921_tx_worker(struct mt76_worker *w); -void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); +void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc); void mt7921_tx_token_put(struct mt7921_dev *dev); void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); void mt7921_stats_work(struct work_struct *work); -void mt7921_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *txwi); void mt7921_set_stream_he_caps(struct mt7921_phy *phy); void mt7921_update_channel(struct mt76_phy *mphy); int mt7921_init_debugfs(struct mt7921_dev *dev); +int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, + struct ieee80211_vif *vif, + bool enable); int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, struct ieee80211_ampdu_params *params, bool enable); @@ -371,21 +420,47 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, bool enable); void mt7921_scan_work(struct work_struct *work); int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif); -int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, - bool enable); -int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, - bool enable); -int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev); void mt7921_pm_wake_work(struct work_struct *work); void mt7921_pm_power_save_work(struct work_struct *work); bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev); -int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy, - struct ieee80211_vif *vif, - bool enable); -void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); void mt7921_coredump_work(struct work_struct *work); int mt7921_wfsys_reset(struct mt7921_dev *dev); int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr); +int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); +int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, + struct netlink_callback *cb, void *data, int len); +void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, int pid, + bool beacon); +void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi); +void mt7921_mac_sta_poll(struct mt7921_dev *dev); +int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *wait_seq); +int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq); +int mt7921_mcu_restart(struct mt76_dev *dev); + +void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); +int mt7921e_mac_reset(struct mt7921_dev *dev); +int mt7921e_mcu_init(struct mt7921_dev *dev); +int mt7921s_wfsys_reset(struct mt7921_dev *dev); +int mt7921s_mac_reset(struct mt7921_dev *dev); +int mt7921s_init_reset(struct mt7921_dev *dev); +int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev); +int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev); + +int mt7921s_mcu_init(struct mt7921_dev *dev); +int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev); +int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev); +int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info); +void mt7921s_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); +bool mt7921s_tx_status_data(struct mt76_dev *mdev, u8 *update); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index c3905bcab360..305b63fa1a8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -14,9 +14,14 @@ static const struct pci_device_id mt7921_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922) }, { }, }; +static bool mt7921_disable_aspm; +module_param_named(disable_aspm, mt7921_disable_aspm, bool, 0644); +MODULE_PARM_DESC(disable_aspm, "disable PCI ASPM support"); + static void mt7921_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { @@ -88,21 +93,46 @@ static void mt7921_irq_tasklet(unsigned long data) napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]); } +static int mt7921e_init_reset(struct mt7921_dev *dev) +{ + return mt7921_wpdma_reset(dev, true); +} + +static void mt7921e_unregister_device(struct mt7921_dev *dev) +{ + int i; + struct mt76_connac_pm *pm = &dev->pm; + + mt76_unregister_device(&dev->mt76); + mt76_for_each_q_rx(&dev->mt76, i) + napi_disable(&dev->mt76.napi[i]); + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + + mt7921_tx_token_put(dev); + mt7921_mcu_drv_pmctrl(dev); + mt7921_dma_cleanup(dev); + mt7921_wfsys_reset(dev); + mt7921_mcu_exit(dev); + + tasklet_disable(&dev->irq_tasklet); + mt76_free_device(&dev->mt76); +} + static int mt7921_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7921_txp_common), - .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | - MT_DRV_AMSDU_OFFLOAD, + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, .token_size = MT7921_TOKEN_SIZE, - .tx_prepare_skb = mt7921_tx_prepare_skb, - .tx_complete_skb = mt7921_tx_complete_skb, - .rx_skb = mt7921_queue_rx_skb, + .tx_prepare_skb = mt7921e_tx_prepare_skb, + .tx_complete_skb = mt7921e_tx_complete_skb, + .rx_skb = mt7921e_queue_rx_skb, .rx_poll_complete = mt7921_rx_poll_complete, .sta_ps = mt7921_sta_ps, .sta_add = mt7921_mac_sta_add, @@ -110,6 +140,15 @@ static int mt7921_pci_probe(struct pci_dev *pdev, .sta_remove = mt7921_mac_sta_remove, .update_survey = mt7921_update_channel, }; + + static const struct mt7921_hif_ops mt7921_pcie_ops = { + .init_reset = mt7921e_init_reset, + .reset = mt7921e_mac_reset, + .mcu_init = mt7921e_mcu_init, + .drv_own = mt7921e_mcu_drv_pmctrl, + .fw_own = mt7921e_mcu_fw_pmctrl, + }; + struct mt7921_dev *dev; struct mt76_dev *mdev; int ret; @@ -128,11 +167,12 @@ static int mt7921_pci_probe(struct pci_dev *pdev, if (ret < 0) return ret; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) goto err_free_pci_vec; - mt76_pci_disable_aspm(pdev); + if (mt7921_disable_aspm) + mt76_pci_disable_aspm(pdev); mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7921_ops, &drv_ops); @@ -142,6 +182,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, } dev = container_of(mdev, struct mt7921_dev, mt76); + dev->hif_ops = &mt7921_pcie_ops; mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev); @@ -158,6 +199,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev, if (ret) goto err_free_dev; + ret = mt7921_dma_init(dev); + if (ret) + goto err_free_irq; + ret = mt7921_register_device(dev); if (ret) goto err_free_irq; @@ -179,7 +224,7 @@ static void mt7921_pci_remove(struct pci_dev *pdev) struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); - mt7921_unregister_device(dev); + mt7921e_unregister_device(dev); devm_free_irq(&pdev->dev, pdev->irq, dev); pci_free_irq_vectors(pdev); } @@ -297,12 +342,15 @@ static int mt7921_pci_resume(struct pci_dev *pdev) MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); mt76_worker_enable(&mdev->tx_worker); + + local_bh_disable(); mt76_for_each_q_rx(mdev, i) { napi_enable(&mdev->napi[i]); napi_schedule(&mdev->napi[i]); } napi_enable(&mdev->tx_napi); napi_schedule(&mdev->tx_napi); + local_bh_enable(); /* restore previous ds setting */ if (!pm->ds_enable) @@ -331,6 +379,8 @@ module_pci_driver(mt7921_pci_driver); MODULE_DEVICE_TABLE(pci, mt7921_pci_device_table); MODULE_FIRMWARE(MT7921_FIRMWARE_WM); MODULE_FIRMWARE(MT7921_ROM_PATCH); +MODULE_FIRMWARE(MT7922_FIRMWARE_WM); +MODULE_FIRMWARE(MT7922_ROM_PATCH); MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c new file mode 100644 index 000000000000..f9547d27356e --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. */ + +#include "mt7921.h" +#include "../dma.h" +#include "mac.h" + +static void +mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info, + void *txp_ptr, u32 id) +{ + struct mt7921_hw_txp *txp = txp_ptr; + struct mt7921_txp_ptr *ptr = &txp->ptr[0]; + int i, nbuf = tx_info->nbuf - 1; + + tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); + tx_info->nbuf = 1; + + txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); + + for (i = 0; i < nbuf; i++) { + u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; + u32 addr = tx_info->buf[i + 1].addr; + + if (i == nbuf - 1) + len |= MT_TXD_LEN_LAST; + + if (i & 1) { + ptr->buf1 = cpu_to_le32(addr); + ptr->len1 = cpu_to_le16(len); + ptr++; + } else { + ptr->buf0 = cpu_to_le32(addr); + ptr->len0 = cpu_to_le16(len); + } + } +} + +int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + struct mt76_txwi_cache *t; + struct mt7921_txp_common *txp; + int id, pid; + u8 *txwi = (u8 *)txwi_ptr; + + if (unlikely(tx_info->skb->len <= ETH_HLEN)) + return -EINVAL; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + + id = mt76_token_consume(mdev, &t); + if (id < 0) + return id; + + if (sta) { + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + + if (time_after(jiffies, msta->last_txs + HZ / 4)) { + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + msta->last_txs = jiffies; + } + } + + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); + mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, + pid, false); + + txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); + memset(txp, 0, sizeof(struct mt7921_txp_common)); + mt7921_write_hw_txp(dev, tx_info, txp, id); + + tx_info->skb = DMA_DUMMY_DATA; + + return 0; +} + +static void +mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) +{ + struct mt7921_txp_common *txp; + int i; + + txp = mt7921_txwi_to_txp(dev, t); + + for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) { + struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i]; + bool last; + u16 len; + + len = le16_to_cpu(ptr->len0); + last = len & MT_TXD_LEN_LAST; + len &= MT_TXD_LEN_MASK; + dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, + DMA_TO_DEVICE); + if (last) + break; + + len = le16_to_cpu(ptr->len1); + last = len & MT_TXD_LEN_LAST; + len &= MT_TXD_LEN_MASK; + dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, + DMA_TO_DEVICE); + if (last) + break; + } +} + +static void +mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t, + struct ieee80211_sta *sta, bool clear_status, + struct list_head *free_list) +{ + struct mt76_dev *mdev = &dev->mt76; + __le32 *txwi; + u16 wcid_idx; + + mt7921_txp_skb_unmap(mdev, t); + if (!t->skb) + goto out; + + txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); + if (sta) { + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + + if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7921_tx_check_aggr(sta, txwi); + + wcid_idx = wcid->idx; + } else { + wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1])); + } + + __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); + +out: + t->skb = NULL; + mt76_put_txwi(mdev, t); +} + +static void +mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_tx_free *free = (struct mt7921_tx_free *)skb->data; + struct mt76_dev *mdev = &dev->mt76; + struct mt76_txwi_cache *txwi; + struct ieee80211_sta *sta = NULL; + LIST_HEAD(free_list); + struct sk_buff *tmp; + bool wake = false; + u8 i, count; + + /* clean DMA queues and unmap buffers first */ + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false); + + /* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE, + * to the time ack is received or dropped by hw (air + hw queue time). + * Should avoid accessing WTBL to get Tx airtime, and use it instead. + */ + count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl)); + for (i = 0; i < count; i++) { + u32 msdu, info = le32_to_cpu(free->info[i]); + u8 stat; + + /* 1'b1: new wcid pair. + * 1'b0: msdu_id with the same 'wcid pair' as above. + */ + if (info & MT_TX_FREE_PAIR) { + struct mt7921_sta *msta; + struct mt76_wcid *wcid; + u16 idx; + + count++; + idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info); + wcid = rcu_dereference(dev->mt76.wcid[idx]); + sta = wcid_to_sta(wcid); + if (!sta) + continue; + + msta = container_of(wcid, struct mt7921_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + continue; + } + + msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); + stat = FIELD_GET(MT_TX_FREE_STATUS, info); + + txwi = mt76_token_release(mdev, msdu, &wake); + if (!txwi) + continue; + + mt7921_txwi_free(dev, txwi, sta, stat, &free_list); + } + + if (wake) + mt76_set_tx_blocked(&dev->mt76, false); + + napi_consume_skb(skb, 1); + + list_for_each_entry_safe(skb, tmp, &free_list, list) { + skb_list_del_init(skb); + napi_consume_skb(skb, 1); + } + + rcu_read_lock(); + mt7921_mac_sta_poll(dev); + rcu_read_unlock(); + + mt76_worker_schedule(&dev->mt76.tx_worker); +} + +void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + enum rx_pkt_type type; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + mt7921_mac_tx_free(dev, skb); + break; + default: + mt7921_queue_rx_skb(mdev, q, skb); + break; + } +} + +void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) +{ + if (!e->txwi) { + dev_kfree_skb_any(e->skb); + return; + } + + /* error path */ + if (e->skb == DMA_DUMMY_DATA) { + struct mt76_txwi_cache *t; + struct mt7921_txp_common *txp; + u16 token; + + txp = mt7921_txwi_to_txp(mdev, e->txwi); + token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID; + t = mt76_token_put(mdev, token); + e->skb = t ? t->skb : NULL; + } + + if (e->skb) + mt76_tx_complete_skb(mdev, e->wcid, e->skb); +} + +void mt7921_tx_token_put(struct mt7921_dev *dev) +{ + struct mt76_txwi_cache *txwi; + int id; + + spin_lock_bh(&dev->mt76.token_lock); + idr_for_each_entry(&dev->mt76.token, txwi, id) { + mt7921_txwi_free(dev, txwi, NULL, false, NULL); + dev->mt76.token_count--; + } + spin_unlock_bh(&dev->mt76.token_lock); + idr_destroy(&dev->mt76.token); +} + +int mt7921e_mac_reset(struct mt7921_dev *dev) +{ + int i, err; + + mt7921e_mcu_drv_pmctrl(dev); + + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + + set_bit(MT76_RESET, &dev->mphy.state); + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + skb_queue_purge(&dev->mt76.mcu.res_q); + + mt76_txq_schedule_all(&dev->mphy); + + mt76_worker_disable(&dev->mt76.tx_worker); + napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]); + napi_disable(&dev->mt76.napi[MT_RXQ_MCU]); + napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]); + napi_disable(&dev->mt76.tx_napi); + + mt7921_tx_token_put(dev); + idr_init(&dev->mt76.token); + + mt7921_wpdma_reset(dev, true); + + local_bh_disable(); + mt76_for_each_q_rx(&dev->mt76, i) { + napi_enable(&dev->mt76.napi[i]); + napi_schedule(&dev->mt76.napi[i]); + } + local_bh_enable(); + + clear_bit(MT76_MCU_RESET, &dev->mphy.state); + + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, + MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_MCU_CMD); + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + + err = mt7921_run_firmware(dev); + if (err) + goto out; + + err = mt7921_mcu_set_eeprom(dev); + if (err) + goto out; + + err = mt7921_mac_init(dev); + if (err) + goto out; + + err = __mt7921_start(&dev->phy); +out: + clear_bit(MT76_RESET, &dev->mphy.state); + + local_bh_disable(); + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); + local_bh_enable(); + + mt76_worker_enable(&dev->mt76.tx_worker); + + return err; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c new file mode 100644 index 000000000000..583a89a34734 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. */ + +#include "mt7921.h" +#include "mcu.h" + +static int mt7921e_driver_own(struct mt7921_dev *dev) +{ + u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + + mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); + if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, + 0, 500)) { + dev_err(dev->mt76.dev, "Timeout for driver own\n"); + return -EIO; + } + + return 0; +} + +static int +mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *seq) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + enum mt76_mcuq_id txq = MT_MCUQ_WM; + int ret; + + ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); + if (ret) + return ret; + + if (cmd == MCU_CMD_FW_SCATTER) + txq = MT_MCUQ_FWDL; + + return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); +} + +int mt7921e_mcu_init(struct mt7921_dev *dev) +{ + static const struct mt76_mcu_ops mt7921_mcu_ops = { + .headroom = sizeof(struct mt7921_mcu_txd), + .mcu_skb_send_msg = mt7921_mcu_send_message, + .mcu_parse_response = mt7921_mcu_parse_response, + .mcu_restart = mt7921_mcu_restart, + }; + int err; + + dev->mt76.mcu_ops = &mt7921_mcu_ops; + + err = mt7921e_driver_own(dev); + if (err) + return err; + + err = mt7921_run_firmware(dev); + + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); + + return err; +} + +int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int i, err = 0; + + for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { + mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); + if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, + PCIE_LPCR_HOST_OWN_SYNC, 0, 50)) + break; + } + + if (i == MT7921_DRV_OWN_RETRY_COUNT) { + dev_err(dev->mt76.dev, "driver own failed\n"); + err = -EIO; + goto out; + } + + mt7921_wpdma_reinit_cond(dev); + clear_bit(MT76_STATE_PM, &mphy->state); + + pm->stats.last_wake_event = jiffies; + pm->stats.doze_time += pm->stats.last_wake_event - + pm->stats.last_doze_event; +out: + return err; +} + +int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int i, err = 0; + + for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { + mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); + if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, + PCIE_LPCR_HOST_OWN_SYNC, 4, 50)) + break; + } + + if (i == MT7921_DRV_OWN_RETRY_COUNT) { + dev_err(dev->mt76.dev, "firmware own failed\n"); + clear_bit(MT76_STATE_PM, &mphy->state); + err = -EIO; + } + + pm->stats.last_doze_event = jiffies; + pm->stats.awake_time += pm->stats.last_doze_event - + pm->stats.last_wake_event; + + return err; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h index b6944c867a57..cbd38122c510 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h @@ -14,7 +14,7 @@ #define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2) #define MT_MCU_INT_EVENT_RESET_DONE BIT(3) -#define MT_PLE_BASE 0x8000 +#define MT_PLE_BASE 0x820c0000 #define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) #define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) @@ -26,7 +26,7 @@ ((n) << 2)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) -#define MT_MDP_BASE 0xf000 +#define MT_MDP_BASE 0x820cd000 #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) #define MT_MDP_DCR0 MT_MDP(0x000) @@ -49,7 +49,7 @@ #define MT_MDP_TO_WM 1 /* TMAC: band 0(0x21000), band 1(0xa1000) */ -#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000) +#define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000) #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) #define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0) @@ -74,7 +74,7 @@ #define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c) #define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0) -#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00) +#define MT_WF_DMA_BASE(_band) ((_band) ? 0x820f7000 : 0x820e7000) #define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs)) #define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000) @@ -82,7 +82,7 @@ #define MT_DMA_DCR0_RXD_G5_EN BIT(23) /* LPON: band 0(0x24200), band 1(0xa4200) */ -#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200) +#define MT_WF_LPON_BASE(_band) ((_band) ? 0x820fb000 : 0x820eb000) #define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs)) #define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080) @@ -92,25 +92,57 @@ #define MT_LPON_TCR_SW_MODE GENMASK(1, 0) #define MT_LPON_TCR_SW_WRITE BIT(0) +/* ETBF: band 0(0x24000), band 1(0xa4000) */ +#define MT_WF_ETBF_BASE(_band) ((_band) ? 0x820fa000 : 0x820ea000) +#define MT_WF_ETBF(_band, ofs) (MT_WF_ETBF_BASE(_band) + (ofs)) + +#define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x150) +#define MT_ETBF_TX_IBF_CNT GENMASK(31, 16) +#define MT_ETBF_TX_EBF_CNT GENMASK(15, 0) + +#define MT_ETBF_RX_FB_CNT(_band) MT_WF_ETBF(_band, 0x158) +#define MT_ETBF_RX_FB_ALL GENMASK(31, 24) +#define MT_ETBF_RX_FB_HE GENMASK(23, 16) +#define MT_ETBF_RX_FB_VHT GENMASK(15, 8) +#define MT_ETBF_RX_FB_HT GENMASK(7, 0) + /* MIB: band 0(0x24800), band 1(0xa4800) */ -#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) +#define MT_WF_MIB_BASE(_band) ((_band) ? 0x820fd000 : 0x820ed000) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) +#define MT_MIB_SCR1(_band) MT_WF_MIB(_band, 0x004) +#define MT_MIB_TXDUR_EN BIT(8) +#define MT_MIB_RXDUR_EN BIT(9) + #define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x698) #define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(31, 16) +#define MT_MIB_SDR5(_band) MT_WF_MIB(_band, 0x780) + #define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) #define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR12(_band) MT_WF_MIB(_band, 0x558) +#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x564) +#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x568) + #define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) #define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR22(_band) MT_WF_MIB(_band, 0x770) +#define MT_MIB_SDR23(_band) MT_WF_MIB(_band, 0x774) +#define MT_MIB_SDR31(_band) MT_WF_MIB(_band, 0x55c) + +#define MT_MIB_SDR32(_band) MT_WF_MIB(_band, 0x7a8) +#define MT_MIB_SDR9_IBF_CNT_MASK GENMASK(31, 16) +#define MT_MIB_SDR9_EBF_CNT_MASK GENMASK(15, 0) + #define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090) #define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0) -#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) +#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x054) #define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) +#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x058) #define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) #define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0) @@ -138,7 +170,7 @@ #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2)) #define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0)) -#define MT_WTBLON_TOP_BASE 0x34000 +#define MT_WTBLON_TOP_BASE 0x820d4000 #define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) #define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x200) #define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0) @@ -148,7 +180,7 @@ #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) #define MT_WTBL_UPDATE_BUSY BIT(31) -#define MT_WTBL_BASE 0x38000 +#define MT_WTBL_BASE 0x820d8000 #define MT_WTBL_LMAC_ID GENMASK(14, 8) #define MT_WTBL_LMAC_DW GENMASK(7, 2) #define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \ @@ -156,7 +188,7 @@ FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) /* AGG: band 0(0x20800), band 1(0xa0800) */ -#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800) +#define MT_WF_AGG_BASE(_band) ((_band) ? 0x820f2000 : 0x820e2000) #define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs)) #define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4) @@ -187,7 +219,7 @@ #define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4) /* ARB: band 0(0x20c00), band 1(0xa0c00) */ -#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00) +#define MT_WF_ARB_BASE(_band) ((_band) ? 0x820f3000 : 0x820e3000) #define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs)) #define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080) @@ -197,7 +229,7 @@ #define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4) /* RMAC: band 0(0x21400), band 1(0xa1400) */ -#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400) +#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000) #define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs)) #define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c new file mode 100644 index 000000000000..ddf0eeb8b688 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. + * + */ + +#include <linux/kernel.h> +#include <linux/iopoll.h> +#include <linux/module.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio_func.h> + +#include "mt7921.h" +#include "../sdio.h" +#include "mac.h" +#include "mcu.h" + +static const struct sdio_device_id mt7921s_table[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) }, + { } /* Terminating entry */ +}; + +static void mt7921s_txrx_worker(struct mt76_worker *w) +{ + struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, + txrx_worker); + struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio); + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + + if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { + queue_work(mdev->wq, &dev->pm.wake_work); + return; + } + + mt76s_txrx_worker(sdio); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); +} + +static void mt7921s_unregister_device(struct mt7921_dev *dev) +{ + struct mt76_connac_pm *pm = &dev->pm; + + mt76_unregister_device(&dev->mt76); + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + + mt76s_deinit(&dev->mt76); + mt7921s_wfsys_reset(dev); + mt7921_mcu_exit(dev); + + mt76_free_device(&dev->mt76); +} + +static int mt7921s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr) +{ + struct mt76_sdio *sdio = &dev->sdio; + struct mt7921_sdio_intr *irq_data = sdio->intr_data; + int i, err; + + err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data)); + if (err < 0) + return err; + + intr->isr = irq_data->isr; + intr->rec_mb = irq_data->rec_mb; + intr->tx.wtqcr = irq_data->tx.wtqcr; + intr->rx.num = irq_data->rx.num; + for (i = 0; i < 2 ; i++) { + if (!i) + intr->rx.len[0] = irq_data->rx.len0; + else + intr->rx.len[1] = irq_data->rx.len1; + } + + return 0; +} + +static int mt7921s_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + static const struct mt76_driver_ops drv_ops = { + .txwi_size = MT_SDIO_TXD_SIZE, + .survey_flags = SURVEY_INFO_TIME_TX | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_BSS_RX, + .tx_prepare_skb = mt7921s_tx_prepare_skb, + .tx_complete_skb = mt7921s_tx_complete_skb, + .tx_status_data = mt7921s_tx_status_data, + .rx_skb = mt7921_queue_rx_skb, + .sta_ps = mt7921_sta_ps, + .sta_add = mt7921_mac_sta_add, + .sta_assoc = mt7921_mac_sta_assoc, + .sta_remove = mt7921_mac_sta_remove, + .update_survey = mt7921_update_channel, + }; + static const struct mt76_bus_ops mt7921s_ops = { + .rr = mt76s_rr, + .rmw = mt76s_rmw, + .wr = mt76s_wr, + .write_copy = mt76s_write_copy, + .read_copy = mt76s_read_copy, + .wr_rp = mt76s_wr_rp, + .rd_rp = mt76s_rd_rp, + .type = MT76_BUS_SDIO, + }; + static const struct mt7921_hif_ops mt7921_sdio_ops = { + .init_reset = mt7921s_init_reset, + .reset = mt7921s_mac_reset, + .mcu_init = mt7921s_mcu_init, + .drv_own = mt7921s_mcu_drv_pmctrl, + .fw_own = mt7921s_mcu_fw_pmctrl, + }; + + struct mt7921_dev *dev; + struct mt76_dev *mdev; + int ret, i; + + mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops, + &drv_ops); + if (!mdev) + return -ENOMEM; + + dev = container_of(mdev, struct mt7921_dev, mt76); + dev->hif_ops = &mt7921_sdio_ops; + + sdio_set_drvdata(func, dev); + + ret = mt76s_init(mdev, func, &mt7921s_ops); + if (ret < 0) + goto error; + + ret = mt76s_hw_init(mdev, func, MT76_CONNAC2_SDIO); + if (ret) + goto error; + + mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | + (mt76_rr(dev, MT_HW_REV) & 0xff); + dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + mdev->sdio.parse_irq = mt7921s_parse_intr; + mdev->sdio.intr_data = devm_kmalloc(mdev->dev, + sizeof(struct mt7921_sdio_intr), + GFP_KERNEL); + if (!mdev->sdio.intr_data) { + ret = -ENOMEM; + goto error; + } + + for (i = 0; i < ARRAY_SIZE(mdev->sdio.xmit_buf); i++) { + mdev->sdio.xmit_buf[i] = devm_kmalloc(mdev->dev, + MT76S_XMIT_BUF_SZ, + GFP_KERNEL); + if (!mdev->sdio.xmit_buf[i]) { + ret = -ENOMEM; + goto error; + } + } + + ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN); + if (ret) + goto error; + + ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MCU); + if (ret) + goto error; + + ret = mt76s_alloc_tx(mdev); + if (ret) + goto error; + + ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker, + mt7921s_txrx_worker, "sdio-txrx"); + if (ret) + goto error; + + sched_set_fifo_low(mdev->sdio.txrx_worker.task); + + ret = mt7921_register_device(dev); + if (ret) + goto error; + + return 0; + +error: + mt76s_deinit(&dev->mt76); + mt76_free_device(&dev->mt76); + + return ret; +} + +static void mt7921s_remove(struct sdio_func *func) +{ + struct mt7921_dev *dev = sdio_get_drvdata(func); + + mt7921s_unregister_device(dev); +} + +#ifdef CONFIG_PM +static int mt7921s_suspend(struct device *__dev) +{ + struct sdio_func *func = dev_to_sdio_func(__dev); + struct mt7921_dev *dev = sdio_get_drvdata(func); + struct mt76_connac_pm *pm = &dev->pm; + struct mt76_dev *mdev = &dev->mt76; + bool hif_suspend; + int err; + + pm->suspended = true; + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + + err = mt7921_mcu_drv_pmctrl(dev); + if (err < 0) + goto restore_suspend; + + hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state); + if (hif_suspend) { + err = mt76_connac_mcu_set_hif_suspend(mdev, true); + if (err) + goto restore_suspend; + } + + /* always enable deep sleep during suspend to reduce + * power consumption + */ + mt76_connac_mcu_set_deep_sleep(mdev, true); + + mt76_txq_schedule_all(&dev->mphy); + mt76_worker_disable(&mdev->tx_worker); + mt76_worker_disable(&mdev->sdio.txrx_worker); + mt76_worker_disable(&mdev->sdio.status_worker); + mt76_worker_disable(&mdev->sdio.net_worker); + cancel_work_sync(&mdev->sdio.stat_work); + clear_bit(MT76_READING_STATS, &dev->mphy.state); + + mt76_tx_status_check(mdev, true); + + err = mt7921_mcu_fw_pmctrl(dev); + if (err) + goto restore_worker; + + sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + + return 0; + +restore_worker: + mt76_worker_enable(&mdev->tx_worker); + mt76_worker_enable(&mdev->sdio.txrx_worker); + mt76_worker_enable(&mdev->sdio.status_worker); + mt76_worker_enable(&mdev->sdio.net_worker); + + if (!pm->ds_enable) + mt76_connac_mcu_set_deep_sleep(mdev, false); + + if (hif_suspend) + mt76_connac_mcu_set_hif_suspend(mdev, false); + +restore_suspend: + pm->suspended = false; + + return err; +} + +static int mt7921s_resume(struct device *__dev) +{ + struct sdio_func *func = dev_to_sdio_func(__dev); + struct mt7921_dev *dev = sdio_get_drvdata(func); + struct mt76_connac_pm *pm = &dev->pm; + struct mt76_dev *mdev = &dev->mt76; + int err; + + pm->suspended = false; + + err = mt7921_mcu_drv_pmctrl(dev); + if (err < 0) + return err; + + mt76_worker_enable(&mdev->tx_worker); + mt76_worker_enable(&mdev->sdio.txrx_worker); + mt76_worker_enable(&mdev->sdio.status_worker); + mt76_worker_enable(&mdev->sdio.net_worker); + + /* restore previous ds setting */ + if (!pm->ds_enable) + mt76_connac_mcu_set_deep_sleep(mdev, false); + + if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state)) + err = mt76_connac_mcu_set_hif_suspend(mdev, false); + + return err; +} + +static const struct dev_pm_ops mt7921s_pm_ops = { + .suspend = mt7921s_suspend, + .resume = mt7921s_resume, +}; +#endif + +MODULE_DEVICE_TABLE(sdio, mt7921s_table); +MODULE_FIRMWARE(MT7921_FIRMWARE_WM); +MODULE_FIRMWARE(MT7921_ROM_PATCH); + +static struct sdio_driver mt7921s_driver = { + .name = KBUILD_MODNAME, + .probe = mt7921s_probe, + .remove = mt7921s_remove, + .id_table = mt7921s_table, +#ifdef CONFIG_PM + .drv = { + .pm = &mt7921s_pm_ops, + } +#endif +}; +module_sdio_driver(mt7921s_driver); +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c new file mode 100644 index 000000000000..137f86a6dbf8 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. */ + +#include <linux/iopoll.h> +#include <linux/mmc/sdio_func.h> +#include "mt7921.h" +#include "mac.h" +#include "../sdio.h" + +static void mt7921s_enable_irq(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + + sdio_claim_host(sdio->func); + sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL); + sdio_release_host(sdio->func); +} + +static void mt7921s_disable_irq(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + + sdio_claim_host(sdio->func); + sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); + sdio_release_host(sdio->func); +} + +static u32 mt7921s_read_whcr(struct mt76_dev *dev) +{ + return sdio_readl(dev->sdio.func, MCR_WHCR, NULL); +} + +int mt7921s_wfsys_reset(struct mt7921_dev *dev) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + u32 val, status; + + mt7921s_mcu_drv_pmctrl(dev); + + sdio_claim_host(sdio->func); + + val = sdio_readl(sdio->func, MCR_WHCR, NULL); + val &= ~WF_WHOLE_PATH_RSTB; + sdio_writel(sdio->func, val, MCR_WHCR, NULL); + + msleep(50); + + val = sdio_readl(sdio->func, MCR_WHCR, NULL); + val &= ~WF_SDIO_WF_PATH_RSTB; + sdio_writel(sdio->func, val, MCR_WHCR, NULL); + + usleep_range(1000, 2000); + + val = sdio_readl(sdio->func, MCR_WHCR, NULL); + val |= WF_WHOLE_PATH_RSTB; + sdio_writel(sdio->func, val, MCR_WHCR, NULL); + + readx_poll_timeout(mt7921s_read_whcr, &dev->mt76, status, + status & WF_RST_DONE, 50000, 2000000); + + sdio_release_host(sdio->func); + + /* activate mt7921s again */ + mt7921s_mcu_fw_pmctrl(dev); + mt7921s_mcu_drv_pmctrl(dev); + + return 0; +} + +int mt7921s_init_reset(struct mt7921_dev *dev) +{ + set_bit(MT76_MCU_RESET, &dev->mphy.state); + + wake_up(&dev->mt76.mcu.wait); + skb_queue_purge(&dev->mt76.mcu.res_q); + wait_event_timeout(dev->mt76.sdio.wait, + mt76s_txqs_empty(&dev->mt76), 5 * HZ); + mt76_worker_disable(&dev->mt76.sdio.txrx_worker); + + mt7921s_disable_irq(&dev->mt76); + mt7921s_wfsys_reset(dev); + + mt76_worker_enable(&dev->mt76.sdio.txrx_worker); + clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + clear_bit(MT76_MCU_RESET, &dev->mphy.state); + mt7921s_enable_irq(&dev->mt76); + + return 0; +} + +int mt7921s_mac_reset(struct mt7921_dev *dev) +{ + int err; + + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + mt76_txq_schedule_all(&dev->mphy); + mt76_worker_disable(&dev->mt76.tx_worker); + set_bit(MT76_RESET, &dev->mphy.state); + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + skb_queue_purge(&dev->mt76.mcu.res_q); + wait_event_timeout(dev->mt76.sdio.wait, + mt76s_txqs_empty(&dev->mt76), 5 * HZ); + mt76_worker_disable(&dev->mt76.sdio.txrx_worker); + mt76_worker_disable(&dev->mt76.sdio.status_worker); + mt76_worker_disable(&dev->mt76.sdio.net_worker); + cancel_work_sync(&dev->mt76.sdio.stat_work); + + mt7921s_disable_irq(&dev->mt76); + mt7921s_wfsys_reset(dev); + + mt76_worker_enable(&dev->mt76.sdio.txrx_worker); + mt76_worker_enable(&dev->mt76.sdio.status_worker); + mt76_worker_enable(&dev->mt76.sdio.net_worker); + + dev->fw_assert = false; + clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + clear_bit(MT76_MCU_RESET, &dev->mphy.state); + mt7921s_enable_irq(&dev->mt76); + + err = mt7921_run_firmware(dev); + if (err) + goto out; + + err = mt7921_mcu_set_eeprom(dev); + if (err) + goto out; + + err = mt7921_mac_init(dev); + if (err) + goto out; + + err = __mt7921_start(&dev->phy); +out: + clear_bit(MT76_RESET, &dev->mphy.state); + + mt76_worker_enable(&dev->mt76.tx_worker); + + return err; +} + +static void +mt7921s_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid, + enum mt76_txq_id qid, struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *key = info->control.hw_key; + __le32 *txwi; + int pid; + + pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); + memset(txwi, 0, MT_SDIO_TXD_SIZE); + mt7921_mac_write_txwi(dev, txwi, skb, wcid, key, pid, false); + skb_push(skb, MT_SDIO_TXD_SIZE); +} + +int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct sk_buff *skb = tx_info->skb; + int pad; + + if (unlikely(tx_info->skb->len <= ETH_HLEN)) + return -EINVAL; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + if (sta) { + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + + if (time_after(jiffies, msta->last_txs + HZ / 4)) { + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + msta->last_txs = jiffies; + } + } + + mt7921s_write_txwi(dev, wcid, qid, sta, skb); + + mt7921_skb_add_sdio_hdr(skb, MT7921_SDIO_DATA); + pad = round_up(skb->len, 4) - skb->len; + + return mt76_skb_adjust_pad(skb, pad); +} + +void mt7921s_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) +{ + __le32 *txwi = (__le32 *)(e->skb->data + MT_SDIO_HDR_SIZE); + unsigned int headroom = MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE; + struct ieee80211_sta *sta; + struct mt76_wcid *wcid; + u16 idx; + + idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1])); + wcid = rcu_dereference(mdev->wcid[idx]); + sta = wcid_to_sta(wcid); + + if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7921_tx_check_aggr(sta, txwi); + + skb_pull(e->skb, headroom); + mt76_tx_complete_skb(mdev, e->wcid, e->skb); +} + +bool mt7921s_tx_status_data(struct mt76_dev *mdev, u8 *update) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + + mt7921_mutex_acquire(dev); + mt7921_mac_sta_poll(dev); + mt7921_mutex_release(dev); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c new file mode 100644 index 000000000000..437cddad9a90 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. */ + +#include <linux/kernel.h> +#include <linux/mmc/sdio_func.h> +#include <linux/module.h> +#include <linux/iopoll.h> + +#include "mt7921.h" +#include "../sdio.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" + +static int +mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *seq) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD; + enum mt76_mcuq_id txq = MT_MCUQ_WM; + int ret, pad; + + /* We just return in case firmware assertion to avoid blocking the + * common workqueue to run, for example, the coredump work might be + * blocked by mt7921_mac_work that is excuting register access via sdio + * bus. + */ + if (dev->fw_assert) + return -EBUSY; + + ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); + if (ret) + return ret; + + if (cmd == MCU_CMD_FW_SCATTER) + type = MT7921_SDIO_FWDL; + + mt7921_skb_add_sdio_hdr(skb, type); + pad = round_up(skb->len, 4) - skb->len; + __skb_put_zero(skb, pad); + + ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); + if (ret) + return ret; + + mt76_queue_kick(dev, mdev->q_mcu[txq]); + + return ret; +} + +int mt7921s_mcu_init(struct mt7921_dev *dev) +{ + static const struct mt76_mcu_ops mt7921s_mcu_ops = { + .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd), + .tailroom = MT_SDIO_TAIL_SIZE, + .mcu_skb_send_msg = mt7921s_mcu_send_message, + .mcu_parse_response = mt7921_mcu_parse_response, + .mcu_rr = mt76_connac_mcu_reg_rr, + .mcu_wr = mt76_connac_mcu_reg_wr, + }; + int ret; + + mt7921s_mcu_drv_pmctrl(dev); + + dev->mt76.mcu_ops = &mt7921s_mcu_ops; + + ret = mt7921_run_firmware(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} + +int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev) +{ + struct sdio_func *func = dev->mt76.sdio.func; + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int err = 0; + u32 status; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); + + err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, + status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); + sdio_release_host(func); + + if (err < 0) { + dev_err(dev->mt76.dev, "driver own failed\n"); + err = -EIO; + goto out; + } + + clear_bit(MT76_STATE_PM, &mphy->state); + + pm->stats.last_wake_event = jiffies; + pm->stats.doze_time += pm->stats.last_wake_event - + pm->stats.last_doze_event; +out: + return err; +} + +int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) +{ + struct sdio_func *func = dev->mt76.sdio.func; + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int err = 0; + u32 status; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); + + err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, + !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); + sdio_release_host(func); + + if (err < 0) { + dev_err(dev->mt76.dev, "firmware own failed\n"); + clear_bit(MT76_STATE_PM, &mphy->state); + err = -EIO; + } + + pm->stats.last_doze_event = jiffies; + pm->stats.awake_time += pm->stats.last_doze_event - + pm->stats.last_wake_event; + + return err; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c new file mode 100644 index 000000000000..8bd43879dd6f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: ISC + +#include "mt7921.h" +#include "mcu.h" + +enum mt7921_testmode_attr { + MT7921_TM_ATTR_UNSPEC, + MT7921_TM_ATTR_SET, + MT7921_TM_ATTR_QUERY, + MT7921_TM_ATTR_RSP, + + /* keep last */ + NUM_MT7921_TM_ATTRS, + MT7921_TM_ATTR_MAX = NUM_MT7921_TM_ATTRS - 1, +}; + +struct mt7921_tm_cmd { + u8 action; + u32 param0; + u32 param1; +}; + +struct mt7921_tm_evt { + u32 param0; + u32 param1; +}; + +static const struct nla_policy mt7921_tm_policy[NUM_MT7921_TM_ATTRS] = { + [MT7921_TM_ATTR_SET] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)), + [MT7921_TM_ATTR_QUERY] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)), +}; + +static int +mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req) +{ + struct mt7921_rftest_cmd cmd = { + .action = req->action, + .param0 = cpu_to_le32(req->param0), + .param1 = cpu_to_le32(req->param1), + }; + bool testmode = false, normal = false; + struct mt76_connac_pm *pm = &dev->pm; + struct mt76_phy *phy = &dev->mphy; + int ret = -ENOTCONN; + + mutex_lock(&dev->mt76.mutex); + + if (req->action == TM_SWITCH_MODE) { + if (req->param0 == MT7921_TM_NORMAL) + normal = true; + else + testmode = true; + } + + if (testmode) { + /* Make sure testmode running on full power mode */ + pm->enable = false; + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + __mt7921_mcu_drv_pmctrl(dev); + + mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter); + phy->test.state = MT76_TM_STATE_ON; + } + + if (!mt76_testmode_enabled(phy)) + goto out; + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_TEST_CTRL, &cmd, + sizeof(cmd), false); + if (ret) + goto out; + + if (normal) { + /* Switch back to the normal world */ + phy->test.state = MT76_TM_STATE_OFF; + pm->enable = true; + } +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static int +mt7921_tm_query(struct mt7921_dev *dev, struct mt7921_tm_cmd *req, + struct mt7921_tm_evt *evt_resp) +{ + struct mt7921_rftest_cmd cmd = { + .action = req->action, + .param0 = cpu_to_le32(req->param0), + .param1 = cpu_to_le32(req->param1), + }; + struct mt7921_rftest_evt *evt; + struct sk_buff *skb; + int ret; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_TEST_CTRL, + &cmd, sizeof(cmd), true, &skb); + if (ret) + goto out; + + evt = (struct mt7921_rftest_evt *)skb->data; + evt_resp->param0 = le32_to_cpu(evt->param0); + evt_resp->param1 = le32_to_cpu(evt->param1); +out: + dev_kfree_skb(skb); + + return ret; +} + +int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len) +{ + struct nlattr *tb[NUM_MT76_TM_ATTRS]; + struct mt76_phy *mphy = hw->priv; + struct mt7921_phy *phy = mphy->priv; + int err; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state) || + !(hw->conf.flags & IEEE80211_CONF_MONITOR)) + return -ENOTCONN; + + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + + if (tb[MT76_TM_ATTR_DRV_DATA]) { + struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data; + int ret; + + data = tb[MT76_TM_ATTR_DRV_DATA]; + ret = nla_parse_nested_deprecated(drv_tb, + MT7921_TM_ATTR_MAX, + data, mt7921_tm_policy, + NULL); + if (ret) + return ret; + + data = drv_tb[MT7921_TM_ATTR_SET]; + if (data) + return mt7921_tm_set(phy->dev, nla_data(data)); + } + + return -EINVAL; +} + +int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, + struct netlink_callback *cb, void *data, int len) +{ + struct nlattr *tb[NUM_MT76_TM_ATTRS]; + struct mt76_phy *mphy = hw->priv; + struct mt7921_phy *phy = mphy->priv; + int err; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state) || + !(hw->conf.flags & IEEE80211_CONF_MONITOR) || + !mt76_testmode_enabled(mphy)) + return -ENOTCONN; + + if (cb->args[2]++ > 0) + return -ENOENT; + + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + + if (tb[MT76_TM_ATTR_DRV_DATA]) { + struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data; + int ret; + + data = tb[MT76_TM_ATTR_DRV_DATA]; + ret = nla_parse_nested_deprecated(drv_tb, + MT7921_TM_ATTR_MAX, + data, mt7921_tm_policy, + NULL); + if (ret) + return ret; + + data = drv_tb[MT7921_TM_ATTR_QUERY]; + if (data) { + struct mt7921_tm_evt evt_resp; + + err = mt7921_tm_query(phy->dev, nla_data(data), + &evt_resp); + if (err) + return err; + + return nla_put(msg, MT7921_TM_ATTR_RSP, + sizeof(evt_resp), &evt_resp); + } + } + + return -EINVAL; +} diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 783a15635ec5..c99acc21225e 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -16,9 +16,290 @@ #include <linux/kthread.h> #include "mt76.h" +#include "sdio.h" -static int -mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) +static u32 mt76s_read_whisr(struct mt76_dev *dev) +{ + return sdio_readl(dev->sdio.func, MCR_WHISR, NULL); +} + +u32 mt76s_read_pcr(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + + return sdio_readl(sdio->func, MCR_WHLPCR, NULL); +} +EXPORT_SYMBOL_GPL(mt76s_read_pcr); + +static u32 mt76s_read_mailbox(struct mt76_dev *dev, u32 offset) +{ + struct sdio_func *func = dev->sdio.func; + u32 val = ~0, status; + int err; + + sdio_claim_host(func); + + sdio_writel(func, offset, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting address [err=%d]\n", err); + goto out; + } + + sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); + goto out; + } + + err = readx_poll_timeout(mt76s_read_whisr, dev, status, + status & H2D_SW_INT_READ, 0, 1000000); + if (err < 0) { + dev_err(dev->dev, "query whisr timeout\n"); + goto out; + } + + sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); + goto out; + } + + val = sdio_readl(func, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); + goto out; + } + + if (val != offset) { + dev_err(dev->dev, "register mismatch\n"); + val = ~0; + goto out; + } + + val = sdio_readl(func, MCR_D2HRM1R, &err); + if (err < 0) + dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err); + +out: + sdio_release_host(func); + + return val; +} + +static void mt76s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val) +{ + struct sdio_func *func = dev->sdio.func; + u32 status; + int err; + + sdio_claim_host(func); + + sdio_writel(func, offset, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting address [err=%d]\n", err); + goto out; + } + + sdio_writel(func, val, MCR_H2DSM1R, &err); + if (err < 0) { + dev_err(dev->dev, + "failed setting write value [err=%d]\n", err); + goto out; + } + + sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); + goto out; + } + + err = readx_poll_timeout(mt76s_read_whisr, dev, status, + status & H2D_SW_INT_WRITE, 0, 1000000); + if (err < 0) { + dev_err(dev->dev, "query whisr timeout\n"); + goto out; + } + + sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); + goto out; + } + + val = sdio_readl(func, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); + goto out; + } + + if (val != offset) + dev_err(dev->dev, "register mismatch\n"); + +out: + sdio_release_host(func); +} + +u32 mt76s_rr(struct mt76_dev *dev, u32 offset) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) + return dev->mcu_ops->mcu_rr(dev, offset); + else + return mt76s_read_mailbox(dev, offset); +} +EXPORT_SYMBOL_GPL(mt76s_rr); + +void mt76s_wr(struct mt76_dev *dev, u32 offset, u32 val) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) + dev->mcu_ops->mcu_wr(dev, offset, val); + else + mt76s_write_mailbox(dev, offset, val); +} +EXPORT_SYMBOL_GPL(mt76s_wr); + +u32 mt76s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) +{ + val |= mt76s_rr(dev, offset) & ~mask; + mt76s_wr(dev, offset, val); + + return val; +} +EXPORT_SYMBOL_GPL(mt76s_rmw); + +void mt76s_write_copy(struct mt76_dev *dev, u32 offset, + const void *data, int len) +{ + const u32 *val = data; + int i; + + for (i = 0; i < len / sizeof(u32); i++) { + mt76s_wr(dev, offset, val[i]); + offset += sizeof(u32); + } +} +EXPORT_SYMBOL_GPL(mt76s_write_copy); + +void mt76s_read_copy(struct mt76_dev *dev, u32 offset, + void *data, int len) +{ + u32 *val = data; + int i; + + for (i = 0; i < len / sizeof(u32); i++) { + val[i] = mt76s_rr(dev, offset); + offset += sizeof(u32); + } +} +EXPORT_SYMBOL_GPL(mt76s_read_copy); + +int mt76s_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + mt76s_wr(dev, data->reg, data->value); + data++; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76s_wr_rp); + +int mt76s_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int len) +{ + int i; + + for (i = 0; i < len; i++) { + data->value = mt76s_rr(dev, data->reg); + data++; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76s_rd_rp); + +int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func, int hw_ver) +{ + u32 status, ctrl; + int ret; + + dev->sdio.hw_ver = hw_ver; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret < 0) + goto release; + + /* Get ownership from the device */ + sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR, + MCR_WHLPCR, &ret); + if (ret < 0) + goto disable_func; + + ret = readx_poll_timeout(mt76s_read_pcr, dev, status, + status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); + if (ret < 0) { + dev_err(dev->dev, "Cannot get ownership from device"); + goto disable_func; + } + + ret = sdio_set_block_size(func, 512); + if (ret < 0) + goto disable_func; + + /* Enable interrupt */ + sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret); + if (ret < 0) + goto disable_func; + + ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN; + if (hw_ver == MT76_CONNAC2_SDIO) + ctrl |= WHIER_RX1_DONE_INT_EN; + sdio_writel(func, ctrl, MCR_WHIER, &ret); + if (ret < 0) + goto disable_func; + + switch (hw_ver) { + case MT76_CONNAC_SDIO: + /* set WHISR as read clear and Rx aggregation number as 16 */ + ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16); + break; + default: + ctrl = sdio_readl(func, MCR_WHCR, &ret); + if (ret < 0) + goto disable_func; + ctrl &= ~MAX_HIF_RX_LEN_NUM_CONNAC2; + ctrl &= ~W_INT_CLR_CTRL; /* read clear */ + ctrl |= FIELD_PREP(MAX_HIF_RX_LEN_NUM_CONNAC2, 0); + break; + } + + sdio_writel(func, ctrl, MCR_WHCR, &ret); + if (ret < 0) + goto disable_func; + + ret = sdio_claim_irq(func, mt76s_sdio_irq); + if (ret < 0) + goto disable_func; + + sdio_release_host(func); + + return 0; + +disable_func: + sdio_disable_func(func); +release: + sdio_release_host(func); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76s_hw_init); + +int mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; @@ -35,6 +316,7 @@ mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) return 0; } +EXPORT_SYMBOL_GPL(mt76s_alloc_rx_queue); static struct mt76_queue *mt76s_alloc_tx_queue(struct mt76_dev *dev) { @@ -56,7 +338,7 @@ static struct mt76_queue *mt76s_alloc_tx_queue(struct mt76_dev *dev) return q; } -static int mt76s_alloc_tx(struct mt76_dev *dev) +int mt76s_alloc_tx(struct mt76_dev *dev) { struct mt76_queue *q; int i; @@ -79,18 +361,7 @@ static int mt76s_alloc_tx(struct mt76_dev *dev) return 0; } - -int mt76s_alloc_queues(struct mt76_dev *dev) -{ - int err; - - err = mt76s_alloc_rx_queue(dev, MT_RXQ_MAIN); - if (err < 0) - return err; - - return mt76s_alloc_tx(dev); -} -EXPORT_SYMBOL_GPL(mt76s_alloc_queues); +EXPORT_SYMBOL_GPL(mt76s_alloc_tx); static struct mt76_queue_entry * mt76s_get_next_rx_entry(struct mt76_queue *q) @@ -328,7 +599,7 @@ void mt76s_deinit(struct mt76_dev *dev) cancel_work_sync(&sdio->stat_work); clear_bit(MT76_READING_STATS, &dev->phy.state); - mt76_tx_status_check(dev, NULL, true); + mt76_tx_status_check(dev, true); sdio_claim_host(sdio->func); sdio_release_irq(sdio->func); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/sdio.h index 03877d89e152..99db4ad93b7c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h +++ b/drivers/net/wireless/mediatek/mt76/sdio.h @@ -21,7 +21,12 @@ #define MCR_WHCR 0x000C #define W_INT_CLR_CTRL BIT(1) #define RECV_MAILBOX_RD_CLR_EN BIT(2) +#define WF_SYS_RSTB BIT(4) /* supported in CONNAC2 */ +#define WF_WHOLE_PATH_RSTB BIT(5) /* supported in CONNAC2 */ +#define WF_SDIO_WF_PATH_RSTB BIT(6) /* supported in CONNAC2 */ #define MAX_HIF_RX_LEN_NUM GENMASK(13, 8) +#define MAX_HIF_RX_LEN_NUM_CONNAC2 GENMASK(14, 8) /* supported in CONNAC2 */ +#define WF_RST_DONE BIT(15) /* supported in CONNAC2 */ #define RX_ENHANCE_MODE BIT(16) #define MCR_WHISR 0x0010 @@ -29,6 +34,7 @@ #define WHIER_D2H_SW_INT GENMASK(31, 8) #define WHIER_FW_OWN_BACK_INT_EN BIT(7) #define WHIER_ABNORMAL_INT_EN BIT(6) +#define WHIER_WDT_INT_EN BIT(5) /* supported in CONNAC2 */ #define WHIER_RX1_DONE_INT_EN BIT(2) #define WHIER_RX0_DONE_INT_EN BIT(1) #define WHIER_TX_DONE_INT_EN BIT(0) @@ -100,16 +106,33 @@ #define MCR_SWPCDBGR 0x0154 +#define MCR_H2DSM2R 0x0160 /* supported in CONNAC2 */ +#define MCR_H2DSM3R 0x0164 /* supported in CONNAC2 */ +#define MCR_D2HRM3R 0x0174 /* supported in CONNAC2 */ +#define MCR_WTQCR8 0x0190 /* supported in CONNAC2 */ +#define MCR_WTQCR9 0x0194 /* supported in CONNAC2 */ +#define MCR_WTQCR10 0x0198 /* supported in CONNAC2 */ +#define MCR_WTQCR11 0x019C /* supported in CONNAC2 */ +#define MCR_WTQCR12 0x01A0 /* supported in CONNAC2 */ +#define MCR_WTQCR13 0x01A4 /* supported in CONNAC2 */ +#define MCR_WTQCR14 0x01A8 /* supported in CONNAC2 */ +#define MCR_WTQCR15 0x01AC /* supported in CONNAC2 */ + +enum mt76_connac_sdio_ver { + MT76_CONNAC_SDIO, + MT76_CONNAC2_SDIO, +}; + struct mt76s_intr { u32 isr; + u32 *rec_mb; struct { - u32 wtqcr[8]; + u32 *wtqcr; } tx; struct { - u16 num[2]; - u16 len[2][16]; + u16 *len[2]; + u16 *num; } rx; - u32 rec_mb[2]; -} __packed; +}; #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index 04f4c89b7499..649a56790b89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -14,12 +14,11 @@ #include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_func.h> -#include "../trace.h" -#include "mt7615.h" +#include "trace.h" #include "sdio.h" -#include "mac.h" +#include "mt76.h" -static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data) +static int mt76s_refill_sched_quota(struct mt76_dev *dev, u32 *data) { u32 ple_ac_data_quota[] = { FIELD_GET(TXQ_CNT_L, data[4]), /* VO */ @@ -53,8 +52,8 @@ static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data) return pse_data_quota + ple_data_quota + pse_mcu_quota; } -static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len, - int buf_len) +static struct sk_buff * +mt76s_build_rx_skb(void *data, int data_len, int buf_len) { int len = min_t(int, data_len, MT_SKB_HEAD_LEN); struct sk_buff *skb; @@ -78,8 +77,9 @@ static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len, return skb; } -static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid, - struct mt76s_intr *intr) +static int +mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid, + struct mt76s_intr *intr) { struct mt76_queue *q = &dev->q_rx[qid]; struct mt76_sdio *sdio = &dev->sdio; @@ -112,9 +112,11 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid, for (i = 0; i < intr->rx.num[qid]; i++) { int index = (q->head + i) % q->ndesc; struct mt76_queue_entry *e = &q->entry[index]; + __le32 *rxd = (__le32 *)buf; - len = intr->rx.len[qid][i]; - e->skb = mt7663s_build_rx_skb(buf, len, round_up(len + 4, 4)); + /* parse rxd to get the actual packet length */ + len = FIELD_GET(GENMASK(15, 0), le32_to_cpu(rxd[0])); + e->skb = mt76s_build_rx_skb(buf, len, round_up(len + 4, 4)); if (!e->skb) break; @@ -132,45 +134,50 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid, return i; } -static int mt7663s_rx_handler(struct mt76_dev *dev) +static int mt76s_rx_handler(struct mt76_dev *dev) { struct mt76_sdio *sdio = &dev->sdio; - struct mt76s_intr *intr = sdio->intr_data; + struct mt76s_intr intr; int nframes = 0, ret; - ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr)); - if (ret < 0) + ret = sdio->parse_irq(dev, &intr); + if (ret) return ret; - trace_dev_irq(dev, intr->isr, 0); + trace_dev_irq(dev, intr.isr, 0); - if (intr->isr & WHIER_RX0_DONE_INT_EN) { - ret = mt7663s_rx_run_queue(dev, 0, intr); + if (intr.isr & WHIER_RX0_DONE_INT_EN) { + ret = mt76s_rx_run_queue(dev, 0, &intr); if (ret > 0) { mt76_worker_schedule(&sdio->net_worker); nframes += ret; } } - if (intr->isr & WHIER_RX1_DONE_INT_EN) { - ret = mt7663s_rx_run_queue(dev, 1, intr); + if (intr.isr & WHIER_RX1_DONE_INT_EN) { + ret = mt76s_rx_run_queue(dev, 1, &intr); if (ret > 0) { mt76_worker_schedule(&sdio->net_worker); nframes += ret; } } - nframes += !!mt7663s_refill_sched_quota(dev, intr->tx.wtqcr); + nframes += !!mt76s_refill_sched_quota(dev, intr.tx.wtqcr); return nframes; } -static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz, - int *pse_size, int *ple_size) +static int +mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz, + int *pse_size, int *ple_size) { int pse_sz; - pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ); + pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, + sdio->sched.pse_page_size); + + if (mcu && sdio->hw_ver == MT76_CONNAC2_SDIO) + pse_sz = 1; if (mcu) { if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz) @@ -187,8 +194,9 @@ static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz, return 0; } -static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, - int pse_size, int ple_size) +static void +mt76s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, int pse_size, + int ple_size) { if (mcu) { sdio->sched.pse_mcu_quota -= pse_size; @@ -198,7 +206,7 @@ static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, } } -static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) +static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) { struct mt76_sdio *sdio = &dev->sdio; int err; @@ -213,7 +221,7 @@ static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) return err; } -static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q) +static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q) { int qid, err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0; bool mcu = q == dev->q_mcu[MT_MCUQ_WM]; @@ -227,10 +235,13 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q) smp_rmb(); + if (test_bit(MT76_MCU_RESET, &dev->phy.state)) + goto next; + if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) { __skb_put_zero(e->skb, 4); - err = __mt7663s_xmit_queue(dev, e->skb->data, - e->skb->len); + err = __mt76s_xmit_queue(dev, e->skb->data, + e->skb->len); if (err) return err; @@ -241,8 +252,8 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q) if (len + e->skb->len + pad + 4 > MT76S_XMIT_BUF_SZ) break; - if (mt7663s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz, - &ple_sz)) + if (mt76s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz, + &ple_sz)) break; memcpy(sdio->xmit_buf[qid] + len, e->skb->data, @@ -268,30 +279,22 @@ next: if (nframes) { memset(sdio->xmit_buf[qid] + len, 0, 4); - err = __mt7663s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4); + err = __mt76s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4); if (err) return err; } - mt7663s_tx_update_quota(sdio, mcu, pse_sz, ple_sz); + mt76s_tx_update_quota(sdio, mcu, pse_sz, ple_sz); mt76_worker_schedule(&sdio->status_worker); return nframes; } -void mt7663s_txrx_worker(struct mt76_worker *w) +void mt76s_txrx_worker(struct mt76_sdio *sdio) { - struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, - txrx_worker); - struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio); - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); int i, nframes, ret; - if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { - queue_work(mdev->wq, &dev->pm.wake_work); - return; - } - /* disable interrupt */ sdio_claim_host(sdio->func); sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); @@ -301,34 +304,61 @@ void mt7663s_txrx_worker(struct mt76_worker *w) /* tx */ for (i = 0; i <= MT_TXQ_PSD; i++) { - ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]); + ret = mt76s_tx_run_queue(dev, dev->phy.q_tx[i]); if (ret > 0) nframes += ret; } - ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]); + ret = mt76s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]); if (ret > 0) nframes += ret; /* rx */ - ret = mt7663s_rx_handler(mdev); + ret = mt76s_rx_handler(dev); if (ret > 0) nframes += ret; + + if (test_bit(MT76_MCU_RESET, &dev->phy.state)) { + if (!mt76s_txqs_empty(dev)) + continue; + else + wake_up(&sdio->wait); + } } while (nframes > 0); /* enable interrupt */ sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL); sdio_release_host(sdio->func); - - mt76_connac_pm_unref(&dev->mphy, &dev->pm); } +EXPORT_SYMBOL_GPL(mt76s_txrx_worker); -void mt7663s_sdio_irq(struct sdio_func *func) +void mt76s_sdio_irq(struct sdio_func *func) { - struct mt7615_dev *dev = sdio_get_drvdata(func); - struct mt76_sdio *sdio = &dev->mt76.sdio; + struct mt76_dev *dev = sdio_get_drvdata(func); + struct mt76_sdio *sdio = &dev->sdio; - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state)) + if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state) || + test_bit(MT76_MCU_RESET, &dev->phy.state)) return; mt76_worker_schedule(&sdio->txrx_worker); } +EXPORT_SYMBOL_GPL(mt76s_sdio_irq); + +bool mt76s_txqs_empty(struct mt76_dev *dev) +{ + struct mt76_queue *q; + int i; + + for (i = 0; i <= MT_TXQ_PSD + 1; i++) { + if (i <= MT_TXQ_PSD) + q = dev->phy.q_tx[i]; + else + q = dev->q_mcu[MT_MCUQ_WM]; + + if (q->first != q->head) + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(mt76s_txqs_empty); diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index f73ffbd6e622..66afc2b0a935 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -2,7 +2,7 @@ /* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */ #include "mt76.h" -static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { +const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { [MT76_TM_ATTR_RESET] = { .type = NLA_FLAG }, [MT76_TM_ATTR_STATE] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 }, @@ -21,7 +21,9 @@ static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 }, [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 }, [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 }, + [MT76_TM_ATTR_DRV_DATA] = { .type = NLA_NESTED }, }; +EXPORT_SYMBOL_GPL(mt76_tm_policy); void mt76_testmode_tx_pending(struct mt76_phy *phy) { diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h index d32a7654c47e..d1f9c036dd1f 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/testmode.h @@ -44,6 +44,7 @@ * @MT76_TM_ATTR_TX_IPG: tx inter-packet gap, in unit of us (u32) * @MT76_TM_ATTR_TX_TIME: packet transmission time, in unit of us (u32) * + * @MT76_TM_ATTR_DRV_DATA: driver specific netlink attrs (nested) */ enum mt76_testmode_attr { MT76_TM_ATTR_UNSPEC, @@ -78,6 +79,8 @@ enum mt76_testmode_attr { MT76_TM_ATTR_TX_IPG, MT76_TM_ATTR_TX_TIME, + MT76_TM_ATTR_DRV_DATA, + /* keep last */ NUM_MT76_TM_ATTRS, MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1, @@ -144,6 +147,7 @@ enum mt76_testmode_rx_attr { * @MT76_TM_STATE_TX_FRAMES: send a fixed number of test frames * @MT76_TM_STATE_RX_FRAMES: receive packets and keep statistics * @MT76_TM_STATE_TX_CONT: waveform tx without time gap + * @MT76_TM_STATE_ON: test mode enabled used in offload firmware */ enum mt76_testmode_state { MT76_TM_STATE_OFF, @@ -151,6 +155,7 @@ enum mt76_testmode_state { MT76_TM_STATE_TX_FRAMES, MT76_TM_STATE_RX_FRAMES, MT76_TM_STATE_TX_CONT, + MT76_TM_STATE_ON, /* keep last */ NUM_MT76_TM_STATES, @@ -184,4 +189,6 @@ enum mt76_testmode_tx_mode { MT76_TM_TX_MODE_MAX = NUM_MT76_TM_TX_MODES - 1, }; +extern const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS]; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index f0f7a913eaab..11719ef034d8 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -38,21 +38,21 @@ EXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn); void mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list) - __acquires(&dev->status_list.lock) + __acquires(&dev->status_lock) { __skb_queue_head_init(list); - spin_lock_bh(&dev->status_list.lock); + spin_lock_bh(&dev->status_lock); } EXPORT_SYMBOL_GPL(mt76_tx_status_lock); void mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) - __releases(&dev->status_list.lock) + __releases(&dev->status_lock) { struct ieee80211_hw *hw; struct sk_buff *skb; - spin_unlock_bh(&dev->status_list.lock); + spin_unlock_bh(&dev->status_lock); rcu_read_lock(); while ((skb = __skb_dequeue(list)) != NULL) { @@ -64,9 +64,13 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) struct mt76_wcid *wcid; wcid = rcu_dereference(dev->wcid[cb->wcid]); - if (wcid) + if (wcid) { status.sta = wcid_to_sta(wcid); + if (status.sta) + status.rate = &wcid->rate; + } + hw = mt76_tx_status_get_hw(dev, skb); ieee80211_tx_status_ext(hw, &status); } @@ -88,8 +92,6 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, if ((flags & done) != done) return; - __skb_unlink(skb, &dev->status_list); - /* Tx status can be unreliable. if it fails, mark the frame as ACKed */ if (flags & MT_TX_CB_TXS_FAILED) { info->status.rates[0].count = 0; @@ -116,6 +118,8 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); int pid; + memset(cb, 0, sizeof(*cb)); + if (!wcid) return MT_PACKET_ID_NO_ACK; @@ -126,16 +130,23 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, IEEE80211_TX_CTL_RATE_CTRL_PROBE))) return MT_PACKET_ID_NO_SKB; - spin_lock_bh(&dev->status_list.lock); + spin_lock_bh(&dev->status_lock); + + pid = idr_alloc(&wcid->pktid, skb, MT_PACKET_ID_FIRST, + MT_PACKET_ID_MASK, GFP_ATOMIC); + if (pid < 0) { + pid = MT_PACKET_ID_NO_SKB; + goto out; + } - memset(cb, 0, sizeof(*cb)); - pid = mt76_get_next_pkt_id(wcid); cb->wcid = wcid->idx; cb->pktid = pid; - cb->jiffies = jiffies; - __skb_queue_tail(&dev->status_list, skb); - spin_unlock_bh(&dev->status_list.lock); + if (list_empty(&wcid->list)) + list_add_tail(&wcid->list, &dev->wcid_list); + +out: + spin_unlock_bh(&dev->status_lock); return pid; } @@ -145,36 +156,53 @@ struct sk_buff * mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, struct sk_buff_head *list) { - struct sk_buff *skb, *tmp; + struct sk_buff *skb; + int id; - skb_queue_walk_safe(&dev->status_list, skb, tmp) { - struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); + lockdep_assert_held(&dev->status_lock); - if (wcid && cb->wcid != wcid->idx) - continue; + skb = idr_remove(&wcid->pktid, pktid); + if (skb) + goto out; - if (cb->pktid == pktid) - return skb; + /* look for stale entries in the wcid idr queue */ + idr_for_each_entry(&wcid->pktid, skb, id) { + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); - if (pktid >= 0 && !time_after(jiffies, cb->jiffies + - MT_TX_STATUS_SKB_TIMEOUT)) - continue; + if (pktid >= 0) { + if (!(cb->flags & MT_TX_CB_DMA_DONE)) + continue; + + if (!time_is_after_jiffies(cb->jiffies + + MT_TX_STATUS_SKB_TIMEOUT)) + continue; + } + /* It has been too long since DMA_DONE, time out this packet + * and stop waiting for TXS callback. + */ + idr_remove(&wcid->pktid, cb->pktid); __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED | MT_TX_CB_TXS_DONE, list); } - return NULL; +out: + if (idr_is_empty(&wcid->pktid)) + list_del_init(&wcid->list); + + return skb; } EXPORT_SYMBOL_GPL(mt76_tx_status_skb_get); void -mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush) +mt76_tx_status_check(struct mt76_dev *dev, bool flush) { + struct mt76_wcid *wcid, *tmp; struct sk_buff_head list; mt76_tx_status_lock(dev, &list); - mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list); + list_for_each_entry_safe(wcid, tmp, &dev->wcid_list, list) + mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list); mt76_tx_status_unlock(dev, &list); } EXPORT_SYMBOL_GPL(mt76_tx_status_check); @@ -197,6 +225,7 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, struct list_head *free_list) { + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); struct ieee80211_tx_status status = { .skb = skb, .free_list = free_list, @@ -226,7 +255,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff * } #endif - if (!skb->prev) { + if (cb->pktid < MT_PACKET_ID_FIRST) { hw = mt76_tx_status_get_hw(dev, skb); status.sta = wcid_to_sta(wcid); ieee80211_tx_status_ext(hw, &status); @@ -234,6 +263,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff * } mt76_tx_status_lock(dev, &list); + cb->jiffies = jiffies; __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list); mt76_tx_status_unlock(dev, &list); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 1e9f60bb811a..0a7006c8959b 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -1081,7 +1081,7 @@ void mt76u_stop_tx(struct mt76_dev *dev) mt76_worker_enable(&dev->usb.status_worker); - mt76_tx_status_check(dev, NULL, true); + mt76_tx_status_check(dev, true); } EXPORT_SYMBOL_GPL(mt76u_stop_tx); |