From df040215c077de0c13aab12c222bd0360a0d3988 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Jun 2021 20:18:19 +0200 Subject: mt76: mt7921: fix endianness in mt7921_mcu_tx_done_event Fix endianness in mt7921_mcu_tx_done_event event reported by the firmware. Fixes: 3cce2b98e0241 ("mt76: mt7921: introduce mac tx done handling") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7921/mcu.h | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 9fbaacc67cfa..68840e55ede7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -532,7 +532,8 @@ mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) 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); + &msta->stats.tx_rate, + le16_to_cpu(event->tx_rate)); spin_lock_bh(&dev->sta_poll_lock); break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index de3c091f6736..42e727184895 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -296,11 +296,11 @@ struct mt7921_txpwr_event { struct mt7921_mcu_tx_done_event { u8 pid; u8 status; - u16 seq; + __le16 seq; u8 wlan_idx; u8 tx_cnt; - u16 tx_rate; + __le16 tx_rate; u8 flag; u8 tid; @@ -312,9 +312,9 @@ struct mt7921_mcu_tx_done_event { u8 reason; u8 rsv0[1]; - u32 delay; - u32 timestamp; - u32 applied_flag; + __le32 delay; + __le32 timestamp; + __le32 applied_flag; u8 txs[28]; -- cgit v1.2.3-70-g09d2 From 305023510f13afae8a0cb8118eb53c6056764781 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Jun 2021 20:19:58 +0200 Subject: mt76: mt7921: avoid unnecessary spin_lock/spin_unlock in mt7921_mcu_tx_done_event Do not grab the spinlock in mt7921_mcu_tx_done_event routine if not necessary. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 68840e55ede7..f32b672f9c3e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -534,9 +534,7 @@ mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) mt7921_mcu_tx_rate_parse(mphy->mt76, &peer, &msta->stats.tx_rate, le16_to_cpu(event->tx_rate)); - - spin_lock_bh(&dev->sta_poll_lock); - break; + return; } spin_unlock_bh(&dev->sta_poll_lock); } -- cgit v1.2.3-70-g09d2 From 08b3c8da87aed4200dab00906f149d675ca90f23 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 21 Jun 2021 10:21:31 +0200 Subject: mt76: mt7915: fix endianness warning in mt7915_mac_add_txs_skb Fix the following sparse warning in mt7915_mac_add_txs_skb routine: drivers/net/wireless/mediatek/mt76/mt7915/mac.c:1235:29: warning: cast to restricted __le32 drivers/net/wireless/mediatek/mt76/mt7915/mac.c:1235:23: warning: restricted __le32 degrades to integer Fixes: 3de4cb1756565 ("mt76: mt7915: add support for tx status reporting") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 2462704094b0..bbc996f86b5c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1232,7 +1232,7 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, goto out; info = IEEE80211_SKB_CB(skb); - if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK))) + if (!(txs_data[0] & cpu_to_le32(MT_TXS0_ACK_ERROR_MASK))) info->flags |= IEEE80211_TX_STAT_ACK; info->status.ampdu_len = 1; -- cgit v1.2.3-70-g09d2 From 7fc167bbc9296e6aeaaa4063db3639e8a3db75f6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 21 Jun 2021 11:18:58 +0200 Subject: mt76: mt7921: fix endianness warning in mt7921_update_txs Fix the following sparse warning in mt7921_update_txs routine: drivers/net/wireless/mediatek/mt76/mt7921/mac.c:752:31: warning: cast to restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:752:31: warning: restricted __le32 degrades to integer Fixes: e5bca8c5d2cd3 ("mt76: mt7921: improve code readability for mt7921_update_txs") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 7fe2e3a50428..f4714b0f6e5c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -735,8 +735,9 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, 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]); + u32 pid, frame_type; + frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, le32_to_cpu(txwi[2])); if (!(frame_type & (IEEE80211_FTYPE_DATA >> 2))) return; -- cgit v1.2.3-70-g09d2 From d81bfb41e30c42531536c5d2baa4d275a8309715 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 21 Jun 2021 23:53:22 +0200 Subject: mt76: mt7615: fix endianness warning in mt7615_mac_write_txwi Fix the following sparse warning in mt7615_mac_write_txwi routine: drivers/net/wireless/mediatek/mt76/mt7615/mac.c:758:17: warning: incorrect type in assignment expected restricted __le32 [usertype] got unsigned long Fixes: 04b8e65922f63 ("mt76: add mac80211 driver for MT7615 PCIe-based chipsets") Fixes: d4bf77bd74930 ("mt76: mt7615: introduce mt7663u support to mt7615_write_txwi") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index ff3f85e4087c..5a8539d5f030 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; } -- cgit v1.2.3-70-g09d2 From 3924715ffe5e064a85f56490f77b7b2084230800 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 25 Jun 2021 17:58:54 +0300 Subject: mt76: mt7915: fix info leak in mt7915_mcu_set_pre_cal() Zero out all the unused members of "req" so that we don't disclose stack information. Fixes: 495184ac91bb ("mt76: mt7915: add support for applying pre-calibration data") Signed-off-by: Dan Carpenter Acked-by: Felix Fietkau Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 43960770a9af..dfb6f1755e62 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3481,7 +3481,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); -- cgit v1.2.3-70-g09d2 From 7e4de0c853ae6875629070afe5e88be3c68d59e9 Mon Sep 17 00:00:00 2001 From: Bo Jiao Date: Tue, 6 Jul 2021 18:56:54 +0800 Subject: mt76: mt7915: fix calling mt76_wcid_alloc with incorrect parameter It will cause maximum connectable STA to be one less when calling mt76_wcid_alloc with parameter MT7915_WTBL_STA - 1. Signed-off-by: Bo Jiao Signed-off-by: Sujuan Chen Reviewed-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 4798d6344305..1d2214519f5a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -480,7 +480,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index c25f8da590dd..d8abebcffe4b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -613,7 +613,7 @@ 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; -- cgit v1.2.3-70-g09d2 From d741abeafa47a7331cd4fe526e44db4ad3da0f62 Mon Sep 17 00:00:00 2001 From: Leon Yen Date: Thu, 8 Jul 2021 12:29:06 +0800 Subject: mt76: connac: fix mt76_connac_gtk_rekey_tlv usage The mistaken structure is introduced since we added the GTK rekey offload to mt7663. The patch fixes mt76_connac_gtk_rekey_tlv structure according to the MT7663 and MT7921 firmware we have submitted into linux-firmware.git. Fixes: b47e21e75c80 ("mt76: mt7615: add gtk rekey offload support") Signed-off-by: Sean Wang Signed-off-by: Leon Yen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 1c73beb22677..4bcd728ff97c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -844,14 +844,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 -- cgit v1.2.3-70-g09d2 From bf3747ae2e25dda6a9e6c464a717c66118c588c8 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sun, 20 Jun 2021 15:48:06 +0800 Subject: mt76: mt7921: enable aspm by default mt7921 is mainly used in NB, CE and IoT application where battery life is much concerned so the patch enabled PCIe ASPM by default to shut off the clocks related PCIe as much as possible when MT7921 is either in suspend state or in runtime pm to lower power consumption. We still leave disable aspm as an option with module_param for users to disable ASPM if necessary. Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index c3905bcab360..33782e1ee312 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -17,6 +17,10 @@ static const struct pci_device_id mt7921_pci_device_table[] = { { }, }; +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) { @@ -132,7 +136,8 @@ static int mt7921_pci_probe(struct pci_dev *pdev, 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); -- cgit v1.2.3-70-g09d2 From adedbc643f02f5a3193b8dcc5cfca97b4c988667 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sun, 20 Jun 2021 15:48:07 +0800 Subject: mt76: fix build error implicit enumeration conversion drivers/net/wireless/mediatek/mt76/mt7915/mcu.c:114:10: error: implicit conversion from enumeration type 'enum mt76_cipher_type' to different enumeration type 'enum mcu_cipher_type' [-Werror,-Wenum-conversion] return MT_CIPHER_NONE; ~~~~~~ ^~~~~~~~~~~~~~ drivers/net/wireless/mediatek/mt76/mt7921/mcu.c:114:10: error: implicit conversion from enumeration type 'enum mt76_cipher_type' to different enumeration type 'enum mcu_cipher_type' [-Werror,-Wenum-conversion] return MT_CIPHER_NONE; ~~~~~~ ^~~~~~~~~~~~~~ Fixes: c368362c36d3 ("mt76: fix iv and CCMP header insertion") Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index dfb6f1755e62..b55fb3529a4b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1201,7 +1201,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]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index f32b672f9c3e..c621ddd365be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -618,7 +618,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]; -- cgit v1.2.3-70-g09d2 From 64ed76d118c656907ec1155f2cdd24de778470a2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 23 Jun 2021 15:19:19 +0200 Subject: mt76: mt7921: fix survey-dump reporting Fix MIB tx-rx MIB counters for survey-dump reporting. Fixes: 163f4d22c118d ("mt76: mt7921: add MAC support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt7921/regs.h | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index a9ce10b98827..52d40385fab6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -106,6 +106,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h index b6944c867a57..26fb11823762 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h @@ -96,6 +96,10 @@ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) #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) @@ -108,9 +112,9 @@ #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) -- cgit v1.2.3-70-g09d2 From c33edef520213feccebc22c9474c685b9fb60611 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 22 Jun 2021 09:48:30 +0200 Subject: mt76: mt76x02: fix endianness warnings in mt76x02_mac.c Fix the following sparse warning in mt76x02_mac_write_txwi and mt76x02_mac_tx_rate_val routines: drivers/net/wireless/mediatek/mt76/mt76x02_mac.c:237:19: warning: restricted __le16 degrades to intege warning: cast from restricted __le16 drivers/net/wireless/mediatek/mt76/mt76x02_mac.c:383:28: warning: incorrect type in assignment (different base types) expected restricted __le16 [usertype] rate got unsigned long Fixes: db9f11d3433f7 ("mt76: store wcid tx rate info in one u32 reduce locking") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index c32e6dc68773..07b21b208582 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); -- cgit v1.2.3-70-g09d2 From 4826075c8da598fbce33499956664cbd37a6c2da Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 23 Jun 2021 01:35:39 +0800 Subject: mt76: mt7915: report HE MU radiotap Report HE MU/BF radiotap. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 63 ++++++++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 8 ++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index bbc996f86b5c..68626ce06996 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -228,12 +228,51 @@ mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); } +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 +280,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 +295,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 +308,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 +321,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 +648,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index eb1885f4bd8e..ccce994dc07a 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) -- cgit v1.2.3-70-g09d2 From d5f4ceeee69ee6afa5ad2e13cf448e132a37543c Mon Sep 17 00:00:00 2001 From: Bo Jiao Date: Tue, 6 Jul 2021 18:04:26 +0800 Subject: mt76: mt7915: adapt new firmware to update BA winsize for Rx session The newer firmware requires host driver to set BA winsize on both Tx/Rx sessions, so modify it for the long run. Signed-off-by: Bo Jiao Signed-off-by: Sujuan Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b55fb3529a4b..0e6c299fc0a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1317,7 +1317,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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index e68a562cc5b4..83cbb99cd723 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -716,6 +716,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]; -- cgit v1.2.3-70-g09d2 From 502604f545978d2d4b12f8029785d5f1e4b32e56 Mon Sep 17 00:00:00 2001 From: YN Chen Date: Tue, 29 Jun 2021 07:05:53 +0800 Subject: mt76: mt7921: add .set_sar_specs support add .set_sar_specs to allow configuring SAR power limitations on the frequency ranges from the userland. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: YN Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 15 +++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 8 +++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 30 ++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 17 ++++++++-- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 38 ++++++++++++++++++++++ 5 files changed, 105 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d03aedc3286b..ee3a5b8d62d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -99,6 +99,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 25c5ceef5257..ec42b87c9779 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -545,6 +545,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, @@ -636,6 +641,8 @@ struct mt76_phy { struct sk_buff **tail; u16 seqno; } rx_amsdu[__MT_RXQ_MAX]; + + struct mt76_freq_range_power *frp; }; struct mt76_dev { @@ -769,6 +776,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__) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 5c3a81e5f559..a2555dc0f003 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1749,6 +1749,30 @@ 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 int mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, enum nl80211_band band) @@ -1816,9 +1840,13 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, .hw_value = ch_list[idx], .band = band, }; + s8 sar_power; + + sar_power = mt76_connac_get_sar_power(phy, &chan, + tx_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]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 52d40385fab6..fd119b260834 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 @@ -211,7 +221,10 @@ int mt7921_register_device(struct mt7921_dev *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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 63ec140c9c37..0ad9ffb52b6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1172,6 +1172,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, @@ -1210,4 +1247,5 @@ 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, }; -- cgit v1.2.3-70-g09d2 From d45dac0732a287fc371a23f257cce04e65627947 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 14 Jul 2021 15:56:10 +0800 Subject: mt76: mt7915: fix an off-by-one bound check The bounds check on datalen is off-by-one, so fix it. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 0e6c299fc0a4..bab652eae434 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -925,7 +925,7 @@ static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, 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; -- cgit v1.2.3-70-g09d2 From ffbebe7649c32139e765e9c64838a7d0a28bbd24 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 14 Jul 2021 17:18:48 +0800 Subject: mt76: mt7915: take RCU read lock when calling ieee80211_bss_get_elem() As ieee80211_bss_get_elem() derefences an RCU to return ie, both the call to this function and any operation on this variable need protection by the RCU read lock. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index bab652eae434..2ba3d92ebd70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -923,12 +923,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 || !(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, -- cgit v1.2.3-70-g09d2 From ae06a88f3d92c2764bc28207bd966d8b5ff3abce Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 14 Jul 2021 17:18:49 +0800 Subject: mt76: mt7915: cleanup -Wunused-but-set-variable Cleanup -Wunused-but-set-variable everywhere in driver. Reported-by: kernel test robot Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 68626ce06996..36b8c9ac8ed7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1203,7 +1203,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. @@ -1211,7 +1210,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; @@ -1223,7 +1221,6 @@ 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); @@ -1234,8 +1231,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; @@ -1374,15 +1369,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; -- cgit v1.2.3-70-g09d2 From 9908d98ae72cdfba85c588a627df9d37401be8af Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 14 Jul 2021 17:18:50 +0800 Subject: mt76: mt7915: report tx rate directly from tx status Report tx rate from tx status packets instead of receving periodic mcu event. This improves flexibility, accuracy and AQL performance, and simplifies code flow for better readability. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 + .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 47 ------ drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 - drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 173 ++++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 26 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 168 -------------------- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 43 ----- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 17 -- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 4 - drivers/net/wireless/mediatek/mt76/tx.c | 6 +- 10 files changed, 153 insertions(+), 335 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ec42b87c9779..0516d3afe262 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -244,6 +244,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 64048243e34b..1a48b09d0cb7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -377,56 +377,9 @@ static int mt7915_sta_fixed_rate_set(void *data, u64 rate) 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) -{ - 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); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(mt7915_sta_stats); - 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); } #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 1d2214519f5a..906dacef5bdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -350,7 +350,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); @@ -787,7 +786,6 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 36b8c9ac8ed7..83660b021d8e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -88,15 +88,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 +106,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 +119,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 +134,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 +175,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(); @@ -1057,6 +1095,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->stats.jiffies + HZ / 4)) { + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + msta->stats.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, @@ -1222,8 +1271,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) msta = container_of(wcid, struct mt7915_sta, wcid); 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); @@ -1257,18 +1304,25 @@ static bool mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data) { + 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; mt76_tx_status_lock(mdev, &list); skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); if (!skb) goto out; + txs = le32_to_cpu(txs_data[0]); + info = IEEE80211_SKB_CB(skb); - if (!(txs_data[0] & cpu_to_le32(MT_TXS0_ACK_ERROR_MASK))) + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) info->flags |= IEEE80211_TX_STAT_ACK; info->status.ampdu_len = 1; @@ -1276,9 +1330,81 @@ 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); + + if (!wcid->sta) + goto out; + + 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; + + switch (FIELD_GET(MT_TX_RATE_MODE, txrate)) { + 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; + } + + switch (FIELD_GET(MT_TXS0_BW, txs)) { + 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; + } + wcid->rate = rate; out: + mt76_tx_status_skb_done(mdev, skb, &list); mt76_tx_status_unlock(mdev, &list); return !!skb; @@ -1769,30 +1895,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); @@ -1849,11 +1951,6 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index d8abebcffe4b..0228fbaa48e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -231,7 +231,6 @@ 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; @@ -618,7 +617,6 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 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; @@ -652,8 +650,6 @@ void mt7915_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); if (!list_empty(&msta->rc_list)) list_del_init(&msta->rc_list); spin_unlock_bh(&dev->sta_poll_lock); @@ -926,7 +922,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 +930,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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 2ba3d92ebd70..5ed123a644ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -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) { @@ -672,9 +526,6 @@ 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; @@ -706,7 +557,6 @@ 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->seq) mt7915_mcu_rx_unsolicited_event(dev, skb); else @@ -3736,24 +3586,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 83cbb99cd723..4142e27c93ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -43,7 +43,6 @@ 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, }; enum { @@ -164,41 +163,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 +174,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; @@ -318,7 +276,6 @@ enum { 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_FW_DBG_CTRL = 0x95, MCU_EXT_CMD_SET_RDD_TH = 0x9d, MCU_EXT_CMD_SET_SPR = 0xa8, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 3f613fae6218..a9c36b515aa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -65,10 +65,6 @@ enum mt7915_rxq_id { }; struct mt7915_sta_stats { - struct rate_info prob_rate; - struct rate_info tx_rate; - - unsigned long per; unsigned long changed; unsigned long jiffies; }; @@ -83,7 +79,6 @@ struct mt7915_sta { struct mt7915_vif *vif; - struct list_head stats_list; struct list_head poll_list; struct list_head rc_list; u32 airtime_ac[8]; @@ -94,7 +89,6 @@ struct mt7915_sta { struct mt7915_sta_key_conf bip; }; - struct mt7915_vif { u16 idx; u8 omac_idx; @@ -151,9 +145,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 { @@ -250,13 +241,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) { @@ -367,7 +351,6 @@ 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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index f4714b0f6e5c..11c2f88c0d71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1092,15 +1092,11 @@ void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { - 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; diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index f0f7a913eaab..6f302acb6e69 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -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); } -- cgit v1.2.3-70-g09d2 From 05909e4625b0411bf897a3339b3b19ab2f36f552 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 14 Jul 2021 17:18:51 +0800 Subject: mt76: mt7915: remove mt7915_sta_stats mt7915_sta_stats is no longer needed after tx rate reworking. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 9 ++------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 83660b021d8e..4c17d1169108 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1100,9 +1100,9 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, msta = (struct mt7915_sta *)sta->drv_priv; - if (time_after(jiffies, msta->stats.jiffies + HZ / 4)) { + if (time_after(jiffies, msta->jiffies + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->stats.jiffies = jiffies; + msta->jiffies = jiffies; } } @@ -1910,8 +1910,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 0228fbaa48e2..48b5e2051bad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -623,7 +623,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 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); @@ -955,7 +955,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index a9c36b515aa6..33be449309e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -64,11 +64,6 @@ enum mt7915_rxq_id { MT7915_RXQ_MCU_WA_EXT, }; -struct mt7915_sta_stats { - unsigned long changed; - unsigned long jiffies; -}; - struct mt7915_sta_key_conf { s8 keyidx; u8 key[16]; @@ -83,8 +78,8 @@ struct mt7915_sta { 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 mt7915_sta_key_conf bip; -- cgit v1.2.3-70-g09d2 From bce844584799c33e16613389a1bcf76644524f97 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 21 Jun 2021 11:23:26 +0200 Subject: mt76: mt7921: introduce testmode support We add the testmode support to access the testmode feature provided by the MT7921 firmware. Tested-by: Sean Wang Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 1 + drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 + drivers/net/wireless/mediatek/mt76/mt7921/mcu.h | 26 +++ drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 4 + .../net/wireless/mediatek/mt76/mt7921/testmode.c | 197 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/testmode.c | 4 +- drivers/net/wireless/mediatek/mt76/testmode.h | 7 + 9 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/testmode.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 4bcd728ff97c..ab77289c0541 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -548,6 +548,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 0ebb59966a08..3471d82fc265 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MT7921E) += mt7921e.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 +mt7921e-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index fd119b260834..49725caca7ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -141,6 +141,8 @@ 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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 0ad9ffb52b6e..7c4f97d65aae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1240,6 +1240,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index 42e727184895..c4fc74991fd4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -320,4 +320,30 @@ struct mt7921_mcu_tx_done_event { u8 rsv1[32]; } __packed; + +enum { + TM_SWITCH_MODE, + TM_SET_AT_CMD, + TM_QUERY_AT_CMD, +}; + +enum { + MT7921_TM_NORMAL, + MT7921_TM_TESTMODE, + MT7921_TM_ICAP, + MT7921_TM_ICAP_OVERLAP, + MT7921_TM_WIFISPECTRUM, +}; + +struct mt7921_rftest_cmd { + u8 action; + u8 rsv[3]; + __le32 param0; + __le32 param1; +} __packed; + +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..ac0b414ccd92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -388,4 +388,8 @@ 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); #endif 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/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 */ #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 -- cgit v1.2.3-70-g09d2 From e4867225431fe6bf09969516994002966c5b755c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 14 Jul 2021 04:15:59 +0800 Subject: mt76: add mt76_default_basic_rate more devices can rely on add mt76_default_basic_rate to mt76 core more devices can rely on to send frames which require the rate in the basic rates. Suggested-by: Ryder Lee Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 14 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index ee3a5b8d62d2..7403a012ceed 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1351,3 +1351,17 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, return hwq; } EXPORT_SYMBOL_GPL(mt76_init_queue); + +u16 mt76_default_basic_rate(struct mt76_phy *phy, struct ieee80211_vif *vif) +{ + int i = ffs(vif->bss_conf.basic_rates) - 1, offset = 0; + struct ieee80211_rate *rate; + + if (phy->chandef.chan->band == NL80211_BAND_5GHZ) + offset = 4; + + rate = &mt76_rates[offset + i]; + + return rate->hw_value; +} +EXPORT_SYMBOL_GPL(mt76_default_basic_rate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 0516d3afe262..bf36f9227713 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -891,6 +891,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_default_basic_rate(struct mt76_phy *phy, struct ieee80211_vif *vif); static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, int n_desc, int ring_base) { -- cgit v1.2.3-70-g09d2 From 326d229f86226670bff7fcadb01bc2b33f112dbf Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 14 Jul 2021 04:16:00 +0800 Subject: mt76: mt7921: fix mgmt frame using unexpected bitrate Fix the current driver mgmt frame is not respecting the basic rates field provided by the AP and then unconditionally is using the lowest (1 or 6 Mbps) rate. For example, if the AP only supported basic rate {24, 36, 48, 54} Mbps, mt7921 cannot send mgmt frame with the rate not in the group. So, instead, we pick up the lowest basic rate the AP can support to send. Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support") Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 10 +++++----- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 11c2f88c0d71..d64a266279d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -811,15 +811,15 @@ 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; + 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_default_basic_rate(mphy, vif); + 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index ac0b414ccd92..6e9e4dfb3928 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -38,8 +38,6 @@ #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 -- cgit v1.2.3-70-g09d2 From bad67a264183004283f4fa6883d594388eae711d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 14 Jul 2021 04:16:01 +0800 Subject: mt76: mt7915: fix mgmt frame using unexpected bitrate Fix the current driver mgmt frame is not respecting the basic rates field provided by the AP and then unconditionally is using the lowest (1 or 6 Mbps) rate. For example, if the AP only supported basic rate {24, 36, 48, 54} Mbps, mt7921 cannot send mgmt frame with the rate not in the group. So, instead, we pick up the lowest basic rate the AP can support to send. Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Suggested-by: Ryder Lee Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 10 +++++----- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 4c17d1169108..dcee3a3890e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1053,15 +1053,15 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, mt7915_mac_write_txwi_80211(dev, txwi, skb, key); if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { - u16 rate; + 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 = MT7915_5G_RATE_DEFAULT; - else - rate = MT7915_2G_RATE_DEFAULT; + rate = mt76_default_basic_rate(mphy, vif); + 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 33be449309e0..a6b5b300d415 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -36,8 +36,6 @@ #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 -- cgit v1.2.3-70-g09d2 From cd3f387371e941e6806b455b4ba5b9f4ca4b77c6 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Wed, 14 Jul 2021 23:50:52 +0800 Subject: mt76: mt7921: Fix out of order process by invalid event pkt The acceptable event report should inlcude original CMD-ID. Otherwise, drop unexpected result from fw. Fixes: 1c099ab44727c ("mt76: mt7921: add MCU support") Signed-off-by: Jimmy Hu Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index c621ddd365be..8d3cf4f99141 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -157,6 +157,7 @@ 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 +195,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: { -- cgit v1.2.3-70-g09d2 From b5cd1fd6043bbb7c5810067b5f93f3016bfd8a6f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 21 Jul 2021 07:23:46 +0200 Subject: mt76: mt7615: fix skb use-after-free on mac reset When clearing all existing pending tx slots, mt76_tx_complete_skb needs to be used to free the skbs, to ensure that they are cleared from the status list as well. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 45 +++++++++++++------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 5a8539d5f030..5455231f5188 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1497,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; @@ -2029,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); } -- cgit v1.2.3-70-g09d2 From 688088728bd3226ef24a2986e2fac2ae01cfbdd9 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 16 Jul 2021 01:34:19 +0800 Subject: mt76: mt7921: Add mt7922 support Add new chip mt7922 in mt7921 module with following items 1. new chip ID / fw bin name 2. is_mt7922() check chip type for different fw files 3. mt7921_get_data_mode() check security type of fw (backward compatible) Co-developed-by: Jimmy Hu Signed-off-by: Jimmy Hu Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 7 ++- drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 71 ++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 3 + drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 3 + 5 files changed, 80 insertions(+), 5 deletions(-) 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/mt7921/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c index 691d14a1a7bf..4d0a4aeac6bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c @@ -36,6 +36,7 @@ static int mt7921_check_eeprom(struct mt7921_dev *dev) val = get_unaligned_le16(eeprom); switch (val) { + case 0x7922: case 0x7961: return 0; default: diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 8d3cf4f99141..b686d62295ce 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) @@ -742,6 +750,46 @@ static int mt7921_driver_own(struct mt7921_dev *dev) return 0; } +static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info) +{ + u32 mode = DL_MODE_NEED_RSP; + + 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 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; @@ -759,7 +807,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; @@ -777,7 +825,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)); @@ -790,9 +839,11 @@ 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; @@ -889,13 +940,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 6e9e4dfb3928..51bcaa599268 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -33,6 +33,9 @@ #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 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 33782e1ee312..97ca8290881f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -14,6 +14,7 @@ static const struct pci_device_id mt7921_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922) }, { }, }; @@ -336,6 +337,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 "); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3-70-g09d2 From 02ee68b95d814f85c2c55a874bef3f15f2f972e5 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 17 Jul 2021 08:18:25 +0800 Subject: mt76: mt7915: add control knobs for thermal throttling With this patch, users can set the trigger/restore temperature for thermal service according to their use cases. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 40 ++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 17 +++------ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 + 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 906dacef5bdf..bfe13452af82 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; @@ -150,6 +180,10 @@ static int mt7915_thermal_init(struct mt7915_phy *phy) 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; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 5ed123a644ab..813092ca2a81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3544,10 +3544,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; @@ -3560,7 +3556,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); @@ -3568,15 +3564,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index a6b5b300d415..d06b7536bba6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -121,6 +121,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; -- cgit v1.2.3-70-g09d2 From 68232efffe4e5ecac28597ade3a92fd9ad9322d4 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 17 Jul 2021 13:05:48 +0800 Subject: mt76: mt7915: send EAPOL frames at lowest rate The firmware rate control may choose the high rate for EAPOL frames, so checking IEEE80211_TX_CTL_USE_MINRATE to use the lowest TX rate. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index dcee3a3890e5..1c6f066de2dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -948,7 +948,8 @@ mt7915_mac_write_txwi_80211(struct mt7915_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); -- cgit v1.2.3-70-g09d2 From 7780ba75c5da07cf55a88886691e94f3c71e82ad Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 17 Jul 2021 13:05:49 +0800 Subject: mt76: mt7921: send EAPOL frames at lowest rate The firmware rate control may choose the high rate for EAPOL frames, so checking IEEE80211_TX_CTL_USE_MINRATE to use the lowest TX rate. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index d64a266279d6..6ff8121741f9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -702,7 +702,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); -- cgit v1.2.3-70-g09d2 From 82a980f82a511ce74ab57eb9f692d02225eb32f4 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Tue, 20 Jul 2021 10:48:32 +0800 Subject: mt76: mt7915: fix potential overflow of eeprom page index If total eeprom size is divisible by per-page size, the i in for loop will exceed max page index, which happens in our newer chipset. Fixes: 26f18380e6ca ("mt76: mt7915: add support for flash mode") Signed-off-by: Bo Jiao Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 813092ca2a81..57c6dbcb1af3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3244,20 +3244,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; @@ -3267,7 +3267,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); -- cgit v1.2.3-70-g09d2 From 978fdd660c50e0c27644a9334c450e1de83ec2ae Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Tue, 20 Jul 2021 21:00:13 +0800 Subject: mt76: mt7915: switch proper tx arbiter mode in testmode Switch proper tx arbiter mode during testmode tx to prevent from entering the flow of normal tx in FW. Also, testmode SU and MU tx need to use different arbiter mode. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7915/testmode.c | 29 ++++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/testmode.h | 10 ++++++++ 3 files changed, 40 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 4142e27c93ca..79b3820c742b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -278,6 +278,7 @@ enum { MCU_EXT_CMD_SCS_CTRL = 0x82, 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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index b220b334906b..00dcc46b9082 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -165,6 +165,28 @@ mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs) sizeof(req), false); } +static int +mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu) +{ + struct mt7915_dev *dev = phy->dev; + struct { + __le32 cmd; + u8 op_mode; + } __packed req = { + .cmd = cpu_to_le32(MURU_SET_ARB_OP_MODE), + }; + + if (!enable) + req.op_mode = TAM_ARB_OP_MODE_NORMAL; + else if (mu) + req.op_mode = TAM_ARB_OP_MODE_TEST; + else + req.op_mode = TAM_ARB_OP_MODE_FORCE_SU; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req, + sizeof(req), false); +} + 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 +419,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 +464,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..107f0cf2505e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h @@ -96,4 +96,14 @@ enum { RF_OPER_WIFI_SPECTRUM, }; +enum { + TAM_ARB_OP_MODE_NORMAL = 1, + TAM_ARB_OP_MODE_TEST, + TAM_ARB_OP_MODE_FORCE_SU = 5, +}; + +enum { + MURU_SET_ARB_OP_MODE = 14, +}; + #endif -- cgit v1.2.3-70-g09d2 From 47f1c08db7f3aaa2d13f8e56209375462ace7b8a Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Tue, 20 Jul 2021 21:00:14 +0800 Subject: mt76: mt7915: fix bit fields for HT rate idx The bit fields of tx rate idx should be 6 bits, otherwise it might be incorrect in HT mode. For VHT/HE rates, only 4 bits are actually used by rate idx, the other 2 bits are used for other functions. Fixes: c31d94af1843 ("mt76: mt7915: fix tx rate related fields in tx descriptor") Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index ccce994dc07a..7a2c740d1464 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -280,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 -- cgit v1.2.3-70-g09d2 From 33920b2bf04834b286981763686be0bc9f141d40 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 21 Jul 2021 10:03:52 +0800 Subject: mt76: add support for setting mcast rate Mesh and ad-hoc interfaces allow users to set mcast rate through NL80211_ATTR_MCAST_RATE, so rework mt76_default_basic_rate() to adapt that. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 12 ++++++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 24 +++++++++++++++++------- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 ++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 7403a012ceed..3658328f513b 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1352,16 +1352,20 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, } EXPORT_SYMBOL_GPL(mt76_init_queue); -u16 mt76_default_basic_rate(struct mt76_phy *phy, struct ieee80211_vif *vif) +u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) { - int i = ffs(vif->bss_conf.basic_rates) - 1, offset = 0; + int offset = 0; struct ieee80211_rate *rate; if (phy->chandef.chan->band == NL80211_BAND_5GHZ) offset = 4; - rate = &mt76_rates[offset + i]; + /* 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_default_basic_rate); +EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index bf36f9227713..b1aeec661498 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -891,7 +891,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_default_basic_rate(struct mt76_phy *phy, struct ieee80211_vif *vif); +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) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 1c6f066de2dd..dfc5ea2cf7d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -904,17 +904,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) { @@ -940,15 +942,15 @@ 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; @@ -989,6 +991,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; @@ -1051,15 +1054,22 @@ 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)) { + u8 band = mphy->chandef.chan->band; + int rateidx, mcast_rate = vif->bss_conf.mcast_rate[band]; u16 rate, mode; /* hardware won't add HTC for mgmt/ctrl frame */ txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); - rate = mt76_default_basic_rate(mphy, vif); + if (mcast && mcast_rate > 0) + rateidx = mcast_rate - 1; + else + rateidx = ffs(vif->bss_conf.basic_rates) - 1; + + rate = mt76_calculate_default_rate(mphy, rateidx); mode = rate >> 8; rate &= GENMASK(7, 0); rate |= FIELD_PREP(MT_TX_RATE_MODE, mode); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 6ff8121741f9..945b2e24edad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -812,12 +812,13 @@ 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)) { + 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); - rate = mt76_default_basic_rate(mphy, vif); + rate = mt76_calculate_default_rate(mphy, rateidx); mode = rate >> 8; rate &= GENMASK(7, 0); rate |= FIELD_PREP(MT_TX_RATE_MODE, mode); -- cgit v1.2.3-70-g09d2 From a23f80aa9c5e6ad4ec8df88037b7ffd4162b1ec4 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Tue, 27 Jul 2021 17:47:09 +0800 Subject: mt76: mt7921: fix dma hang in rmmod The dma would be broken after rmmod flow. There are two different cases causing this issue. 1. dma access without privilege. 2. hw access sequence borken by another context. This patch handle both cases to avoid hw crash. Fixes: 2b9ea5a8cf1bd ("mt76: mt7921: add mt7921_dma_cleanup in mt7921_unregister_device") Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 49725caca7ed..3e84ef8f5358 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -266,8 +266,17 @@ int mt7921_register_device(struct mt7921_dev *dev) void mt7921_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_mcu_exit(dev); -- cgit v1.2.3-70-g09d2 From 781f62960c635cfed55a8f8c0f909bdaf8268257 Mon Sep 17 00:00:00 2001 From: Leon Yen Date: Wed, 28 Jul 2021 06:59:16 +0800 Subject: mt76: connac: fix GTK rekey offload failure on WPA mixed mode Update the proper firmware programming sequence to fix GTK rekey offload failure on WPA mixed mode. In the mt76_connac_mcu_key_iter, gtk_tlv->proto should be only set up on pairwise key and gtk_tlk->group_cipher should be only set up on the group key. Otherwise, those parameters required by firmware would be set incorrectly to cause GTK rekey offload failure on WPA mixed mode and then disconnection follows. Fixes: b47e21e75c80 ("mt76: mt7615: add gtk rekey offload support") Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Leon Yen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index a2555dc0f003..d71393b1c5e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1957,19 +1957,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); } } -- cgit v1.2.3-70-g09d2 From f3f1c04536b86b63cc4f3e571a44d8377c5f7ff6 Mon Sep 17 00:00:00 2001 From: YN Chen Date: Thu, 5 Aug 2021 06:23:00 +0800 Subject: mt76: connac: add support for limiting to maximum regulatory Tx power Consider .max_reg_power in struct ieee80211_channel to limit the maximum power the wireless device allowed to transmit on the corresponding channel according to the regulatory domain. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: YN Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 43 +++++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index d71393b1c5e6..80987af03efe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1773,6 +1773,43 @@ static s8 mt76_connac_get_sar_power(struct mt76_phy *phy, 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; + 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) @@ -1840,10 +1877,12 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, .hw_value = ch_list[idx], .band = band, }; - s8 sar_power; + 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, - tx_power); + reg_power); mt76_get_rate_power_limits(phy, &chan, &limits, sar_power); -- cgit v1.2.3-70-g09d2 From 82e0f5964737db3ba0457e941b6c7e3c008304b7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 9 Aug 2021 09:38:07 +0200 Subject: mt76: mt7921: get rid of monitor_vif Remove monitor_vif pointer from mt7921 since it is just a leftover of initial porting. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 7 ------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 -- 2 files changed, 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 7c4f97d65aae..b121a0e369c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -243,10 +243,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; @@ -306,9 +302,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 51bcaa599268..388522ff1059 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -126,8 +126,6 @@ struct mt7921_phy { struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; - struct ieee80211_vif *monitor_vif; - u32 rxfilter; u64 omac_mask; -- cgit v1.2.3-70-g09d2 From b30363102a4122f6eed37927b64a2c7ac70b8859 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 9 Aug 2021 10:38:03 +0200 Subject: mt76: mt7921: get rid of mt7921_mac_set_beacon_filter Remove mt7921_mac_set_beacon_filter routine since it is no longer used. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 28 ---------------------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 3 --- 2 files changed, 31 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 945b2e24edad..912036cc5fc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1505,34 +1505,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/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 388522ff1059..aaf86d867473 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -380,9 +380,6 @@ 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); -- cgit v1.2.3-70-g09d2 From 890809ca1986e63d29dd1591090af67b655ed89c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 9 Aug 2021 12:37:22 +0200 Subject: mt76: mt7921: introduce mt7921_mcu_set_beacon_filter utility routine Introduce mt7921_mcu_set_beacon_filter utility routine in order to remove duplicated code for hw beacon filtering. Move mt7921_pm_interface_iter in debugfs since it is just used there. Make the following routine static: - mt7921_pm_interface_iter - mt7921_mcu_uni_bss_bcnft - mt7921_mcu_set_bss_pm Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/debugfs.c | 20 ++++++--- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 33 +-------------- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 47 ++++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 8 ++-- 4 files changed, 45 insertions(+), 63 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 77468bdae460..da443ece0e1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -229,30 +229,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index b121a0e369c7..7ce014de3443 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -526,36 +526,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, @@ -585,7 +555,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) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index b686d62295ce..cadb633639d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1259,8 +1259,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 { @@ -1294,8 +1295,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 { @@ -1444,31 +1446,34 @@ out: return err; } -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/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index aaf86d867473..6a47ba65b96e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -362,6 +362,9 @@ 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); @@ -370,17 +373,12 @@ 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); -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); -- cgit v1.2.3-70-g09d2 From f6e1f59885dae5a2553f8bbd328be2cb1c80ccb2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 8 Aug 2021 21:11:49 +0200 Subject: mt76: overwrite default reg_ops if necessary Introduce mt76_register_debugfs_fops routine in order to define per-driver regs file operations and make sure the device is up before reading or writing its registers Fixes: 1d8efc741df8 ("mt76: mt7921: introduce Runtime PM support") Fixes: de5ff3c9d1a2 ("mt76: mt7615: introduce pm_power_save delayed work") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 10 +++++--- drivers/net/wireless/mediatek/mt76/mt76.h | 8 +++++- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 29 +++++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7921/debugfs.c | 28 ++++++++++++++++++++- 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index fa48cc3a7a8f..ad97308c7853 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -116,8 +116,11 @@ 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_dev *dev, + const struct file_operations *ops) { + const struct file_operations *fops = ops ? ops : &fops_regval; struct dentry *dir; dir = debugfs_create_dir("mt76", dev->hw->wiphy->debugfsdir); @@ -126,8 +129,7 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) 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 +142,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/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b1aeec661498..8e7fedfd1758 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -879,7 +879,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_dev *dev, + const struct file_operations *ops); +static inline struct dentry *mt76_register_debugfs(struct mt76_dev *dev) +{ + return mt76_register_debugfs_fops(dev, 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index cb4659771fd9..bda22ca0bd71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -2,6 +2,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) { @@ -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->mt76, &fops_regval); if (!dir) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index da443ece0e1d..29a24e768617 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -4,6 +4,32 @@ #include "mt7921.h" #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) { @@ -381,7 +407,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev) { struct dentry *dir; - dir = mt76_register_debugfs(&dev->mt76); + dir = mt76_register_debugfs_fops(&dev->mt76, &fops_regval); if (!dir) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 1f832887d75e5d5fcc5100ff7c0aaae06a68896a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 7 Aug 2021 09:40:30 +0200 Subject: mt76: mt7615: move mt7615_mcu_set_p2p_oppps in mt76_connac module Move mt7615_mcu_set_p2p_oppps routine in mt76_connac_lib module in order to be reused in mt7921 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 22 ---------------------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 -- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 20 ++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 ++ 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index dada43d6d879..457e50255250 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -567,8 +567,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 | diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index f8a09692d3e4..a39776833efd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2762,28 +2762,6 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, 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 { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index d0c64a9b09cf..58a98b5c0cbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -541,8 +541,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 80987af03efe..9cdd49bf1b67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1969,6 +1969,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 = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index ab77289c0541..43787ab224b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1094,4 +1094,6 @@ 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); #endif /* __MT76_CONNAC_MCU_H */ -- cgit v1.2.3-70-g09d2 From 4fee32153ab62356aeea9d152d8f33a5fd3a0086 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 13 Aug 2021 06:48:24 +0800 Subject: mt76: mt7921: report HE MU radiotap Report HE MU/BF radiotap. That fixed HE MU packets dropped by mac80211 because they are missing the ieee80211_radiotap_he_mu header. Fixes: 163f4d22c118d ("mt76: mt7921: add MAC support") Co-developed-by: Ryder Lee Signed-off-by: Ryder Lee Co-developed-by: Eric-SY Chang Signed-off-by: Eric-SY Chang Tested-by: Eric-SY Chang Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 65 ++++++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 8 +++ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 912036cc5fc9..1e845adcc0f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -180,12 +180,56 @@ mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); } +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 = 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] = FIELD_GET(MT_CRXV_HE_RU0, cpu_to_le32(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, cpu_to_le32(rxv[3])); + } + + if (status->bw >= RATE_INFO_BW_80) { + he_mu->ru_ch1[1] = + FIELD_GET(MT_CRXV_HE_RU2, cpu_to_le32(rxv[3])); + he_mu->ru_ch2[1] = + FIELD_GET(MT_CRXV_HE_RU3, cpu_to_le32(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 +237,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 +252,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 (cpu_to_le32(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 +265,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 +279,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); @@ -606,9 +651,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 3af67fac213d..f0194c878037 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) -- cgit v1.2.3-70-g09d2 From 4d2423326de9e9866f59df2b055b9cd1b4388743 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 7 Aug 2021 11:14:23 +0800 Subject: mt76: mt7915: add HE-LTF into fixed rate command Add HE-LTF control. Signed-off-by: Shayne Chen Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 13 +++++++------ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 1a48b09d0cb7..d9d18f662039 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -365,12 +365,14 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) #ifdef CONFIG_MAC80211_DEBUGFS /** per-station debugfs **/ -/* usage: */ 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: + * : see enum mt76_phy_type + */ return mt7915_mcu_set_fixed_rate(msta->vif->phy->dev, sta, rate); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 57c6dbcb1af3..173a9a324a2a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2317,10 +2317,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); @@ -2333,10 +2332,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 79b3820c742b..05c7981c503d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -948,6 +948,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; -- cgit v1.2.3-70-g09d2 From 99b8e195994d9d77de3bfe0cb403c44a57c2cf79 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 11 Aug 2021 13:58:24 +0800 Subject: mt76: mt7921: fix firmware usage of RA info using legacy rates According to the firmware usage, OFDM rates should fill out bit 6 - 13 while CCK rates should fill out bit 0 - 3 in legacy field of RA info to make the rate adaption runs propertly. Otherwise, a unicast frame might be picking up the unsupported rate to send out. Fixes: 1c099ab44727 ("mt76: mt7921: add MCU support") Reported-by: Joshua Emele Co-developed-by: YN Chen Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 11 ++++++++++- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 9cdd49bf1b67..9c0f86eefd75 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -719,6 +719,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) { @@ -767,7 +768,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 43787ab224b2..cb36dd39221c 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; -- cgit v1.2.3-70-g09d2 From 8e695328a1006b7bab2d972e7d0111fa6e6faf51 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 14 Aug 2021 02:09:18 +0800 Subject: mt76: mt7921: fix kernel warning from cfg80211_calculate_bitrate Fix the kernel warning from cfg80211_calculate_bitrate due to the legacy rate is not parsed well in the current driver. Also, zeros struct rate_info before we fill it out to avoid the old value is kept such as rate->legacy. [ 790.921560] WARNING: CPU: 7 PID: 970 at net/wireless/util.c:1298 cfg80211_calculate_bitrate+0x354/0x35c [cfg80211] [ 790.987738] Hardware name: MediaTek Asurada rev1 board (DT) [ 790.993298] pstate: a0400009 (NzCv daif +PAN -UAO) [ 790.998104] pc : cfg80211_calculate_bitrate+0x354/0x35c [cfg80211] [ 791.004295] lr : cfg80211_calculate_bitrate+0x180/0x35c [cfg80211] [ 791.010462] sp : ffffffc0129c3880 [ 791.013765] x29: ffffffc0129c3880 x28: ffffffd38305bea8 [ 791.019065] x27: ffffffc0129c3970 x26: 0000000000000013 [ 791.024364] x25: 00000000000003ca x24: 000000000000002f [ 791.029664] x23: 00000000000000d0 x22: ffffff8d108bc000 [ 791.034964] x21: ffffff8d108bc0d0 x20: ffffffc0129c39a8 [ 791.040264] x19: ffffffc0129c39a8 x18: 00000000ffff0a10 [ 791.045563] x17: 0000000000000050 x16: 00000000000000ec [ 791.050910] x15: ffffffd3f9ebed9c x14: 0000000000000006 [ 791.056211] x13: 00000000000b2eea x12: 0000000000000000 [ 791.061511] x11: 00000000ffffffff x10: 0000000000000000 [ 791.066811] x9 : 0000000000000000 x8 : 0000000000000000 [ 791.072110] x7 : 0000000000000000 x6 : ffffffd3fafa5a7b [ 791.077409] x5 : 0000000000000000 x4 : 0000000000000000 [ 791.082708] x3 : 0000000000000000 x2 : 0000000000000000 [ 791.088008] x1 : ffffff8d3f79c918 x0 : 0000000000000000 [ 791.093308] Call trace: [ 791.095770] cfg80211_calculate_bitrate+0x354/0x35c [cfg80211] [ 791.101615] nl80211_put_sta_rate+0x6c/0x2c0 [cfg80211] [ 791.106853] nl80211_send_station+0x980/0xaa4 [cfg80211] [ 791.112178] nl80211_get_station+0xb4/0x134 [cfg80211] [ 791.117308] genl_rcv_msg+0x3a0/0x440 [ 791.120960] netlink_rcv_skb+0xcc/0x118 [ 791.124785] genl_rcv+0x34/0x48 [ 791.127916] netlink_unicast+0x144/0x1dc Fixes: 1c099ab44727 ("mt76: mt7921: add MCU support") Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index cadb633639d3..9b35b5da3619 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -328,11 +328,13 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, struct rate_info *rate, u16 r) { struct ieee80211_supported_band *sband; - u16 flags = 0; + u16 flags = 0, rate_idx; u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r); u8 gi = 0; u8 bw = 0; + bool cck = false; + memset(rate, 0, sizeof(*rate)); rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r); rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1; @@ -357,13 +359,18 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, switch (txmode) { 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->legacy = sband->bitrates[rate->mcs].bitrate; + rate_idx = FIELD_GET(MT_TX_RATE_IDX, r); + rate_idx = mt76_get_rate(mphy->dev, sband, rate_idx, + cck); + rate->legacy = sband->bitrates[rate_idx].bitrate; break; case MT_PHY_TYPE_HT: case MT_PHY_TYPE_HT_GF: -- cgit v1.2.3-70-g09d2 From 67f938577b2ce7a1c6135d0ca77f26c9753cf9d0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Aug 2021 13:26:53 +0200 Subject: mt76: mt7921: fix endianness warnings in mt7921_mac_decode_he_mu_radiotap Fix the following sparse endianness warnings drivers/net/wireless/mediatek/mt76/mt7921/mac.c:212:28: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:212:28: warning: cast to restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:212:28: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:212:28: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:212:28: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:217:25: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:217:25: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:217:25: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:217:25: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:222:25: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:222:25: warning: cast to restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:222:25: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:222:25: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:222:25: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:224:25: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:224:25: warning: cast to restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:224:25: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:224:25: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:224:25: warning: restricted __le32 degrades to integer drivers/net/wireless/mediatek/mt76/mt7921/mac.c:259:13: warning: cast from restricted __le32 drivers/net/wireless/mediatek/mt76/mt7921/mac.c:259:13: warning: restricted __le32 degrades to integer Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 1e845adcc0f3..7425d57032f8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -194,7 +194,7 @@ mt7921_mac_decode_he_mu_radiotap(struct sk_buff *skb, .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 = NULL; + struct ieee80211_radiotap_he_mu *he_mu; he_mu = skb_push(skb, sizeof(mu_known)); memcpy(he_mu, &mu_known, sizeof(mu_known)); @@ -209,19 +209,19 @@ mt7921_mac_decode_he_mu_radiotap(struct sk_buff *skb, 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, cpu_to_le32(rxv[3])); + 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, cpu_to_le32(rxv[3])); + 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, cpu_to_le32(rxv[3])); + FIELD_GET(MT_CRXV_HE_RU2, le32_to_cpu(rxv[3])); he_mu->ru_ch2[1] = - FIELD_GET(MT_CRXV_HE_RU3, cpu_to_le32(rxv[3])); + FIELD_GET(MT_CRXV_HE_RU3, le32_to_cpu(rxv[3])); } } @@ -256,7 +256,7 @@ mt7921_mac_decode_he_radiotap(struct sk_buff *skb, he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | le16_encode_bits(ltf_size, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); - if (cpu_to_le32(rxv[0]) & MT_PRXV_TXBF) + 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]); -- cgit v1.2.3-70-g09d2 From 9aac2969fe5f8c3d7a827b73e4fe904e0abce9c2 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 16 Aug 2021 08:32:26 +0800 Subject: mt76: mt7915: update mac timing settings 1. EIFS has been divided into OFDM/CCK fields after 11ax generation. 2. For 5G/6G SIFS setting, hardware counts extra 6us for OFDM. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 14 ++++++-------- drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 5 ++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index dfc5ea2cf7d0..5439fa766182 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1572,17 +1572,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); @@ -1604,11 +1599,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 diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index a213b5cb82f8..91c1fb56b0ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -72,11 +72,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) -- cgit v1.2.3-70-g09d2 From f17f4864504d754bcbf31e4c89412cdf9946c409 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Fri, 18 Jun 2021 04:39:00 +0800 Subject: mt76: use IEEE80211_OFFLOAD_ENCAP_ENABLED instead of MT_DRV_AMSDU_OFFLOAD Drop MT_DRV_AMSDU_OFFLOAD after introducing IEEE80211_OFFLOAD_ENCAP_ENABLED flag in mac80211. Driver now checks vif->offload_flags to know encap offload status of each interface. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 8 ++------ drivers/net/wireless/mediatek/mt76/mt76.h | 1 - drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 3 +-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 3658328f513b..a8695d3d359e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -337,12 +337,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8e7fedfd1758..783ea555fa60 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -346,7 +346,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 340b364da5f0..e5a3f0ddaec3 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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 97ca8290881f..cd710360d180 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -99,8 +99,7 @@ static int mt7921_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 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, -- cgit v1.2.3-70-g09d2 From e63db6d35f79c1434139db103e6373500da253cf Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 4 Aug 2021 06:43:33 -0700 Subject: mt76: mt7915: fix he_mcs capabilities for 160mhz At 160, this chip can only do 2x2 NSS. Fix the features accordingly, verified it shows up properly in iw phy foo info now. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index bfe13452af82..a5b871efa971 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -646,12 +646,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++) { @@ -753,10 +760,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); -- cgit v1.2.3-70-g09d2 From 16bab114895ea574de8432a0e5f838af037b66ba Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 19 Aug 2021 13:49:43 -0700 Subject: mt76: mt7915: fix potential NPE in TXS processing If skb is null, then don't try to dereference it. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 5439fa766182..02e2b8f80720 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1328,7 +1328,7 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, 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]); @@ -1416,6 +1416,8 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, out: mt76_tx_status_skb_done(mdev, skb, &list); + +out_no_skb: mt76_tx_status_unlock(mdev, &list); return !!skb; -- cgit v1.2.3-70-g09d2 From 0421bf80579b5d17e2b9c892a33617337679839b Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Sun, 29 Aug 2021 01:02:38 +0800 Subject: mt76: mt7915: add LED support Initialize brightness_set and blink_set callbacks to enable LED support. The base 0x7c000000 is MCU space so driver can't touch it, and should map the LED base to 0x18000000 host's view. Signed-off-by: MeiChia Chiu Signed-off-by: Ryder Lee Signed-off-by: Money Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 69 ++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 19 +++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index a5b871efa971..311369c7e9c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -187,6 +187,64 @@ static int mt7915_thermal_init(struct mt7915_phy *phy) 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) @@ -341,6 +399,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) @@ -855,6 +918,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) 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/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 91c1fb56b0ed..4f7eb48634b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -57,6 +57,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) @@ -423,6 +424,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)) @@ -433,6 +448,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 -- cgit v1.2.3-70-g09d2 From b4b9f0a32d3106ba4d0bbd07312dc35d1f2152dc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 2 Jul 2021 19:44:09 +0200 Subject: mt76: mt7915: introduce bss coloring support Introduce mcu APIs to configure bss coloring and to report bss coloring collisions. Add support to report coloring countdown in beacon sent by the device. Co-developed-by: Ryder Lee Signed-off-by: Ryder Lee Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7915/main.c | 26 +++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 84 +++++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 21 +++--- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 + 5 files changed, 105 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 311369c7e9c2..4c4abda6dc6d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -324,6 +324,7 @@ 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); ieee80211_hw_set(hw, HAS_RATE_CONTROL); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 48b5e2051bad..440064e506c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -537,6 +537,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, @@ -585,6 +608,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 173a9a324a2a..65feb88be29a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -511,6 +511,15 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) (int)(skb->len - sizeof(*rxd)), data); } +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) { @@ -529,6 +538,11 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) 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; } @@ -557,6 +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_BCC_NOTIFY || !rxd->seq) mt7915_mcu_rx_unsolicited_event(dev, skb); else @@ -2388,25 +2403,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; @@ -2422,8 +2440,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, @@ -2471,9 +2495,9 @@ 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); + /* 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: @@ -3898,3 +3922,25 @@ 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); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 05c7981c503d..e02659272f9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -43,6 +43,7 @@ enum { MCU_EXT_EVENT_ASSERT_DUMP = 0x23, MCU_EXT_EVENT_RDD_REPORT = 0x3a, MCU_EXT_EVENT_CSA_NOTIFY = 0x4f, + MCU_EXT_EVENT_BCC_NOTIFY = 0x75, }; enum { @@ -503,6 +504,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; @@ -521,14 +530,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; @@ -1117,8 +1119,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/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index d06b7536bba6..2788ae529c7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -305,6 +305,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, -- cgit v1.2.3-70-g09d2 From 2c3b26f2bc1fe4f01195fd7cbd93cf440ac6358f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 31 Jul 2021 18:12:14 +0200 Subject: mt76: mt7915: improve code readability in mt7915_mcu_sta_bfer_ht Even if it is a not real issue, add missing brackets in mt7915_mcu_sta_bfer_ht routine in order to improve code readability Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 65feb88be29a..5a3dc04de31f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1775,7 +1775,7 @@ mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy, 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); -- cgit v1.2.3-70-g09d2 From ab06964eb96cedbfa7394abb0cdd8192c9317b66 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 8 Sep 2021 17:46:44 +0200 Subject: mt76: mt7915: fix WMM index on DBDC cards WMM index range needs to be split between both PHYs if a second PHY exists. The condition for that was accidentally written as checking if the vif PHY is the secondary one Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 440064e506c2..3caefafde62c 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 -- cgit v1.2.3-70-g09d2 From 0ab947c3dc8e0d611888c57dffd7b606c50fd338 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 16 Aug 2021 15:11:24 +0200 Subject: mt76: mt7921: move mt7921_queue_rx_skb to mac.c As for 7915 moving mt7921_queue_rx_skb makes it possible to make some functions in mac.c static Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 34 ------------------ drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 40 ++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 3 -- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 7d7d43a5422f..62cee662ba28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -19,40 +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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 7425d57032f8..e26ecfc2bdd3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -351,7 +351,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; @@ -1045,7 +1046,8 @@ void mt7921_txp_skb_unmap(struct mt76_dev *dev, } } -void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) +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; @@ -1141,6 +1143,40 @@ void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) mt76_worker_schedule(&dev->mt76.tx_worker); } +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_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { if (!e->txwi) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 6a47ba65b96e..547f777beb15 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -330,9 +330,6 @@ 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, -- cgit v1.2.3-70-g09d2 From 776ec4e77aa63e1417fcb1f2914a3882a96e0c87 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 17 Aug 2021 02:37:34 +0800 Subject: mt76: mt7915: rework debugfs queue info Complete PSE/PLE queue statistics, including per-sta AC queue information. Co-developed-by: Sujuan Chen Signed-off-by: Sujuan Chen Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 160 ++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 6 +- drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 19 ++- 3 files changed, 159 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index d9d18f662039..4377580fbdb4 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) { @@ -233,30 +240,131 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) 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; + 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_read(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + struct mt7915_phy *phy = mt7915_ext_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(s, "PLE page info:\n"); + seq_printf(s, "\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(s, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", + val, head, tail); + + seq_puts(s, "PLE non-empty queue info:\n"); + mt7915_hw_queue_read(s, MT_PLE_BASE, ARRAY_SIZE(ple_queue_map), + &ple_queue_map[0]); + + /* iterate per-sta ple queue */ + ieee80211_iterate_stations_atomic(dev->mphy.hw, + mt7915_sta_hw_queue_read, s); + if (phy) + ieee80211_iterate_stations_atomic(phy->mt76->hw, + mt7915_sta_hw_queue_read, s); + + /* pse queue */ + seq_puts(s, "PSE non-empty queue info:\n"); + mt7915_hw_queue_read(s, MT_PSE_BASE, ARRAY_SIZE(pse_queue_map), + &pse_queue_map[0]); return 0; } @@ -345,8 +453,8 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) 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_devm_seqfile(dev->mt76.dev, "hw-queues", dir, + mt7915_hw_queues_read); debugfs_create_file("tx_stats", 0400, dir, dev, &mt7915_tx_stats_fops); debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); debugfs_create_file("implicit_txbf", 0600, dir, dev, @@ -379,9 +487,23 @@ static int mt7915_sta_fixed_rate_set(void *data, u64 rate) DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL, mt7915_sta_fixed_rate_set, "%llx\n"); +static int +mt7915_queues_show(struct seq_file *s, void *data) +{ + struct ieee80211_sta *sta = s->private; + + mt7915_sta_hw_queue_read(s, sta); + + return 0; +} + +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("hw-queues", 0400, dir, sta, &mt7915_queues_fops); } + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 2788ae529c7f..ff3be5ba2ce9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -205,13 +205,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 { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 4f7eb48634b7..3cf81bbcf1d8 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)) -- cgit v1.2.3-70-g09d2 From 6e5ceaff752859cc80d60a1d2079a8c061c8bb1e Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 17 Aug 2021 02:37:35 +0800 Subject: mt76: mt7915: rename debugfs tx-queues Rename "queues" to "tx-queues" to reflect its meaning. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 4377580fbdb4..8c1725c00126 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -379,12 +379,11 @@ mt7915_queues_read(struct seq_file *s, void *data) 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->mphy.q_tx[MT_TXQ_BE], "MAIN" }, + { ext_q, "EXT" }, { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" }, { dev->mt76.q_mcu[MT_MCUQ_WA], "MCUWA" }, - { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" }, + { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" }, }; int i; @@ -451,7 +450,7 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) if (!dir) return -ENOMEM; - debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + debugfs_create_devm_seqfile(dev->mt76.dev, "tx-queues", dir, mt7915_queues_read); debugfs_create_devm_seqfile(dev->mt76.dev, "hw-queues", dir, mt7915_hw_queues_read); -- cgit v1.2.3-70-g09d2 From 569008744178b672ea3ad9047fa3098f1b73ca55 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Aug 2021 10:20:57 +0200 Subject: mt76: mt7921: always wake device if necessary in debugfs Add missing device wakeup in debugfs code if we are accessing chip registers. Fixes: 1d8efc741df8 ("mt76: mt7921: introduce Runtime PM support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 29a24e768617..599e6e53e94f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -95,6 +95,8 @@ mt7921_tx_stats_show(struct seq_file *file, void *data) struct mt7921_dev *dev = file->private; int stat[8], i, n; + mt7921_mutex_acquire(dev); + mt7921_ampdu_stat_read_phy(&dev->phy, file); /* Tx amsdu info */ @@ -104,6 +106,8 @@ mt7921_tx_stats_show(struct seq_file *file, void *data) n += stat[i]; } + mt7921_mutex_release(dev); + 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]); @@ -124,6 +128,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; @@ -143,6 +149,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; } -- cgit v1.2.3-70-g09d2 From cf592be1d734ea139c815e78751c5dbcdaa2aed9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Aug 2021 10:23:14 +0200 Subject: mt76: mt7921: update mib counters dumping phy stats mt7921 mac work can be idle for a long time due to runtime-pm so update mib counters dumping phy stats Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 599e6e53e94f..11f8acf4f59e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -68,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)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index e26ecfc2bdd3..99db8c68713f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1483,8 +1483,7 @@ 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 547f777beb15..5aac76dba90c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -338,6 +338,7 @@ 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, -- cgit v1.2.3-70-g09d2 From 4fb0a7d26ab0516cacdb2cc1784c9694680d24ec Mon Sep 17 00:00:00 2001 From: jing yangyang Date: Thu, 19 Aug 2021 19:41:17 -0700 Subject: mt76: fix boolreturn.cocci warnings ./drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c:172:8-9:WARNING: return of 0/1 in function 'mt7663_usb_sdio_tx_status_data' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: scripts/coccinelle/misc/boolreturn.cocci Reported-by: Zeal Robot Signed-off-by: jing yangyang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); -- cgit v1.2.3-70-g09d2 From a2e759612e5ff3858856fe97be5245eecb84e29b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 22 Aug 2021 09:39:45 +0200 Subject: mt76: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below. It has been compile tested. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) 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/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 11f169cdd603..7a54ea6a86d0 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index b795e7245c07..92ddb8c68938 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index adf288e50e21..fb8de1833937 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index e5a3f0ddaec3..0af4cdb897b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -250,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/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index cd710360d180..44075f8f6e79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -132,7 +132,7 @@ 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; -- cgit v1.2.3-70-g09d2 From abe3f3da670981b6d7241c73a664ed850c8c3b9f Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 25 Aug 2021 04:35:16 +0800 Subject: mt76: fill boottime_ns in Rx path Give a proper boottime_ns value for netlink RX to avoid scan issues with Android. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index a8695d3d359e..bbe7ba64ccd2 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -801,6 +801,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); @@ -823,6 +824,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)); -- cgit v1.2.3-70-g09d2 From 970be1dff26dc387591688a08e4c21ebd13c3fc2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 24 Sep 2021 17:54:40 +0200 Subject: mt76: disable BH around napi_schedule() calls napi_schedule() can call __raise_softirq_irqoff(), which can perform softirq handling, so it must not be called in a pure process context with BH enabled. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 7 +++++-- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 6 ++++-- drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 5 +++++ drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 3 +++ 9 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 3972c56136a2..d1cbe06ee8da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 7a54ea6a86d0..b808248943ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -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..0a4caddeb75d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -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/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 92ddb8c68938..f19228fc5a70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -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_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index b50084bbe83d..f4451fbec958 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -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/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index fb8de1833937..8a22ee581674 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -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/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 02e2b8f80720..81cde3c1d915 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1837,6 +1837,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]); @@ -1845,6 +1846,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 99db8c68713f..4023e0aba3f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1390,10 +1390,12 @@ mt7921_mac_reset(struct mt7921_dev *dev) 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); @@ -1418,8 +1420,11 @@ mt7921_mac_reset(struct mt7921_dev *dev) 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.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 44075f8f6e79..b5622b612613 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -302,12 +302,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) -- cgit v1.2.3-70-g09d2 From 68ee6a14fe628d3d56dec8535f41a2a4f3ae6709 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sun, 29 Aug 2021 04:01:02 +0800 Subject: mt76: mt7915: enable configured beacon tx rate The user is allowed to change beacon tx rate (HT/VHT/HE) from hostapd. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 ++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 59 ++++++++++++++++++------ 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 4c4abda6dc6d..d87b151fdca4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -326,6 +326,10 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 81cde3c1d915..5e29707a5464 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -981,6 +981,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) @@ -1057,23 +1102,11 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, mt7915_mac_write_txwi_80211(dev, txwi, skb, key, &mcast); if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { - u8 band = mphy->chandef.chan->band; - int rateidx, mcast_rate = vif->bss_conf.mcast_rate[band]; - u16 rate, mode; + 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 (mcast && mcast_rate > 0) - rateidx = mcast_rate - 1; - else - rateidx = ffs(vif->bss_conf.basic_rates) - 1; - - 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); -- cgit v1.2.3-70-g09d2 From 0ae3ff5684514d72357240f1033a7494c51f93ed Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 2 Sep 2021 13:52:03 +0800 Subject: mt76: mt7915: fix hwmon temp sensor mem use-after-free Without this change, garbage is seen in the hwmon name and sensors output for mt7915 is garbled. It appears that the hwmon logic does not make a copy of the incoming string, but instead just copies a char* and expects it to never go away. Fixes: 33fe9c639c13 ("mt76: mt7915: add thermal sensor device support") Signed-off-by: Ben Greear Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index d87b151fdca4..30d51b640bf9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -160,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) @@ -174,8 +177,7 @@ 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); -- cgit v1.2.3-70-g09d2 From 0bb4e9187ea4a59dc6658a62978deda0c0dc4b28 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 2 Sep 2021 13:52:04 +0800 Subject: mt76: mt7615: fix hwmon temp sensor mem use-after-free Without this change, garbage is seen in the hwmon name and sensors output for mt7615 is garbled. Fixes: 109e505ad944 ("mt76: mt7615: add thermal sensor device support") Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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); -- cgit v1.2.3-70-g09d2 From 159d95d4737fc5157e369609f5d706c26e1b1e8f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 4 Sep 2021 12:16:43 +0200 Subject: mt76: mt7921: start reworking tx rate reporting Similar to mt7915, introduce mt7921_txwi_free to report tx rate to mac80211. This is a preliminary patch to add proper tx status report. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 76 ++++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 - 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 4023e0aba3f0..b3574e249167 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -981,7 +981,7 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) static void mt7921_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, - struct ieee80211_sta *sta, u8 stat, + struct ieee80211_sta *sta, bool clear_status, struct list_head *free_list) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1005,7 +1005,7 @@ mt7921_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_AMPDU) info->flags |= IEEE80211_TX_STAT_AMPDU; - if (stat) + if (clear_status) ieee80211_tx_info_clear_status(info); if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -1015,8 +1015,8 @@ mt7921_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, ieee80211_tx_status_ext(hw, &status); } -void mt7921_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *t) +static void +mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { struct mt7921_txp_common *txp; int i; @@ -1046,6 +1046,42 @@ void mt7921_txp_skb_unmap(struct mt76_dev *dev, } } +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; + struct ieee80211_tx_info *info; + __le32 *txwi; + + mt7921_txp_skb_unmap(mdev, t); + if (!t->skb) + goto out; + + if (!sta) + goto out; + + txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); + if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7921_tx_check_aggr(sta, txwi); + + info = IEEE80211_SKB_CB(t->skb); + if (!info->tx_time_est) { + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + int pending; + + pending = atomic_dec_return(&wcid->non_aql_packets); + if (pending < 0) + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); + } + + mt7921_tx_complete_status(mdev, t->skb, sta, clear_status, 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) { @@ -1105,28 +1141,7 @@ mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) if (!txwi) continue; - 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); - - if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7921_tx_check_aggr(sta, txwi_ptr); - - if (sta && !info->tx_time_est) { - struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; - int pending; - - pending = atomic_dec_return(&wcid->non_aql_packets); - if (pending < 0) - atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); - } - - mt7921_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list); - txwi->skb = NULL; - } - - mt76_put_txwi(mdev, txwi); + mt7921_txwi_free(dev, txwi, sta, stat, &free_list); } if (wake) @@ -1334,14 +1349,7 @@ void mt7921_tx_token_put(struct mt7921_dev *dev) 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); + mt7921_txwi_free(dev, txwi, NULL, false, NULL); dev->mt76.token_count--; } spin_unlock_bh(&dev->mt76.token_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 5aac76dba90c..0baa9b37aeda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -354,8 +354,6 @@ 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); -- cgit v1.2.3-70-g09d2 From 273910ac437523fab13bfc22cb54a32158f20ba0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 4 Sep 2021 12:16:44 +0200 Subject: mt76: mt7921: add support for tx status reporting Introduce infrastructure support for tx status reporting Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 102 ++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 7 ++ drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 3 - 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index b3574e249167..948428f50db5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -801,9 +801,11 @@ static void mt7921_update_txs(struct mt76_wcid *wcid, __le32 *txwi) 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) +static 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) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; @@ -852,7 +854,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; @@ -943,7 +950,7 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return id; mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, - false); + MT_PACKET_ID_NO_SKB, false); txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); memset(txp, 0, sizeof(struct mt7921_txp_common)); @@ -1158,11 +1165,89 @@ mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) mt76_worker_schedule(&dev->mt76.tx_worker); } +static bool +mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, + __le32 *txs_data) +{ + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_tx_info *info; + struct sk_buff_head list; + struct sk_buff *skb; + + mt76_tx_status_lock(mdev, &list); + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (!skb) + goto out; + + info = IEEE80211_SKB_CB(skb); + if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK))) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & + IEEE80211_TX_STAT_ACK); + + info->status.rates[0].idx = -1; + mt76_tx_status_skb_done(mdev, skb, &list); + +out: + mt76_tx_status_unlock(mdev, &list); + + return !!skb; +} + +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; + + txs = le32_to_cpu(txs_data[0]); + if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) + return; + + txs = le32_to_cpu(txs_data[2]); + wcidx = FIELD_GET(MT_TXS2_WCID, txs); + + txs = le32_to_cpu(txs_data[3]); + pid = FIELD_GET(MT_TXS3_PID, txs); + + if (pid < MT_PACKET_ID_FIRST) + return; + + if (wcidx >= MT7921_WTBL_SIZE) + return; + + rcu_read_lock(); + + wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + if (!wcid) + goto out; + + mt7921_mac_add_txs_skb(dev, wcid, pid, txs_data); + + if (!wcid->sta) + goto out; + + 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); + +out: + rcu_read_unlock(); +} + 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; + __le32 *end = (__le32 *)&skb->data[skb->len]; enum rx_pkt_type type; u16 flag; @@ -1179,6 +1264,11 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, 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)) { @@ -1545,6 +1635,8 @@ void mt7921_mac_work(struct work_struct *work) } mt7921_mutex_release(phy->dev); + + mt76_tx_status_check(mphy->dev, NULL, false); ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, MT7921_WATCHDOG_TIME); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index f0194c878037..4b29d2728f4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -317,6 +317,13 @@ struct mt7921_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) +#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) +#define MT_TXS0_TXS_FORMAT GENMASK(24, 23) + +#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) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 0baa9b37aeda..761fc605e5e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -326,9 +326,6 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev) 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_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -- cgit v1.2.3-70-g09d2 From 970ab80ef9f63f01c7272db1e756d2764cfe8f89 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 4 Sep 2021 12:16:45 +0200 Subject: mt76: mt7921: report tx rate directly from tx status Report tx rate from tx status packets instead of receiving periodic mcu event. This improves flexibility, accuracy and AQL performance, and simplifies code flow for better readability. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 229 +++++++++++++-------- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 15 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 22 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 - 4 files changed, 166 insertions(+), 102 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 948428f50db5..053d44d5ba64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -61,6 +61,7 @@ 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); @@ -71,8 +72,9 @@ static void mt7921_mac_sta_poll(struct mt7921_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)) { @@ -85,7 +87,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,6 +128,43 @@ static void mt7921_mac_sta_poll(struct mt7921_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 = 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; + } } rcu_read_unlock(); @@ -783,24 +822,6 @@ 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; - - frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, le32_to_cpu(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)); -} - static void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, @@ -885,8 +906,6 @@ mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } - - mt7921_update_txs(wcid, txwi); } static void @@ -928,10 +947,9 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, 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; + int id, pid; u8 *txwi = (u8 *)txwi_ptr; if (unlikely(tx_info->skb->len <= ETH_HLEN)) @@ -940,8 +958,6 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, 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; @@ -949,8 +965,18 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (id < 0) return id; + if (sta) { + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + + if (time_after(jiffies, msta->stats.jiffies + HZ / 4)) { + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + msta->stats.jiffies = jiffies; + } + } + + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, - MT_PACKET_ID_NO_SKB, false); + pid, false); txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE); memset(txp, 0, sizeof(struct mt7921_txp_common)); @@ -986,42 +1012,6 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) ieee80211_start_tx_ba_session(sta, tid, 0); } -static void -mt7921_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, - struct ieee80211_sta *sta, bool clear_status, - struct list_head *free_list) -{ - 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; - - if (sta) { - struct mt7921_sta *msta; - - msta = (struct mt7921_sta *)sta->drv_priv; - status.rate = &msta->stats.tx_rate; - } - - hw = mt76_tx_status_get_hw(mdev, skb); - - if (info->flags & IEEE80211_TX_CTL_AMPDU) - info->flags |= IEEE80211_TX_STAT_AMPDU; - - if (clear_status) - ieee80211_tx_info_clear_status(info); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.tx_time = 0; - ieee80211_tx_status_ext(hw, &status); -} - static void mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { @@ -1059,31 +1049,27 @@ mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t, struct list_head *free_list) { struct mt76_dev *mdev = &dev->mt76; - struct ieee80211_tx_info *info; __le32 *txwi; + u16 wcid_idx; mt7921_txp_skb_unmap(mdev, t); if (!t->skb) goto out; - if (!sta) - goto out; - txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); - if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7921_tx_check_aggr(sta, txwi); - - info = IEEE80211_SKB_CB(t->skb); - if (!info->tx_time_est) { + if (sta) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; - int pending; - pending = atomic_dec_return(&wcid->non_aql_packets); - if (pending < 0) - atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); + 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])); } - mt7921_tx_complete_status(mdev, t->skb, sta, clear_status, free_list); + __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); + out: t->skb = NULL; mt76_put_txwi(mdev, t); @@ -1169,10 +1155,14 @@ static bool mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data) { + 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; struct sk_buff *skb; + bool cck = false; + u32 txrate, txs; mt76_tx_status_lock(mdev, &list); skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); @@ -1180,7 +1170,8 @@ mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, goto out; info = IEEE80211_SKB_CB(skb); - if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK))) + txs = le32_to_cpu(txs_data[0]); + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) info->flags |= IEEE80211_TX_STAT_ACK; info->status.ampdu_len = 1; @@ -1188,9 +1179,78 @@ mt7921_mac_add_txs_skb(struct mt7921_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); + + if (!wcid->sta) + goto out; + + 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; + + switch (FIELD_GET(MT_TX_RATE_MODE, txrate)) { + 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; + + 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; + + 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; + } + + switch (FIELD_GET(MT_TXS0_BW, txs)) { + 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; + } + wcid->rate = rate; out: + if (skb) + mt76_tx_status_skb_done(mdev, skb, &list); mt76_tx_status_unlock(mdev, &list); return !!skb; @@ -1301,15 +1361,8 @@ void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) e->skb = t ? t->skb : NULL; } - if (e->skb) { - struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb); - struct mt76_wcid *wcid; - - wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]); - - mt7921_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0, - NULL); - } + if (e->skb) + mt76_tx_complete_skb(mdev, e->wcid, e->skb); } void mt7921_mac_reset_counters(struct mt7921_phy *phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 4b29d2728f4d..ad2e52c97aa8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -317,8 +317,10 @@ struct mt7921_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) -#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) +#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) @@ -365,4 +367,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 7ce014de3443..874c7c18ad09 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1012,22 +1012,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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 761fc605e5e9..26f175ef505e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -93,8 +93,6 @@ struct mt7921_sta { unsigned long ampdu_state; struct mt7921_sta_key_conf bip; - - unsigned long next_txs_ts; }; DECLARE_EWMA(rssi, 10, 8); -- cgit v1.2.3-70-g09d2 From 8c19b3fe6942bba9418042f345a2d8b3a3834d17 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 4 Sep 2021 12:16:46 +0200 Subject: mt76: mt7921: remove mcu rate reporting code Remove unused tx rate reporting through mcu tx done event since now tx status is fully supported Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 1 - drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 4 - drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 - drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 140 --------------------- drivers/net/wireless/mediatek/mt76/mt7921/mcu.h | 47 ------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 - 6 files changed, 198 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 3e84ef8f5358..f94d0f4862c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -202,7 +202,6 @@ int mt7921_register_device(struct mt7921_dev *dev) mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 053d44d5ba64..68ab61d4f061 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1105,7 +1105,6 @@ mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) */ if (info & MT_TX_FREE_PAIR) { struct mt7921_sta *msta; - struct mt7921_phy *phy; struct mt76_wcid *wcid; u16 idx; @@ -1117,10 +1116,7 @@ mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb) continue; 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 874c7c18ad09..8a7b4e78c097 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -264,7 +264,6 @@ 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; @@ -581,7 +580,6 @@ 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; @@ -657,8 +655,6 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 9b35b5da3619..f49fc8078125 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -322,101 +322,6 @@ exit: 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, rate_idx; - u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r); - u8 gi = 0; - u8 bw = 0; - bool cck = false; - - memset(rate, 0, sizeof(*rate)); - 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: - 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_idx = FIELD_GET(MT_TX_RATE_IDX, r); - rate_idx = mt76_get_rate(mphy->dev, sband, rate_idx, - cck); - rate->legacy = sband->bitrates[rate_idx].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; - } -} - static void mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) { @@ -516,48 +421,6 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) trace_lp_event(dev, event->state); } -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, - le16_to_cpu(event->tx_rate)); - return; - } - spin_unlock_bh(&dev->sta_poll_lock); -} - static void mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) { @@ -584,9 +447,6 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) 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; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index c4fc74991fd4..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,34 +274,6 @@ struct mt7921_txpwr_event { struct mt7921_txpwr txpwr; } __packed; -struct mt7921_mcu_tx_done_event { - u8 pid; - u8 status; - __le16 seq; - - u8 wlan_idx; - u8 tx_cnt; - __le16 tx_rate; - - u8 flag; - u8 tid; - u8 rsp_rate; - u8 mcs; - - u8 bw; - u8 tx_pwr; - u8 reason; - u8 rsv0[1]; - - __le32 delay; - __le32 timestamp; - __le32 applied_flag; - - u8 txs[28]; - - u8 rsv1[32]; -} __packed; - enum { TM_SWITCH_MODE, TM_SET_AT_CMD, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 26f175ef505e..61fa53af3840 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -84,7 +84,6 @@ struct mt7921_sta { struct mt7921_vif *vif; - struct list_head stats_list; struct list_head poll_list; u32 airtime_ac[8]; @@ -136,7 +135,6 @@ struct mt7921_phy { u32 ampdu_ref; struct mib_stats mib; - struct list_head stats_list; u8 sta_work_count; -- cgit v1.2.3-70-g09d2 From 1799c220d8075ccaa30e6a3b69f5bef71e620e92 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 4 Sep 2021 12:16:47 +0200 Subject: mt76: mt7921: remove mt7921_sta_stats mt7921_sta_stats is no longer needed Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 12 +----------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 68ab61d4f061..3684b3bafca0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -968,9 +968,9 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (sta) { struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; - if (time_after(jiffies, msta->stats.jiffies + HZ / 4)) { + if (time_after(jiffies, msta->last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->stats.jiffies = jiffies; + msta->last_txs = jiffies; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 8a7b4e78c097..217ed7055aa0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -586,7 +586,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 61fa53af3840..a6caca73fdda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -65,15 +65,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]; @@ -87,8 +78,7 @@ struct mt7921_sta { struct list_head poll_list; u32 airtime_ac[8]; - struct mt7921_sta_stats stats; - + unsigned long last_txs; unsigned long ampdu_state; struct mt7921_sta_key_conf bip; -- cgit v1.2.3-70-g09d2 From b5cdb4f9d14947ebdfd717e2f467f44041dd850e Mon Sep 17 00:00:00 2001 From: Xingbang Liu Date: Fri, 10 Sep 2021 13:39:28 +0800 Subject: mt76: move spin_lock_bh to spin_lock in tasklet as you are already in a tasklet, it is unnecessary to call spin_lock_bh. Signed-off-by: Xingbang Liu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index f4451fbec958..468be651010d 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) -- cgit v1.2.3-70-g09d2 From 706dc08c2936be970f171e6b095db99493406c72 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 12 Sep 2021 17:49:50 +0200 Subject: mt76: mt7915: honor all possible error conditions in mt7915_mcu_init() Check all possible errors returned in mt7915_mcu_init routine. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 5a3dc04de31f..f07d935c52b2 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 @@ -2889,11 +2889,16 @@ 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; + + 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) -- cgit v1.2.3-70-g09d2 From e500c9470e26be66eb2bc6de773ae9091149118a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 14 Sep 2021 18:42:51 +0200 Subject: mt76: mt7915: fix possible infinite loop release semaphore Fix possible infinite loop in mt7915_load_patch if mt7915_mcu_patch_sem_ctrl always returns an error. Fixes: e57b7901469fc ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index f07d935c52b2..7415b9391175 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2668,7 +2668,7 @@ out: default: ret = -EAGAIN; dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); - goto out; + break; } release_firmware(fw); -- cgit v1.2.3-70-g09d2 From 3a0098768761d335222a7f437870fd23287819f7 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 14 Sep 2021 23:50:21 +0800 Subject: mt76: mt7921: robustify hardware initialization flow Robustify hardware initialization in the current driver probing flow to get rid of the device is possibly lost after the machine boot due to possible firmware abnormal state by trying to recover the failure with more chances. Tested-by: Leon Yen Tested-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 53 ++++++++++++++++------ drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index f94d0f4862c4..4ef54343cef3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -146,33 +146,60 @@ int mt7921_mac_init(struct mt7921_dev *dev) return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); } -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); + struct mt76_dev *mdev = &dev->mt76; + 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; + if (ret) + goto out; ret = mt7921_mcu_set_eeprom(dev); + if (ret) + goto out; + + ret = mt7921_mac_init(dev); +out: + if (ret && mdev->eeprom.data) { + devm_kfree(mdev->dev, mdev->eeprom.data); + mdev->eeprom.data = NULL; + } + + return ret; +} + +static int mt7921_init_hardware(struct mt7921_dev *dev) +{ + int ret, idx, i; + + ret = mt7921_dma_init(dev); if (ret) return ret; + 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_wpdma_reset(dev, true); + } + + 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); if (idx) @@ -183,7 +210,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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index a6caca73fdda..16d7d159a71c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -29,6 +29,7 @@ #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" -- cgit v1.2.3-70-g09d2 From 02d1c7d494d8052288bc175e4ff54b56d08a3c5f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 14 Sep 2021 23:50:22 +0800 Subject: mt76: mt7921: fix retrying release semaphore without end We should pass the error code to the caller immediately to avoid the possible infinite retry to release the semaphore. Fixes: 1c099ab44727 ("mt76: mt7921: add MCU support") Co-developed-by: YN Chen Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index f49fc8078125..56fb7e54e283 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -736,7 +736,7 @@ out: default: ret = -EAGAIN; dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); - goto out; + break; } release_firmware(fw); -- cgit v1.2.3-70-g09d2 From 95bc1457f66a4297676e725a4dbb50cd36d38ba4 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 4 Aug 2021 06:43:29 -0700 Subject: mt76: mt7915: add ethtool stats support This exposes some tx-path stats to the ethtool API, so that ethtool -S wlanX provides some more useful info. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 129 +++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 3caefafde62c..d643df8f3d19 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1054,6 +1054,132 @@ 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_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", +}; + +#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_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); + + /* See mt7915_ampdu_stat_read_phy, etc */ + bool ext_phy = phy != &dev->phy; + int i, n, ei = 0; + + /* 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 */ + cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy)); + data[ei++] = FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt); + data[ei++] = FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt); + + /* Tx Beamformer Rx feedback monitor */ + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy)); + data[ei++] = FIELD_GET(MT_ETBF_RX_FB_ALL, cnt); + data[ei++] = FIELD_GET(MT_ETBF_RX_FB_HE, cnt); + data[ei++] = FIELD_GET(MT_ETBF_RX_FB_VHT, cnt); + data[ei++] = FIELD_GET(MT_ETBF_RX_FB_HT, cnt); + + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy)); + data[ei++] = FIELD_GET(MT_ETBF_RX_FB_BW, cnt); + data[ei++] = FIELD_GET(MT_ETBF_RX_FB_NC, cnt); + data[ei++] = FIELD_GET(MT_ETBF_RX_FB_NR, cnt); + + /* Tx Beamformee Rx NDPA & Tx feedback report */ + cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy)); + data[ei++] = FIELD_GET(MT_ETBF_TX_FB_CPL, cnt); + data[ei++] = FIELD_GET(MT_ETBF_TX_FB_TRI, cnt); + + /* Tx SU & MU counters */ + cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy)); + data[ei++] = FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt); + + cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy)); + data[ei++] = cnt; + + cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy)); + data[ei++] = cnt; /* MU MPDU SUccessful */ + + cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy)); + data[ei++] = cnt; /* SU MPDU successful */ + + /* Tx amsdu info (pack-count histogram) */ + for (i = 0; i < 8; i++) + data[ei++] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + + WARN_ON(ei != MT7915_SSTATS_LEN); +} + const struct ieee80211_ops mt7915_ops = { .tx = mt7915_tx, .start = mt7915_start, @@ -1078,6 +1204,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, -- cgit v1.2.3-70-g09d2 From c4c2a370300e10f03afb762aa762ff0ec09e0006 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 4 Aug 2021 06:43:30 -0700 Subject: mt76: mt7915: add tx stats gathered from tx-status callbacks Add tx-mode (ofdma, ht, vht, HE) histogram, tx-ru-idx histogram, and tx-bandwidth histogram. Also add tx attempts and tx success counters. All of this is per-station. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 26 +++++++++++++++------- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 11 +++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 783ea555fa60..f4dd61c5ecb8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -761,6 +761,7 @@ 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, }; #define CCK_RATE(_idx, _rate) { \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 5e29707a5464..1563e27e161a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1346,7 +1346,7 @@ 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 mt7915_sta_stats *stats) { struct ieee80211_supported_band *sband; struct mt76_dev *mdev = &dev->mt76; @@ -1356,7 +1356,7 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, struct rate_info rate = {}; struct sk_buff *skb; bool cck = false; - u32 txrate, txs; + u32 txrate, txs, mode; mt76_tx_status_lock(mdev, &list); skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); @@ -1375,15 +1375,18 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, info->status.rates[0].idx = -1; - if (!wcid->sta) - goto out; - 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; - switch (FIELD_GET(MT_TX_RATE_MODE, txrate)) { + 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; @@ -1431,18 +1434,24 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, 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; @@ -1487,12 +1496,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index ff3be5ba2ce9..3c1ba6f4c6e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -62,6 +62,13 @@ enum mt7915_rxq_id { MT7915_RXQ_MCU_WA_EXT, }; +struct mt7915_sta_stats { + unsigned long tx_mode[__MT_PHY_TYPE_HE_MAX]; /* See mt76_phy_type */ + unsigned long tx_bw[4]; /* 20, 40, 80, 160 */ + unsigned long tx_nss[4]; /* 1, 2, 3, 4 */ + unsigned long tx_mcs[16]; /* mcs idx */ +}; + struct mt7915_sta_key_conf { s8 keyidx; u8 key[16]; @@ -80,8 +87,11 @@ struct mt7915_sta { unsigned long jiffies; unsigned long ampdu_state; + struct mt7915_sta_stats stats; + struct mt7915_sta_key_conf bip; }; + struct mt7915_vif { u16 idx; u8 omac_idx; @@ -101,6 +111,7 @@ struct mib_stats { u32 rts_cnt; u32 rts_retries_cnt; u32 ba_miss_cnt; + /* Add more stats here, updated from mac_update_stats */ }; struct mt7915_hif { -- cgit v1.2.3-70-g09d2 From bc529ee3a7b89419e039a36acdeec99634eee4af Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 4 Aug 2021 06:43:31 -0700 Subject: mt76: mt7915: add some per-station tx stats to ethtool The tx status callback is not called for every frame, so those specific counters under-count, but at least they give some idea of what is going on. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 86 +++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index d643df8f3d19..6f66cd4ca269 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1094,6 +1094,32 @@ static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_msdu_pack_6", "tx_msdu_pack_7", "tx_msdu_pack_8", + /* 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) @@ -1119,6 +1145,47 @@ int mt7915_get_et_sset_count(struct ieee80211_hw *hw, return 0; } +struct mt7915_ethtool_worker_info { + u64 *data; + struct mt7915_vif *mvif; + int initial_stat_idx; + int worker_stat_count; + int sta_count; +}; + +static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) +{ + struct mt7915_ethtool_worker_info *wi = wi_data; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + int ei = wi->initial_stat_idx; + int q; + u64 *data = wi->data; + struct mt7915_sta_stats *mstats = &msta->stats; + + if (msta->vif != wi->mvif) + return; + + wi->sta_count++; + + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_CCK]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_OFDM]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HT]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HT_GF]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_VHT]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_SU]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_TB]; + data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_MU]; + + for (q = 0; q < ARRAY_SIZE(mstats->tx_bw); q++) + data[ei++] += mstats->tx_bw[q]; + + for (q = 0; q < 12; q++) + data[ei++] += mstats->tx_mcs[q]; + + wi->worker_stat_count = ei - wi->initial_stat_idx; +} + static void mt7915_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1126,6 +1193,8 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, { 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 mt7915_ethtool_worker_info wi; /* See mt7915_ampdu_stat_read_phy, etc */ bool ext_phy = phy != &dev->phy; @@ -1177,7 +1246,22 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, for (i = 0; i < 8; i++) data[ei++] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); - WARN_ON(ei != MT7915_SSTATS_LEN); + /* Add values for all stations owned by this vif */ + wi.data = data; + wi.mvif = mvif; + wi.initial_stat_idx = ei; + wi.worker_stat_count = 0; + wi.sta_count = 0; + + ieee80211_iterate_stations_atomic(hw, mt7915_ethtool_worker, &wi); + + 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); } const struct ieee80211_ops mt7915_ops = { -- cgit v1.2.3-70-g09d2 From 016f2040591f97ebb093d205f90fc02032f775c0 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 4 Aug 2021 06:43:32 -0700 Subject: mt76: mt7915: add tx mu/su counters to mib These counters are clear-on-read, so we need to accumulate them in the update_stats poll logic, and read the accumulated values instead of directly doing register reads when reporting to debugfs and ethtool stats. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 59 ++++++++++------------ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 32 +++++++++++- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 42 ++++++--------- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 19 +++++++ 4 files changed, 93 insertions(+), 59 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 8c1725c00126..1d237e7908e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -153,56 +153,51 @@ 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; + struct mib_stats *mib; if (!phy) return; + 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"); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 1563e27e161a..dfc8460ee717 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1923,10 +1923,40 @@ 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_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); aggr0 = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 6f66cd4ca269..21a0a9b77e4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1195,6 +1195,7 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_ethtool_worker_info wi; + struct mib_stats *mib = &phy->mib; /* See mt7915_ampdu_stat_read_phy, etc */ bool ext_phy = phy != &dev->phy; @@ -1208,39 +1209,28 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, data[ei++] = phy->mib.ba_miss_cnt; /* Tx Beamformer monitor */ - cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy)); - data[ei++] = FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt); - data[ei++] = FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt); + data[ei++] = mib->tx_bf_ibf_ppdu_cnt; + data[ei++] = mib->tx_bf_ebf_ppdu_cnt; /* Tx Beamformer Rx feedback monitor */ - cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy)); - data[ei++] = FIELD_GET(MT_ETBF_RX_FB_ALL, cnt); - data[ei++] = FIELD_GET(MT_ETBF_RX_FB_HE, cnt); - data[ei++] = FIELD_GET(MT_ETBF_RX_FB_VHT, cnt); - data[ei++] = FIELD_GET(MT_ETBF_RX_FB_HT, cnt); + 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; - cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy)); - data[ei++] = FIELD_GET(MT_ETBF_RX_FB_BW, cnt); - data[ei++] = FIELD_GET(MT_ETBF_RX_FB_NC, cnt); - data[ei++] = FIELD_GET(MT_ETBF_RX_FB_NR, 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 */ - cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy)); - data[ei++] = FIELD_GET(MT_ETBF_TX_FB_CPL, cnt); - data[ei++] = FIELD_GET(MT_ETBF_TX_FB_TRI, cnt); + data[ei++] = mib->tx_bf_fb_cpl_cnt; + data[ei++] = mib->tx_bf_fb_trig_cnt; /* Tx SU & MU counters */ - cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy)); - data[ei++] = FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt); - - cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy)); - data[ei++] = cnt; - - cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy)); - data[ei++] = cnt; /* MU MPDU SUccessful */ - - cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy)); - data[ei++] = cnt; /* SU MPDU successful */ + 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 < 8; i++) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 3c1ba6f4c6e6..f664f46ca261 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -105,12 +105,31 @@ 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; + /* Add more stats here, updated from mac_update_stats */ }; -- cgit v1.2.3-70-g09d2 From a90f2115c1a8577ac1ab80111ddd7261cff0a3d8 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 4 Aug 2021 06:43:34 -0700 Subject: mt76: mt7915: add more MIB registers Add register definitions and read & accumulate them in the mib polling logic. Note that some registers should not be read since firmware is already reading them. If driver reads those, they will be cleared-on-read, and so the firmware stats will be incorrect. For these 'do-not-read' stats, add them to the registers definition so that other developers can be aware of these constraints, but do not actually read them in the driver. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 65 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 25 ++++- drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 105 +++++++++++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index dfc8460ee717..3e699193705e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1927,6 +1927,71 @@ mt7915_mac_update_stats(struct mt7915_phy *phy) 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index f664f46ca261..1fc014b59495 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -130,7 +130,30 @@ struct mib_stats { u32 tx_bf_fb_cpl_cnt; u32 tx_bf_fb_trig_cnt; - /* Add more stats here, updated from mac_update_stats */ + 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; }; struct mt7915_hif { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 3cf81bbcf1d8..6771870a867c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -139,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) -- cgit v1.2.3-70-g09d2 From f474e6f1b3174bdec80917181ae9dcbb8b527afa Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 4 Aug 2021 06:43:35 -0700 Subject: mt76: mt7915: add mib counters to ethtool stats This adds the new mib counters from last patch into ethtool stats. Signed-off-by: Ben Greear Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 21a0a9b77e4d..cca94b3b372f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1055,6 +1055,14 @@ static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw, } 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", @@ -1094,6 +1102,22 @@ static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = { "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", @@ -1201,6 +1225,15 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, bool ext_phy = phy != &dev->phy; int i, n, ei = 0; + 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++) @@ -1236,6 +1269,21 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, for (i = 0; i < 8; i++) data[ei++] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(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.data = data; wi.mvif = mvif; -- cgit v1.2.3-70-g09d2 From b64c3202d4e4ea7decf969561ddeabb049874d61 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:19 +0200 Subject: mt76: connac: set 6G phymode in mt76_connac_get_phy_mode{,v2} This is a preliminary patch to support 6GHz band on mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 9c0f86eefd75..8b72ed77881c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -691,7 +691,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, if (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) @@ -1154,7 +1154,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) @@ -1163,8 +1163,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; -- cgit v1.2.3-70-g09d2 From 212e5197eec24e0e437cbcfdc73dc3be1c749ef5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:20 +0200 Subject: mt76: connac: enable 6GHz band for hw scan This is a preliminary patch to support 6GHz band on mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 8b72ed77881c..8858a06ebd95 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1458,7 +1458,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; @@ -1567,7 +1577,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; } -- cgit v1.2.3-70-g09d2 From cee3fd2979598c8499067587299d5484bcff36d1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:21 +0200 Subject: mt76: connac: add 6GHz support to mt76_connac_mcu_set_channel_domain Configure 6GHz channels defining mcu channel domain. This is a preliminary patch to enable 6GHz band on mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 29 +++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f4dd61c5ecb8..aa38ac93b7c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -623,6 +623,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]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 8858a06ebd95..f5c1a7d9306e 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)); -- cgit v1.2.3-70-g09d2 From 9b2ea8eee42a19bb8187a3a5c48496ad8b257026 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:22 +0200 Subject: mt76: connac: set 6G phymode in single-sku support Configure tx rate power for 6GHz channels. This is a preliminary patch to enable 6GHz band for mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 3 ++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 48 ++++++++++++++++++++-- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 3b47e85e95e7..376c3bd883e5 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -285,6 +285,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/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index f5c1a7d9306e..8e1475aa35ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1839,6 +1839,9 @@ static s8 mt76_connac_get_ch_power(struct mt76_phy *phy, case NL80211_BAND_5GHZ: sband = &phy->sband_5g.sband; break; + case NL80211_BAND_6GHZ: + sband = &phy->sband_6g.sband; + break; default: return target_power; } @@ -1880,6 +1883,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; @@ -1893,6 +1914,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; @@ -1901,13 +1925,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; @@ -1923,6 +1947,18 @@ 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], @@ -1973,6 +2009,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; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index cb36dd39221c..0f11574af535 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -964,7 +964,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 */ -- cgit v1.2.3-70-g09d2 From 5883892bab53bb18713d9a9f4a75a413619bf68e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:23 +0200 Subject: mt76: connac: add 6GHz support to mt76_connac_mcu_sta_tlv Introduce sta_rec_he_6g_capa tlv in order configure the mcu with 6GHz capabilities. This is a preliminary patch to enable 6GHz band for mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 12 +++++++++++- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 8e1475aa35ac..ab44e61e3aaf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -770,8 +770,18 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 0f11574af535..5ab5e185a8bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -145,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 { @@ -303,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) @@ -329,6 +337,7 @@ enum { STA_REC_MUEDCA, STA_REC_BFEE, STA_REC_PHY = 0x15, + STA_REC_HE_6G = 0x17, STA_REC_MAX_NUM }; -- cgit v1.2.3-70-g09d2 From 3cf3e01ba62026bd5df2e49c42cf14abf1c3bc8e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:24 +0200 Subject: mt76: connac: add 6GHz support to mt76_connac_mcu_uni_add_bss This is a preliminary patch to enable 6GHz band for mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 11 +++++++++-- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 8 ++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index ab44e61e3aaf..3b9c4180f954 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1292,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 = { @@ -1308,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: diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 5ab5e185a8bb..ea46dde364e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -668,10 +668,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 { -- cgit v1.2.3-70-g09d2 From bebd3681113ad329f27bb61e5465b62b48bcf971 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:25 +0200 Subject: mt76: connac: enable hw amsdu @ 6GHz This is a preliminary patch to enable 6GHz band for mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 3b9c4180f954..10198c0c065b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -766,7 +766,7 @@ 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 */ -- cgit v1.2.3-70-g09d2 From edf9dab8ba27f42bb8f32d2df63a0a5bd3d896d2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:26 +0200 Subject: mt76: add 6GHz support Introduce 6GHz channel list in mt76 module. This is a preliminary patch to unlock 6GHz band for mt7921 devices. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 128 ++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index bbe7ba64ccd2..4ca2c154e046 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 }, @@ -194,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; @@ -224,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 | @@ -260,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 @@ -271,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 @@ -396,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) @@ -506,9 +603,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); @@ -653,6 +757,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; @@ -728,10 +834,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) { @@ -1286,7 +1398,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 */ @@ -1358,7 +1470,7 @@ 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_5GHZ) + if (phy->chandef.chan->band != NL80211_BAND_2GHZ) offset = 4; /* pick the lowest rate for hidden nodes */ -- cgit v1.2.3-70-g09d2 From 50ac15a511e3a03d5ade7fad976973560c3d453e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 24 Aug 2021 12:22:27 +0200 Subject: mt76: mt7921: add 6GHz support Unlock 6GHz band if supported by the device. Configure HE 6G capabilities. Tested-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 33 +++++++++++------- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 39 ++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 6 +++- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 +- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 3684b3bafca0..14024ae50d1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -355,7 +355,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); } @@ -441,10 +448,17 @@ 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; @@ -994,7 +1008,7 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) 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])); @@ -1392,17 +1406,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); @@ -1419,7 +1428,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 217ed7055aa0..cd3974b6ba8f 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; + } } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 56fb7e54e283..ecdc879216b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1028,9 +1028,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) && diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 16d7d159a71c..e14b86b1c6d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -112,7 +112,7 @@ struct mt7921_phy { struct mt76_phy *mt76; struct mt7921_dev *dev; - struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; + struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES]; u32 rxfilter; u64 omac_mask; -- cgit v1.2.3-70-g09d2 From bd1e3e7b693c17a04e7d2bd9119daa482b7c7720 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Sep 2021 11:25:02 +0200 Subject: mt76: introduce packet_id idr Introduce per-wcid idr to manage packet id for txs. This allow fast idr lookup and skb queueing at the same time. Tested-by: mrkiko.rs@gmail.com Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 ++- drivers/net/wireless/mediatek/mt76/mt76.h | 26 +++++++--- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 3 ++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 ++ drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 3 ++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 4 ++ drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 ++ drivers/net/wireless/mediatek/mt76/tx.c | 59 ++++++++++++++++------- 8 files changed, 82 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4ca2c154e046..ddc692d7b59e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -566,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++) @@ -1237,6 +1239,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); @@ -1255,7 +1258,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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index aa38ac93b7c3..7bd82cfbf0b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -261,7 +261,8 @@ struct mt76_wcid { u32 tx_info; bool sw_iv; - u8 packet_id; + struct list_head list; + struct idr pktid; }; struct mt76_txq { @@ -701,6 +702,7 @@ struct mt76_dev { struct mt76_wcid global_wcid; struct mt76_wcid __rcu *wcid[MT76_N_WCIDS]; + struct list_head wcid_list; u32 rev; @@ -1311,14 +1313,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) +{ + INIT_LIST_HEAD(&wcid->list); + idr_init(&wcid->pktid); +} + +static inline void +mt76_packet_id_flush(struct mt76_dev *dev, 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; + struct sk_buff_head list; - return wcid->packet_id; + 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/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/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 457e50255250..d5bcffef7122 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) 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/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index cca94b3b372f..bdd5f525e621 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -236,6 +236,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, 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); @@ -290,6 +292,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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index cd3974b6ba8f..c51266e40cb4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -304,6 +304,8 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, 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); @@ -350,6 +352,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) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 6f302acb6e69..15916f6d9f1b 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -92,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; @@ -120,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; @@ -132,13 +132,21 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, spin_lock_bh(&dev->status_list.lock); - memset(cb, 0, sizeof(*cb)); - pid = mt76_get_next_pkt_id(wcid); + 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; + } + cb->wcid = wcid->idx; cb->pktid = pid; cb->jiffies = jiffies; - __skb_queue_tail(&dev->status_list, skb); + if (list_empty(&wcid->list)) + list_add_tail(&wcid->list, &dev->wcid_list); + +out: spin_unlock_bh(&dev->status_list.lock); return pid; @@ -149,26 +157,38 @@ 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_list.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; + } + 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); @@ -176,9 +196,11 @@ void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush) { struct sk_buff_head list; + struct mt76_wcid *tmp; 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); @@ -201,6 +223,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, @@ -230,7 +253,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); -- cgit v1.2.3-70-g09d2 From c02f86eee8daf1b97c6fa7c42030f5df857a7a5c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Sep 2021 11:25:03 +0200 Subject: mt76: remove mt76_wcid pointer from mt76_tx_status_check signature Remove mt76_wcid pointer from mt76_tx_status_check signature since it is always set to NULL Tested-by: mrkiko.rs@gmail.com Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76.h | 3 +-- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/sdio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/sdio.c | 2 +- drivers/net/wireless/mediatek/mt76/tx.c | 4 ++-- drivers/net/wireless/mediatek/mt76/usb.c | 2 +- 14 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index ddc692d7b59e..61fff98c1fd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -511,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; } @@ -639,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 7bd82cfbf0b5..1c18e75c3f6a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1116,8 +1116,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index d1cbe06ee8da..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); @@ -1817,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/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 5455231f5188..423f69015e3e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -2026,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 0a4caddeb75d..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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index 305bb8597531..fb0f8f34b8f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -432,7 +432,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/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 07b21b208582..a404fd7ea968 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1186,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 468be651010d..ec0de691129a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 3e699193705e..48777993b7ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1792,7 +1792,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); @@ -2105,7 +2105,7 @@ void mt7915_mac_work(struct work_struct *work) 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 62cee662ba28..802e40e42040 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -272,7 +272,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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 14024ae50d1c..0659ff290af9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1694,7 +1694,7 @@ void mt7921_mac_work(struct work_struct *work) mt7921_mutex_release(phy->dev); - mt76_tx_status_check(mphy->dev, NULL, false); + mt76_tx_status_check(mphy->dev, false); ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, MT7921_WATCHDOG_TIME); } diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 783a15635ec5..4abf432750c6 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -328,7 +328,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/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 15916f6d9f1b..8b4c6ce900ee 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -193,10 +193,10 @@ out: 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; - struct mt76_wcid *tmp; mt76_tx_status_lock(dev, &list); list_for_each_entry_safe(wcid, tmp, &dev->wcid_list, 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); -- cgit v1.2.3-70-g09d2 From c34f100590f1239811db576d9923e77b75f627db Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Sep 2021 11:25:04 +0200 Subject: mt76: substitute sk_buff_head status_list with spinlock_t status_lock Substitute sk_buff_head status_list with spinlock_t status_lock since we just need it for locking Tested-by: mrkiko.rs@gmail.com Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76.h | 7 ++++--- drivers/net/wireless/mediatek/mt76/tx.c | 14 +++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 61fff98c1fd6..831717d9638c 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -543,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 1c18e75c3f6a..8c617fe2d551 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -693,7 +693,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)]; @@ -1097,9 +1098,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); diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 8b4c6ce900ee..ef75f168ba82 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) { @@ -130,7 +130,7 @@ 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); @@ -147,7 +147,7 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, list_add_tail(&wcid->list, &dev->wcid_list); out: - spin_unlock_bh(&dev->status_list.lock); + spin_unlock_bh(&dev->status_lock); return pid; } @@ -160,7 +160,7 @@ mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, struct sk_buff *skb; int id; - lockdep_assert_held(&dev->status_list.lock); + lockdep_assert_held(&dev->status_lock); skb = idr_remove(&wcid->pktid, pktid); if (skb) -- cgit v1.2.3-70-g09d2 From c4a784e34bd5c30bfc1dbb6131e05b92237ac750 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Sep 2021 11:25:05 +0200 Subject: mt76: schedule status timeout at dma completion Reduce MT_TX_STATUS_SKB_TIMEOUT to 250ms Tested-by: mrkiko.rs@gmail.com Co-developed-by: Ben Greear Signed-off-by: Ben Greear Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 9 +++++++-- drivers/net/wireless/mediatek/mt76/tx.c | 5 ++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8c617fe2d551..a3873de3b838 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -308,8 +308,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; diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index ef75f168ba82..11719ef034d8 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -141,7 +141,6 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, cb->wcid = wcid->idx; cb->pktid = pid; - cb->jiffies = jiffies; if (list_empty(&wcid->list)) list_add_tail(&wcid->list, &dev->wcid_list); @@ -179,6 +178,9 @@ mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, 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); @@ -261,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); -- cgit v1.2.3-70-g09d2 From 255d3807b60436c9699fc593b66b2dbb6203b2df Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Aug 2021 02:32:16 +0100 Subject: mt76: support reading EEPROM data embedded in fdt Some platforms boot from SD card and don't come with calibration data stored anywhere on the board. As EEPROM data is rather small it can be embedded into the device tree to be loaded from there by the mt76. Signed-off-by: Daniel Golle Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 376c3bd883e5..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; -- cgit v1.2.3-70-g09d2 From a8315b2b94f4ee2c472403376556db4e51da2d97 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Aug 2021 02:33:23 +0100 Subject: dt: bindings: net: mt76: add eeprom-data property EEPROM data for mt76 can be embedded into device-tree as an array. Signed-off-by: Daniel Golle Acked-by: Rob Herring Signed-off-by: Felix Fietkau --- Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml index 3e2c2e43175e..1489d3c1cd6e 100644 --- a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml +++ b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml @@ -47,6 +47,11 @@ properties: ieee80211-freq-limit: true + mediatek,eeprom-data: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + EEPROM data embedded as array. + mediatek,mtd-eeprom: $ref: /schemas/types.yaml#/definitions/phandle-array description: -- cgit v1.2.3-70-g09d2 From 215a2efae38fc75e847007f7c189b2e2d5850549 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 15 Sep 2021 17:07:45 +0200 Subject: mt76: introduce __mt76_mcu_send_firmware routine Introduce __mt76_mcu_send_firmware routine to specify mcu message max length. This is a preliminary patch to support mt7921s driver. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mcu.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 11 +++++++++-- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 8 ++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index d3a5e2c4f12a..946694af5dcc 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 - dev->mcu_ops->headroom, 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 a3873de3b838..59ca90d49978 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1258,8 +1258,15 @@ 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) +{ + return __mt76_mcu_send_firmware(dev, cmd, data, len, 4096); +} + static inline int mt76_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, int len, bool wait_resp) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index ecdc879216b9..3f6c9839d9d4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -716,8 +716,8 @@ static int mt7921_load_patch(struct mt7921_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; @@ -788,8 +788,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, 4096); if (err) { dev_err(dev->mt76.dev, "Failed to send firmware.\n"); return err; -- cgit v1.2.3-70-g09d2 From 5b8f1840c3e11e5422f395a0acb0bbb1ba5f889f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sat, 18 Sep 2021 07:54:21 +0800 Subject: mt76: drop MCU header size from buffer size in __mt76_mcu_send_firmware Each firmware piece with mt7915 and mt7921 do not have the MCU header to reroute the packet to the internal RAM. So we do not need to consider the MCU header size in __mt76_mcu_send_firmware. Move the MCU header overhead calculation to mt76_mcu_send_firmware (for older chipsets) Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Fixes: 1c099ab44727 ("mt76: mt7921: add MCU support") Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76.h | 4 +++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index 946694af5dcc..3f94c37251df 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -112,7 +112,7 @@ int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, int err, cur_len; while (len > 0) { - cur_len = min_t(int, max_len - 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) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 59ca90d49978..520fd162d406 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1264,7 +1264,9 @@ static inline int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, int len) { - return __mt76_mcu_send_firmware(dev, cmd, data, len, 4096); + int max_len = 4096 - dev->mcu_ops->headroom; + + return __mt76_mcu_send_firmware(dev, cmd, data, len, max_len); } static inline int diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 7415b9391175..c6fd14f53962 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2648,8 +2648,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; @@ -2717,8 +2717,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; -- cgit v1.2.3-70-g09d2 From f05c8c9827b7acd7d458c223abc09fb64950081c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 23 Sep 2021 16:29:30 +0200 Subject: mt76: mt7915: introduce __mt7915_get_tsf routine Introduce an unlocked verion of mt7915_get_tsf routine. This is a preliminary patch to add TWT support to mt7915. Tested-by: Peter Chiu Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 20 +++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index bdd5f525e621..e77a77428923 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -819,10 +819,8 @@ mt7915_get_stats(struct ieee80211_hw *hw, 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; @@ -832,7 +830,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 */ @@ -841,9 +839,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 diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 1fc014b59495..2df22fab0b05 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -329,7 +329,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); -- cgit v1.2.3-70-g09d2 From 179090a589400cbe6476b431d1b41563825213b6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 23 Sep 2021 16:29:31 +0200 Subject: mt76: mt7915: introduce mt7915_mcu_twt_agrt_update mcu command This is a preliminary patch to add TWT support to mt7915 Tested-by: Peter Chiu Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 50 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 9 ++++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 20 +++++++++ 3 files changed, 79 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c6fd14f53962..82f6258a0e94 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3949,3 +3949,53 @@ int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vi 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 e02659272f9e..0bd66c5136e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -277,6 +277,7 @@ enum { MCU_EXT_CMD_MWDS_SUPPORT = 0x80, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, + 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, @@ -286,6 +287,14 @@ enum { MCU_EXT_CMD_PHY_STAT_INFO = 0xad, }; +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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 2df22fab0b05..9e9fea345679 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -74,6 +74,22 @@ struct mt7915_sta_key_conf { 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 */ @@ -342,6 +358,10 @@ 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, -- cgit v1.2.3-70-g09d2 From 3782b69d03e714b8ff98b84c7426d8cef0e64d7c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 23 Sep 2021 16:29:32 +0200 Subject: mt76: mt7915: introduce mt7915_mac_add_twt_setup routine Introduce individual TWT support to mt7915 in AP mode. Implement the two following mac80211 callbacks: - add_twt_setup - twt_teardown_request Tested-by: Peter Chiu Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 180 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 19 +++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 20 +++ 4 files changed, 220 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 30d51b640bf9..409f2b60373d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -901,6 +901,7 @@ int mt7915_register_device(struct mt7915_dev *dev) 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 48777993b7ee..b992fdd338e2 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) @@ -2242,3 +2243,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/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index e77a77428923..244133d17cd1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -670,6 +670,7 @@ 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); @@ -677,6 +678,9 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 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); @@ -1316,6 +1320,19 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, 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, @@ -1354,6 +1371,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/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 9e9fea345679..6966795a65a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -41,6 +41,9 @@ #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; @@ -106,6 +109,11 @@ struct mt7915_sta { struct mt7915_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 { @@ -247,6 +255,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; @@ -257,6 +266,11 @@ struct mt7915_dev { bool ibf; void *cal; + + struct { + u8 table_mask; + u8 n_agrt; + } twt; }; enum { @@ -475,6 +489,12 @@ 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); 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, -- cgit v1.2.3-70-g09d2 From 204324764cb2a99534bddeda9b74f314d62cd885 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 23 Sep 2021 16:29:33 +0200 Subject: mt76: mt7915: enable twt responder capability Enable TWT support in AP mode Tested-by: Peter Chiu Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 409f2b60373d..ffe744e69482 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -777,6 +777,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] |= -- cgit v1.2.3-70-g09d2 From 34f374f85effc17815e807ffe63ce9710384b50d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 23 Sep 2021 16:29:34 +0200 Subject: mt76: mt7915: add twt_stats knob in debugfs Introduce twt_stats knob in debugfs in order to dump established agreements Tested-by: Peter Chiu Tested-by: Evelyn Tsai Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 1d237e7908e7..04a81b5d0c9d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -437,6 +437,32 @@ mt7915_read_rate_txpower(struct seq_file *s, void *data) return 0; } +static int +mt7915_twt_stats(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + struct mt7915_twt_flow *iter; + + 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) { struct dentry *dir; @@ -454,6 +480,8 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) debugfs_create_file("implicit_txbf", 0600, dir, dev, &fops_implicit_txbf); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); + debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, + mt7915_twt_stats); /* test knobs */ debugfs_create_file("radar_trigger", 0200, dir, dev, &fops_radar_trigger); -- cgit v1.2.3-70-g09d2 From 2d8be76c16746f1c90f4a01c188b6aad190b747e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Sep 2021 15:27:02 +0200 Subject: mt76: debugfs: improve queue node readability Improve {xmit,rx}-queue debugfs node readability Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index ad97308c7853..c9b03b3fed2a 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; -- cgit v1.2.3-70-g09d2 From a6fdbdd1ac2996a58a84672ef37efb5cbb98fadf Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 27 Sep 2021 12:59:49 +0800 Subject: mt76: mt7615: fix monitor mode tear down crash [ 103.451600] CPU 3 Unable to handle kernel paging request at virtual address 00000003, epc == 8576591c, ra == 857659f0 [ 103.462226] Oops[#1]: [ 103.464499] CPU: 3 PID: 9247 Comm: ifconfig Tainted: G W 5.4.143 #0 [ 103.472031] $ 0 : 00000000 00000001 83be3854 00000000 [ 103.477239] $ 4 : 8102a374 8102a374 8102f0b0 00000200 [ 103.482444] $ 8 : 0000002d 000001e4 64373765 5d206337 [ 103.487647] $12 : 00000000 00000005 00000000 0006d1df [ 103.492853] $16 : 83be3848 853838a8 8743d600 00010000 [ 103.498059] $20 : 00000000 00000000 8553dec0 0000007f [ 103.503266] $24 : 00000003 80382084 [ 103.508472] $28 : 831d4000 831d5bc0 00000001 857659f0 [ 103.513678] Hi : 00000122 [ 103.516543] Lo : d1768000 [ 103.519452] epc : 8576591c mt7615_mcu_add_bss+0xd0/0x3c0 [mt7615_common] [ 103.526306] ra : 857659f0 mt7615_mcu_add_bss+0x1a4/0x3c0 [mt7615_common] [ 103.533232] Status: 11007c03 KERNEL EXL IE [ 103.537402] Cause : 40800008 (ExcCode 02) [ 103.541389] BadVA : 00000003 [ 103.544253] PrId : 0001992f (MIPS 1004Kc) [ 103.797086] Call Trace: [ 103.799562] [<8576591c>] mt7615_mcu_add_bss+0xd0/0x3c0 [mt7615_common] [ 103.806082] [<85760a14>] mt7615_remove_interface+0x74/0x1e0 [mt7615_common] [ 103.813280] [<85603fcc>] drv_remove_interface+0x2c/0xa0 [mac80211] [ 103.819612] [<8561a8e4>] ieee80211_del_virtual_monitor.part.22+0x74/0xe8 [mac80211] [ 103.827410] [<8561b7f0>] ieee80211_do_stop+0x4a4/0x8a0 [mac80211] [ 103.833671] [<8561bc00>] ieee80211_stop+0x14/0x24 [mac80211] [ 103.839405] [<8045a328>] __dev_close_many+0x9c/0x10c [ 103.844364] [<80463de4>] __dev_change_flags+0x16c/0x1e4 [ 103.849569] [<80463e84>] dev_change_flags+0x28/0x70 [ 103.854440] [<80521e54>] devinet_ioctl+0x280/0x774 [ 103.859222] [<80526248>] inet_ioctl+0xa4/0x1c8 [ 103.863674] [<80436830>] sock_ioctl+0x2d8/0x4bc [ 103.868201] [<801adbb4>] do_vfs_ioctl+0xb8/0x7c0 [ 103.872804] [<801ae30c>] ksys_ioctl+0x50/0xb4 [ 103.877156] [<80014598>] syscall_common+0x34/0x58 Fixes: 04b8e65922f63 ("mt76: add mac80211 driver for MT7615 PCIe-based chipsets") Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index a39776833efd..2ba730808f3b 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) -- cgit v1.2.3-70-g09d2 From b94c0ed609bd2aac6ee058f6fdc7c6eaad1b0ec1 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 8 Oct 2021 23:40:50 +0800 Subject: mt76: mt7921: add delay config for sched scan Add a delay parameter for firmware to support delay scheduled scan. Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 10198c0c065b..c569e320f843 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1588,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++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index ea46dde364e1..848f43c44258 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -818,7 +818,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; -- cgit v1.2.3-70-g09d2 From a1b0bbd4846b46f45a13a669ce46725988660b2a Mon Sep 17 00:00:00 2001 From: Xing Song Date: Thu, 30 Sep 2021 15:37:37 +0800 Subject: mt76: use a separate CCMP PN receive counter for management frames When received frame is decryped by hardware, CCMP PN is checked by mt76. When management frame protection (IEEE 802.11w) is used, we must use a separate counter for tracking received CCMP packet number for the management frames. The previously used counter was shared with data frames and that can cause problems in detecting replays incorrectly for robust management frames. Add a new counter just for robust management frames to avoid this issue. Signed-off-by: Xing Song Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 27 +++++++++++++++++++++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 831717d9638c..5a6608f36ebc 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -902,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); @@ -958,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)) @@ -967,24 +974,36 @@ mt76_check_ccmp_pn(struct sk_buff *skb) if (!wcid || !wcid->rx_check_pn) return 0; + 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; + else + security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; + 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 520fd162d406..4c20b128466d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -255,7 +255,7 @@ 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; -- cgit v1.2.3-70-g09d2 From 7360cdec1cb55ae1e9515ffffc496c5dd0cf861a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 11 Oct 2021 12:07:46 +0200 Subject: mt76: do not access 802.11 header in ccmp check for 802.3 rx skbs Avoids false positive on detecting frags or encrypted mgmt frames Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 5a6608f36ebc..766681a4f89e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -974,6 +974,10 @@ 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)) { /* @@ -994,9 +998,8 @@ mt76_check_ccmp_pn(struct sk_buff *skb) if (ieee80211_is_mgmt(hdr->frame_control) && !ieee80211_has_tods(hdr->frame_control)) security_idx = IEEE80211_NUM_TIDS; - else - security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; +skip_hdr_check: BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], sizeof(status->iv)); -- cgit v1.2.3-70-g09d2 From b5f2ba8a4c794e8349c0e30036352b9f685164c4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 14 Oct 2021 17:19:53 +0200 Subject: mt76: connac: fix possible NULL pointer dereference in mt76_connac_get_phy_mode_v2 Fix the following NULL pointer dereference in mt76_connac_get_phy_mode_v2 routine triggered on mt7663s device when sta is NULL [ 5.490700] mt7663s mmc0:0001:1: N9 Firmware Version: 3.1.1, Build Time: 20200604161656 [ 5.490815] mt7663s mmc0:0001:1: Region number: 0x4 [ 5.490868] mt7663s mmc0:0001:1: Parsing tailer Region: 0 [ 5.496251] mt7663s mmc0:0001:1: Region 0, override_addr = 0x00118000 [ 5.496419] mt7663s mmc0:0001:1: Parsing tailer Region: 1 [ 5.624027] mt7663s mmc0:0001:1: Parsing tailer Region: 2 [ 5.656999] mt7663s mmc0:0001:1: Parsing tailer Region: 3 [ 5.671876] mt7663s mmc0:0001:1: override_addr = 0x00118000, option = 3 [ 9.358658] BUG: kernel NULL pointer dereference, address: 0000000000000000 [ 9.358775] #PF: supervisor read access in kernel mode [ 9.358831] #PF: error_code(0x0000) - not-present page [ 9.358886] PGD 0 P4D 0 [ 9.358917] Oops: 0000 [#1] SMP [ 9.358960] CPU: 0 PID: 235 Comm: NetworkManager Not tainted 5.15.0-rc4-kvm-02151-g39e333d657f4-dirty #769 [ 9.359057] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.14.0-4.fc34 04/01/2014 [ 9.359150] RIP: 0010:mt76_connac_get_phy_mode_v2+0xc9/0x11c [ 9.359473] RAX: 0000000000000013 RBX: 0000000000000000 RCX: 0000000000000027 [ 9.359546] RDX: ffff8881f9c17358 RSI: 0000000000000001 RDI: ffff8881f9c17350 [ 9.359624] RBP: ffff88810bac1ed4 R08: ffffffff822a4a48 R09: 0000000000000003 [ 9.359697] R10: ffffffff82234a60 R11: ffffffff82234a60 R12: ffff88810bac1eec [ 9.359779] R13: 0000000000000000 R14: ffff88810bad1648 R15: ffff88810bac1eb8 [ 9.359859] FS: 00007f5f1e45bbc0(0000) GS:ffff8881f9c00000(0000) knlGS:0000000000000000 [ 9.359939] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 9.360003] CR2: 0000000000000000 CR3: 0000000105d5d000 CR4: 00000000000006b0 [ 9.360083] Call Trace: [ 9.360116] mt76_connac_mcu_uni_add_bss.cold+0x21/0x250 [ 9.360175] ? schedule_preempt_disabled+0xa/0x10 [ 9.360232] ? __mutex_lock.constprop.0+0x2ab/0x460 [ 9.360286] mt7615_remove_interface+0x63/0x1d0 [ 9.360342] drv_remove_interface+0x32/0xe0 [ 9.360385] ieee80211_do_stop+0x5da/0x800 [ 9.360428] ? dev_reset_queue+0x30/0x90 [ 9.360472] ieee80211_stop+0x3b/0xb0 [ 9.360516] __dev_close_many+0x7a/0xd0 [ 9.360559] __dev_change_flags+0xd6/0x1f0 [ 9.360604] dev_change_flags+0x21/0x60 [ 9.360648] do_setlink+0x259/0xfb0 [ 9.360686] ? __nla_validate_parse+0x51/0xb80 [ 9.360742] __rtnl_newlink+0x5b3/0x960 [ 9.360785] ? inet6_fill_ifla6_attrs+0x41d/0x470 [ 9.360841] ? __kmalloc_track_caller+0x57/0x3c0 [ 9.360905] ? netlink_trim+0x8a/0xb0 [ 9.360949] ? skb_queue_tail+0x1b/0x50 Fixes: 67aa27431c7f8 ("mt76: mt7921: rely on mt76_connac_mcu common library") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index c569e320f843..9a1af2ba7e8e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -706,7 +706,7 @@ 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 || band == NL80211_BAND_6GHZ) { mode |= PHY_TYPE_BIT_OFDM; @@ -717,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; } -- cgit v1.2.3-70-g09d2 From 22dffbddf016791e99f02d1ad36f5043ce615085 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 18 Oct 2021 16:06:59 +0800 Subject: mt76: mt7915: introduce mt7915_mcu_beacon_check_caps() Beacon elements might be changed by hostapd configuraion, so driver should compare both IEs and PHY capabilities to get the least common denominator before association. Co-developed-by: Evelyn Tsai Signed-off-by: Evelyn Tsai Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 163 ++++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 12 ++ 3 files changed, 137 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 244133d17cd1..5351cfa1dd60 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -253,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 82f6258a0e94..559f58af47f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1337,9 +1337,11 @@ 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 mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band; @@ -1372,8 +1374,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] & @@ -1508,8 +1510,10 @@ 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 mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; struct sta_rec_muru *muru; @@ -1519,7 +1523,13 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) muru = (struct sta_rec_muru *)tlv; muru->cfg.ofdma_dl_en = true; - muru->cfg.mimo_dl_en = true; + + /* A non-AP HE station must support MU beamformee */ + muru->cfg.mimo_dl_en = (vif->type == NL80211_IFTYPE_STATION && + vif->bss_conf.he_support) || + mvif->cap.he_mu_ebfer || + mvif->cap.vht_mu_ebfer || + mvif->cap.vht_mu_ebfee; muru->ofdma_dl.punc_pream_rx = HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); @@ -1618,7 +1628,7 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, /* starec he */ if (sta->he_cap.has_he) - mt7915_mcu_sta_he_tlv(skb, sta); + mt7915_mcu_sta_he_tlv(skb, sta, vif); /* starec uapsd */ mt7915_mcu_sta_uapsd_tlv(skb, sta, vif); @@ -1640,9 +1650,11 @@ mt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, } 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; @@ -1651,7 +1663,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; @@ -1665,7 +1678,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, @@ -1988,7 +2002,7 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct mt7915_phy *phy; struct sk_buff *skb; int r, len; - bool ebfee = 0, ebf = 0; + bool ebfee = false, ebfer = false; if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP) @@ -1997,42 +2011,32 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, 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; + struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem; - pc = &sta->vht_cap; - vc = &phy->mt76->sband_5g.sband.vht_cap; + ebfee = mvif->cap.he_su_ebfee && + HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); + ebfer = mvif->cap.he_su_ebfer && + HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); + } else if (sta->vht_cap.vht_supported) { + u32 cap = sta->vht_cap.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)); + ebfee = mvif->cap.vht_su_ebfee && + (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); + ebfer = mvif->cap.vht_su_ebfer && + (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); } /* must keep each tag independent */ /* starec bf */ - if (ebf || dev->ibf) { + if (ebfer || 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); + mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable, ebfer); r = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); @@ -2116,7 +2120,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); @@ -2141,7 +2146,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); @@ -2190,7 +2196,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); @@ -2246,7 +2252,7 @@ mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, /* wait until TxBF and MU ready to update stare vht */ /* starec muru */ - mt7915_mcu_sta_muru_tlv(skb, sta); + mt7915_mcu_sta_muru_tlv(skb, sta, vif); /* starec vht */ mt7915_mcu_sta_vht_tlv(skb, sta); @@ -2305,7 +2311,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, 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); + mt7915_mcu_wtbl_ht_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); } return mt76_mcu_skb_send_msg(&dev->mt76, skb, @@ -2455,6 +2461,83 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, 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) { @@ -2495,6 +2578,8 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; } + 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 6966795a65a4..267fd18b859e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -116,12 +116,24 @@ struct mt7915_sta { } 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 { u16 idx; u8 omac_idx; u8 band_idx; u8 wmm_idx; + struct mt7915_vif_cap cap; struct mt7915_sta sta; struct mt7915_phy *phy; -- cgit v1.2.3-70-g09d2 From f89f297aef2815e3c16ab719eecab2cfdbc87b9f Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 18 Oct 2021 16:07:00 +0800 Subject: mt76: mt7915: fix txbf starec TLV issues With this patch we can append txbf starec TLVs. This is an intermediate patch to improve HE MUMIMO performances. Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 139 ++++++++++++------------ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 4 +- 2 files changed, 71 insertions(+), 72 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 559f58af47f5..a7f9809e2f72 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1769,6 +1769,45 @@ 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) { @@ -1900,10 +1939,12 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, } 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; @@ -1913,25 +1954,23 @@ 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 @@ -1941,12 +1980,12 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, 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->nc) bf->ibf_timeout = 0x48; else bf->ibf_timeout = 0x18; - if (explicit && bf->nr != tx_ant) + if (ebf && bf->nr != tx_ant) bf->mem_20m = matrix[tx_ant][bf->nc]; else bf->mem_20m = matrix[bf->nr][bf->nc]; @@ -1966,14 +2005,20 @@ 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; + 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; @@ -1999,68 +2044,20 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, { 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 = false, ebfer = false; - - 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 = &sta->he_cap.he_cap_elem; - - ebfee = mvif->cap.he_su_ebfee && - HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); - ebfer = mvif->cap.he_su_ebfer && - HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); - } else if (sta->vht_cap.vht_supported) { - u32 cap = sta->vht_cap.cap; - - ebfee = mvif->cap.vht_su_ebfee && - (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); - ebfer = mvif->cap.vht_su_ebfer && - (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); - } - /* must keep each tag independent */ + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); /* starec bf */ - if (ebfer || 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, ebfer); - - r = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD(STA_REC_UPDATE), true); - if (r) - return r; - } - + mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta); /* 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; - } + mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta); - return 0; + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(STA_REC_UPDATE), true); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 0bd66c5136e9..f011479ea2bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -1007,7 +1007,7 @@ struct sta_rec_bf { bool codebook75_mu; u8 he_ltf; - u8 rsv[2]; + u8 rsv[3]; } __packed; struct sta_rec_bfee { @@ -1108,12 +1108,14 @@ 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_bfee) + \ sizeof(struct tlv) + \ MT7915_WTBL_UPDATE_MAX_SIZE) -- cgit v1.2.3-70-g09d2 From a56c431ededa4e0f02cf4740cc5cd76063d3df1e Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 18 Oct 2021 16:07:01 +0800 Subject: mt76: mt7915: improve starec readability of txbf 1. Drop unnecessary MT_EBF/MT_IBF enum. 2. Rename fields 'nc'/'nr' to 'ncol'/'nrow'. Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 81 +++++++++++++------------ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 13 ++-- 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index a7f9809e2f72..d65d428e6845 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1811,7 +1811,6 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif, 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 */ @@ -1826,7 +1825,6 @@ 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) && (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) @@ -1839,8 +1837,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; } @@ -1857,23 +1855,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) @@ -1891,21 +1889,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; @@ -1916,7 +1916,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] & @@ -1924,18 +1924,18 @@ 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 @@ -1976,19 +1976,20 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 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 (!ebf && 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 (ebf && 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: @@ -2014,7 +2015,7 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 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; @@ -2025,17 +2026,17 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb, 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); + bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index f011479ea2bb..40b61caee901 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -973,8 +973,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; @@ -994,8 +994,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; @@ -1086,11 +1086,6 @@ enum { THERMAL_PROTECT_STATE_ACT, }; -enum { - MT_EBF = BIT(0), /* explicit beamforming */ - MT_IBF = BIT(1) /* implicit beamforming */ -}; - enum { MT_BF_SOUNDING_ON = 1, MT_BF_TYPE_UPDATE = 20, -- cgit v1.2.3-70-g09d2 From afa0370f3a3a64af6d368da0bedd72ab2a026cd0 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:07:02 +0800 Subject: mt76: mt7915: fix sta_rec_wtbl tag len Fix tag len error for sta_rec_wtbl, which causes fw parsing error for the tags placed behind it. Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index d65d428e6845..4e4906d9d374 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -622,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)); } -- cgit v1.2.3-70-g09d2 From 89bbd3730f382f15cfcc2c9264c65b5901ce02fa Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:07:03 +0800 Subject: mt76: mt7915: rework starec TLV tags Rework starec tags to the order which firmware expected. This also fixes some weird behaviors during generating SPL of HE-MU. Co-developed-by: Ryder Lee Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 229 +++++++++------------ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 - 4 files changed, 94 insertions(+), 141 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 5351cfa1dd60..de68c85f6e66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -663,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, @@ -673,7 +673,6 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 4e4906d9d374..4e48c06bd467 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1342,14 +1342,16 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; - struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + 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; @@ -1514,11 +1516,13 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; - struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct ieee80211_he_cap_elem *elem = &sta->he_cap.he_cap_elem; struct sta_rec_muru *muru; struct tlv *tlv; + if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) + return; + tlv = mt7915_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); muru = (struct sta_rec_muru *)tlv; @@ -1563,12 +1567,27 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); } +static void +mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct sta_rec_ht *ht; + struct tlv *tlv; + + 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 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; @@ -1578,12 +1597,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; @@ -1596,44 +1620,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, vif); - - /* 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) @@ -1644,9 +1630,7 @@ 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 @@ -1720,6 +1704,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) @@ -2039,28 +2049,6 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb, bfee->fb_identity_matrix = (nrow == 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 sk_buff *skb; - - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, - MT7915_STA_UPDATE_MAX_SIZE); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - /* starec bf */ - mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta); - /* starec bfee */ - mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta); - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD(STA_REC_UPDATE), true); -} - static void mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -2206,7 +2194,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; @@ -2217,75 +2205,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, vif); - /* 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; @@ -2294,24 +2231,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, vif, 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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 40b61caee901..a1a6cc064573 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -1110,6 +1110,7 @@ enum { 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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 267fd18b859e..78c0896f97b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -394,8 +394,6 @@ 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); -- cgit v1.2.3-70-g09d2 From 161cc13912d3c3e8857001988dfba39be842454a Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:07:04 +0800 Subject: mt76: mt7915: fix muar_idx in mt7915_mcu_alloc_sta_req() For broadcast/multicast wcid, the muar_idx should be 0xe. Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 4e48c06bd467..f32e124b1a0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -586,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; -- cgit v1.2.3-70-g09d2 From f9372753648ee1dd53de20e8d508a1569ea5b4d9 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:07:05 +0800 Subject: mt76: mt7915: set VTA bit in tx descriptor The VTA (Valid for Txd Arrival time) bit should be set in tx descriptor, which is necessary for WM fw to schedule SPL (station priority list) normally before generating txcmd. If it's not set, some unexpected wcids may be involved in SPL. Suggested-by: Nelson Chang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index b992fdd338e2..d3d220f2f493 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1068,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); -- cgit v1.2.3-70-g09d2 From e5a9f383134ec6e91be11208864dd7533fcefa46 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:07:06 +0800 Subject: mt76: mt7915: set muru platform type Set muru platform type by mcu cmd to notify fw to init corresponding algorithm. Suggested-by: Money Wang Reviewed-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 20 ++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/testmode.c | 16 +++++----------- drivers/net/wireless/mediatek/mt76/mt7915/testmode.h | 4 ---- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index f32e124b1a0f..d4c8759bedd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2906,6 +2906,21 @@ 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); +} + int mt7915_mcu_init(struct mt7915_dev *dev) { static const struct mt76_mcu_ops mt7915_mcu_ops = { @@ -2935,6 +2950,11 @@ int mt7915_mcu_init(struct mt7915_dev *dev) 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; + return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_RED, 0, 0); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index a1a6cc064573..4043cf547c9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -1092,6 +1092,16 @@ enum { 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) + \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 78c0896f97b9..bb8ef60f1b1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -443,6 +443,7 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index 00dcc46b9082..89aae323d29e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -169,22 +169,16 @@ static int mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu) { struct mt7915_dev *dev = phy->dev; - struct { - __le32 cmd; - u8 op_mode; - } __packed req = { - .cmd = cpu_to_le32(MURU_SET_ARB_OP_MODE), - }; + u32 op_mode; if (!enable) - req.op_mode = TAM_ARB_OP_MODE_NORMAL; + op_mode = TAM_ARB_OP_MODE_NORMAL; else if (mu) - req.op_mode = TAM_ARB_OP_MODE_TEST; + op_mode = TAM_ARB_OP_MODE_TEST; else - req.op_mode = TAM_ARB_OP_MODE_FORCE_SU; + op_mode = TAM_ARB_OP_MODE_FORCE_SU; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req, - sizeof(req), false); + return mt7915_mcu_set_muru_ctrl(dev, MURU_SET_ARB_OP_MODE, op_mode); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h index 107f0cf2505e..5573ac309363 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h @@ -102,8 +102,4 @@ enum { TAM_ARB_OP_MODE_FORCE_SU = 5, }; -enum { - MURU_SET_ARB_OP_MODE = 14, -}; - #endif -- cgit v1.2.3-70-g09d2 From 3263039d757c7e27c0cd287a9df80a8b85edfb79 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Oct 2021 12:38:27 +0200 Subject: mt76: rely on phy pointer in mt76_register_debugfs_fops routine signature This is a preliminary patch to create a mt76 debugfs subir for ext-phy. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index c9b03b3fed2a..b8bcf22a07fd 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -118,13 +118,14 @@ static int mt76_read_rate_txpower(struct seq_file *s, void *data) } struct dentry * -mt76_register_debugfs_fops(struct mt76_dev *dev, +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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 4c20b128466d..0b8f3b7c7a38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -888,11 +888,11 @@ 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_fops(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, NULL); + return mt76_register_debugfs_fops(&dev->phy, NULL); } int mt76_queues_read(struct seq_file *s, void *data); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index bda22ca0bd71..6fd6f067da49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -533,7 +533,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) { struct dentry *dir; - dir = mt76_register_debugfs_fops(&dev->mt76, &fops_regval); + dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval); if (!dir) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 11f8acf4f59e..71aabb632e05 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -417,7 +417,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev) { struct dentry *dir; - dir = mt76_register_debugfs_fops(&dev->mt76, &fops_regval); + dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval); if (!dir) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 115a2d733b3dcae38010c14a2c745d936bc6edc0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Oct 2021 12:38:28 +0200 Subject: mt76: mt7915: introduce mt76 debugfs sub-dir for ext-phy Introduce a dedicated mt76 debugfs sub-dir for ext-phy in dbdc mode. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 157 +++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 6 +- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- 3 files changed, 86 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 04a81b5d0c9d..ec39a3b81c89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -120,7 +120,7 @@ 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; @@ -205,14 +205,12 @@ 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; + struct mt7915_phy *phy = file->private; + struct mt7915_dev *dev = phy->dev; int stat[8], i, n; - mt7915_ampdu_stat_read_phy(&dev->phy, file); - mt7915_txbf_stat_read_phy(&dev->phy, file); - - 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_txbf_stat_read_phy(phy, file); /* Tx amsdu info */ seq_puts(file, "Tx MSDU statistics:\n"); @@ -239,7 +237,8 @@ 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); + struct mt7915_phy *phy = s->private; + struct mt7915_dev *dev = phy->dev; u32 i, val; val = mt76_rr(dev, base + MT_FL_Q_EMPTY); @@ -294,40 +293,40 @@ mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) } static int -mt7915_hw_queues_read(struct seq_file *s, void *data) +mt7915_hw_queues_show(struct seq_file *file, void *data) { - struct mt7915_dev *dev = dev_get_drvdata(s->private); - struct mt7915_phy *phy = mt7915_ext_phy(dev); + 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}, + { "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}, + { "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; @@ -335,49 +334,46 @@ mt7915_hw_queues_read(struct seq_file *s, void *data) 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(s, "PLE page info:\n"); - seq_printf(s, "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n", + 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(s, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", + seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", val, head, tail); - seq_puts(s, "PLE non-empty queue info:\n"); - mt7915_hw_queue_read(s, MT_PLE_BASE, ARRAY_SIZE(ple_queue_map), + 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(dev->mphy.hw, - mt7915_sta_hw_queue_read, s); - if (phy) - ieee80211_iterate_stations_atomic(phy->mt76->hw, - mt7915_sta_hw_queue_read, s); - + ieee80211_iterate_stations_atomic(phy->mt76->hw, + mt7915_sta_hw_queue_read, file); /* pse queue */ - seq_puts(s, "PSE non-empty queue info:\n"); - mt7915_hw_queue_read(s, MT_PSE_BASE, ARRAY_SIZE(pse_queue_map), + 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], "MAIN" }, - { ext_q, "EXT" }, - { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" }, - { dev->mt76.q_mcu[MT_MCUQ_WA], "MCUWA" }, + { 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; @@ -388,7 +384,7 @@ mt7915_queues_read(struct seq_file *s, void *data) if (!q) continue; - seq_printf(s, + seq_printf(file, "%s: queued=%d head=%d tail=%d\n", queue_map[i].queue, q->queued, q->head, q->tail); @@ -397,6 +393,8 @@ mt7915_queues_read(struct seq_file *s, void *data) return 0; } +DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); + static void mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) { @@ -427,16 +425,17 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) } static int -mt7915_read_rate_txpower(struct seq_file *s, void *data) +mt7915_rate_txpower_show(struct seq_file *file, void *data) { - struct mt7915_dev *dev = dev_get_drvdata(s->private); + struct mt7915_phy *phy = file->private; - mt7915_puts_rate_txpower(s, &dev->phy); - mt7915_puts_rate_txpower(s, mt7915_ext_phy(dev)); + mt7915_puts_rate_txpower(file, phy); return 0; } +DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower); + static int mt7915_twt_stats(struct seq_file *s, void *data) { @@ -463,31 +462,35 @@ mt7915_twt_stats(struct seq_file *s, void *data) 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, "tx-queues", dir, - mt7915_queues_read); - debugfs_create_devm_seqfile(dev->mt76.dev, "hw-queues", dir, - mt7915_hw_queues_read); - 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); + 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); - /* test knobs */ - debugfs_create_file("radar_trigger", 0200, dir, dev, - &fops_radar_trigger); 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; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index ffe744e69482..85afe965169e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -477,6 +477,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: @@ -949,7 +953,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/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index bb8ef60f1b1e..84b4c5cb9596 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -522,7 +522,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); -- cgit v1.2.3-70-g09d2 From 53d12b55063cd0d903d8b58a4a2aac2d06a1e1a4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 11 Oct 2021 12:38:29 +0200 Subject: mt76: mt7915: improve code readability for xmit-queue handler Improve xmit-queue debugfs node readability for mt7915 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index ec39a3b81c89..86c681dd7a62 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -378,14 +378,14 @@ mt7915_xmit_queues_show(struct seq_file *file, void *data) }; 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(file, - "%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); } -- cgit v1.2.3-70-g09d2 From d512b008fafb62e042dd5142148a51dcbff40483 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 13 Oct 2021 23:40:22 +0200 Subject: mt76: sdio: export mt76s_alloc_rx_queue and mt76s_alloc_tx routines Export mt76s_alloc_rx_queue and mt76s_alloc_tx utility routines in order to allow mt7921s driver to configure a different main rx queue. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/sdio.c | 6 +++++- drivers/net/wireless/mediatek/mt76/sdio.c | 19 ++++--------------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 0b8f3b7c7a38..a28e5c0a158f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1245,7 +1245,8 @@ 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); struct sk_buff * diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index fb0f8f34b8f2..ff1e62035f37 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -367,7 +367,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; diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 4abf432750c6..f7a1838b4576 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -17,8 +17,7 @@ #include "mt76.h" -static int -mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) +int mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; @@ -35,6 +34,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 +56,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 +79,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) -- cgit v1.2.3-70-g09d2 From e0710ca9576a656da4379fa6bac0e72da7b3da42 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 18 Oct 2021 17:43:23 +0200 Subject: mt76: mt7915: remove dead code in debugfs code Remove some more not used code in mt7915 debugfs. Squash mt7915_puts_rate_txpower and mt7915_rate_txpower_show. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 31 +++++----------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 86c681dd7a62..6efa3d7e39be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -124,9 +124,6 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, 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)); @@ -156,12 +153,7 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) static const char * const bw[] = { "BW20", "BW40", "BW80", "BW160" }; - struct mib_stats *mib; - - if (!phy) - return; - - mib = &phy->mib; + struct mib_stats *mib = &phy->mib; /* Tx Beamformer monitor */ seq_puts(s, "\nTx Beamformer applied PPDU counts: "); @@ -395,8 +387,8 @@ mt7915_xmit_queues_show(struct seq_file *file, void *data) DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); -static void -mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) +static int +mt7915_rate_txpower_show(struct seq_file *file, void *data) { static const char * const sku_group_name[] = { "CCK", "OFDM", "HT20", "HT40", @@ -404,14 +396,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]; @@ -419,17 +408,9 @@ 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]; } -} - -static int -mt7915_rate_txpower_show(struct seq_file *file, void *data) -{ - struct mt7915_phy *phy = file->private; - - mt7915_puts_rate_txpower(file, phy); return 0; } -- cgit v1.2.3-70-g09d2 From bb0ae4cfeea9bffaac64b72e238431d5900ee346 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 13 Oct 2021 06:12:10 +0800 Subject: mt76: mt7921: add MU EDCA cmd support Add MU EDCA MCU command support to update MU AC parameter record field from the access point. Co-developed-by: Eric-SY Chang Signed-off-by: Eric-SY Chang Tested-by: Eric-SY Chang Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 55 ++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 848f43c44258..751e621a6f9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -572,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 3f6c9839d9d4..457365f40d30 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -974,7 +974,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]; @@ -995,8 +1018,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) -- cgit v1.2.3-70-g09d2 From 576b4484f3a8f4a1b2067236dda2a1676f82ef36 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:31 +0800 Subject: mt76: mt7921: refactor mac.c to be bus independent This is a preliminary patch to introduce mt7921s support. Split out a new pci_mac.c from mac.c to make mac.c reusable between mt7921s and mt7921e. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 342 +------------------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 25 +- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 12 +- .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 346 +++++++++++++++++++++ 5 files changed, 383 insertions(+), 344 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 3471d82fc265..554202358470 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_MT7921E) += mt7921e.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 +mt7921e-y := pci.o pci_mac.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o trace.o mt7921e-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 0659ff290af9..0857d523bb06 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -49,7 +49,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, @@ -68,8 +68,6 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev) 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, val; @@ -166,8 +164,6 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev) rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; } } - - rcu_read_unlock(); } static void @@ -836,11 +832,10 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, txwi[7] |= cpu_to_le32(val); } -static 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_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) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; @@ -922,87 +917,7 @@ mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *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); - } - } -} - -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_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_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; @@ -1026,141 +941,6 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) ieee80211_start_tx_ba_session(sta, tid, 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); - } - - mt7921_mac_sta_poll(dev); - mt76_worker_schedule(&dev->mt76.tx_worker); -} - static bool mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data) @@ -1328,9 +1108,6 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, 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; @@ -1352,29 +1129,6 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } } -void mt7921_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_mac_reset_counters(struct mt7921_phy *phy) { struct mt7921_dev *dev = phy->dev; @@ -1490,20 +1244,6 @@ 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_txwi_free(dev, txwi, NULL, false, NULL); - dev->mt76.token_count--; - } - spin_unlock_bh(&dev->mt76.token_lock); - idr_destroy(&dev->mt76.token); -} - static void mt7921_vif_connect_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) @@ -1518,74 +1258,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); - - 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; -} - /* system error recovery */ void mt7921_mac_reset_work(struct work_struct *work) { @@ -1607,7 +1279,7 @@ void mt7921_mac_reset_work(struct work_struct *work) for (i = 0; i < 10; i++) { __mt7921_mcu_drv_pmctrl(dev); - if (!mt7921_mac_reset(dev)) + if (!mt7921_dev_reset(dev)) break; } mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index e14b86b1c6d1..70c0f41180a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -133,6 +133,11 @@ struct mt7921_phy { struct delayed_work scan_work; }; +#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev)) +struct mt7921_hif_ops { + int (*reset)(struct mt7921_dev *dev); +}; + struct mt7921_dev { union { /* must be first */ struct mt76_dev mt76; @@ -156,6 +161,7 @@ struct mt7921_dev { struct mt76_connac_pm pm; struct mt76_connac_coredump coredump; + const struct mt7921_hif_ops *hif_ops; }; enum { @@ -325,13 +331,13 @@ 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, @@ -366,4 +372,13 @@ 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); +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); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index b5622b612613..fb19cff4a697 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -104,9 +104,9 @@ static int mt7921_pci_probe(struct pci_dev *pdev, 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, @@ -114,6 +114,11 @@ 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 = { + .reset = mt7921e_mac_reset, + }; + struct mt7921_dev *dev; struct mt76_dev *mdev; int ret; @@ -147,6 +152,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); 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..312e42db40bd --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -0,0 +1,346 @@ +// 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; + + 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; +} -- cgit v1.2.3-70-g09d2 From f1b27f54cf66742965d09c6a92af0360f3203d20 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:32 +0800 Subject: mt76: mt7921: refactor dma.c to be pcie specific This is a preliminary patch to introduce mt7921s support. make dma.c be used dedicately for mt7921e. by moving out mt7921_tx_cleanup from dma.c to mcu.c and then renaming mt7921_tx_cleanup to refect the exact thing the function actually does. Finally, dma.c totally become pcie specific one, only needed to be compiled only when CONFIG_MT7921E is enabled. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 8 +------- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 7 ++++++- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 802e40e42040..d3e2036a1974 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -19,12 +19,6 @@ int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc) return 0; } -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; @@ -37,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 0857d523bb06..eb27d8ab4a8b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1386,7 +1386,7 @@ void mt7921_pm_wake_work(struct work_struct *work) 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); + 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 70c0f41180a1..a6c3661b2bdd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -316,6 +316,12 @@ 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); +} + 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); @@ -330,7 +336,6 @@ 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 mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, -- cgit v1.2.3-70-g09d2 From dfc7743de1ebb5ff5c2ed323eaff1994da11abd9 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:33 +0800 Subject: mt76: mt7921: refactor mcu.c to be bus independent This is a preliminary patch to introduce mt7921s support. Make mcu.c reusable between mt7921s and mt7921e Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 3 +- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 5 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 94 ++------------------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 20 ++++- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 3 + .../net/wireless/mediatek/mt76/mt7921/pci_mac.c | 2 + .../net/wireless/mediatek/mt76/mt7921/pci_mcu.c | 97 ++++++++++++++++++++++ 8 files changed, 130 insertions(+), 95 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 554202358470..4cb0b000cfe1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_MT7921E) += mt7921e.o CFLAGS_trace.o := -I$(src) -mt7921e-y := pci.o pci_mac.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o trace.o +mt7921e-y := pci.o pci_mac.o pci_mcu.o mac.o mcu.o dma.o eeprom.o main.o \ + init.o debugfs.o trace.o mt7921e-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 4ef54343cef3..7956a57510c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -304,6 +304,7 @@ void mt7921_unregister_device(struct mt7921_dev *dev) 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index eb27d8ab4a8b..bb6f0cea93bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1276,12 +1276,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); - + for (i = 0; i < 10; i++) if (!mt7921_dev_reset(dev)) break; - } mutex_unlock(&dev->mt76.mutex); if (i == 10) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 457365f40d30..54a2c846fd0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -160,9 +160,8 @@ 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; @@ -224,9 +223,8 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, return ret; } -static int -mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, - int cmd, int *wait_seq) +int mt7921_mcu_send_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; @@ -590,7 +588,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; @@ -603,20 +601,6 @@ static int mt7921_mcu_restart(struct mt76_dev *dev) sizeof(req), false); } -static int mt7921_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 u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info) { u32 mode = DL_MODE_NEED_RSP; @@ -883,7 +867,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; @@ -911,10 +894,6 @@ int mt7921_run_firmware(struct mt7921_dev *dev) { int err; - err = mt7921_driver_own(dev); - if (err) - return err; - err = mt7921_load_firmware(dev); if (err) return err; @@ -925,23 +904,8 @@ int mt7921_run_firmware(struct mt7921_dev *dev) 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); -} - void mt7921_mcu_exit(struct mt7921_dev *dev) { - mt7921_wfsys_reset(dev); skb_queue_purge(&dev->mt76.mcu.res_q); } @@ -1280,35 +1244,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; @@ -1334,29 +1269,14 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index a6c3661b2bdd..9c15c9bdd41e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -133,9 +133,15 @@ struct mt7921_phy { struct delayed_work scan_work; }; -#define mt7921_dev_reset(dev) ((dev)->hif_ops->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 (*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 { @@ -250,7 +256,6 @@ 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); @@ -364,7 +369,6 @@ 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_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); @@ -383,7 +387,17 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, 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_send_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 mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev); +int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev); + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index fb19cff4a697..171aa2daef4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -117,6 +117,9 @@ static int mt7921_pci_probe(struct pci_dev *pdev, static const struct mt7921_hif_ops mt7921_pcie_ops = { .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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 312e42db40bd..f9547d27356e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -282,6 +282,8 @@ 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); 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..9ac3bc25f067 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c @@ -0,0 +1,97 @@ +// 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; +} + +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; +} -- cgit v1.2.3-70-g09d2 From 033ae79b383020928c687e345661f080e5f42c51 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:34 +0800 Subject: mt76: mt7921: refactor init.c to be bus independent This is a preliminary patch to introduce mt7921s support. Make init.c reusable between mt7921s and mt7921e Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 3 ++ drivers/net/wireless/mediatek/mt76/mt7921/init.c | 27 +----------------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 33 +++++++++++++++++++++- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index d3e2036a1974..8f29d09179e4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -343,6 +343,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/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 7956a57510c4..f0fd32c424c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -181,10 +181,6 @@ static int mt7921_init_hardware(struct mt7921_dev *dev) { int ret, idx, i; - ret = mt7921_dma_init(dev); - if (ret) - return ret; - set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); for (i = 0; i < MT7921_MCU_INIT_RETRY_COUNT; i++) { @@ -192,7 +188,7 @@ static int mt7921_init_hardware(struct mt7921_dev *dev) if (!ret) break; - mt7921_wpdma_reset(dev, true); + mt7921_init_reset(dev); } if (i == MT7921_MCU_INIT_RETRY_COUNT) { @@ -289,24 +285,3 @@ int mt7921_register_device(struct mt7921_dev *dev) return 0; } - -void mt7921_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); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 9c15c9bdd41e..295f57ce7eba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -133,11 +133,13 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 171aa2daef4d..305b63fa1a8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -93,6 +93,32 @@ 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) { @@ -116,6 +142,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, }; 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, @@ -172,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; @@ -193,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); } -- cgit v1.2.3-70-g09d2 From 8910a4e5ba342ad661acb6f99fa14e0dd809465e Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:35 +0800 Subject: mt76: mt7921: add MT7921_COMMON module This is a preliminary patch to introduce mt7921s support. MT7921_COMMON module grouping bus independent objects the both mt7921e and mt7921s can share with and have to rely on. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/Kconfig | 8 ++++++-- drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 7 ++++--- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7921/main.c | 8 ++++++++ drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 8 ++++++++ 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig index 001f2b9cec26..071746809b1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig @@ -1,8 +1,12 @@ # 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 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 4cb0b000cfe1..8cea896d5965 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -1,9 +1,10 @@ # SPDX-License-Identifier: ISC +obj-$(CONFIG_MT7921_COMMON) += mt7921-common.o obj-$(CONFIG_MT7921E) += mt7921e.o CFLAGS_trace.o := -I$(src) -mt7921e-y := pci.o pci_mac.o pci_mcu.o mac.o mcu.o dma.o eeprom.o main.o \ - init.o debugfs.o trace.o -mt7921e-$(CONFIG_NL80211_TESTMODE) += testmode.o +mt7921-common-y := mac.o mcu.o eeprom.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 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index f0fd32c424c6..d310d6e1e566 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -145,6 +145,7 @@ int mt7921_mac_init(struct mt7921_dev *dev) 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) { @@ -285,3 +286,4 @@ int mt7921_register_device(struct mt7921_dev *dev) return 0; } +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 bb6f0cea93bb..e49dfcf5558d 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) { @@ -165,6 +166,7 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev) } } } +EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll); static void mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, @@ -916,6 +918,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } } +EXPORT_SYMBOL_GPL(mt7921_mac_write_txwi); void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) { @@ -940,6 +943,7 @@ void 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 bool mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, @@ -1128,6 +1132,7 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, break; } } +EXPORT_SYMBOL_GPL(mt7921_queue_rx_skb); void mt7921_mac_reset_counters(struct mt7921_phy *phy) { @@ -1243,6 +1248,7 @@ void mt7921_update_channel(struct mt76_phy *mphy) mt76_connac_power_save_sched(mphy, &dev->pm); } +EXPORT_SYMBOL_GPL(mt7921_update_channel); static void mt7921_vif_connect_iter(void *priv, u8 *mac, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index c51266e40cb4..d968990dac6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -237,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) { @@ -646,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) @@ -667,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) @@ -698,6 +701,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } +EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove); void mt7921_tx_worker(struct mt76_worker *w) { @@ -1250,3 +1254,7 @@ const struct ieee80211_ops mt7921_ops = { .flush = mt7921_flush, .set_sar_specs = mt7921_set_sar_specs, }; +EXPORT_SYMBOL_GPL(mt7921_ops); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Sean Wang "); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 54a2c846fd0d..10b992103ade 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -222,6 +222,7 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, return ret; } +EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response); int mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq) @@ -319,6 +320,7 @@ exit: return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); } +EXPORT_SYMBOL_GPL(mt7921_mcu_send_message); static void mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) @@ -600,6 +602,7 @@ 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 u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info) { @@ -903,11 +906,13 @@ int mt7921_run_firmware(struct mt7921_dev *dev) return mt76_connac_mcu_get_nic_capability(&dev->mphy); } +EXPORT_SYMBOL_GPL(mt7921_run_firmware); void mt7921_mcu_exit(struct mt7921_dev *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) { @@ -1082,6 +1087,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) { @@ -1264,6 +1270,7 @@ out: return err; } +EXPORT_SYMBOL_GPL(mt7921_mcu_drv_pmctrl); int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev) { @@ -1285,6 +1292,7 @@ out: return err; } +EXPORT_SYMBOL_GPL(mt7921_mcu_fw_pmctrl); int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, struct ieee80211_vif *vif, -- cgit v1.2.3-70-g09d2 From 87f9bf24ea840b3fff025a856e7746514ce12bd3 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:36 +0800 Subject: mt76: connac: move mcu reg access utility routines in mt76_connac_lib module Move mcu reg access shared between mt7663s and mt7921s in mt76_connac_lib module. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 27 ++++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 9a1af2ba7e8e..70d72dfa239e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -2412,6 +2412,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 "); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 751e621a6f9b..b89faab04996 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1114,4 +1114,6 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, 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 */ -- cgit v1.2.3-70-g09d2 From 02fbf8199f6e2724d0b96cc0cbd1847d13b4f9fa Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:37 +0800 Subject: mt76: mt7663s: rely on mcu reg access utility rely on mcu reg access utility and drop the duplicated code. Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 28 ---------------------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 -- .../net/wireless/mediatek/mt76/mt7615/sdio_mcu.c | 4 ++-- 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 2ba730808f3b..2cb3969e6432 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2769,31 +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); } - -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 58a98b5c0cbc..437f14f06e63 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -553,8 +553,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index 45c1cd3b9f49..517419bb7772 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -137,8 +137,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; -- cgit v1.2.3-70-g09d2 From f0ff5d3aa648128d0fc8055df072551d0d89c88d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:38 +0800 Subject: mt76: mt7921: make all event parser reusable between mt7921s and mt7921e The longer event such as the event for mcu_get_nic_capability would hold the data in paged fragment skb for the SDIO device so we turn the skb to be linearized skb before accessing it to reuse the same event parser betweem mt7921s and mt7921e. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 10b992103ade..e315eb4186d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -455,7 +455,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); -- cgit v1.2.3-70-g09d2 From f1e2eef111018a4f0d280656be4351c37e9e554b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:39 +0800 Subject: mt76: mt7921: use physical addr to unify register access Use physical address to unify the register access and reorder the entries in fixed_map table to accelerate the address lookup for MT7921e. Cosmetics the patch with adding an extra space to make all entries in the array style consistent. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 27 ++++++++++++------------ drivers/net/wireless/mediatek/mt76/mt7921/regs.h | 22 +++++++++---------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 8f29d09179e4..cdff1fd52d93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -85,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) */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h index 26fb11823762..cb6069024320 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) @@ -93,7 +93,7 @@ #define MT_LPON_TCR_SW_WRITE BIT(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) @@ -142,7 +142,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) @@ -152,7 +152,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 | \ @@ -160,7 +160,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) @@ -191,7 +191,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) @@ -201,7 +201,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) -- cgit v1.2.3-70-g09d2 From 764dee47e2c1ed828c8a51cbf58f89b5e3ded11b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 07:11:40 +0800 Subject: mt76: sdio: move common code in mt76_sdio module Move sdio common code in mt76_sdio module. This is a preliminary patch to support mt7921s devices. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt76.h | 16 + drivers/net/wireless/mediatek/mt76/mt7615/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 4 - drivers/net/wireless/mediatek/mt76/mt7615/sdio.c | 279 ++--------------- drivers/net/wireless/mediatek/mt76/mt7615/sdio.h | 115 ------- .../net/wireless/mediatek/mt76/mt7615/sdio_mcu.c | 6 +- .../net/wireless/mediatek/mt76/mt7615/sdio_txrx.c | 334 --------------------- drivers/net/wireless/mediatek/mt76/sdio.c | 265 ++++++++++++++++ drivers/net/wireless/mediatek/mt76/sdio.h | 115 +++++++ drivers/net/wireless/mediatek/mt76/sdio_txrx.c | 328 ++++++++++++++++++++ 11 files changed, 748 insertions(+), 718 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c create mode 100644 drivers/net/wireless/mediatek/mt76/sdio.h create mode 100644 drivers/net/wireless/mediatek/mt76/sdio_txrx.c 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/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a28e5c0a158f..8dc4bbaca15d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1248,6 +1248,22 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, 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); +int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func); +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, 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/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 437f14f06e63..77bd59813d47 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -569,10 +569,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/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index ff1e62035f37..14108e3fadda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -14,8 +14,8 @@ #include #include +#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); -} - -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); - } -} + 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 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,66 +50,6 @@ 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) -{ - u32 status, ctrl; - int ret; - - 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(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; - - sdio_release_host(func); - - return 0; - -disable_func: - sdio_disable_func(func); -release: - sdio_release_host(func); - - return ret; -} - static int mt7663s_probe(struct sdio_func *func, const struct sdio_device_id *id) { @@ -307,13 +66,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 +100,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); if (ret) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h deleted file mode 100644 index 03877d89e152..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: ISC */ -/* Copyright (C) 2020 MediaTek Inc. - * - * Author: Sean Wang - */ - -#ifndef __MT76S_H -#define __MT76S_H - -#define MT_PSE_PAGE_SZ 128 - -#define MCR_WCIR 0x0000 -#define MCR_WHLPCR 0x0004 -#define WHLPCR_FW_OWN_REQ_CLR BIT(9) -#define WHLPCR_FW_OWN_REQ_SET BIT(8) -#define WHLPCR_IS_DRIVER_OWN BIT(8) -#define WHLPCR_INT_EN_CLR BIT(1) -#define WHLPCR_INT_EN_SET BIT(0) - -#define MCR_WSDIOCSR 0x0008 -#define MCR_WHCR 0x000C -#define W_INT_CLR_CTRL BIT(1) -#define RECV_MAILBOX_RD_CLR_EN BIT(2) -#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8) -#define RX_ENHANCE_MODE BIT(16) - -#define MCR_WHISR 0x0010 -#define MCR_WHIER 0x0014 -#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_RX1_DONE_INT_EN BIT(2) -#define WHIER_RX0_DONE_INT_EN BIT(1) -#define WHIER_TX_DONE_INT_EN BIT(0) -#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ - WHIER_RX1_DONE_INT_EN | \ - WHIER_TX_DONE_INT_EN | \ - WHIER_ABNORMAL_INT_EN | \ - WHIER_D2H_SW_INT) - -#define MCR_WASR 0x0020 -#define MCR_WSICR 0x0024 -#define MCR_WTSR0 0x0028 -#define TQ0_CNT GENMASK(7, 0) -#define TQ1_CNT GENMASK(15, 8) -#define TQ2_CNT GENMASK(23, 16) -#define TQ3_CNT GENMASK(31, 24) - -#define MCR_WTSR1 0x002c -#define TQ4_CNT GENMASK(7, 0) -#define TQ5_CNT GENMASK(15, 8) -#define TQ6_CNT GENMASK(23, 16) -#define TQ7_CNT GENMASK(31, 24) - -#define MCR_WTDR1 0x0034 -#define MCR_WRDR0 0x0050 -#define MCR_WRDR1 0x0054 -#define MCR_WRDR(p) (0x0050 + 4 * (p)) -#define MCR_H2DSM0R 0x0070 -#define H2D_SW_INT_READ BIT(16) -#define H2D_SW_INT_WRITE BIT(17) - -#define MCR_H2DSM1R 0x0074 -#define MCR_D2HRM0R 0x0078 -#define MCR_D2HRM1R 0x007c -#define MCR_D2HRM2R 0x0080 -#define MCR_WRPLR 0x0090 -#define RX0_PACKET_LENGTH GENMASK(15, 0) -#define RX1_PACKET_LENGTH GENMASK(31, 16) - -#define MCR_WTMDR 0x00b0 -#define MCR_WTMCR 0x00b4 -#define MCR_WTMDPCR0 0x00b8 -#define MCR_WTMDPCR1 0x00bc -#define MCR_WPLRCR 0x00d4 -#define MCR_WSR 0x00D8 -#define MCR_CLKIOCR 0x0100 -#define MCR_CMDIOCR 0x0104 -#define MCR_DAT0IOCR 0x0108 -#define MCR_DAT1IOCR 0x010C -#define MCR_DAT2IOCR 0x0110 -#define MCR_DAT3IOCR 0x0114 -#define MCR_CLKDLYCR 0x0118 -#define MCR_CMDDLYCR 0x011C -#define MCR_ODATDLYCR 0x0120 -#define MCR_IDATDLYCR1 0x0124 -#define MCR_IDATDLYCR2 0x0128 -#define MCR_ILCHCR 0x012C -#define MCR_WTQCR0 0x0130 -#define MCR_WTQCR1 0x0134 -#define MCR_WTQCR2 0x0138 -#define MCR_WTQCR3 0x013C -#define MCR_WTQCR4 0x0140 -#define MCR_WTQCR5 0x0144 -#define MCR_WTQCR6 0x0148 -#define MCR_WTQCR7 0x014C -#define MCR_WTQCR(x) (0x130 + 4 * (x)) -#define TXQ_CNT_L GENMASK(15, 0) -#define TXQ_CNT_H GENMASK(31, 16) - -#define MCR_SWPCDBGR 0x0154 - -struct mt76s_intr { - u32 isr; - struct { - u32 wtqcr[8]; - } tx; - struct { - u16 num[2]; - u16 len[2][16]; - } rx; - u32 rec_mb[2]; -} __packed; - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index 517419bb7772..f76986c807ab 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 #include +#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) { @@ -63,7 +63,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 +111,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"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c deleted file mode 100644 index 04f4c89b7499..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c +++ /dev/null @@ -1,334 +0,0 @@ -// SPDX-License-Identifier: ISC -/* Copyright (C) 2020 MediaTek Inc. - * - * Author: Felix Fietkau - * Lorenzo Bianconi - * Sean Wang - */ - -#include -#include -#include - -#include -#include -#include - -#include "../trace.h" -#include "mt7615.h" -#include "sdio.h" -#include "mac.h" - -static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data) -{ - u32 ple_ac_data_quota[] = { - FIELD_GET(TXQ_CNT_L, data[4]), /* VO */ - FIELD_GET(TXQ_CNT_H, data[3]), /* VI */ - FIELD_GET(TXQ_CNT_L, data[3]), /* BE */ - FIELD_GET(TXQ_CNT_H, data[2]), /* BK */ - }; - u32 pse_ac_data_quota[] = { - FIELD_GET(TXQ_CNT_H, data[1]), /* VO */ - FIELD_GET(TXQ_CNT_L, data[1]), /* VI */ - FIELD_GET(TXQ_CNT_H, data[0]), /* BE */ - FIELD_GET(TXQ_CNT_L, data[0]), /* BK */ - }; - u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]); - u32 pse_data_quota = 0, ple_data_quota = 0; - struct mt76_sdio *sdio = &dev->sdio; - int i; - - for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) { - pse_data_quota += pse_ac_data_quota[i]; - ple_data_quota += ple_ac_data_quota[i]; - } - - if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota) - return 0; - - sdio->sched.pse_mcu_quota += pse_mcu_quota; - sdio->sched.pse_data_quota += pse_data_quota; - sdio->sched.ple_data_quota += ple_data_quota; - - 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) -{ - int len = min_t(int, data_len, MT_SKB_HEAD_LEN); - struct sk_buff *skb; - - skb = alloc_skb(len, GFP_KERNEL); - if (!skb) - return NULL; - - skb_put_data(skb, data, len); - if (data_len > len) { - struct page *page; - - data += len; - page = virt_to_head_page(data); - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - page, data - page_address(page), - data_len - len, buf_len); - get_page(page); - } - - return skb; -} - -static int mt7663s_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; - int len = 0, err, i; - struct page *page; - u8 *buf; - - for (i = 0; i < intr->rx.num[qid]; i++) - len += round_up(intr->rx.len[qid][i] + 4, 4); - - if (!len) - return 0; - - if (len > sdio->func->cur_blksize) - len = roundup(len, sdio->func->cur_blksize); - - page = __dev_alloc_pages(GFP_KERNEL, get_order(len)); - if (!page) - return -ENOMEM; - - buf = page_address(page); - - err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len); - if (err < 0) { - dev_err(dev->dev, "sdio read data failed:%d\n", err); - put_page(page); - return err; - } - - for (i = 0; i < intr->rx.num[qid]; i++) { - int index = (q->head + i) % q->ndesc; - struct mt76_queue_entry *e = &q->entry[index]; - - len = intr->rx.len[qid][i]; - e->skb = mt7663s_build_rx_skb(buf, len, round_up(len + 4, 4)); - if (!e->skb) - break; - - buf += round_up(len + 4, 4); - if (q->queued + i + 1 == q->ndesc) - break; - } - put_page(page); - - spin_lock_bh(&q->lock); - q->head = (q->head + i) % q->ndesc; - q->queued += i; - spin_unlock_bh(&q->lock); - - return i; -} - -static int mt7663s_rx_handler(struct mt76_dev *dev) -{ - struct mt76_sdio *sdio = &dev->sdio; - struct mt76s_intr *intr = sdio->intr_data; - int nframes = 0, ret; - - ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr)); - if (ret < 0) - return ret; - - trace_dev_irq(dev, intr->isr, 0); - - if (intr->isr & WHIER_RX0_DONE_INT_EN) { - ret = mt7663s_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 (ret > 0) { - mt76_worker_schedule(&sdio->net_worker); - nframes += ret; - } - } - - nframes += !!mt7663s_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) -{ - int pse_sz; - - pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ); - - if (mcu) { - if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz) - return -EBUSY; - } else { - if (sdio->sched.pse_data_quota < *pse_size + pse_sz || - sdio->sched.ple_data_quota < *ple_size + 1) - return -EBUSY; - - *ple_size = *ple_size + 1; - } - *pse_size = *pse_size + pse_sz; - - return 0; -} - -static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, - int pse_size, int ple_size) -{ - if (mcu) { - sdio->sched.pse_mcu_quota -= pse_size; - } else { - sdio->sched.pse_data_quota -= pse_size; - sdio->sched.ple_data_quota -= ple_size; - } -} - -static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) -{ - struct mt76_sdio *sdio = &dev->sdio; - int err; - - if (len > sdio->func->cur_blksize) - len = roundup(len, sdio->func->cur_blksize); - - err = sdio_writesb(sdio->func, MCR_WTDR1, data, len); - if (err) - dev_err(dev->dev, "sdio write failed: %d\n", err); - - return err; -} - -static int mt7663s_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]; - struct mt76_sdio *sdio = &dev->sdio; - u8 pad; - - qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid; - while (q->first != q->head) { - struct mt76_queue_entry *e = &q->entry[q->first]; - struct sk_buff *iter; - - smp_rmb(); - - 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); - if (err) - return err; - - goto next; - } - - pad = roundup(e->skb->len, 4) - e->skb->len; - 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)) - break; - - memcpy(sdio->xmit_buf[qid] + len, e->skb->data, - skb_headlen(e->skb)); - len += skb_headlen(e->skb); - nframes++; - - skb_walk_frags(e->skb, iter) { - memcpy(sdio->xmit_buf[qid] + len, iter->data, - iter->len); - len += iter->len; - nframes++; - } - - if (unlikely(pad)) { - memset(sdio->xmit_buf[qid] + len, 0, pad); - len += pad; - } -next: - q->first = (q->first + 1) % q->ndesc; - e->done = true; - } - - if (nframes) { - memset(sdio->xmit_buf[qid] + len, 0, 4); - err = __mt7663s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4); - if (err) - return err; - } - mt7663s_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) -{ - 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); - 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); - - do { - nframes = 0; - - /* tx */ - for (i = 0; i <= MT_TXQ_PSD; i++) { - ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]); - if (ret > 0) - nframes += ret; - } - ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]); - if (ret > 0) - nframes += ret; - - /* rx */ - ret = mt7663s_rx_handler(mdev); - if (ret > 0) - nframes += ret; - } 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); -} - -void mt7663s_sdio_irq(struct sdio_func *func) -{ - struct mt7615_dev *dev = sdio_get_drvdata(func); - struct mt76_sdio *sdio = &dev->mt76.sdio; - - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state)) - return; - - mt76_worker_schedule(&sdio->txrx_worker); -} diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index f7a1838b4576..7e613462b60e 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -16,6 +16,271 @@ #include #include "mt76.h" +#include "sdio.h" + +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) +{ + u32 status, ctrl; + int ret; + + 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; + 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, 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) { diff --git a/drivers/net/wireless/mediatek/mt76/sdio.h b/drivers/net/wireless/mediatek/mt76/sdio.h new file mode 100644 index 000000000000..03877d89e152 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/sdio.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Sean Wang + */ + +#ifndef __MT76S_H +#define __MT76S_H + +#define MT_PSE_PAGE_SZ 128 + +#define MCR_WCIR 0x0000 +#define MCR_WHLPCR 0x0004 +#define WHLPCR_FW_OWN_REQ_CLR BIT(9) +#define WHLPCR_FW_OWN_REQ_SET BIT(8) +#define WHLPCR_IS_DRIVER_OWN BIT(8) +#define WHLPCR_INT_EN_CLR BIT(1) +#define WHLPCR_INT_EN_SET BIT(0) + +#define MCR_WSDIOCSR 0x0008 +#define MCR_WHCR 0x000C +#define W_INT_CLR_CTRL BIT(1) +#define RECV_MAILBOX_RD_CLR_EN BIT(2) +#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8) +#define RX_ENHANCE_MODE BIT(16) + +#define MCR_WHISR 0x0010 +#define MCR_WHIER 0x0014 +#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_RX1_DONE_INT_EN BIT(2) +#define WHIER_RX0_DONE_INT_EN BIT(1) +#define WHIER_TX_DONE_INT_EN BIT(0) +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ + WHIER_RX1_DONE_INT_EN | \ + WHIER_TX_DONE_INT_EN | \ + WHIER_ABNORMAL_INT_EN | \ + WHIER_D2H_SW_INT) + +#define MCR_WASR 0x0020 +#define MCR_WSICR 0x0024 +#define MCR_WTSR0 0x0028 +#define TQ0_CNT GENMASK(7, 0) +#define TQ1_CNT GENMASK(15, 8) +#define TQ2_CNT GENMASK(23, 16) +#define TQ3_CNT GENMASK(31, 24) + +#define MCR_WTSR1 0x002c +#define TQ4_CNT GENMASK(7, 0) +#define TQ5_CNT GENMASK(15, 8) +#define TQ6_CNT GENMASK(23, 16) +#define TQ7_CNT GENMASK(31, 24) + +#define MCR_WTDR1 0x0034 +#define MCR_WRDR0 0x0050 +#define MCR_WRDR1 0x0054 +#define MCR_WRDR(p) (0x0050 + 4 * (p)) +#define MCR_H2DSM0R 0x0070 +#define H2D_SW_INT_READ BIT(16) +#define H2D_SW_INT_WRITE BIT(17) + +#define MCR_H2DSM1R 0x0074 +#define MCR_D2HRM0R 0x0078 +#define MCR_D2HRM1R 0x007c +#define MCR_D2HRM2R 0x0080 +#define MCR_WRPLR 0x0090 +#define RX0_PACKET_LENGTH GENMASK(15, 0) +#define RX1_PACKET_LENGTH GENMASK(31, 16) + +#define MCR_WTMDR 0x00b0 +#define MCR_WTMCR 0x00b4 +#define MCR_WTMDPCR0 0x00b8 +#define MCR_WTMDPCR1 0x00bc +#define MCR_WPLRCR 0x00d4 +#define MCR_WSR 0x00D8 +#define MCR_CLKIOCR 0x0100 +#define MCR_CMDIOCR 0x0104 +#define MCR_DAT0IOCR 0x0108 +#define MCR_DAT1IOCR 0x010C +#define MCR_DAT2IOCR 0x0110 +#define MCR_DAT3IOCR 0x0114 +#define MCR_CLKDLYCR 0x0118 +#define MCR_CMDDLYCR 0x011C +#define MCR_ODATDLYCR 0x0120 +#define MCR_IDATDLYCR1 0x0124 +#define MCR_IDATDLYCR2 0x0128 +#define MCR_ILCHCR 0x012C +#define MCR_WTQCR0 0x0130 +#define MCR_WTQCR1 0x0134 +#define MCR_WTQCR2 0x0138 +#define MCR_WTQCR3 0x013C +#define MCR_WTQCR4 0x0140 +#define MCR_WTQCR5 0x0144 +#define MCR_WTQCR6 0x0148 +#define MCR_WTQCR7 0x014C +#define MCR_WTQCR(x) (0x130 + 4 * (x)) +#define TXQ_CNT_L GENMASK(15, 0) +#define TXQ_CNT_H GENMASK(31, 16) + +#define MCR_SWPCDBGR 0x0154 + +struct mt76s_intr { + u32 isr; + struct { + u32 wtqcr[8]; + } tx; + struct { + u16 num[2]; + u16 len[2][16]; + } rx; + u32 rec_mb[2]; +} __packed; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c new file mode 100644 index 000000000000..ceb3dc0613d6 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ + +#include +#include +#include + +#include +#include +#include + +#include "trace.h" +#include "sdio.h" +#include "mt76.h" + +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 */ + FIELD_GET(TXQ_CNT_H, data[3]), /* VI */ + FIELD_GET(TXQ_CNT_L, data[3]), /* BE */ + FIELD_GET(TXQ_CNT_H, data[2]), /* BK */ + }; + u32 pse_ac_data_quota[] = { + FIELD_GET(TXQ_CNT_H, data[1]), /* VO */ + FIELD_GET(TXQ_CNT_L, data[1]), /* VI */ + FIELD_GET(TXQ_CNT_H, data[0]), /* BE */ + FIELD_GET(TXQ_CNT_L, data[0]), /* BK */ + }; + u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]); + u32 pse_data_quota = 0, ple_data_quota = 0; + struct mt76_sdio *sdio = &dev->sdio; + int i; + + for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) { + pse_data_quota += pse_ac_data_quota[i]; + ple_data_quota += ple_ac_data_quota[i]; + } + + if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota) + return 0; + + sdio->sched.pse_mcu_quota += pse_mcu_quota; + sdio->sched.pse_data_quota += pse_data_quota; + sdio->sched.ple_data_quota += ple_data_quota; + + return pse_data_quota + ple_data_quota + pse_mcu_quota; +} + +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; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return NULL; + + skb_put_data(skb, data, len); + if (data_len > len) { + struct page *page; + + data += len; + page = virt_to_head_page(data); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + page, data - page_address(page), + data_len - len, buf_len); + get_page(page); + } + + return skb; +} + +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; + int len = 0, err, i; + struct page *page; + u8 *buf; + + for (i = 0; i < intr->rx.num[qid]; i++) + len += round_up(intr->rx.len[qid][i] + 4, 4); + + if (!len) + return 0; + + if (len > sdio->func->cur_blksize) + len = roundup(len, sdio->func->cur_blksize); + + page = __dev_alloc_pages(GFP_KERNEL, get_order(len)); + if (!page) + return -ENOMEM; + + buf = page_address(page); + + err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len); + if (err < 0) { + dev_err(dev->dev, "sdio read data failed:%d\n", err); + put_page(page); + return err; + } + + for (i = 0; i < intr->rx.num[qid]; i++) { + int index = (q->head + i) % q->ndesc; + struct mt76_queue_entry *e = &q->entry[index]; + + len = intr->rx.len[qid][i]; + e->skb = mt76s_build_rx_skb(buf, len, round_up(len + 4, 4)); + if (!e->skb) + break; + + buf += round_up(len + 4, 4); + if (q->queued + i + 1 == q->ndesc) + break; + } + put_page(page); + + spin_lock_bh(&q->lock); + q->head = (q->head + i) % q->ndesc; + q->queued += i; + spin_unlock_bh(&q->lock); + + return i; +} + +static int mt76s_rx_handler(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + struct mt76s_intr *intr = sdio->intr_data; + int nframes = 0, ret; + + ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr)); + if (ret < 0) + return ret; + + trace_dev_irq(dev, intr->isr, 0); + + 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 = mt76s_rx_run_queue(dev, 1, intr); + if (ret > 0) { + mt76_worker_schedule(&sdio->net_worker); + nframes += ret; + } + } + + nframes += !!mt76s_refill_sched_quota(dev, intr->tx.wtqcr); + + return nframes; +} + +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); + + if (mcu) { + if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz) + return -EBUSY; + } else { + if (sdio->sched.pse_data_quota < *pse_size + pse_sz || + sdio->sched.ple_data_quota < *ple_size + 1) + return -EBUSY; + + *ple_size = *ple_size + 1; + } + *pse_size = *pse_size + pse_sz; + + return 0; +} + +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; + } else { + sdio->sched.pse_data_quota -= pse_size; + sdio->sched.ple_data_quota -= ple_size; + } +} + +static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) +{ + struct mt76_sdio *sdio = &dev->sdio; + int err; + + if (len > sdio->func->cur_blksize) + len = roundup(len, sdio->func->cur_blksize); + + err = sdio_writesb(sdio->func, MCR_WTDR1, data, len); + if (err) + dev_err(dev->dev, "sdio write failed: %d\n", err); + + return err; +} + +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]; + struct mt76_sdio *sdio = &dev->sdio; + u8 pad; + + qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid; + while (q->first != q->head) { + struct mt76_queue_entry *e = &q->entry[q->first]; + struct sk_buff *iter; + + smp_rmb(); + + if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) { + __skb_put_zero(e->skb, 4); + err = __mt76s_xmit_queue(dev, e->skb->data, + e->skb->len); + if (err) + return err; + + goto next; + } + + pad = roundup(e->skb->len, 4) - e->skb->len; + if (len + e->skb->len + pad + 4 > MT76S_XMIT_BUF_SZ) + break; + + if (mt76s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz, + &ple_sz)) + break; + + memcpy(sdio->xmit_buf[qid] + len, e->skb->data, + skb_headlen(e->skb)); + len += skb_headlen(e->skb); + nframes++; + + skb_walk_frags(e->skb, iter) { + memcpy(sdio->xmit_buf[qid] + len, iter->data, + iter->len); + len += iter->len; + nframes++; + } + + if (unlikely(pad)) { + memset(sdio->xmit_buf[qid] + len, 0, pad); + len += pad; + } +next: + q->first = (q->first + 1) % q->ndesc; + e->done = true; + } + + if (nframes) { + memset(sdio->xmit_buf[qid] + len, 0, 4); + err = __mt76s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4); + if (err) + return err; + } + mt76s_tx_update_quota(sdio, mcu, pse_sz, ple_sz); + + mt76_worker_schedule(&sdio->status_worker); + + return nframes; +} + +void mt76s_txrx_worker(struct mt76_sdio *sdio) +{ + struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); + int i, nframes, ret; + + /* disable interrupt */ + sdio_claim_host(sdio->func); + sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); + + do { + nframes = 0; + + /* tx */ + for (i = 0; i <= MT_TXQ_PSD; i++) { + ret = mt76s_tx_run_queue(dev, dev->phy.q_tx[i]); + if (ret > 0) + nframes += ret; + } + ret = mt76s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]); + if (ret > 0) + nframes += ret; + + /* rx */ + ret = mt76s_rx_handler(dev); + if (ret > 0) + nframes += ret; + } while (nframes > 0); + + /* enable interrupt */ + sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL); + sdio_release_host(sdio->func); +} +EXPORT_SYMBOL_GPL(mt76s_txrx_worker); + +void mt76s_sdio_irq(struct sdio_func *func) +{ + struct mt76_dev *dev = sdio_get_drvdata(func); + struct mt76_sdio *sdio = &dev->sdio; + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state)) + return; + + mt76_worker_schedule(&sdio->txrx_worker); +} +EXPORT_SYMBOL_GPL(mt76s_sdio_irq); -- cgit v1.2.3-70-g09d2 From 3ad0850934179103e7c4ba8574139543b1109bbf Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 07:11:41 +0800 Subject: mt76: sdio: introduce parse_irq callback Add parse_irq to handle that interrupt status structure is different between mt7663s and mt7921s. This is a preliminary patch to introduce mt7921s driver Tested-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 12 +++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/sdio.c | 23 +++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/sdio.h | 10 +++++----- drivers/net/wireless/mediatek/mt76/sdio_txrx.c | 18 ++++++++--------- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8dc4bbaca15d..a3fc0c920f46 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; @@ -512,6 +513,8 @@ struct mt76_sdio { int pse_mcu_quota; int deficit; } sched; + + int (*parse_irq)(struct mt76_dev *dev, struct mt76s_intr *intr); }; struct mt76_mmio { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 77bd59813d47..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 */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index 14108e3fadda..8d23dd4d5457 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -50,6 +50,26 @@ static void mt7663s_init_work(struct work_struct *work) mt7615_init_work(dev); } +static int mt7663s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr) +{ + struct mt76_sdio *sdio = &dev->sdio; + struct mt7663s_intr *irq_data = sdio->intr_data; + int i, err; + + err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data)); + if (err) + 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++) + intr->rx.len[i] = irq_data->rx.len[i]; + + return 0; +} + static int mt7663s_probe(struct sdio_func *func, const struct sdio_device_id *id) { @@ -108,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; diff --git a/drivers/net/wireless/mediatek/mt76/sdio.h b/drivers/net/wireless/mediatek/mt76/sdio.h index 03877d89e152..dfcba5e3786c 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.h +++ b/drivers/net/wireless/mediatek/mt76/sdio.h @@ -102,14 +102,14 @@ 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/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index ceb3dc0613d6..f94de48ebadc 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -135,32 +135,32 @@ mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid, 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 = mt76s_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 = mt76s_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 += !!mt76s_refill_sched_quota(dev, intr->tx.wtqcr); + nframes += !!mt76s_refill_sched_quota(dev, intr.tx.wtqcr); return nframes; } -- cgit v1.2.3-70-g09d2 From dacf0acfe2ce8179d5b470f43099ce92213ede90 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:42 +0800 Subject: mt76: sdio: extend sdio module to support CONNAC2 Extend sdio module to support CONNAC2 hw that mt7921s rely on. Tested-by: Deren Wu Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 +++- drivers/net/wireless/mediatek/mt76/mt7615/sdio.c | 2 +- drivers/net/wireless/mediatek/mt76/sdio.c | 23 ++++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/sdio.h | 23 +++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/sdio_txrx.c | 7 ++++++- 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a3fc0c920f46..85afe05d7f30 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -506,6 +506,7 @@ struct mt76_sdio { struct sdio_func *func; void *intr_data; + u8 hw_ver; struct { int pse_data_quota; @@ -1253,7 +1254,8 @@ 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); -int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func); +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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index 8d23dd4d5457..31c4a76b7f91 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -120,7 +120,7 @@ static int mt7663s_probe(struct sdio_func *func, if (ret < 0) goto error; - ret = mt76s_hw_init(mdev, func); + ret = mt76s_hw_init(mdev, func, MT76_CONNAC_SDIO); if (ret) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 7e613462b60e..c99acc21225e 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -221,11 +221,13 @@ int mt76s_rd_rp(struct mt76_dev *dev, u32 base, } EXPORT_SYMBOL_GPL(mt76s_rd_rp); -int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func) +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); @@ -255,12 +257,27 @@ int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func) 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; - /* set WHISR as read clear and Rx aggregation number as 16 */ - ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16); + 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; diff --git a/drivers/net/wireless/mediatek/mt76/sdio.h b/drivers/net/wireless/mediatek/mt76/sdio.h index dfcba5e3786c..99db4ad93b7c 100644 --- a/drivers/net/wireless/mediatek/mt76/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,6 +106,23 @@ #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; diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index f94de48ebadc..2728d45a2e61 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -112,8 +112,10 @@ mt76s_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]; + /* 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; @@ -173,6 +175,9 @@ mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz, pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ); + if (mcu && sdio->hw_ver == MT76_CONNAC2_SDIO) + pse_sz = 1; + if (mcu) { if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz) return -EBUSY; -- cgit v1.2.3-70-g09d2 From 8c94f0e63bb3f6ea5755d416293788ba93dfc82f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:43 +0800 Subject: mt76: connac: extend mcu_get_nic_capability Extend mcu_get_nic_capability to obtain tx resource for SDIO device, MAC address, and PHY capability. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 66 ++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 85afe05d7f30..46e8fe3869c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -512,6 +512,7 @@ struct mt76_sdio { int pse_data_quota; int ple_data_quota; int pse_mcu_quota; + int pse_page_size; int deficit; } sched; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 70d72dfa239e..32e25180fc1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1722,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 { @@ -1764,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; } -- cgit v1.2.3-70-g09d2 From 16d98b548365fcd6fc3fe2e1ae73c9e3cc5ee43d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:44 +0800 Subject: mt76: mt7921: rely on mcu_get_nic_capability Rely on mcu_get_nic_capability to obtain Tx quota information for the SDIO device, get PHY capability, MAC address and then we can totally drop mt7921/eeprom.c and any unnecessary code. Noting that mt76_connac_mcu_get_nic_capability should be run before set flag MT76_STATE_MCU_RUNNING being set to setup the proper parameters like Tx quota control before the device is started to running. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/sdio_mcu.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c | 101 --------------------- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 10 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 8 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 8 -- drivers/net/wireless/mediatek/mt76/sdio_txrx.c | 3 +- 7 files changed, 10 insertions(+), 123 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index f76986c807ab..dc9a2f0b45a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 8cea896d5965..5f32c2c71134 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -5,6 +5,6 @@ obj-$(CONFIG_MT7921E) += mt7921e.o CFLAGS_trace.o := -I$(src) -mt7921-common-y := mac.o mcu.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 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 4d0a4aeac6bf..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c +++ /dev/null @@ -1,101 +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 0x7922: - 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 d310d6e1e566..6a4b014e8afd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -149,7 +149,6 @@ EXPORT_SYMBOL_GPL(mt7921_mac_init); static int __mt7921_init_hardware(struct mt7921_dev *dev) { - struct mt76_dev *mdev = &dev->mt76; int ret; /* force firmware operation mode into normal state, @@ -160,9 +159,7 @@ static int __mt7921_init_hardware(struct mt7921_dev *dev) if (ret) goto out; - ret = mt7921_eeprom_init(dev); - if (ret) - goto out; + mt76_eeprom_override(&dev->mphy); ret = mt7921_mcu_set_eeprom(dev); if (ret) @@ -170,11 +167,6 @@ static int __mt7921_init_hardware(struct mt7921_dev *dev) ret = mt7921_mac_init(dev); out: - if (ret && mdev->eeprom.data) { - devm_kfree(mdev->dev, mdev->eeprom.data); - mdev->eeprom.data = NULL; - } - return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index e315eb4186d3..a95495069a4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -906,10 +906,12 @@ int mt7921_run_firmware(struct mt7921_dev *dev) if (err) return err; - set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); - mt7921_mcu_fw_log_2_host(dev, 1); + err = mt76_connac_mcu_get_nic_capability(&dev->mphy); + if (err) + return err; - return mt76_connac_mcu_get_nic_capability(&dev->mphy); + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + return mt7921_mcu_fw_log_2_host(dev, 1); } EXPORT_SYMBOL_GPL(mt7921_run_firmware); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 295f57ce7eba..2082b4d2a23d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -156,8 +156,6 @@ 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; @@ -247,12 +245,6 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index 2728d45a2e61..9b4c95a47d47 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -173,7 +173,8 @@ mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz, { 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; -- cgit v1.2.3-70-g09d2 From fe0195f7563314a88cf08a1e7e528d3c0266fbbe Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:45 +0800 Subject: mt76: mt7921: refactor mt7921_mcu_send_message This is a preliminary patch to introduce mt7921s support. Refactor mt7921_mcu_send_message to be sharable between mt7921s and mt7921e. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 11 ++++------- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index a95495069a4d..44e74e43ee78 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -224,12 +224,11 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, } EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response); -int mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, +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; @@ -251,10 +250,8 @@ int 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); @@ -318,9 +315,9 @@ exit: if (wait_seq) *wait_seq = seq; - return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); + return 0; } -EXPORT_SYMBOL_GPL(mt7921_mcu_send_message); +EXPORT_SYMBOL_GPL(mt7921_mcu_fill_message); static void mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 2082b4d2a23d..f4b85ec530bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -381,7 +381,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, 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_send_message(struct mt76_dev *mdev, struct sk_buff *skb, +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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c index 9ac3bc25f067..583a89a34734 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c @@ -18,6 +18,24 @@ static int mt7921e_driver_own(struct mt7921_dev *dev) 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 = { -- cgit v1.2.3-70-g09d2 From 48fab5bbef4092d925ab3214773ad12e68807223 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:46 +0800 Subject: mt76: mt7921: introduce mt7921s support Introduce support for mt7921s 802.11ax (Wi-Fi 6) 2x2:2SS chipset. Tested-by: Deren Wu Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/Kconfig | 10 + drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 2 + .../net/wireless/mediatek/mt76/mt7921/debugfs.c | 18 +- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 11 +- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 22 +- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 4 + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 14 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 43 +++ drivers/net/wireless/mediatek/mt76/mt7921/sdio.c | 314 +++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/sdio_mac.c | 87 ++++++ .../net/wireless/mediatek/mt76/mt7921/sdio_mcu.c | 127 +++++++++ 11 files changed, 637 insertions(+), 15 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig index 071746809b1c..ce3a06227901 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig @@ -13,3 +13,13 @@ config MT7921E 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 5f32c2c71134..1187acedfeda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -2,9 +2,11 @@ obj-$(CONFIG_MT7921_COMMON) += mt7921-common.o obj-$(CONFIG_MT7921E) += mt7921e.o +obj-$(CONFIG_MT7921S) += mt7921s.o CFLAGS_trace.o := -I$(src) 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 71aabb632e05..68f393c07a31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -413,6 +413,20 @@ 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; @@ -436,6 +450,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/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 6a4b014e8afd..2b7260be224f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -231,8 +231,15 @@ 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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index e49dfcf5558d..f5b179601030 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -843,6 +843,8 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, 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; @@ -858,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); @@ -1384,12 +1386,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_mcu_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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index ad2e52c97aa8..544a1c33126a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -199,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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 44e74e43ee78..571f559d3363 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -650,7 +650,9 @@ 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) { @@ -706,7 +708,7 @@ static int mt7921_load_patch(struct mt7921_dev *dev) } ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, - dl, len, 4096); + dl, len, max_len); if (ret) { dev_err(dev->mt76.dev, "Failed to send patch\n"); goto out; @@ -753,9 +755,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; @@ -778,7 +782,7 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev, } err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER, - data + offset, len, 4096); + data + offset, len, max_len); if (err) { dev_err(dev->mt76.dev, "Failed to send firmware.\n"); return err; @@ -851,7 +855,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; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index f4b85ec530bd..05e0d4371d32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -47,6 +47,29 @@ #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) @@ -321,6 +344,17 @@ static inline void mt7921_mcu_tx_cleanup(struct mt7921_dev *dev) 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); @@ -394,4 +428,13 @@ int mt7921e_mcu_init(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/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c new file mode 100644 index 000000000000..e0ad97f27fea --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. + * + */ + +#include +#include +#include + +#include +#include +#include + +#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); + 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 = { + .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 "); +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..91a7acd49ee4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. */ + +#include +#include +#include "mt7921.h" +#include "mac.h" + +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..049e06d7c3fb --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2021 MediaTek Inc. */ + +#include +#include +#include +#include + +#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; + + 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; +} -- cgit v1.2.3-70-g09d2 From ca74b9b907f93424ea16785871e68d705b276d5e Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 19 Oct 2021 07:11:47 +0800 Subject: mt76: mt7921s: add reset support Introduce wifi chip reset support for mt7921 device to recover mcu hangs or abnormal wifi system. Tested-by: Deren Wu Acked-by: Lorenzo Bianconi Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 + drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 4 + drivers/net/wireless/mediatek/mt76/mt7921/sdio.c | 3 + .../net/wireless/mediatek/mt76/mt7921/sdio_mac.c | 133 +++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/sdio_mcu.c | 8 ++ drivers/net/wireless/mediatek/mt76/sdio_txrx.c | 32 ++++- 8 files changed, 184 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 46e8fe3869c2..32d68ecf4c3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -507,6 +507,7 @@ struct mt76_sdio { struct sdio_func *func; void *intr_data; u8 hw_ver; + wait_queue_head_t wait; struct { int pse_data_quota; @@ -1255,6 +1256,7 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 2b7260be224f..87265045e2dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -217,6 +217,8 @@ 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_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 571f559d3363..6ada1ebe7d68 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -438,6 +438,7 @@ 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 05e0d4371d32..eebf367be296 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -182,6 +182,7 @@ struct mt7921_dev { 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; @@ -425,6 +426,9 @@ 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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index e0ad97f27fea..ddf0eeb8b688 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -46,6 +46,7 @@ static void mt7921s_unregister_device(struct mt7921_dev *dev) cancel_work_sync(&pm->wake_work); mt76s_deinit(&dev->mt76); + mt7921s_wfsys_reset(dev); mt7921_mcu_exit(dev); mt76_free_device(&dev->mt76); @@ -104,6 +105,8 @@ static int mt7921s_probe(struct sdio_func *func, .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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c index 91a7acd49ee4..137f86a6dbf8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c @@ -5,6 +5,139 @@ #include #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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c index 049e06d7c3fb..437cddad9a90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c @@ -21,6 +21,14 @@ mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 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; diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index 9b4c95a47d47..649a56790b89 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -235,6 +235,9 @@ static int mt76s_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 = __mt76s_xmit_queue(dev, e->skb->data, @@ -313,6 +316,13 @@ void mt76s_txrx_worker(struct mt76_sdio *sdio) 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 */ @@ -326,9 +336,29 @@ void mt76s_sdio_irq(struct sdio_func *func) struct mt76_dev *dev = sdio_get_drvdata(func); struct mt76_sdio *sdio = &dev->sdio; - if (!test_bit(MT76_STATE_INITIALIZED, &dev->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); -- cgit v1.2.3-70-g09d2 From d387cde7af84a5100bd717bb7359e9b30d95587d Mon Sep 17 00:00:00 2001 From: Richard Huynh Date: Tue, 7 Sep 2021 18:58:24 +1000 Subject: mt76: mt76x0: correct VHT MCS 8/9 tx power eeprom offset Appears to have incorrectly offset 0x120 + 0x12 instead of 12 decimal, leading to bogus power values being used. Signed-off-by: Richard Huynh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); -- cgit v1.2.3-70-g09d2 From 99043e99a7743f606320018e477381ef3eaf424b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:23 +0200 Subject: mt76: move mt76_sta_stats in mt76.h This is a preliminary patch to add ethtool stats to mt7921 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 9 +-------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 32d68ecf4c3a..ae6c3a735f49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -779,6 +779,13 @@ enum mt76_phy_type { __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 */ +}; + #define CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index d3d220f2f493..b04b62e5c25e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1347,7 +1347,7 @@ 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, struct mt7915_sta_stats *stats) + __le32 *txs_data, struct mt76_sta_stats *stats) { struct ieee80211_supported_band *sband; struct mt76_dev *mdev = &dev->mt76; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index de68c85f6e66..1d7c9a257681 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1199,10 +1199,10 @@ static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) { struct mt7915_ethtool_worker_info *wi = wi_data; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt76_sta_stats *mstats = &msta->stats; int ei = wi->initial_stat_idx; int q; u64 *data = wi->data; - struct mt7915_sta_stats *mstats = &msta->stats; if (msta->vif != wi->mvif) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 84b4c5cb9596..b3749d8d4294 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -65,13 +65,6 @@ enum mt7915_rxq_id { MT7915_RXQ_MCU_WA_EXT, }; -struct mt7915_sta_stats { - unsigned long tx_mode[__MT_PHY_TYPE_HE_MAX]; /* See mt76_phy_type */ - unsigned long tx_bw[4]; /* 20, 40, 80, 160 */ - unsigned long tx_nss[4]; /* 1, 2, 3, 4 */ - unsigned long tx_mcs[16]; /* mcs idx */ -}; - struct mt7915_sta_key_conf { s8 keyidx; u8 key[16]; @@ -106,7 +99,7 @@ struct mt7915_sta { unsigned long jiffies; unsigned long ampdu_state; - struct mt7915_sta_stats stats; + struct mt76_sta_stats stats; struct mt7915_sta_key_conf bip; -- cgit v1.2.3-70-g09d2 From 54ae98ff4b2267e22a4a10a0ccbe2250666da859 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:24 +0200 Subject: mt76: move mt76_ethtool_worker_info in mt76 module Move mt76_ethtool_worker_info in common code in order to be reused in mt7921 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 28 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 10 +++++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 47 ++++-------------------- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 766681a4f89e..62807dc311c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1508,3 +1508,31 @@ u16 mt76_calculate_default_rate(struct mt76_phy *phy, int 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/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ae6c3a735f49..e2da720a91b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -786,6 +786,14 @@ struct mt76_sta_stats { 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) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ @@ -1241,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 1d7c9a257681..7cb6ba410ffc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1187,45 +1187,15 @@ int mt7915_get_et_sset_count(struct ieee80211_hw *hw, return 0; } -struct mt7915_ethtool_worker_info { - u64 *data; - struct mt7915_vif *mvif; - int initial_stat_idx; - int worker_stat_count; - int sta_count; -}; - static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) { - struct mt7915_ethtool_worker_info *wi = wi_data; + struct mt76_ethtool_worker_info *wi = wi_data; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct mt76_sta_stats *mstats = &msta->stats; - int ei = wi->initial_stat_idx; - int q; - u64 *data = wi->data; - if (msta->vif != wi->mvif) + if (msta->vif->idx != wi->idx) return; - wi->sta_count++; - - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_CCK]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_OFDM]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HT]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HT_GF]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_VHT]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_SU]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_TB]; - data[ei++] += mstats->tx_mode[MT_PHY_TYPE_HE_MU]; - - for (q = 0; q < ARRAY_SIZE(mstats->tx_bw); q++) - data[ei++] += mstats->tx_bw[q]; - - for (q = 0; q < 12; q++) - data[ei++] += mstats->tx_mcs[q]; - - wi->worker_stat_count = ei - wi->initial_stat_idx; + mt76_ethtool_worker(wi, &msta->stats); } static @@ -1236,9 +1206,11 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, 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 mt7915_ethtool_worker_info wi; + 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; @@ -1303,12 +1275,7 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, data[ei++] = mib->rx_ba_cnt; /* Add values for all stations owned by this vif */ - wi.data = data; - wi.mvif = mvif; wi.initial_stat_idx = ei; - wi.worker_stat_count = 0; - wi.sta_count = 0; - ieee80211_iterate_stations_atomic(hw, mt7915_ethtool_worker, &wi); if (wi.sta_count == 0) -- cgit v1.2.3-70-g09d2 From 81811173de4fe73317ad420ac373baa12d1326d0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:25 +0200 Subject: mt76: mt7915: run mt7915_get_et_stats holding mt76 mutex Since it can run in parallel with mac_work, hold mutex lock in mt7915_get_et_stats. Moreover update mib counters running mt7915_get_et_stats. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 5 +++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 6efa3d7e39be..a265069c4d4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -201,7 +201,10 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) struct mt7915_dev *dev = phy->dev; int stat[8], i, n; + mutex_lock(&dev->mt76.mutex); + mt7915_ampdu_stat_read_phy(phy, file); + mt7915_mac_update_stats(phy); mt7915_txbf_stat_read_phy(phy, file); /* Tx amsdu info */ @@ -220,6 +223,8 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) seq_puts(file, "\n"); } + mutex_unlock(&dev->mt76.mutex); + return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index b04b62e5c25e..b611e4abc561 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1918,8 +1918,7 @@ 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 7cb6ba410ffc..aea6bce7e9da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1215,6 +1215,10 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, 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; @@ -1278,6 +1282,8 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b3749d8d4294..884e8a04c914 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -492,6 +492,7 @@ 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, -- cgit v1.2.3-70-g09d2 From 37dd57554c3572262042336a98f263dec1582f17 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:26 +0200 Subject: mt76: mt7915: move tx amsdu stats in mib_stats Move tx_amsdu histogram stats in mib_stats structure since registers are clear-on-read Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 19 ++++++++----------- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 3 +++ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index a265069c4d4d..4b7f38fcbe64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -199,7 +199,8 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) { struct mt7915_phy *phy = file->private; struct mt7915_dev *dev = phy->dev; - int stat[8], i, n; + struct mib_stats *mib = &phy->mib; + int i; mutex_lock(&dev->mt76.mutex); @@ -209,16 +210,12 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) /* 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"); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index b611e4abc561..21e6ef07814c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -2023,6 +2023,12 @@ void mt7915_mac_update_stats(struct mt7915_phy *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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index aea6bce7e9da..48d0e0795415 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1260,8 +1260,8 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, data[ei++] = mib->tx_su_acked_mpdu_cnt; /* Tx amsdu info (pack-count histogram) */ - for (i = 0; i < 8; i++) - data[ei++] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 884e8a04c914..fff15f6b9cad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -183,6 +183,9 @@ struct mib_stats { 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 { -- cgit v1.2.3-70-g09d2 From 6c833df90ce95a1855ba9d916ecc209c56ded3ee Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:27 +0200 Subject: mt76: do not reset MIB counters in get_stats callback MIB counters are used for ethtool stats as well Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 -- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index d5bcffef7122..343e157261ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -862,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/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 48d0e0795415..8be78917dee9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -811,13 +811,12 @@ 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index d968990dac6e..22d5a0adb5ad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -856,8 +856,6 @@ 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; -- cgit v1.2.3-70-g09d2 From 6b16ae47eb82701504746bc342c04e301c450a42 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:28 +0200 Subject: mt76: mt7921: add some more MIB counters This is a preliminary patch to introduce ethtool stats support to mt7921 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 26 +++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 18 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/regs.h | 28 ++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index f5b179601030..8a5b92b1e055 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1326,6 +1326,7 @@ 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); @@ -1338,8 +1339,31 @@ void 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, 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)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index eebf367be296..86c741569a9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -129,6 +129,24 @@ 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; }; struct mt7921_phy { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h index cb6069024320..cbd38122c510 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h @@ -92,6 +92,20 @@ #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) ? 0x820fd000 : 0x820ed000) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) @@ -103,12 +117,26 @@ #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) -- cgit v1.2.3-70-g09d2 From 6eb58ceaf21d568965c820fd7f81ca637f1cbe0a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:29 +0200 Subject: mt76: mt7921: introduce stats reporting through ethtool Similar to mt7915 driver, add tx/rx statistics reporting through ethtool. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 116 +++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 22d5a0adb5ad..bd49cfd59617 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -861,6 +861,119 @@ mt7921_get_stats(struct ieee80211_hw *hw, 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" +}; + +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_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data) +{ + struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = phy->dev; + struct mib_stats *mib = &phy->mib; + 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 < 8; i++) + data[ei++] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(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; + + mt7921_mutex_release(dev); + + 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) { @@ -1230,6 +1343,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, -- cgit v1.2.3-70-g09d2 From 9e893d28ce4a59f764ab40ba86c69bec42f60dea Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:30 +0200 Subject: mt76: mt7921: add sta stats accounting in mt7921_mac_add_txs_skb This is a preliminary patch to add ethtool stats to mt7921 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 17 +++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 8a5b92b1e055..d45c54f92b9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -951,14 +951,16 @@ static bool mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data) { + 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; - u32 txrate, txs; mt76_tx_status_lock(mdev, &list); skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); @@ -984,7 +986,13 @@ mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; - switch (FIELD_GET(MT_TX_RATE_MODE, txrate)) { + 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; @@ -1027,19 +1035,24 @@ mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid, 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; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 86c741569a9b..9347859a291c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -104,6 +104,7 @@ struct mt7921_sta { unsigned long last_txs; unsigned long ampdu_state; + struct mt76_sta_stats stats; struct mt7921_sta_key_conf bip; }; -- cgit v1.2.3-70-g09d2 From fe041bee9c231e57422ea43ab65d761dd4169cc9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:31 +0200 Subject: mt76: mt7921: move tx amsdu stats in mib_stats Move tx_amsdu histogram stats in mib_stats structure since registers are clear-on-read Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/debugfs.c | 27 ++++++++++------------ drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 6 +++++ drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 3 +++ 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 68f393c07a31..7cdfdf83529f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -95,30 +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_mutex_acquire(dev); - mt7921_ampdu_stat_read_phy(&dev->phy, file); + mt7921_ampdu_stat_read_phy(phy, file); - /* 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_mutex_release(dev); - - 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"); } + mt7921_mutex_release(dev); + return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index d45c54f92b9e..db3302b1576a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1375,6 +1375,12 @@ void mt7921_mac_update_mib_stats(struct mt7921_phy *phy) 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 val2; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index bd49cfd59617..575f23d9ec52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -958,8 +958,8 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, data[ei++] = mib->tx_bf_rx_fb_ht_cnt; /* Tx amsdu info (pack-count histogram) */ - for (i = 0; i < 8; i++) - data[ei++] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) + data[ei++] = mib->tx_amsdu[i]; /* rx counters */ data[ei++] = mib->rx_mpdu_cnt; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 9347859a291c..e9c7c3a19507 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -148,6 +148,9 @@ struct mib_stats { u32 rx_ampdu_cnt; u32 rx_ampdu_bytes_cnt; u32 rx_ba_cnt; + + u32 tx_amsdu[8]; + u32 tx_amsdu_cnt; }; struct mt7921_phy { -- cgit v1.2.3-70-g09d2 From 568a1b516a2c1c24ad908dfd8b77e5ac6a3580c3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 19 Oct 2021 12:12:32 +0200 Subject: mt76: mt7921: add per-vif counters in ethtool Similar to mt7915 driver, add per-vif tx counters in ethtool. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 53 +++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 575f23d9ec52..35a490c049e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -902,7 +902,33 @@ static const char mt7921_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_mpdu_cnt", "rx_ampdu_cnt", "rx_ampdu_bytes_cnt", - "rx_ba_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 @@ -922,13 +948,30 @@ mt7921_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 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); @@ -967,8 +1010,16 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 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)); -- cgit v1.2.3-70-g09d2 From bbf77f6ccebfb3511b1a2a2e7e7b8f9c235fcf73 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:09:38 +0800 Subject: mt76: mt7915: enable HE UL MU-MIMO Enable HE UL MU-MIMO in sta_rec_muru, which works on both ap and station mode. For sending trigger frames, one of the conditions fw uses is to check if mib rx airtime meets the threshold. There's a main control of mib rx airtime report register in fw, so we need to enable the register by mcu cmd instead of directly writing it, otherwise it will still be disabled by fw. Signed-off-by: Shayne Chen Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 -- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 46 ++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 1 - 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 85afe965169e..7bb7e9742755 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -386,8 +386,6 @@ 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); /* disable rx rate report by default due to hw issues */ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index d4c8759bedd8..8ba60b66e4a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1534,6 +1534,7 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, mvif->cap.he_mu_ebfer || mvif->cap.vht_mu_ebfer || mvif->cap.vht_mu_ebfee; + muru->cfg.mimo_ul_en = true; muru->ofdma_dl.punc_pream_rx = HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); @@ -2921,6 +2922,47 @@ int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val) 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 = { @@ -2955,6 +2997,10 @@ int mt7915_mcu_init(struct mt7915_dev *dev) 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); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 4043cf547c9e..d66918d914da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -271,6 +271,7 @@ 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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 6771870a867c..a2e98788f421 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -364,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 -- cgit v1.2.3-70-g09d2 From 16bff457dd33aa0997f7f8aea1c843e05c766bfb Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:09:39 +0800 Subject: mt76: mt7915: rework mt7915_mcu_sta_muru_tlv() Re-order and modify conditions for MU DL/UL and ofdma DL fields, and also clean up some unnecessary zero settings. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 42 ++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 8ba60b66e4a9..4c687380120e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1520,22 +1520,37 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct sta_rec_muru *muru; struct tlv *tlv; - if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) + 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; - /* A non-AP HE station must support MU beamformee */ - muru->cfg.mimo_dl_en = (vif->type == NL80211_IFTYPE_STATION && - vif->bss_conf.he_support) || - mvif->cap.he_mu_ebfer || + 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 = @@ -1544,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]); @@ -1554,18 +1566,6 @@ 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]); - - 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]); } static void -- cgit v1.2.3-70-g09d2 From 3176487f3fde6d10201e62b5b9a42c39ad22f683 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:09:40 +0800 Subject: mt76: mt7915: fix missing HE phy cap Fix missing HE phy cap related to vif and starec setting. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 12 +++++++++--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 8 ++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 7bb7e9742755..727c529bfdea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -630,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 @@ -682,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 | @@ -791,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] |= diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 4c687380120e..b4cc4cb35762 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1396,6 +1396,10 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) 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; @@ -1420,10 +1424,6 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) 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; -- cgit v1.2.3-70-g09d2 From ff8c049891688131682ac0b7fb0ef55595b19898 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 18 Oct 2021 16:09:41 +0800 Subject: mt76: mt7915: change max rx len limit of hw modules Update max rx len of some hw modules, which aligns out vendor SDK. In normal modes, we exchange MPDU 7991 cap with peers; however, this won't play a part in sniffer mode. To prevent packets which exceed the max MPDU size from entering specific rx path in hw, we need to set a proper limit to filter them out. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 727c529bfdea..4fa8e7ba93e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -386,7 +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_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); } @@ -395,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); -- cgit v1.2.3-70-g09d2