diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 15:47:48 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 15:47:48 -0800 |
commit | 7e68dd7d07a28faa2e6574dd6b9dbd90cdeaae91 (patch) | |
tree | ae0427c5a3b905f24b3a44b510a9bcf35d9b67a3 /drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | |
parent | 1ca06f1c1acecbe02124f14a37cce347b8c1a90c (diff) | |
parent | 7c4a6309e27f411743817fe74a832ec2d2798a4b (diff) | |
download | linux-7e68dd7d07a28faa2e6574dd6b9dbd90cdeaae91.tar.bz2 |
Merge tag 'net-next-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Paolo Abeni:
"Core:
- Allow live renaming when an interface is up
- Add retpoline wrappers for tc, improving considerably the
performances of complex queue discipline configurations
- Add inet drop monitor support
- A few GRO performance improvements
- Add infrastructure for atomic dev stats, addressing long standing
data races
- De-duplicate common code between OVS and conntrack offloading
infrastructure
- A bunch of UBSAN_BOUNDS/FORTIFY_SOURCE improvements
- Netfilter: introduce packet parser for tunneled packets
- Replace IPVS timer-based estimators with kthreads to scale up the
workload with the number of available CPUs
- Add the helper support for connection-tracking OVS offload
BPF:
- Support for user defined BPF objects: the use case is to allocate
own objects, build own object hierarchies and use the building
blocks to build own data structures flexibly, for example, linked
lists in BPF
- Make cgroup local storage available to non-cgroup attached BPF
programs
- Avoid unnecessary deadlock detection and failures wrt BPF task
storage helpers
- A relevant bunch of BPF verifier fixes and improvements
- Veristat tool improvements to support custom filtering, sorting,
and replay of results
- Add LLVM disassembler as default library for dumping JITed code
- Lots of new BPF documentation for various BPF maps
- Add bpf_rcu_read_{,un}lock() support for sleepable programs
- Add RCU grace period chaining to BPF to wait for the completion of
access from both sleepable and non-sleepable BPF programs
- Add support storing struct task_struct objects as kptrs in maps
- Improve helper UAPI by explicitly defining BPF_FUNC_xxx integer
values
- Add libbpf *_opts API-variants for bpf_*_get_fd_by_id() functions
Protocols:
- TCP: implement Protective Load Balancing across switch links
- TCP: allow dynamically disabling TCP-MD5 static key, reverting back
to fast[er]-path
- UDP: Introduce optional per-netns hash lookup table
- IPv6: simplify and cleanup sockets disposal
- Netlink: support different type policies for each generic netlink
operation
- MPTCP: add MSG_FASTOPEN and FastOpen listener side support
- MPTCP: add netlink notification support for listener sockets events
- SCTP: add VRF support, allowing sctp sockets binding to VRF devices
- Add bridging MAC Authentication Bypass (MAB) support
- Extensions for Ethernet VPN bridging implementation to better
support multicast scenarios
- More work for Wi-Fi 7 support, comprising conversion of all the
existing drivers to internal TX queue usage
- IPSec: introduce a new offload type (packet offload) allowing
complete header processing and crypto offloading
- IPSec: extended ack support for more descriptive XFRM error
reporting
- RXRPC: increase SACK table size and move processing into a
per-local endpoint kernel thread, reducing considerably the
required locking
- IEEE 802154: synchronous send frame and extended filtering support,
initial support for scanning available 15.4 networks
- Tun: bump the link speed from 10Mbps to 10Gbps
- Tun/VirtioNet: implement UDP segmentation offload support
Driver API:
- PHY/SFP: improve power level switching between standard level 1 and
the higher power levels
- New API for netdev <-> devlink_port linkage
- PTP: convert existing drivers to new frequency adjustment
implementation
- DSA: add support for rx offloading
- Autoload DSA tagging driver when dynamically changing protocol
- Add new PCP and APPTRUST attributes to Data Center Bridging
- Add configuration support for 800Gbps link speed
- Add devlink port function attribute to enable/disable RoCE and
migratable
- Extend devlink-rate to support strict prioriry and weighted fair
queuing
- Add devlink support to directly reading from region memory
- New device tree helper to fetch MAC address from nvmem
- New big TCP helper to simplify temporary header stripping
New hardware / drivers:
- Ethernet:
- Marvel Octeon CNF95N and CN10KB Ethernet Switches
- Marvel Prestera AC5X Ethernet Switch
- WangXun 10 Gigabit NIC
- Motorcomm yt8521 Gigabit Ethernet
- Microchip ksz9563 Gigabit Ethernet Switch
- Microsoft Azure Network Adapter
- Linux Automation 10Base-T1L adapter
- PHY:
- Aquantia AQR112 and AQR412
- Motorcomm YT8531S
- PTP:
- Orolia ART-CARD
- WiFi:
- MediaTek Wi-Fi 7 (802.11be) devices
- RealTek rtw8821cu, rtw8822bu, rtw8822cu and rtw8723du USB
devices
- Bluetooth:
- Broadcom BCM4377/4378/4387 Bluetooth chipsets
- Realtek RTL8852BE and RTL8723DS
- Cypress.CYW4373A0 WiFi + Bluetooth combo device
Drivers:
- CAN:
- gs_usb: bus error reporting support
- kvaser_usb: listen only and bus error reporting support
- Ethernet NICs:
- Intel (100G):
- extend action skbedit to RX queue mapping
- implement devlink-rate support
- support direct read from memory
- nVidia/Mellanox (mlx5):
- SW steering improvements, increasing rules update rate
- Support for enhanced events compression
- extend H/W offload packet manipulation capabilities
- implement IPSec packet offload mode
- nVidia/Mellanox (mlx4):
- better big TCP support
- Netronome Ethernet NICs (nfp):
- IPsec offload support
- add support for multicast filter
- Broadcom:
- RSS and PTP support improvements
- AMD/SolarFlare:
- netlink extened ack improvements
- add basic flower matches to offload, and related stats
- Virtual NICs:
- ibmvnic: introduce affinity hint support
- small / embedded:
- FreeScale fec: add initial XDP support
- Marvel mv643xx_eth: support MII/GMII/RGMII modes for Kirkwood
- TI am65-cpsw: add suspend/resume support
- Mediatek MT7986: add RX wireless wthernet dispatch support
- Realtek 8169: enable GRO software interrupt coalescing per
default
- Ethernet high-speed switches:
- Microchip (sparx5):
- add support for Sparx5 TC/flower H/W offload via VCAP
- Mellanox mlxsw:
- add 802.1X and MAC Authentication Bypass offload support
- add ip6gre support
- Embedded Ethernet switches:
- Mediatek (mtk_eth_soc):
- improve PCS implementation, add DSA untag support
- enable flow offload support
- Renesas:
- add rswitch R-Car Gen4 gPTP support
- Microchip (lan966x):
- add full XDP support
- add TC H/W offload via VCAP
- enable PTP on bridge interfaces
- Microchip (ksz8):
- add MTU support for KSZ8 series
- Qualcomm 802.11ax WiFi (ath11k):
- support configuring channel dwell time during scan
- MediaTek WiFi (mt76):
- enable Wireless Ethernet Dispatch (WED) offload support
- add ack signal support
- enable coredump support
- remain_on_channel support
- Intel WiFi (iwlwifi):
- enable Wi-Fi 7 Extremely High Throughput (EHT) PHY capabilities
- 320 MHz channels support
- RealTek WiFi (rtw89):
- new dynamic header firmware format support
- wake-over-WLAN support"
* tag 'net-next-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2002 commits)
ipvs: fix type warning in do_div() on 32 bit
net: lan966x: Remove a useless test in lan966x_ptp_add_trap()
net: ipa: add IPA v4.7 support
dt-bindings: net: qcom,ipa: Add SM6350 compatible
bnxt: Use generic HBH removal helper in tx path
IPv6/GRO: generic helper to remove temporary HBH/jumbo header in driver
selftests: forwarding: Add bridge MDB test
selftests: forwarding: Rename bridge_mdb test
bridge: mcast: Support replacement of MDB port group entries
bridge: mcast: Allow user space to specify MDB entry routing protocol
bridge: mcast: Allow user space to add (*, G) with a source list and filter mode
bridge: mcast: Add support for (*, G) with a source list and filter mode
bridge: mcast: Avoid arming group timer when (S, G) corresponds to a source
bridge: mcast: Add a flag for user installed source entries
bridge: mcast: Expose __br_multicast_del_group_src()
bridge: mcast: Expose br_multicast_new_group_src()
bridge: mcast: Add a centralized error path
bridge: mcast: Place netlink policy before validation functions
bridge: mcast: Split (*, G) and (S, G) addition into different functions
bridge: mcast: Do not derive entry type from its filter mode
...
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7915/mcu.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 495 |
1 files changed, 398 insertions, 97 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 8d297e4aa7d4..b2652de082ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -32,6 +32,10 @@ #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) +static bool sr_scene_detect = true; +module_param(sr_scene_detect, bool, 0644); +MODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm"); + static u8 mt7915_mcu_get_sta_nss(u16 mcs_map) { @@ -228,7 +232,8 @@ mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) c = (struct mt7915_mcu_csa_notify *)skb->data; - if ((c->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((c->band_idx && !dev->phy.mt76->band_idx) && + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, @@ -247,7 +252,8 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) return; - if ((t->ctrl.band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) && + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; phy = (struct mt7915_phy *)mphy->priv; @@ -262,7 +268,8 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) r = (struct mt7915_mcu_rdd_report *)skb->data; - if ((r->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((r->band_idx && !dev->phy.mt76->band_idx) && + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (r->band_idx == MT_RX_SEL2) @@ -319,7 +326,7 @@ mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) b = (struct mt7915_mcu_bcc_notify *)skb->data; - if ((b->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((b->band_idx && !dev->phy.mt76->band_idx) && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, @@ -485,7 +492,7 @@ static void mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) { - int max_nss = hweight8(phy->mt76->chainmask); + int max_nss = hweight8(phy->mt76->antenna_mask); struct bss_info_ra *ra; struct tlv *tlv; @@ -595,7 +602,7 @@ mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif, .mode = !!mask || enable, .entry_count = 1, .write = 1, - .band = phy != &dev->phy, + .band = phy->mt76->band_idx, .index = idx * 2 + bssid, }; @@ -1131,7 +1138,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - bf->ncol_bw160 = nss_mcs; + bf->ncol_gt_bw80 = nss_mcs; } if (pe->phy_cap_info[0] & @@ -1139,10 +1146,10 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - if (bf->ncol_bw160) - bf->ncol_bw160 = min_t(u8, bf->ncol_bw160, nss_mcs); + if (bf->ncol_gt_bw80) + bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs); else - bf->ncol_bw160 = nss_mcs; + bf->ncol_gt_bw80 = nss_mcs; } snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, @@ -1150,7 +1157,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, pe->phy_cap_info[4]); - bf->nrow_bw160 = min_t(int, snd_dim, sts); + bf->nrow_gt_bw80 = min_t(int, snd_dim, sts); } static void @@ -1306,6 +1313,9 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev, case RATE_PARAM_MMPS_UPDATE: ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode); break; + case RATE_PARAM_SPE_UPDATE: + ra->spe_idx = *(u8 *)data; + break; default: break; } @@ -1349,6 +1359,18 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, } static int +mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt76_phy *mphy = mvif->phy->mt76; + u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); + + return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx, + RATE_PARAM_SPE_UPDATE); +} + +static int mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1435,7 +1457,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev, return ret; } - return 0; + return mt7915_mcu_set_spe_idx(dev, vif, sta); } static void @@ -1662,10 +1684,32 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, return ret; } out: + ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); + if (ret) + return ret; + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); } +int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct { + __le32 args[2]; + } req = { + .args[0] = cpu_to_le32(1), + .args[1] = cpu_to_le32(6), + }; + + return mtk_wed_device_update_msg(wed, MTK_WED_WO_CMD_RXCNT_CTRL, + &req, sizeof(req)); +#else + return 0; +#endif +} + int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool enable) { @@ -1674,7 +1718,7 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, struct { struct req_hdr { u8 omac_idx; - u8 dbdc_idx; + u8 band_idx; __le16 tlv_num; u8 is_tlv_append; u8 rsv[3]; @@ -1683,13 +1727,13 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, __le16 tag; __le16 len; u8 active; - u8 dbdc_idx; + u8 band_idx; u8 omac_addr[ETH_ALEN]; } __packed tlv; } data = { .hdr = { .omac_idx = mvif->mt76.omac_idx, - .dbdc_idx = mvif->mt76.band_idx, + .band_idx = mvif->mt76.band_idx, .tlv_num = cpu_to_le16(1), .is_tlv_append = 1, }, @@ -1697,7 +1741,7 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, - .dbdc_idx = mvif->mt76.band_idx, + .band_idx = mvif->mt76.band_idx, }, }; @@ -2151,7 +2195,7 @@ int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms) u8 band_idx; } req = { .cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS), - .band_idx = phy->band_idx, + .band_idx = phy->mt76->band_idx, }; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), @@ -2234,18 +2278,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) sizeof(req), true); } -int mt7915_mcu_init(struct mt7915_dev *dev) +int mt7915_mcu_init_firmware(struct mt7915_dev *dev) { - static const struct mt76_mcu_ops mt7915_mcu_ops = { - .headroom = sizeof(struct mt76_connac2_mcu_txd), - .mcu_skb_send_msg = mt7915_mcu_send_message, - .mcu_parse_response = mt7915_mcu_parse_response, - .mcu_restart = mt76_connac_mcu_restart, - }; int ret; - dev->mt76.mcu_ops = &mt7915_mcu_ops; - /* force firmware operation mode into normal state, * which should be set before firmware download stage. */ @@ -2274,7 +2310,7 @@ int mt7915_mcu_init(struct mt7915_dev *dev) if (ret) return ret; - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && is_mt7915(&dev->mt76)) mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0); ret = mt7915_mcu_set_mwds(dev, 1); @@ -2294,6 +2330,20 @@ int mt7915_mcu_init(struct mt7915_dev *dev) MCU_WA_PARAM_RED, 0, 0); } +int mt7915_mcu_init(struct mt7915_dev *dev) +{ + static const struct mt76_mcu_ops mt7915_mcu_ops = { + .headroom = sizeof(struct mt76_connac2_mcu_txd), + .mcu_skb_send_msg = mt7915_mcu_send_message, + .mcu_parse_response = mt7915_mcu_parse_response, + .mcu_restart = mt76_connac_mcu_restart, + }; + + dev->mt76.mcu_ops = &mt7915_mcu_ops; + + return mt7915_mcu_init_firmware(dev); +} + void mt7915_mcu_exit(struct mt7915_dev *dev) { __mt76_mcu_restart(&dev->mt76); @@ -2538,7 +2588,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy, req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); req.monitor_bw = mt76_connac_chan_bw(chandef); - req.band_idx = phy != &dev->phy; + req.band_idx = phy->mt76->band_idx; req.scan_mode = 1; break; } @@ -2546,7 +2596,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy, req.monitor_chan = chandef->chan->hw_value; req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); - req.band_idx = phy != &dev->phy; + req.band_idx = phy->mt76->band_idx; req.scan_mode = 2; break; case CH_SWITCH_BACKGROUND_SCAN_STOP: @@ -2613,12 +2663,13 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = chandef->center_freq1; + u8 band = phy->mt76->band_idx; struct { u8 control_ch; u8 center_ch; u8 bw; - u8 tx_streams_num; - u8 rx_streams; /* mask or num */ + u8 tx_path_num; + u8 rx_path; /* mask or num */ u8 switch_reason; u8 band_idx; u8 center_ch2; /* for 80+80 only */ @@ -2634,25 +2685,23 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), - .tx_streams_num = hweight8(phy->mt76->antenna_mask), - .rx_streams = phy->mt76->antenna_mask, - .band_idx = phy->band_idx, + .tx_path_num = hweight16(phy->mt76->chainmask), + .rx_path = phy->mt76->chainmask >> (dev->chainshift * band), + .band_idx = band, .channel_band = ch_band[chandef->chan->band], }; #ifdef CONFIG_NL80211_TESTMODE if (phy->mt76->test.tx_antenna_mask && - (phy->mt76->test.state == MT76_TM_STATE_TX_FRAMES || - phy->mt76->test.state == MT76_TM_STATE_RX_FRAMES || - phy->mt76->test.state == MT76_TM_STATE_TX_CONT)) { - req.tx_streams_num = fls(phy->mt76->test.tx_antenna_mask); - req.rx_streams = phy->mt76->test.tx_antenna_mask; - - if (phy != &dev->phy) - req.rx_streams >>= dev->chainshift; + mt76_testmode_enabled(phy->mt76)) { + req.tx_path_num = fls(phy->mt76->test.tx_antenna_mask); + req.rx_path = phy->mt76->test.tx_antenna_mask; } #endif + if (mt76_connac_spe_idx(phy->mt76->antenna_mask)) + req.tx_path_num = fls(phy->mt76->antenna_mask); + if (cmd == MCU_EXT_CMD(SET_RX_PATH) || dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) req.switch_reason = CH_SWITCH_NORMAL; @@ -2665,7 +2714,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) req.switch_reason = CH_SWITCH_NORMAL; if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) - req.rx_streams = hweight8(req.rx_streams); + req.rx_path = hweight8(req.rx_path); if (chandef->width == NL80211_CHAN_WIDTH_80P80) { int freq2 = chandef->center_freq2; @@ -2927,25 +2976,36 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) { /* strict order */ static const u32 offs[] = { - MIB_BUSY_TIME, MIB_TX_TIME, MIB_RX_TIME, MIB_OBSS_AIRTIME, - MIB_BUSY_TIME_V2, MIB_TX_TIME_V2, MIB_RX_TIME_V2, + MIB_NON_WIFI_TIME, + MIB_TX_TIME, + MIB_RX_TIME, + MIB_OBSS_AIRTIME, + MIB_TXOP_INIT_COUNT, + /* v2 */ + MIB_NON_WIFI_TIME_V2, + MIB_TX_TIME_V2, + MIB_RX_TIME_V2, MIB_OBSS_AIRTIME_V2 }; struct mt76_channel_state *state = phy->mt76->chan_state; struct mt76_channel_state *state_ts = &phy->state_ts; struct mt7915_dev *dev = phy->dev; - struct mt7915_mcu_mib *res, req[4]; + struct mt7915_mcu_mib *res, req[5]; struct sk_buff *skb; int i, ret, start = 0, ofs = 20; + u64 cc_tx; if (!is_mt7915(&dev->mt76)) { - start = 4; + start = 5; ofs = 0; } - for (i = 0; i < 4; i++) { - req[i].band = cpu_to_le32(phy != &dev->phy); + for (i = 0; i < 5; i++) { + req[i].band = cpu_to_le32(phy->mt76->band_idx); req[i].offs = cpu_to_le32(offs[i + start]); + + if (!is_mt7915(&dev->mt76) && i == 3) + break; } ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), @@ -2955,20 +3015,24 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) res = (struct mt7915_mcu_mib *)(skb->data + ofs); +#define __res_u64(s) le64_to_cpu(res[s].data) + /* subtract Tx backoff time from Tx duration */ + cc_tx = is_mt7915(&dev->mt76) ? __res_u64(1) - __res_u64(4) : __res_u64(1); + if (chan_switch) goto out; -#define __res_u64(s) le64_to_cpu(res[s].data) - state->cc_busy += __res_u64(0) - state_ts->cc_busy; - state->cc_tx += __res_u64(1) - state_ts->cc_tx; + state->cc_tx += cc_tx - state_ts->cc_tx; state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx; state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx; + state->cc_busy += __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3) - + state_ts->cc_busy; out: - state_ts->cc_busy = __res_u64(0); - state_ts->cc_tx = __res_u64(1); + state_ts->cc_tx = cc_tx; state_ts->cc_bss_rx = __res_u64(2); state_ts->cc_rx = __res_u64(2) + __res_u64(3); + state_ts->cc_busy = __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3); #undef __res_u64 dev_kfree_skb(skb); @@ -2982,11 +3046,11 @@ int mt7915_mcu_get_temperature(struct mt7915_phy *phy) struct { u8 ctrl_id; u8 action; - u8 dbdc_idx; + u8 band_idx; u8 rsv[5]; } req = { .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, - .dbdc_idx = phy != &dev->phy, + .band_idx = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, @@ -3005,7 +3069,7 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) u8 rsv[2]; } __packed req = { .ctrl = { - .band_idx = phy->band_idx, + .band_idx = phy->mt76->band_idx, }, }; int level; @@ -3045,28 +3109,103 @@ out: &req, sizeof(req), false); } -int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) +int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower) { struct mt7915_dev *dev = phy->dev; + struct { + u8 format_id; + u8 rsv; + u8 band_idx; + s8 txpower_min; + } __packed req = { + .format_id = TX_POWER_LIMIT_FRAME_MIN, + .band_idx = phy->mt76->band_idx, + .txpower_min = txpower * 2, /* 0.5db */ + }; + + return mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, + sizeof(req), true); +} + +int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, s8 txpower) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; - struct ieee80211_hw *hw = mphy->hw; - struct mt7915_sku_val { + struct { u8 format_id; - u8 limit_type; - u8 dbdc_idx; - s8 val[MT7915_SKU_RATE_NUM]; + u8 rsv[3]; + u8 band_idx; + s8 txpower_max; + __le16 wcid; + s8 txpower_offs[48]; } __packed req = { - .format_id = 4, - .dbdc_idx = phy != &dev->phy, + .format_id = TX_POWER_LIMIT_FRAME, + .band_idx = phy->mt76->band_idx, + .txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2), + .wcid = cpu_to_le16(msta->wcid.idx), + }; + int ret; + s8 txpower_sku[MT7915_SKU_RATE_NUM]; + + ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku)); + if (ret) + return ret; + + txpower = mt7915_get_power_bound(phy, txpower); + if (txpower > mphy->txpower_cur || txpower < 0) + return -EINVAL; + + if (txpower) { + u32 offs, len, i; + + if (sta->deflink.ht_cap.ht_supported) { + const u8 *sku_len = mt7915_sku_group_len; + + offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM]; + len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40]; + + if (sta->deflink.vht_cap.vht_supported) { + offs += len; + len = sku_len[SKU_VHT_BW20] * 4; + + if (sta->deflink.he_cap.has_he) { + offs += len + sku_len[SKU_HE_RU26] * 3; + len = sku_len[SKU_HE_RU242] * 4; + } + } + } else { + return -EINVAL; + } + + for (i = 0; i < len; i++, offs++) + req.txpower_offs[i] = + DIV_ROUND_UP(txpower - txpower_sku[offs], 2); + } + + return mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, + sizeof(req), true); +} + +int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct mt7915_mcu_txpower_sku req = { + .format_id = TX_POWER_LIMIT_TABLE, + .band_idx = phy->mt76->band_idx, }; struct mt76_power_limits limits_array; s8 *la = (s8 *)&limits_array; - int i, idx, n_chains = hweight8(mphy->antenna_mask); - int tx_power = hw->conf.power_level * 2; + int i, idx; + int tx_power; - tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, - tx_power); - tx_power -= mt76_tx_power_nss_delta(n_chains); + tx_power = mt7915_get_power_bound(phy, hw->conf.power_level); tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, &limits_array, tx_power); mphy->txpower_cur = tx_power; @@ -3085,7 +3224,7 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) } for (j = 0; j < min_t(u8, mcs_num, len); j++) - req.val[idx + j] = la[j]; + req.txpower_sku[idx + j] = la[j]; la += mcs_num; idx += len; @@ -3103,14 +3242,14 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) struct { u8 format_id; u8 category; - u8 band; + u8 band_idx; u8 _rsv; } __packed req = { - .format_id = 7, + .format_id = TX_POWER_LIMIT_INFO, .category = RATE_POWER_INFO, - .band = phy != &dev->phy, + .band_idx = phy->mt76->band_idx, }; - s8 res[MT7915_SKU_RATE_NUM][2]; + s8 txpower_sku[MT7915_SKU_RATE_NUM][2]; struct sk_buff *skb; int ret, i; @@ -3120,9 +3259,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) if (ret) return ret; - memcpy(res, skb->data + 4, sizeof(res)); + memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku)); for (i = 0; i < len; i++) - txpower[i] = res[i][req.band]; + txpower[i] = txpower_sku[i][req.band_idx]; dev_kfree_skb(skb); @@ -3157,11 +3296,11 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) struct mt7915_sku { u8 format_id; u8 sku_enable; - u8 dbdc_idx; + u8 band_idx; u8 rsv; } __packed req = { - .format_id = 0, - .dbdc_idx = phy != &dev->phy, + .format_id = TX_POWER_LIMIT_ENABLE, + .band_idx = phy->mt76->band_idx, .sku_enable = enable, }; @@ -3236,31 +3375,193 @@ int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action) sizeof(req), true); } -int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, - bool enable) +static int +mt7915_mcu_enable_obss_spr(struct mt7915_phy *phy, u8 action, u8 val) +{ + struct mt7915_dev *dev = phy->dev; + struct mt7915_mcu_sr_ctrl req = { + .action = action, + .argnum = 1, + .band_idx = phy->mt76->band_idx, + .val = cpu_to_le32(val), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, + sizeof(req), true); +} + +static int +mt7915_mcu_set_obss_spr_pd(struct mt7915_phy *phy, + struct ieee80211_he_obss_pd *he_obss_pd) +{ + struct mt7915_dev *dev = phy->dev; + struct { + struct mt7915_mcu_sr_ctrl ctrl; + struct { + u8 pd_th_non_srg; + u8 pd_th_srg; + u8 period_offs; + u8 rcpi_src; + __le16 obss_pd_min; + __le16 obss_pd_min_srg; + u8 resp_txpwr_mode; + u8 txpwr_restrict_mode; + u8 txpwr_ref; + u8 rsv[3]; + } __packed param; + } __packed req = { + .ctrl = { + .action = SPR_SET_PARAM, + .argnum = 9, + .band_idx = phy->mt76->band_idx, + }, + }; + int ret; + u8 max_th = 82, non_srg_max_th = 62; + + /* disable firmware dynamical PD asjustment */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_DPD, false); + if (ret) + return ret; + + if (he_obss_pd->sr_ctrl & + IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED) + req.param.pd_th_non_srg = max_th; + else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) + req.param.pd_th_non_srg = max_th - he_obss_pd->non_srg_max_offset; + else + req.param.pd_th_non_srg = non_srg_max_th; + + if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) + req.param.pd_th_srg = max_th - he_obss_pd->max_offset; + + req.param.obss_pd_min = cpu_to_le16(82); + req.param.obss_pd_min_srg = cpu_to_le16(82); + req.param.txpwr_restrict_mode = 2; + req.param.txpwr_ref = 21; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, + sizeof(req), true); +} + +static int +mt7915_mcu_set_obss_spr_siga(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd) { -#define MT_SPR_ENABLE 1 struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = phy->dev; + u8 omac = mvif->mt76.omac_idx; struct { - u8 action; - u8 arg_num; - u8 band_idx; - u8 status; - u8 drop_tx_idx; - u8 sta_idx; /* 256 sta */ - u8 rsv[2]; - __le32 val; + struct mt7915_mcu_sr_ctrl ctrl; + struct { + u8 omac; + u8 rsv[3]; + u8 flag[20]; + } __packed siga; + } __packed req = { + .ctrl = { + .action = SPR_SET_SIGA, + .argnum = 1, + .band_idx = phy->mt76->band_idx, + }, + .siga = { + .omac = omac > HW_BSSID_MAX ? omac - 12 : omac, + }, + }; + int ret; + + if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED) + req.siga.flag[req.siga.omac] = 0xf; + else + return 0; + + /* switch to normal AP mode */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_MODE, 0); + if (ret) + return ret; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, + sizeof(req), true); +} + +static int +mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy *phy, + struct ieee80211_he_obss_pd *he_obss_pd) +{ + struct mt7915_dev *dev = phy->dev; + struct { + struct mt7915_mcu_sr_ctrl ctrl; + struct { + __le32 color_l[2]; + __le32 color_h[2]; + __le32 bssid_l[2]; + __le32 bssid_h[2]; + } __packed bitmap; } __packed req = { - .action = MT_SPR_ENABLE, - .arg_num = 1, - .band_idx = mvif->mt76.band_idx, - .val = cpu_to_le32(enable), + .ctrl = { + .action = SPR_SET_SRG_BITMAP, + .argnum = 4, + .band_idx = phy->mt76->band_idx, + }, }; + u32 bitmap; + + memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap)); + req.bitmap.color_l[req.ctrl.band_idx] = cpu_to_le32(bitmap); + + memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap)); + req.bitmap.color_h[req.ctrl.band_idx] = cpu_to_le32(bitmap); + + memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap)); + req.bitmap.bssid_l[req.ctrl.band_idx] = cpu_to_le32(bitmap); + + memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap)); + req.bitmap.bssid_h[req.ctrl.band_idx] = cpu_to_le32(bitmap); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, sizeof(req), true); } +int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd) +{ + int ret; + + /* enable firmware scene detection algorithms */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_SD, sr_scene_detect); + if (ret) + return ret; + + /* firmware dynamically adjusts PD threshold so skip manual control */ + if (sr_scene_detect && !he_obss_pd->enable) + return 0; + + /* enable spatial reuse */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE, he_obss_pd->enable); + if (ret) + return ret; + + if (sr_scene_detect || !he_obss_pd->enable) + return 0; + + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_TX, true); + if (ret) + return ret; + + /* set SRG/non-SRG OBSS PD threshold */ + ret = mt7915_mcu_set_obss_spr_pd(phy, he_obss_pd); + if (ret) + return ret; + + /* Set SR prohibit */ + ret = mt7915_mcu_set_obss_spr_siga(phy, vif, he_obss_pd); + if (ret) + return ret; + + /* set SRG BSS color/BSSID bitmap */ + return mt7915_mcu_set_obss_spr_bitmap(phy, he_obss_pd); +} + int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate) { @@ -3447,8 +3748,8 @@ int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set) __le32 ofs; __le32 data; } __packed req = { - .idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 28))), - .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(27, 0))), + .idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 24))), + .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))), .data = set ? cpu_to_le32(*val) : 0, }; struct sk_buff *skb; |