introduce mt7921e support
Subsystems (2)
[email protected]
reviewerv7 cover introduce mt7921e support
From: Sean Wang <[email protected]>
Introduce support for mt7921e 802.11ax (Wi-Fi 6) 2x2:2SS chipset.
v2:
- Mark the patch as -next
v3:
- Remove sw scan support
- Get rid of dbdc code
- Run mt7921_configure_filter hodling mt76 mutex
- Correct Txp programming in Txd
- Correct fw log to host command
- Correct eeprom offset definition
- Update rate adaption info report
- Remove unused code and fields in struture
- Split the previous driver into several patches for easy review
v4:
- introduce sched scan support
- introduce 802.11 PS support in sta mode
- introduce support for hardware beacon filter
- introduce beacon_loss mcu event
- introduce PM support
- refine sta_rec_phy and add sta_rec_ra_info
- remove incorrect mt7921_mcu_tx_config member
- fix erroneous endianness conversion in mt7921_tx_complete_skb()
- fix endianness warning in mt7921_get_wtbl_info()
- fix endianness warnings in mt7921_mcu_sta_tlv()
- remove unused code in mt7921_mcu_send_message
- remove scan with random mac until fw is ready
- channel domain is added for hw scan
v5:
- fix implicit conversion from enumeration type
- remove unused function declaration
- drop zero-length packet to avoid Tx hang
- fix MT_CIPHER_BIP_CMAC_128 setkey
- reset token when mac_reset happens
- create mac.h when mac support is added
- reorder the patch of adding module support
- move mac_work in mt76_core module
- move chainmask in mt76_phy
- rebase per moving mac_work in mt76_core module
- rebase per moving chainmask in mt76_phy
v6:
- use UNI_BSS_INFO_BCNFT and UNI_BSS_INFO_PS to carry out enabling hardware beacon filter and 802.11 power saving mode according to the MT7921 firmware
v7:
- remove the merged patches
- rebase onto the series mt76: introduce mt76_connac common module
https://patchwork.kernel.org/project/linux-wireless/list/?series=418597
- rely on mt76_connac_mcu common library
- rely on mt76_connac_mcu module for sched_scan and hw_scan
- rely on mt76_connac_mcu module for suspend and WoW support
- introduce regdomain notifier support
- enable MSI interrupts
- introduce Runtime PM support
- add coredump support
- add sta statistics
- disable Rx header translation on default
- set nss to 2 on default
Lorenzo Bianconi (6):
mt76: mt7921: rely on mt76_connac_mcu common library
mt76: mt7921: rely on mt76_connac_mcu module for sched_scan and
hw_scan
mt76: mt7921: rely on mt76_connac_mcu module for suspend and WoW
support
mt76: mt7921: introduce regdomain notifier support
mt76: mt7921: enable MSI interrupts
mt76: mt7663: introduce coredump support
Sean Wang (16):
mt76: mt7921: add MAC support
mt76: mt7921: add MCU support
mt76: mt7921: add DMA support
mt76: mt7921: add EEPROM support
mt76: mt7921: add ieee80211_ops
mt76: mt7921: introduce mt7921e support
mt76: mt7921: add debugfs support
mt76: mt7921: add module support
mt76: mt7921: introduce schedule scan support
mt76: mt7921: introduce 802.11 PS support in sta mode
mt76: mt7921: introduce support for hardware beacon filter
mt76: mt7921: introduce beacon_loss mcu event
mt76: mt7921: introduce PM support
mt76: mt7921: introduce Runtime PM support
mt76: mt7921: add coredump support
mt76: mt7921: add sta statistics
drivers/net/wireless/mediatek/mt76/Kconfig | 1 + drivers/net/wireless/mediatek/mt76/Makefile | 1 + .../net/wireless/mediatek/mt76/mt7615/Kconfig | 1 + .../wireless/mediatek/mt76/mt7615/debugfs.c | 17 + .../net/wireless/mediatek/mt76/mt7615/init.c | 2 + .../net/wireless/mediatek/mt76/mt7615/mac.c | 43 + .../net/wireless/mediatek/mt76/mt7615/mcu.c | 4 + .../net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + .../wireless/mediatek/mt76/mt7615/mt7615.h | 4 +- .../net/wireless/mediatek/mt76/mt76_connac.h | 14 + .../wireless/mediatek/mt76/mt76_connac_mcu.c | 370 +++- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 25 + .../net/wireless/mediatek/mt76/mt7921/Kconfig | 11 + .../wireless/mediatek/mt76/mt7921/Makefile | 5 + .../wireless/mediatek/mt76/mt7921/debugfs.c | 250 +++ .../net/wireless/mediatek/mt76/mt7921/dma.c | 356 ++++ .../wireless/mediatek/mt76/mt7921/eeprom.c | 100 ++ .../wireless/mediatek/mt76/mt7921/eeprom.h | 27 + .../net/wireless/mediatek/mt76/mt7921/init.c | 282 +++ .../net/wireless/mediatek/mt76/mt7921/mac.c | 1516 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mac.h | 333 ++++ .../net/wireless/mediatek/mt76/mt7921/main.c | 1161 +++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 1308 ++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 434 +++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 342 ++++ .../net/wireless/mediatek/mt76/mt7921/pci.c | 292 ++++ .../net/wireless/mediatek/mt76/mt7921/regs.h | 419 +++++ 27 files changed, 7309 insertions(+), 10 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/Makefile create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/dma.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mac.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/main.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mcu.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/regs.h
--
2.25.1
_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek
[email protected]
reviewerPATCH v7 1/22 mt76: mt7921: add MAC support
From: Sean Wang <[email protected]>
Add Rx packet description parsing, Tx packet description compositon, handle packet recycling and provide MAC information mt76 core needs to support mac80211.
--- .../net/wireless/mediatek/mt76/mt7921/mac.c | 1363 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mac.h | 333 ++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 347 +++++ .../net/wireless/mediatek/mt76/mt7921/regs.h | 414 +++++ 4 files changed, 2457 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mac.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/regs.h
drivers/net/wireless/mediatek/mt76/mt7921/mac.c new file +1363 -0
@@ -0,0 +1,1363 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include <linux/etherdevice.h> +#include <linux/timekeeping.h> +#include "mt7921.h" +#include "../dma.h" +#include "mac.h" + +#define to_rssi (field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) + +#define HE_BITS (f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) +#define HE_PREP (f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ + IEEE80211_RADIOTAP_HE_##f) + +static struct mt76_wcid *mt7921_rx_get_wcid (struct mt7921_dev *dev, +u16 idx,bool unicast) +{ +struct mt7921_sta *sta; +struct mt76_wcid *wcid; + +if (idx >=ARRAY_SIZE (dev->mt76.wcid)) +return NULL ; + + wcid =rcu_dereference (dev->mt76.wcid[idx]); +if (unicast || !wcid) +return wcid; + +if (!wcid->sta) +return NULL ; + + sta = container_of(wcid, struct mt7921_sta, wcid); +if (!sta->vif) +return NULL ; + +return &sta->vif->sta.wcid; +} + +void mt7921_sta_ps (struct mt76_dev *mdev,struct ieee80211_sta *sta,bool ps) +{ +} + +bool mt7921_mac_wtbl_update (struct mt7921_dev *dev,int idx,u32 mask) +{ +mt76_rmw (dev,MT_WTBL_UPDATE ,MT_WTBL_UPDATE_WLAN_IDX , +FIELD_PREP (MT_WTBL_UPDATE_WLAN_IDX , idx) | mask); + +return mt76_poll (dev,MT_WTBL_UPDATE ,MT_WTBL_UPDATE_BUSY , +0 ,5000 ); +} + +static u32 mt7921_mac_wtbl_lmac_addr (struct mt7921_dev *dev,u16 wcid) +{ +mt76_wr (dev,MT_WTBLON_TOP_WDUCR , +FIELD_PREP (MT_WTBLON_TOP_WDUCR_GROUP , (wcid >>7 ))); + +return MT_WTBL_LMAC_OFFS (wcid,0 ); +} + +static void mt7921_mac_sta_poll (struct mt7921_dev *dev) +{ +static const u8 ac_to_tid[] = { + [IEEE80211_AC_BE ] =0 , + [IEEE80211_AC_BK ] =1 , + [IEEE80211_AC_VI ] =4 , + [IEEE80211_AC_VO ] =6 + }; +struct ieee80211_sta *sta; +struct mt7921_sta *msta; +u32 tx_time[IEEE80211_NUM_ACS ], rx_time[IEEE80211_NUM_ACS ]; +LIST_HEAD (sta_poll_list); +int i; + +spin_lock_bh (&dev->sta_poll_lock); +list_splice_init (&dev->sta_poll_list, &sta_poll_list); +spin_unlock_bh (&dev->sta_poll_lock); + +rcu_read_lock (); + +while (true) { +bool clear = false; +u32 addr; +u16 idx; + +spin_lock_bh (&dev->sta_poll_lock); +if (list_empty (&sta_poll_list)) { +spin_unlock_bh (&dev->sta_poll_lock); +break ; + } + msta =list_first_entry (&sta_poll_list, + struct mt7921_sta, poll_list); +list_del_init (&msta->poll_list); +spin_unlock_bh (&dev->sta_poll_lock); + + idx = msta->wcid.idx; + addr =mt7921_mac_wtbl_lmac_addr (dev, idx) +20 *4 ; + +for (i =0 ; i <IEEE80211_NUM_ACS ; i++) { +u32 tx_last = msta->airtime_ac[i]; +u32 rx_last = msta->airtime_ac[i +4 ]; + + msta->airtime_ac[i] =mt76_rr (dev, addr); + msta->airtime_ac[i +4 ] =mt76_rr (dev, addr +4 ); + + tx_time[i] = msta->airtime_ac[i] - tx_last; + rx_time[i] = msta->airtime_ac[i +4 ] - rx_last; + +if ((tx_last | rx_last) &BIT (30 )) + clear = true; + + addr +=8 ; + } + +if (clear) { +mt7921_mac_wtbl_update (dev, idx, +MT_WTBL_UPDATE_ADM_COUNT_CLEAR ); +memset (msta->airtime_ac,0 ,sizeof (msta->airtime_ac)); + } + +if (!msta->wcid.sta) +continue ; + + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); +for (i =0 ; i <IEEE80211_NUM_ACS ; i++) { +u8 q =mt7921_lmac_mapping (dev, i); +u32 tx_cur = tx_time[q]; +u32 rx_cur = rx_time[q]; +u8 tid = ac_to_tid[i]; + +if (!tx_cur && !rx_cur) +continue ; + +ieee80211_sta_register_airtime (sta, tid, tx_cur, + rx_cur); + } + } + +rcu_read_unlock (); +} + +static void +mt7921_mac_decode_he_radiotap_ru (struct mt76_rx_status *status, +struct ieee80211_radiotap_he *he, +__le32 *rxv) +{ +u32 ru_h, ru_l; +u8 ru, offs =0 ; + + ru_l =FIELD_GET (MT_PRXV_HE_RU_ALLOC_L ,le32_to_cpu (rxv[0 ])); + ru_h =FIELD_GET (MT_PRXV_HE_RU_ALLOC_H ,le32_to_cpu (rxv[1 ])); + ru = (u8)(ru_l | ru_h <<4 ); + + status->bw =RATE_INFO_BW_HE_RU ; + +switch (ru) { + case 0 ... 36: + status->he_ru =NL80211_RATE_INFO_HE_RU_ALLOC_26 ; + offs = ru; +break ; + case 37 ... 52: + status->he_ru =NL80211_RATE_INFO_HE_RU_ALLOC_52 ; + offs = ru -37 ; +break ; + case 53 ... 60: + status->he_ru =NL80211_RATE_INFO_HE_RU_ALLOC_106 ; + offs = ru -53 ; +break ; + case 61 ... 64: + status->he_ru =NL80211_RATE_INFO_HE_RU_ALLOC_242 ; + offs = ru -61 ; +break ; + case 65 ... 66: + status->he_ru =NL80211_RATE_INFO_HE_RU_ALLOC_484 ; + offs = ru -65 ; +break ; +case 67 : + status->he_ru =NL80211_RATE_INFO_HE_RU_ALLOC_996 ; +break ; +case 68 : + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; +break ; + } + + he->data1 |=HE_BITS (DATA1_BW_RU_ALLOC_KNOWN ); + he->data2 |=HE_BITS (DATA2_RU_OFFSET_KNOWN ) | +le16_encode_bits (offs, +IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET ); +} + +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 ) | +HE_BITS (DATA1_STBC_KNOWN ) | +HE_BITS (DATA1_CODING_KNOWN ) | +HE_BITS (DATA1_LDPC_XSYMSEG_KNOWN ) | +HE_BITS (DATA1_DOPPLER_KNOWN ) | +HE_BITS (DATA1_BSS_COLOR_KNOWN ), + .data2 =HE_BITS (DATA2_GI_KNOWN ) | +HE_BITS (DATA2_TXBF_KNOWN ) | +HE_BITS (DATA2_PE_DISAMBIG_KNOWN ) | +HE_BITS (DATA2_TXOP_KNOWN ), + }; +struct ieee80211_radiotap_he *he =NULL ; +u32 ltf_size =le32_get_bits (rxv[2 ],MT_CRXV_HE_LTF_SIZE ) +1 ; + + he =skb_push (skb,sizeof (known)); +memcpy (he, &known,sizeof (known)); + + he->data3 =HE_PREP (DATA3_BSS_COLOR ,BSS_COLOR , rxv[14 ]) | +HE_PREP (DATA3_LDPC_XSYMSEG ,LDPC_EXT_SYM , rxv[2 ]); + he->data5 =HE_PREP (DATA5_PE_DISAMBIG ,PE_DISAMBIG , rxv[2 ]) | +le16_encode_bits (ltf_size, +IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE ); + he->data6 =HE_PREP (DATA6_TXOP ,TXOP_DUR , rxv[14 ]) | +HE_PREP (DATA6_DOPPLER ,DOPPLER , rxv[14 ]); + +switch (phy) { +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->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 ) | +HE_BITS (DATA1_UL_DL_KNOWN ); + + he->data3 |=HE_PREP (DATA3_UL_DL ,UPLINK , rxv[2 ]); +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->data3 |=HE_PREP (DATA3_UL_DL ,UPLINK , rxv[2 ]); + he->data4 |=HE_PREP (DATA4_SU_MU_SPTL_REUSE ,SR_MASK , rxv[11 ]); + +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 ); + + he->data4 |=HE_PREP (DATA4_TB_SPTL_REUSE1 ,SR_MASK , rxv[11 ]) | +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 ]); + +mt7921_mac_decode_he_radiotap_ru (status, he, rxv); +break ; +default : +break ; + } +} + +static void +mt7921_get_status_freq_info (struct mt7921_dev *dev,struct mt76_phy *mphy, +struct mt76_rx_status *status,u8 chfreq) +{ +if (!test_bit (MT76_HW_SCANNING , &mphy->state) && + !test_bit (MT76_HW_SCHED_SCANNING , &mphy->state) && + !test_bit (MT76_STATE_ROC , &mphy->state)) { + status->freq = mphy->chandef.chan->center_freq; + status->band = mphy->chandef.chan->band; +return ; + } + + status->band = chfreq <=14 ?NL80211_BAND_2GHZ :NL80211_BAND_5GHZ ; + status->freq =ieee80211_channel_to_frequency (chfreq, status->band); +} + +int mt7921_mac_fill_rx (struct mt7921_dev *dev,struct sk_buff *skb) +{ +struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; +struct mt76_phy *mphy = &dev->mt76.phy; +struct mt7921_phy *phy = &dev->phy; +struct ieee80211_supported_band *sband; +struct ieee80211_hdr *hdr; +__le32 *rxd = (__le32 *)skb->data; +__le32 *rxv =NULL ; +u32 mode =0 ; +u32 rxd1 =le32_to_cpu (rxd[1 ]); +u32 rxd2 =le32_to_cpu (rxd[2 ]); +u32 rxd3 =le32_to_cpu (rxd[3 ]); +bool unicast, insert_ccmp_hdr = false; +u8 remove_pad; +int i, idx; +u8 chfreq; + +memset (status,0 ,sizeof (*status)); + +if (rxd1 &MT_RXD1_NORMAL_BAND_IDX ) +return -EINVAL ; + +if (!test_bit (MT76_STATE_RUNNING , &mphy->state)) +return -EINVAL ; + + chfreq =FIELD_GET (MT_RXD3_NORMAL_CH_FREQ , rxd3); + unicast =FIELD_GET (MT_RXD3_NORMAL_ADDR_TYPE , rxd3) ==MT_RXD3_NORMAL_U2M ; + idx =FIELD_GET (MT_RXD1_NORMAL_WLAN_IDX , rxd1); + status->wcid =mt7921_rx_get_wcid (dev, idx, unicast); + +if (status->wcid) { +struct mt7921_sta *msta; + + msta = container_of(status->wcid, struct mt7921_sta, wcid); +spin_lock_bh (&dev->sta_poll_lock); +if (list_empty (&msta->poll_list)) +list_add_tail (&msta->poll_list, &dev->sta_poll_list); +spin_unlock_bh (&dev->sta_poll_lock); + } + +mt7921_get_status_freq_info (dev, mphy, status, chfreq); + +if (status->band ==NL80211_BAND_5GHZ ) + sband = &mphy->sband_5g.sband; +else + sband = &mphy->sband_2g.sband; + +if (!sband->channels) +return -EINVAL ; + +if (rxd1 &MT_RXD1_NORMAL_FCS_ERR ) + status->flag |=RX_FLAG_FAILED_FCS_CRC ; + +if (rxd1 &MT_RXD1_NORMAL_TKIP_MIC_ERR ) + status->flag |=RX_FLAG_MMIC_ERROR ; + +if (FIELD_GET (MT_RXD1_NORMAL_SEC_MODE , rxd1) !=0 && + !(rxd1 & (MT_RXD1_NORMAL_CLM |MT_RXD1_NORMAL_CM ))) { + status->flag |=RX_FLAG_DECRYPTED ; + status->flag |=RX_FLAG_IV_STRIPPED ; + status->flag |=RX_FLAG_MMIC_STRIPPED |RX_FLAG_MIC_STRIPPED ; + } + +if (!(rxd2 &MT_RXD2_NORMAL_NON_AMPDU )) { + status->flag |=RX_FLAG_AMPDU_DETAILS ; + +/* all subframes of an A-MPDU have the same timestamp */ +if (phy->rx_ampdu_ts != rxd[14 ]) { +if (!++phy->ampdu_ref) + phy->ampdu_ref++; + } + phy->rx_ampdu_ts = rxd[14 ]; + + status->ampdu_ref = phy->ampdu_ref; + } + + remove_pad =FIELD_GET (MT_RXD2_NORMAL_HDR_OFFSET , rxd2); + +if (rxd2 &MT_RXD2_NORMAL_MAX_LEN_ERROR ) +return -EINVAL ; + + rxd +=6 ; +if (rxd1 &MT_RXD1_NORMAL_GROUP_4 ) { + rxd +=4 ; +if ((u8 *)rxd - skb->data >= skb->len) +return -EINVAL ; + } + +if (rxd1 &MT_RXD1_NORMAL_GROUP_1 ) { +u8 *data = (u8 *)rxd; + +if (status->flag &RX_FLAG_DECRYPTED ) { + status->iv[0 ] = data[5 ]; + status->iv[1 ] = data[4 ]; + status->iv[2 ] = data[3 ]; + status->iv[3 ] = data[2 ]; + status->iv[4 ] = data[1 ]; + status->iv[5 ] = data[0 ]; + + insert_ccmp_hdr =FIELD_GET (MT_RXD2_NORMAL_FRAG , rxd2); + } + rxd +=4 ; +if ((u8 *)rxd - skb->data >= skb->len) +return -EINVAL ; + } + +if (rxd1 &MT_RXD1_NORMAL_GROUP_2 ) { + rxd +=2 ; +if ((u8 *)rxd - skb->data >= skb->len) +return -EINVAL ; + } + +/* RXD Group 3 - P-RXV */ +if (rxd1 &MT_RXD1_NORMAL_GROUP_3 ) { +u32 v0, v1, v2; + + rxv = rxd; + rxd +=2 ; +if ((u8 *)rxd - skb->data >= skb->len) +return -EINVAL ; + + v0 =le32_to_cpu (rxv[0 ]); + v1 =le32_to_cpu (rxv[1 ]); + v2 =le32_to_cpu (rxv[2 ]); + +if (v0 &MT_PRXV_HT_AD_CODE ) + status->enc_flags |=RX_ENC_FLAG_LDPC ; + + status->chains = mphy->antenna_mask; + status->chain_signal[0 ] =to_rssi (MT_PRXV_RCPI0 , v1); + status->chain_signal[1 ] =to_rssi (MT_PRXV_RCPI1 , v1); + status->chain_signal[2 ] =to_rssi (MT_PRXV_RCPI2 , v1); + status->chain_signal[3 ] =to_rssi (MT_PRXV_RCPI3 , v1); + status->signal = status->chain_signal[0 ]; + +for (i =1 ; i <hweight8 (mphy->antenna_mask); i++) { +if (!(status->chains &BIT (i))) +continue ; + + status->signal =max (status->signal, + status->chain_signal[i]); + } + +/* RXD Group 5 - C-RXV */ +if (rxd1 &MT_RXD1_NORMAL_GROUP_5 ) { +u8 stbc =FIELD_GET (MT_CRXV_HT_STBC , v2); +u8 gi =FIELD_GET (MT_CRXV_HT_SHORT_GI , v2); +bool cck = false; + + rxd +=18 ; +if ((u8 *)rxd - skb->data >= skb->len) +return -EINVAL ; + + idx = i =FIELD_GET (MT_PRXV_TX_RATE , v0); + mode =FIELD_GET (MT_CRXV_TX_MODE , v2); + +switch (mode) { +case MT_PHY_TYPE_CCK : + cck = true; + fallthrough; +case MT_PHY_TYPE_OFDM : + i =mt76_get_rate (&dev->mt76, sband, i, cck); +break ; +case MT_PHY_TYPE_HT_GF : +case MT_PHY_TYPE_HT : + status->encoding =RX_ENC_HT ; +if (i >31 ) +return -EINVAL ; +break ; +case MT_PHY_TYPE_VHT : + status->nss = +FIELD_GET (MT_PRXV_NSTS , v0) +1 ; + status->encoding =RX_ENC_VHT ; +if (i >9 ) +return -EINVAL ; +break ; +case MT_PHY_TYPE_HE_MU : + status->flag |=RX_FLAG_RADIOTAP_HE_MU ; + fallthrough; +case MT_PHY_TYPE_HE_SU : +case MT_PHY_TYPE_HE_EXT_SU : +case MT_PHY_TYPE_HE_TB : + status->nss = +FIELD_GET (MT_PRXV_NSTS , v0) +1 ; + status->encoding =RX_ENC_HE ; + status->flag |=RX_FLAG_RADIOTAP_HE ; + i &=GENMASK (3 ,0 ); + +if (gi <=NL80211_RATE_INFO_HE_GI_3_2 ) + status->he_gi = gi; + + status->he_dcm = !!(idx &MT_PRXV_TX_DCM ); +break ; +default : +return -EINVAL ; + } + status->rate_idx = i; + +switch (FIELD_GET (MT_CRXV_FRAME_MODE , v2)) { +case IEEE80211_STA_RX_BW_20 : +break ; +case IEEE80211_STA_RX_BW_40 : +if (mode &MT_PHY_TYPE_HE_EXT_SU && + (idx &MT_PRXV_TX_ER_SU_106T )) { + status->bw =RATE_INFO_BW_HE_RU ; + status->he_ru = +NL80211_RATE_INFO_HE_RU_ALLOC_106 ; + }else { + status->bw =RATE_INFO_BW_40 ; + } +break ; +case IEEE80211_STA_RX_BW_80 : + status->bw =RATE_INFO_BW_80 ; +break ; +case IEEE80211_STA_RX_BW_160 : + status->bw =RATE_INFO_BW_160 ; +break ; +default : +return -EINVAL ; + } + + status->enc_flags |=RX_ENC_FLAG_STBC_MASK * stbc; +if (mode <MT_PHY_TYPE_HE_SU && gi) + status->enc_flags |=RX_ENC_FLAG_SHORT_GI ; + } + } + +skb_pull (skb, (u8 *)rxd - skb->data +2 * remove_pad); + +if (insert_ccmp_hdr) { +u8 key_id =FIELD_GET (MT_RXD1_NORMAL_KEY_ID , rxd1); + +mt76_insert_ccmp_hdr (skb, key_id); + } + +if (rxv && status->flag &RX_FLAG_RADIOTAP_HE ) +mt7921_mac_decode_he_radiotap (skb, status, rxv, mode); + + hdr =mt76_skb_get_hdr (skb); +if (!status->wcid || !ieee80211_is_data_qos (hdr->frame_control)) +return 0 ; + + status->aggr = unicast && + !ieee80211_is_qos_nullfunc (hdr->frame_control); + status->tid = *ieee80211_get_qos_ctl (hdr) &IEEE80211_QOS_CTL_TID_MASK ; + status->seqno =IEEE80211_SEQ_TO_SN (le16_to_cpu (hdr->seq_ctrl)); + +return 0 ; +} + +static void +mt7921_mac_write_txwi_8023 (struct mt7921_dev *dev,__le32 *txwi, +struct sk_buff *skb,struct mt76_wcid *wcid) +{ +u8 tid = skb->priority &IEEE80211_QOS_CTL_TID_MASK ; +u8 fc_type, fc_stype; +bool wmm = false; +u32 val; + +if (wcid->sta) { +struct ieee80211_sta *sta; + + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); + wmm = sta->wme; + } + + val =FIELD_PREP (MT_TXD1_HDR_FORMAT ,MT_HDR_FORMAT_802_3 ) | +FIELD_PREP (MT_TXD1_TID , tid); + +if (be16_to_cpu (skb->protocol) >=ETH_P_802_3_MIN ) + val |=MT_TXD1_ETH_802_3 ; + + txwi[1 ] |=cpu_to_le32 (val); + + fc_type =IEEE80211_FTYPE_DATA >>2 ; + fc_stype = wmm ?IEEE80211_STYPE_QOS_DATA >>4 :0 ; + + val =FIELD_PREP (MT_TXD2_FRAME_TYPE , fc_type) | +FIELD_PREP (MT_TXD2_SUB_TYPE , fc_stype); + + txwi[2 ] |=cpu_to_le32 (val); + + val =FIELD_PREP (MT_TXD7_TYPE , fc_type) | +FIELD_PREP (MT_TXD7_SUB_TYPE , fc_stype); + txwi[7 ] |=cpu_to_le32 (val); +} + +static void +mt7921_mac_write_txwi_80211 (struct mt7921_dev *dev,__le32 *txwi, +struct sk_buff *skb,struct ieee80211_key_conf *key) +{ +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; + +if (ieee80211_is_action (fc) && + mgmt->u.action.category ==WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code ==WLAN_ACTION_ADDBA_REQ ) { +u16 capab =le16_to_cpu (mgmt->u.action.u.addba_req.capab); + + txwi[5 ] |=cpu_to_le32 (MT_TXD5_ADD_BA ); + tid = (capab >>2 ) &IEEE80211_QOS_CTL_TID_MASK ; + }else if (ieee80211_is_back_req (hdr->frame_control)) { +struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; +u16 control =le16_to_cpu (bar->control); + + tid =FIELD_GET (IEEE80211_BAR_CTRL_TID_INFO_MASK , control); + } + + val =FIELD_PREP (MT_TXD1_HDR_FORMAT ,MT_HDR_FORMAT_802_11 ) | +FIELD_PREP (MT_TXD1_HDR_INFO , +ieee80211_get_hdrlen_from_skb (skb) /2 ) | +FIELD_PREP (MT_TXD1_TID , tid); + txwi[1 ] |=cpu_to_le32 (val); + + fc_type = (le16_to_cpu (fc) &IEEE80211_FCTL_FTYPE ) >>2 ; + fc_stype = (le16_to_cpu (fc) &IEEE80211_FCTL_STYPE ) >>4 ; + + val =FIELD_PREP (MT_TXD2_FRAME_TYPE , fc_type) | +FIELD_PREP (MT_TXD2_SUB_TYPE , fc_stype) | +FIELD_PREP (MT_TXD2_MULTICAST , multicast); + +if (key && multicast &&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) + val |=MT_TXD2_FIX_RATE ; + + txwi[2 ] |=cpu_to_le32 (val); + +if (ieee80211_is_beacon (fc)) { + txwi[3 ] &= ~cpu_to_le32 (MT_TXD3_SW_POWER_MGMT ); + txwi[3 ] |=cpu_to_le32 (MT_TXD3_REM_TX_COUNT ); + } + +if (info->flags &IEEE80211_TX_CTL_INJECTED ) { +u16 seqno =le16_to_cpu (hdr->seq_ctrl); + +if (ieee80211_is_back_req (hdr->frame_control)) { +struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno =le16_to_cpu (bar->start_seq_num); + } + + val =MT_TXD3_SN_VALID | +FIELD_PREP (MT_TXD3_SEQ ,IEEE80211_SEQ_TO_SN (seqno)); + txwi[3 ] |=cpu_to_le32 (val); + } + + val =FIELD_PREP (MT_TXD7_TYPE , fc_type) | +FIELD_PREP (MT_TXD7_SUB_TYPE , fc_stype); + txwi[7 ] |=cpu_to_le32 (val); +} + +void mt7921_mac_write_txwi (struct mt7921_dev *dev,__le32 *txwi, +struct sk_buff *skb,struct mt76_wcid *wcid, +struct ieee80211_key_conf *key,bool beacon) +{ +struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb); +struct ieee80211_vif *vif = info->control.vif; +struct mt76_phy *mphy = &dev->mphy; +u8 p_fmt, q_idx, omac_idx =0 , wmm_idx =0 ; +bool is_8023 = info->flags &IEEE80211_TX_CTL_HW_80211_ENCAP ; +u16 tx_count =15 ; +u32 val; + +if (vif) { +struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + + omac_idx = mvif->omac_idx; + wmm_idx = mvif->wmm_idx; + } + +if (beacon) { + 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 ; + q_idx =MT_LMAC_ALTX0 ; + }else { + p_fmt =MT_TX_TYPE_CT ; + 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 ) | +FIELD_PREP (MT_TXD0_PKT_FMT , p_fmt) | +FIELD_PREP (MT_TXD0_Q_IDX , q_idx); + txwi[0 ] =cpu_to_le32 (val); + + val =MT_TXD1_LONG_FORMAT | +FIELD_PREP (MT_TXD1_WLAN_IDX , wcid->idx) | +FIELD_PREP (MT_TXD1_OWN_MAC , omac_idx); + + txwi[1 ] =cpu_to_le32 (val); + txwi[2 ] =0 ; + + val =MT_TXD3_SW_POWER_MGMT | +FIELD_PREP (MT_TXD3_REM_TX_COUNT , tx_count); +if (key) + val |=MT_TXD3_PROTECT_FRAME ; +if (info->flags &IEEE80211_TX_CTL_NO_ACK ) + val |=MT_TXD3_NO_ACK ; + + txwi[3 ] =cpu_to_le32 (val); + txwi[4 ] =0 ; + txwi[5 ] =0 ; + txwi[6 ] =0 ; + txwi[7 ] = wcid->amsdu ?cpu_to_le32 (MT_TXD7_HW_AMSDU ) :0 ; + +if (is_8023) +mt7921_mac_write_txwi_8023 (dev, txwi, skb, wcid); +else +mt7921_mac_write_txwi_80211 (dev, txwi, skb, key); + +if (txwi[2 ] &cpu_to_le32 (MT_TXD2_FIX_RATE )) { +u16 rate; + +/* 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 ; + + val =MT_TXD6_FIXED_BW | +FIELD_PREP (MT_TXD6_TX_RATE , rate); + txwi[6 ] |=cpu_to_le32 (val); + txwi[3 ] |=cpu_to_le32 (MT_TXD3_BA_DISABLE ); + } +} + +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); + } + } +} + +static void mt7921_set_tx_blocked (struct mt7921_dev *dev,bool blocked) +{ +struct mt76_phy *mphy = &dev->mphy; +struct mt76_queue *q; + + q = mphy->q_tx[0 ]; +if (blocked == q->blocked) +return ; + + q->blocked = blocked; +if (!blocked) +mt76_worker_schedule (&dev->mt76.tx_worker); +} + +int mt7921_tx_prepare_skb (struct mt76_dev *mdev,void *txwi_ptr, +enum mt76_txq_id qid,struct mt76_wcid *wcid, +struct ieee80211_sta *sta, +struct mt76_tx_info *tx_info) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); +struct ieee80211_tx_info *info =IEEE80211_SKB_CB (tx_info->skb); +struct ieee80211_key_conf *key = info->control.hw_key; +struct mt76_tx_cb *cb =mt76_tx_skb_cb (tx_info->skb); +struct mt76_txwi_cache *t; +struct mt7921_txp_common *txp; +int id; +u8 *txwi = (u8 *)txwi_ptr; + +if (unlikely (tx_info->skb->len <=ETH_HLEN )) +return -EINVAL ; + +if (!wcid) + wcid = &dev->mt76.global_wcid; + + cb->wcid = wcid->idx; + + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + +spin_lock_bh (&dev->token_lock); + id =idr_alloc (&dev->token, t,0 ,MT7921_TOKEN_SIZE ,GFP_ATOMIC ); +if (id >=0 ) + dev->token_count++; + +if (dev->token_count >=MT7921_TOKEN_SIZE -MT7921_TOKEN_FREE_THR ) +mt7921_set_tx_blocked (dev, true); +spin_unlock_bh (&dev->token_lock); + +if (id <0 ) +return id; + +mt7921_mac_write_txwi (dev, txwi_ptr, tx_info->skb, wcid, key, + false); + + txp = (struct mt7921_txp_common *)(txwi +MT_TXD_SIZE ); +memset (txp,0 ,sizeof (struct mt7921_txp_common )); +mt7921_write_hw_txp (dev, tx_info, txp, id); + + tx_info->skb =DMA_DUMMY_DATA ; + +return 0 ; +} + +static void +mt7921_tx_check_aggr (struct ieee80211_sta *sta,__le32 *txwi) +{ +struct mt7921_sta *msta; +u16 fc, tid; +u32 val; + +if (!sta || !sta->ht_cap.ht_supported) +return ; + + tid =FIELD_GET (MT_TXD1_TID ,le32_to_cpu (txwi[1 ])); +if (tid >=6 )/* skip VO queue */ +return ; + + val =le32_to_cpu (txwi[2 ]); + fc =FIELD_GET (MT_TXD2_FRAME_TYPE , val) <<2 | +FIELD_GET (MT_TXD2_SUB_TYPE , val) <<4 ; +if (unlikely (fc != (IEEE80211_FTYPE_DATA |IEEE80211_STYPE_QOS_DATA ))) +return ; + + msta = (struct mt7921_sta *)sta->drv_priv; +if (!test_and_set_bit (tid, &msta->ampdu_state)) +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,u8 stat, +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 (stat) +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); +} + +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 ; + } +} + +void mt7921_mac_tx_free (struct mt7921_dev *dev,struct sk_buff *skb) +{ +struct mt7921_tx_free *free = (struct mt7921_tx_free *)skb->data; +struct mt76_dev *mdev = &dev->mt76; +struct mt76_txwi_cache *txwi; +struct ieee80211_sta *sta =NULL ; +LIST_HEAD (free_list); +struct sk_buff *tmp; +bool wake = false; +u8 i, count; + +/* clean DMA queues and unmap buffers first */ +mt76_queue_tx_cleanup (dev, dev->mphy.q_tx[MT_TXQ_PSD ], false); +mt76_queue_tx_cleanup (dev, dev->mphy.q_tx[MT_TXQ_BE ], false); + +/* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE, +* to the time ack is received or dropped by hw (air + hw queue time). +* Should avoid accessing WTBL to get Tx airtime, and use it instead. +*/ + count =FIELD_GET (MT_TX_FREE_MSDU_CNT ,le16_to_cpu (free->ctrl)); +for (i =0 ; i < count; i++) { +u32 msdu, info =le32_to_cpu (free->info[i]); +u8 stat; + +/* 1'b1: new wcid pair. +* 1'b0: msdu_id with the same 'wcid pair' as above. +*/ +if (info &MT_TX_FREE_PAIR ) { +struct mt7921_sta *msta; +struct mt7921_phy *phy; +struct mt76_wcid *wcid; +u16 idx; + + count++; + idx =FIELD_GET (MT_TX_FREE_WLAN_ID , info); + wcid =rcu_dereference (dev->mt76.wcid[idx]); + sta =wcid_to_sta (wcid); +if (!sta) +continue ; + + msta = container_of(wcid, struct mt7921_sta, wcid); + phy = msta->vif->phy; +spin_lock_bh (&dev->sta_poll_lock); +if (list_empty (&msta->stats_list)) +list_add_tail (&msta->stats_list, &phy->stats_list); +if (list_empty (&msta->poll_list)) +list_add_tail (&msta->poll_list, &dev->sta_poll_list); +spin_unlock_bh (&dev->sta_poll_lock); +continue ; + } + + msdu =FIELD_GET (MT_TX_FREE_MSDU_ID , info); + stat =FIELD_GET (MT_TX_FREE_STATUS , info); + +spin_lock_bh (&dev->token_lock); + txwi =idr_remove (&dev->token, msdu); +if (txwi) + dev->token_count--; +if (dev->token_count <MT7921_TOKEN_SIZE -MT7921_TOKEN_FREE_THR && + dev->mphy.q_tx[0 ]->blocked) + wake = true; +spin_unlock_bh (&dev->token_lock); + +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_mac_sta_poll (dev); + +if (wake) { +spin_lock_bh (&dev->token_lock); +mt7921_set_tx_blocked (dev, false); +spin_unlock_bh (&dev->token_lock); + } + +mt76_worker_schedule (&dev->mt76.tx_worker); + +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 ); + } +} + +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; +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 ; +spin_lock_bh (&dev->token_lock); + t =idr_remove (&dev->token, token); +spin_unlock_bh (&dev->token_lock); + 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 ); + } +} + +void mt7921_mac_reset_counters (struct mt7921_phy *phy) +{ +struct mt7921_dev *dev = phy->dev; +int i; + +for (i =0 ; i <4 ; i++) { +mt76_rr (dev,MT_TX_AGG_CNT (0 , i)); +mt76_rr (dev,MT_TX_AGG_CNT2 (0 , i)); + } + + dev->mt76.phy.survey_time =ktime_get_boottime (); +memset (&dev->mt76.aggr_stats[0 ],0 ,sizeof (dev->mt76.aggr_stats) /2 ); + +/* reset airtime counters */ +mt76_rr (dev,MT_MIB_SDR9 (0 )); +mt76_rr (dev,MT_MIB_SDR36 (0 )); +mt76_rr (dev,MT_MIB_SDR37 (0 )); + +mt76_set (dev,MT_WF_RMAC_MIB_TIME0 (0 ),MT_WF_RMAC_MIB_RXTIME_CLR ); +mt76_set (dev,MT_WF_RMAC_MIB_AIRTIME0 (0 ),MT_WF_RMAC_MIB_RXTIME_CLR ); +} + +void mt7921_mac_set_timing (struct mt7921_phy *phy) +{ +s16 coverage_class = phy->coverage_class; +struct mt7921_dev *dev = phy->dev; +u32 val, reg_offset; +u32 cck =FIELD_PREP (MT_TIMEOUT_VAL_PLCP ,231 ) | +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 ; + +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 ); + + offset =3 * coverage_class; + reg_offset =FIELD_PREP (MT_TIMEOUT_VAL_PLCP , offset) | +FIELD_PREP (MT_TIMEOUT_VAL_CCA , offset); + +mt76_wr (dev,MT_TMAC_CDTR (0 ), cck + reg_offset); +mt76_wr (dev,MT_TMAC_ODTR (0 ), ofdm + reg_offset); +mt76_wr (dev,MT_TMAC_ICR0 (0 ), +FIELD_PREP (MT_IFS_EIFS ,360 ) | +FIELD_PREP (MT_IFS_RIFS ,2 ) | +FIELD_PREP (MT_IFS_SIFS , sifs) | +FIELD_PREP (MT_IFS_SLOT , phy->slottime)); + +if (phy->slottime <20 || is_5ghz) + val =MT7921_CFEND_RATE_DEFAULT ; +else + val =MT7921_CFEND_RATE_11B ; + +mt76_rmw_field (dev,MT_AGG_ACR0 (0 ),MT_AGG_ACR_CFEND_RATE , val); +mt76_clear (dev,MT_ARB_SCR (0 ), +MT_ARB_SCR_TX_DISABLE |MT_ARB_SCR_RX_DISABLE ); +} + +static u8 +mt7921_phy_get_nf (struct mt7921_phy *phy,int idx) +{ +return 0 ; +} + +static void +mt7921_phy_update_channel (struct mt76_phy *mphy,int idx) +{ + struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76); +struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv; +struct mt76_channel_state *state; +u64 busy_time, tx_time, rx_time, obss_time; +int nf; + + busy_time =mt76_get_field (dev,MT_MIB_SDR9 (idx), +MT_MIB_SDR9_BUSY_MASK ); + tx_time =mt76_get_field (dev,MT_MIB_SDR36 (idx), +MT_MIB_SDR36_TXTIME_MASK ); + rx_time =mt76_get_field (dev,MT_MIB_SDR37 (idx), +MT_MIB_SDR37_RXTIME_MASK ); + obss_time =mt76_get_field (dev,MT_WF_RMAC_MIB_AIRTIME14 (idx), +MT_MIB_OBSSTIME_MASK ); + + nf =mt7921_phy_get_nf (phy, idx); +if (!phy->noise) + phy->noise = nf <<4 ; +else if (nf) + phy->noise += nf - (phy->noise >>4 ); + + state = mphy->chan_state; + state->cc_busy += busy_time; + state->cc_tx += tx_time; + state->cc_rx += rx_time + obss_time; + state->cc_bss_rx += rx_time; + state->noise = -(phy->noise >>4 ); +} + +void mt7921_update_channel (struct mt76_dev *mdev) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + +mt7921_phy_update_channel (&mdev->phy,0 ); +/* reset obss airtime */ +mt76_set (dev,MT_WF_RMAC_MIB_TIME0 (0 ),MT_WF_RMAC_MIB_RXTIME_CLR ); +} + +static bool +mt7921_wait_reset_state (struct mt7921_dev *dev,u32 state) +{ +bool ret; + + ret =wait_event_timeout (dev->reset_wait, + (READ_ONCE (dev->reset_state) & state), +MT7921_RESET_TIMEOUT ); + +WARN (!ret,"Timeout waiting for MCU reset state %x\n" , state); +return ret; +} + +static void +mt7921_dma_reset (struct mt7921_phy *phy) +{ +struct mt7921_dev *dev = phy->dev; +int i; + +mt76_clear (dev,MT_WFDMA0_GLO_CFG , +MT_WFDMA0_GLO_CFG_TX_DMA_EN |MT_WFDMA0_GLO_CFG_RX_DMA_EN ); + +usleep_range (1000 ,2000 ); + +mt76_queue_tx_cleanup (dev, dev->mt76.q_mcu[MT_MCUQ_WA ], true); +for (i =0 ; i < __MT_TXQ_MAX; i++) +mt76_queue_tx_cleanup (dev, phy->mt76->q_tx[i], true); + +mt76_for_each_q_rx (&dev->mt76, i) { +mt76_queue_rx_reset (dev, i); + } + +mt76_set (dev,MT_WFDMA0_GLO_CFG , +MT_WFDMA0_GLO_CFG_TX_DMA_EN |MT_WFDMA0_GLO_CFG_RX_DMA_EN ); +} + +void mt7921_tx_token_put (struct mt7921_dev *dev) +{ +struct mt76_txwi_cache *txwi; +int id; + +spin_lock_bh (&dev->token_lock); +idr_for_each_entry (&dev->token, txwi, id) { +mt7921_txp_skb_unmap (&dev->mt76, txwi); +if (txwi->skb) { +struct ieee80211_hw *hw; + + hw =mt76_tx_status_get_hw (&dev->mt76, txwi->skb); +ieee80211_free_txskb (hw, txwi->skb); + } +mt76_put_txwi (&dev->mt76, txwi); + dev->token_count--; + } +spin_unlock_bh (&dev->token_lock); +idr_destroy (&dev->token); +} + +/* system error recovery */ +void mt7921_mac_reset_work (struct work_struct *work) +{ +struct mt7921_dev *dev; + + dev = container_of(work, struct mt7921_dev, reset_work); + +if (!(READ_ONCE (dev->reset_state) &MT_MCU_CMD_STOP_DMA )) +return ; + +ieee80211_stop_queues (mt76_hw (dev)); + +set_bit (MT76_RESET , &dev->mphy.state); +set_bit (MT76_MCU_RESET , &dev->mphy.state); +wake_up (&dev->mt76.mcu.wait); +cancel_delayed_work_sync (&dev->mphy.mac_work); + +/* lock/unlock all queues to ensure that no tx is pending */ +mt76_txq_schedule_all (&dev->mphy); + +mt76_worker_disable (&dev->mt76.tx_worker); +napi_disable (&dev->mt76.napi[0 ]); +napi_disable (&dev->mt76.napi[1 ]); +napi_disable (&dev->mt76.napi[2 ]); +napi_disable (&dev->mt76.tx_napi); + +mutex_lock (&dev->mt76.mutex); + +mt76_wr (dev,MT_MCU_INT_EVENT ,MT_MCU_INT_EVENT_DMA_STOPPED ); + +mt7921_tx_token_put (dev); +idr_init (&dev->token); + +if (mt7921_wait_reset_state (dev,MT_MCU_CMD_RESET_DONE )) { +mt7921_dma_reset (&dev->phy); + +mt76_wr (dev,MT_MCU_INT_EVENT ,MT_MCU_INT_EVENT_DMA_INIT ); +mt7921_wait_reset_state (dev,MT_MCU_CMD_RECOVERY_DONE ); + } + +clear_bit (MT76_MCU_RESET , &dev->mphy.state); +clear_bit (MT76_RESET , &dev->mphy.state); + +mt76_worker_enable (&dev->mt76.tx_worker); +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 ]); + +napi_enable (&dev->mt76.napi[2 ]); +napi_schedule (&dev->mt76.napi[2 ]); + +ieee80211_wake_queues (mt76_hw (dev)); + +mt76_wr (dev,MT_MCU_INT_EVENT ,MT_MCU_INT_EVENT_RESET_DONE ); +mt7921_wait_reset_state (dev,MT_MCU_CMD_NORMAL_STATE ); + +mutex_unlock (&dev->mt76.mutex); + +ieee80211_queue_delayed_work (mt76_hw (dev), &dev->mphy.mac_work, +MT7921_WATCHDOG_TIME ); +} + +static 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; + +memset (mib,0 ,sizeof (*mib)); + + mib->fcs_err_cnt =mt76_get_field (dev,MT_MIB_SDR3 (0 ), +MT_MIB_SDR3_FCS_ERR_MASK ); + +for (i =0 , aggr1 = aggr0 +4 ; i <4 ; i++) { +u32 val, val2; + + val =mt76_rr (dev,MT_MIB_MB_SDR1 (0 , i)); + + val2 =FIELD_GET (MT_MIB_ACK_FAIL_COUNT_MASK , val); +if (val2 > mib->ack_fail_cnt) + mib->ack_fail_cnt = val2; + + val2 =FIELD_GET (MT_MIB_BA_MISS_COUNT_MASK , val); +if (val2 > mib->ba_miss_cnt) + mib->ba_miss_cnt = val2; + + val =mt76_rr (dev,MT_MIB_MB_SDR0 (0 , i)); + val2 =FIELD_GET (MT_MIB_RTS_RETRIES_COUNT_MASK , val); +if (val2 > mib->rts_retries_cnt) { + mib->rts_cnt =FIELD_GET (MT_MIB_RTS_COUNT_MASK , val); + mib->rts_retries_cnt = val2; + } + + val =mt76_rr (dev,MT_TX_AGG_CNT (0 , i)); + val2 =mt76_rr (dev,MT_TX_AGG_CNT2 (0 , i)); + + dev->mt76.aggr_stats[aggr0++] += val &0xffff ; + dev->mt76.aggr_stats[aggr0++] += val >>16 ; + dev->mt76.aggr_stats[aggr1++] += val2 &0xffff ; + dev->mt76.aggr_stats[aggr1++] += val2 >>16 ; + } +} + +void mt7921_mac_work (struct work_struct *work) +{ +struct mt7921_phy *phy; +struct mt76_phy *mphy; + + mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, + mac_work.work); + phy = mphy->priv; + +mutex_lock (&mphy->dev->mutex); + +mt76_update_survey (mphy->dev); +if (++mphy->mac_work_count ==5 ) { + mphy->mac_work_count =0 ; + +mt7921_mac_update_mib_stats (phy); + } + +mutex_unlock (&mphy->dev->mutex); + +ieee80211_queue_delayed_work (mphy->hw, &mphy->mac_work, +MT7921_WATCHDOG_TIME ); +}
drivers/net/wireless/mediatek/mt76/mt7921/mac.h new file +333 -0
333 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h new file +347 -0
347 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/regs.h new file +414 -0
414 lines not on this page · raw message
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 2/22 mt76: mt7921: add MCU support
In reply to [email protected]From: Sean Wang <[email protected]>
MT7921 contains a microprocessor with which the host can use command/event to communicate to implement offload features such as establish connection, hardware scan and so on. The host has to download the ROM patch, RAM firmware and finally activate the MCU to complete the MT7921 initialization.
--- .../net/wireless/mediatek/mt76/mt7921/mac.c | 28 + .../net/wireless/mediatek/mt76/mt7921/mcu.c | 2382 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 1050 ++++++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 2 + 4 files changed, 3462 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +28 -0
@@ -1338,6 +1338,30 @@ mt7921_mac_update_mib_stats(struct mt7921_phy *phy) } } +static void +mt7921_mac_sta_stats_work (struct mt7921_phy *phy) +{ +struct mt7921_dev *dev = phy->dev; +struct mt7921_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 mt7921_sta, stats_list); +list_del_init (&msta->stats_list); +spin_unlock_bh (&dev->sta_poll_lock); + +/* query wtbl info to report tx rate for further devices */ +mt7921_get_wtbl_info (dev, msta->wcid.idx); + +spin_lock_bh (&dev->sta_poll_lock); + } + +spin_unlock_bh (&dev->sta_poll_lock); +} +void mt7921_mac_work (struct work_struct *work) {struct mt7921_phy *phy;
@@ -1355,6 +1379,10 @@ void mt7921_mac_work(struct work_struct *work)mt7921_mac_update_mib_stats (phy); } +if (++phy->sta_work_count ==10 ) { + phy->sta_work_count =0 ; +mt7921_mac_sta_stats_work (phy); + };mutex_unlock (&mphy->dev->mutex);
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c new file +2382 -0
2,382 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h new file +1050 -0
578 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +2 -0
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.25.1
Part of the diff is not shown here. View the raw message.
[email protected]
reviewerPATCH v7 3/22 mt76: mt7921: add DMA support
In reply to [email protected]From: Sean Wang <[email protected]>
Add DMA and register access support to MT7921e driver to set up the link for the data movement between the host and MT7921 MAC, or the host and MT7921 MCU.
--- .../net/wireless/mediatek/mt76/mt7921/dma.c | 356 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mac.c | 3 + 2 files changed, 359 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/dma.c
drivers/net/wireless/mediatek/mt76/mt7921/dma.c new file +356 -0
@@ -0,0 +1,356 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7921.h" +#include "../dma.h" +#include "mac.h" + +int mt7921_init_tx_queues (struct mt7921_phy *phy,int idx,int n_desc) +{ +int i, err; + + err =mt76_init_tx_queue (phy->mt76,0 , idx, n_desc,MT_TX_RING_BASE ); +if (err <0 ) +return err; + +for (i =0 ; i <=MT_TXQ_PSD ; i++) + phy->mt76->q_tx[i] = phy->mt76->q_tx[0 ]; + +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 ; + } +} + +static 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; + + dev = container_of(napi, struct mt7921_dev, mt76.tx_napi); + +mt7921_tx_cleanup (dev); + +if (napi_complete_done (napi,0 )) +mt7921_irq_enable (dev,MT_INT_TX_DONE_ALL ); + +return 0 ; +} + +void mt7921_dma_prefetch (struct mt7921_dev *dev) +{ +#define PREFETCH (base, depth) ((base) << 16 | (depth)) + +mt76_wr (dev,MT_WFDMA0_RX_RING0_EXT_CTRL ,PREFETCH (0x0 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_RX_RING2_EXT_CTRL ,PREFETCH (0x40 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_RX_RING3_EXT_CTRL ,PREFETCH (0x80 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_RX_RING4_EXT_CTRL ,PREFETCH (0xc0 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_RX_RING5_EXT_CTRL ,PREFETCH (0x100 ,0x4 )); + +mt76_wr (dev,MT_WFDMA0_TX_RING0_EXT_CTRL ,PREFETCH (0x140 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING1_EXT_CTRL ,PREFETCH (0x180 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING2_EXT_CTRL ,PREFETCH (0x1c0 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING3_EXT_CTRL ,PREFETCH (0x200 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING4_EXT_CTRL ,PREFETCH (0x240 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING5_EXT_CTRL ,PREFETCH (0x280 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING6_EXT_CTRL ,PREFETCH (0x2c0 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING16_EXT_CTRL ,PREFETCH (0x340 ,0x4 )); +mt76_wr (dev,MT_WFDMA0_TX_RING17_EXT_CTRL ,PREFETCH (0x380 ,0x4 )); +} + +static u32 __mt7921_reg_addr (struct mt7921_dev *dev,u32 addr) +{ +static const struct { +u32 phys; +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 */ + {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 */ + {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) */ + {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) */ + {0x820f3000 ,0xa0c00 ,0x0400 },/* WF_LMAC_TOP BN1 (WF_ARB) */ + {0x820f4000 ,0xa1000 ,0x0400 },/* WF_LMAC_TOP BN1 (WF_TMAC) */ + {0x820f5000 ,0xa1400 ,0x0800 },/* WF_LMAC_TOP BN1 (WF_RMAC) */ + {0x820f7000 ,0xa1e00 ,0x0200 },/* WF_LMAC_TOP BN1 (WF_DMA) */ + {0x820f9000 ,0xa3400 ,0x0200 },/* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ + {0x820fa000 ,0xa4000 ,0x0200 },/* WF_LMAC_TOP BN1 (WF_ETBF) */ + {0x820fb000 ,0xa4200 ,0x0400 },/* WF_LMAC_TOP BN1 (WF_LPON) */ + {0x820fc000 ,0xa4600 ,0x0200 },/* WF_LMAC_TOP BN1 (WF_INT) */ + {0x820fd000 ,0xa4800 ,0x0800 },/* WF_LMAC_TOP BN1 (WF_MIB) */ + }; +int i; + +if (addr <0x100000 ) +return addr; + +for (i =0 ; i <ARRAY_SIZE (fixed_map); i++) { +u32 ofs; + +if (addr < fixed_map[i].phys) +continue ; + + ofs = addr - fixed_map[i].phys; +if (ofs > fixed_map[i].size) +continue ; + +return fixed_map[i].mapped + ofs; + } + +if ((addr >=0x18000000 && addr <0x18c00000 ) || + (addr >=0x70000000 && addr <0x78000000 ) || + (addr >=0x7c000000 && addr <0x7c400000 )) +return mt7921_reg_map_l1 (dev, addr); + +dev_err (dev->mt76.dev,"Access currently unsupported address %08x\n" , + addr); + +return 0 ; +} + +static u32 mt7921_rr (struct mt76_dev *mdev,u32 offset) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); +u32 addr =__mt7921_reg_addr (dev, offset); + +return dev->bus_ops->rr (mdev, addr); +} + +static void mt7921_wr (struct mt76_dev *mdev,u32 offset,u32 val) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); +u32 addr =__mt7921_reg_addr (dev, offset); + + dev->bus_ops->wr (mdev, addr, val); +} + +static u32 mt7921_rmw (struct mt76_dev *mdev,u32 offset,u32 mask,u32 val) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); +u32 addr =__mt7921_reg_addr (dev, offset); + +return dev->bus_ops->rmw (mdev, addr, mask, val); +} + +static int mt7921_dmashdl_disabled (struct mt7921_dev *dev) +{ +mt76_clear (dev,MT_WFDMA0_GLO_CFG_EXT0 ,MT_WFDMA0_CSR_TX_DMASHDL_ENABLE ); +mt76_set (dev,MT_DMASHDL_SW_CONTROL ,MT_DMASHDL_DMASHDL_BYPASS ); + +return 0 ; +} + +int mt7921_dma_init (struct mt7921_dev *dev) +{ +/* Increase buffer size to receive large VHT/HE MPDUs */ +struct mt76_bus_ops *bus_ops; +int rx_buf_size =MT_RX_BUF_SIZE *2 ; +int ret; + + dev->bus_ops = dev->mt76.bus; + bus_ops =devm_kmemdup (dev->mt76.dev, dev->bus_ops,sizeof (*bus_ops), +GFP_KERNEL ); +if (!bus_ops) +return -ENOMEM ; + + bus_ops->rr = mt7921_rr; + bus_ops->wr = mt7921_wr; + bus_ops->rmw = mt7921_rmw; + dev->mt76.bus = bus_ops; + +mt76_dma_attach (&dev->mt76); + +/* reset */ +mt76_clear (dev,MT_WFDMA0_RST , +MT_WFDMA0_RST_DMASHDL_ALL_RST | +MT_WFDMA0_RST_LOGIC_RST ); + +mt76_set (dev,MT_WFDMA0_RST , +MT_WFDMA0_RST_DMASHDL_ALL_RST | +MT_WFDMA0_RST_LOGIC_RST ); + + ret =mt7921_dmashdl_disabled (dev); +if (ret) +return ret; + +/* disable WFDMA0 */ +mt76_clear (dev,MT_WFDMA0_GLO_CFG , +MT_WFDMA0_GLO_CFG_TX_DMA_EN | +MT_WFDMA0_GLO_CFG_RX_DMA_EN | +MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | +MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | +MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | +MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 ); + +mt76_poll (dev,MT_WFDMA0_GLO_CFG , +MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | +MT_WFDMA0_GLO_CFG_RX_DMA_BUSY ,0 ,1000 ); + +/* init tx queue */ + ret =mt7921_init_tx_queues (&dev->phy,MT7921_TXQ_BAND0 , +MT7921_TX_RING_SIZE ); +if (ret) +return ret; + +mt76_wr (dev,MT_WFDMA0_TX_RING0_EXT_CTRL ,0x4 ); + +/* command to WM */ + ret =mt76_init_mcu_queue (&dev->mt76,MT_MCUQ_WM ,MT7921_TXQ_MCU_WM , +MT7921_TX_MCU_RING_SIZE ,MT_TX_RING_BASE ); +if (ret) +return ret; + +/* firmware download */ + ret =mt76_init_mcu_queue (&dev->mt76,MT_MCUQ_FWDL ,MT7921_TXQ_FWDL , +MT7921_TX_FWDL_RING_SIZE ,MT_TX_RING_BASE ); +if (ret) +return ret; + +/* event from WM before firmware download */ + ret =mt76_queue_alloc (dev, &dev->mt76.q_rx[MT_RXQ_MCU ], +MT7921_RXQ_MCU_WM , +MT7921_RX_MCU_RING_SIZE , + rx_buf_size,MT_RX_EVENT_RING_BASE ); +if (ret) +return ret; + +/* Change mcu queue after firmware download */ + ret =mt76_queue_alloc (dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA ], +MT7921_RXQ_MCU_WM , +MT7921_RX_MCU_RING_SIZE , + rx_buf_size,MT_WFDMA0 (0x540 )); +if (ret) +return ret; + +/* rx data */ + ret =mt76_queue_alloc (dev, &dev->mt76.q_rx[MT_RXQ_MAIN ], +MT7921_RXQ_BAND0 ,MT7921_RX_RING_SIZE , + rx_buf_size,MT_RX_DATA_RING_BASE ); +if (ret) +return ret; + + ret =mt76_init_queues (dev); +if (ret <0 ) +return ret; + +netif_tx_napi_add (&dev->mt76.napi_dev, &dev->mt76.tx_napi, + mt7921_poll_tx,NAPI_POLL_WEIGHT ); +napi_enable (&dev->mt76.tx_napi); + +/* configure perfetch settings */ +mt7921_dma_prefetch (dev); + +/* reset dma idx */ +mt76_wr (dev,MT_WFDMA0_RST_DTX_PTR , ~0 ); + +/* configure delay interrupt */ +mt76_wr (dev,MT_WFDMA0_PRI_DLY_INT_CFG0 ,0 ); + +mt76_set (dev,MT_WFDMA0_GLO_CFG , +MT_WFDMA0_GLO_CFG_TX_WB_DDONE | +MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | +MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | +MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | +MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | +MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 ); + +mt76_set (dev,MT_WFDMA0_GLO_CFG , +MT_WFDMA0_GLO_CFG_TX_DMA_EN |MT_WFDMA0_GLO_CFG_RX_DMA_EN ); + +mt76_set (dev,0x54000120 ,BIT (1 )); + +/* enable interrupts for TX/RX rings */ +mt7921_irq_enable (dev,MT_INT_RX_DONE_ALL |MT_INT_TX_DONE_ALL | +MT_INT_MCU_CMD ); + +return 0 ; +} + +void mt7921_dma_cleanup (struct mt7921_dev *dev) +{ +/* disable */ +mt76_clear (dev,MT_WFDMA0_GLO_CFG , +MT_WFDMA0_GLO_CFG_TX_DMA_EN | +MT_WFDMA0_GLO_CFG_RX_DMA_EN | +MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | +MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | +MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | +MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 ); + +/* reset */ +mt76_clear (dev,MT_WFDMA0_RST , +MT_WFDMA0_RST_DMASHDL_ALL_RST | +MT_WFDMA0_RST_LOGIC_RST ); + +mt76_set (dev,MT_WFDMA0_RST , +MT_WFDMA0_RST_DMASHDL_ALL_RST | +MT_WFDMA0_RST_LOGIC_RST ); + +mt76_dma_cleanup (&dev->mt76); +}
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +3 -0
@@ -1204,6 +1204,9 @@ mt7921_dma_reset(struct mt7921_phy *phy)mt76_queue_rx_reset (dev, i); } +/* re-init prefetch settings after reset */ +mt7921_dma_prefetch (dev); +mt76_set (dev,MT_WFDMA0_GLO_CFG ,MT_WFDMA0_GLO_CFG_TX_DMA_EN |MT_WFDMA0_GLO_CFG_RX_DMA_EN ); }
Signature · 5 lines
2.25.1 _______________________________________________ Linux-mediatek mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-mediatek
[email protected]
reviewerPATCH v7 4/22 mt76: mt7921: add EEPROM support
In reply to [email protected]From: Sean Wang <[email protected]>
Add EEPROM support to MT7921 to determine the capability the card has such as indentificaiton, MAC address, the band and antenna number the card able to support.
--- .../wireless/mediatek/mt76/mt7921/eeprom.c | 100 ++++++++++++++++++ .../wireless/mediatek/mt76/mt7921/eeprom.h | 27 +++++ 2 files changed, 127 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.h
drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c new file +100 -0
@@ -0,0 +1,100 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7921.h" +#include "eeprom.h" + +static u32 mt7921_eeprom_read (struct mt7921_dev *dev,u32 offset) +{ +u8 *data = dev->mt76.eeprom.data; + +if (data[offset] ==0xff ) +mt7921_mcu_get_eeprom (dev, offset); + +return data[offset]; +} + +static int mt7921_eeprom_load (struct mt7921_dev *dev) +{ +int ret; + + ret =mt76_eeprom_init (&dev->mt76,MT7921_EEPROM_SIZE ); +if (ret <0 ) +return ret; + +memset (dev->mt76.eeprom.data,-1 ,MT7921_EEPROM_SIZE ); + +return 0 ; +} + +static int mt7921_check_eeprom (struct mt7921_dev *dev) +{ +u8 *eeprom = dev->mt76.eeprom.data; +u16 val; + +mt7921_eeprom_read (dev,MT_EE_CHIP_ID ); + val =get_unaligned_le16 (eeprom); + +switch (val) { +case 0x7961 : +return 0 ; +default : +return -EINVAL ; + } +} + +void mt7921_eeprom_parse_band_config (struct mt7921_phy *phy) +{ +struct mt7921_dev *dev = phy->dev; +u32 val; + + val =mt7921_eeprom_read (dev,MT_EE_WIFI_CONF ); + val =FIELD_GET (MT_EE_WIFI_CONF_BAND_SEL , val); + +switch (val) { +case MT_EE_5GHZ : + phy->mt76->cap.has_5ghz = true; +break ; +case MT_EE_2GHZ : + phy->mt76->cap.has_2ghz = true; +break ; +default : + phy->mt76->cap.has_2ghz = true; + phy->mt76->cap.has_5ghz = true; +break ; + } +} + +static void mt7921_eeprom_parse_hw_cap (struct mt7921_dev *dev) +{ +u8 tx_mask; + +mt7921_eeprom_parse_band_config (&dev->phy); + +/* TODO: read NSS with MCU_CMD_NIC_CAPV2 */ + tx_mask =2 ; + dev->chainmask =BIT (tx_mask) -1 ; + dev->mphy.antenna_mask = dev->chainmask; + dev->mphy.chainmask = dev->mphy.antenna_mask; +} + +int mt7921_eeprom_init (struct mt7921_dev *dev) +{ +int ret; + + ret =mt7921_eeprom_load (dev); +if (ret <0 ) +return ret; + + ret =mt7921_check_eeprom (dev); +if (ret) +return ret; + +mt7921_eeprom_parse_hw_cap (dev); +memcpy (dev->mphy.macaddr, dev->mt76.eeprom.data +MT_EE_MAC_ADDR , +ETH_ALEN ); + +mt76_eeprom_override (&dev->mphy); + +return 0 ; +}
drivers/net/wireless/mediatek/mt76/mt7921/eeprom.h new file +27 -0
@@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7921_EEPROM_H +#define __MT7921_EEPROM_H + +#include "mt7921.h" + +enum mt7921_eeprom_field { +MT_EE_CHIP_ID =0x000 , +MT_EE_VERSION =0x002 , +MT_EE_MAC_ADDR =0x004 , +MT_EE_WIFI_CONF =0x07c , + __MT_EE_MAX =0x3bf +}; + +#define MT_EE_WIFI_CONF_TX_MASK BIT(0) +#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(3, 2) + +enum mt7921_eeprom_band { +MT_EE_NA , +MT_EE_5GHZ , +MT_EE_2GHZ , +MT_EE_DUAL_BAND , +}; + +#endif
Signature · 5 lines
2.25.1 _______________________________________________ Linux-mediatek mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-mediatek
[email protected]
reviewerPATCH v7 5/22 mt76: mt7921: add ieee80211_ops
In reply to [email protected]From: Sean Wang <[email protected]>
Filling ieee80211_ops with the mt7921 operations.
--- .../net/wireless/mediatek/mt76/mt7921/main.c | 934 ++++++++++++++++++ 1 file changed, 934 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/main.c
drivers/net/wireless/mediatek/mt76/mt7921/main.c new file +934 -0
@@ -0,0 +1,934 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include <linux/etherdevice.h> +#include <linux/platform_device.h> +#include <linux/pci.h> +#include <linux/module.h> +#include "mt7921.h" +#include "mcu.h" + +static void +mt7921_gen_ppe_thresh (u8 *he_ppet,int nss) +{ +u8 i, ppet_bits, ppet_size, ru_bit_mask =0x7 ;/* HE80 */ +u8 ppet16_ppet8_ru3_ru0[] = {0x1c ,0xc7 ,0x71 }; + + he_ppet[0 ] =FIELD_PREP (IEEE80211_PPE_THRES_NSS_MASK , nss -1 ) | +FIELD_PREP (IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK , + ru_bit_mask); + + ppet_bits =IEEE80211_PPE_THRES_INFO_PPET_SIZE * + nss *hweight8 (ru_bit_mask) *2 ; + ppet_size =DIV_ROUND_UP (ppet_bits,8 ); + +for (i =0 ; i < ppet_size -1 ; i++) + he_ppet[i +1 ] = ppet16_ppet8_ru3_ru0[i %3 ]; + + he_ppet[i +1 ] = ppet16_ppet8_ru3_ru0[i %3 ] & + (0xff >> (8 - (ppet_bits -1 ) %8 )); +} + +static int +mt7921_init_he_caps (struct mt7921_phy *phy,enum nl80211_band band, +struct ieee80211_sband_iftype_data *data) +{ +int i, idx =0 ; +int nss =hweight8 (phy->mt76->chainmask); +u16 mcs_map =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 )); + } + +for (i =0 ; i <NUM_NL80211_IFTYPES ; i++) { +struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; +struct ieee80211_he_cap_elem *he_cap_elem = + &he_cap->he_cap_elem; +struct ieee80211_he_mcs_nss_supp *he_mcs = + &he_cap->he_mcs_nss_supp; + +switch (i) { +case NL80211_IFTYPE_STATION : +break ; +default : +continue ; + } + + data[idx].types_mask =BIT (i); + he_cap->has_he = true; + + he_cap_elem->mac_cap_info[0 ] = +IEEE80211_HE_MAC_CAP0_HTC_HE ; + he_cap_elem->mac_cap_info[3 ] = +IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED ; + he_cap_elem->mac_cap_info[4 ] = +IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU ; + +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 ) + he_cap_elem->phy_cap_info[0 ] = +IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | +IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G ; + + he_cap_elem->phy_cap_info[1 ] = +IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD ; + he_cap_elem->phy_cap_info[2 ] = +IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | +IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ ; + +switch (i) { +case NL80211_IFTYPE_STATION : + he_cap_elem->mac_cap_info[0 ] |= +IEEE80211_HE_MAC_CAP0_TWT_REQ ; + he_cap_elem->mac_cap_info[1 ] |= +IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US ; + +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 ) + he_cap_elem->phy_cap_info[0 ] |= +IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G ; + + he_cap_elem->phy_cap_info[1 ] |= +IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | +IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US ; + he_cap_elem->phy_cap_info[3 ] |= +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_TRIG_CQI_FB | +IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | +IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT ; + he_cap_elem->phy_cap_info[7 ] |= +IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | +IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI ; + he_cap_elem->phy_cap_info[8 ] |= +IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | +IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484 ; + he_cap_elem->phy_cap_info[9 ] |= +IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | +IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | +IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | +IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | +IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | +IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB ; +break ; + } + + 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); + +memset (he_cap->ppe_thres,0 ,sizeof (he_cap->ppe_thres)); +if (he_cap_elem->phy_cap_info[6 ] & +IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT ) { +mt7921_gen_ppe_thresh (he_cap->ppe_thres, nss); + }else { + he_cap_elem->phy_cap_info[9 ] |= +IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US ; + } + idx++; + } + +return idx; +} + +void mt7921_set_stream_he_caps (struct mt7921_phy *phy) +{ +struct ieee80211_sband_iftype_data *data; +struct ieee80211_supported_band *band; +int n; + +if (phy->mt76->cap.has_2ghz) { + data = phy->iftype[NL80211_BAND_2GHZ ]; + n =mt7921_init_he_caps (phy,NL80211_BAND_2GHZ , data); + + band = &phy->mt76->sband_2g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } + +if (phy->mt76->cap.has_5ghz) { + data = phy->iftype[NL80211_BAND_5GHZ ]; + n =mt7921_init_he_caps (phy,NL80211_BAND_5GHZ , data); + + band = &phy->mt76->sband_5g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } +} + +static int mt7921_start (struct ieee80211_hw *hw) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); + +mutex_lock (&dev->mt76.mutex); + +mt7921_mcu_set_mac (dev,0 , true, false); +mt7921_mcu_set_channel_domain (phy); +mt7921_mcu_set_chan_info (phy,MCU_EXT_CMD_SET_RX_PATH ); +mt7921_mac_reset_counters (phy); +set_bit (MT76_STATE_RUNNING , &phy->mt76->state); + +ieee80211_queue_delayed_work (hw, &phy->mt76->mac_work, +MT7921_WATCHDOG_TIME ); + +mutex_unlock (&dev->mt76.mutex); + +return 0 ; +} + +static void mt7921_stop (struct ieee80211_hw *hw) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); + +cancel_delayed_work_sync (&phy->mt76->mac_work); + +mutex_lock (&dev->mt76.mutex); +clear_bit (MT76_STATE_RUNNING , &phy->mt76->state); +mt7921_mcu_set_mac (dev,0 , false, false); +mutex_unlock (&dev->mt76.mutex); +} + +static inline int get_free_idx (u32 mask,u8 start,u8 end) +{ +return ffs (~mask &GENMASK (end, start)); +} + +static int get_omac_idx (enum nl80211_iftype type,u64 mask) +{ +int i; + +switch (type) { +case NL80211_IFTYPE_STATION : +/* prefer hw bssid slot 1-3 */ + i =get_free_idx (mask,HW_BSSID_1 ,HW_BSSID_3 ); +if (i) +return i -1 ; + +if (type !=NL80211_IFTYPE_STATION ) +break ; + +/* next, try to find a free repeater entry for the sta */ + i =get_free_idx (mask >>REPEATER_BSSID_START ,0 , +REPEATER_BSSID_MAX -REPEATER_BSSID_START ); +if (i) +return i +32 -1 ; + + i =get_free_idx (mask,EXT_BSSID_1 ,EXT_BSSID_MAX ); +if (i) +return i -1 ; + +if (~mask &BIT (HW_BSSID_0 )) +return HW_BSSID_0 ; + +break ; +case NL80211_IFTYPE_MONITOR : +/* ap uses hw bssid 0 and ext bssid */ +if (~mask &BIT (HW_BSSID_0 )) +return HW_BSSID_0 ; + + i =get_free_idx (mask,EXT_BSSID_1 ,EXT_BSSID_MAX ); +if (i) +return i -1 ; + +break ; +default : +WARN_ON (1 ); +break ; + } + +return -1 ; +} + +static int mt7921_add_interface (struct ieee80211_hw *hw, +struct ieee80211_vif *vif) +{ +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +struct mt76_txq *mtxq; +int idx, ret =0 ; + +mutex_lock (&dev->mt76.mutex); + +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 ; + goto out; + } + + idx =get_omac_idx (vif->type, phy->omac_mask); +if (idx <0 ) { + ret = -ENOSPC ; + goto out; + } + mvif->mt76.omac_idx = idx; + mvif->phy = phy; + mvif->mt76.band_idx =0 ; + mvif->mt76.wmm_idx = mvif->mt76.idx %MT7921_MAX_WMM_SETS ; + + ret =mt7921_mcu_uni_add_dev (dev, vif, true); +if (ret) + goto out; + + dev->mt76.vif_mask |=BIT (mvif->mt76.idx); + phy->omac_mask |=BIT_ULL (mvif->mt76.omac_idx); + + idx =MT7921_WTBL_RESERVED - mvif->mt76.idx; + +INIT_LIST_HEAD (&mvif->sta.stats_list); +INIT_LIST_HEAD (&mvif->sta.poll_list); + mvif->sta.wcid.idx = idx; + mvif->sta.wcid.ext_phy = mvif->mt76.band_idx; + mvif->sta.wcid.hw_key_idx =-1 ; + mvif->sta.wcid.tx_info |=MT_WCID_TX_INFO_SET ; +mt7921_mac_wtbl_update (dev, idx, +MT_WTBL_UPDATE_ADM_COUNT_CLEAR ); + +rcu_assign_pointer (dev->mt76.wcid[idx], &mvif->sta.wcid); +if (vif->txq) { + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + mtxq->wcid = &mvif->sta.wcid; + } + +if (vif->type !=NL80211_IFTYPE_AP && + (!mvif->mt76.omac_idx || mvif->mt76.omac_idx >3 )) + vif->offload_flags =0 ; + + vif->offload_flags |=IEEE80211_OFFLOAD_ENCAP_4ADDR ; + +out: +mutex_unlock (&dev->mt76.mutex); + +return ret; +} + +static void mt7921_remove_interface (struct ieee80211_hw *hw, +struct ieee80211_vif *vif) +{ +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +struct mt7921_sta *msta = &mvif->sta; +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +int idx = msta->wcid.idx; + +if (vif == phy->monitor_vif) + phy->monitor_vif =NULL ; + +mt7921_mcu_uni_add_dev (dev, vif, false); + +rcu_assign_pointer (dev->mt76.wcid[idx],NULL ); + +mutex_lock (&dev->mt76.mutex); + dev->mt76.vif_mask &= ~BIT (mvif->mt76.idx); + phy->omac_mask &= ~BIT_ULL (mvif->mt76.omac_idx); +mutex_unlock (&dev->mt76.mutex); + +spin_lock_bh (&dev->sta_poll_lock); +if (!list_empty (&msta->poll_list)) +list_del_init (&msta->poll_list); +spin_unlock_bh (&dev->sta_poll_lock); +} + +int mt7921_set_channel (struct mt7921_phy *phy) +{ +struct mt7921_dev *dev = phy->dev; +int ret; + +cancel_delayed_work_sync (&phy->mt76->mac_work); + +mutex_lock (&dev->mt76.mutex); +set_bit (MT76_RESET , &phy->mt76->state); + +mt76_set_channel (phy->mt76); + + ret =mt7921_mcu_set_chan_info (phy,MCU_EXT_CMD_CHANNEL_SWITCH ); +if (ret) + goto out; + +mt7921_mac_set_timing (phy); + +mt7921_mac_reset_counters (phy); + phy->noise =0 ; + +out: +clear_bit (MT76_RESET , &phy->mt76->state); +mutex_unlock (&dev->mt76.mutex); + +mt76_txq_schedule_all (phy->mt76); + +ieee80211_queue_delayed_work (phy->mt76->hw, &phy->mt76->mac_work, +MT7921_WATCHDOG_TIME ); + +return ret; +} + +static int mt7921_set_key (struct ieee80211_hw *hw,enum set_key_cmd cmd, +struct ieee80211_vif *vif,struct ieee80211_sta *sta, +struct ieee80211_key_conf *key) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +struct mt7921_sta *msta = sta ? (struct mt7921_sta *)sta->drv_priv : + &mvif->sta; +struct mt76_wcid *wcid = &msta->wcid; +int idx = key->keyidx; + +/* The hardware does not support per-STA RX GTK, fallback +* to software mode for these. +*/ +if ((vif->type ==NL80211_IFTYPE_ADHOC || + vif->type ==NL80211_IFTYPE_MESH_POINT ) && + (key->cipher ==WLAN_CIPHER_SUITE_TKIP || + key->cipher ==WLAN_CIPHER_SUITE_CCMP ) && + !(key->flags &IEEE80211_KEY_FLAG_PAIRWISE )) +return -EOPNOTSUPP ; + +/* fall back to sw encryption for unsupported ciphers */ +switch (key->cipher) { +case WLAN_CIPHER_SUITE_AES_CMAC : + key->flags |=IEEE80211_KEY_FLAG_GENERATE_MMIE ; +break ; +case WLAN_CIPHER_SUITE_TKIP : +case WLAN_CIPHER_SUITE_CCMP : +case WLAN_CIPHER_SUITE_CCMP_256 : +case WLAN_CIPHER_SUITE_GCMP : +case WLAN_CIPHER_SUITE_GCMP_256 : +case WLAN_CIPHER_SUITE_SMS4 : +break ; +case WLAN_CIPHER_SUITE_WEP40 : +case WLAN_CIPHER_SUITE_WEP104 : +default : +return -EOPNOTSUPP ; + } + +if (cmd ==SET_KEY ) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + }else if (idx == wcid->hw_key_idx) { + wcid->hw_key_idx =-1 ; + } +mt76_wcid_key_setup (&dev->mt76, wcid, + cmd ==SET_KEY ? key :NULL ); + +return mt7921_mcu_add_key (dev, vif, msta, key, cmd); +} + +static int mt7921_config (struct ieee80211_hw *hw,u32 changed) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +bool band = phy != &dev->phy; +int ret; + +if (changed &IEEE80211_CONF_CHANGE_CHANNEL ) { +ieee80211_stop_queues (hw); + ret =mt7921_set_channel (phy); +if (ret) +return ret; +ieee80211_wake_queues (hw); + } + +mutex_lock (&dev->mt76.mutex); + +if (changed &IEEE80211_CONF_CHANGE_MONITOR ) { +bool enabled = !!(hw->conf.flags &IEEE80211_CONF_MONITOR ); + +if (!enabled) + phy->rxfilter |=MT_WF_RFCR_DROP_OTHER_UC ; +else + phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC ; + +mt76_rmw_field (dev,MT_DMA_DCR0 (band),MT_DMA_DCR0_RXD_G5_EN , + enabled); +mt76_wr (dev,MT_WF_RFCR (band), phy->rxfilter); + } + +mutex_unlock (&dev->mt76.mutex); + +return 0 ; +} + +static int +mt7921_conf_tx (struct ieee80211_hw *hw,struct ieee80211_vif *vif,u16 queue, +const struct ieee80211_tx_queue_params *params) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + +/* no need to update right away, we'll get BSS_CHANGED_QOS */ + queue =mt7921_lmac_mapping (dev, queue); + mvif->queue_params[queue] = *params; + +return 0 ; +} + +static void mt7921_configure_filter (struct ieee80211_hw *hw, +unsigned int changed_flags, +unsigned int *total_flags, +u64 multicast) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +bool band = phy != &dev->phy; +u32 ctl_flags =MT_WF_RFCR1_DROP_ACK | +MT_WF_RFCR1_DROP_BF_POLL | +MT_WF_RFCR1_DROP_BA | +MT_WF_RFCR1_DROP_CFEND | +MT_WF_RFCR1_DROP_CFACK ; +u32 flags =0 ; + +#define MT76_FILTER (_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + phy->rxfilter &= ~(_hw); \ + phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + +mutex_lock (&dev->mt76.mutex); + + phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | +MT_WF_RFCR_DROP_OTHER_BEACON | +MT_WF_RFCR_DROP_FRAME_REPORT | +MT_WF_RFCR_DROP_PROBEREQ | +MT_WF_RFCR_DROP_MCAST_FILTERED | +MT_WF_RFCR_DROP_MCAST | +MT_WF_RFCR_DROP_BCAST | +MT_WF_RFCR_DROP_DUPLICATE | +MT_WF_RFCR_DROP_A2_BSSID | +MT_WF_RFCR_DROP_UNWANTED_CTL | +MT_WF_RFCR_DROP_STBC_MULTI ); + +MT76_FILTER (OTHER_BSS ,MT_WF_RFCR_DROP_OTHER_TIM | +MT_WF_RFCR_DROP_A3_MAC | +MT_WF_RFCR_DROP_A3_BSSID ); + +MT76_FILTER (FCSFAIL ,MT_WF_RFCR_DROP_FCSFAIL ); + +MT76_FILTER (CONTROL ,MT_WF_RFCR_DROP_CTS | +MT_WF_RFCR_DROP_RTS | +MT_WF_RFCR_DROP_CTL_RSV | +MT_WF_RFCR_DROP_NDPA ); + + *total_flags = flags; +mt76_wr (dev,MT_WF_RFCR (band), phy->rxfilter); + +if (*total_flags &FIF_CONTROL ) +mt76_clear (dev,MT_WF_RFCR1 (band), ctl_flags); +else +mt76_set (dev,MT_WF_RFCR1 (band), ctl_flags); + +mutex_unlock (&dev->mt76.mutex); +} + +static void mt7921_bss_info_changed (struct ieee80211_hw *hw, +struct ieee80211_vif *vif, +struct ieee80211_bss_conf *info, +u32 changed) +{ +struct mt7921_phy *phy =mt7921_hw_phy (hw); +struct mt7921_dev *dev =mt7921_hw_dev (hw); + +mutex_lock (&dev->mt76.mutex); + +if (changed &BSS_CHANGED_ERP_SLOT ) { +int slottime = info->use_short_slot ?9 :20 ; + +if (slottime != phy->slottime) { + phy->slottime = slottime; +mt7921_mac_set_timing (phy); + } + } + +/* ensure that enable txcmd_mode after bss_info */ +if (changed & (BSS_CHANGED_QOS |BSS_CHANGED_BEACON_ENABLED )) +mt7921_mcu_set_tx (dev, vif); + +mutex_unlock (&dev->mt76.mutex); +} + +int mt7921_mac_sta_add (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); +struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +int ret, idx; + + idx =mt76_wcid_alloc (dev->mt76.wcid_mask,MT7921_WTBL_STA -1 ); +if (idx <0 ) +return -ENOSPC ; + +INIT_LIST_HEAD (&msta->stats_list); +INIT_LIST_HEAD (&msta->poll_list); + msta->vif = mvif; + msta->wcid.sta =1 ; + msta->wcid.idx = idx; + msta->wcid.ext_phy = mvif->mt76.band_idx; + msta->wcid.tx_info |=MT_WCID_TX_INFO_SET ; + msta->stats.jiffies = jiffies; + +if (vif->type ==NL80211_IFTYPE_STATION && !sta->tdls) +mt7921_mcu_uni_add_bss (&dev->phy, vif, true); +mt7921_mac_wtbl_update (dev, idx, +MT_WTBL_UPDATE_ADM_COUNT_CLEAR ); + + ret =mt7921_mcu_uni_add_sta (dev, vif, sta, true); +if (ret) +return ret; + +return 0 ; +} + +void mt7921_mac_sta_remove (struct mt76_dev *mdev,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); +struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + +mt7921_mcu_uni_add_sta (dev, vif, sta, false); +mt7921_mac_wtbl_update (dev, msta->wcid.idx, +MT_WTBL_UPDATE_ADM_COUNT_CLEAR ); +if (vif->type ==NL80211_IFTYPE_STATION && !sta->tdls) +mt7921_mcu_uni_add_bss (&dev->phy, vif, false); + +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); +} + +static void mt7921_tx (struct ieee80211_hw *hw, +struct ieee80211_tx_control *control, +struct sk_buff *skb) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt76_phy *mphy = hw->priv; +struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb); +struct ieee80211_vif *vif = info->control.vif; +struct mt76_wcid *wcid = &dev->mt76.global_wcid; + +if (control->sta) { +struct mt7921_sta *sta; + + sta = (struct mt7921_sta *)control->sta->drv_priv; + wcid = &sta->wcid; + } + +if (vif && !control->sta) { +struct mt7921_vif *mvif; + + mvif = (struct mt7921_vif *)vif->drv_priv; + wcid = &mvif->sta.wcid; + } + +mt76_tx (mphy, control->sta, wcid, skb); +} + +static int mt7921_set_rts_threshold (struct ieee80211_hw *hw,u32 val) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); + +mutex_lock (&dev->mt76.mutex); +mt7921_mcu_set_rts_thresh (phy, val); +mutex_unlock (&dev->mt76.mutex); + +return 0 ; +} + +static int +mt7921_ampdu_action (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_ampdu_params *params) +{ +enum ieee80211_ampdu_mlme_action action = params->action; +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct ieee80211_sta *sta = params->sta; +struct ieee80211_txq *txq = sta->txq[params->tid]; +struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; +u16 tid = params->tid; +u16 ssn = params->ssn; +struct mt76_txq *mtxq; +int ret =0 ; + +if (!txq) +return -EINVAL ; + + mtxq = (struct mt76_txq *)txq->drv_priv; + +mutex_lock (&dev->mt76.mutex); +switch (action) { +case IEEE80211_AMPDU_RX_START : +mt76_rx_aggr_start (&dev->mt76, &msta->wcid, tid, ssn, + params->buf_size); +mt7921_mcu_uni_rx_ba (dev, params, true); +break ; +case IEEE80211_AMPDU_RX_STOP : +mt76_rx_aggr_stop (&dev->mt76, &msta->wcid, tid); +mt7921_mcu_uni_rx_ba (dev, params, false); +break ; +case IEEE80211_AMPDU_TX_OPERATIONAL : + mtxq->aggr = true; + mtxq->send_bar = false; +mt7921_mcu_uni_tx_ba (dev, params, true); +break ; +case IEEE80211_AMPDU_TX_STOP_FLUSH : +case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT : + mtxq->aggr = false; +clear_bit (tid, &msta->ampdu_state); +mt7921_mcu_uni_tx_ba (dev, params, false); +break ; +case IEEE80211_AMPDU_TX_START : +set_bit (tid, &msta->ampdu_state); + ret =IEEE80211_AMPDU_TX_START_IMMEDIATE ; +break ; +case IEEE80211_AMPDU_TX_STOP_CONT : + mtxq->aggr = false; +clear_bit (tid, &msta->ampdu_state); +mt7921_mcu_uni_tx_ba (dev, params, false); +ieee80211_stop_tx_ba_cb_irqsafe (vif, sta->addr, tid); +break ; + } +mutex_unlock (&dev->mt76.mutex); + +return ret; +} + +static int +mt7921_sta_add (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ +return mt76_sta_state (hw, vif, sta,IEEE80211_STA_NOTEXIST , +IEEE80211_STA_NONE ); +} + +static int +mt7921_sta_remove (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ +return mt76_sta_state (hw, vif, sta,IEEE80211_STA_NONE , +IEEE80211_STA_NOTEXIST ); +} + +static int +mt7921_get_stats (struct ieee80211_hw *hw, +struct ieee80211_low_level_stats *stats) +{ +struct mt7921_phy *phy =mt7921_hw_phy (hw); +struct mib_stats *mib = &phy->mib; + + stats->dot11RTSSuccessCount = mib->rts_cnt; + stats->dot11RTSFailureCount = mib->rts_retries_cnt; + stats->dot11FCSErrorCount = mib->fcs_err_cnt; + stats->dot11ACKFailureCount = mib->ack_fail_cnt; + +return 0 ; +} + +static u64 +mt7921_get_tsf (struct ieee80211_hw *hw,struct ieee80211_vif *vif) +{ +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +u8 omac_idx = mvif->mt76.omac_idx; +bool band = phy != &dev->phy; +union { +u64 t64; +u32 t32[2 ]; + } tsf; +u16 n; + +mutex_lock (&dev->mt76.mutex); + + n = omac_idx >HW_BSSID_MAX ?HW_BSSID_0 : omac_idx; +/* TSF software read */ +mt76_set (dev,MT_LPON_TCR (band, n),MT_LPON_TCR_SW_MODE ); + tsf.t32[0 ] =mt76_rr (dev,MT_LPON_UTTR0 (band)); + tsf.t32[1 ] =mt76_rr (dev,MT_LPON_UTTR1 (band)); + +mutex_unlock (&dev->mt76.mutex); + +return tsf.t64; +} + +static void +mt7921_set_tsf (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +u64 timestamp) +{ +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +u8 omac_idx = mvif->mt76.omac_idx; +bool band = phy != &dev->phy; +union { +u64 t64; +u32 t32[2 ]; + } tsf = { .t64 = timestamp, }; +u16 n; + +mutex_lock (&dev->mt76.mutex); + + n = omac_idx >HW_BSSID_MAX ?HW_BSSID_0 : omac_idx; +mt76_wr (dev,MT_LPON_UTTR0 (band), tsf.t32[0 ]); +mt76_wr (dev,MT_LPON_UTTR1 (band), tsf.t32[1 ]); +/* TSF software overwrite */ +mt76_set (dev,MT_LPON_TCR (band, n),MT_LPON_TCR_SW_WRITE ); + +mutex_unlock (&dev->mt76.mutex); +} + +static void +mt7921_set_coverage_class (struct ieee80211_hw *hw,s16 coverage_class) +{ +struct mt7921_phy *phy =mt7921_hw_phy (hw); +struct mt7921_dev *dev = phy->dev; + +mutex_lock (&dev->mt76.mutex); + phy->coverage_class =max_t (s16, coverage_class,0 ); +mt7921_mac_set_timing (phy); +mutex_unlock (&dev->mt76.mutex); +} + +void mt7921_scan_work (struct work_struct *work) +{ +struct mt7921_phy *phy; + + phy = (struct mt7921_phy *)container_of(work, struct mt7921_phy, + scan_work.work); + +while (true) { +struct mt7921_mcu_rxd *rxd; +struct sk_buff *skb; + +spin_lock_bh (&phy->dev->mt76.lock); + skb =__skb_dequeue (&phy->scan_event_list); +spin_unlock_bh (&phy->dev->mt76.lock); + +if (!skb) +break ; + + rxd = (struct mt7921_mcu_rxd *)skb->data; +if (rxd->eid ==MCU_EVENT_SCHED_SCAN_DONE ) { +ieee80211_sched_scan_results (phy->mt76->hw); + }else if (test_and_clear_bit (MT76_HW_SCANNING , + &phy->mt76->state)) { +struct cfg80211_scan_info info = { + .aborted = false, + }; + +ieee80211_scan_completed (phy->mt76->hw, &info); + } +dev_kfree_skb (skb); + } +} + +static int +mt7921_hw_scan (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct ieee80211_scan_request *req) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt76_phy *mphy = hw->priv; +int err; + +mutex_lock (&dev->mt76.mutex); + err =mt7921_mcu_hw_scan (mphy->priv, vif, req); +mutex_unlock (&dev->mt76.mutex); + +return err; +} + +static void +mt7921_cancel_hw_scan (struct ieee80211_hw *hw,struct ieee80211_vif *vif) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt76_phy *mphy = hw->priv; + +mutex_lock (&dev->mt76.mutex); +mt7921_mcu_cancel_hw_scan (mphy->priv, vif); +mutex_unlock (&dev->mt76.mutex); +} + +static int +mt7921_set_antenna (struct ieee80211_hw *hw,u32 tx_ant,u32 rx_ant) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +int max_nss =hweight8 (hw->wiphy->available_antennas_tx); + +if (!tx_ant || tx_ant != rx_ant ||ffs (tx_ant) > max_nss) +return -EINVAL ; + +if ((BIT (hweight8 (tx_ant)) -1 ) != tx_ant) + tx_ant =BIT (ffs (tx_ant) -1 ) -1 ; + +mutex_lock (&dev->mt76.mutex); + + phy->mt76->antenna_mask = tx_ant; + phy->mt76->chainmask = tx_ant; + +mt76_set_stream_caps (phy->mt76, true); +mt7921_set_stream_he_caps (phy); + +mutex_unlock (&dev->mt76.mutex); + +return 0 ; +} + +static void +mt7921_sta_rc_update (struct ieee80211_hw *hw, +struct ieee80211_vif *vif, +struct ieee80211_sta *sta, +u32 changed) +{ +} + +const struct ieee80211_ops mt7921_ops = { + .tx = mt7921_tx, + .start = mt7921_start, + .stop = mt7921_stop, + .add_interface = mt7921_add_interface, + .remove_interface = mt7921_remove_interface, + .config = mt7921_config, + .conf_tx = mt7921_conf_tx, + .configure_filter = mt7921_configure_filter, + .bss_info_changed = mt7921_bss_info_changed, + .sta_add = mt7921_sta_add, + .sta_remove = mt7921_sta_remove, + .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .sta_rc_update = mt7921_sta_rc_update, + .set_key = mt7921_set_key, + .ampdu_action = mt7921_ampdu_action, + .set_rts_threshold = mt7921_set_rts_threshold, + .wake_tx_queue = mt76_wake_tx_queue, + .release_buffered_frames = mt76_release_buffered_frames, + .get_txpower = mt76_get_txpower, + .get_stats = mt7921_get_stats, + .get_tsf = mt7921_get_tsf, + .set_tsf = mt7921_set_tsf, + .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, + .set_antenna = mt7921_set_antenna, + .set_coverage_class = mt7921_set_coverage_class, + .hw_scan = mt7921_hw_scan, + .cancel_hw_scan = mt7921_cancel_hw_scan, +};
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 6/22 mt76: mt7921: introduce mt7921e support
In reply to [email protected]From: Sean Wang <[email protected]>
Introduce support for mt7921e 802.11ax (Wi-Fi 6) 2x2:2SS chipset.
--- .../net/wireless/mediatek/mt76/mt7921/init.c | 248 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/pci.c | 184 +++++++++++++ 2 files changed, 432 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci.c
drivers/net/wireless/mediatek/mt76/mt7921/init.c new file +248 -0
@@ -0,0 +1,248 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include <linux/etherdevice.h> +#include "mt7921.h" +#include "mac.h" +#include "eeprom.h" + +#define CCK_RATE (_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ +} + +#define OFDM_RATE (_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ +} + +static struct ieee80211_rate mt7921_rates[] = { +CCK_RATE (0 ,10 ), +CCK_RATE (1 ,20 ), +CCK_RATE (2 ,55 ), +CCK_RATE (3 ,110 ), +OFDM_RATE (11 ,60 ), +OFDM_RATE (15 ,90 ), +OFDM_RATE (10 ,120 ), +OFDM_RATE (14 ,180 ), +OFDM_RATE (9 ,240 ), +OFDM_RATE (13 ,360 ), +OFDM_RATE (8 ,480 ), +OFDM_RATE (12 ,540 ), +}; + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max =MT7921_MAX_INTERFACES , + .types =BIT (NL80211_IFTYPE_STATION ) + } +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits =ARRAY_SIZE (if_limits), + .max_interfaces =MT7921_MAX_INTERFACES , + .num_different_channels =1 , + .beacon_int_infra_match = true, + } +}; + +static void +mt7921_init_wiphy (struct ieee80211_hw *hw) +{ +struct mt7921_phy *phy =mt7921_hw_phy (hw); +struct wiphy *wiphy = hw->wiphy; + + hw->queues =4 ; + hw->max_rx_aggregation_subframes =IEEE80211_MAX_AMPDU_BUF ; + hw->max_tx_aggregation_subframes =IEEE80211_MAX_AMPDU_BUF ; + + phy->slottime =9 ; + + hw->sta_data_size =sizeof (struct mt7921_sta ); + hw->vif_data_size =sizeof (struct mt7921_vif ); + + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations =ARRAY_SIZE (if_comb); + wiphy->max_scan_ie_len =MT7921_SCAN_IE_LEN ; + wiphy->max_scan_ssids =4 ; + wiphy->flags |=WIPHY_FLAG_HAS_CHANNEL_SWITCH ; + +wiphy_ext_feature_set (wiphy,NL80211_EXT_FEATURE_SET_SCAN_DWELL ); + +ieee80211_hw_set (hw,SINGLE_SCAN_ON_ALL_BANDS ); +ieee80211_hw_set (hw,HAS_RATE_CONTROL ); +ieee80211_hw_set (hw,SUPPORTS_TX_ENCAP_OFFLOAD ); +ieee80211_hw_set (hw,WANT_MONITOR_VIF ); + + hw->max_tx_fragments =4 ; +} + +static void +mt7921_mac_init_band (struct mt7921_dev *dev,u8 band) +{ +u32 mask, set; + +mt76_rmw_field (dev,MT_TMAC_CTCR0 (band), +MT_TMAC_CTCR0_INS_DDLMT_REFTIME ,0x3f ); +mt76_set (dev,MT_TMAC_CTCR0 (band), +MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | +MT_TMAC_CTCR0_INS_DDLMT_EN ); + + mask =MT_MDP_RCFR0_MCU_RX_MGMT | +MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | +MT_MDP_RCFR0_MCU_RX_CTL_BAR ; + set =FIELD_PREP (MT_MDP_RCFR0_MCU_RX_MGMT ,MT_MDP_TO_HIF ) | +FIELD_PREP (MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR ,MT_MDP_TO_HIF ) | +FIELD_PREP (MT_MDP_RCFR0_MCU_RX_CTL_BAR ,MT_MDP_TO_HIF ); +mt76_rmw (dev,MT_MDP_BNRCFR0 (band), mask, set); + + mask =MT_MDP_RCFR1_MCU_RX_BYPASS | +MT_MDP_RCFR1_RX_DROPPED_UCAST | +MT_MDP_RCFR1_RX_DROPPED_MCAST ; + set =FIELD_PREP (MT_MDP_RCFR1_MCU_RX_BYPASS ,MT_MDP_TO_HIF ) | +FIELD_PREP (MT_MDP_RCFR1_RX_DROPPED_UCAST ,MT_MDP_TO_HIF ) | +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_TIME0 (band),MT_WF_RMAC_MIB_RXTIME_EN ); +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 ); +} + +static void mt7921_mac_init (struct mt7921_dev *dev) +{ +int i; + +mt76_rmw_field (dev,MT_MDP_DCR1 ,MT_MDP_DCR1_MAX_RX_LEN ,1536 ); +/* disable hardware de-agg */ +mt76_clear (dev,MT_MDP_DCR0 ,MT_MDP_DCR0_DAMSDU_EN ); +mt76_clear (dev,MT_MDP_DCR0 ,MT_MDP_DCR0_RX_HDR_TRANS_EN ); + +for (i =0 ; i <MT7921_WTBL_SIZE ; i++) +mt7921_mac_wtbl_update (dev, i, +MT_WTBL_UPDATE_ADM_COUNT_CLEAR ); +for (i =0 ; i <2 ; i++) +mt7921_mac_init_band (dev, i); + +mt7921_mcu_set_rts_thresh (&dev->phy,0x92b ); +} + +static void mt7921_init_work (struct work_struct *work) +{ + struct mt7921_dev *dev = container_of(work, struct mt7921_dev, + init_work); + +mt7921_mcu_set_eeprom (dev); +mt7921_mac_init (dev); +} + +static int mt7921_init_hardware (struct mt7921_dev *dev) +{ +int ret, idx; + +INIT_WORK (&dev->init_work, mt7921_init_work); +spin_lock_init (&dev->token_lock); +idr_init (&dev->token); + + ret =mt7921_dma_init (dev); +if (ret) +return ret; + +set_bit (MT76_STATE_INITIALIZED , &dev->mphy.state); + +/* 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; + + ret =mt7921_eeprom_init (dev); +if (ret <0 ) +return ret; + +/* Beacon and mgmt frames should occupy wcid 0 */ + idx =mt76_wcid_alloc (dev->mt76.wcid_mask,MT7921_WTBL_STA -1 ); +if (idx) +return -ENOSPC ; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx =-1 ; + dev->mt76.global_wcid.tx_info |=MT_WCID_TX_INFO_SET ; +rcu_assign_pointer (dev->mt76.wcid[idx], &dev->mt76.global_wcid); + +return 0 ; +} + +int mt7921_register_device (struct mt7921_dev *dev) +{ +struct ieee80211_hw *hw =mt76_hw (dev); +int ret; + + dev->phy.dev = dev; + dev->phy.mt76 = &dev->mt76.phy; + dev->mt76.phy.priv = &dev->phy; +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); +skb_queue_head_init (&dev->phy.scan_event_list); +INIT_LIST_HEAD (&dev->sta_poll_list); +spin_lock_init (&dev->sta_poll_lock); + +init_waitqueue_head (&dev->reset_wait); +INIT_WORK (&dev->reset_work, mt7921_mac_reset_work); + + ret =mt7921_init_hardware (dev); +if (ret) +return ret; + +mt7921_init_wiphy (hw); + dev->mphy.sband_2g.sband.ht_cap.cap |= +IEEE80211_HT_CAP_LDPC_CODING | +IEEE80211_HT_CAP_MAX_AMSDU ; + dev->mphy.sband_5g.sband.ht_cap.cap |= +IEEE80211_HT_CAP_LDPC_CODING | +IEEE80211_HT_CAP_MAX_AMSDU ; + dev->mphy.sband_5g.sband.vht_cap.cap |= +IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | +IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK ; + dev->mphy.sband_5g.sband.vht_cap.cap |= +IEEE80211_VHT_CAP_SHORT_GI_160 | +IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ; + dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; + +mt76_set_stream_caps (&dev->mphy, true); +mt7921_set_stream_he_caps (&dev->phy); + + ret =mt76_register_device (&dev->mt76, true, mt7921_rates, +ARRAY_SIZE (mt7921_rates)); +if (ret) +return ret; + +ieee80211_queue_work (mt76_hw (dev), &dev->init_work); + +return 0 ; +} + +void mt7921_unregister_device (struct mt7921_dev *dev) +{ +mt76_unregister_device (&dev->mt76); +mt7921_mcu_exit (dev); +mt7921_dma_cleanup (dev); + +mt7921_tx_token_put (dev); + +tasklet_disable (&dev->irq_tasklet); +mt76_free_device (&dev->mt76); +}
drivers/net/wireless/mediatek/mt76/mt7921/pci.c new file +184 -0
184 lines not on this page · raw message
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 7/22 mt76: mt7921: add debugfs support
In reply to [email protected]From: Sean Wang <[email protected]>
Add debugfs support to dump driver statistics and hardware details.
--- .../wireless/mediatek/mt76/mt7921/debugfs.c | 178 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/init.c | 2 +- 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c new file +178 -0
@@ -0,0 +1,178 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7921.h" +#include "eeprom.h" + +static int +mt7921_fw_debug_set (void *data,u64 val) +{ +struct mt7921_dev *dev = data; + + dev->fw_debug = (u8 )val; + +mt7921_mcu_fw_log_2_host (dev, dev->fw_debug); + +return 0 ; +} + +static int +mt7921_fw_debug_get (void *data,u64 *val) +{ +struct mt7921_dev *dev = data; + + *val = dev->fw_debug; + +return 0 ; +} + +DEFINE_DEBUGFS_ATTRIBUTE (fops_fw_debug, mt7921_fw_debug_get, + mt7921_fw_debug_set,"%lld\n" ); + +static void +mt7921_ampdu_stat_read_phy (struct mt7921_phy *phy, +struct seq_file *file) +{ +struct mt7921_dev *dev = file->private; +int bound[15 ], range[4 ], i; + +if (!phy) +return ; + +/* Tx ampdu stat */ +for (i =0 ; i <ARRAY_SIZE (range); i++) + range[i] =mt76_rr (dev,MT_MIB_ARNG (0 , i)); + +for (i =0 ; i <ARRAY_SIZE (bound); i++) + bound[i] =MT_MIB_ARNCR_RANGE (range[i /4 ], i) +1 ; + +seq_printf (file,"\nPhy0\n" ); + +seq_printf (file,"Length: %8d | " , bound[0 ]); +for (i =0 ; i <ARRAY_SIZE (bound) -1 ; i++) +seq_printf (file,"%3d -%3d | " , + bound[i] +1 , bound[i +1 ]); + +seq_puts (file,"\nCount: " ); +for (i =0 ; i <ARRAY_SIZE (bound); i++) +seq_printf (file,"%8d | " , dev->mt76.aggr_stats[i]); +seq_puts (file,"\n" ); + +seq_printf (file,"BA miss count: %d\n" , phy->mib.ba_miss_cnt); +} + +static int +mt7921_tx_stats_read (struct seq_file *file,void *data) +{ +struct mt7921_dev *dev = file->private; +int stat[8 ], i, n; + +mt7921_ampdu_stat_read_phy (&dev->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]; + } + +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); +else +seq_puts (file,"\n" ); + } + +return 0 ; +} + +static int +mt7921_tx_stats_open (struct inode *inode,struct file *f) +{ +return single_open (f, mt7921_tx_stats_read, inode->i_private); +} + +static const struct file_operations fops_tx_stats = { + .open = mt7921_tx_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner =THIS_MODULE , +}; + +static int +mt7921_queues_acq (struct seq_file *s,void *data) +{ +struct mt7921_dev *dev =dev_get_drvdata (s->private); +int i; + +for (i =0 ; i <16 ; i++) { +int j, acs = i /4 , index = i %4 ; +u32 ctrl, val, qlen =0 ; + + val =mt76_rr (dev,MT_PLE_AC_QEMPTY (acs, index)); + ctrl =BIT (31 ) |BIT (15 ) | (acs <<8 ); + +for (j =0 ; j <32 ; j++) { +if (val &BIT (j)) +continue ; + +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); + } + +return 0 ; +} + +static int +mt7921_queues_read (struct seq_file *s,void *data) +{ +struct mt7921_dev *dev =dev_get_drvdata (s->private); +struct { +struct mt76_queue *q; +char *queue; + } queue_map[] = { + { dev->mphy.q_tx[MT_TXQ_BE ],"WFDMA0" }, + { dev->mt76.q_mcu[MT_MCUQ_WM ],"MCUWM" }, + { dev->mt76.q_mcu[MT_MCUQ_FWDL ],"MCUFWQ" }, + }; +int i; + +for (i =0 ; i <ARRAY_SIZE (queue_map); i++) { +struct mt76_queue *q = queue_map[i].q; + +if (!q) +continue ; + +seq_printf (s, +"%s: queued=%d head=%d tail=%d\n" , + queue_map[i].queue, q->queued, q->head, + q->tail); + } + +return 0 ; +} + +int mt7921_init_debugfs (struct mt7921_dev *dev) +{ +struct dentry *dir; + + dir =mt76_register_debugfs (&dev->mt76); +if (!dir) +return -ENOMEM ; + +debugfs_create_devm_seqfile (dev->mt76.dev,"queues" , dir, + mt7921_queues_read); +debugfs_create_devm_seqfile (dev->mt76.dev,"acq" , dir, + mt7921_queues_acq); +debugfs_create_file ("tx_stats" ,0400 , dir, dev, &fops_tx_stats); +debugfs_create_file ("fw_debug" ,0600 , dir, dev, &fops_fw_debug); + +return 0 ; +}
drivers/net/wireless/mediatek/mt76/mt7921/init.c +1 -1
@@ -232,7 +232,7 @@ int mt7921_register_device(struct mt7921_dev *dev)ieee80211_queue_work (mt76_hw (dev), &dev->init_work); -return 0 ; +return mt7921_init_debugfs (dev); }void mt7921_unregister_device (struct mt7921_dev *dev)
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 8/22 mt76: mt7921: add module support
In reply to [email protected]From: Sean Wang <[email protected]>
Add mt7921 as the pci driver module.
The purpose of the patch is to check about if the following patches are able to compile properly.
--- drivers/net/wireless/mediatek/mt76/Kconfig | 1 + drivers/net/wireless/mediatek/mt76/Makefile | 1 + drivers/net/wireless/mediatek/mt76/mt7921/Kconfig | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 5 +++++ 4 files changed, 17 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/Makefile
drivers/net/wireless/mediatek/mt76/Kconfig +1 -0
@@ -33,3 +33,4 @@ source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig" +source "drivers/net/wireless/mediatek/mt76/mt7921/Kconfig"
drivers/net/wireless/mediatek/mt76/Makefile +1 -0
@@ -34,3 +34,4 @@ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ obj-$(CONFIG_MT7603E) += mt7603/ obj-$(CONFIG_MT7615_COMMON) += mt7615/ obj-$(CONFIG_MT7915E) += mt7915/ +obj-$(CONFIG_MT7921E) += mt7921/
drivers/net/wireless/mediatek/mt76/mt7921/Kconfig new file +10 -0
@@ -0,0 +1,10 @@ +# SPDX-License-Identifier: ISC +config MT7921E + tristate "MediaTek MT7921E (PCIe) support" + select MT76_CORE + depends on MAC80211 + depends on PCI + help + This adds support for MT7921E 802.11ax 2x2:2SS wireless devices. + + To compile this driver as a module, choose M here.
drivers/net/wireless/mediatek/mt76/mt7921/Makefile new file +5 -0
@@ -0,0 +1,5 @@ +#SPDX-License-Identifier: ISC + +obj-$(CONFIG_MT7921E) += mt7921e.o + +mt7921e-y := pci.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o
Signature · 1 line
2.25.1
Ryder Lee
maintainerRe: [PATCH -next v7 08/22] mt76: mt7921: add module support
Quoted 61 lines · On Sat, 2021-01-23 at 16:34 +0800, [email protected] wrote:
From: Sean Wang <[email protected]>
Add mt7921 as the pci driver module.
The purpose of the patch is to check about if the following patches are able to compile properly.
Co-developed-by Lorenzo Bianconi <[email protected]>Signed-off-by Lorenzo Bianconi <[email protected]>Co-developed-by Soul Huang <[email protected]>Signed-off-by Soul Huang <[email protected]>Signed-off-by Sean Wang <[email protected]>--- drivers/net/wireless/mediatek/mt76/Kconfig | 1 + drivers/net/wireless/mediatek/mt76/Makefile | 1 + drivers/net/wireless/mediatek/mt76/mt7921/Kconfig | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 5 +++++ 4 files changed, 17 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/Makefiledrivers/net/wireless/mediatek/mt76/Kconfig +1
-0@@ -33,3 +33,4 @@ source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig" +source "drivers/net/wireless/mediatek/mt76/mt7921/Kconfig"drivers/net/wireless/mediatek/mt76/Makefile +1
-0@@ -34,3 +34,4 @@ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ obj-$(CONFIG_MT7603E) += mt7603/ obj-$(CONFIG_MT7615_COMMON) += mt7615/ obj-$(CONFIG_MT7915E) += mt7915/ +obj-$(CONFIG_MT7921E) += mt7921/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig new file +10
-0@@ -0,0 +1,10 @@ +# SPDX-License-Identifier: ISC +config MT7921E + tristate "MediaTek MT7921E (PCIe) support" + select MT76_CORE + depends on MAC80211 + depends on PCI + help + This adds support for MT7921E 802.11ax 2x2:2SS wireless devices. + + To compile this driver as a module, choose M here.drivers/net/wireless/mediatek/mt76/mt7921/Makefile new file +0
-0
drivers/net/wireless/mediatek/mt76/mt7921/Makefile line 5
Quoted 5 lines
drivers/net/wireless/mediatek/mt76/mt7921/Makefile new file +5
-0@@ -0,0 +1,5 @@ +#SPDX-License-Identifier: ISC + +obj-$(CONFIG_MT7921E) += mt7921e.o + +mt7921e-y := pci.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o
I think it's more reasonable to move this into 'mt76: mt7921: introduce mt7921e support' to make it complete.
Ryder
_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek
[email protected]
reviewerPATCH v7 9/22 mt76: mt7921: introduce schedule scan support
In reply to [email protected]From: Sean Wang <[email protected]>
introduce schedule scan to control mt7921 firmware to do background scan in defined plan to see if the matched SSID is available.
--- .../net/wireless/mediatek/mt76/mt7921/init.c | 5 ++ .../net/wireless/mediatek/mt76/mt7921/main.c | 38 +++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 83 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 20 +++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 9 ++ 5 files changed, 155 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +5 -0
@@ -70,6 +70,11 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) wiphy->n_iface_combinations =ARRAY_SIZE (if_comb); wiphy->max_scan_ie_len =MT7921_SCAN_IE_LEN ; wiphy->max_scan_ssids =4 ; + wiphy->max_sched_scan_plan_interval =MT7921_MAX_SCHED_SCAN_INTERVAL ; + wiphy->max_sched_scan_ie_len =IEEE80211_MAX_DATA_LEN ; + wiphy->max_sched_scan_ssids =MT7921_MAX_SCHED_SCAN_SSID ; + wiphy->max_match_sets =MT7921_MAX_SCAN_MATCH ; + wiphy->max_sched_scan_reqs =1 ; wiphy->flags |=WIPHY_FLAG_HAS_CHANNEL_SWITCH ;wiphy_ext_feature_set (wiphy,NL80211_EXT_FEATURE_SET_SCAN_DWELL );
drivers/net/wireless/mediatek/mt76/mt7921/main.c +38 -0
@@ -868,6 +868,42 @@ mt7921_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)mutex_unlock (&dev->mt76.mutex); } +static int +mt7921_start_sched_scan (struct ieee80211_hw *hw,struct ieee80211_vif *vif, +struct cfg80211_sched_scan_request *req, +struct ieee80211_scan_ies *ies) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt76_phy *mphy = hw->priv; +int err; + +mutex_lock (&dev->mt76.mutex); + + err =mt7921_mcu_sched_scan_req (mphy->priv, vif, req); +if (err <0 ) + goto out; + + err =mt7921_mcu_sched_scan_enable (mphy->priv, vif, true); +out: +mutex_unlock (&dev->mt76.mutex); + +return err; +} + +static int +mt7921_stop_sched_scan (struct ieee80211_hw *hw,struct ieee80211_vif *vif) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt76_phy *mphy = hw->priv; +int err; + +mutex_lock (&dev->mt76.mutex); + err =mt7921_mcu_sched_scan_enable (mphy->priv, vif, false); +mutex_unlock (&dev->mt76.mutex); + +return err; +} +static int mt7921_set_antenna (struct ieee80211_hw *hw,u32 tx_ant,u32 rx_ant) {
@@ -931,4 +967,6 @@ const struct ieee80211_ops mt7921_ops = { .set_coverage_class = mt7921_set_coverage_class, .hw_scan = mt7921_hw_scan, .cancel_hw_scan = mt7921_cancel_hw_scan, + .sched_scan_start = mt7921_start_sched_scan, + .sched_scan_stop = mt7921_stop_sched_scan, };
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +83 -0
89 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +20 -0
@@ -879,6 +879,26 @@ struct mt7921_hw_scan_done {__le32 beacon_5g_num; } __packed; +struct mt7921_sched_scan_req { +u8 version; +u8 seq_num; +u8 stop_on_match; +u8 ssids_num; +u8 match_num; +u8 pad; +__le16 ie_len; +struct mt7921_mcu_scan_ssid ssids[MT7921_MAX_SCHED_SCAN_SSID ]; +struct mt7921_mcu_scan_match match[MT7921_MAX_SCAN_MATCH ]; +u8 channel_type; +u8 channels_num; +u8 intervals_num; +u8 scan_func; +struct mt7921_mcu_scan_channel channels[64 ]; +__le16 intervals[MT7921_MAX_SCHED_SCAN_INTERVAL ]; +u8 bss_idx; +u8 pad2[64 ]; +} __packed; +struct mt7921_mcu_bss_event {u8 bss_idx;u8 is_absent;
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +9 -0
@@ -44,6 +44,9 @@#define MT7921_SKU_TABLE_SIZE (MT7921_SKU_RATE_NUM + 1)#define MT7921_SCAN_IE_LEN 600 +#define MT7921_MAX_SCHED_SCAN_INTERVAL 10 +#define MT7921_MAX_SCHED_SCAN_SSID 10 +#define MT7921_MAX_SCAN_MATCH 16struct mt7921_vif ;struct mt7921_sta ;
@@ -343,6 +346,12 @@ void mt7921_scan_work(struct work_struct *work);int mt7921_mcu_set_channel_domain (struct mt7921_phy *phy);int mt7921_mcu_hw_scan (struct mt7921_phy *phy,struct ieee80211_vif *vif,struct ieee80211_scan_request *scan_req); +int mt7921_mcu_sched_scan_req (struct mt7921_phy *phy, +struct ieee80211_vif *vif, +struct cfg80211_sched_scan_request *sreq); +int mt7921_mcu_sched_scan_enable (struct mt7921_phy *phy, +struct ieee80211_vif *vif, +bool enable);int mt7921_mcu_cancel_hw_scan (struct mt7921_phy *phy,struct ieee80211_vif *vif);u32 mt7921_get_wtbl_info (struct mt7921_dev *dev,u16 wlan_idx);
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 10/22 mt76: mt7921: introduce 802.11 PS support in sta mode
In reply to [email protected]From: Sean Wang <[email protected]>
Enable 802.11 power-save support available in mt7921 firmware
--- .../net/wireless/mediatek/mt76/mt7921/init.c | 2 + .../net/wireless/mediatek/mt76/mt7921/mac.c | 3 +- .../net/wireless/mediatek/mt76/mt7921/main.c | 3 ++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 37 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 2 +- .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 6 files changed, 45 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +2 -0
@@ -83,6 +83,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)ieee80211_hw_set (hw,HAS_RATE_CONTROL );ieee80211_hw_set (hw,SUPPORTS_TX_ENCAP_OFFLOAD );ieee80211_hw_set (hw,WANT_MONITOR_VIF ); +ieee80211_hw_set (hw,SUPPORTS_PS ); +ieee80211_hw_set (hw,SUPPORTS_DYNAMIC_PS ); hw->max_tx_fragments =4 ; }
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +1 -2
@@ -690,8 +690,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[1 ] =cpu_to_le32 (val); txwi[2 ] =0 ; - val =MT_TXD3_SW_POWER_MGMT | -FIELD_PREP (MT_TXD3_REM_TX_COUNT , tx_count); + val =FIELD_PREP (MT_TXD3_REM_TX_COUNT , tx_count);if (key) val |=MT_TXD3_PROTECT_FRAME ;if (info->flags &IEEE80211_TX_CTL_NO_ACK )
drivers/net/wireless/mediatek/mt76/mt7921/main.c +3 -0
@@ -561,6 +561,9 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,if (changed & (BSS_CHANGED_QOS |BSS_CHANGED_BEACON_ENABLED ))mt7921_mcu_set_tx (dev, vif); +if (changed &BSS_CHANGED_PS ) +mt7921_mcu_uni_bss_ps (dev, vif); +mutex_unlock (&dev->mt76.mutex); }
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +37 -0
@@ -2463,3 +2463,40 @@ u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u16 wlan_idx)return 0 ; } + +int mt7921_mcu_uni_bss_ps (struct mt7921_dev *dev,struct ieee80211_vif *vif) +{ +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +struct { +struct { +u8 bss_idx; +u8 pad[3 ]; + } __packed hdr; +struct ps_tlv { +__le16 tag; +__le16 len; +u8 ps_state;/* 0: device awake +* 1: static power save +* 2: dynamic power saving +* 3: enter TWT power saving +* 4: leave TWT power saving +*/ +u8 pad[3 ]; + } __packed ps; + } __packed ps_req = { + .hdr = { + .bss_idx = mvif->mt76.idx, + }, + .ps = { + .tag =cpu_to_le16 (UNI_BSS_INFO_PS ), + .len =cpu_to_le16 (sizeof (struct ps_tlv )), + .ps_state = vif->bss_conf.ps ?2 :0 , + }, + }; + +if (vif->type !=NL80211_IFTYPE_STATION ) +return -EOPNOTSUPP ; + +return mt76_mcu_send_msg (&dev->mt76,MCU_UNI_CMD_BSS_INFO_UPDATE , + &ps_req,sizeof (ps_req), true); +}
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +1 -1
@@ -185,7 +185,6 @@ struct mt7921_mcu_uni_event {/* offload mcu commands */ enum {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 ,MCU_CMD_SET_BSS_CONNECTED =MCU_CE_PREFIX |0x16 ,MCU_CMD_SET_BSS_ABORT =MCU_CE_PREFIX |0x17 ,
@@ -211,6 +210,7 @@ enum {UNI_BSS_INFO_BCN_CONTENT =7 ,UNI_BSS_INFO_QBSS =15 ,UNI_BSS_INFO_UAPSD =19 , + UNI_BSS_INFO_PS = 21, }; enum {
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +1 -0
@@ -355,4 +355,5 @@ int mt7921_mcu_sched_scan_enable(struct mt7921_phy *phy,int mt7921_mcu_cancel_hw_scan (struct mt7921_phy *phy,struct ieee80211_vif *vif);u32 mt7921_get_wtbl_info (struct mt7921_dev *dev,u16 wlan_idx); +int mt7921_mcu_uni_bss_ps (struct mt7921_dev *dev,struct ieee80211_vif *vif);#endif
Signature · 5 lines
2.25.1 _______________________________________________ Linux-mediatek mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-mediatek
[email protected]
reviewerPATCH v7 11/22 mt76: mt7921: introduce support for hardware beacon filter
In reply to [email protected]From: Sean Wang <[email protected]>
Introduce support for hw beacon filter available in the mt7921 firmware.
According to mt7921e firmware, enabling hardware filter would rely on mt7921_mcu_uni_bss_bcnft and disabling hardware filter still rely on legacy mt7921_mcu_set_bss_pm.
--- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 75 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 1 + .../wireless/mediatek/mt76/mt7921/mt7921.h | 4 + 3 files changed, 80 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +75 -0
@@ -2500,3 +2500,78 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)return mt76_mcu_send_msg (&dev->mt76,MCU_UNI_CMD_BSS_INFO_UPDATE , &ps_req,sizeof (ps_req), true); } + +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 { +struct { +u8 bss_idx; +u8 pad[3 ]; + } __packed hdr; +struct bcnft_tlv { +__le16 tag; +__le16 len; +__le16 bcn_interval; +u8 dtim_period; +u8 pad; + } __packed bcnft; + } __packed bcnft_req = { + .hdr = { + .bss_idx = mvif->mt76.idx, + }, + .bcnft = { + .tag =cpu_to_le16 (UNI_BSS_INFO_BCNFT ), + .len =cpu_to_le16 (sizeof (struct bcnft_tlv )), + .bcn_interval =cpu_to_le16 (vif->bss_conf.beacon_int), + .dtim_period = vif->bss_conf.dtim_period, + }, + }; + +if (vif->type !=NL80211_IFTYPE_STATION ) +return 0 ; + +return mt76_mcu_send_msg (&dev->mt76,MCU_UNI_CMD_BSS_INFO_UPDATE , + &bcnft_req,sizeof (bcnft_req), true); +} + +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 { +u8 bss_idx; +u8 dtim_period; +__le16 aid; +__le16 bcn_interval; +__le16 atim_window; +u8 uapsd; +u8 bmc_delivered_ac; +u8 bmc_triggered_ac; +u8 pad; + } req = { + .bss_idx = mvif->mt76.idx, + .aid =cpu_to_le16 (vif->bss_conf.aid), + .dtim_period = vif->bss_conf.dtim_period, + .bcn_interval =cpu_to_le16 (vif->bss_conf.beacon_int), + }; +struct { +u8 bss_idx; +u8 pad[3 ]; + } req_hdr = { + .bss_idx = mvif->mt76.idx, + }; +int err; + +if (vif->type !=NL80211_IFTYPE_STATION ) +return 0 ; + + err =mt76_mcu_send_msg (&dev->mt76,MCU_CMD_SET_BSS_ABORT , &req_hdr, +sizeof (req_hdr), false); +if (err <0 || !enable) +return err; + +return mt76_mcu_send_msg (&dev->mt76,MCU_CMD_SET_BSS_CONNECTED , &req, +sizeof (req), false); +}
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +1 -0
@@ -211,6 +211,7 @@ enum {UNI_BSS_INFO_QBSS =15 ,UNI_BSS_INFO_UAPSD =19 ,UNI_BSS_INFO_PS =21 , + UNI_BSS_INFO_BCNFT = 22, }; enum {
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +4 -0
@@ -356,4 +356,8 @@ int mt7921_mcu_cancel_hw_scan(struct mt7921_phy *phy, struct ieee80211_vif *vif);u32 mt7921_get_wtbl_info (struct mt7921_dev *dev,u16 wlan_idx);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);#endif
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 12/22 mt76: mt7921: introduce beacon_loss mcu event
In reply to [email protected]From: Sean Wang <[email protected]>
If device has enabled beacon hw filter rx beacons are not reported to the host. Introduce beacon_loss mcu event to trigger mac80211 mlme connection state machine in this configuration. IEEE80211_VIF_BEACON_FILTER has not set in vif flags since hw beacon filter is not enabled yet
--- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 35 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 6 ++++ 2 files changed, 41 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +35 -0
@@ -543,6 +543,40 @@ mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) MT7921_HW_SCAN_TIMEOUT); } +static void +mt7921_mcu_beacon_loss_iter (void *priv,u8 *mac,struct ieee80211_vif *vif) +{ +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +struct mt7921_beacon_loss_event *event = priv; + +if (mvif->mt76.idx != event->bss_idx) +return ; + +if (!(vif->driver_flags &IEEE80211_VIF_BEACON_FILTER )) +return ; + +ieee80211_beacon_loss (vif); +} + +static void +mt7921_mcu_beacon_loss_event (struct mt7921_dev *dev,struct sk_buff *skb) +{ +struct mt7921_beacon_loss_event *event; +struct mt76_phy *mphy; +u8 band_idx =0 ;/* DBDC support */ + +skb_pull (skb,sizeof (struct mt7921_mcu_rxd )); + event = (struct mt7921_beacon_loss_event *)skb->data; +if (band_idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; +else + mphy = &dev->mt76.phy; + +ieee80211_iterate_active_interfaces_atomic (mphy->hw, +IEEE80211_IFACE_ITER_RESUME_ALL , + mt7921_mcu_beacon_loss_iter, event); +} +static void mt7921_mcu_bss_event (struct mt7921_dev *dev,struct sk_buff *skb) {
@@ -593,6 +627,7 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)switch (rxd->eid) {case MCU_EVENT_BSS_BEACON_LOSS : +mt7921_mcu_beacon_loss_event (dev, skb);break ;case MCU_EVENT_SCHED_SCAN_DONE :case MCU_EVENT_SCAN_DONE :
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +6 -0
@@ -784,6 +784,12 @@ struct mt7921_bss_qos_tlv {u8 pad[3 ]; } __packed; +struct mt7921_beacon_loss_event { +u8 bss_idx; +u8 reason; +u8 pad[2 ]; +} __packed; +struct mt7921_mcu_scan_ssid {__le32 ssid_len;u8 ssid[IEEE80211_MAX_SSID_LEN ];
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 13/22 mt76: mt7921: introduce PM support
In reply to [email protected]From: Sean Wang <[email protected]>
Introduce suspend/resume and WoW (Wake-on-WoWLAN) support to mt7921 driver to allow remote wakeu-up from the suspend state.
--- .../net/wireless/mediatek/mt76/mt7921/main.c | 79 +++++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 307 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 99 ++++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 9 + .../net/wireless/mediatek/mt76/mt7921/pci.c | 95 ++++++ 5 files changed, 589 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +79 -0
@@ -941,6 +941,79 @@ mt7921_sta_rc_update(struct ieee80211_hw *hw, { } +#ifdef CONFIG_PM +static int mt7921_suspend (struct ieee80211_hw *hw, +struct cfg80211_wowlan *wowlan) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +int err; + +cancel_delayed_work_sync (&phy->scan_work); +cancel_delayed_work_sync (&phy->mt76->mac_work); + +mutex_lock (&dev->mt76.mutex); + +clear_bit (MT76_STATE_RUNNING , &phy->mt76->state); + +set_bit (MT76_STATE_SUSPEND , &phy->mt76->state); +ieee80211_iterate_active_interfaces (hw, +IEEE80211_IFACE_ITER_RESUME_ALL , + mt7921_mcu_set_suspend_iter, phy); + + err =mt7921_mcu_set_hif_suspend (dev, true); + +mutex_unlock (&dev->mt76.mutex); + +return err; +} + +static int mt7921_resume (struct ieee80211_hw *hw) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt7921_phy *phy =mt7921_hw_phy (hw); +int err; + +mutex_lock (&dev->mt76.mutex); + + err =mt7921_mcu_set_hif_suspend (dev, false); +if (err <0 ) + goto out; + +set_bit (MT76_STATE_RUNNING , &phy->mt76->state); +clear_bit (MT76_STATE_SUSPEND , &phy->mt76->state); +ieee80211_iterate_active_interfaces (hw, +IEEE80211_IFACE_ITER_RESUME_ALL , + mt7921_mcu_set_suspend_iter, phy); + +ieee80211_queue_delayed_work (hw, &phy->mt76->mac_work, +MT7921_WATCHDOG_TIME ); +out: +mutex_unlock (&dev->mt76.mutex); + +return err; +} + +static void mt7921_set_wakeup (struct ieee80211_hw *hw,bool enabled) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); +struct mt76_dev *mdev = &dev->mt76; + +device_set_wakeup_enable (mdev->dev, enabled); +} + +static void mt7921_set_rekey_data (struct ieee80211_hw *hw, +struct ieee80211_vif *vif, +struct cfg80211_gtk_rekey_data *data) +{ +struct mt7921_dev *dev =mt7921_hw_dev (hw); + +mutex_lock (&dev->mt76.mutex); +mt7921_mcu_update_gtk_rekey (hw, vif, data); +mutex_unlock (&dev->mt76.mutex); +} +#endif /* CONFIG_PM */ +const struct ieee80211_ops mt7921_ops = { .tx = mt7921_tx, .start = mt7921_start,
@@ -972,4 +1045,10 @@ const struct ieee80211_ops mt7921_ops = { .cancel_hw_scan = mt7921_cancel_hw_scan, .sched_scan_start = mt7921_start_sched_scan, .sched_scan_stop = mt7921_stop_sched_scan, +#ifdef CONFIG_PM + .suspend = mt7921_suspend, + .resume = mt7921_resume, + .set_wakeup = mt7921_set_wakeup, + .set_rekey_data = mt7921_set_rekey_data, +#endif /* CONFIG_PM */ };
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +307 -0
322 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +99 -0
105 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +9 -0
@@ -360,4 +360,13 @@ 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_set_hif_suspend (struct mt7921_dev *dev,bool suspend); +void mt7921_mcu_set_suspend_iter (void *priv,u8 *mac, +struct ieee80211_vif *vif); +int mt7921_mcu_update_gtk_rekey (struct ieee80211_hw *hw, +struct ieee80211_vif *vif, +struct cfg80211_gtk_rekey_data *key); +int mt7921_mcu_update_arp_filter (struct ieee80211_hw *hw, +struct ieee80211_vif *vif, +struct ieee80211_bss_conf *info);#endif
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +95 -0
106 lines not on this page · raw message
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 14/22 mt76: mt7921: rely on mt76_connac_mcu common library
In reply to [email protected]From: Lorenzo Bianconi <[email protected]>
Rely on mt76_connac_mcu common library and remove duplicated code
--- .../net/wireless/mediatek/mt76/mt76_connac.h | 5 + .../wireless/mediatek/mt76/mt76_connac_mcu.c | 336 ++++- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 21 + .../net/wireless/mediatek/mt76/mt7921/Kconfig | 2 +- .../net/wireless/mediatek/mt76/mt7921/init.c | 3 +- .../net/wireless/mediatek/mt76/mt7921/main.c | 34 +- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 1246 +---------------- .../net/wireless/mediatek/mt76/mt7921/mcu.h | 538 +------ .../wireless/mediatek/mt76/mt7921/mt7921.h | 36 +- .../net/wireless/mediatek/mt76/mt7921/pci.c | 1 + 10 files changed, 411 insertions(+), 1811 deletions(-)
drivers/net/wireless/mediatek/mt76/mt76_connac.h +5 -0
@@ -59,6 +59,11 @@ struct mt76_connac_pm {extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; +static inline bool is_mt7921 (struct mt76_dev *dev) +{ +return mt76_chip (dev) ==0x7961 ; +} +int mt76_connac_pm_wake (struct mt76_phy *phy,struct mt76_connac_pm *pm);void mt76_connac_power_save_sched (struct mt76_phy *phy,struct mt76_connac_pm *pm);
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +327 -9
428 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +21 -0
@@ -561,6 +561,8 @@ enum {MCU_CMD_SCHED_SCAN_REQ =MCU_CE_PREFIX |0x62 ,MCU_CMD_REG_WRITE =MCU_CE_PREFIX |0xc0 ,MCU_CMD_REG_READ =MCU_CE_PREFIX |MCU_QUERY_MASK |0xc0 , +MCU_CMD_FWLOG_2_HOST =MCU_CE_PREFIX |0xc5 , + MCU_CMD_GET_WTBL = MCU_CE_PREFIX | 0xcd, }; enum {
@@ -575,6 +577,8 @@ enum {UNI_BSS_INFO_BCN_CONTENT =7 ,UNI_BSS_INFO_QBSS =15 ,UNI_BSS_INFO_UAPSD =19 , +UNI_BSS_INFO_PS =21 , + UNI_BSS_INFO_BCNFT = 22, }; enum {
@@ -871,6 +875,23 @@ struct mt76_connac_suspend_tlv {u8 pad[5 ]; } __packed; +#define to_wcid_lo (id) FIELD_GET(GENMASK(7, 0), (u16)id) +#define to_wcid_hi (id) FIELD_GET(GENMASK(9, 8), (u16)id) + +static inline void +mt76_connac_mcu_get_wlan_idx (struct mt76_dev *dev,struct mt76_wcid *wcid, +u8 *wlan_idx_lo,u8 *wlan_idx_hi) +{ + *wlan_idx_hi =0 ; + +if (is_mt7921 (dev)) { + *wlan_idx_lo = wcid ?to_wcid_lo (wcid->idx) :0 ; + *wlan_idx_hi = wcid ?to_wcid_hi (wcid->idx) :0 ; + }else { + *wlan_idx_lo = wcid ? wcid->idx :0 ; + } +} +struct sk_buff *mt76_connac_mcu_alloc_sta_req (struct mt76_dev *dev,struct mt76_vif *mvif,struct mt76_wcid *wcid);
drivers/net/wireless/mediatek/mt76/mt7921/Kconfig +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: ISC config MT7921E tristate "MediaTek MT7921E (PCIe) support" - select MT76_CORE + select MT76_CONNAC_LIB depends on MAC80211 depends on PCI help
drivers/net/wireless/mediatek/mt76/mt7921/init.c +2 -1
@@ -4,6 +4,7 @@#include <linux/etherdevice.h> #include "mt7921.h" #include "mac.h" +#include "mcu.h" #include "eeprom.h" #define CCK_RATE (_idx, _rate) { \
@@ -139,7 +140,7 @@ static void mt7921_mac_init(struct mt7921_dev *dev)for (i =0 ; i <2 ; i++)mt7921_mac_init_band (dev, i); -mt7921_mcu_set_rts_thresh (&dev->phy,0x92b ); +mt76_connac_mcu_set_rts_thresh (&dev->mt76,0x92b ,0 ); }static void mt7921_init_work (struct work_struct *work)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +22 -12
@@ -176,8 +176,9 @@ static int mt7921_start(struct ieee80211_hw *hw)mutex_lock (&dev->mt76.mutex); -mt7921_mcu_set_mac (dev,0 , true, false); -mt7921_mcu_set_channel_domain (phy); +mt76_connac_mcu_set_mac_enable (&dev->mt76,0 , true, false); +mt76_connac_mcu_set_channel_domain (phy->mt76); +mt7921_mcu_set_chan_info (phy,MCU_EXT_CMD_SET_RX_PATH );mt7921_mac_reset_counters (phy);set_bit (MT76_STATE_RUNNING , &phy->mt76->state);
@@ -199,7 +200,7 @@ static void mt7921_stop(struct ieee80211_hw *hw)mutex_lock (&dev->mt76.mutex);clear_bit (MT76_STATE_RUNNING , &phy->mt76->state); -mt7921_mcu_set_mac (dev,0 , false, false); +mt76_connac_mcu_set_mac_enable (&dev->mt76,0 , false, false);mutex_unlock (&dev->mt76.mutex); }
@@ -285,7 +286,8 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, mvif->mt76.band_idx =0 ; mvif->mt76.wmm_idx = mvif->mt76.idx %MT7921_MAX_WMM_SETS ; - ret =mt7921_mcu_uni_add_dev (dev, vif, true); + ret =mt76_connac_mcu_uni_add_dev (&dev->mphy, vif, &mvif->sta.wcid, + true);if (ret) goto out;
@@ -333,7 +335,7 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,if (vif == phy->monitor_vif) phy->monitor_vif =NULL ; -mt7921_mcu_uni_add_dev (dev, vif, false); +mt76_connac_mcu_uni_add_dev (&dev->mphy, vif, &mvif->sta.wcid, false);rcu_assign_pointer (dev->mt76.wcid[idx],NULL );
@@ -589,11 +591,14 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->stats.jiffies = jiffies;if (vif->type ==NL80211_IFTYPE_STATION && !sta->tdls) -mt7921_mcu_uni_add_bss (&dev->phy, vif, true); +mt76_connac_mcu_uni_add_bss (&dev->mphy, vif, &mvif->sta.wcid, + true); +mt7921_mac_wtbl_update (dev, idx,MT_WTBL_UPDATE_ADM_COUNT_CLEAR ); - ret =mt7921_mcu_uni_add_sta (dev, vif, sta, true); + ret =mt76_connac_mcu_add_sta_cmd (&dev->mphy, vif, sta, &msta->wcid, + true,MCU_UNI_CMD_STA_REC_UPDATE );if (ret)return ret;
@@ -606,11 +611,17 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; -mt7921_mcu_uni_add_sta (dev, vif, sta, false); +mt76_connac_mcu_add_sta_cmd (&dev->mphy, vif, sta, &msta->wcid, false, +MCU_UNI_CMD_STA_REC_UPDATE );mt7921_mac_wtbl_update (dev, msta->wcid.idx,MT_WTBL_UPDATE_ADM_COUNT_CLEAR ); -if (vif->type ==NL80211_IFTYPE_STATION && !sta->tdls) -mt7921_mcu_uni_add_bss (&dev->phy, vif, false); + +if (vif->type ==NL80211_IFTYPE_STATION && !sta->tdls) { +struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + +mt76_connac_mcu_uni_add_bss (&dev->mphy, vif, &mvif->sta.wcid, + false); + }spin_lock_bh (&dev->sta_poll_lock);if (!list_empty (&msta->poll_list))
@@ -650,10 +661,9 @@ static void mt7921_tx(struct ieee80211_hw *hw,static int mt7921_set_rts_threshold (struct ieee80211_hw *hw,u32 val) {struct mt7921_dev *dev =mt7921_hw_dev (hw); -struct mt7921_phy *phy =mt7921_hw_phy (hw);mutex_lock (&dev->mt76.mutex); -mt7921_mcu_set_rts_thresh (phy, val); +mt76_connac_mcu_set_rts_thresh (&dev->mt76, val,0 );mutex_unlock (&dev->mt76.mutex);return 0 ;
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +27 -1219
1,392 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +2 -536
597 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +3 -33
@@ -166,20 +166,6 @@ struct mt7921_dev {u8 fw_debug; }; -enum { -HW_BSSID_0 =0x0 , -HW_BSSID_1 , -HW_BSSID_2 , -HW_BSSID_3 , -HW_BSSID_MAX =HW_BSSID_3 , -EXT_BSSID_START =0x10 , -EXT_BSSID_1 , -EXT_BSSID_15 =0x1f , -EXT_BSSID_MAX =EXT_BSSID_15 , -REPEATER_BSSID_START =0x20 , -REPEATER_BSSID_MAX =0x3f , -}; -enum {MT_LMAC_AC00 ,MT_LMAC_AC01 ,
@@ -239,18 +225,12 @@ int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd);int mt7921_mcu_set_tx (struct mt7921_dev *dev,struct ieee80211_vif *vif);int mt7921_mcu_set_eeprom (struct mt7921_dev *dev);int mt7921_mcu_get_eeprom (struct mt7921_dev *dev,u32 offset); -int mt7921_mcu_set_mac (struct mt7921_dev *dev,int band,bool enable, -bool hdr_trans); -int mt7921_mcu_set_rts_thresh (struct mt7921_phy *phy,u32 val); +int mt7921_mcu_get_rx_rate (struct mt7921_phy *phy,struct ieee80211_vif *vif, +struct ieee80211_sta *sta,struct rate_info *rate);int mt7921_mcu_fw_log_2_host (struct mt7921_dev *dev,u8 ctrl);void mt7921_mcu_rx_event (struct mt7921_dev *dev,struct sk_buff *skb);void mt7921_mcu_exit (struct mt7921_dev *dev); -static inline bool is_mt7921 (struct mt76_dev *dev) -{ -return mt76_chip (dev) ==0x7961 ; -} -static inline void mt7921_irq_enable (struct mt7921_dev *dev,u32 mask) {mt76_set_irq_mask (&dev->mt76,0 ,0 , mask);
@@ -326,16 +306,7 @@ void mt7921_txp_skb_unmap(struct mt76_dev *dev,void mt7921_set_stream_he_caps (struct mt7921_phy *phy);void mt7921_update_channel (struct mt76_dev *mdev);int mt7921_init_debugfs (struct mt7921_dev *dev); -int -mt7921_mcu_uni_add_dev (struct mt7921_dev *dev, -struct ieee80211_vif *vif,bool enable); -int -mt7921_mcu_uni_add_bss (struct mt7921_phy *phy,struct ieee80211_vif *vif, -bool enable); - -int -mt7921_mcu_uni_add_sta (struct mt7921_dev *dev,struct ieee80211_vif *vif, -struct ieee80211_sta *sta,bool enable); +int mt7921_mcu_uni_tx_ba (struct mt7921_dev *dev,struct ieee80211_ampdu_params *params,bool enable);
@@ -343,7 +314,6 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,struct ieee80211_ampdu_params *params, bool enable);void mt7921_scan_work (struct work_struct *work); -int mt7921_mcu_set_channel_domain (struct mt7921_phy *phy);int mt7921_mcu_hw_scan (struct mt7921_phy *phy,struct ieee80211_vif *vif,struct ieee80211_scan_request *scan_req); int mt7921_mcu_sched_scan_req(struct mt7921_phy *phy,
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +1 -0
@@ -9,6 +9,7 @@#include "mt7921.h" #include "mac.h" +#include "mcu.h" #include "../trace.h" static const struct pci_device_id mt7921_pci_device_table[] = {
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 15/22 mt76: mt7921: rely on mt76_connac_mcu module for sched_scan and hw_scan
In reply to [email protected]From: Lorenzo Bianconi <[email protected]>
Rely on mt76_connac_mcu module for sched_scan and hw_scan and remove duplicated code
--- .../net/wireless/mediatek/mt76/mt7921/init.c | 9 +- .../net/wireless/mediatek/mt76/mt7921/main.c | 10 +- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 197 +----------------- .../net/wireless/mediatek/mt76/mt7921/mcu.h | 116 ----------- .../wireless/mediatek/mt76/mt7921/mt7921.h | 17 +- 5 files changed, 15 insertions(+), 334 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +5 -4
@@ -69,12 +69,13 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations =ARRAY_SIZE (if_comb); - wiphy->max_scan_ie_len =MT7921_SCAN_IE_LEN ; + wiphy->max_scan_ie_len =MT76_CONNAC_SCAN_IE_LEN ; wiphy->max_scan_ssids =4 ; - wiphy->max_sched_scan_plan_interval =MT7921_MAX_SCHED_SCAN_INTERVAL ; + wiphy->max_sched_scan_plan_interval = +MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL ; wiphy->max_sched_scan_ie_len =IEEE80211_MAX_DATA_LEN ; - wiphy->max_sched_scan_ssids =MT7921_MAX_SCHED_SCAN_SSID ; - wiphy->max_match_sets =MT7921_MAX_SCAN_MATCH ; + wiphy->max_sched_scan_ssids =MT76_CONNAC_MAX_SCHED_SCAN_SSID ; + wiphy->max_match_sets =MT76_CONNAC_MAX_SCAN_MATCH ; wiphy->max_sched_scan_reqs =1 ; wiphy->flags |=WIPHY_FLAG_HAS_CHANNEL_SWITCH ;
drivers/net/wireless/mediatek/mt76/mt7921/main.c +5 -5
@@ -864,7 +864,7 @@ mt7921_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,int err;mutex_lock (&dev->mt76.mutex); - err =mt7921_mcu_hw_scan (mphy->priv, vif, req); + err =mt76_connac_mcu_hw_scan (mphy, vif, req);mutex_unlock (&dev->mt76.mutex);return err;
@@ -877,7 +877,7 @@ mt7921_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)struct mt76_phy *mphy = hw->priv;mutex_lock (&dev->mt76.mutex); -mt7921_mcu_cancel_hw_scan (mphy->priv, vif); +mt76_connac_mcu_cancel_hw_scan (mphy, vif);mutex_unlock (&dev->mt76.mutex); }
@@ -892,11 +892,11 @@ mt7921_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,mutex_lock (&dev->mt76.mutex); - err =mt7921_mcu_sched_scan_req (mphy->priv, vif, req); + err =mt76_connac_mcu_sched_scan_req (mphy, vif, req);if (err <0 ) goto out; - err =mt7921_mcu_sched_scan_enable (mphy->priv, vif, true); + err =mt76_connac_mcu_sched_scan_enable (mphy, vif, true); out:mutex_unlock (&dev->mt76.mutex);
@@ -911,7 +911,7 @@ mt7921_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)int err;mutex_lock (&dev->mt76.mutex); - err =mt7921_mcu_sched_scan_enable (mphy->priv, vif, false); + err =mt76_connac_mcu_sched_scan_enable (mphy, vif, false);mutex_unlock (&dev->mt76.mutex);return err;
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +4 -193
210 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +0 -116
122 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +1 -16
@@ -43,11 +43,6 @@#define MT7921_SKU_MAX_DELTA_IDX MT7921_SKU_RATE_NUM#define MT7921_SKU_TABLE_SIZE (MT7921_SKU_RATE_NUM + 1) -#define MT7921_SCAN_IE_LEN 600 -#define MT7921_MAX_SCHED_SCAN_INTERVAL 10 -#define MT7921_MAX_SCHED_SCAN_SSID 10 -#define MT7921_MAX_SCAN_MATCH 16 -struct mt7921_vif ;struct mt7921_sta ;
@@ -314,17 +309,7 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,struct ieee80211_ampdu_params *params, bool enable);void mt7921_scan_work (struct work_struct *work); -int mt7921_mcu_hw_scan (struct mt7921_phy *phy,struct ieee80211_vif *vif, -struct ieee80211_scan_request *scan_req); -int mt7921_mcu_sched_scan_req (struct mt7921_phy *phy, -struct ieee80211_vif *vif, -struct cfg80211_sched_scan_request *sreq); -int mt7921_mcu_sched_scan_enable (struct mt7921_phy *phy, -struct ieee80211_vif *vif, -bool enable); -int mt7921_mcu_cancel_hw_scan (struct mt7921_phy *phy, -struct ieee80211_vif *vif); -u32 mt7921_get_wtbl_info (struct mt7921_dev *dev,u16 wlan_idx); +u32 mt7921_get_wtbl_info (struct mt7921_dev *dev,u32 wlan_idx);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);
Signature · 5 lines
2.25.1 _______________________________________________ Linux-mediatek mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-mediatek
[email protected]
reviewerPATCH v7 16/22 mt76: mt7921: rely on mt76_connac_mcu module for suspend and WoW support
In reply to [email protected]From: Lorenzo Bianconi <[email protected]>
Rely on mt76_connac_mcu module for suspend and WoW support and remove duplicated code
--- .../net/wireless/mediatek/mt76/mt7921/main.c | 12 +- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 306 +----------------- .../net/wireless/mediatek/mt76/mt7921/mcu.h | 93 ------ .../wireless/mediatek/mt76/mt7921/mt7921.h | 6 - .../net/wireless/mediatek/mt76/mt7921/pci.c | 6 +- 5 files changed, 11 insertions(+), 412 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +7 -5
@@ -969,9 +969,10 @@ static int mt7921_suspend(struct ieee80211_hw *hw,set_bit (MT76_STATE_SUSPEND , &phy->mt76->state);ieee80211_iterate_active_interfaces (hw,IEEE80211_IFACE_ITER_RESUME_ALL , - mt7921_mcu_set_suspend_iter, phy); + mt76_connac_mcu_set_suspend_iter, + &dev->mphy); - err =mt7921_mcu_set_hif_suspend (dev, true); + err =mt76_connac_mcu_set_hif_suspend (&dev->mt76, true);mutex_unlock (&dev->mt76.mutex);
@@ -986,7 +987,7 @@ static int mt7921_resume(struct ieee80211_hw *hw)mutex_lock (&dev->mt76.mutex); - err =mt7921_mcu_set_hif_suspend (dev, false); + err =mt76_connac_mcu_set_hif_suspend (&dev->mt76, false);if (err <0 ) goto out;
@@ -994,7 +995,8 @@ static int mt7921_resume(struct ieee80211_hw *hw)clear_bit (MT76_STATE_SUSPEND , &phy->mt76->state);ieee80211_iterate_active_interfaces (hw,IEEE80211_IFACE_ITER_RESUME_ALL , - mt7921_mcu_set_suspend_iter, phy); + mt76_connac_mcu_set_suspend_iter, + &dev->mphy);ieee80211_queue_delayed_work (hw, &phy->mt76->mac_work,MT7921_WATCHDOG_TIME );
@@ -1019,7 +1021,7 @@ static void mt7921_set_rekey_data(struct ieee80211_hw *hw,struct mt7921_dev *dev =mt7921_hw_dev (hw);mutex_lock (&dev->mt76.mutex); -mt7921_mcu_update_gtk_rekey (hw, vif, data); +mt76_connac_mcu_update_gtk_rekey (hw, vif, data); mutex_unlock(&dev->mt76.mutex); }#endif /* CONFIG_PM */
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +1 -305
321 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +0 -93
99 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +0 -6
@@ -315,12 +315,6 @@ 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_set_hif_suspend (struct mt7921_dev *dev,bool suspend); -void mt7921_mcu_set_suspend_iter (void *priv,u8 *mac, -struct ieee80211_vif *vif); -int mt7921_mcu_update_gtk_rekey (struct ieee80211_hw *hw, -struct ieee80211_vif *vif, -struct cfg80211_gtk_rekey_data *key);int mt7921_mcu_update_arp_filter (struct ieee80211_hw *hw,struct ieee80211_vif *vif,struct ieee80211_bss_conf *info);
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +3 -3
@@ -178,7 +178,7 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) hif_suspend = !test_bit (MT76_STATE_SUSPEND , &dev->mphy.state);if (hif_suspend) { - err =mt7921_mcu_set_hif_suspend (dev, true); + err =mt76_connac_mcu_set_hif_suspend (mdev, true);if (err)return err; }
@@ -218,7 +218,7 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) }napi_enable (&mdev->tx_napi);if (hif_suspend) -mt7921_mcu_set_hif_suspend (dev, false); +mt76_connac_mcu_set_hif_suspend (mdev, false);return err; }
@@ -253,7 +253,7 @@ static int mt7921_pci_resume(struct pci_dev *pdev)napi_schedule (&mdev->tx_napi);if (!test_bit (MT76_STATE_SUSPEND , &dev->mphy.state)) - err =mt7921_mcu_set_hif_suspend (dev, false); + err =mt76_connac_mcu_set_hif_suspend (mdev, false);return err; }
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 17/22 mt76: mt7921: introduce Runtime PM support
In reply to [email protected]From: Sean Wang <[email protected]>
Introduce runtime PM to mt7921 driver
--- .../wireless/mediatek/mt76/mt7921/debugfs.c | 57 +++++++ .../net/wireless/mediatek/mt76/mt7921/init.c | 7 + .../net/wireless/mediatek/mt76/mt7921/mac.c | 98 ++++++++++- .../net/wireless/mediatek/mt76/mt7921/main.c | 157 +++++++++++++----- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 69 ++++++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 21 ++- .../net/wireless/mediatek/mt76/mt7921/pci.c | 12 ++ .../net/wireless/mediatek/mt76/mt7921/regs.h | 5 + 8 files changed, 372 insertions(+), 54 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +57 -0
@@ -159,6 +159,60 @@ mt7921_queues_read(struct seq_file *s, void *data)return 0 ; } +static int +mt7921_pm_set (void *data,u64 val) +{ +struct mt7921_dev *dev = data; +struct mt76_phy *mphy = dev->phy.mt76; +int ret =0 ; + +mt7921_mutex_acquire (dev); + + dev->pm.enable = val; + +ieee80211_iterate_active_interfaces (mphy->hw, +IEEE80211_IFACE_ITER_RESUME_ALL , + mt7921_pm_interface_iter, mphy->priv); +mt7921_mutex_release (dev); + +return ret; +} + +static int +mt7921_pm_get (void *data,u64 *val) +{ +struct mt7921_dev *dev = data; + + *val = dev->pm.enable; + +return 0 ; +} + +DEFINE_DEBUGFS_ATTRIBUTE (fops_pm, mt7921_pm_get, mt7921_pm_set,"%lld\n" ); + +static int +mt7921_pm_idle_timeout_set (void *data,u64 val) +{ +struct mt7921_dev *dev = data; + + dev->pm.idle_timeout =msecs_to_jiffies (val); + +return 0 ; +} + +static int +mt7921_pm_idle_timeout_get (void *data,u64 *val) +{ +struct mt7921_dev *dev = data; + + *val =jiffies_to_msecs (dev->pm.idle_timeout); + +return 0 ; +} + +DEFINE_DEBUGFS_ATTRIBUTE (fops_pm_idle_timeout, mt7921_pm_idle_timeout_get, + mt7921_pm_idle_timeout_set,"%lld\n" ); +int mt7921_init_debugfs (struct mt7921_dev *dev) {struct dentry *dir;
@@ -173,6 +227,9 @@ int mt7921_init_debugfs(struct mt7921_dev *dev) mt7921_queues_acq);debugfs_create_file ("tx_stats" ,0400 , dir, dev, &fops_tx_stats);debugfs_create_file ("fw_debug" ,0600 , dir, dev, &fops_fw_debug); +debugfs_create_file ("runtime-pm" ,0600 , dir, dev, &fops_pm); +debugfs_create_file ("idle-timeout" ,0600 , dir, dev, + &fops_pm_idle_timeout);return 0 ; }
drivers/net/wireless/mediatek/mt76/mt7921/init.c +7 -0
@@ -201,6 +201,12 @@ int mt7921_register_device(struct mt7921_dev *dev) dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; + +INIT_DELAYED_WORK (&dev->pm.ps_work, mt7921_pm_power_save_work); +INIT_WORK (&dev->pm.wake_work, mt7921_pm_wake_work); +init_completion (&dev->pm.wake_cmpl); +spin_lock_init (&dev->pm.txq_lock); +set_bit (MT76_STATE_PM , &dev->mphy.state);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);
@@ -216,6 +222,7 @@ int mt7921_register_device(struct mt7921_dev *dev)return ret;mt7921_init_wiphy (hw); + dev->pm.idle_timeout =MT7921_PM_TIMEOUT ; dev->mphy.sband_2g.sband.ht_cap.cap |=IEEE80211_HT_CAP_LDPC_CODING |IEEE80211_HT_CAP_MAX_AMSDU ;
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +89 -9
149 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/main.c +113 -44
426 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +69 -0
78 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +20 -1
@@ -6,7 +6,7 @@#include <linux/interrupt.h> #include <linux/ktime.h> -#include "../mt76.h" +#include "../mt76_connac.h" #include "regs.h" #define MT7921_MAX_INTERFACES 4
@@ -16,6 +16,7 @@#define MT7921_WTBL_STA (MT7921_WTBL_RESERVED - \ MT7921_MAX_INTERFACES) +#define MT7921_PM_TIMEOUT (HZ / 12)#define MT7921_HW_SCAN_TIMEOUT (HZ / 10)#define MT7921_WATCHDOG_TIME (HZ / 10)#define MT7921_RESET_TIMEOUT (30 * HZ)
@@ -27,6 +28,8 @@#define MT7921_RX_RING_SIZE 1536#define MT7921_RX_MCU_RING_SIZE 512 +#define MT7921_DRV_OWN_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"
@@ -159,6 +162,8 @@ struct mt7921_dev {struct idr token;u8 fw_debug; + +struct mt76_connac_pm pm; };enum {
@@ -187,6 +192,11 @@ mt7921_hw_dev(struct ieee80211_hw *hw) return container_of(phy->dev, struct mt7921_dev, mt76); } +#define mt7921_mutex_acquire (dev) \ + mt76_connac_mutex_acquire(&(dev)->mt76, &(dev)->pm) +#define mt7921_mutex_release (dev) \ + mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) +static inline u8 mt7921_lmac_mapping (struct mt7921_dev *dev,u8 ac) {/* LMAC uses the reverse order of mac80211 AC indexes */
@@ -318,4 +328,13 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,int mt7921_mcu_update_arp_filter (struct ieee80211_hw *hw,struct ieee80211_vif *vif,struct ieee80211_bss_conf *info); +int mt7921_mcu_drv_pmctrl (struct mt7921_dev *dev); +int mt7921_mcu_fw_pmctrl (struct mt7921_dev *dev); +void mt7921_pm_wake_work (struct work_struct *work); +void mt7921_pm_power_save_work (struct work_struct *work); +bool mt7921_wait_for_mcu_init (struct mt7921_dev *dev); +int mt7921_mac_set_beacon_filter (struct mt7921_phy *phy, +struct ieee80211_vif *vif, +bool enable); +void mt7921_pm_interface_iter (void *priv,u8 *mac,struct ieee80211_vif *vif);#endif
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +12 -0
@@ -176,6 +176,10 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)bool hif_suspend;int i, err; + err =mt76_connac_pm_wake (&dev->mphy, &dev->pm); +if (err <0 ) +return err; + hif_suspend = !test_bit (MT76_STATE_SUSPEND , &dev->mphy.state);if (hif_suspend) { err =mt76_connac_mcu_set_hif_suspend (mdev, true);
@@ -210,6 +214,10 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)if (err) goto restore; + err =mt7921_mcu_drv_pmctrl (dev); +if (err) + goto restore; +return 0 ; restore:
@@ -229,6 +237,10 @@ static int mt7921_pci_resume(struct pci_dev *pdev) struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);int i, err; + err =mt7921_mcu_fw_pmctrl (dev); +if (err <0 ) +return err; + err =pci_set_power_state (pdev,PCI_D0 );if (err)return err;
drivers/net/wireless/mediatek/mt76/mt7921/regs.h +5 -0
@@ -408,6 +408,11 @@#define MT_DMASHDL_SCHED_SET (_n) MT_DMA_SHDL(0x070 + ((_n) << 2)) +#define MT_CONN_ON_LPCTL 0x7c060010 +#define PCIE_LPCR_HOST_OWN_SYNC BIT(2) +#define PCIE_LPCR_HOST_CLR_OWN BIT(1) +#define PCIE_LPCR_HOST_SET_OWN BIT(0) +#define MT_CONN_ON_MISC 0x7c0600f0#define MT_TOP_MISC2_FW_N9_RDY GENMASK(1, 0)
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 18/22 mt76: mt7921: introduce regdomain notifier support
In reply to [email protected]From: Lorenzo Bianconi <[email protected]>
Register regdomain notifier to determine the channel domain the hw scan should rely on.
--- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +16 -0
@@ -52,6 +52,21 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static void +mt7921_regd_notifier (struct wiphy *wiphy, +struct regulatory_request *request) +{ +struct ieee80211_hw *hw =wiphy_to_ieee80211_hw (wiphy); +struct mt7921_dev *dev =mt7921_hw_dev (hw); + +memcpy (dev->mt76.alpha2, request->alpha2,sizeof (dev->mt76.alpha2)); + dev->mt76.region = request->dfs_region; + +mt7921_mutex_acquire (dev); +mt76_connac_mcu_set_channel_domain (hw->priv); +mt7921_mutex_release (dev); +} +static void mt7921_init_wiphy (struct ieee80211_hw *hw) {
@@ -78,6 +93,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) wiphy->max_match_sets =MT76_CONNAC_MAX_SCAN_MATCH ; wiphy->max_sched_scan_reqs =1 ; wiphy->flags |=WIPHY_FLAG_HAS_CHANNEL_SWITCH ; + wiphy->reg_notifier = mt7921_regd_notifier;wiphy_ext_feature_set (wiphy,NL80211_EXT_FEATURE_SET_SCAN_DWELL );
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 19/22 mt76: mt7921: enable MSI interrupts
In reply to [email protected]From: Lorenzo Bianconi <[email protected]>
Enable MSI interrupts for mt7921 driver
--- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +1 -1
@@ -110,7 +110,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,pci_set_master (pdev); - ret =pci_alloc_irq_vectors (pdev,1 ,1 ,PCI_IRQ_LEGACY ); + ret =pci_alloc_irq_vectors (pdev,1 ,1 ,PCI_IRQ_ALL_TYPES );if (ret <0 )return ret;
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 20/22 mt76: mt7921: add coredump support
In reply to [email protected]From: Sean Wang <[email protected]>
Introduce coredump support to mt7921 driver.
The coredump would be produced when MCU met the fatal error or driver sent out the specific cmd to force trigger it.
--- .../net/wireless/mediatek/mt76/mt76_connac.h | 9 ++++ .../wireless/mediatek/mt76/mt76_connac_mcu.c | 34 +++++++++++++++ .../wireless/mediatek/mt76/mt76_connac_mcu.h | 4 ++ .../net/wireless/mediatek/mt76/mt7921/Kconfig | 1 + .../wireless/mediatek/mt76/mt7921/debugfs.c | 15 +++++++ .../net/wireless/mediatek/mt76/mt7921/init.c | 2 + .../net/wireless/mediatek/mt76/mt7921/mac.c | 43 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 5 +++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 1 + .../wireless/mediatek/mt76/mt7921/mt7921.h | 4 +- 10 files changed, 117 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt76_connac.h +9 -0
@@ -11,6 +11,9 @@#define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10#define MT76_CONNAC_MAX_SCAN_MATCH 16 +#define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) +#define MT76_CONNAC_COREDUMP_SZ (128 * 1024) +enum {CMD_CBW_20MHZ =IEEE80211_STA_RX_BW_20 ,CMD_CBW_40MHZ =IEEE80211_STA_RX_BW_40 ,
@@ -57,6 +60,12 @@ struct mt76_connac_pm {unsigned long idle_timeout; }; +struct mt76_connac_coredump { +struct sk_buff_head msg_list; +struct delayed_work work; +unsigned long last_activity; +}; +extern const struct wiphy_wowlan_support mt76_connac_wowlan_support;static inline bool is_mt7921 (struct mt76_dev *dev)
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +34 -0
@@ -1497,6 +1497,40 @@ int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy, }EXPORT_SYMBOL_GPL (mt76_connac_mcu_sched_scan_enable); +int mt76_connac_mcu_chip_config (struct mt76_dev *dev) +{ +struct { +__le16 id; +u8 type; +u8 resp_type; +__le16 data_size; +__le16 resv; +u8 data[320 ]; + } req = { + .resp_type =0 , + }; + +memcpy (req.data,"assert" ,7 ); + +return mt76_mcu_send_msg (dev,MCU_CMD_CHIP_CONFIG , &req,sizeof (req), + false); +} +EXPORT_SYMBOL_GPL (mt76_connac_mcu_chip_config); + +void mt76_connac_mcu_coredump_event (struct mt76_dev *dev,struct sk_buff *skb, +struct mt76_connac_coredump *coredump) +{ +spin_lock_bh (&dev->lock); +__skb_queue_tail (&coredump->msg_list, skb); +spin_unlock_bh (&dev->lock); + + coredump->last_activity = jiffies; + +queue_delayed_work (dev->wq, &coredump->work, +MT76_CONNAC_COREDUMP_TIMEOUT ); +} +EXPORT_SYMBOL_GPL (mt76_connac_mcu_coredump_event); +#ifdef CONFIG_PM const struct wiphy_wowlan_support mt76_connac_wowlan_support = {
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +4 -0
@@ -561,6 +561,7 @@ enum {MCU_CMD_SCHED_SCAN_REQ =MCU_CE_PREFIX |0x62 ,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 ,MCU_CMD_FWLOG_2_HOST =MCU_CE_PREFIX |0xc5 , MCU_CMD_GET_WTBL = MCU_CE_PREFIX | 0xcd, };
@@ -972,4 +973,7 @@ int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw,int mt76_connac_mcu_set_hif_suspend (struct mt76_dev *dev,bool suspend);void mt76_connac_mcu_set_suspend_iter (void *priv,u8 *mac,struct ieee80211_vif *vif); +int mt76_connac_mcu_chip_config (struct mt76_dev *dev); +void mt76_connac_mcu_coredump_event (struct mt76_dev *dev,struct sk_buff *skb, +struct mt76_connac_coredump *coredump);#endif /* __MT76_CONNAC_MCU_H */
drivers/net/wireless/mediatek/mt76/mt7921/Kconfig +1 -0
@@ -2,6 +2,7 @@ config MT7921E tristate "MediaTek MT7921E (PCIe) support" select MT76_CONNAC_LIB + select WANT_DEV_COREDUMP depends on MAC80211 depends on PCI help
drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +15 -0
@@ -213,6 +213,20 @@ mt7921_pm_idle_timeout_get(void *data, u64 *val)DEFINE_DEBUGFS_ATTRIBUTE (fops_pm_idle_timeout, mt7921_pm_idle_timeout_get, mt7921_pm_idle_timeout_set,"%lld\n" ); +static int mt7921_config (void *data,u64 val) +{ +struct mt7921_dev *dev = data; +int ret; + +mt7921_mutex_acquire (dev); + ret =mt76_connac_mcu_chip_config (&dev->mt76); +mt7921_mutex_release (dev); + +return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE (fops_config,NULL , mt7921_config,"%lld\n" ); +int mt7921_init_debugfs (struct mt7921_dev *dev) {struct dentry *dir;
@@ -230,6 +244,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)debugfs_create_file ("runtime-pm" ,0600 , dir, dev, &fops_pm);debugfs_create_file ("idle-timeout" ,0600 , dir, dev, &fops_pm_idle_timeout); +debugfs_create_file ("chip_config" ,0600 , dir, dev, &fops_config);return 0 ; }
drivers/net/wireless/mediatek/mt76/mt7921/init.c +2 -0
@@ -226,7 +226,9 @@ int mt7921_register_device(struct mt7921_dev *dev)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);skb_queue_head_init (&dev->phy.scan_event_list); +skb_queue_head_init (&dev->coredump.msg_list);INIT_LIST_HEAD (&dev->sta_poll_list);spin_lock_init (&dev->sta_poll_lock);
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +43 -0
57 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +5 -0
@@ -513,6 +513,10 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)case MCU_EVENT_DBG_MSG :mt7921_mcu_debug_msg_event (dev, skb);break ; +case MCU_EVENT_COREDUMP : +mt76_connac_mcu_coredump_event (&dev->mt76, skb, + &dev->coredump); +return ;default :break ; }
@@ -534,6 +538,7 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) rxd->eid == MCU_EVENT_BSS_ABSENCE || rxd->eid == MCU_EVENT_SCAN_DONE || rxd->eid == MCU_EVENT_DBG_MSG || + rxd->eid == MCU_EVENT_COREDUMP || !rxd->seq)mt7921_mcu_rx_unsolicited_event (dev, skb); else
drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +1 -0
@@ -85,6 +85,7 @@ enum {MCU_EVENT_CH_PRIVILEGE =0x18 ,MCU_EVENT_SCHED_SCAN_DONE =0x23 ,MCU_EVENT_DBG_MSG =0x27 , + MCU_EVENT_COREDUMP = 0xf0, };/* ext event table */
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +3 -1
@@ -6,7 +6,7 @@#include <linux/interrupt.h> #include <linux/ktime.h> -#include "../mt76_connac.h" +#include "../mt76_connac_mcu.h" #include "regs.h" #define MT7921_MAX_INTERFACES 4
@@ -164,6 +164,7 @@ struct mt7921_dev {u8 fw_debug;struct mt76_connac_pm pm; +struct mt76_connac_coredump coredump; };enum {
@@ -337,4 +338,5 @@ 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);#endif
Signature · 5 lines
2.25.1 _______________________________________________ Linux-mediatek mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-mediatek
[email protected]
reviewerPATCH v7 21/22 mt76: mt7663: introduce coredump support
In reply to [email protected]From: Lorenzo Bianconi <[email protected]>
Similar to mt7921 devices, introduce coredump support for mt7663 chipset
--- .../net/wireless/mediatek/mt76/mt7615/Kconfig | 1 + .../wireless/mediatek/mt76/mt7615/debugfs.c | 17 ++++++++ .../net/wireless/mediatek/mt76/mt7615/init.c | 2 + .../net/wireless/mediatek/mt76/mt7615/mac.c | 43 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++ .../net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + .../wireless/mediatek/mt76/mt7615/mt7615.h | 4 +- 7 files changed, 71 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +1 -0
@@ -2,6 +2,7 @@ config MT7615_COMMON tristate + select WANT_DEV_COREDUMP select MT76_CONNAC_LIB config MT7615E
drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +17 -0
@@ -21,6 +21,20 @@ mt7615_radar_pattern_set(void *data, u64 val)DEFINE_DEBUGFS_ATTRIBUTE (fops_radar_pattern,NULL , mt7615_radar_pattern_set,"%lld\n" ); +static int mt7615_config (void *data,u64 val) +{ +struct mt7615_dev *dev = data; +int ret; + +mt7615_mutex_acquire (dev); + ret =mt76_connac_mcu_chip_config (&dev->mt76); +mt7615_mutex_release (dev); + +return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE (fops_config,NULL , mt7615_config,"%lld\n" ); +static int mt7615_scs_set (void *data,u64 val) {
@@ -525,6 +539,9 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)debugfs_create_u32 ("rf_regidx" ,0600 , dir, &dev->debugfs_rf_reg);debugfs_create_file_unsafe ("rf_regval" ,0600 , dir, dev, &fops_rf_reg); +if (is_mt7663 (&dev->mt76)) +debugfs_create_file ("chip_config" ,0600 , dir, dev, + &fops_config);if (mt76_is_sdio (&dev->mt76))debugfs_create_devm_seqfile (dev->mt76.dev,"sched-quota" , dir, mt7663s_sched_quota_read);
drivers/net/wireless/mediatek/mt76/mt7615/init.c +2 -0
@@ -488,7 +488,9 @@ void mt7615_init_device(struct mt7615_dev *dev)set_bit (MT76_STATE_PM , &dev->mphy.state);INIT_DELAYED_WORK (&dev->mphy.mac_work, mt7615_mac_work);INIT_DELAYED_WORK (&dev->phy.scan_work, mt7615_scan_work); +INIT_DELAYED_WORK (&dev->coredump.work, mt7615_coredump_work);skb_queue_head_init (&dev->phy.scan_event_list); +skb_queue_head_init (&dev->coredump.msg_list);INIT_LIST_HEAD (&dev->sta_poll_list);spin_lock_init (&dev->sta_poll_lock);init_waitqueue_head (&dev->reset_wait);
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +43 -0
58 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +4 -0
@@ -543,6 +543,10 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)case MCU_EVENT_BSS_ABSENCE :mt7615_mcu_bss_event (dev, skb);break ; +case MCU_EVENT_COREDUMP : +mt76_connac_mcu_coredump_event (&dev->mt76, skb, + &dev->coredump); +return ;default :break ; }
drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +1 -0
@@ -92,6 +92,7 @@ enum {MCU_EVENT_SCHED_SCAN_DONE =0x23 ,MCU_EVENT_EXT =0xed ,MCU_EVENT_RESTART_DL =0xef , + MCU_EVENT_COREDUMP = 0xf0, };/* ext event table */
drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +3 -1
@@ -8,7 +8,7 @@#include <linux/interrupt.h> #include <linux/ktime.h> #include <linux/regmap.h> -#include "../mt76_connac.h" +#include "../mt76_connac_mcu.h" #include "regs.h" #define MT7615_MAX_INTERFACES 16
@@ -277,6 +277,7 @@ struct mt7615_dev {u32 muar_mask;struct mt76_connac_pm pm; +struct mt76_connac_coredump coredump; };enum tx_pkt_queue_idx {
@@ -554,6 +555,7 @@ int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw,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);/* usb */ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v7 22/22 mt76: mt7921: add sta statistics
In reply to [email protected]From: Sean Wang <[email protected]>
Add sta statistics support to query current tx bitrate
--- .../net/wireless/mediatek/mt76/mt7921/main.c | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +26 -0
@@ -1095,6 +1095,31 @@ static void mt7921_set_rekey_data(struct ieee80211_hw *hw, }#endif /* CONFIG_PM */ +static void mt7921_sta_statistics (struct ieee80211_hw *hw, +struct ieee80211_vif *vif, +struct ieee80211_sta *sta, +struct station_info *sinfo) +{ +struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; +struct mt7921_sta_stats *stats = &msta->stats; + +if (!stats->tx_rate.legacy && !stats->tx_rate.flags) +return ; + +if (stats->tx_rate.legacy) { + sinfo->txrate.legacy = stats->tx_rate.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.flags = stats->tx_rate.flags; + sinfo->filled |=BIT_ULL (NL80211_STA_INFO_TX_BITRATE ); +} +const struct ieee80211_ops mt7921_ops = { .tx = mt7921_tx, .start = mt7921_start,
@@ -1132,4 +1157,5 @@ const struct ieee80211_ops mt7921_ops = { .set_wakeup = mt7921_set_wakeup, .set_rekey_data = mt7921_set_rekey_data,#endif /* CONFIG_PM */ + .sta_statistics = mt7921_sta_statistics, };
Signature · 1 line
2.25.1
Ryder Lee
maintainerRe: [PATCH -next v7 22/22] mt76: mt7921: add sta statistics
Quoted 10 lines · On Sat, 2021-01-23 at 16:35 +0800, [email protected] wrote:
From: Sean Wang <[email protected]>
Add sta statistics support to query current tx bitrate
Co-developed-by Soul Huang <[email protected]>Signed-off-by Soul Huang <[email protected]>Signed-off-by Sean Wang <[email protected]>--- .../net/wireless/mediatek/mt76/mt7921/main.c | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+)
why didn't you just merge this into [-next,v7,05/22] mt76: mt7921: add ieee80211_ops?
Ryder
_______________________________________________
Linux-mediatek mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-mediatek