diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-21 18:24:12 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-21 18:24:12 -0800 |
commit | 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 (patch) | |
tree | cc5c2d0a898769fd59549594fedb3ee6f84e59a0 /drivers/net/wireless/realtek | |
parent | 36289a03bcd3aabdf66de75cb6d1b4ee15726438 (diff) | |
parent | d1fabc68f8e0541d41657096dc713cb01775652d (diff) |
Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Jakub Kicinski:
"Core:
- Add dedicated kmem_cache for typical/small skb->head, avoid having
to access struct page at kfree time, and improve memory use.
- Introduce sysctl to set default RPS configuration for new netdevs.
- Define Netlink protocol specification format which can be used to
describe messages used by each family and auto-generate parsers.
Add tools for generating kernel data structures and uAPI headers.
- Expose all net/core sysctls inside netns.
- Remove 4s sleep in netpoll if carrier is instantly detected on
boot.
- Add configurable limit of MDB entries per port, and port-vlan.
- Continue populating drop reasons throughout the stack.
- Retire a handful of legacy Qdiscs and classifiers.
Protocols:
- Support IPv4 big TCP (TSO frames larger than 64kB).
- Add IP_LOCAL_PORT_RANGE socket option, to control local port range
on socket by socket basis.
- Track and report in procfs number of MPTCP sockets used.
- Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path
manager.
- IPv6: don't check net.ipv6.route.max_size and rely on garbage
collection to free memory (similarly to IPv4).
- Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986).
- ICMP: add per-rate limit counters.
- Add support for user scanning requests in ieee802154.
- Remove static WEP support.
- Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate
reporting.
- WiFi 7 EHT channel puncturing support (client & AP).
BPF:
- Add a rbtree data structure following the "next-gen data structure"
precedent set by recently added linked list, that is, by using
kfunc + kptr instead of adding a new BPF map type.
- Expose XDP hints via kfuncs with initial support for RX hash and
timestamp metadata.
- Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to
better support decap on GRE tunnel devices not operating in collect
metadata.
- Improve x86 JIT's codegen for PROBE_MEM runtime error checks.
- Remove the need for trace_printk_lock for bpf_trace_printk and
bpf_trace_vprintk helpers.
- Extend libbpf's bpf_tracing.h support for tracing arguments of
kprobes/uprobes and syscall as a special case.
- Significantly reduce the search time for module symbols by
livepatch and BPF.
- Enable cpumasks to be used as kptrs, which is useful for tracing
programs tracking which tasks end up running on which CPUs in
different time intervals.
- Add support for BPF trampoline on s390x and riscv64.
- Add capability to export the XDP features supported by the NIC.
- Add __bpf_kfunc tag for marking kernel functions as kfuncs.
- Add cgroup.memory=nobpf kernel parameter option to disable BPF
memory accounting for container environments.
Netfilter:
- Remove the CLUSTERIP target. It has been marked as obsolete for
years, and we still have WARN splats wrt races of the out-of-band
/proc interface installed by this target.
- Add 'destroy' commands to nf_tables. They are identical to the
existing 'delete' commands, but do not return an error if the
referenced object (set, chain, rule...) did not exist.
Driver API:
- Improve cpumask_local_spread() locality to help NICs set the right
IRQ affinity on AMD platforms.
- Separate C22 and C45 MDIO bus transactions more clearly.
- Introduce new DCB table to control DSCP rewrite on egress.
- Support configuration of Physical Layer Collision Avoidance (PLCA)
Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of
shared medium Ethernet.
- Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing
preemption of low priority frames by high priority frames.
- Add support for controlling MACSec offload using netlink SET.
- Rework devlink instance refcounts to allow registration and
de-registration under the instance lock. Split the code into
multiple files, drop some of the unnecessarily granular locks and
factor out common parts of netlink operation handling.
- Add TX frame aggregation parameters (for USB drivers).
- Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning
messages with notifications for debug.
- Allow offloading of UDP NEW connections via act_ct.
- Add support for per action HW stats in TC.
- Support hardware miss to TC action (continue processing in SW from
a specific point in the action chain).
- Warn if old Wireless Extension user space interface is used with
modern cfg80211/mac80211 drivers. Do not support Wireless
Extensions for Wi-Fi 7 devices at all. Everyone should switch to
using nl80211 interface instead.
- Improve the CAN bit timing configuration. Use extack to return
error messages directly to user space, update the SJW handling,
including the definition of a new default value that will benefit
CAN-FD controllers, by increasing their oscillator tolerance.
New hardware / drivers:
- Ethernet:
- nVidia BlueField-3 support (control traffic driver)
- Ethernet support for imx93 SoCs
- Motorcomm yt8531 gigabit Ethernet PHY
- onsemi NCN26000 10BASE-T1S PHY (with support for PLCA)
- Microchip LAN8841 PHY (incl. cable diagnostics and PTP)
- Amlogic gxl MDIO mux
- WiFi:
- RealTek RTL8188EU (rtl8xxxu)
- Qualcomm Wi-Fi 7 devices (ath12k)
- CAN:
- Renesas R-Car V4H
Drivers:
- Bluetooth:
- Set Per Platform Antenna Gain (PPAG) for Intel controllers.
- Ethernet NICs:
- Intel (1G, igc):
- support TSN / Qbv / packet scheduling features of i226 model
- Intel (100G, ice):
- use GNSS subsystem instead of TTY
- multi-buffer XDP support
- extend support for GPIO pins to E823 devices
- nVidia/Mellanox:
- update the shared buffer configuration on PFC commands
- implement PTP adjphase function for HW offset control
- TC support for Geneve and GRE with VF tunnel offload
- more efficient crypto key management method
- multi-port eswitch support
- Netronome/Corigine:
- add DCB IEEE support
- support IPsec offloading for NFP3800
- Freescale/NXP (enetc):
- support XDP_REDIRECT for XDP non-linear buffers
- improve reconfig, avoid link flap and waiting for idle
- support MAC Merge layer
- Other NICs:
- sfc/ef100: add basic devlink support for ef100
- ionic: rx_push mode operation (writing descriptors via MMIO)
- bnxt: use the auxiliary bus abstraction for RDMA
- r8169: disable ASPM and reset bus in case of tx timeout
- cpsw: support QSGMII mode for J721e CPSW9G
- cpts: support pulse-per-second output
- ngbe: add an mdio bus driver
- usbnet: optimize usbnet_bh() by avoiding unnecessary queuing
- r8152: handle devices with FW with NCM support
- amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation
- virtio-net: support multi buffer XDP
- virtio/vsock: replace virtio_vsock_pkt with sk_buff
- tsnep: XDP support
- Ethernet high-speed switches:
- nVidia/Mellanox (mlxsw):
- add support for latency TLV (in FW control messages)
- Microchip (sparx5):
- separate explicit and implicit traffic forwarding rules, make
the implicit rules always active
- add support for egress DSCP rewrite
- IS0 VCAP support (Ingress Classification)
- IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS
etc.)
- ES2 VCAP support (Egress Access Control)
- support for Per-Stream Filtering and Policing (802.1Q,
8.6.5.1)
- Ethernet embedded switches:
- Marvell (mv88e6xxx):
- add MAB (port auth) offload support
- enable PTP receive for mv88e6390
- NXP (ocelot):
- support MAC Merge layer
- support for the the vsc7512 internal copper phys
- Microchip:
- lan9303: convert to PHYLINK
- lan966x: support TC flower filter statistics
- lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x
- lan937x: support Credit Based Shaper configuration
- ksz9477: support Energy Efficient Ethernet
- other:
- qca8k: convert to regmap read/write API, use bulk operations
- rswitch: Improve TX timestamp accuracy
- Intel WiFi (iwlwifi):
- EHT (Wi-Fi 7) rate reporting
- STEP equalizer support: transfer some STEP (connection to radio
on platforms with integrated wifi) related parameters from the
BIOS to the firmware.
- Qualcomm 802.11ax WiFi (ath11k):
- IPQ5018 support
- Fine Timing Measurement (FTM) responder role support
- channel 177 support
- MediaTek WiFi (mt76):
- per-PHY LED support
- mt7996: EHT (Wi-Fi 7) support
- Wireless Ethernet Dispatch (WED) reset support
- switch to using page pool allocator
- RealTek WiFi (rtw89):
- support new version of Bluetooth co-existance
- Mobile:
- rmnet: support TX aggregation"
* tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits)
page_pool: add a comment explaining the fragment counter usage
net: ethtool: fix __ethtool_dev_mm_supported() implementation
ethtool: pse-pd: Fix double word in comments
xsk: add linux/vmalloc.h to xsk.c
sefltests: netdevsim: wait for devlink instance after netns removal
selftest: fib_tests: Always cleanup before exit
net/mlx5e: Align IPsec ASO result memory to be as required by hardware
net/mlx5e: TC, Set CT miss to the specific ct action instance
net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG
net/mlx5: Refactor tc miss handling to a single function
net/mlx5: Kconfig: Make tc offload depend on tc skb extension
net/sched: flower: Support hardware miss to tc action
net/sched: flower: Move filter handle initialization earlier
net/sched: cls_api: Support hardware miss to tc action
net/sched: Rename user cookie and act cookie
sfc: fix builds without CONFIG_RTC_LIB
sfc: clean up some inconsistent indentings
net/mlx4_en: Introduce flexible array to silence overflow warning
net: lan966x: Fix possible deadlock inside PTP
net/ulp: Remove redundant ->clone() test in inet_clone_ulp().
...
Diffstat (limited to 'drivers/net/wireless/realtek')
54 files changed, 4869 insertions, 1171 deletions
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig index 631d078278be..2eed20b0988c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig +++ b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig @@ -5,12 +5,13 @@ config RTL8XXXU tristate "Realtek 802.11n USB wireless chips support" depends on MAC80211 && USB + depends on LEDS_CLASS help This is an alternative driver for various Realtek RTL8XXX parts written to utilize the Linux mac80211 stack. The driver is known to work with a number of RTL8723AU, RL8188CU, RTL8188RU, RTL8191CU, RTL8192CU, RTL8723BU, RTL8192EU, - and RTL8188FU devices. + RTL8188FU, and RTL8188EU devices. This driver is under development and has a limited feature set. In particular it does not yet support 40MHz channels diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Makefile b/drivers/net/wireless/realtek/rtl8xxxu/Makefile index c4ad5325f5e7..0cb58fb30228 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/Makefile +++ b/drivers/net/wireless/realtek/rtl8xxxu/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o rtl8xxxu-y := rtl8xxxu_core.o rtl8xxxu_8192e.o rtl8xxxu_8723b.o \ - rtl8xxxu_8723a.o rtl8xxxu_8192c.o rtl8xxxu_8188f.o + rtl8xxxu_8723a.o rtl8xxxu_8192c.o rtl8xxxu_8188f.o \ + rtl8xxxu_8188e.o diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index d26df4095da0..c8cee4a24755 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -36,6 +36,7 @@ #define TX_TOTAL_PAGE_NUM 0xf8 #define TX_TOTAL_PAGE_NUM_8188F 0xf7 +#define TX_TOTAL_PAGE_NUM_8188E 0xa9 #define TX_TOTAL_PAGE_NUM_8192E 0xf3 #define TX_TOTAL_PAGE_NUM_8723B 0xf7 /* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */ @@ -49,6 +50,11 @@ #define TX_PAGE_NUM_LO_PQ_8188F 0x02 #define TX_PAGE_NUM_NORM_PQ_8188F 0x02 +#define TX_PAGE_NUM_PUBQ_8188E 0x47 +#define TX_PAGE_NUM_HI_PQ_8188E 0x29 +#define TX_PAGE_NUM_LO_PQ_8188E 0x1c +#define TX_PAGE_NUM_NORM_PQ_8188E 0x1c + #define TX_PAGE_NUM_PUBQ_8192E 0xe7 #define TX_PAGE_NUM_HI_PQ_8192E 0x08 #define TX_PAGE_NUM_LO_PQ_8192E 0x0c @@ -153,7 +159,8 @@ struct rtl8xxxu_rxdesc16 { u32 htc:1; u32 eosp:1; u32 bssidfit:2; - u32 reserved1:16; + u32 rpt_sel:2; /* 8188e */ + u32 reserved1:14; u32 unicastwake:1; u32 magicwake:1; @@ -211,7 +218,8 @@ struct rtl8xxxu_rxdesc16 { u32 magicwake:1; u32 unicastwake:1; - u32 reserved1:16; + u32 reserved1:14; + u32 rpt_sel:2; /* 8188e */ u32 bssidfit:2; u32 eosp:1; u32 htc:1; @@ -502,6 +510,8 @@ struct rtl8xxxu_txdesc40 { #define TXDESC_AMPDU_DENSITY_SHIFT 20 #define TXDESC40_BT_INT BIT(23) #define TXDESC40_GID_SHIFT 24 +#define TXDESC_ANTENNA_SELECT_A BIT(24) +#define TXDESC_ANTENNA_SELECT_B BIT(25) /* Word 3 */ #define TXDESC40_USE_DRIVER_RATE BIT(8) @@ -521,6 +531,7 @@ struct rtl8xxxu_txdesc40 { #define TXDESC32_CTS_SELF_ENABLE BIT(11) #define TXDESC32_RTS_CTS_ENABLE BIT(12) #define TXDESC32_HW_RTS_ENABLE BIT(13) +#define TXDESC32_PT_STAGE_MASK GENMASK(17, 15) #define TXDESC_PRIME_CH_OFF_LOWER BIT(20) #define TXDESC_PRIME_CH_OFF_UPPER BIT(21) #define TXDESC32_SHORT_PREAMBLE BIT(24) @@ -546,6 +557,10 @@ struct rtl8xxxu_txdesc40 { /* Word 6 */ #define TXDESC_MAX_AGG_SHIFT 11 +#define TXDESC_USB_TX_AGG_SHIT 24 + +/* Word 7 */ +#define TXDESC_ANTENNA_SELECT_C BIT(29) /* Word 8 */ #define TXDESC40_HW_SEQ_ENABLE BIT(15) @@ -562,6 +577,9 @@ struct phy_rx_agc_info { #endif }; +#define CCK_AGC_RPT_LNA_IDX_MASK GENMASK(7, 5) +#define CCK_AGC_RPT_VGA_IDX_MASK GENMASK(4, 0) + struct rtl8723au_phy_stats { struct phy_rx_agc_info path_agc[RTL8723A_MAX_RF_PATHS]; u8 ch_corr[RTL8723A_MAX_RF_PATHS]; @@ -909,6 +927,42 @@ struct rtl8188fu_efuse { u8 res11[0xc3]; }; +struct rtl8188eu_efuse { + __le16 rtl_id; + u8 res0[0x0e]; + struct rtl8192eu_efuse_tx_power tx_power_index_A; /* 0x10 */ + u8 res1[0x7e]; /* 0x3a */ + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; + u8 thermal_meter; + u8 iqk_lck; + u8 res2[5]; + u8 rf_board_option; + u8 rf_feature_option; + u8 rf_bt_setting; + u8 eeprom_version; + u8 eeprom_customer_id; + u8 res3[3]; + u8 rf_antenna_option; /* 0xc9 */ + u8 res4[6]; + u8 vid; /* 0xd0 */ + u8 res5[1]; + u8 pid; /* 0xd2 */ + u8 res6[1]; + u8 usb_optional_function; + u8 res7[2]; + u8 mac_addr[ETH_ALEN]; /* 0xd7 */ + u8 res8[2]; + u8 vendor_name[7]; + u8 res9[2]; + u8 device_name[0x0b]; /* 0xe8 */ + u8 res10[2]; + u8 serial[0x0b]; /* 0xf5 */ + u8 res11[0x30]; + u8 unknown[0x0d]; /* 0x130 */ + u8 res12[0xc3]; +} __packed; + struct rtl8xxxu_reg8val { u16 reg; u8 val; @@ -1114,6 +1168,26 @@ struct h2c_cmd { u8 cmd; u8 data; } __packed bt_grant; + struct { + u8 cmd; + u8 macid; + u8 unknown0; + u8 rssi; + /* + * [0] - is_rx + * [1] - stbc_en + * [2] - noisy_decision + * [6] - bf_en + */ + u8 data; + /* + * [0:6] - ra_th_offset + * [7] - ra_offset_direction + */ + u8 ra_th_offset; + u8 unknown1; + u8 unknown2; + } __packed rssi_report; }; }; @@ -1323,6 +1397,39 @@ struct rtl8xxxu_ra_report { u8 desc_rate; }; +struct rtl8xxxu_ra_info { + u8 rate_id; + u32 rate_mask; + u32 ra_use_rate; + u8 rate_sgi; + u8 rssi_sta_ra; /* Percentage */ + u8 pre_rssi_sta_ra; + u8 sgi_enable; + u8 decision_rate; + u8 pre_rate; + u8 highest_rate; + u8 lowest_rate; + u32 nsc_up; + u32 nsc_down; + u32 total; + u16 retry[5]; + u16 drop; + u16 rpt_time; + u16 pre_min_rpt_time; + u8 dynamic_tx_rpt_timing_counter; + u8 ra_waiting_counter; + u8 ra_pending_counter; + u8 ra_drop_after_down; + u8 pt_try_state; /* 0 trying state, 1 for decision state */ + u8 pt_stage; /* 0~6 */ + u8 pt_stop_count; /* Stop PT counter */ + u8 pt_pre_rate; /* if rate change do PT */ + u8 pt_pre_rssi; /* if RSSI change 5% do PT */ + u8 pt_mode_ss; /* decide which rate should do PT */ + u8 ra_stage; /* StageRA, decide how many times RA will be done between PT */ + u8 pt_smooth_factor; +}; + #define CFO_TH_XTAL_HIGH 20 /* kHz */ #define CFO_TH_XTAL_LOW 10 /* kHz */ #define CFO_TH_ATC 80 /* kHz */ @@ -1336,6 +1443,8 @@ struct rtl8xxxu_cfo_tracking { u32 packet_count_pre; }; +#define RTL8XXXU_HW_LED_CONTROL 2 + struct rtl8xxxu_priv { struct ieee80211_hw *hw; struct usb_device *udev; @@ -1432,6 +1541,7 @@ struct rtl8xxxu_priv { struct rtl8192cu_efuse efuse8192; struct rtl8192eu_efuse efuse8192eu; struct rtl8188fu_efuse efuse8188fu; + struct rtl8188eu_efuse efuse8188eu; } efuse_wifi; u32 adda_backup[RTL8XXXU_ADDA_REGS]; u32 mac_backup[RTL8XXXU_MAC_REGS]; @@ -1455,6 +1565,11 @@ struct rtl8xxxu_priv { struct rtl8xxxu_btcoex bt_coex; struct rtl8xxxu_ra_report ra_report; struct rtl8xxxu_cfo_tracking cfo_tracking; + struct rtl8xxxu_ra_info ra_info; + + bool led_registered; + char led_name[32]; + struct led_classdev led_cdev; }; struct rtl8xxxu_rx_urb { @@ -1496,6 +1611,7 @@ struct rtl8xxxu_fileops { u32 ramask, u8 rateid, int sgi, int txbw_40mhz); void (*report_connect) (struct rtl8xxxu_priv *priv, u8 macid, bool connect); + void (*report_rssi) (struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, @@ -1503,6 +1619,8 @@ struct rtl8xxxu_fileops { u32 rts_rate); void (*set_crystal_cap) (struct rtl8xxxu_priv *priv, u8 crystal_cap); s8 (*cck_rssi) (struct rtl8xxxu_priv *priv, u8 cck_agc_rpt); + int (*led_classdev_brightness_set) (struct led_classdev *led_cdev, + enum led_brightness brightness); int writeN_block_size; int rx_agg_buf_size; char tx_desc_size; @@ -1523,6 +1641,7 @@ struct rtl8xxxu_fileops { u8 page_num_hi; u8 page_num_lo; u8 page_num_norm; + u8 last_llt_entry; }; extern int rtl8xxxu_debug; @@ -1560,7 +1679,7 @@ int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv, enum rtl8xxxu_rfpath path); int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv, const struct rtl8xxxu_reg32val *array); -int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name); +int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, const char *fw_name); void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv); void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv); void rtl8xxxu_identify_vendor_1bit(struct rtl8xxxu_priv *priv, u32 vendor); @@ -1582,6 +1701,8 @@ void rtl8xxxu_gen1_phy_iq_calibrate(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_init_phy_bb(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40); +void rtl8188f_set_tx_power(struct rtl8xxxu_priv *priv, + int channel, bool ht40); void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw); void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw); void rtl8xxxu_gen1_usb_quirks(struct rtl8xxxu_priv *priv); @@ -1594,6 +1715,8 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); +void rtl8xxxu_gen1_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); +void rtl8xxxu_gen2_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_enable_rf(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_disable_rf(struct rtl8xxxu_priv *priv); @@ -1602,6 +1725,8 @@ void rtl8xxxu_init_burst(struct rtl8xxxu_priv *priv); int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb); int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb); int rtl8xxxu_gen2_channel_to_group(int channel); +bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2); bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv, int result[][8], int c1, int c2); void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, @@ -1614,13 +1739,24 @@ void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, bool short_preamble, bool ampdu_enable, u32 rts_rate); +void rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + struct ieee80211_tx_info *tx_info, + struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, + bool short_preamble, bool ampdu_enable, + u32 rts_rate); void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5); void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv); void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap); +void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap); s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt); +void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt, + u8 rate, u8 sgi, u8 bw); +void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra); +void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb); extern struct rtl8xxxu_fileops rtl8188fu_fops; +extern struct rtl8xxxu_fileops rtl8188eu_fops; extern struct rtl8xxxu_fileops rtl8192cu_fops; extern struct rtl8xxxu_fileops rtl8192eu_fops; extern struct rtl8xxxu_fileops rtl8723au_fops; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c new file mode 100644 index 000000000000..a99ddb41cd24 --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c @@ -0,0 +1,1899 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RTL8XXXU mac80211 USB driver - 8188e specific subdriver + * + * Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@gmail.com> + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This driver was written as a replacement for the vendor provided + * rtl8723au driver. As the Realtek 8xxx chips are very similar in + * their programming interface, I have started adding support for + * additional 8xxx chips like the 8192cu, 8188cus, etc. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/usb.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/wireless.h> +#include <linux/firmware.h> +#include <linux/moduleparam.h> +#include <net/mac80211.h> +#include "rtl8xxxu.h" +#include "rtl8xxxu_regs.h" + +static const struct rtl8xxxu_reg8val rtl8188e_mac_init_table[] = { + {0x026, 0x41}, {0x027, 0x35}, {0x040, 0x00}, {0x421, 0x0f}, + {0x428, 0x0a}, {0x429, 0x10}, {0x430, 0x00}, {0x431, 0x01}, + {0x432, 0x02}, {0x433, 0x04}, {0x434, 0x05}, {0x435, 0x06}, + {0x436, 0x07}, {0x437, 0x08}, {0x438, 0x00}, {0x439, 0x00}, + {0x43a, 0x01}, {0x43b, 0x02}, {0x43c, 0x04}, {0x43d, 0x05}, + {0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01}, + {0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f}, + {0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72}, + {0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x480, 0x08}, + {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff}, {0x4cd, 0xff}, + {0x4ce, 0x01}, {0x4d3, 0x01}, {0x500, 0x26}, {0x501, 0xa2}, + {0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3}, + {0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4}, + {0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4}, + {0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a}, + {0x516, 0x0a}, {0x525, 0x4f}, {0x550, 0x10}, {0x551, 0x10}, + {0x559, 0x02}, {0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, + {0x609, 0x2a}, {0x620, 0xff}, {0x621, 0xff}, {0x622, 0xff}, + {0x623, 0xff}, {0x624, 0xff}, {0x625, 0xff}, {0x626, 0xff}, + {0x627, 0xff}, {0x63c, 0x08}, {0x63d, 0x08}, {0x63e, 0x0c}, + {0x63f, 0x0c}, {0x640, 0x40}, {0x652, 0x20}, {0x66e, 0x05}, + {0x700, 0x21}, {0x701, 0x43}, {0x702, 0x65}, {0x703, 0x87}, + {0x708, 0x21}, {0x709, 0x43}, {0x70a, 0x65}, {0x70b, 0x87}, + {0xffff, 0xff}, +}; + +static const struct rtl8xxxu_reg32val rtl8188eu_phy_init_table[] = { + {0x800, 0x80040000}, {0x804, 0x00000003}, + {0x808, 0x0000fc00}, {0x80c, 0x0000000a}, + {0x810, 0x10001331}, {0x814, 0x020c3d10}, + {0x818, 0x02200385}, {0x81c, 0x00000000}, + {0x820, 0x01000100}, {0x824, 0x00390204}, + {0x828, 0x00000000}, {0x82c, 0x00000000}, + {0x830, 0x00000000}, {0x834, 0x00000000}, + {0x838, 0x00000000}, {0x83c, 0x00000000}, + {0x840, 0x00010000}, {0x844, 0x00000000}, + {0x848, 0x00000000}, {0x84c, 0x00000000}, + {0x850, 0x00000000}, {0x854, 0x00000000}, + {0x858, 0x569a11a9}, {0x85c, 0x01000014}, + {0x860, 0x66f60110}, {0x864, 0x061f0649}, + {0x868, 0x00000000}, {0x86c, 0x27272700}, + {0x870, 0x07000760}, {0x874, 0x25004000}, + {0x878, 0x00000808}, {0x87c, 0x00000000}, + {0x880, 0xb0000c1c}, {0x884, 0x00000001}, + {0x888, 0x00000000}, {0x88c, 0xccc000c0}, + {0x890, 0x00000800}, {0x894, 0xfffffffe}, + {0x898, 0x40302010}, {0x89c, 0x00706050}, + {0x900, 0x00000000}, {0x904, 0x00000023}, + {0x908, 0x00000000}, {0x90c, 0x81121111}, + {0x910, 0x00000002}, {0x914, 0x00000201}, + {0xa00, 0x00d047c8}, {0xa04, 0x80ff800c}, + {0xa08, 0x8c838300}, {0xa0c, 0x2e7f120f}, + {0xa10, 0x9500bb7e}, {0xa14, 0x1114d028}, + {0xa18, 0x00881117}, {0xa1c, 0x89140f00}, + {0xa20, 0x1a1b0000}, {0xa24, 0x090e1317}, + {0xa28, 0x00000204}, {0xa2c, 0x00d30000}, + {0xa70, 0x101fbf00}, {0xa74, 0x00000007}, + {0xa78, 0x00000900}, {0xa7c, 0x225b0606}, + {0xa80, 0x218075b1}, {0xb2c, 0x80000000}, + {0xc00, 0x48071d40}, {0xc04, 0x03a05611}, + {0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c}, + {0xc10, 0x08800000}, {0xc14, 0x40000100}, + {0xc18, 0x08800000}, {0xc1c, 0x40000100}, + {0xc20, 0x00000000}, {0xc24, 0x00000000}, + {0xc28, 0x00000000}, {0xc2c, 0x00000000}, + {0xc30, 0x69e9ac47}, {0xc34, 0x469652af}, + {0xc38, 0x49795994}, {0xc3c, 0x0a97971c}, + {0xc40, 0x1f7c403f}, {0xc44, 0x000100b7}, + {0xc48, 0xec020107}, {0xc4c, 0x007f037f}, + {0xc50, 0x69553420}, {0xc54, 0x43bc0094}, + {0xc58, 0x00013169}, {0xc5c, 0x00250492}, + {0xc60, 0x00000000}, {0xc64, 0x7112848b}, + {0xc68, 0x47c00bff}, {0xc6c, 0x00000036}, + {0xc70, 0x2c7f000d}, {0xc74, 0x020610db}, + {0xc78, 0x0000001f}, {0xc7c, 0x00b91612}, + {0xc80, 0x390000e4}, {0xc84, 0x21f60000}, + {0xc88, 0x40000100}, {0xc8c, 0x20200000}, + {0xc90, 0x00091521}, {0xc94, 0x00000000}, + {0xc98, 0x00121820}, {0xc9c, 0x00007f7f}, + {0xca0, 0x00000000}, {0xca4, 0x000300a0}, + {0xca8, 0x00000000}, {0xcac, 0x00000000}, + {0xcb0, 0x00000000}, {0xcb4, 0x00000000}, + {0xcb8, 0x00000000}, {0xcbc, 0x28000000}, + {0xcc0, 0x00000000}, {0xcc4, 0x00000000}, + {0xcc8, 0x00000000}, {0xccc, 0x00000000}, + {0xcd0, 0x00000000}, {0xcd4, 0x00000000}, + {0xcd8, 0x64b22427}, {0xcdc, 0x00766932}, + {0xce0, 0x00222222}, {0xce4, 0x00000000}, + {0xce8, 0x37644302}, {0xcec, 0x2f97d40c}, + {0xd00, 0x00000740}, {0xd04, 0x00020401}, + {0xd08, 0x0000907f}, {0xd0c, 0x20010201}, + {0xd10, 0xa0633333}, {0xd14, 0x3333bc43}, + {0xd18, 0x7a8f5b6f}, {0xd2c, 0xcc979975}, + {0xd30, 0x00000000}, {0xd34, 0x80608000}, + {0xd38, 0x00000000}, {0xd3c, 0x00127353}, + {0xd40, 0x00000000}, {0xd44, 0x00000000}, + {0xd48, 0x00000000}, {0xd4c, 0x00000000}, + {0xd50, 0x6437140a}, {0xd54, 0x00000000}, + {0xd58, 0x00000282}, {0xd5c, 0x30032064}, + {0xd60, 0x4653de68}, {0xd64, 0x04518a3c}, + {0xd68, 0x00002101}, {0xd6c, 0x2a201c16}, + {0xd70, 0x1812362e}, {0xd74, 0x322c2220}, + {0xd78, 0x000e3c24}, {0xe00, 0x2d2d2d2d}, + {0xe04, 0x2d2d2d2d}, {0xe08, 0x0390272d}, + {0xe10, 0x2d2d2d2d}, {0xe14, 0x2d2d2d2d}, + {0xe18, 0x2d2d2d2d}, {0xe1c, 0x2d2d2d2d}, + {0xe28, 0x00000000}, {0xe30, 0x1000dc1f}, + {0xe34, 0x10008c1f}, {0xe38, 0x02140102}, + {0xe3c, 0x681604c2}, {0xe40, 0x01007c00}, + {0xe44, 0x01004800}, {0xe48, 0xfb000000}, + {0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f}, + {0xe54, 0x10008c1f}, {0xe58, 0x02140102}, + {0xe5c, 0x28160d05}, {0xe60, 0x00000048}, + {0xe68, 0x001b25a4}, {0xe6c, 0x00c00014}, + {0xe70, 0x00c00014}, {0xe74, 0x01000014}, + {0xe78, 0x01000014}, {0xe7c, 0x01000014}, + {0xe80, 0x01000014}, {0xe84, 0x00c00014}, + {0xe88, 0x01000014}, {0xe8c, 0x00c00014}, + {0xed0, 0x00c00014}, {0xed4, 0x00c00014}, + {0xed8, 0x00c00014}, {0xedc, 0x00000014}, + {0xee0, 0x00000014}, {0xee8, 0x21555448}, + {0xeec, 0x01c00014}, {0xf14, 0x00000003}, + {0xf4c, 0x00000000}, {0xf00, 0x00000300}, + {0xffff, 0xffffffff}, +}; + +static const struct rtl8xxxu_reg32val rtl8188e_agc_table[] = { + {0xc78, 0xfb000001}, {0xc78, 0xfb010001}, + {0xc78, 0xfb020001}, {0xc78, 0xfb030001}, + {0xc78, 0xfb040001}, {0xc78, 0xfb050001}, + {0xc78, 0xfa060001}, {0xc78, 0xf9070001}, + {0xc78, 0xf8080001}, {0xc78, 0xf7090001}, + {0xc78, 0xf60a0001}, {0xc78, 0xf50b0001}, + {0xc78, 0xf40c0001}, {0xc78, 0xf30d0001}, + {0xc78, 0xf20e0001}, {0xc78, 0xf10f0001}, + {0xc78, 0xf0100001}, {0xc78, 0xef110001}, + {0xc78, 0xee120001}, {0xc78, 0xed130001}, + {0xc78, 0xec140001}, {0xc78, 0xeb150001}, + {0xc78, 0xea160001}, {0xc78, 0xe9170001}, + {0xc78, 0xe8180001}, {0xc78, 0xe7190001}, + {0xc78, 0xe61a0001}, {0xc78, 0xe51b0001}, + {0xc78, 0xe41c0001}, {0xc78, 0xe31d0001}, + {0xc78, 0xe21e0001}, {0xc78, 0xe11f0001}, + {0xc78, 0x8a200001}, {0xc78, 0x89210001}, + {0xc78, 0x88220001}, {0xc78, 0x87230001}, + {0xc78, 0x86240001}, {0xc78, 0x85250001}, + {0xc78, 0x84260001}, {0xc78, 0x83270001}, + {0xc78, 0x82280001}, {0xc78, 0x6b290001}, + {0xc78, 0x6a2a0001}, {0xc78, 0x692b0001}, + {0xc78, 0x682c0001}, {0xc78, 0x672d0001}, + {0xc78, 0x662e0001}, {0xc78, 0x652f0001}, + {0xc78, 0x64300001}, {0xc78, 0x63310001}, + {0xc78, 0x62320001}, {0xc78, 0x61330001}, + {0xc78, 0x46340001}, {0xc78, 0x45350001}, + {0xc78, 0x44360001}, {0xc78, 0x43370001}, + {0xc78, 0x42380001}, {0xc78, 0x41390001}, + {0xc78, 0x403a0001}, {0xc78, 0x403b0001}, + {0xc78, 0x403c0001}, {0xc78, 0x403d0001}, + {0xc78, 0x403e0001}, {0xc78, 0x403f0001}, + {0xc78, 0xfb400001}, {0xc78, 0xfb410001}, + {0xc78, 0xfb420001}, {0xc78, 0xfb430001}, + {0xc78, 0xfb440001}, {0xc78, 0xfb450001}, + {0xc78, 0xfb460001}, {0xc78, 0xfb470001}, + {0xc78, 0xfb480001}, {0xc78, 0xfa490001}, + {0xc78, 0xf94a0001}, {0xc78, 0xf84b0001}, + {0xc78, 0xf74c0001}, {0xc78, 0xf64d0001}, + {0xc78, 0xf54e0001}, {0xc78, 0xf44f0001}, + {0xc78, 0xf3500001}, {0xc78, 0xf2510001}, + {0xc78, 0xf1520001}, {0xc78, 0xf0530001}, + {0xc78, 0xef540001}, {0xc78, 0xee550001}, + {0xc78, 0xed560001}, {0xc78, 0xec570001}, + {0xc78, 0xeb580001}, {0xc78, 0xea590001}, + {0xc78, 0xe95a0001}, {0xc78, 0xe85b0001}, + {0xc78, 0xe75c0001}, {0xc78, 0xe65d0001}, + {0xc78, 0xe55e0001}, {0xc78, 0xe45f0001}, + {0xc78, 0xe3600001}, {0xc78, 0xe2610001}, + {0xc78, 0xc3620001}, {0xc78, 0xc2630001}, + {0xc78, 0xc1640001}, {0xc78, 0x8b650001}, + {0xc78, 0x8a660001}, {0xc78, 0x89670001}, + {0xc78, 0x88680001}, {0xc78, 0x87690001}, + {0xc78, 0x866a0001}, {0xc78, 0x856b0001}, + {0xc78, 0x846c0001}, {0xc78, 0x676d0001}, + {0xc78, 0x666e0001}, {0xc78, 0x656f0001}, + {0xc78, 0x64700001}, {0xc78, 0x63710001}, + {0xc78, 0x62720001}, {0xc78, 0x61730001}, + {0xc78, 0x60740001}, {0xc78, 0x46750001}, + {0xc78, 0x45760001}, {0xc78, 0x44770001}, + {0xc78, 0x43780001}, {0xc78, 0x42790001}, + {0xc78, 0x417a0001}, {0xc78, 0x407b0001}, + {0xc78, 0x407c0001}, {0xc78, 0x407d0001}, + {0xc78, 0x407e0001}, {0xc78, 0x407f0001}, + {0xc50, 0x69553422}, {0xc50, 0x69553420}, + {0xffff, 0xffffffff} +}; + +static const struct rtl8xxxu_rfregval rtl8188eu_radioa_init_table[] = { + {0x00, 0x00030000}, {0x08, 0x00084000}, + {0x18, 0x00000407}, {0x19, 0x00000012}, + {0x1e, 0x00080009}, {0x1f, 0x00000880}, + {0x2f, 0x0001a060}, {0x3f, 0x00000000}, + {0x42, 0x000060c0}, {0x57, 0x000d0000}, + {0x58, 0x000be180}, {0x67, 0x00001552}, + {0x83, 0x00000000}, {0xb0, 0x000ff8fc}, + {0xb1, 0x00054400}, {0xb2, 0x000ccc19}, + {0xb4, 0x00043003}, {0xb6, 0x0004953e}, + {0xb7, 0x0001c718}, {0xb8, 0x000060ff}, + {0xb9, 0x00080001}, {0xba, 0x00040000}, + {0xbb, 0x00000400}, {0xbf, 0x000c0000}, + {0xc2, 0x00002400}, {0xc3, 0x00000009}, + {0xc4, 0x00040c91}, {0xc5, 0x00099999}, + {0xc6, 0x000000a3}, {0xc7, 0x00088820}, + {0xc8, 0x00076c06}, {0xc9, 0x00000000}, + {0xca, 0x00080000}, {0xdf, 0x00000180}, + {0xef, 0x000001a0}, {0x51, 0x0006b27d}, + {0x52, 0x0007e49d}, /* Set to 0x0007e4dd for SDIO */ + {0x53, 0x00000073}, {0x56, 0x00051ff3}, + {0x35, 0x00000086}, {0x35, 0x00000186}, + {0x35, 0x00000286}, {0x36, 0x00001c25}, + {0x36, 0x00009c25}, {0x36, 0x00011c25}, + {0x36, 0x00019c25}, {0xb6, 0x00048538}, + {0x18, 0x00000c07}, {0x5a, 0x0004bd00}, + {0x19, 0x000739d0}, {0x34, 0x0000adf3}, + {0x34, 0x00009df0}, {0x34, 0x00008ded}, + {0x34, 0x00007dea}, {0x34, 0x00006de7}, + {0x34, 0x000054ee}, {0x34, 0x000044eb}, + {0x34, 0x000034e8}, {0x34, 0x0000246b}, + {0x34, 0x00001468}, {0x34, 0x0000006d}, + {0x00, 0x00030159}, {0x84, 0x00068200}, + {0x86, 0x000000ce}, {0x87, 0x00048a00}, + {0x8e, 0x00065540}, {0x8f, 0x00088000}, + {0xef, 0x000020a0}, {0x3b, 0x000f02b0}, + {0x3b, 0x000ef7b0}, {0x3b, 0x000d4fb0}, + {0x3b, 0x000cf060}, {0x3b, 0x000b0090}, + {0x3b, 0x000a0080}, {0x3b, 0x00090080}, + {0x3b, 0x0008f780}, {0x3b, 0x000722b0}, + {0x3b, 0x0006f7b0}, {0x3b, 0x00054fb0}, + {0x3b, 0x0004f060}, {0x3b, 0x00030090}, + {0x3b, 0x00020080}, {0x3b, 0x00010080}, + {0x3b, 0x0000f780}, {0xef, 0x000000a0}, + {0x00, 0x00010159}, {0x18, 0x0000f407}, + {0xFE, 0x00000000}, {0xFE, 0x00000000}, + {0x1F, 0x00080003}, {0xFE, 0x00000000}, + {0xFE, 0x00000000}, {0x1E, 0x00000001}, + {0x1F, 0x00080000}, {0x00, 0x00033e60}, + {0xff, 0xffffffff} +}; + +#define PERENTRY 23 +#define RETRYSIZE 5 +#define RATESIZE 28 +#define TX_RPT2_ITEM_SIZE 8 + +static const u8 retry_penalty[PERENTRY][RETRYSIZE + 1] = { + {5, 4, 3, 2, 0, 3}, /* 92 , idx=0 */ + {6, 5, 4, 3, 0, 4}, /* 86 , idx=1 */ + {6, 5, 4, 2, 0, 4}, /* 81 , idx=2 */ + {8, 7, 6, 4, 0, 6}, /* 75 , idx=3 */ + {10, 9, 8, 6, 0, 8}, /* 71 , idx=4 */ + {10, 9, 8, 4, 0, 8}, /* 66 , idx=5 */ + {10, 9, 8, 2, 0, 8}, /* 62 , idx=6 */ + {10, 9, 8, 0, 0, 8}, /* 59 , idx=7 */ + {18, 17, 16, 8, 0, 16}, /* 53 , idx=8 */ + {26, 25, 24, 16, 0, 24}, /* 50 , idx=9 */ + {34, 33, 32, 24, 0, 32}, /* 47 , idx=0x0a */ + {34, 31, 28, 20, 0, 32}, /* 43 , idx=0x0b */ + {34, 31, 27, 18, 0, 32}, /* 40 , idx=0x0c */ + {34, 31, 26, 16, 0, 32}, /* 37 , idx=0x0d */ + {34, 30, 22, 16, 0, 32}, /* 32 , idx=0x0e */ + {34, 30, 24, 16, 0, 32}, /* 26 , idx=0x0f */ + {49, 46, 40, 16, 0, 48}, /* 20 , idx=0x10 */ + {49, 45, 32, 0, 0, 48}, /* 17 , idx=0x11 */ + {49, 45, 22, 18, 0, 48}, /* 15 , idx=0x12 */ + {49, 40, 24, 16, 0, 48}, /* 12 , idx=0x13 */ + {49, 32, 18, 12, 0, 48}, /* 9 , idx=0x14 */ + {49, 22, 18, 14, 0, 48}, /* 6 , idx=0x15 */ + {49, 16, 16, 0, 0, 48} /* 3, idx=0x16 */ +}; + +static const u8 pt_penalty[RETRYSIZE + 1] = {34, 31, 30, 24, 0, 32}; + +static const u8 retry_penalty_idx_normal[2][RATESIZE] = { + { /* RSSI>TH */ + 4, 4, 4, 5, + 4, 4, 5, 7, 7, 7, 8, 0x0a, + 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d, + 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f + }, + { /* RSSI<TH */ + 0x0a, 0x0a, 0x0b, 0x0c, + 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x13, + 9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13 + } +}; + +static const u8 retry_penalty_idx_cut_i[2][RATESIZE] = { + { /* RSSI>TH */ + 4, 4, 4, 5, + 4, 4, 5, 7, 7, 7, 8, 0x0a, + 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d, + 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f + }, + { /* RSSI<TH */ + 0x0a, 0x0a, 0x0b, 0x0c, + 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13, + 0x06, 0x07, 0x08, 0x0d, 0x0e, 0x11, 0x11, 0x11, + 9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13 + } +}; + +static const u8 retry_penalty_up_idx_normal[RATESIZE] = { + 0x0c, 0x0d, 0x0d, 0x0f, + 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14, + 0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15, + 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15 +}; + +static const u8 retry_penalty_up_idx_cut_i[RATESIZE] = { + 0x0c, 0x0d, 0x0d, 0x0f, + 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14, + 0x0b, 0x0b, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, + 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15 +}; + +static const u8 rssi_threshold[RATESIZE] = { + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0x24, 0x26, 0x2a, + 0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a, + 0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c +}; + +static const u16 n_threshold_high[RATESIZE] = { + 4, 4, 8, 16, + 24, 36, 48, 72, 96, 144, 192, 216, + 60, 80, 100, 160, 240, 400, 600, 800, + 300, 320, 480, 720, 1000, 1200, 1600, 2000 +}; + +static const u16 n_threshold_low[RATESIZE] = { + 2, 2, 4, 8, + 12, 18, 24, 36, 48, 72, 96, 108, + 30, 40, 50, 80, 120, 200, 300, 400, + 150, 160, 240, 360, 500, 600, 800, 1000 +}; + +static const u8 dropping_necessary[RATESIZE] = { + 1, 1, 1, 1, + 1, 2, 3, 4, 5, 6, 7, 8, + 1, 2, 3, 4, 5, 6, 7, 8, + 5, 6, 7, 8, 9, 10, 11, 12 +}; + +static const u8 pending_for_rate_up_fail[5] = {2, 10, 24, 40, 60}; + +static const u16 dynamic_tx_rpt_timing[6] = { + 0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12, 0x927c /* 200ms-1200ms */ +}; + +enum rtl8188e_tx_rpt_timing { + DEFAULT_TIMING = 0, + INCREASE_TIMING, + DECREASE_TIMING +}; + +static int rtl8188eu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 sys_cfg, vendor; + int ret = 0; + + strscpy(priv->chip_name, "8188EU", sizeof(priv->chip_name)); + priv->rtl_chip = RTL8188E; + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + priv->has_wifi = 1; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + return -EOPNOTSUPP; + } + + /* + * TODO: At a glance, I cut requires a different firmware, + * different initialisation tables, and no software rate + * control. The vendor driver is not configured to handle + * I cut chips by default. Are there any in the wild? + */ + if (priv->chip_cut == 8) { + dev_info(dev, "RTL8188EU cut I is not supported. Please complain about it at linux-wireless@vger.kernel.org.\n"); + return -EOPNOTSUPP; + } + + vendor = sys_cfg & SYS_CFG_VENDOR_ID; + rtl8xxxu_identify_vendor_1bit(priv, vendor); + + ret = rtl8xxxu_config_endpoints_no_sie(priv); + + return ret; +} + +static void rtl8188eu_config_channel(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + u32 val32, rsr; + u8 opmode; + int sec_ch_above, channel; + int i; + + opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE); + rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); + channel = hw->conf.chandef.chan->hw_value; + + switch (hw->conf.chandef.width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + opmode |= BW_OPMODE_20MHZ; + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + break; + case NL80211_CHAN_WIDTH_40: + if (hw->conf.chandef.center_freq1 > + hw->conf.chandef.chan->center_freq) { + sec_ch_above = 1; + channel += 2; + } else { + sec_ch_above = 0; + channel -= 2; + } + + opmode &= ~BW_OPMODE_20MHZ; + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); + rsr &= ~RSR_RSC_BANDWIDTH_40M; + if (sec_ch_above) + rsr |= RSR_RSC_LOWER_SUB_CHANNEL; + else + rsr |= RSR_RSC_UPPER_SUB_CHANNEL; + rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + + /* + * Set Control channel to upper or lower. These settings + * are required only for 40MHz + */ + val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM); + val32 &= ~CCK0_SIDEBAND; + if (!sec_ch_above) + val32 |= CCK0_SIDEBAND; + rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF); + val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */ + if (sec_ch_above) + val32 |= OFDM_LSTF_PRIME_CH_LOW; + else + val32 |= OFDM_LSTF_PRIME_CH_HIGH; + rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE); + val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL); + if (sec_ch_above) + val32 |= FPGA0_PS_UPPER_CHANNEL; + else + val32 |= FPGA0_PS_LOWER_CHANNEL; + rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32); + break; + + default: + break; + } + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + u32p_replace_bits(&val32, channel, MODE_AG_CHANNEL_MASK); + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + val32 &= ~MODE_AG_BW_MASK; + if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) + val32 |= MODE_AG_BW_40MHZ_8723B; + else + val32 |= MODE_AG_BW_20MHZ_8723B; + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } +} + +static void rtl8188eu_init_aggregation(struct rtl8xxxu_priv *priv) +{ + u8 agg_ctrl, usb_spec; + + usb_spec = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION); + usb_spec &= ~USB_SPEC_USB_AGG_ENABLE; + rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, usb_spec); + + agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL); + agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN; + rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl); +} + +static int rtl8188eu_parse_efuse(struct rtl8xxxu_priv *priv) +{ + struct rtl8188eu_efuse *efuse = &priv->efuse_wifi.efuse8188eu; + + if (efuse->rtl_id != cpu_to_le16(0x8129)) + return -EINVAL; + + ether_addr_copy(priv->mac_addr, efuse->mac_addr); + + memcpy(priv->cck_tx_power_index_A, efuse->tx_power_index_A.cck_base, + sizeof(efuse->tx_power_index_A.cck_base)); + + memcpy(priv->ht40_1s_tx_power_index_A, + efuse->tx_power_index_A.ht40_base, + sizeof(efuse->tx_power_index_A.ht40_base)); + + priv->default_crystal_cap = efuse->xtal_k & 0x3f; + + dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); + dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); + dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); + + return 0; +} + +static void rtl8188eu_reset_8051(struct rtl8xxxu_priv *priv) +{ + u16 sys_func; + + sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC); + sys_func &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); + + sys_func |= SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func); +} + +static int rtl8188eu_load_firmware(struct rtl8xxxu_priv *priv) +{ + const char *fw_name; + int ret; + + fw_name = "rtlwifi/rtl8188eufw.bin"; + + ret = rtl8xxxu_load_firmware(priv, fw_name); + + return ret; +} + +static void rtl8188eu_init_phy_bb(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB | SYS_FUNC_DIO_RF; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + + /* + * Per vendor driver, run power sequence before init of RF + */ + val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB; + rtl8xxxu_write8(priv, REG_RF_CTRL, val8); + + val8 = SYS_FUNC_USBA | SYS_FUNC_USBD | + SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + rtl8xxxu_init_phy_regs(priv, rtl8188eu_phy_init_table); + rtl8xxxu_init_phy_regs(priv, rtl8188e_agc_table); +} + +static int rtl8188eu_init_phy_rf(struct rtl8xxxu_priv *priv) +{ + return rtl8xxxu_init_phy_rf(priv, rtl8188eu_radioa_init_table, RF_A); +} + +static int rtl8188eu_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_e94, reg_e9c; + int result = 0; + + /* Path A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x30008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x8214032a); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00462911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(10); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000)) + result |= 0x01; + + return result; +} + +static int rtl8188eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_ea4, reg_eac, reg_e94, reg_e9c, val32; + int result = 0; + + /* Leave IQK mode */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* Enable path A PA in TX IQK mode */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf117b); + + /* Enter IQK mode */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0x808000, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* TX IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x81004800); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x30008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160804); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(10); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000)) + result |= 0x01; + else + goto out; + + val32 = 0x80007c00 | + (reg_e94 & 0x03ff0000) | ((reg_e9c >> 16) & 0x03ff); + rtl8xxxu_write32(priv, REG_TX_IQK, val32); + + /* Modify RX IQK mode table */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ffa); + + /* Enter IQK mode */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0x808000, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + /* IQK setting */ + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* Path A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x30008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c05); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c05); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(10); + + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); + + if (!(reg_eac & BIT(27)) && + ((reg_ea4 & 0x03ff0000) != 0x01320000) && + ((reg_eac & 0x03ff0000) != 0x00360000)) + result |= 0x02; + else + dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n", + __func__); + +out: + return result; +} + +static void rtl8188eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, + int result[][8], int t) +{ + struct device *dev = &priv->udev->dev; + u32 i, val32; + int path_a_ok; + int retry = 2; + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, + REG_RX_WAIT_CCA, REG_TX_CCK_RFON, + REG_TX_CCK_BBON, REG_TX_OFDM_RFON, + REG_TX_OFDM_BBON, REG_TX_TO_RX, + REG_TX_TO_TX, REG_RX_CCK, + REG_RX_OFDM, REG_RX_WAIT_RIFS, + REG_RX_TO_RX, REG_STANDBY, + REG_SLEEP, REG_PMPD_ANAEN + }; + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + REG_TXPAUSE, REG_BEACON_CTRL, + REG_BEACON_CTRL_1, REG_GPIO_MUXCFG + }; + static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, + REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, + REG_FPGA0_XB_RF_INT_OE, REG_CCK0_AFE_SETTING + }; + + /* + * Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt + */ + + if (t == 0) { + /* Save ADDA parameters, turn Path A ADDA on */ + rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + rtl8xxxu_save_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + } + + rtl8xxxu_path_adda_on(priv, adda_regs, true); + + if (t == 0) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1); + priv->pi_enabled = u32_get_bits(val32, FPGA0_HSSI_PARM1_PI); + } + + if (!priv->pi_enabled) { + /* Switch BB to PI mode to do IQ Calibration. */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); + rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100); + } + + /* MAC settings */ + rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup); + + val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING); + u32p_replace_bits(&val32, 0xf, 0x0f000000); + rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32); + + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000); + + if (!priv->no_pape) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL); + val32 |= (FPGA0_RF_PAPE | + (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT)); + rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32); + } + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE); + val32 &= ~BIT(10); + rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32); + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE); + val32 &= ~BIT(10); + rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32); + + /* Page B init */ + rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x0f600000); + + /* IQ calibration setting */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0x808000, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x81004800); + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8188eu_iqk_path_a(priv); + if (path_a_ok == 0x01) { + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_BEFORE_IQK_A); + result[t][0] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_AFTER_IQK_A); + result[t][1] = (val32 >> 16) & 0x3ff; + break; + } + } + + if (!path_a_ok) + dev_dbg(dev, "%s: Path A TX IQK failed!\n", __func__); + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8188eu_rx_iqk_path_a(priv); + if (path_a_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_BEFORE_IQK_A_2); + result[t][2] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_AFTER_IQK_A_2); + result[t][3] = (val32 >> 16) & 0x3ff; + + break; + } + } + + if (!path_a_ok) + dev_dbg(dev, "%s: Path A RX IQK failed!\n", __func__); + + /* Back to BB mode, load original value */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); + u32p_replace_bits(&val32, 0, 0xffffff00); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); + + if (t == 0) + return; + + if (!priv->pi_enabled) { + /* Switch back BB to SI mode after finishing IQ Calibration */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000000); + rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000000); + } + + /* Reload ADDA power saving parameters */ + rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + + /* Reload MAC parameters */ + rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + + /* Reload BB parameters */ + rtl8xxxu_restore_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + + /* Restore RX initial gain */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3); + + /* Load 0xe30 IQC default value */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00); +} + +static void rtl8188eu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + int result[4][8]; /* last is final result */ + int i, candidate; + bool path_a_ok; + u32 reg_e94, reg_e9c, reg_ea4, reg_eac; + u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc; + bool simu; + + memset(result, 0, sizeof(result)); + result[3][0] = 0x100; + result[3][2] = 0x100; + result[3][4] = 0x100; + result[3][6] = 0x100; + + candidate = -1; + + path_a_ok = false; + + for (i = 0; i < 3; i++) { + rtl8188eu_phy_iqcalibrate(priv, result, i); + + if (i == 1) { + simu = rtl8xxxu_simularity_compare(priv, + result, 0, 1); + if (simu) { + candidate = 0; + break; + } + } + + if (i == 2) { + simu = rtl8xxxu_simularity_compare(priv, + result, 0, 2); + if (simu) { + candidate = 0; + break; + } + + simu = rtl8xxxu_simularity_compare(priv, + result, 1, 2); + if (simu) + candidate = 1; + else + candidate = 3; + } + } + + if (candidate >= 0) { + reg_e94 = result[candidate][0]; + priv->rege94 = reg_e94; + reg_e9c = result[candidate][1]; + priv->rege9c = reg_e9c; + reg_ea4 = result[candidate][2]; + reg_eac = result[candidate][3]; + reg_eb4 = result[candidate][4]; + priv->regeb4 = reg_eb4; + reg_ebc = result[candidate][5]; + priv->regebc = reg_ebc; + reg_ec4 = result[candidate][6]; + reg_ecc = result[candidate][7]; + dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); + dev_dbg(dev, + "%s: e94=%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x ecc=%x\n", + __func__, reg_e94, reg_e9c, reg_ea4, reg_eac, + reg_eb4, reg_ebc, reg_ec4, reg_ecc); + path_a_ok = true; + } else { + reg_e94 = 0x100; + reg_eb4 = 0x100; + priv->rege94 = 0x100; + priv->regeb4 = 0x100; + reg_e9c = 0x0; + reg_ebc = 0x0; + priv->rege9c = 0x0; + priv->regebc = 0x0; + } + + if (reg_e94 && candidate >= 0) + rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result, + candidate, (reg_ea4 == 0)); + + rtl8xxxu_save_regs(priv, rtl8xxxu_iqk_phy_iq_bb_reg, + priv->bb_recovery_backup, RTL8XXXU_BB_REGS); +} + +static void rtl8188e_disabled_to_emu(struct rtl8xxxu_priv *priv) +{ + u16 val16; + + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~(APS_FSMCO_HW_SUSPEND | APS_FSMCO_PCIE); + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); +} + +static int rtl8188e_emu_to_active(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u32 val32; + u16 val16; + int count, ret = 0; + + /* wait till 0x04[17] = 1 power ready*/ + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if (val32 & BIT(17)) + break; + + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* reset baseband */ + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); + val8 &= ~(SYS_FUNC_BBRSTB | SYS_FUNC_BB_GLB_RSTN); + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + /*0x24[23] = 2b'01 schmit trigger */ + val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + val32 |= BIT(23); + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + + /* 0x04[15] = 0 disable HWPDN (control by DRV)*/ + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~APS_FSMCO_HW_POWERDOWN; + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + /*0x04[12:11] = 2b'00 disable WL suspend*/ + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~(APS_FSMCO_HW_SUSPEND | APS_FSMCO_PCIE); + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + /* set, then poll until 0 */ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 |= APS_FSMCO_MAC_ENABLE; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) { + ret = 0; + break; + } + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* LDO normal mode*/ + val8 = rtl8xxxu_read8(priv, REG_LPLDO_CTRL); + val8 &= ~BIT(4); + rtl8xxxu_write8(priv, REG_LPLDO_CTRL, val8); + +exit: + return ret; +} + +static int rtl8188eu_active_to_emu(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + /* Turn off RF */ + val8 = rtl8xxxu_read8(priv, REG_RF_CTRL); + val8 &= ~RF_ENABLE; + rtl8xxxu_write8(priv, REG_RF_CTRL, val8); + + /* LDO Sleep mode */ + val8 = rtl8xxxu_read8(priv, REG_LPLDO_CTRL); + val8 |= BIT(4); + rtl8xxxu_write8(priv, REG_LPLDO_CTRL, val8); + + return 0; +} + +static int rtl8188eu_emu_to_disabled(struct rtl8xxxu_priv *priv) +{ + u32 val32; + u16 val16; + u8 val8; + + val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + val32 |= BIT(23); + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~APS_FSMCO_PCIE; + val16 |= APS_FSMCO_HW_SUSPEND; + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x00); + + val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG + 1); + val8 &= ~BIT(4); + rtl8xxxu_write8(priv, REG_GPIO_MUXCFG + 1, val8); + + /* Set USB suspend enable local register 0xfe10[4]=1 */ + val8 = rtl8xxxu_read8(priv, 0xfe10); + val8 |= BIT(4); + rtl8xxxu_write8(priv, 0xfe10, val8); + + return 0; +} + +static int rtl8188eu_active_to_lps(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u8 val8; + u16 val16; + u32 val32; + int retry, retval; + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x7f); + + retry = 100; + retval = -EBUSY; + /* Poll 32 bit wide REG_SCH_TX_CMD for 0 to ensure no TX is pending. */ + do { + val32 = rtl8xxxu_read32(priv, REG_SCH_TX_CMD); + if (!val32) { + retval = 0; + break; + } + } while (retry--); + + if (!retry) { + dev_warn(dev, "Failed to flush TX queue\n"); + retval = -EBUSY; + goto out; + } + + /* Disable CCK and OFDM, clock gated */ + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); + val8 &= ~SYS_FUNC_BBRSTB; + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + udelay(2); + + /* Reset MAC TRX */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= 0xff; + val16 &= ~(CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE | CR_SECURITY_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + + val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST); + val8 |= DUAL_TSF_TX_OK; + rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8); + +out: + return retval; +} + +static int rtl8188eu_power_on(struct rtl8xxxu_priv *priv) +{ + u16 val16; + int ret; + + rtl8188e_disabled_to_emu(priv); + + ret = rtl8188e_emu_to_active(priv); + if (ret) + goto exit; + + /* + * Enable MAC DMA/WMAC/SCHEDULE/SEC block + * Set CR bit10 to enable 32k calibration. + * We do not set CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE here + * due to a hardware bug in the 88E, requiring those to be + * set after REG_TRXFF_BNDY is set. If not the RXFF bundary + * will get set to a larger buffer size than the real buffer + * size. + */ + val16 = (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE | + CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | + CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE | + CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + +exit: + return ret; +} + +static void rtl8188eu_power_off(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + + rtl8xxxu_flush_fifo(priv); + + val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL); + val8 &= ~TX_REPORT_CTRL_TIMER_ENABLE; + rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8); + + /* Turn off RF */ + rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00); + + rtl8188eu_active_to_lps(priv); + + /* Reset Firmware if running in RAM */ + if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL) + rtl8xxxu_firmware_self_reset(priv); + + /* Reset MCU */ + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + + /* Reset MCU ready status */ + rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); + + /* 32K_CTRL looks to be very 8188e specific */ + val8 = rtl8xxxu_read8(priv, REG_32K_CTRL); + val8 &= ~BIT(0); + rtl8xxxu_write8(priv, REG_32K_CTRL, val8); + + rtl8188eu_active_to_emu(priv); + rtl8188eu_emu_to_disabled(priv); + + /* Reset MCU IO Wrapper */ + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 &= ~BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 |= BIT(3); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + /* Vendor driver refers to GPIO_IN */ + val8 = rtl8xxxu_read8(priv, REG_GPIO_PIN_CTRL); + /* Vendor driver refers to GPIO_OUT */ + rtl8xxxu_write8(priv, REG_GPIO_PIN_CTRL + 1, val8); + rtl8xxxu_write8(priv, REG_GPIO_PIN_CTRL + 2, 0xff); + + val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL); + rtl8xxxu_write8(priv, REG_GPIO_IO_SEL, val8 << 4); + val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL + 1); + rtl8xxxu_write8(priv, REG_GPIO_IO_SEL + 1, val8 | 0x0f); + + /* + * Set LNA, TRSW, EX_PA Pin to output mode + * Referred to as REG_BB_PAD_CTRL in 8188eu vendor driver + */ + rtl8xxxu_write32(priv, REG_PAD_CTRL1, 0x00080808); + + rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x00); + + rtl8xxxu_write32(priv, REG_GPIO_MUXCFG, 0x00000000); +} + +static void rtl8188e_enable_rf(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + rtl8xxxu_write8(priv, REG_RF_CTRL, RF_ENABLE | RF_RSTB | RF_SDMRSTB); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK); + val32 |= OFDM_RF_PATH_RX_A | OFDM_RF_PATH_TX_A; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); +} + +static void rtl8188e_disable_rf(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~OFDM_RF_PATH_TX_MASK; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + /* Power down RF module */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0); + + rtl8188eu_active_to_emu(priv); +} + +static void rtl8188e_usb_quirks(struct rtl8xxxu_priv *priv) +{ + u16 val16; + + /* + * Technically this is not a USB quirk, but a chip quirk. + * This has to be done after REG_TRXFF_BNDY is set, see + * rtl8188eu_power_on() for details. + */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= (CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + + rtl8xxxu_gen2_usb_quirks(priv); + + /* Pre-TX enable WEP/TKIP security */ + rtl8xxxu_write8(priv, REG_EARLY_MODE_CONTROL_8188E + 3, 0x01); +} + +static s8 rtl8188e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) +{ + /* only use lna 0/1/2/3/7 */ + static const s8 lna_gain_table_0[8] = {17, -1, -13, -29, -32, -35, -38, -41}; + /* only use lna 3/7 */ + static const s8 lna_gain_table_1[8] = {29, 20, 12, 3, -6, -15, -24, -33}; + + s8 rx_pwr_all = 0x00; + u8 vga_idx, lna_idx; + s8 lna_gain = 0; + + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); + + if (priv->chip_cut >= 8) /* cut I */ /* SMIC */ + lna_gain = lna_gain_table_0[lna_idx]; + else /* TSMC */ + lna_gain = lna_gain_table_1[lna_idx]; + + rx_pwr_all = lna_gain - (2 * vga_idx); + + return rx_pwr_all; +} + +static int rtl8188eu_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rtl8xxxu_priv *priv = container_of(led_cdev, + struct rtl8xxxu_priv, + led_cdev); + u8 ledcfg = rtl8xxxu_read8(priv, REG_LEDCFG2); + + if (brightness == LED_OFF) { + ledcfg &= ~LEDCFG2_HW_LED_CONTROL; + ledcfg |= LEDCFG2_SW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE; + } else if (brightness == LED_ON) { + ledcfg &= ~(LEDCFG2_HW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE); + ledcfg |= LEDCFG2_SW_LED_CONTROL; + } else if (brightness == RTL8XXXU_HW_LED_CONTROL) { + ledcfg &= ~LEDCFG2_SW_LED_DISABLE; + ledcfg |= LEDCFG2_HW_LED_CONTROL | LEDCFG2_HW_LED_ENABLE; + } + + rtl8xxxu_write8(priv, REG_LEDCFG2, ledcfg); + + return 0; +} + +static void rtl8188e_set_tx_rpt_timing(struct rtl8xxxu_ra_info *ra, u8 timing) +{ + u8 idx; + + for (idx = 0; idx < 5; idx++) + if (dynamic_tx_rpt_timing[idx] == ra->rpt_time) + break; + + if (timing == DEFAULT_TIMING) { + idx = 0; /* 200ms */ + } else if (timing == INCREASE_TIMING) { + if (idx < 5) + idx++; + } else if (timing == DECREASE_TIMING) { + if (idx > 0) + idx--; + } + + ra->rpt_time = dynamic_tx_rpt_timing[idx]; +} + +static void rtl8188e_rate_down(struct rtl8xxxu_ra_info *ra) +{ + u8 rate_id = ra->pre_rate; + u8 lowest_rate = ra->lowest_rate; + u8 highest_rate = ra->highest_rate; + s8 i; + + if (rate_id > highest_rate) { + rate_id = highest_rate; + } else if (ra->rate_sgi) { + ra->rate_sgi = 0; + } else if (rate_id > lowest_rate) { + if (rate_id > 0) { + for (i = rate_id - 1; i >= lowest_rate; i--) { + if (ra->ra_use_rate & BIT(i)) { + rate_id = i; + goto rate_down_finish; + } + } + } + } else if (rate_id <= lowest_rate) { + rate_id = lowest_rate; + } + +rate_down_finish: + if (ra->ra_waiting_counter == 1) { + ra->ra_waiting_counter++; + ra->ra_pending_counter++; + } else if (ra->ra_waiting_counter > 1) { + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + } + + if (ra->ra_pending_counter >= 4) + ra->ra_pending_counter = 4; + + ra->ra_drop_after_down = 1; + + ra->decision_rate = rate_id; + + rtl8188e_set_tx_rpt_timing(ra, DECREASE_TIMING); +} + +static void rtl8188e_rate_up(struct rtl8xxxu_ra_info *ra) +{ + u8 rate_id = ra->pre_rate; + u8 highest_rate = ra->highest_rate; + u8 i; + + if (ra->ra_waiting_counter == 1) { + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + } else if (ra->ra_waiting_counter > 1) { + ra->pre_rssi_sta_ra = ra->rssi_sta_ra; + goto rate_up_finish; + } + + rtl8188e_set_tx_rpt_timing(ra, DEFAULT_TIMING); + + if (rate_id < highest_rate) { + for (i = rate_id + 1; i <= highest_rate; i++) { + if (ra->ra_use_rate & BIT(i)) { + rate_id = i; + goto rate_up_finish; + } + } + } else if (rate_id == highest_rate) { + if (ra->sgi_enable && !ra->rate_sgi) + ra->rate_sgi = 1; + else if (!ra->sgi_enable) + ra->rate_sgi = 0; + } else { /* rate_id > ra->highest_rate */ + rate_id = highest_rate; + } + +rate_up_finish: + if (ra->ra_waiting_counter == (4 + pending_for_rate_up_fail[ra->ra_pending_counter])) + ra->ra_waiting_counter = 0; + else + ra->ra_waiting_counter++; + + ra->decision_rate = rate_id; +} + +static void rtl8188e_reset_ra_counter(struct rtl8xxxu_ra_info *ra) +{ + u8 rate_id = ra->decision_rate; + + ra->nsc_up = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1; + ra->nsc_down = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1; +} + +static void rtl8188e_rate_decision(struct rtl8xxxu_ra_info *ra) +{ + struct rtl8xxxu_priv *priv = container_of(ra, struct rtl8xxxu_priv, ra_info); + const u8 *retry_penalty_idx_0; + const u8 *retry_penalty_idx_1; + const u8 *retry_penalty_up_idx; + u8 rate_id, penalty_id1, penalty_id2; + int i; + + if (ra->total == 0) + return; + + if (ra->ra_drop_after_down) { + ra->ra_drop_after_down--; + + rtl8188e_reset_ra_counter(ra); + + return; + } + + if (priv->chip_cut == 8) { /* cut I */ + retry_penalty_idx_0 = retry_penalty_idx_cut_i[0]; + retry_penalty_idx_1 = retry_penalty_idx_cut_i[1]; + retry_penalty_up_idx = retry_penalty_up_idx_cut_i; + } else { + retry_penalty_idx_0 = retry_penalty_idx_normal[0]; + retry_penalty_idx_1 = retry_penalty_idx_normal[1]; + retry_penalty_up_idx = retry_penalty_up_idx_normal; + } + + if (ra->rssi_sta_ra < (ra->pre_rssi_sta_ra - 3) || + ra->rssi_sta_ra > (ra->pre_rssi_sta_ra + 3)) { + ra->pre_rssi_sta_ra = ra->rssi_sta_ra; + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + } + + /* Start RA decision */ + if (ra->pre_rate > ra->highest_rate) + rate_id = ra->highest_rate; + else + rate_id = ra->pre_rate; + + /* rate down */ + if (ra->rssi_sta_ra > rssi_threshold[rate_id]) + penalty_id1 = retry_penalty_idx_0[rate_id]; + else + penalty_id1 = retry_penalty_idx_1[rate_id]; + + for (i = 0; i < 5; i++) + ra->nsc_down += ra->retry[i] * retry_penalty[penalty_id1][i]; + + if (ra->nsc_down > (ra->total * retry_penalty[penalty_id1][5])) + ra->nsc_down -= ra->total * retry_penalty[penalty_id1][5]; + else + ra->nsc_down = 0; + + /* rate up */ + penalty_id2 = retry_penalty_up_idx[rate_id]; + + for (i = 0; i < 5; i++) + ra->nsc_up += ra->retry[i] * retry_penalty[penalty_id2][i]; + + if (ra->nsc_up > (ra->total * retry_penalty[penalty_id2][5])) + ra->nsc_up -= ra->total * retry_penalty[penalty_id2][5]; + else + ra->nsc_up = 0; + + if (ra->nsc_down < n_threshold_low[rate_id] || + ra->drop > dropping_necessary[rate_id]) { + rtl8188e_rate_down(ra); + + rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate, + ra->rate_sgi, priv->ra_report.txrate.bw); + } else if (ra->nsc_up > n_threshold_high[rate_id]) { + rtl8188e_rate_up(ra); + + rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate, + ra->rate_sgi, priv->ra_report.txrate.bw); + } + + if (ra->decision_rate == ra->pre_rate) + ra->dynamic_tx_rpt_timing_counter++; + else + ra->dynamic_tx_rpt_timing_counter = 0; + + if (ra->dynamic_tx_rpt_timing_counter >= 4) { + /* Rate didn't change 4 times, extend RPT timing */ + rtl8188e_set_tx_rpt_timing(ra, INCREASE_TIMING); + ra->dynamic_tx_rpt_timing_counter = 0; + } + + ra->pre_rate = ra->decision_rate; + + rtl8188e_reset_ra_counter(ra); +} + +static void rtl8188e_power_training_try_state(struct rtl8xxxu_ra_info *ra) +{ + ra->pt_try_state = 0; + switch (ra->pt_mode_ss) { + case 3: + if (ra->decision_rate >= DESC_RATE_MCS13) + ra->pt_try_state = 1; + break; + case 2: + if (ra->decision_rate >= DESC_RATE_MCS5) + ra->pt_try_state = 1; + break; + case 1: + if (ra->decision_rate >= DESC_RATE_48M) + ra->pt_try_state = 1; + break; + case 0: + if (ra->decision_rate >= DESC_RATE_11M) + ra->pt_try_state = 1; + break; + default: + break; + } + + if (ra->rssi_sta_ra < 48) { + ra->pt_stage = 0; + } else if (ra->pt_try_state == 1) { + if ((ra->pt_stop_count >= 10) || + (ra->pt_pre_rssi > ra->rssi_sta_ra + 5) || + (ra->pt_pre_rssi < ra->rssi_sta_ra - 5) || + (ra->decision_rate != ra->pt_pre_rate)) { + if (ra->pt_stage == 0) + ra->pt_stage = 1; + else if (ra->pt_stage == 1) + ra->pt_stage = 3; + else + ra->pt_stage = 5; + + ra->pt_pre_rssi = ra->rssi_sta_ra; + ra->pt_stop_count = 0; + } else { + ra->ra_stage = 0; + ra->pt_stop_count++; + } + } else { + ra->pt_stage = 0; + ra->ra_stage = 0; + } + + ra->pt_pre_rate = ra->decision_rate; + + /* TODO: implement the "false alarm" statistics for this */ + /* Disable power training when noisy environment */ + /* if (p_dm_odm->is_disable_power_training) { */ + if (1) { + ra->pt_stage = 0; + ra->ra_stage = 0; + ra->pt_stop_count = 0; + } +} + +static void rtl8188e_power_training_decision(struct rtl8xxxu_ra_info *ra) +{ + u8 temp_stage; + u32 numsc; + u32 num_total; + u8 stage_id; + u8 j; + + numsc = 0; + num_total = ra->total * pt_penalty[5]; + for (j = 0; j <= 4; j++) { + numsc += ra->retry[j] * pt_penalty[j]; + + if (numsc > num_total) + break; + } + + j >>= 1; + temp_stage = (ra->pt_stage + 1) >> 1; + if (temp_stage > j) + stage_id = temp_stage - j; + else + stage_id = 0; + + ra->pt_smooth_factor = (ra->pt_smooth_factor >> 1) + + (ra->pt_smooth_factor >> 2) + + stage_id * 16 + 2; + if (ra->pt_smooth_factor > 192) + ra->pt_smooth_factor = 192; + stage_id = ra->pt_smooth_factor >> 6; + temp_stage = stage_id * 2; + if (temp_stage != 0) + temp_stage--; + if (ra->drop > 3) + temp_stage = 0; + ra->pt_stage = temp_stage; +} + +void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb) +{ + u32 *_rx_desc = (u32 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16)); + struct rtl8xxxu_rxdesc16 *rx_desc = (struct rtl8xxxu_rxdesc16 *)_rx_desc; + struct device *dev = &priv->udev->dev; + struct rtl8xxxu_ra_info *ra = &priv->ra_info; + u32 tx_rpt_len = rx_desc->pktlen & 0x3ff; + u32 items = tx_rpt_len / TX_RPT2_ITEM_SIZE; + u64 macid_valid = ((u64)_rx_desc[5] << 32) | _rx_desc[4]; + u32 macid; + u8 *rpt = skb->data; + bool valid; + u16 min_rpt_time = 0x927c; + + dev_dbg(dev, "%s: len: %d items: %d\n", __func__, tx_rpt_len, items); + + for (macid = 0; macid < items; macid++) { + valid = false; + + if (macid < 64) + valid = macid_valid & BIT(macid); + + if (valid) { + ra->retry[0] = le16_to_cpu(*(__le16 *)rpt); + ra->retry[1] = rpt[2]; + ra->retry[2] = rpt[3]; + ra->retry[3] = rpt[4]; + ra->retry[4] = rpt[5]; + ra->drop = rpt[6]; + ra->total = ra->retry[0] + ra->retry[1] + ra->retry[2] + + ra->retry[3] + ra->retry[4] + ra->drop; + + if (ra->total > 0) { + if (ra->ra_stage < 5) + rtl8188e_rate_decision(ra); + else if (ra->ra_stage == 5) + rtl8188e_power_training_try_state(ra); + else /* ra->ra_stage == 6 */ + rtl8188e_power_training_decision(ra); + + if (ra->ra_stage <= 5) + ra->ra_stage++; + else + ra->ra_stage = 0; + } + } else if (macid == 0) { + dev_warn(dev, "%s: TX report item 0 not valid\n", __func__); + } + + dev_dbg(dev, "%s: valid: %d retry: %d %d %d %d %d drop: %d\n", + __func__, valid, + ra->retry[0], ra->retry[1], ra->retry[2], + ra->retry[3], ra->retry[4], ra->drop); + + if (min_rpt_time > ra->rpt_time) + min_rpt_time = ra->rpt_time; + + rpt += TX_RPT2_ITEM_SIZE; + + /* + * We only use macid 0, so only the first item is relevant. + * AP mode will use more of them if it's ever implemented. + */ + break; + } + + if (min_rpt_time != ra->pre_min_rpt_time) { + rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, min_rpt_time); + ra->pre_min_rpt_time = min_rpt_time; + } +} + +static void rtl8188e_arfb_refresh(struct rtl8xxxu_ra_info *ra) +{ + s8 i; + + ra->ra_use_rate = ra->rate_mask; + + /* Highest rate */ + if (ra->ra_use_rate) { + for (i = RATESIZE; i >= 0; i--) { + if (ra->ra_use_rate & BIT(i)) { + ra->highest_rate = i; + break; + } + } + } else { + ra->highest_rate = 0; + } + + /* Lowest rate */ + if (ra->ra_use_rate) { + for (i = 0; i < RATESIZE; i++) { + if (ra->ra_use_rate & BIT(i)) { + ra->lowest_rate = i; + break; + } + } + } else { + ra->lowest_rate = 0; + } + + if (ra->highest_rate > DESC_RATE_MCS7) + ra->pt_mode_ss = 3; + else if (ra->highest_rate > DESC_RATE_54M) + ra->pt_mode_ss = 2; + else if (ra->highest_rate > DESC_RATE_11M) + ra->pt_mode_ss = 1; + else + ra->pt_mode_ss = 0; +} + +static void +rtl8188e_update_rate_mask(struct rtl8xxxu_priv *priv, + u32 ramask, u8 rateid, int sgi, int txbw_40mhz) +{ + struct rtl8xxxu_ra_info *ra = &priv->ra_info; + + ra->rate_id = rateid; + ra->rate_mask = ramask; + ra->sgi_enable = sgi; + + rtl8188e_arfb_refresh(ra); +} + +static void rtl8188e_ra_set_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi) +{ + priv->ra_info.rssi_sta_ra = rssi; +} + +void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra) +{ + ra->decision_rate = DESC_RATE_MCS7; + ra->pre_rate = DESC_RATE_MCS7; + ra->highest_rate = DESC_RATE_MCS7; + ra->lowest_rate = 0; + ra->rate_id = 0; + ra->rate_mask = 0xfffff; + ra->rssi_sta_ra = 0; + ra->pre_rssi_sta_ra = 0; + ra->sgi_enable = 0; + ra->ra_use_rate = 0xfffff; + ra->nsc_down = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2; + ra->nsc_up = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2; + ra->rate_sgi = 0; + ra->rpt_time = 0x927c; + ra->drop = 0; + ra->retry[0] = 0; + ra->retry[1] = 0; + ra->retry[2] = 0; + ra->retry[3] = 0; + ra->retry[4] = 0; + ra->total = 0; + ra->ra_waiting_counter = 0; + ra->ra_pending_counter = 0; + ra->ra_drop_after_down = 0; + + ra->pt_try_state = 0; + ra->pt_stage = 5; + ra->pt_smooth_factor = 192; + ra->pt_stop_count = 0; + ra->pt_pre_rate = 0; + ra->pt_pre_rssi = 0; + ra->pt_mode_ss = 0; + ra->ra_stage = 0; +} + +struct rtl8xxxu_fileops rtl8188eu_fops = { + .identify_chip = rtl8188eu_identify_chip, + .parse_efuse = rtl8188eu_parse_efuse, + .load_firmware = rtl8188eu_load_firmware, + .power_on = rtl8188eu_power_on, + .power_off = rtl8188eu_power_off, + .reset_8051 = rtl8188eu_reset_8051, + .llt_init = rtl8xxxu_init_llt_table, + .init_phy_bb = rtl8188eu_init_phy_bb, + .init_phy_rf = rtl8188eu_init_phy_rf, + .phy_lc_calibrate = rtl8723a_phy_lc_calibrate, + .phy_iq_calibrate = rtl8188eu_phy_iq_calibrate, + .config_channel = rtl8188eu_config_channel, + .parse_rx_desc = rtl8xxxu_parse_rxdesc16, + .init_aggregation = rtl8188eu_init_aggregation, + .enable_rf = rtl8188e_enable_rf, + .disable_rf = rtl8188e_disable_rf, + .usb_quirks = rtl8188e_usb_quirks, + .set_tx_power = rtl8188f_set_tx_power, + .update_rate_mask = rtl8188e_update_rate_mask, + .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8188e_ra_set_rssi, + .fill_txdesc = rtl8xxxu_fill_txdesc_v3, + .set_crystal_cap = rtl8188f_set_crystal_cap, + .cck_rssi = rtl8188e_cck_rssi, + .led_classdev_brightness_set = rtl8188eu_led_brightness_set, + .writeN_block_size = 128, + .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), + .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), + .has_tx_report = 1, + .gen2_thermal_meter = 1, + .adda_1t_init = 0x0b1b25a0, + .adda_1t_path_on = 0x0bdb25a0, + /* + * Use 9K for 8188e normal chip + * Max RX buffer = 10K - max(TxReportSize(64*8), WOLPattern(16*24)) + */ + .trxff_boundary = 0x25ff, + .pbp_rx = PBP_PAGE_SIZE_128, + .pbp_tx = PBP_PAGE_SIZE_128, + .mactable = rtl8188e_mac_init_table, + .total_page_num = TX_TOTAL_PAGE_NUM_8188E, + .page_num_hi = TX_PAGE_NUM_HI_PQ_8188E, + .page_num_lo = TX_PAGE_NUM_LO_PQ_8188E, + .page_num_norm = TX_PAGE_NUM_NORM_PQ_8188E, + .last_llt_entry = 175, +}; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 2c4f403ba68f..af6e2c8a5025 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -370,7 +370,7 @@ static void rtl8188f_channel_to_group(int channel, int *group, int *cck_group) *cck_group = *group; } -static void +void rtl8188f_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) { u32 val32, ofdm, mcs; @@ -716,7 +716,6 @@ static void rtl8188fu_init_statistics(struct rtl8xxxu_priv *priv) static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8188fu_efuse *efuse = &priv->efuse_wifi.efuse8188fu; - int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; @@ -738,22 +737,12 @@ static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv) dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.7s\n", efuse->device_name); - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8188fu_efuse)); - for (i = 0; i < sizeof(struct rtl8188fu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } - return 0; } static int rtl8188fu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; fw_name = "rtlwifi/rtl8188fufw.bin"; @@ -1122,7 +1111,7 @@ static void rtl8188fu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, if (t == 0) { val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1); - priv->pi_enabled = val32 & FPGA0_HSSI_PARM1_PI; + priv->pi_enabled = u32_get_bits(val32, FPGA0_HSSI_PARM1_PI); } /* save RF path */ @@ -1662,7 +1651,7 @@ static void rtl8188f_usb_quirks(struct rtl8xxxu_priv *priv) #define XTAL1 GENMASK(22, 17) #define XTAL0 GENMASK(16, 11) -static void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) +void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) { struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; u32 val32; @@ -1693,8 +1682,8 @@ static s8 rtl8188f_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) s8 rx_pwr_all = 0x00; u8 vga_idx, lna_idx; - lna_idx = (cck_agc_rpt & 0xE0) >> 5; - vga_idx = cck_agc_rpt & 0x1F; + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); switch (lna_idx) { case 7: @@ -1743,6 +1732,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .set_tx_power = rtl8188f_set_tx_power, .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8xxxu_gen2_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, .set_crystal_cap = rtl8188f_set_crystal_cap, .cck_rssi = rtl8188f_cck_rssi, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c index 3bef9ffc8b02..e61d65c3579b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c @@ -386,7 +386,7 @@ out: static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; if (!priv->vendor_umc) @@ -404,7 +404,6 @@ static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8192cu_efuse *efuse = &priv->efuse_wifi.efuse8192; - int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) return -EINVAL; @@ -457,15 +456,6 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) priv->power_base = &rtl8188r_power_base; } - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8192cu_efuse)); - for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } return 0; } @@ -619,6 +609,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = { .set_tx_power = rtl8xxxu_gen1_set_tx_power, .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, + .report_rssi = rtl8xxxu_gen1_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v1, .cck_rssi = rtl8723a_cck_rssi, .writeN_block_size = 128, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index a7d76693c02d..5cfc00237f42 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -704,21 +704,12 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) rtl8192eu_log_next_device_info(priv, "Product", efuse->device_info, &record_offset); rtl8192eu_log_next_device_info(priv, "Serial", efuse->device_info, &record_offset); - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8192eu_efuse)); - for (i = 0; i < sizeof(struct rtl8192eu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } return 0; } static int rtl8192eu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; fw_name = "rtlwifi/rtl8192eu_nic.bin"; @@ -1744,6 +1735,11 @@ static void rtl8192e_enable_rf(struct rtl8xxxu_priv *priv) val8 = rtl8xxxu_read8(priv, REG_PAD_CTRL1); val8 &= ~BIT(0); rtl8xxxu_write8(priv, REG_PAD_CTRL1, val8); + + /* + * Fix transmission failure of rtl8192e. + */ + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); } static s8 rtl8192e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) @@ -1755,8 +1751,8 @@ static s8 rtl8192e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) u8 vga_idx, lna_idx; s8 lna_gain = 0; - lna_idx = (cck_agc_rpt & 0xE0) >> 5; - vga_idx = cck_agc_rpt & 0x1F; + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); if (priv->cck_agc_report_type == 0) lna_gain = lna_gain_table_0[lna_idx]; @@ -1768,6 +1764,29 @@ static s8 rtl8192e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) return rx_pwr_all; } +static int rtl8192eu_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rtl8xxxu_priv *priv = container_of(led_cdev, + struct rtl8xxxu_priv, + led_cdev); + u8 ledcfg = rtl8xxxu_read8(priv, REG_LEDCFG1); + + if (brightness == LED_OFF) { + ledcfg &= ~LEDCFG1_HW_LED_CONTROL; + ledcfg |= LEDCFG1_LED_DISABLE; + } else if (brightness == LED_ON) { + ledcfg &= ~(LEDCFG1_HW_LED_CONTROL | LEDCFG1_LED_DISABLE); + } else if (brightness == RTL8XXXU_HW_LED_CONTROL) { + ledcfg &= ~LEDCFG1_LED_DISABLE; + ledcfg |= LEDCFG1_HW_LED_CONTROL; + } + + rtl8xxxu_write8(priv, REG_LEDCFG1, ledcfg); + + return 0; +} + struct rtl8xxxu_fileops rtl8192eu_fops = { .identify_chip = rtl8192eu_identify_chip, .parse_efuse = rtl8192eu_parse_efuse, @@ -1788,9 +1807,11 @@ struct rtl8xxxu_fileops rtl8192eu_fops = { .set_tx_power = rtl8192e_set_tx_power, .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8xxxu_gen2_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, .set_crystal_cap = rtl8723a_set_crystal_cap, .cck_rssi = rtl8192e_cck_rssi, + .led_classdev_brightness_set = rtl8192eu_led_brightness_set, .writeN_block_size = 128, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c index 707ac48ecc83..5e7b58d395ba 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c @@ -231,7 +231,7 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; switch (priv->chip_cut) { @@ -457,6 +457,30 @@ s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) return rx_pwr_all; } +static int rtl8723au_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rtl8xxxu_priv *priv = container_of(led_cdev, + struct rtl8xxxu_priv, + led_cdev); + u8 ledcfg = rtl8xxxu_read8(priv, REG_LEDCFG2); + + if (brightness == LED_OFF) { + ledcfg &= ~LEDCFG2_HW_LED_CONTROL; + ledcfg |= LEDCFG2_SW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE; + } else if (brightness == LED_ON) { + ledcfg &= ~(LEDCFG2_HW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE); + ledcfg |= LEDCFG2_SW_LED_CONTROL; + } else if (brightness == RTL8XXXU_HW_LED_CONTROL) { + ledcfg &= ~LEDCFG2_SW_LED_DISABLE; + ledcfg |= LEDCFG2_HW_LED_CONTROL | LEDCFG2_HW_LED_ENABLE; + } + + rtl8xxxu_write8(priv, REG_LEDCFG2, ledcfg); + + return 0; +} + struct rtl8xxxu_fileops rtl8723au_fops = { .identify_chip = rtl8723au_identify_chip, .parse_efuse = rtl8723au_parse_efuse, @@ -478,9 +502,11 @@ struct rtl8xxxu_fileops rtl8723au_fops = { .set_tx_power = rtl8xxxu_gen1_set_tx_power, .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, + .report_rssi = rtl8xxxu_gen1_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v1, .set_crystal_cap = rtl8723a_set_crystal_cap, .cck_rssi = rtl8723a_cck_rssi, + .led_classdev_brightness_set = rtl8723au_led_brightness_set, .writeN_block_size = 1024, .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index a0ec895b61a4..21613d60dc22 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -497,23 +497,12 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.41s\n", efuse->device_name); - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { - int i; - unsigned char *raw = priv->efuse_wifi.raw; - - dev_info(&priv->udev->dev, - "%s: dumping efuse (0x%02zx bytes):\n", - __func__, sizeof(struct rtl8723bu_efuse)); - for (i = 0; i < sizeof(struct rtl8723bu_efuse); i += 8) - dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]); - } - return 0; } static int rtl8723bu_load_firmware(struct rtl8xxxu_priv *priv) { - char *fw_name; + const char *fw_name; int ret; if (priv->enable_bluetooth) @@ -1691,8 +1680,8 @@ static s8 rtl8723b_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) s8 rx_pwr_all = 0x00; u8 vga_idx, lna_idx; - lna_idx = (cck_agc_rpt & 0xE0) >> 5; - vga_idx = cck_agc_rpt & 0x1F; + lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK); + vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK); switch (lna_idx) { case 6: @@ -1738,6 +1727,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .set_tx_power = rtl8723b_set_tx_power, .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8xxxu_gen2_report_rssi, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, .set_crystal_cap = rtl8723a_set_crystal_cap, .cck_rssi = rtl8723b_cck_rssi, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 3ed435401e57..620a5cc2bfdd 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -34,7 +34,7 @@ #define DRIVER_NAME "rtl8xxxu" -int rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE; +int rtl8xxxu_debug; static bool rtl8xxxu_ht40_2g; static bool rtl8xxxu_dma_aggregation; static int rtl8xxxu_dma_agg_timeout = -1; @@ -46,6 +46,7 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin"); MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin"); MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); @@ -1581,10 +1582,11 @@ static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv) cut = 'A' + priv->chip_cut; dev_info(dev, - "RTL%s rev %c (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", - priv->chip_name, cut, priv->chip_vendor, priv->tx_paths, - priv->rx_paths, priv->ep_tx_count, priv->has_wifi, - priv->has_bluetooth, priv->has_gps, priv->hi_pa); + "RTL%s rev %c (%s) romver %d, %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", + priv->chip_name, cut, priv->chip_vendor, priv->rom_rev, + priv->tx_paths, priv->rx_paths, priv->ep_tx_count, + priv->has_wifi, priv->has_bluetooth, priv->has_gps, + priv->hi_pa); dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr); } @@ -1813,6 +1815,16 @@ exit: return ret; } +static void rtl8xxxu_dump_efuse(struct rtl8xxxu_priv *priv) +{ + dev_info(&priv->udev->dev, + "Dumping efuse for RTL%s (0x%02x bytes):\n", + priv->chip_name, EFUSE_MAP_LEN); + + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, + priv->efuse_wifi.raw, EFUSE_MAP_LEN, true); +} + void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv) { u8 val8; @@ -1970,7 +1982,7 @@ fw_abort: return ret; } -int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) +int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, const char *fw_name) { struct device *dev = &priv->udev->dev; const struct firmware *fw; @@ -2000,6 +2012,7 @@ int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) switch (signature & 0xfff0) { case 0x92e0: case 0x92c0: + case 0x88e0: case 0x88c0: case 0x5300: case 0x2300: @@ -2071,10 +2084,20 @@ rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv) } } - if (priv->rtl_chip != RTL8723B && - priv->rtl_chip != RTL8192E && - priv->rtl_chip != RTL8188F) + switch (priv->rtl_chip) { + case RTL8188C: + case RTL8188R: + case RTL8191C: + case RTL8192C: + case RTL8723A: rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a); + break; + case RTL8188E: + rtl8xxxu_write16(priv, REG_MAX_AGGR_NUM, 0x0707); + break; + default: + break; + } return 0; } @@ -2373,11 +2396,16 @@ static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data) int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv) { int ret; - int i; + int i, last_entry; u8 last_tx_page; last_tx_page = priv->fops->total_page_num; + if (priv->fops->last_llt_entry) + last_entry = priv->fops->last_llt_entry; + else + last_entry = 255; + for (i = 0; i < last_tx_page; i++) { ret = rtl8xxxu_llt_write(priv, i, i + 1); if (ret) @@ -2389,14 +2417,14 @@ int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv) goto exit; /* Mark remaining pages as a ring buffer */ - for (i = last_tx_page + 1; i < 0xff; i++) { + for (i = last_tx_page + 1; i < last_entry; i++) { ret = rtl8xxxu_llt_write(priv, i, (i + 1)); if (ret) goto exit; } /* Let last entry point to the start entry of ring buffer */ - ret = rtl8xxxu_llt_write(priv, 0xff, last_tx_page + 1); + ret = rtl8xxxu_llt_write(priv, last_entry, last_tx_page + 1); if (ret) goto exit; @@ -2704,8 +2732,8 @@ void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv, bool iqk_ok, #define MAX_TOLERANCE 5 -static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, - int result[][8], int c1, int c2) +bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2) { u32 i, j, diff, simubitmap, bound = 0; int candidate[2] = {-1, -1}; /* for path A and path B */ @@ -3898,7 +3926,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) goto exit; /* RFSW Control - clear bit 14 ?? */ - if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E) + if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E && + priv->rtl_chip != RTL8188E) rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW | @@ -3911,7 +3940,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32); /* 0x860[6:5]= 00 - why? - this sets antenna B */ - if (priv->rtl_chip != RTL8192E) + if (priv->rtl_chip != RTL8192E && priv->rtl_chip != RTL8188E) rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66f60210); if (!macpower) { @@ -3953,7 +3982,25 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * Enable TX report and TX report timer for 8723bu/8188eu/... */ if (fops->has_tx_report) { + /* + * The RTL8188EU has two types of TX reports: + * rpt_sel=1: + * One report for one frame. We can use this for frames + * with IEEE80211_TX_CTL_REQ_TX_STATUS. + * rpt_sel=2: + * One report for many frames transmitted over a period + * of time. (This is what REG_TX_REPORT_TIME is for.) The + * report includes the number of frames transmitted + * successfully, and the number of unsuccessful + * transmissions. We use this for software rate control. + * + * Bit 0 of REG_TX_REPORT_CTRL is required for both types. + * Bit 1 (TX_REPORT_CTRL_TIMER_ENABLE) is required for + * type 2. + */ val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL); + if (priv->rtl_chip == RTL8188E) + val8 |= BIT(0); val8 |= TX_REPORT_CTRL_TIMER_ENABLE; rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8); /* Set MAX RPT MACID */ @@ -3979,6 +4026,15 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) } else if (priv->rtl_chip == RTL8188F) { rtl8xxxu_write32(priv, REG_HISR0, 0xffffffff); rtl8xxxu_write32(priv, REG_HISR1, 0xffffffff); + } else if (priv->rtl_chip == RTL8188E) { + rtl8xxxu_write32(priv, REG_HISR0, 0xffffffff); + val32 = IMR0_PSTIMEOUT | IMR0_TBDER | IMR0_CPWM | IMR0_CPWM2; + rtl8xxxu_write32(priv, REG_HIMR0, val32); + val32 = IMR1_TXERR | IMR1_RXERR | IMR1_TXFOVW | IMR1_RXFOVW; + rtl8xxxu_write32(priv, REG_HIMR1, val32); + val8 = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION); + val8 |= USB_SPEC_INT_BULK_SELECT; + rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, val8); } else { /* * Enable all interrupts - not obvious USB needs to do this @@ -4084,7 +4140,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (fops->init_aggregation) fops->init_aggregation(priv); - if (priv->rtl_chip == RTL8188F) { + if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8188E) { rtl8xxxu_write16(priv, REG_PKT_VO_VI_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ rtl8xxxu_write16(priv, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ } @@ -4118,7 +4174,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* Disable BAR - not sure if this has any effect on USB */ rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff); - if (priv->rtl_chip != RTL8188F) + if (priv->rtl_chip != RTL8188F && priv->rtl_chip != RTL8188E) rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); if (fops->init_statistics) @@ -4136,9 +4192,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * Reset USB mode switch setting */ rtl8xxxu_write8(priv, REG_ACLK_MON, 0x00); - } else if (priv->rtl_chip == RTL8188F) { + } else if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8188E) { /* - * Init GPIO settings for 8188f + * Init GPIO settings for 8188f, 8188e */ val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG); val8 &= ~GPIO_MUXCFG_IO_SEL_ENBT; @@ -4184,7 +4240,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) val32 |= FPGA_RF_MODE_CCK; rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); } - } else if (priv->rtl_chip == RTL8192E) { + } else if (priv->rtl_chip == RTL8192E || priv->rtl_chip == RTL8188E) { rtl8xxxu_write8(priv, REG_USB_HRPWM, 0x00); } @@ -4208,10 +4264,12 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * should be equal or CCK RSSI report may be incorrect */ val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2); - priv->cck_agc_report_type = val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR; + priv->cck_agc_report_type = + u32_get_bits(val32, FPGA0_HSSI_PARM2_CCK_HIGH_PWR); val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_HSSI_PARM2); - if (priv->cck_agc_report_type != (bool)(val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)) { + if (priv->cck_agc_report_type != + u32_get_bits(val32, FPGA0_HSSI_PARM2_CCK_HIGH_PWR)) { if (priv->cck_agc_report_type) val32 |= FPGA0_HSSI_PARM2_CCK_HIGH_PWR; else @@ -4235,6 +4293,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) priv->cfo_tracking.crystal_cap = priv->default_crystal_cap; } + if (priv->rtl_chip == RTL8188E) + rtl8188e_ra_info_init_all(&priv->ra_info); + exit: return ret; } @@ -4401,6 +4462,37 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt)); } +void rtl8xxxu_gen1_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi) +{ + struct h2c_cmd h2c; + const int h2c_size = 4; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + + h2c.rssi_report.cmd = H2C_SET_RSSI; + h2c.rssi_report.macid = macid; + h2c.rssi_report.rssi = rssi; + + rtl8xxxu_gen1_h2c_cmd(priv, &h2c, h2c_size); +} + +void rtl8xxxu_gen2_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi) +{ + struct h2c_cmd h2c; + int h2c_size = sizeof(h2c.rssi_report); + + if (priv->rtl_chip == RTL8723B) + h2c_size = 4; + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + + h2c.rssi_report.cmd = H2C_8723B_RSSI_SETTING; + h2c.rssi_report.macid = macid; + h2c.rssi_report.rssi = rssi; + + rtl8xxxu_gen2_h2c_cmd(priv, &h2c, h2c_size); +} + void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv) { u8 agg_ctrl, usb_spec, page_thresh, timeout; @@ -4598,8 +4690,8 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time) } } -static void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt, - u8 rate, u8 sgi, u8 bw) +void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt, + u8 rate, u8 sgi, u8 bw) { u8 mcs, nss; @@ -5069,6 +5161,98 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, } } +/* + * Fill in v3 (gen1) specific TX descriptor bits. + * This format is a hybrid between the v1 and v2 formats, only seen + * on 8188eu devices so far. + */ +void +rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + struct ieee80211_tx_info *tx_info, + struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, + bool short_preamble, bool ampdu_enable, u32 rts_rate) +{ + struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + struct rtl8xxxu_ra_info *ra = &priv->ra_info; + u8 *qc = ieee80211_get_qos_ctl(hdr); + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + u32 rate; + u16 rate_flags = tx_info->control.rates[0].flags; + u16 seq_number; + + if (rate_flags & IEEE80211_TX_RC_MCS && + !ieee80211_is_mgmt(hdr->frame_control)) + rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; + else + rate = tx_rate->hw_value; + + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + if (ieee80211_is_data(hdr->frame_control)) { + rate = ra->decision_rate; + tx_desc->txdw5 = cpu_to_le32(rate); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_USE_DRIVER_RATE); + tx_desc->txdw4 |= le32_encode_bits(ra->pt_stage, TXDESC32_PT_STAGE_MASK); + /* Data/RTS rate FB limit */ + tx_desc->txdw5 |= cpu_to_le32(0x0001ff00); + } + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) + dev_info(dev, "%s: TX rate: %d, pkt size %d\n", + __func__, rate, le16_to_cpu(tx_desc->pkt_size)); + + tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC32_SEQ_SHIFT); + + if (ampdu_enable && test_bit(tid, priv->tid_tx_operational)) + tx_desc->txdw2 |= cpu_to_le32(TXDESC40_AGG_ENABLE); + else + tx_desc->txdw2 |= cpu_to_le32(TXDESC40_AGG_BREAK); + + if (ieee80211_is_mgmt(hdr->frame_control)) { + tx_desc->txdw5 = cpu_to_le32(rate); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_USE_DRIVER_RATE); + tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC32_RETRY_LIMIT_SHIFT); + tx_desc->txdw5 |= cpu_to_le32(TXDESC32_RETRY_LIMIT_ENABLE); + } + + if (ieee80211_is_data_qos(hdr->frame_control)) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_QOS); + + if (conf_is_ht40(&hw->conf)) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC_DATA_BW); + + if (conf_is_ht40_minus(&hw->conf)) + tx_desc->txdw4 |= cpu_to_le32(TXDESC_PRIME_CH_OFF_UPPER); + else + tx_desc->txdw4 |= cpu_to_le32(TXDESC_PRIME_CH_OFF_LOWER); + } + } + + if (short_preamble) + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_SHORT_PREAMBLE); + + if (sgi && ra->rate_sgi) + tx_desc->txdw5 |= cpu_to_le32(TXDESC32_SHORT_GI); + + /* + * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled + */ + tx_desc->txdw4 |= cpu_to_le32(rts_rate << TXDESC32_RTS_RATE_SHIFT); + if (ampdu_enable || (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_RTS_CTS_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); + } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_CTS_SELF_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); + } + + tx_desc->txdw2 |= cpu_to_le32(TXDESC_ANTENNA_SELECT_A | + TXDESC_ANTENNA_SELECT_B); + tx_desc->txdw7 |= cpu_to_le16(TXDESC_ANTENNA_SELECT_C >> 16); +} + static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -5274,7 +5458,7 @@ static void rtl8xxxu_queue_rx_urb(struct rtl8xxxu_priv *priv, pending = priv->rx_urb_pending_count; } else { skb = (struct sk_buff *)rx_urb->urb.context; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); usb_free_urb(&rx_urb->urb); } @@ -5550,9 +5734,6 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) btcoex = &priv->bt_coex; rarpt = &priv->ra_report; - if (priv->rf_paths > 1) - goto out; - while (!skb_queue_empty(&priv->c2hcmd_queue)) { skb = skb_dequeue(&priv->c2hcmd_queue); @@ -5585,10 +5766,9 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) default: break; } - } -out: - dev_kfree_skb(skb); + dev_kfree_skb(skb); + } } static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, @@ -5640,6 +5820,44 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, schedule_work(&priv->c2hcmd_work); } +static void rtl8188e_c2hcmd_callback(struct work_struct *work) +{ + struct rtl8xxxu_priv *priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work); + struct device *dev = &priv->udev->dev; + struct sk_buff *skb = NULL; + struct rtl8xxxu_rxdesc16 *rx_desc; + + while (!skb_queue_empty(&priv->c2hcmd_queue)) { + skb = skb_dequeue(&priv->c2hcmd_queue); + + rx_desc = (struct rtl8xxxu_rxdesc16 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16)); + + switch (rx_desc->rpt_sel) { + case 1: + dev_dbg(dev, "C2H TX report type 1\n"); + + break; + case 2: + dev_dbg(dev, "C2H TX report type 2\n"); + + rtl8188e_handle_ra_tx_report2(priv, skb); + + break; + case 3: + dev_dbg(dev, "C2H USB interrupt report\n"); + + break; + default: + dev_warn(dev, "%s: rpt_sel should not be %d\n", + __func__, rx_desc->rpt_sel); + + break; + } + + dev_kfree_skb(skb); + } +} + int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct ieee80211_hw *hw = priv->hw; @@ -5695,38 +5913,45 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16)); - phy_stats = (struct rtl8723au_phy_stats *)skb->data; + if (rx_desc->rpt_sel) { + skb_queue_tail(&priv->c2hcmd_queue, skb); + schedule_work(&priv->c2hcmd_work); + } else { + phy_stats = (struct rtl8723au_phy_stats *)skb->data; - skb_pull(skb, drvinfo_sz + desc_shift); + skb_pull(skb, drvinfo_sz + desc_shift); - skb_trim(skb, pkt_len); + skb_trim(skb, pkt_len); - if (rx_desc->phy_stats) - rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, - rx_desc->rxmcs, (struct ieee80211_hdr *)skb->data, - rx_desc->crc32 || rx_desc->icverr); + if (rx_desc->phy_stats) + rtl8xxxu_rx_parse_phystats( + priv, rx_status, phy_stats, + rx_desc->rxmcs, + (struct ieee80211_hdr *)skb->data, + rx_desc->crc32 || rx_desc->icverr); - rx_status->mactime = rx_desc->tsfl; - rx_status->flag |= RX_FLAG_MACTIME_START; + rx_status->mactime = rx_desc->tsfl; + rx_status->flag |= RX_FLAG_MACTIME_START; - if (!rx_desc->swdec) - rx_status->flag |= RX_FLAG_DECRYPTED; - if (rx_desc->crc32) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rx_desc->bw) - rx_status->bw = RATE_INFO_BW_40; + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->bw = RATE_INFO_BW_40; - if (rx_desc->rxht) { - rx_status->encoding = RX_ENC_HT; - rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; - } else { - rx_status->rate_idx = rx_desc->rxmcs; - } + if (rx_desc->rxht) { + rx_status->encoding = RX_ENC_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->band = hw->conf.chandef.chan->band; + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; - ieee80211_rx_irqsafe(hw, skb); + ieee80211_rx_irqsafe(hw, skb); + } skb = next_skb; if (skb) @@ -5956,7 +6181,6 @@ static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) { struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; - u16 val16; int ret = 0, channel; bool ht40; @@ -5966,14 +6190,6 @@ static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) __func__, hw->conf.chandef.chan->hw_value, changed, hw->conf.chandef.width); - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - val16 = ((hw->conf.long_frame_max_tx_count << - RETRY_LIMIT_LONG_SHIFT) & RETRY_LIMIT_LONG_MASK) | - ((hw->conf.short_frame_max_tx_count << - RETRY_LIMIT_SHORT_SHIFT) & RETRY_LIMIT_SHORT_MASK); - rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16); - } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { switch (hw->conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: @@ -6504,6 +6720,9 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) signal = ieee80211_ave_rssi(vif); + priv->fops->report_rssi(priv, 0, + rtl8xxxu_signal_to_snr(signal)); + if (priv->fops->set_crystal_cap) rtl8xxxu_track_cfo(priv); @@ -6587,7 +6806,10 @@ exit: rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff); rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff); - rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e); + if (priv->rtl_chip == RTL8188E) + rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6955341e); + else + rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e); return ret; @@ -6733,6 +6955,40 @@ exit: return ret; } +static void rtl8xxxu_init_led(struct rtl8xxxu_priv *priv) +{ + struct led_classdev *led = &priv->led_cdev; + + if (!priv->fops->led_classdev_brightness_set) + return; + + led->brightness_set_blocking = priv->fops->led_classdev_brightness_set; + + snprintf(priv->led_name, sizeof(priv->led_name), + "rtl8xxxu-usb%s", dev_name(&priv->udev->dev)); + led->name = priv->led_name; + led->max_brightness = RTL8XXXU_HW_LED_CONTROL; + + if (led_classdev_register(&priv->udev->dev, led)) + return; + + priv->led_registered = true; + + led->brightness = led->max_brightness; + priv->fops->led_classdev_brightness_set(led, led->brightness); +} + +static void rtl8xxxu_deinit_led(struct rtl8xxxu_priv *priv) +{ + struct led_classdev *led = &priv->led_cdev; + + if (!priv->led_registered) + return; + + priv->fops->led_classdev_brightness_set(led, LED_OFF); + led_classdev_unregister(led); +} + static int rtl8xxxu_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -6754,6 +7010,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, case 0x817f: case 0x818b: case 0xf179: + case 0x8179: untested = 0; break; } @@ -6809,7 +7066,6 @@ static int rtl8xxxu_probe(struct usb_interface *interface, spin_lock_init(&priv->rx_urb_lock); INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback); - INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback); skb_queue_head_init(&priv->c2hcmd_queue); usb_set_intfdata(interface, hw); @@ -6827,6 +7083,11 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->wiphy->available_antennas_tx = BIT(priv->tx_paths) - 1; hw->wiphy->available_antennas_rx = BIT(priv->rx_paths) - 1; + if (priv->rtl_chip == RTL8188E) + INIT_WORK(&priv->c2hcmd_work, rtl8188e_c2hcmd_callback); + else + INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback); + ret = rtl8xxxu_read_efuse(priv); if (ret) { dev_err(&udev->dev, "Fatal - failed to read EFuse\n"); @@ -6839,6 +7100,9 @@ static int rtl8xxxu_probe(struct usb_interface *interface, goto err_set_intfdata; } + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) + rtl8xxxu_dump_efuse(priv); + rtl8xxxu_print_chipinfo(priv); ret = priv->fops->load_firmware(priv); @@ -6887,8 +7151,10 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->extra_tx_headroom = priv->fops->tx_desc_size; ieee80211_hw_set(hw, SIGNAL_DBM); + /* - * The firmware handles rate control + * The firmware handles rate control, except for RTL8188EU, + * where we handle the rate control in the driver. */ ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); @@ -6903,6 +7169,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, goto err_set_intfdata; } + rtl8xxxu_init_led(priv); + return 0; err_set_intfdata: @@ -6927,6 +7195,8 @@ static void rtl8xxxu_disconnect(struct usb_interface *interface) hw = usb_get_intfdata(interface); priv = hw->priv; + rtl8xxxu_deinit_led(priv); + ieee80211_unregister_hw(hw); priv->fops->power_off(priv); @@ -6973,6 +7243,50 @@ static const struct usb_device_id dev_table[] = { /* RTL8188FU */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xf179, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8188fu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8179, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Tested by Hans de Goede - rtl8188etv */ +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0179, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Sitecom rtl8188eus */ +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0076, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link USB-GO-N150 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3311, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link DWA-125 REV D1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330f, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link DWA-123 REV D1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3310, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* D-Link DWA-121 rev B1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Abocom - Abocom */ +{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8179, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Elecom WDC-150SU2M */ +{USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x4008, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* TP-Link TL-WN722N v2 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x010c, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* TP-Link TL-WN727N v5.21 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0111, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* MERCUSYS MW150US v2 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0102, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* ASUS USB-N10 Nano B1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x18f0, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, + /* Edimax EW-7811Un V2 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb811, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, +/* Rosewill USB-N150 Nano */ +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xffef, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8188eu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 3e79efdfb4c2..5849fa4e1566 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -147,7 +147,13 @@ #define REG_LEDCFG0 0x004c #define LEDCFG0_DPDT_SELECT BIT(23) #define REG_LEDCFG1 0x004d +#define LEDCFG1_HW_LED_CONTROL BIT(1) +#define LEDCFG1_LED_DISABLE BIT(7) #define REG_LEDCFG2 0x004e +#define LEDCFG2_HW_LED_CONTROL BIT(1) +#define LEDCFG2_HW_LED_ENABLE BIT(5) +#define LEDCFG2_SW_LED_DISABLE BIT(3) +#define LEDCFG2_SW_LED_CONTROL BIT(5) #define LEDCFG2_DPDT_SELECT BIT(7) #define REG_LEDCFG3 0x004f #define REG_LEDCFG REG_LEDCFG2 @@ -371,6 +377,11 @@ #define PBP_PAGE_SIZE_512 0x3 #define PBP_PAGE_SIZE_1024 0x4 +/* 8188eu IOL magic */ +#define REG_PKT_BUF_ACCESS_CTRL 0x0106 +#define PKT_BUF_ACCESS_CTRL_TX 0x69 +#define PKT_BUF_ACCESS_CTRL_RX 0xa5 + #define REG_TRXDMA_CTRL 0x010c #define TRXDMA_CTRL_RXDMA_AGG_EN BIT(2) #define TRXDMA_CTRL_VOQ_SHIFT 4 @@ -407,6 +418,8 @@ #define REG_MBIST_START 0x0174 #define REG_MBIST_DONE 0x0178 #define REG_MBIST_FAIL 0x017c +/* 8188EU */ +#define REG_32K_CTRL 0x0194 #define REG_C2HEVT_MSG_NORMAL 0x01a0 /* 8192EU/8723BU/8812 */ #define REG_C2HEVT_CMD_ID_8723B 0x01ae @@ -942,6 +955,16 @@ #define REG_FPGA1_RF_MODE 0x0900 #define REG_FPGA1_TX_INFO 0x090c +#define FPGA1_TX_ANT_MASK 0x0000000f +#define FPGA1_TX_ANT_L_MASK 0x000000f0 +#define FPGA1_TX_ANT_NON_HT_MASK 0x00000f00 +#define FPGA1_TX_ANT_HT1_MASK 0x0000f000 +#define FPGA1_TX_ANT_HT2_MASK 0x000f0000 +#define FPGA1_TX_ANT_HT_S1_MASK 0x00f00000 +#define FPGA1_TX_ANT_NON_HT_S1_MASK 0x0f000000 +#define FPGA1_TX_OFDM_TXSC_MASK 0x30000000 + +#define REG_ANT_MAPPING1 0x0914 #define REG_DPDT_CTRL 0x092c /* 8723BU */ #define REG_RFE_CTRL_ANTA_SRC 0x0930 /* 8723BU */ #define REG_RFE_PATH_SELECT 0x0940 /* 8723BU */ @@ -954,9 +977,25 @@ #define REG_CCK0_AFE_SETTING 0x0a04 #define CCK0_AFE_RX_MASK 0x0f000000 -#define CCK0_AFE_RX_ANT_AB BIT(24) +#define CCK0_AFE_TX_MASK 0xf0000000 #define CCK0_AFE_RX_ANT_A 0 -#define CCK0_AFE_RX_ANT_B (BIT(24) | BIT(26)) +#define CCK0_AFE_RX_ANT_B BIT(26) +#define CCK0_AFE_RX_ANT_C BIT(27) +#define CCK0_AFE_RX_ANT_D (BIT(26) | BIT(27)) +#define CCK0_AFE_RX_ANT_OPTION_A 0 +#define CCK0_AFE_RX_ANT_OPTION_B BIT(24) +#define CCK0_AFE_RX_ANT_OPTION_C BIT(25) +#define CCK0_AFE_RX_ANT_OPTION_D (BIT(24) | BIT(25)) +#define CCK0_AFE_TX_ANT_A BIT(31) +#define CCK0_AFE_TX_ANT_B BIT(30) + +#define REG_CCK_ANTDIV_PARA2 0x0a04 +#define REG_BB_POWER_SAVE4 0x0a74 + +/* 8188eu */ +#define REG_LNA_SWITCH 0x0b2c +#define LNA_SWITCH_DISABLE_CSCG BIT(22) +#define LNA_SWITCH_OUTPUT_CG BIT(31) #define REG_CCK_PD_THRESH 0x0a0a #define CCK_PD_TYPE1_LV0_TH 0x40 @@ -1020,6 +1059,9 @@ #define REG_OFDM0_RX_IQ_EXT_ANTA 0x0ca0 +/* 8188eu */ +#define REG_ANTDIV_PARA1 0x0ca4 + /* 8723bu */ #define REG_OFDM0_TX_PSDO_NOISE_WEIGHT 0x0ce4 diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index 58c2ab3d44be..de61c9c0ddec 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -68,8 +68,10 @@ static void _rtl88ee_return_beacon_queue_skb(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct sk_buff_head free_list; unsigned long flags; + skb_queue_head_init(&free_list); spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); while (skb_queue_len(&ring->queue)) { struct rtl_tx_desc *entry = &ring->desc[ring->idx]; @@ -79,10 +81,12 @@ static void _rtl88ee_return_beacon_queue_skb(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), skb->len, DMA_TO_DEVICE); - kfree_skb(skb); + __skb_queue_tail(&free_list, skb); ring->idx = (ring->idx + 1) % ring->entries; } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + __skb_queue_purge(&free_list); } static void _rtl88ee_disable_bcn_sub_func(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h index 0455a3712f3e..12cdecdafc32 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_bt_coexist.h @@ -116,7 +116,7 @@ void rtl8723e_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw); long rtl8723e_dm_bt_get_rx_ss(struct ieee80211_hw *hw); void rtl8723e_dm_bt_balance(struct ieee80211_hw *hw, bool balance_on, u8 ms0, u8 ms1); -void rtl8723e_dm_bt_agc_table(struct ieee80211_hw *hw, u8 tyep); +void rtl8723e_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type); void rtl8723e_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type); u8 rtl8723e_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw, u8 level_num, u8 rssi_thresh, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 189cc6437600..0ba3bbed6ed3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -30,8 +30,10 @@ static void _rtl8723be_return_beacon_queue_skb(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct sk_buff_head free_list; unsigned long flags; + skb_queue_head_init(&free_list); spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); while (skb_queue_len(&ring->queue)) { struct rtl_tx_desc *entry = &ring->desc[ring->idx]; @@ -41,10 +43,12 @@ static void _rtl8723be_return_beacon_queue_skb(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), skb->len, DMA_TO_DEVICE); - kfree_skb(skb); + __skb_queue_tail(&free_list, skb); ring->idx = (ring->idx + 1) % ring->entries; } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + __skb_queue_purge(&free_list); } static void _rtl8723be_set_bcn_ctrl_reg(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 7e0f62d59fe1..a7e3250957dc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -26,8 +26,10 @@ static void _rtl8821ae_return_beacon_queue_skb(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct sk_buff_head free_list; unsigned long flags; + skb_queue_head_init(&free_list); spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); while (skb_queue_len(&ring->queue)) { struct rtl_tx_desc *entry = &ring->desc[ring->idx]; @@ -37,10 +39,12 @@ static void _rtl8821ae_return_beacon_queue_skb(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_desc(hw, (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), skb->len, DMA_TO_DEVICE); - kfree_skb(skb); + __skb_queue_tail(&free_list, skb); ring->idx = (ring->idx + 1) % ring->entries; } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + __skb_queue_purge(&free_list); } static void _rtl8821ae_set_bcn_ctrl_reg(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index a29321e2fa72..5323ead30db0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -1598,18 +1598,6 @@ static bool _rtl8812ae_get_integer_from_string(const char *str, u8 *pint) return true; } -static bool _rtl8812ae_eq_n_byte(const char *str1, const char *str2, u32 num) -{ - if (num == 0) - return false; - while (num > 0) { - num--; - if (str1[num] != str2[num]) - return false; - } - return true; -} - static s8 _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw, u8 band, u8 channel) { @@ -1659,42 +1647,42 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, power_limit = power_limit > MAX_POWER_INDEX ? MAX_POWER_INDEX : power_limit; - if (_rtl8812ae_eq_n_byte(pregulation, "FCC", 3)) + if (strcmp(pregulation, "FCC") == 0) regulation = 0; - else if (_rtl8812ae_eq_n_byte(pregulation, "MKK", 3)) + else if (strcmp(pregulation, "MKK") == 0) regulation = 1; - else if (_rtl8812ae_eq_n_byte(pregulation, "ETSI", 4)) + else if (strcmp(pregulation, "ETSI") == 0) regulation = 2; - else if (_rtl8812ae_eq_n_byte(pregulation, "WW13", 4)) + else if (strcmp(pregulation, "WW13") == 0) regulation = 3; - if (_rtl8812ae_eq_n_byte(prate_section, "CCK", 3)) + if (strcmp(prate_section, "CCK") == 0) rate_section = 0; - else if (_rtl8812ae_eq_n_byte(prate_section, "OFDM", 4)) + else if (strcmp(prate_section, "OFDM") == 0) rate_section = 1; - else if (_rtl8812ae_eq_n_byte(prate_section, "HT", 2) && - _rtl8812ae_eq_n_byte(prf_path, "1T", 2)) + else if (strcmp(prate_section, "HT") == 0 && + strcmp(prf_path, "1T") == 0) rate_section = 2; - else if (_rtl8812ae_eq_n_byte(prate_section, "HT", 2) && - _rtl8812ae_eq_n_byte(prf_path, "2T", 2)) + else if (strcmp(prate_section, "HT") == 0 && + strcmp(prf_path, "2T") == 0) rate_section = 3; - else if (_rtl8812ae_eq_n_byte(prate_section, "VHT", 3) && - _rtl8812ae_eq_n_byte(prf_path, "1T", 2)) + else if (strcmp(prate_section, "VHT") == 0 && + strcmp(prf_path, "1T") == 0) rate_section = 4; - else if (_rtl8812ae_eq_n_byte(prate_section, "VHT", 3) && - _rtl8812ae_eq_n_byte(prf_path, "2T", 2)) + else if (strcmp(prate_section, "VHT") == 0 && + strcmp(prf_path, "2T") == 0) rate_section = 5; - if (_rtl8812ae_eq_n_byte(pbandwidth, "20M", 3)) + if (strcmp(pbandwidth, "20M") == 0) bandwidth = 0; - else if (_rtl8812ae_eq_n_byte(pbandwidth, "40M", 3)) + else if (strcmp(pbandwidth, "40M") == 0) bandwidth = 1; - else if (_rtl8812ae_eq_n_byte(pbandwidth, "80M", 3)) + else if (strcmp(pbandwidth, "80M") == 0) bandwidth = 2; - else if (_rtl8812ae_eq_n_byte(pbandwidth, "160M", 4)) + else if (strcmp(pbandwidth, "160M") == 0) bandwidth = 3; - if (_rtl8812ae_eq_n_byte(pband, "2.4G", 4)) { + if (strcmp(pband, "2.4G") == 0) { ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw, BAND_ON_2_4G, channel); @@ -1718,7 +1706,7 @@ static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, regulation, bandwidth, rate_section, channel_index, rtlphy->txpwr_limit_2_4g[regulation][bandwidth] [rate_section][channel_index][RF90_PATH_A]); - } else if (_rtl8812ae_eq_n_byte(pband, "5G", 2)) { + } else if (strcmp(pband, "5G") == 0) { ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw, BAND_ON_5G, channel); diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c index 038a30b170ef..c827c4a2814b 100644 --- a/drivers/net/wireless/realtek/rtw88/bf.c +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -49,19 +49,23 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, sta = ieee80211_find_sta(vif, bssid); if (!sta) { + rcu_read_unlock(); + rtw_warn(rtwdev, "failed to find station entry for bss %pM\n", bssid); - goto out_unlock; + return; } ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap; vht_cap = &sta->deflink.vht_cap; + rcu_read_unlock(); + if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) { rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n"); - goto out_unlock; + return; } ether_addr_copy(bfee->mac_addr, bssid); @@ -75,7 +79,7 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) { rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n"); - goto out_unlock; + return; } sound_dim = vht_cap->cap & @@ -98,9 +102,6 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true); } - -out_unlock: - rcu_read_unlock(); } void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 38697237ee5f..86467d2f8888 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -4056,7 +4056,7 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m) rtwdev->stats.tx_throughput, rtwdev->stats.rx_throughput); seq_printf(m, "%-40s = %u/ %u/ %u\n", "IPS/ Low Power/ PS mode", - test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags), + !test_bit(RTW_FLAG_POWERON, rtwdev->flags), test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags), rtwdev->lps_conf.mode); diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 98777f294945..dae64901bac5 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -217,10 +217,10 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, cut_mask = cut_version_to_mask(cut); switch (rtw_hci_type(rtwdev)) { case RTW_HCI_TYPE_PCIE: - intf_mask = BIT(2); + intf_mask = RTW_PWR_INTF_PCI_MSK; break; case RTW_HCI_TYPE_USB: - intf_mask = BIT(1); + intf_mask = RTW_PWR_INTF_USB_MSK; break; default: return -EINVAL; @@ -273,6 +273,11 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) if (rtw_pwr_seq_parser(rtwdev, pwr_seq)) return -EINVAL; + if (pwr_on) + set_bit(RTW_FLAG_POWERON, rtwdev->flags); + else + clear_bit(RTW_FLAG_POWERON, rtwdev->flags); + return 0; } @@ -335,6 +340,11 @@ int rtw_mac_power_on(struct rtw_dev *rtwdev) ret = rtw_mac_power_switch(rtwdev, true); if (ret == -EALREADY) { rtw_mac_power_switch(rtwdev, false); + + ret = rtw_mac_pre_system_cfg(rtwdev); + if (ret) + goto err; + ret = rtw_mac_power_switch(rtwdev, true); if (ret) goto err; diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 776a9a9884b5..3b92ac611d3f 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -737,7 +737,7 @@ static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev, br_data.rtwdev = rtwdev; br_data.vif = vif; br_data.mask = mask; - rtw_iterate_stas_atomic(rtwdev, rtw_ra_mask_info_update_iter, &br_data); + rtw_iterate_stas(rtwdev, rtw_ra_mask_info_update_iter, &br_data); } static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, @@ -746,7 +746,9 @@ static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; + mutex_lock(&rtwdev->mutex); rtw_ra_mask_info_update(rtwdev, vif, mask); + mutex_unlock(&rtwdev->mutex); return 0; } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 888427cf3bdf..b2e78737bd5d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -241,8 +241,10 @@ static void rtw_watch_dog_work(struct work_struct *work) rtw_phy_dynamic_mechanism(rtwdev); data.rtwdev = rtwdev; - /* use atomic version to avoid taking local->iflist_mtx mutex */ - rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); + /* rtw_iterate_vifs internally uses an atomic iterator which is needed + * to avoid taking local->iflist_mtx mutex + */ + rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 165f299e8e1f..d4a53d556745 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -356,7 +356,7 @@ enum rtw_flags { RTW_FLAG_RUNNING, RTW_FLAG_FW_RUNNING, RTW_FLAG_SCANNING, - RTW_FLAG_INACTIVE_PS, + RTW_FLAG_POWERON, RTW_FLAG_LEISURE_PS, RTW_FLAG_LEISURE_PS_DEEP, RTW_FLAG_DIG_DISABLE, diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 0975d27240e4..b4bd831c9845 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -30,7 +30,8 @@ static u32 rtw_pci_tx_queue_idx_addr[] = { [RTW_TX_QUEUE_H2C] = RTK_PCI_TXBD_IDX_H2CQ, }; -static u8 rtw_pci_get_tx_qsel(struct sk_buff *skb, u8 queue) +static u8 rtw_pci_get_tx_qsel(struct sk_buff *skb, + enum rtw_tx_queue_type queue) { switch (queue) { case RTW_TX_QUEUE_BCN: @@ -542,7 +543,7 @@ static int rtw_pci_setup(struct rtw_dev *rtwdev) static void rtw_pci_dma_release(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci) { struct rtw_pci_tx_ring *tx_ring; - u8 queue; + enum rtw_tx_queue_type queue; rtw_pci_reset_trx_ring(rtwdev); for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) { @@ -608,8 +609,8 @@ static void rtw_pci_deep_ps_enter(struct rtw_dev *rtwdev) { struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci_tx_ring *tx_ring; + enum rtw_tx_queue_type queue; bool tx_empty = true; - u8 queue; if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) goto enter_deep_ps; @@ -669,37 +670,6 @@ static void rtw_pci_deep_ps(struct rtw_dev *rtwdev, bool enter) spin_unlock_bh(&rtwpci->irq_lock); } -static u8 ac_to_hwq[] = { - [IEEE80211_AC_VO] = RTW_TX_QUEUE_VO, - [IEEE80211_AC_VI] = RTW_TX_QUEUE_VI, - [IEEE80211_AC_BE] = RTW_TX_QUEUE_BE, - [IEEE80211_AC_BK] = RTW_TX_QUEUE_BK, -}; - -static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS); - -static u8 rtw_hw_queue_mapping(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - u8 q_mapping = skb_get_queue_mapping(skb); - u8 queue; - - if (unlikely(ieee80211_is_beacon(fc))) - queue = RTW_TX_QUEUE_BCN; - else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) - queue = RTW_TX_QUEUE_MGMT; - else if (is_broadcast_ether_addr(hdr->addr1) || - is_multicast_ether_addr(hdr->addr1)) - queue = RTW_TX_QUEUE_HI0; - else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq))) - queue = ac_to_hwq[IEEE80211_AC_BE]; - else - queue = ac_to_hwq[q_mapping]; - - return queue; -} - static void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci, struct rtw_pci_tx_ring *ring) { @@ -797,13 +767,14 @@ static void rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop) } else { for (i = 0; i < rtwdev->hw->queues; i++) if (queues & BIT(i)) - pci_queues |= BIT(ac_to_hwq[i]); + pci_queues |= BIT(rtw_tx_ac_to_hwq(i)); } __rtw_pci_flush_queues(rtwdev, pci_queues, drop); } -static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev, u8 queue) +static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev, + enum rtw_tx_queue_type queue) { struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci_tx_ring *ring; @@ -822,7 +793,7 @@ static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev, u8 queue) static void rtw_pci_tx_kick_off(struct rtw_dev *rtwdev) { struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; - u8 queue; + enum rtw_tx_queue_type queue; for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) if (test_and_clear_bit(queue, rtwpci->tx_queued)) @@ -831,7 +802,8 @@ static void rtw_pci_tx_kick_off(struct rtw_dev *rtwdev) static int rtw_pci_tx_write_data(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, - struct sk_buff *skb, u8 queue) + struct sk_buff *skb, + enum rtw_tx_queue_type queue) { struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; const struct rtw_chip_info *chip = rtwdev->chip; @@ -949,9 +921,9 @@ static int rtw_pci_tx_write(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) { + enum rtw_tx_queue_type queue = rtw_tx_queue_mapping(skb); struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci_tx_ring *ring; - u8 queue = rtw_hw_queue_mapping(skb); int ret; ret = rtw_pci_tx_write_data(rtwdev, pkt_info, skb, queue); diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 11594940d6b0..996365575f44 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -25,7 +25,7 @@ static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) int rtw_enter_ips(struct rtw_dev *rtwdev) { - if (test_and_set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags)) + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags)) return 0; rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER); @@ -50,7 +50,7 @@ int rtw_leave_ips(struct rtw_dev *rtwdev) { int ret; - if (!test_and_clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags)) + if (test_bit(RTW_FLAG_POWERON, rtwdev->flags)) return 0; rtw_hci_link_ps(rtwdev, false); diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index ab39245e9c2f..bb5c7492c98b 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -682,3 +682,44 @@ void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) list_del_init(&rtwtxq->list); spin_unlock_bh(&rtwdev->txq_lock); } + +static const enum rtw_tx_queue_type ac_to_hwq[] = { + [IEEE80211_AC_VO] = RTW_TX_QUEUE_VO, + [IEEE80211_AC_VI] = RTW_TX_QUEUE_VI, + [IEEE80211_AC_BE] = RTW_TX_QUEUE_BE, + [IEEE80211_AC_BK] = RTW_TX_QUEUE_BK, +}; + +static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS); + +enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac) +{ + if (WARN_ON(unlikely(ac >= IEEE80211_NUM_ACS))) + return RTW_TX_QUEUE_BE; + + return ac_to_hwq[ac]; +} +EXPORT_SYMBOL(rtw_tx_ac_to_hwq); + +enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + __le16 fc = hdr->frame_control; + u8 q_mapping = skb_get_queue_mapping(skb); + enum rtw_tx_queue_type queue; + + if (unlikely(ieee80211_is_beacon(fc))) + queue = RTW_TX_QUEUE_BCN; + else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) + queue = RTW_TX_QUEUE_MGMT; + else if (is_broadcast_ether_addr(hdr->addr1) || + is_multicast_ether_addr(hdr->addr1)) + queue = RTW_TX_QUEUE_HI0; + else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq))) + queue = ac_to_hwq[IEEE80211_AC_BE]; + else + queue = ac_to_hwq[q_mapping]; + + return queue; +} +EXPORT_SYMBOL(rtw_tx_queue_mapping); diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index a2f3ac326041..197d5868c8ad 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -131,6 +131,9 @@ rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, u8 *buf, u32 size); +enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac); +enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb); + static inline void fill_txdesc_checksum_common(u8 *txdesc, size_t words) { diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index 4ef38279b64c..2a8336b1847a 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -271,6 +271,7 @@ static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *s return -ENOMEM; usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context); + urb->transfer_flags |= URB_ZERO_PACKET; ret = usb_submit_urb(urb, GFP_ATOMIC); usb_free_urb(urb); @@ -413,24 +414,11 @@ static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size) { const struct rtw_chip_info *chip = rtwdev->chip; - struct rtw_usb *rtwusb; struct rtw_tx_pkt_info pkt_info = {0}; - u32 len, desclen; - - rtwusb = rtw_get_usb_priv(rtwdev); pkt_info.tx_pkt_size = size; pkt_info.qsel = TX_DESC_QSEL_BEACON; - - desclen = chip->tx_pkt_desc_sz; - len = desclen + size; - if (len % rtwusb->bulkout_size == 0) { - len += RTW_USB_PACKET_OFFSET_SZ; - pkt_info.offset = desclen + RTW_USB_PACKET_OFFSET_SZ; - pkt_info.pkt_offset = 1; - } else { - pkt_info.offset = desclen; - } + pkt_info.offset = chip->tx_pkt_desc_sz; return rtw_usb_write_data(rtwdev, &pkt_info, buf); } @@ -471,9 +459,9 @@ static int rtw_usb_tx_write(struct rtw_dev *rtwdev, u8 *pkt_desc; int ep; + pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb); pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, chip->tx_pkt_desc_sz); - pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb); ep = qsel_to_ep(rtwusb, pkt_info->qsel); rtw_tx_fill_tx_desc(pkt_info, skb); rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); diff --git a/drivers/net/wireless/realtek/rtw88/wow.c b/drivers/net/wireless/realtek/rtw88/wow.c index 89dc595094d5..16ddee577efe 100644 --- a/drivers/net/wireless/realtek/rtw88/wow.c +++ b/drivers/net/wireless/realtek/rtw88/wow.c @@ -592,7 +592,7 @@ static int rtw_wow_leave_no_link_ps(struct rtw_dev *rtwdev) if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE) rtw_leave_lps_deep(rtwdev); } else { - if (test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags)) { + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags)) { rtw_wow->ips_enabled = true; ret = rtw_leave_ips(rtwdev); if (ret) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index f21c73310fdb..bcf483cafd20 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -9,7 +9,7 @@ #include "ps.h" #include "reg.h" -#define RTW89_COEX_VERSION 0x06030013 +#define RTW89_COEX_VERSION 0x07000013 #define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/ enum btc_fbtc_tdma_template { @@ -63,7 +63,7 @@ struct btc_fbtc_1slot { static const struct rtw89_btc_fbtc_tdma t_def[] = { [CXTD_OFF] = { CXTDMA_OFF, CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0}, [CXTD_OFF_B2] = { CXTDMA_OFF, CXFLC_OFF, CXTPS_OFF, 0, 0, 1, 0, 0}, - [CXTD_OFF_EXT] = { CXTDMA_OFF, CXFLC_OFF, CXTPS_OFF, 0, 0, 3, 0, 0}, + [CXTD_OFF_EXT] = { CXTDMA_OFF, CXFLC_OFF, CXTPS_OFF, 0, 0, 2, 0, 0}, [CXTD_FIX] = { CXTDMA_FIX, CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0}, [CXTD_PFIX] = { CXTDMA_FIX, CXFLC_NULLP, CXTPS_ON, 0, 5, 0, 0, 0}, [CXTD_AUTO] = { CXTDMA_AUTO, CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0}, @@ -80,21 +80,21 @@ static const struct rtw89_btc_fbtc_slot s_def[] = { [CXST_OFF] = __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX), [CXST_B2W] = __DEF_FBTC_SLOT(5, 0xea5a5a5a, SLOT_ISO), [CXST_W1] = __DEF_FBTC_SLOT(70, 0xea5a5a5a, SLOT_ISO), - [CXST_W2] = __DEF_FBTC_SLOT(70, 0xea5a5aaa, SLOT_ISO), + [CXST_W2] = __DEF_FBTC_SLOT(15, 0xea5a5a5a, SLOT_ISO), [CXST_W2B] = __DEF_FBTC_SLOT(15, 0xea5a5a5a, SLOT_ISO), - [CXST_B1] = __DEF_FBTC_SLOT(100, 0xe5555555, SLOT_MIX), + [CXST_B1] = __DEF_FBTC_SLOT(250, 0xe5555555, SLOT_MIX), [CXST_B2] = __DEF_FBTC_SLOT(7, 0xea5a5a5a, SLOT_MIX), [CXST_B3] = __DEF_FBTC_SLOT(5, 0xe5555555, SLOT_MIX), [CXST_B4] = __DEF_FBTC_SLOT(50, 0xe5555555, SLOT_MIX), [CXST_LK] = __DEF_FBTC_SLOT(20, 0xea5a5a5a, SLOT_ISO), - [CXST_BLK] = __DEF_FBTC_SLOT(250, 0x55555555, SLOT_MIX), - [CXST_E2G] = __DEF_FBTC_SLOT(20, 0xea5a5a5a, SLOT_MIX), - [CXST_E5G] = __DEF_FBTC_SLOT(20, 0xffffffff, SLOT_MIX), - [CXST_EBT] = __DEF_FBTC_SLOT(20, 0xe5555555, SLOT_MIX), - [CXST_ENULL] = __DEF_FBTC_SLOT(7, 0xaaaaaaaa, SLOT_ISO), + [CXST_BLK] = __DEF_FBTC_SLOT(500, 0x55555555, SLOT_MIX), + [CXST_E2G] = __DEF_FBTC_SLOT(0, 0xea5a5a5a, SLOT_MIX), + [CXST_E5G] = __DEF_FBTC_SLOT(0, 0xffffffff, SLOT_ISO), + [CXST_EBT] = __DEF_FBTC_SLOT(0, 0xe5555555, SLOT_MIX), + [CXST_ENULL] = __DEF_FBTC_SLOT(0, 0xaaaaaaaa, SLOT_ISO), [CXST_WLK] = __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX), - [CXST_W1FDD] = __DEF_FBTC_SLOT(35, 0xfafafafa, SLOT_ISO), - [CXST_B1FDD] = __DEF_FBTC_SLOT(100, 0xffffffff, SLOT_MIX), + [CXST_W1FDD] = __DEF_FBTC_SLOT(50, 0xffffffff, SLOT_ISO), + [CXST_B1FDD] = __DEF_FBTC_SLOT(50, 0xffffdfff, SLOT_ISO), }; static const u32 cxtbl[] = { @@ -117,9 +117,78 @@ static const u32 cxtbl[] = { 0xfafafafa, /* 16 */ 0xffffddff, /* 17 */ 0xdaffdaff, /* 18 */ - 0xfafadafa /* 19 */ + 0xfafadafa, /* 19 */ + 0xea6a6a6a, /* 20 */ + 0xea55556a, /* 21 */ + 0xaafafafa, /* 22 */ + 0xfafaaafa, /* 23 */ + 0xfafffaff /* 24 */ }; +static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { + /* firmware version must be in decreasing order for each chip */ + {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), + .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .info_buf = 1800, .max_role_num = 6, + }, + {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), + .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .info_buf = 1280, .max_role_num = 5, + }, + {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), + .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, + .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, + .info_buf = 1024, .max_role_num = 5, + }, + + /* keep it to be the last as default entry */ + {0, RTW89_FW_VER_CODE(0, 0, 0, 0), + .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, + .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, + .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, + .info_buf = 1024, .max_role_num = 5, + }, +}; + +#define RTW89_DEFAULT_BTC_VER_IDX (ARRAY_SIZE(rtw89_btc_ver_defs) - 1) + struct rtw89_btc_btf_tlv { u8 type; u8 len; @@ -127,16 +196,20 @@ struct rtw89_btc_btf_tlv { } __packed; enum btc_btf_set_report_en { - RPT_EN_TDMA = BIT(0), - RPT_EN_CYCLE = BIT(1), - RPT_EN_MREG = BIT(2), - RPT_EN_BT_VER_INFO = BIT(3), - RPT_EN_BT_SCAN_INFO = BIT(4), - RPT_EN_BT_AFH_MAP = BIT(5), - RPT_EN_BT_DEVICE_INFO = BIT(6), - RPT_EN_WL_ALL = GENMASK(2, 0), - RPT_EN_BT_ALL = GENMASK(6, 3), - RPT_EN_ALL = GENMASK(6, 0), + RPT_EN_TDMA, + RPT_EN_CYCLE, + RPT_EN_MREG, + RPT_EN_BT_VER_INFO, + RPT_EN_BT_SCAN_INFO, + RPT_EN_BT_DEVICE_INFO, + RPT_EN_BT_AFH_MAP, + RPT_EN_BT_AFH_MAP_LE, + RPT_EN_FW_STEP_INFO, + RPT_EN_TEST, + RPT_EN_WL_ALL, + RPT_EN_BT_ALL, + RPT_EN_ALL, + RPT_EN_MONITER, }; #define BTF_SET_REPORT_VER 1 @@ -786,17 +859,18 @@ static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt) static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc; struct rtw89_btc_fbtc_btver *pver = NULL; struct rtw89_btc_fbtc_btscan *pscan = NULL; - struct rtw89_btc_fbtc_btafh *pafh = NULL; + struct rtw89_btc_fbtc_btafh *pafh_v1 = NULL; + struct rtw89_btc_fbtc_btafh_v2 *pafh_v2 = NULL; struct rtw89_btc_fbtc_btdevinfo *pdev = NULL; pver = (struct rtw89_btc_fbtc_btver *)pfinfo; pscan = (struct rtw89_btc_fbtc_btscan *)pfinfo; - pafh = (struct rtw89_btc_fbtc_btafh *)pfinfo; pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo; rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -813,9 +887,23 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) memcpy(bt->scan_info, pscan->scan, BTC_SCAN_MAX1); break; case BTC_RPT_TYPE_BT_AFH: - memcpy(&bt_linfo->afh_map[0], pafh->afh_l, 4); - memcpy(&bt_linfo->afh_map[4], pafh->afh_m, 4); - memcpy(&bt_linfo->afh_map[8], pafh->afh_h, 2); + if (ver->fcxbtafh == 2) { + pafh_v2 = (struct rtw89_btc_fbtc_btafh_v2 *)pfinfo; + if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LEGACY) { + memcpy(&bt_linfo->afh_map[0], pafh_v2->afh_l, 4); + memcpy(&bt_linfo->afh_map[4], pafh_v2->afh_m, 4); + memcpy(&bt_linfo->afh_map[8], pafh_v2->afh_h, 2); + } + if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LE) { + memcpy(&bt_linfo->afh_map_le[0], pafh_v2->afh_le_a, 4); + memcpy(&bt_linfo->afh_map_le[4], pafh_v2->afh_le_b, 1); + } + } else if (ver->fcxbtafh == 1) { + pafh_v1 = (struct rtw89_btc_fbtc_btafh *)pfinfo; + memcpy(&bt_linfo->afh_map[0], pafh_v1->afh_l, 4); + memcpy(&bt_linfo->afh_map[4], pafh_v1->afh_m, 4); + memcpy(&bt_linfo->afh_map[8], pafh_v1->afh_h, 2); + } break; case BTC_RPT_TYPE_BT_DEVICE: a2dp->device_name = le32_to_cpu(pdev->dev_name); @@ -827,76 +915,6 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) } } -struct rtw89_btc_fbtc_cysta_cpu { - u8 fver; - u8 rsvd; - u16 cycles; - u16 cycles_a2dp[CXT_FLCTRL_MAX]; - u16 a2dpept; - u16 a2dpeptto; - u16 tavg_cycle[CXT_MAX]; - u16 tmax_cycle[CXT_MAX]; - u16 tmaxdiff_cycle[CXT_MAX]; - u16 tavg_a2dp[CXT_FLCTRL_MAX]; - u16 tmax_a2dp[CXT_FLCTRL_MAX]; - u16 tavg_a2dpept; - u16 tmax_a2dpept; - u16 tavg_lk; - u16 tmax_lk; - u32 slot_cnt[CXST_MAX]; - u32 bcn_cnt[CXBCN_MAX]; - u32 leakrx_cnt; - u32 collision_cnt; - u32 skip_cnt; - u32 exception; - u32 except_cnt; - u16 tslot_cycle[BTC_CYCLE_SLOT_MAX]; -}; - -static void rtw89_btc_fbtc_cysta_to_cpu(const struct rtw89_btc_fbtc_cysta *src, - struct rtw89_btc_fbtc_cysta_cpu *dst) -{ - static_assert(sizeof(*src) == sizeof(*dst)); - -#define __CPY_U8(_x) ({dst->_x = src->_x; }) -#define __CPY_LE16(_x) ({dst->_x = le16_to_cpu(src->_x); }) -#define __CPY_LE16S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \ - dst->_x[_i] = le16_to_cpu(src->_x[_i]); }) -#define __CPY_LE32(_x) ({dst->_x = le32_to_cpu(src->_x); }) -#define __CPY_LE32S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \ - dst->_x[_i] = le32_to_cpu(src->_x[_i]); }) - - __CPY_U8(fver); - __CPY_U8(rsvd); - __CPY_LE16(cycles); - __CPY_LE16S(cycles_a2dp); - __CPY_LE16(a2dpept); - __CPY_LE16(a2dpeptto); - __CPY_LE16S(tavg_cycle); - __CPY_LE16S(tmax_cycle); - __CPY_LE16S(tmaxdiff_cycle); - __CPY_LE16S(tavg_a2dp); - __CPY_LE16S(tmax_a2dp); - __CPY_LE16(tavg_a2dpept); - __CPY_LE16(tmax_a2dpept); - __CPY_LE16(tavg_lk); - __CPY_LE16(tmax_lk); - __CPY_LE32S(slot_cnt); - __CPY_LE32S(bcn_cnt); - __CPY_LE32(leakrx_cnt); - __CPY_LE32(collision_cnt); - __CPY_LE32(skip_cnt); - __CPY_LE32(exception); - __CPY_LE32(except_cnt); - __CPY_LE16S(tslot_cycle); - -#undef __CPY_U8 -#undef __CPY_LE16 -#undef __CPY_LE16S -#undef __CPY_LE32 -#undef __CPY_LE32S -} - #define BTC_LEAK_AP_TH 10 #define BTC_CYSTA_CHK_PERIOD 100 @@ -910,19 +928,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, struct rtw89_btc_btf_fwinfo *pfwinfo, u8 *prptbuf, u32 index) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; - struct rtw89_btc_fbtc_rpt_ctrl *prpt; - struct rtw89_btc_fbtc_rpt_ctrl_v1 *prpt_v1; - struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL; - struct rtw89_btc_fbtc_cysta_v1 *pcysta_v1 = NULL; - struct rtw89_btc_fbtc_cysta_cpu pcysta[1]; + union rtw89_btc_fbtc_rpt_ctrl_ver_info *prpt = NULL; + union rtw89_btc_fbtc_cysta_info *pcysta = NULL; struct rtw89_btc_prpt *btc_prpt = NULL; - struct rtw89_btc_fbtc_slot *rtp_slot = NULL; void *rpt_content = NULL, *pfinfo = NULL; u8 rpt_type = 0; u16 wl_slot_set = 0, wl_slot_real = 0; @@ -951,137 +965,141 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, switch (rpt_type) { case BTC_RPT_TYPE_CTRL: pcinfo = &pfwinfo->rpt_ctrl.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_ctrl.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo); + prpt = &pfwinfo->rpt_ctrl.finfo; + if (ver->fcxbtcrpt == 1) { + pfinfo = &pfwinfo->rpt_ctrl.finfo.v1; + pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v1); + } else if (ver->fcxbtcrpt == 4) { + pfinfo = &pfwinfo->rpt_ctrl.finfo.v4; + pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v4); + } else if (ver->fcxbtcrpt == 5) { + pfinfo = &pfwinfo->rpt_ctrl.finfo.v5; + pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v5); } else { - pfinfo = &pfwinfo->rpt_ctrl.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxbtcrpt_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtcrpt; break; case BTC_RPT_TYPE_TDMA: pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo); + if (ver->fcxtdma == 1) { + pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1); + } else if (ver->fcxtdma == 3) { + pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3); } else { - pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxtdma_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxtdma; break; case BTC_RPT_TYPE_SLOT: pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo; pfinfo = &pfwinfo->rpt_fbtc_slots.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo); - pcinfo->req_fver = chip->fcxslots_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxslots; break; case BTC_RPT_TYPE_CYSTA: pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo; - pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo; - rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta); - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo); + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; + if (ver->fcxcysta == 2) { + pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2; + pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2); + } else if (ver->fcxcysta == 3) { + pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3; + pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3); + } else if (ver->fcxcysta == 4) { + pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v4; + pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v4); } else { - pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo_v1; - pcysta_v1 = &pfwinfo->rpt_fbtc_cysta.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxcysta_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxcysta; break; case BTC_RPT_TYPE_STEP: pcinfo = &pfwinfo->rpt_fbtc_step.cinfo; - if (chip->chip_id == RTL8852A) { - pfinfo = &pfwinfo->rpt_fbtc_step.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.step[0]) * + if (ver->fcxstep == 2) { + pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) * trace_step + - offsetof(struct rtw89_btc_fbtc_steps, step); - } else { - pfinfo = &pfwinfo->rpt_fbtc_step.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo_v1.step[0]) * + offsetof(struct rtw89_btc_fbtc_steps_v2, step); + } else if (ver->fcxstep == 3) { + pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v3; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v3.step[0]) * trace_step + - offsetof(struct rtw89_btc_fbtc_steps_v1, step); + offsetof(struct rtw89_btc_fbtc_steps_v3, step); + } else { + goto err; } - pcinfo->req_fver = chip->fcxstep_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxstep; break; case BTC_RPT_TYPE_NULLSTA: pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo; - if (chip->chip_id == RTL8852A) { + if (ver->fcxnullsta == 1) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo); + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v1); + } else if (ver->fcxnullsta == 2) { + pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2); } else { - pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo_v1; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo_v1); + goto err; } - pcinfo->req_fver = chip->fcxnullsta_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxnullsta; break; case BTC_RPT_TYPE_MREG: pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo; pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo); - pcinfo->req_fver = chip->fcxmreg_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxmreg; break; case BTC_RPT_TYPE_GPIO_DBG: pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo; pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo); - pcinfo->req_fver = chip->fcxgpiodbg_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxgpiodbg; break; case BTC_RPT_TYPE_BT_VER: pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btver.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo); - pcinfo->req_fver = chip->fcxbtver_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtver; break; case BTC_RPT_TYPE_BT_SCAN: pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo); - pcinfo->req_fver = chip->fcxbtscan_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtscan; break; case BTC_RPT_TYPE_BT_AFH: pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo; - pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo; - pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo); - pcinfo->req_fver = chip->fcxbtafh_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + if (ver->fcxbtafh == 1) { + pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v1; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v1); + } else if (ver->fcxbtafh == 2) { + pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v2; + pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v2); + } else { + goto err; + } + pcinfo->req_fver = ver->fcxbtafh; break; case BTC_RPT_TYPE_BT_DEVICE: pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btdev.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo); - pcinfo->req_fver = chip->fcxbtdevinfo_ver; - pcinfo->rx_len = rpt_len; - pcinfo->rx_cnt++; + pcinfo->req_fver = ver->fcxbtdevinfo; break; default: pfwinfo->err[BTFRE_UNDEF_TYPE]++; return 0; } + pcinfo->rx_len = rpt_len; + pcinfo->rx_cnt++; + if (rpt_len != pcinfo->req_len) { if (rpt_type < BTC_RPT_TYPE_MAX) pfwinfo->len_mismch |= (0x1 << rpt_type); @@ -1102,235 +1120,257 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, memcpy(pfinfo, rpt_content, pcinfo->req_len); pcinfo->valid = 1; - if (rpt_type == BTC_RPT_TYPE_TDMA && chip->chip_id == RTL8852A) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): check %d %zu\n", __func__, - BTC_DCNT_TDMA_NONSYNC, sizeof(dm->tdma_now)); - - if (memcmp(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo, - sizeof(dm->tdma_now)) != 0) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d tdma_now %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - dm->tdma_now.type, dm->tdma_now.rxflctrl, - dm->tdma_now.txpause, dm->tdma_now.wtgle_n, - dm->tdma_now.leak_n, dm->tdma_now.ext_ctrl, - dm->tdma_now.rxflctrl_role, - dm->tdma_now.option_ctrl); - - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d rpt_fbtc_tdma %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - pfwinfo->rpt_fbtc_tdma.finfo.type, - pfwinfo->rpt_fbtc_tdma.finfo.rxflctrl, - pfwinfo->rpt_fbtc_tdma.finfo.txpause, - pfwinfo->rpt_fbtc_tdma.finfo.wtgle_n, - pfwinfo->rpt_fbtc_tdma.finfo.leak_n, - pfwinfo->rpt_fbtc_tdma.finfo.ext_ctrl, - pfwinfo->rpt_fbtc_tdma.finfo.rxflctrl_role, - pfwinfo->rpt_fbtc_tdma.finfo.option_ctrl); - } + switch (rpt_type) { + case BTC_RPT_TYPE_CTRL: + if (ver->fcxbtcrpt == 1) { + prpt->v1 = pfwinfo->rpt_ctrl.finfo.v1; + btc->fwinfo.rpt_en_map = prpt->v1.rpt_enable; + wl->ver_info.fw_coex = prpt->v1.wl_fw_coex_ver; + wl->ver_info.fw = prpt->v1.wl_fw_ver; + dm->wl_fw_cx_offload = !!prpt->v1.wl_fw_cx_offload; + + _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, + pfwinfo->event[BTF_EVNT_RPT]); + + /* To avoid I/O if WL LPS or power-off */ + if (wl->status.map.lps != BTC_LPS_RF_OFF && + !wl->status.map.rf_off) { + rtwdev->chip->ops->btc_update_bt_cnt(rtwdev); + _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + + btc->cx.cnt_bt[BTC_BCNT_POLUT] = + rtw89_mac_get_plt_cnt(rtwdev, + RTW89_MAC_0); + } + } else if (ver->fcxbtcrpt == 4) { + prpt->v4 = pfwinfo->rpt_ctrl.finfo.v4; + btc->fwinfo.rpt_en_map = le32_to_cpu(prpt->v4.rpt_info.en); + wl->ver_info.fw_coex = le32_to_cpu(prpt->v4.wl_fw_info.cx_ver); + wl->ver_info.fw = le32_to_cpu(prpt->v4.wl_fw_info.fw_ver); + dm->wl_fw_cx_offload = !!le32_to_cpu(prpt->v4.wl_fw_info.cx_offload); + + for (i = RTW89_PHY_0; i < RTW89_PHY_MAX; i++) + memcpy(&dm->gnt.band[i], &prpt->v4.gnt_val[i], + sizeof(dm->gnt.band[i])); + + btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_TX]); + btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_RX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_TX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_RX]); + btc->cx.cnt_bt[BTC_BCNT_POLUT] = + le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_POLLUTED]); - _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, - memcmp(&dm->tdma_now, - &pfwinfo->rpt_fbtc_tdma.finfo, - sizeof(dm->tdma_now))); - } else if (rpt_type == BTC_RPT_TYPE_TDMA) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): check %d %zu\n", __func__, - BTC_DCNT_TDMA_NONSYNC, sizeof(dm->tdma_now)); - - if (memcmp(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma, - sizeof(dm->tdma_now)) != 0) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d tdma_now %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - dm->tdma_now.type, dm->tdma_now.rxflctrl, - dm->tdma_now.txpause, dm->tdma_now.wtgle_n, - dm->tdma_now.leak_n, dm->tdma_now.ext_ctrl, - dm->tdma_now.rxflctrl_role, - dm->tdma_now.option_ctrl); - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d rpt_fbtc_tdma %x %x %x %x %x %x %x %x\n", - __func__, BTC_DCNT_TDMA_NONSYNC, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.type, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.rxflctrl, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.txpause, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.wtgle_n, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.leak_n, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.ext_ctrl, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.rxflctrl_role, - pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma.option_ctrl); - } + _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, + pfwinfo->event[BTF_EVNT_RPT]); - _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, - memcmp(&dm->tdma_now, - &pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma, - sizeof(dm->tdma_now))); - } + if (le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0) + bt->rfk_info.map.timeout = 1; + else + bt->rfk_info.map.timeout = 0; + + dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout; + } else if (ver->fcxbtcrpt == 5) { + prpt->v5 = pfwinfo->rpt_ctrl.finfo.v5; + pfwinfo->rpt_en_map = le32_to_cpu(prpt->v5.rpt_info.en); + wl->ver_info.fw_coex = le32_to_cpu(prpt->v5.rpt_info.cx_ver); + wl->ver_info.fw = le32_to_cpu(prpt->v5.rpt_info.fw_ver); + dm->wl_fw_cx_offload = 0; + + for (i = RTW89_PHY_0; i < RTW89_PHY_MAX; i++) + memcpy(&dm->gnt.band[i], &prpt->v5.gnt_val[i][0], + sizeof(dm->gnt.band[i])); + + btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_TX]); + btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_RX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_TX]); + btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_RX]); + btc->cx.cnt_bt[BTC_BCNT_POLUT] = + le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_POLLUTED]); + + _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, + pfwinfo->event[BTF_EVNT_RPT]); - if (rpt_type == BTC_RPT_TYPE_SLOT) { + dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout; + } else { + goto err; + } + break; + case BTC_RPT_TYPE_TDMA: + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): check %d %zu\n", __func__, + BTC_DCNT_TDMA_NONSYNC, + sizeof(dm->tdma_now)); + if (ver->fcxtdma == 1) + _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, + memcmp(&dm->tdma_now, + &pfwinfo->rpt_fbtc_tdma.finfo.v1, + sizeof(dm->tdma_now))); + else if (ver->fcxtdma == 3) + _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, + memcmp(&dm->tdma_now, + &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma, + sizeof(dm->tdma_now))); + else + goto err; + break; + case BTC_RPT_TYPE_SLOT: rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): check %d %zu\n", __func__, BTC_DCNT_SLOT_NONSYNC, sizeof(dm->slot_now)); - - if (memcmp(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot, - sizeof(dm->slot_now)) != 0) { - for (i = 0; i < CXST_MAX; i++) { - rtp_slot = - &pfwinfo->rpt_fbtc_slots.finfo.slot[i]; - if (memcmp(&dm->slot_now[i], rtp_slot, - sizeof(dm->slot_now[i])) != 0) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d slot_now[%d] dur=0x%04x tbl=%08x type=0x%04x\n", - __func__, - BTC_DCNT_SLOT_NONSYNC, i, - dm->slot_now[i].dur, - dm->slot_now[i].cxtbl, - dm->slot_now[i].cxtype); - - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], %s(): %d rpt_fbtc_slots[%d] dur=0x%04x tbl=%08x type=0x%04x\n", - __func__, - BTC_DCNT_SLOT_NONSYNC, i, - rtp_slot->dur, - rtp_slot->cxtbl, - rtp_slot->cxtype); - } - } - } _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC, memcmp(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot, sizeof(dm->slot_now))); - } + break; + case BTC_RPT_TYPE_CYSTA: + if (ver->fcxcysta == 2) { + if (le16_to_cpu(pcysta->v2.cycles) < BTC_CYSTA_CHK_PERIOD) + break; + /* Check Leak-AP */ + if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) != 0 && + le32_to_cpu(pcysta->v2.leakrx_cnt) != 0 && dm->tdma_now.rxflctrl) { + if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) < + BTC_LEAK_AP_TH * le32_to_cpu(pcysta->v2.leakrx_cnt)) + dm->leak_ap = 1; + } - if (rpt_type == BTC_RPT_TYPE_CYSTA && chip->chip_id == RTL8852A && - pcysta->cycles >= BTC_CYSTA_CHK_PERIOD) { - /* Check Leak-AP */ - if (pcysta->slot_cnt[CXST_LK] != 0 && - pcysta->leakrx_cnt != 0 && dm->tdma_now.rxflctrl) { - if (pcysta->slot_cnt[CXST_LK] < - BTC_LEAK_AP_TH * pcysta->leakrx_cnt) - dm->leak_ap = 1; - } + /* Check diff time between WL slot and W1/E2G slot */ + if (dm->tdma_now.type == CXTDMA_OFF && + dm->tdma_now.ext_ctrl == CXECTL_EXT) + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_E2G].dur); + else + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); - /* Check diff time between WL slot and W1/E2G slot */ - if (dm->tdma_now.type == CXTDMA_OFF && - dm->tdma_now.ext_ctrl == CXECTL_EXT) - wl_slot_set = le16_to_cpu(dm->slot_now[CXST_E2G].dur); - else - wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); + if (le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) > wl_slot_set) { + diff_t = le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) - wl_slot_set; + _chk_btc_err(rtwdev, + BTC_DCNT_WL_SLOT_DRIFT, diff_t); + } - if (pcysta->tavg_cycle[CXT_WL] > wl_slot_set) { - diff_t = pcysta->tavg_cycle[CXT_WL] - wl_slot_set; - _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); - } + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le32_to_cpu(pcysta->v2.slot_cnt[CXST_W1])); + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le32_to_cpu(pcysta->v2.slot_cnt[CXST_B1])); + _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, + le16_to_cpu(pcysta->v2.cycles)); + } else if (ver->fcxcysta == 3) { + if (le16_to_cpu(pcysta->v3.cycles) < BTC_CYSTA_CHK_PERIOD) + break; - _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_W1]); - _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_B1]); - _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, (u32)pcysta->cycles); - } else if (rpt_type == BTC_RPT_TYPE_CYSTA && pcysta_v1 && - le16_to_cpu(pcysta_v1->cycles) >= BTC_CYSTA_CHK_PERIOD) { - cnt_leak_slot = le32_to_cpu(pcysta_v1->slot_cnt[CXST_LK]); - cnt_rx_imr = le32_to_cpu(pcysta_v1->leak_slot.cnt_rximr); - /* Check Leak-AP */ - if (cnt_leak_slot != 0 && cnt_rx_imr != 0 && - dm->tdma_now.rxflctrl) { - if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr) - dm->leak_ap = 1; - } + cnt_leak_slot = le32_to_cpu(pcysta->v3.slot_cnt[CXST_LK]); + cnt_rx_imr = le32_to_cpu(pcysta->v3.leak_slot.cnt_rximr); - /* Check diff time between real WL slot and W1 slot */ - if (dm->tdma_now.type == CXTDMA_OFF) { - wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); - wl_slot_real = le16_to_cpu(pcysta_v1->cycle_time.tavg[CXT_WL]); - if (wl_slot_real > wl_slot_set) { - diff_t = wl_slot_real - wl_slot_set; - _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); + /* Check Leak-AP */ + if (cnt_leak_slot != 0 && cnt_rx_imr != 0 && + dm->tdma_now.rxflctrl) { + if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr) + dm->leak_ap = 1; } - } - /* Check diff time between real BT slot and EBT/E5G slot */ - if (dm->tdma_now.type == CXTDMA_OFF && - dm->tdma_now.ext_ctrl == CXECTL_EXT && - btc->bt_req_len != 0) { - bt_slot_real = le16_to_cpu(pcysta_v1->cycle_time.tavg[CXT_BT]); + /* Check diff time between real WL slot and W1 slot */ + if (dm->tdma_now.type == CXTDMA_OFF) { + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); + wl_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_WL]); + if (wl_slot_real > wl_slot_set) { + diff_t = wl_slot_real - wl_slot_set; + _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); + } + } - if (btc->bt_req_len > bt_slot_real) { - diff_t = btc->bt_req_len - bt_slot_real; - _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t); + /* Check diff time between real BT slot and EBT/E5G slot */ + if (dm->tdma_now.type == CXTDMA_OFF && + dm->tdma_now.ext_ctrl == CXECTL_EXT && + btc->bt_req_len != 0) { + bt_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_BT]); + if (btc->bt_req_len > bt_slot_real) { + diff_t = btc->bt_req_len - bt_slot_real; + _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t); + } } - } - _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, - le32_to_cpu(pcysta_v1->slot_cnt[CXST_W1])); - _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, - le32_to_cpu(pcysta_v1->slot_cnt[CXST_B1])); - _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, - (u32)le16_to_cpu(pcysta_v1->cycles)); - } + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le32_to_cpu(pcysta->v3.slot_cnt[CXST_W1])); + _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, + le32_to_cpu(pcysta->v3.slot_cnt[CXST_B1])); + _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, + le16_to_cpu(pcysta->v3.cycles)); + } else if (ver->fcxcysta == 4) { + if (le16_to_cpu(pcysta->v4.cycles) < BTC_CYSTA_CHK_PERIOD) + break; - if (rpt_type == BTC_RPT_TYPE_CTRL && chip->chip_id == RTL8852A) { - prpt = &pfwinfo->rpt_ctrl.finfo; - btc->fwinfo.rpt_en_map = prpt->rpt_enable; - wl->ver_info.fw_coex = prpt->wl_fw_coex_ver; - wl->ver_info.fw = prpt->wl_fw_ver; - dm->wl_fw_cx_offload = !!prpt->wl_fw_cx_offload; + cnt_leak_slot = le16_to_cpu(pcysta->v4.slot_cnt[CXST_LK]); + cnt_rx_imr = le32_to_cpu(pcysta->v4.leak_slot.cnt_rximr); - _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, - pfwinfo->event[BTF_EVNT_RPT]); + /* Check Leak-AP */ + if (cnt_leak_slot != 0 && cnt_rx_imr != 0 && + dm->tdma_now.rxflctrl) { + if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr) + dm->leak_ap = 1; + } - /* To avoid I/O if WL LPS or power-off */ - if (wl->status.map.lps != BTC_LPS_RF_OFF && !wl->status.map.rf_off) { - rtwdev->chip->ops->btc_update_bt_cnt(rtwdev); - _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + /* Check diff time between real WL slot and W1 slot */ + if (dm->tdma_now.type == CXTDMA_OFF) { + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); + wl_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_WL]); + if (wl_slot_real > wl_slot_set) { + diff_t = wl_slot_real - wl_slot_set; + _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); + } + } - btc->cx.cnt_bt[BTC_BCNT_POLUT] = - rtw89_mac_get_plt_cnt(rtwdev, RTW89_MAC_0); - } - } else if (rpt_type == BTC_RPT_TYPE_CTRL) { - prpt_v1 = &pfwinfo->rpt_ctrl.finfo_v1; - btc->fwinfo.rpt_en_map = le32_to_cpu(prpt_v1->rpt_info.en); - wl->ver_info.fw_coex = le32_to_cpu(prpt_v1->wl_fw_info.cx_ver); - wl->ver_info.fw = le32_to_cpu(prpt_v1->wl_fw_info.fw_ver); - dm->wl_fw_cx_offload = !!le32_to_cpu(prpt_v1->wl_fw_info.cx_offload); - - for (i = RTW89_PHY_0; i < RTW89_PHY_MAX; i++) - memcpy(&dm->gnt.band[i], &prpt_v1->gnt_val[i], - sizeof(dm->gnt.band[i])); - - btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_HI_TX]); - btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_HI_RX]); - btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_LO_TX]); - btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_LO_RX]); - btc->cx.cnt_bt[BTC_BCNT_POLUT] = le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_POLLUTED]); - - _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); - _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, - pfwinfo->event[BTF_EVNT_RPT]); - - if (le32_to_cpu(prpt_v1->bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0) - bt->rfk_info.map.timeout = 1; - else - bt->rfk_info.map.timeout = 0; + /* Check diff time between real BT slot and EBT/E5G slot */ + if (dm->tdma_now.type == CXTDMA_OFF && + dm->tdma_now.ext_ctrl == CXECTL_EXT && + btc->bt_req_len != 0) { + bt_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_BT]); - dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout; - } + if (btc->bt_req_len > bt_slot_real) { + diff_t = btc->bt_req_len - bt_slot_real; + _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t); + } + } - if (rpt_type >= BTC_RPT_TYPE_BT_VER && - rpt_type <= BTC_RPT_TYPE_BT_DEVICE) + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, + le16_to_cpu(pcysta->v4.slot_cnt[CXST_W1])); + _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, + le16_to_cpu(pcysta->v4.slot_cnt[CXST_B1])); + _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, + le16_to_cpu(pcysta->v4.cycles)); + } else { + goto err; + } + break; + case BTC_RPT_TYPE_BT_VER: + case BTC_RPT_TYPE_BT_SCAN: + case BTC_RPT_TYPE_BT_AFH: + case BTC_RPT_TYPE_BT_DEVICE: _update_bt_report(rtwdev, rpt_type, pfinfo); - + break; + } return (rpt_len + BTC_RPT_HDR_SIZE); + +err: + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): Undefined version for type=%d\n", __func__, rpt_type); + return 0; } static void _parse_btc_report(struct rtw89_dev *rtwdev, struct rtw89_btc_btf_fwinfo *pfwinfo, u8 *pbuf, u32 buf_len) { - const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_btc_ver *ver = rtwdev->btc.ver; struct rtw89_btc_prpt *btc_prpt = NULL; u32 index = 0, rpt_len = 0; @@ -1340,7 +1380,7 @@ static void _parse_btc_report(struct rtw89_dev *rtwdev, while (pbuf) { btc_prpt = (struct rtw89_btc_prpt *)&pbuf[index]; - if (index + 2 >= chip->btc_fwinfo_buf) + if (index + 2 >= ver->info_buf) break; /* At least 3 bytes: type(1) & len(2) */ rpt_len = le16_to_cpu(btc_prpt->len); @@ -1358,12 +1398,12 @@ static void _parse_btc_report(struct rtw89_dev *rtwdev, static void _append_tdma(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_btf_tlv *tlv; struct rtw89_btc_fbtc_tdma *v; - struct rtw89_btc_fbtc_tdma_v1 *v1; + struct rtw89_btc_fbtc_tdma_v3 *v3; u16 len = btc->policy_len; if (!btc->update_policy_force && @@ -1376,17 +1416,17 @@ static void _append_tdma(struct rtw89_dev *rtwdev) tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len]; tlv->type = CXPOLICY_TDMA; - if (chip->chip_id == RTL8852A) { + if (ver->fcxtdma == 1) { v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0]; tlv->len = sizeof(*v); memcpy(v, &dm->tdma, sizeof(*v)); - btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v); + btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v); } else { - tlv->len = sizeof(*v1); - v1 = (struct rtw89_btc_fbtc_tdma_v1 *)&tlv->val[0]; - v1->fver = chip->fcxtdma_ver; - v1->tdma = dm->tdma; - btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v1); + tlv->len = sizeof(*v3); + v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0]; + v3->fver = ver->fcxtdma; + memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma)); + btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3); } rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -1441,22 +1481,169 @@ static void _append_slot(struct rtw89_dev *rtwdev) __func__, cnt); } +static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) +{ + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; + u32 bit_map = 0; + + switch (rpt_map) { + case RPT_EN_TDMA: + bit_map = BIT(0); + break; + case RPT_EN_CYCLE: + bit_map = BIT(1); + break; + case RPT_EN_MREG: + bit_map = BIT(2); + break; + case RPT_EN_BT_VER_INFO: + bit_map = BIT(3); + break; + case RPT_EN_BT_SCAN_INFO: + bit_map = BIT(4); + break; + case RPT_EN_BT_DEVICE_INFO: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + bit_map = BIT(6); + break; + case 3: + bit_map = BIT(5); + break; + default: + break; + } + break; + case RPT_EN_BT_AFH_MAP: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + bit_map = BIT(5); + break; + case 3: + bit_map = BIT(6); + break; + default: + break; + } + break; + case RPT_EN_BT_AFH_MAP_LE: + switch (ver->frptmap) { + case 2: + bit_map = BIT(8); + break; + case 3: + bit_map = BIT(7); + break; + default: + break; + } + break; + case RPT_EN_FW_STEP_INFO: + switch (ver->frptmap) { + case 1: + case 2: + bit_map = BIT(7); + break; + case 3: + bit_map = BIT(8); + break; + default: + break; + } + break; + case RPT_EN_TEST: + bit_map = BIT(31); + break; + case RPT_EN_WL_ALL: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + bit_map = GENMASK(2, 0); + break; + case 3: + bit_map = GENMASK(2, 0) | BIT(8); + break; + default: + break; + } + break; + case RPT_EN_BT_ALL: + switch (ver->frptmap) { + case 0: + case 1: + bit_map = GENMASK(6, 3); + break; + case 2: + bit_map = GENMASK(6, 3) | BIT(8); + break; + case 3: + bit_map = GENMASK(7, 3); + break; + default: + break; + } + break; + case RPT_EN_ALL: + switch (ver->frptmap) { + case 0: + bit_map = GENMASK(6, 0); + break; + case 1: + bit_map = GENMASK(7, 0); + break; + case 2: + case 3: + bit_map = GENMASK(8, 0); + break; + default: + break; + } + break; + case RPT_EN_MONITER: + switch (ver->frptmap) { + case 0: + case 1: + bit_map = GENMASK(6, 2); + break; + case 2: + bit_map = GENMASK(6, 2) | BIT(8); + break; + case 3: + bit_map = GENMASK(8, 2); + break; + default: + break; + } + break; + } + + return bit_map; +} + static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev, u32 rpt_map, bool rpt_state) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *fwinfo = &btc->fwinfo; struct rtw89_btc_btf_set_report r = {0}; - u32 val = 0; + u32 val, bit_map; + + bit_map = rtw89_btc_fw_rpt_ver(rtwdev, rpt_map); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rpt_map=%x, rpt_state=%x\n", __func__, rpt_map, rpt_state); if (rpt_state) - val = fwinfo->rpt_en_map | rpt_map; + val = fwinfo->rpt_en_map | bit_map; else - val = fwinfo->rpt_en_map & ~rpt_map; + val = fwinfo->rpt_en_map & ~bit_map; if (val == fwinfo->rpt_en_map) return; @@ -1593,16 +1780,17 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type, static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) { - const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; switch (type) { case CXDRVINFO_INIT: rtw89_fw_h2c_cxdrv_init(rtwdev); break; case CXDRVINFO_ROLE: - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) rtw89_fw_h2c_cxdrv_role(rtwdev); - else + else if (ver->fwlrole == 1) rtw89_fw_h2c_cxdrv_role_v1(rtwdev); break; case CXDRVINFO_CTRL: @@ -1892,6 +2080,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_bt_link_info *b = &bt->link_info; @@ -1905,7 +2094,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) if (btc->ctrl.manual || wl->status.map.scan) return; - if (chip->chip_id == RTL8852A) { + if (ver->fwlrole == 0) { mode = wl_rinfo->link_mode; connect_cnt = wl_rinfo->connect_cnt; } else { @@ -1924,13 +2113,13 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) r = &wl_rinfo->active_role[i]; r1 = &wl_rinfo_v1->active_role_v1[i]; - if (chip->chip_id == RTL8852A && + if (ver->fwlrole == 0 && (r->role == RTW89_WIFI_ROLE_P2P_GO || r->role == RTW89_WIFI_ROLE_P2P_CLIENT)) { ch = r->ch; bw = r->bw; break; - } else if (chip->chip_id != RTL8852A && + } else if (ver->fwlrole == 1 && (r1->role == RTW89_WIFI_ROLE_P2P_GO || r1->role == RTW89_WIFI_ROLE_P2P_CLIENT)) { ch = r1->ch; @@ -1945,12 +2134,12 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) r = &wl_rinfo->active_role[i]; r1 = &wl_rinfo_v1->active_role_v1[i]; - if (chip->chip_id == RTL8852A && + if (ver->fwlrole == 0 && r->connected && r->band == RTW89_BAND_2G) { ch = r->ch; bw = r->bw; break; - } else if (chip->chip_id != RTL8852A && + } else if (ver->fwlrole == 1 && r1->connected && r1->band == RTW89_BAND_2G) { ch = r1->ch; bw = r1->bw; @@ -2517,15 +2706,16 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) break; case BTC_CXP_OFF_EQ0: _slot_set_tbl(btc, CXST_OFF, cxtbl[0]); + _slot_set_type(btc, CXST_OFF, SLOT_ISO); break; case BTC_CXP_OFF_EQ1: _slot_set_tbl(btc, CXST_OFF, cxtbl[16]); break; case BTC_CXP_OFF_EQ2: - _slot_set_tbl(btc, CXST_OFF, cxtbl[17]); + _slot_set_tbl(btc, CXST_OFF, cxtbl[0]); break; case BTC_CXP_OFF_EQ3: - _slot_set_tbl(btc, CXST_OFF, cxtbl[18]); + _slot_set_tbl(btc, CXST_OFF, cxtbl[24]); break; case BTC_CXP_OFF_BWB0: _slot_set_tbl(btc, CXST_OFF, cxtbl[5]); @@ -2581,6 +2771,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) default: break; } + s[CXST_OFF] = s_def[CXST_OFF]; break; case BTC_CXP_FIX: /* TDMA Fix-Slot */ _write_scbd(rtwdev, BTC_WSCB_TDMA, true); @@ -2607,6 +2798,10 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO); _slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX); break; + case BTC_CXP_FIX_TD4020: + _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX); + _slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX); + break; case BTC_CXP_FIX_TD7010: _slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO); _slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX); @@ -3398,8 +3593,8 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev) static void _set_btg_ctrl(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; @@ -3410,7 +3605,7 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) if (btc->ctrl.manual) return; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -3503,8 +3698,8 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &cx->wl; @@ -3524,7 +3719,7 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) if (btc->ctrl.manual) return; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -3572,8 +3767,8 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) static void _set_bt_rx_agc(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1; @@ -3581,7 +3776,7 @@ static void _set_bt_rx_agc(struct rtw89_dev *rtwdev) bool bt_hi_lna_rx = false; u8 mode; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -3623,6 +3818,7 @@ static void _action_common(struct rtw89_dev *rtwdev) wl->scbd_change = false; btc->cx.cnt_wl[BTC_WCNT_SCBDUPDATE]++; } + btc->dm.tdma_instant_excute = 0; } static void _action_by_bt(struct rtw89_dev *rtwdev) @@ -3651,7 +3847,7 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) case BTC_BT_NOPROFILE: if (_check_freerun(rtwdev)) _action_freerun(rtwdev); - else if (a2dp.active || pan.active) + else if (pan.active) _action_bt_pan(rtwdev); else _action_bt_idle(rtwdev); @@ -4406,7 +4602,7 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update) bt->whql_test = !!(val & BTC_BSCB_WHQL); bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE; - bt->link_info.a2dp_desc.active = !!(val & BTC_BSCB_A2DP_ACT); + bt->link_info.a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT); /* if rfk run 1->0 */ if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN)) @@ -4445,8 +4641,8 @@ static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev) static void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &rtwdev->btc.dm; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &btc->cx.wl; @@ -4461,7 +4657,7 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) _update_dm_step(rtwdev, reason); _update_btc_state_map(rtwdev); - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -4567,6 +4763,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) _action_wl_nc(rtwdev); break; case BTC_WLINK_2G_STA: + if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL)) + bt->scan_rx_low_pri = true; _action_wl_2g_sta(rtwdev); break; case BTC_WLINK_2G_AP: @@ -4583,9 +4781,9 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) break; case BTC_WLINK_2G_SCC: bt->scan_rx_low_pri = true; - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) _action_wl_2g_scc(rtwdev); - else if (chip->chip_id == RTL8852C) + else if (ver->fwlrole == 1) _action_wl_2g_scc_v1(rtwdev); break; case BTC_WLINK_2G_MCC: @@ -4690,7 +4888,7 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode) _write_scbd(rtwdev, BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true); _update_bt_scbd(rtwdev, true); - if (rtw89_mac_get_ctrl_path(rtwdev) && chip->chip_id == RTL8852A) { + if (rtw89_mac_get_ctrl_path(rtwdev)) { rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): PTA owner warning!!\n", __func__); @@ -5000,11 +5198,6 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) a2dp->sink = btinfo.hb3.a2dp_sink; - if (b->profile_cnt.now || b->status.map.ble_connect) - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 1); - else - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 0); - if (!a2dp->exist_last && a2dp->exist) { a2dp->vendor_id = 0; a2dp->flush_time = 0; @@ -5014,12 +5207,6 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) RTW89_COEX_BT_DEVINFO_WORK_PERIOD); } - if (a2dp->exist && (a2dp->flush_time == 0 || a2dp->vendor_id == 0 || - a2dp->play_latency == 1)) - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 1); - else - rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 0); - _run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO); } @@ -5034,10 +5221,10 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif struct rtw89_sta *rtwsta, enum btc_role_state state) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); - const struct rtw89_chip_info *chip = rtwdev->chip; struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_link_info r = {0}; struct rtw89_btc_wl_link_info *wlinfo = NULL; @@ -5101,7 +5288,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif wlinfo = &wl->link_info[r.pid]; memcpy(wlinfo, &r, sizeof(*wlinfo)); - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) _update_wl_info(rtwdev); else _update_wl_info_v1(rtwdev); @@ -5151,9 +5338,7 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta } if (rf_state == BTC_RFCTRL_WL_ON) { - btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0; - rtw89_btc_fw_en_rpt(rtwdev, - RPT_EN_MREG | RPT_EN_BT_VER_INFO, true); + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, true); val = BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG; _write_scbd(rtwdev, val, true); _update_bt_scbd(rtwdev, true); @@ -5164,6 +5349,13 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta _write_scbd(rtwdev, BTC_WSCB_ALL, false); } + btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0; + if (wl->status.map.lps_pre == BTC_LPS_OFF && + wl->status.map.lps_pre != wl->status.map.lps) + btc->dm.tdma_instant_excute = 1; + else + btc->dm.tdma_instant_excute = 0; + _run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE); wl->status.map.rf_off_pre = wl->status.map.rf_off; @@ -5618,8 +5810,8 @@ static void _show_wl_role_info(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &cx->wl; struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info; @@ -5631,7 +5823,7 @@ static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m) seq_puts(m, "========== [WL Status] ==========\n"); - if (chip->chip_id == RTL8852A) + if (ver->fwlrole == 0) mode = wl_rinfo->link_mode; else mode = wl_rinfo_v1->link_mode; @@ -5714,12 +5906,14 @@ static void _show_bt_profile_info(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; struct rtw89_btc_wl_info *wl = &cx->wl; struct rtw89_btc_module *module = &btc->mdinfo; struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; u8 *afh = bt_linfo->afh_map; + u8 *afh_le = bt_linfo->afh_map_le; if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT)) return; @@ -5769,6 +5963,12 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) afh[0], afh[1], afh[2], afh[3], afh[4], afh[5], afh[6], afh[7], afh[8], afh[9]); + if (ver->fcxbtafh == 2 && bt_linfo->status.map.ble_connect) + seq_printf(m, + "LE[%02x%02x_%02x_%02x%02x]", + afh_le[0], afh_le[1], afh_le[2], + afh_le[3], afh_le[4]); + seq_printf(m, "wl_ch_map[en:%d/ch:%d/bw:%d]\n", wl->afh_info.en, wl->afh_info.ch, wl->afh_info.bw); @@ -5800,6 +6000,29 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) "[trx_req_cnt]", cx->cnt_bt[BTC_BCNT_HIPRI_RX], cx->cnt_bt[BTC_BCNT_HIPRI_TX], cx->cnt_bt[BTC_BCNT_LOPRI_RX], cx->cnt_bt[BTC_BCNT_LOPRI_TX], cx->cnt_bt[BTC_BCNT_POLUT]); + + if (bt->enable.now && bt->ver_info.fw == 0) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, false); + + if (bt_linfo->profile_cnt.now || bt_linfo->status.map.ble_connect) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, false); + + if (ver->fcxbtafh == 2 && bt_linfo->status.map.ble_connect) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP_LE, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP_LE, false); + + if (bt_linfo->a2dp_desc.exist && + (bt_linfo->a2dp_desc.flush_time == 0 || + bt_linfo->a2dp_desc.vendor_id == 0 || + bt_linfo->a2dp_desc.play_latency == 1)) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, false); } #define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e @@ -5807,6 +6030,7 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) #define CASE_BTC_POLICY_STR(e) \ case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e #define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e +#define CASE_BTC_EVT_STR(e) case CXEVNT_## e: return #e static const char *steps_to_str(u16 step) { @@ -5947,6 +6171,40 @@ static const char *id_to_slot(u32 id) } } +static const char *id_to_evt(u32 id) +{ + switch (id) { + CASE_BTC_EVT_STR(TDMA_ENTRY); + CASE_BTC_EVT_STR(WL_TMR); + CASE_BTC_EVT_STR(B1_TMR); + CASE_BTC_EVT_STR(B2_TMR); + CASE_BTC_EVT_STR(B3_TMR); + CASE_BTC_EVT_STR(B4_TMR); + CASE_BTC_EVT_STR(W2B_TMR); + CASE_BTC_EVT_STR(B2W_TMR); + CASE_BTC_EVT_STR(BCN_EARLY); + CASE_BTC_EVT_STR(A2DP_EMPTY); + CASE_BTC_EVT_STR(LK_END); + CASE_BTC_EVT_STR(RX_ISR); + CASE_BTC_EVT_STR(RX_FC0); + CASE_BTC_EVT_STR(RX_FC1); + CASE_BTC_EVT_STR(BT_RELINK); + CASE_BTC_EVT_STR(BT_RETRY); + CASE_BTC_EVT_STR(E2G); + CASE_BTC_EVT_STR(E5G); + CASE_BTC_EVT_STR(EBT); + CASE_BTC_EVT_STR(ENULL); + CASE_BTC_EVT_STR(DRV_WLK); + CASE_BTC_EVT_STR(BCN_OK); + CASE_BTC_EVT_STR(BT_CHANGE); + CASE_BTC_EVT_STR(EBT_EXTEND); + CASE_BTC_EVT_STR(E2G_NULL1); + CASE_BTC_EVT_STR(B1FDD_TMR); + default: + return "unknown"; + } +} + static void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data, u8 len, u8 seg_len, u8 start_idx, u8 ring_len) @@ -6045,21 +6303,27 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; - struct rtw89_btc_fbtc_cysta *pcysta; - struct rtw89_btc_fbtc_cysta_v1 *pcysta_v1; + union rtw89_btc_fbtc_cysta_info *pcysta; u32 except_cnt, exception_map; - if (chip->chip_id == RTL8852A) { - pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; - except_cnt = le32_to_cpu(pcysta->except_cnt); - exception_map = le32_to_cpu(pcysta->exception); + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; + if (ver->fcxcysta == 2) { + pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2; + except_cnt = le32_to_cpu(pcysta->v2.except_cnt); + exception_map = le32_to_cpu(pcysta->v2.exception); + } else if (ver->fcxcysta == 3) { + pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3; + except_cnt = le32_to_cpu(pcysta->v3.except_cnt); + exception_map = le32_to_cpu(pcysta->v3.except_map); + } else if (ver->fcxcysta == 4) { + pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4; + except_cnt = pcysta->v4.except_cnt; + exception_map = le32_to_cpu(pcysta->v4.except_map); } else { - pcysta_v1 = &pfwinfo->rpt_fbtc_cysta.finfo_v1; - except_cnt = le32_to_cpu(pcysta_v1->except_cnt); - exception_map = le32_to_cpu(pcysta_v1->except_map); + return; } if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 && except_cnt == 0 && @@ -6097,23 +6361,20 @@ static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_fbtc_tdma(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; struct rtw89_btc_fbtc_tdma *t = NULL; - struct rtw89_btc_fbtc_slot *s = NULL; - struct rtw89_btc_dm *dm = &btc->dm; - u8 i, cnt = 0; pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo; if (!pcinfo->valid) return; - if (chip->chip_id == RTL8852A) - t = &pfwinfo->rpt_fbtc_tdma.finfo; + if (ver->fcxtdma == 1) + t = &pfwinfo->rpt_fbtc_tdma.finfo.v1; else - t = &pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma; + t = &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma; seq_printf(m, " %-15s : ", "[tdma_policy]"); @@ -6130,75 +6391,43 @@ static void _show_fbtc_tdma(struct rtw89_dev *rtwdev, struct seq_file *m) "policy_type:%d", (u32)btc->policy_type); - s = pfwinfo->rpt_fbtc_slots.finfo.slot; - - for (i = 0; i < CXST_MAX; i++) { - if (dm->update_slot_map == BIT(CXST_MAX) - 1) - break; - - if (!(dm->update_slot_map & BIT(i))) - continue; - - if (cnt % 6 == 0) - seq_printf(m, - " %-15s : %d[%d/0x%x/%d]", - "[slot_policy]", - (u32)i, - s[i].dur, s[i].cxtbl, s[i].cxtype); - else - seq_printf(m, - ", %d[%d/0x%x/%d]", - (u32)i, - s[i].dur, s[i].cxtbl, s[i].cxtype); - if (cnt % 6 == 5) - seq_puts(m, "\n"); - cnt++; - } seq_puts(m, "\n"); } static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; - struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_slots *pslots = NULL; - struct rtw89_btc_fbtc_slot s; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_fbtc_slot *s; u8 i = 0; - pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo; - if (!pcinfo->valid) - return; - - pslots = &pfwinfo->rpt_fbtc_slots.finfo; - for (i = 0; i < CXST_MAX; i++) { - s = pslots->slot[i]; - if (i % 6 == 0) + s = &dm->slot_now[i]; + if (i % 5 == 0) seq_printf(m, - " %-15s : %02d[%03d/0x%x/%d]", + " %-15s : %5s[%03d/0x%x/%d]", "[slot_list]", - (u32)i, - s.dur, s.cxtbl, s.cxtype); + id_to_slot((u32)i), + s->dur, s->cxtbl, s->cxtype); else seq_printf(m, - ", %02d[%03d/0x%x/%d]", - (u32)i, - s.dur, s.cxtbl, s.cxtype); - if (i % 6 == 5) + ", %5s[%03d/0x%x/%d]", + id_to_slot((u32)i), + s->dur, s->cxtbl, s->cxtype); + if (i % 5 == 4) seq_puts(m, "\n"); } + seq_puts(m, "\n"); } -static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_fbtc_cysta_v2(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL; - struct rtw89_btc_fbtc_cysta_cpu pcysta[1]; + struct rtw89_btc_fbtc_cysta_v2 *pcysta_le32 = NULL; union rtw89_btc_fbtc_rxflct r; u8 i, cnt = 0, slot_pair; u16 cycle, c_begin, c_end, store_index; @@ -6207,65 +6436,66 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo; - rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta); + pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo.v2; seq_printf(m, " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", - "[cycle_cnt]", pcysta->cycles, pcysta->bcn_cnt[CXBCN_ALL], - pcysta->bcn_cnt[CXBCN_ALL_OK], - pcysta->bcn_cnt[CXBCN_BT_SLOT], - pcysta->bcn_cnt[CXBCN_BT_OK]); + "[cycle_cnt]", + le16_to_cpu(pcysta_le32->cycles), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL]), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL_OK]), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_SLOT]), + le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_OK])); for (i = 0; i < CXST_MAX; i++) { - if (!pcysta->slot_cnt[i]) + if (!le32_to_cpu(pcysta_le32->slot_cnt[i])) continue; - seq_printf(m, - ", %d:%d", (u32)i, pcysta->slot_cnt[i]); + seq_printf(m, ", %s:%d", id_to_slot((u32)i), + le32_to_cpu(pcysta_le32->slot_cnt[i])); } if (dm->tdma_now.rxflctrl) { - seq_printf(m, - ", leak_rx:%d", pcysta->leakrx_cnt); + seq_printf(m, ", leak_rx:%d", + le32_to_cpu(pcysta_le32->leakrx_cnt)); } - if (pcysta->collision_cnt) { - seq_printf(m, - ", collision:%d", pcysta->collision_cnt); + if (le32_to_cpu(pcysta_le32->collision_cnt)) { + seq_printf(m, ", collision:%d", + le32_to_cpu(pcysta_le32->collision_cnt)); } - if (pcysta->skip_cnt) { - seq_printf(m, - ", skip:%d", pcysta->skip_cnt); + if (le32_to_cpu(pcysta_le32->skip_cnt)) { + seq_printf(m, ", skip:%d", + le32_to_cpu(pcysta_le32->skip_cnt)); } seq_puts(m, "\n"); seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]", "[cycle_time]", - pcysta->tavg_cycle[CXT_WL], - pcysta->tavg_cycle[CXT_BT], - pcysta->tavg_lk / 1000, pcysta->tavg_lk % 1000); - seq_printf(m, - ", max_t[wl:%d/bt:%d/lk:%d.%03d]", - pcysta->tmax_cycle[CXT_WL], - pcysta->tmax_cycle[CXT_BT], - pcysta->tmax_lk / 1000, pcysta->tmax_lk % 1000); - seq_printf(m, - ", maxdiff_t[wl:%d/bt:%d]\n", - pcysta->tmaxdiff_cycle[CXT_WL], - pcysta->tmaxdiff_cycle[CXT_BT]); - - if (pcysta->cycles == 0) + le16_to_cpu(pcysta_le32->tavg_cycle[CXT_WL]), + le16_to_cpu(pcysta_le32->tavg_cycle[CXT_BT]), + le16_to_cpu(pcysta_le32->tavg_lk) / 1000, + le16_to_cpu(pcysta_le32->tavg_lk) % 1000); + seq_printf(m, ", max_t[wl:%d/bt:%d/lk:%d.%03d]", + le16_to_cpu(pcysta_le32->tmax_cycle[CXT_WL]), + le16_to_cpu(pcysta_le32->tmax_cycle[CXT_BT]), + le16_to_cpu(pcysta_le32->tmax_lk) / 1000, + le16_to_cpu(pcysta_le32->tmax_lk) % 1000); + seq_printf(m, ", maxdiff_t[wl:%d/bt:%d]\n", + le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_WL]), + le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_BT])); + + if (le16_to_cpu(pcysta_le32->cycles) <= 1) return; /* 1 cycle record 1 wl-slot and 1 bt-slot */ slot_pair = BTC_CYCLE_SLOT_MAX / 2; - if (pcysta->cycles <= slot_pair) + if (le16_to_cpu(pcysta_le32->cycles) <= slot_pair) c_begin = 1; else - c_begin = pcysta->cycles - slot_pair + 1; + c_begin = le16_to_cpu(pcysta_le32->cycles) - slot_pair + 1; - c_end = pcysta->cycles; + c_end = le16_to_cpu(pcysta_le32->cycles); for (cycle = c_begin; cycle <= c_end; cycle++) { cnt++; @@ -6274,13 +6504,13 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 1) seq_printf(m, " %-15s : ->b%02d->w%02d", "[cycle_step]", - pcysta->tslot_cycle[store_index], - pcysta->tslot_cycle[store_index + 1]); + le16_to_cpu(pcysta_le32->tslot_cycle[store_index]), + le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1])); else seq_printf(m, "->b%02d->w%02d", - pcysta->tslot_cycle[store_index], - pcysta->tslot_cycle[store_index + 1]); + le16_to_cpu(pcysta_le32->tslot_cycle[store_index]), + le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1])); if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end) seq_puts(m, "\n"); } @@ -6289,41 +6519,43 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) seq_printf(m, " %-15s : a2dp_ept:%d, a2dp_late:%d", "[a2dp_t_sta]", - pcysta->a2dpept, pcysta->a2dpeptto); + le16_to_cpu(pcysta_le32->a2dpept), + le16_to_cpu(pcysta_le32->a2dpeptto)); seq_printf(m, ", avg_t:%d, max_t:%d", - pcysta->tavg_a2dpept, pcysta->tmax_a2dpept); + le16_to_cpu(pcysta_le32->tavg_a2dpept), + le16_to_cpu(pcysta_le32->tmax_a2dpept)); r.val = dm->tdma_now.rxflctrl; if (r.type && r.tgln_n) { seq_printf(m, ", cycle[PSTDMA:%d/TDMA:%d], ", - pcysta->cycles_a2dp[CXT_FLCTRL_ON], - pcysta->cycles_a2dp[CXT_FLCTRL_OFF]); + le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_ON]), + le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_OFF])); seq_printf(m, "avg_t[PSTDMA:%d/TDMA:%d], ", - pcysta->tavg_a2dp[CXT_FLCTRL_ON], - pcysta->tavg_a2dp[CXT_FLCTRL_OFF]); + le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_ON]), + le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_OFF])); seq_printf(m, "max_t[PSTDMA:%d/TDMA:%d]", - pcysta->tmax_a2dp[CXT_FLCTRL_ON], - pcysta->tmax_a2dp[CXT_FLCTRL_OFF]); + le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_ON]), + le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_OFF])); } seq_puts(m, "\n"); } } -static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_fbtc_cysta_v3(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_fbtc_a2dp_trx_stat *a2dp_trx; - struct rtw89_btc_fbtc_cysta_v1 *pcysta; + struct rtw89_btc_fbtc_cysta_v3 *pcysta; struct rtw89_btc_rpt_cmn_info *pcinfo; u8 i, cnt = 0, slot_pair, divide_cnt; u16 cycle, c_begin, c_end, store_index; @@ -6332,7 +6564,7 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - pcysta = &pfwinfo->rpt_fbtc_cysta.finfo_v1; + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v3; seq_printf(m, " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", "[cycle_cnt]", @@ -6379,7 +6611,7 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT])); cycle = le16_to_cpu(pcysta->cycles); - if (cycle == 0) + if (cycle <= 1) return; /* 1 cycle record 1 wl-slot and 1 bt-slot */ @@ -6401,40 +6633,171 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) cnt++; store_index = ((cycle - 1) % slot_pair) * 2; - if (cnt % divide_cnt == 1) { - seq_printf(m, "\n\r %-15s : ", "[cycle_step]"); - } else { - seq_printf(m, "->b%02d", - le16_to_cpu(pcysta->slot_step_time[store_index])); - if (a2dp->exist) { - a2dp_trx = &pcysta->a2dp_trx[store_index]; - seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", - a2dp_trx->empty_cnt, - a2dp_trx->retry_cnt, - a2dp_trx->tx_rate ? 3 : 2, - a2dp_trx->tx_cnt, - a2dp_trx->ack_cnt, - a2dp_trx->nack_cnt); - } - seq_printf(m, "->w%02d", - le16_to_cpu(pcysta->slot_step_time[store_index + 1])); - if (a2dp->exist) { - a2dp_trx = &pcysta->a2dp_trx[store_index + 1]; - seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", - a2dp_trx->empty_cnt, - a2dp_trx->retry_cnt, - a2dp_trx->tx_rate ? 3 : 2, - a2dp_trx->tx_cnt, - a2dp_trx->ack_cnt, - a2dp_trx->nack_cnt); - } + if (cnt % divide_cnt == 1) + seq_printf(m, " %-15s : ", "[cycle_step]"); + + seq_printf(m, "->b%02d", + le16_to_cpu(pcysta->slot_step_time[store_index])); + if (a2dp->exist) { + a2dp_trx = &pcysta->a2dp_trx[store_index]; + seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", + a2dp_trx->empty_cnt, + a2dp_trx->retry_cnt, + a2dp_trx->tx_rate ? 3 : 2, + a2dp_trx->tx_cnt, + a2dp_trx->ack_cnt, + a2dp_trx->nack_cnt); } - if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end) + seq_printf(m, "->w%02d", + le16_to_cpu(pcysta->slot_step_time[store_index + 1])); + if (a2dp->exist) { + a2dp_trx = &pcysta->a2dp_trx[store_index + 1]; + seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", + a2dp_trx->empty_cnt, + a2dp_trx->retry_cnt, + a2dp_trx->tx_rate ? 3 : 2, + a2dp_trx->tx_cnt, + a2dp_trx->ack_cnt, + a2dp_trx->nack_cnt); + } + if (cnt % divide_cnt == 0 || cnt == c_end) seq_puts(m, "\n"); } if (a2dp->exist) { - seq_printf(m, "%-15s : a2dp_ept:%d, a2dp_late:%d", + seq_printf(m, " %-15s : a2dp_ept:%d, a2dp_late:%d", + "[a2dp_t_sta]", + le16_to_cpu(pcysta->a2dp_ept.cnt), + le16_to_cpu(pcysta->a2dp_ept.cnt_timeout)); + + seq_printf(m, ", avg_t:%d, max_t:%d", + le16_to_cpu(pcysta->a2dp_ept.tavg), + le16_to_cpu(pcysta->a2dp_ept.tmax)); + + seq_puts(m, "\n"); + } +} + +static void _show_fbtc_cysta_v4(struct rtw89_dev *rtwdev, struct seq_file *m) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; + struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx; + struct rtw89_btc_fbtc_cysta_v4 *pcysta; + struct rtw89_btc_rpt_cmn_info *pcinfo; + u8 i, cnt = 0, slot_pair, divide_cnt; + u16 cycle, c_begin, c_end, store_index; + + pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo; + if (!pcinfo->valid) + return; + + pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v4; + seq_printf(m, + " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", + "[cycle_cnt]", + le16_to_cpu(pcysta->cycles), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]), + le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK])); + + for (i = 0; i < CXST_MAX; i++) { + if (!le16_to_cpu(pcysta->slot_cnt[i])) + continue; + + seq_printf(m, ", %s:%d", id_to_slot(i), + le16_to_cpu(pcysta->slot_cnt[i])); + } + + if (dm->tdma_now.rxflctrl) + seq_printf(m, ", leak_rx:%d", + le32_to_cpu(pcysta->leak_slot.cnt_rximr)); + + if (pcysta->collision_cnt) + seq_printf(m, ", collision:%d", pcysta->collision_cnt); + + if (le16_to_cpu(pcysta->skip_cnt)) + seq_printf(m, ", skip:%d", + le16_to_cpu(pcysta->skip_cnt)); + + seq_puts(m, "\n"); + + seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]", + "[cycle_time]", + le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]), + le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]), + le16_to_cpu(pcysta->leak_slot.tavg) / 1000, + le16_to_cpu(pcysta->leak_slot.tavg) % 1000); + seq_printf(m, + ", max_t[wl:%d/bt:%d/lk:%d.%03d]", + le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]), + le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]), + le16_to_cpu(pcysta->leak_slot.tmax) / 1000, + le16_to_cpu(pcysta->leak_slot.tmax) % 1000); + seq_printf(m, + ", maxdiff_t[wl:%d/bt:%d]\n", + le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_WL]), + le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT])); + + cycle = le16_to_cpu(pcysta->cycles); + if (cycle <= 1) + return; + + /* 1 cycle record 1 wl-slot and 1 bt-slot */ + slot_pair = BTC_CYCLE_SLOT_MAX / 2; + + if (cycle <= slot_pair) + c_begin = 1; + else + c_begin = cycle - slot_pair + 1; + + c_end = cycle; + + if (a2dp->exist) + divide_cnt = 3; + else + divide_cnt = BTC_CYCLE_SLOT_MAX / 4; + + for (cycle = c_begin; cycle <= c_end; cycle++) { + cnt++; + store_index = ((cycle - 1) % slot_pair) * 2; + + if (cnt % divide_cnt == 1) + seq_printf(m, " %-15s : ", "[cycle_step]"); + + seq_printf(m, "->b%02d", + le16_to_cpu(pcysta->slot_step_time[store_index])); + if (a2dp->exist) { + a2dp_trx = &pcysta->a2dp_trx[store_index]; + seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", + a2dp_trx->empty_cnt, + a2dp_trx->retry_cnt, + a2dp_trx->tx_rate ? 3 : 2, + a2dp_trx->tx_cnt, + a2dp_trx->ack_cnt, + a2dp_trx->nack_cnt); + } + seq_printf(m, "->w%02d", + le16_to_cpu(pcysta->slot_step_time[store_index + 1])); + if (a2dp->exist) { + a2dp_trx = &pcysta->a2dp_trx[store_index + 1]; + seq_printf(m, "(%d/%d/%dM/%d/%d/%d)", + a2dp_trx->empty_cnt, + a2dp_trx->retry_cnt, + a2dp_trx->tx_rate ? 3 : 2, + a2dp_trx->tx_cnt, + a2dp_trx->ack_cnt, + a2dp_trx->nack_cnt); + } + if (cnt % divide_cnt == 0 || cnt == c_end) + seq_puts(m, "\n"); + } + + if (a2dp->exist) { + seq_printf(m, " %-15s : a2dp_ept:%d, a2dp_late:%d", "[a2dp_t_sta]", le16_to_cpu(pcysta->a2dp_ept.cnt), le16_to_cpu(pcysta->a2dp_ept.cnt_timeout)); @@ -6449,12 +6812,11 @@ static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo; - struct rtw89_btc_fbtc_cynullsta *ns; - struct rtw89_btc_fbtc_cynullsta_v1 *ns_v1; + union rtw89_btc_fbtc_cynullsta_info *ns; u8 i = 0; if (!btc->dm.tdma_now.rxflctrl) @@ -6464,68 +6826,56 @@ static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - if (chip->chip_id == RTL8852A) { - ns = &pfwinfo->rpt_fbtc_nullsta.finfo; - - seq_printf(m, " %-15s : ", "[null_sta]"); - + ns = &pfwinfo->rpt_fbtc_nullsta.finfo; + if (ver->fcxnullsta == 1) { for (i = 0; i < 2; i++) { - if (i != 0) - seq_printf(m, ", null-%d", i); - else - seq_printf(m, "null-%d", i); + seq_printf(m, " %-15s : ", "[NULL-STA]"); + seq_printf(m, "null-%d", i); seq_printf(m, "[ok:%d/", - le32_to_cpu(ns->result[i][1])); + le32_to_cpu(ns->v1.result[i][1])); seq_printf(m, "fail:%d/", - le32_to_cpu(ns->result[i][0])); + le32_to_cpu(ns->v1.result[i][0])); seq_printf(m, "on_time:%d/", - le32_to_cpu(ns->result[i][2])); + le32_to_cpu(ns->v1.result[i][2])); seq_printf(m, "retry:%d/", - le32_to_cpu(ns->result[i][3])); + le32_to_cpu(ns->v1.result[i][3])); seq_printf(m, "avg_t:%d.%03d/", - le32_to_cpu(ns->avg_t[i]) / 1000, - le32_to_cpu(ns->avg_t[i]) % 1000); - seq_printf(m, "max_t:%d.%03d]", - le32_to_cpu(ns->max_t[i]) / 1000, - le32_to_cpu(ns->max_t[i]) % 1000); + le32_to_cpu(ns->v1.avg_t[i]) / 1000, + le32_to_cpu(ns->v1.avg_t[i]) % 1000); + seq_printf(m, "max_t:%d.%03d]\n", + le32_to_cpu(ns->v1.max_t[i]) / 1000, + le32_to_cpu(ns->v1.max_t[i]) % 1000); } } else { - ns_v1 = &pfwinfo->rpt_fbtc_nullsta.finfo_v1; - - seq_printf(m, " %-15s : ", "[null_sta]"); - for (i = 0; i < 2; i++) { - if (i != 0) - seq_printf(m, ", null-%d", i); - else - seq_printf(m, "null-%d", i); + seq_printf(m, " %-15s : ", "[NULL-STA]"); + seq_printf(m, "null-%d", i); seq_printf(m, "[Tx:%d/", - le32_to_cpu(ns_v1->result[i][4])); + le32_to_cpu(ns->v2.result[i][4])); seq_printf(m, "[ok:%d/", - le32_to_cpu(ns_v1->result[i][1])); + le32_to_cpu(ns->v2.result[i][1])); seq_printf(m, "fail:%d/", - le32_to_cpu(ns_v1->result[i][0])); + le32_to_cpu(ns->v2.result[i][0])); seq_printf(m, "on_time:%d/", - le32_to_cpu(ns_v1->result[i][2])); + le32_to_cpu(ns->v2.result[i][2])); seq_printf(m, "retry:%d/", - le32_to_cpu(ns_v1->result[i][3])); + le32_to_cpu(ns->v2.result[i][3])); seq_printf(m, "avg_t:%d.%03d/", - le32_to_cpu(ns_v1->avg_t[i]) / 1000, - le32_to_cpu(ns_v1->avg_t[i]) % 1000); - seq_printf(m, "max_t:%d.%03d]", - le32_to_cpu(ns_v1->max_t[i]) / 1000, - le32_to_cpu(ns_v1->max_t[i]) % 1000); + le32_to_cpu(ns->v2.avg_t[i]) / 1000, + le32_to_cpu(ns->v2.avg_t[i]) % 1000); + seq_printf(m, "max_t:%d.%03d]\n", + le32_to_cpu(ns->v2.max_t[i]) / 1000, + le32_to_cpu(ns->v2.max_t[i]) % 1000); } } - seq_puts(m, "\n"); } -static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_fbtc_step_v2(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_steps *pstep = NULL; + struct rtw89_btc_fbtc_steps_v2 *pstep = NULL; u8 type, val, cnt = 0, state = 0; bool outloop = false; u16 i, diff_t, n_start = 0, n_stop = 0; @@ -6535,7 +6885,7 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - pstep = &pfwinfo->rpt_fbtc_step.finfo; + pstep = &pfwinfo->rpt_fbtc_step.finfo.v2; pos_old = le16_to_cpu(pstep->pos_old); pos_new = le16_to_cpu(pstep->pos_new); @@ -6589,10 +6939,67 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) } while (!outloop); } +static void _show_fbtc_step_v3(struct rtw89_dev *rtwdev, struct seq_file *m) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; + struct rtw89_btc_rpt_cmn_info *pcinfo; + struct rtw89_btc_fbtc_steps_v3 *pstep; + u32 i, n_begin, n_end, array_idx, cnt = 0; + u8 type, val; + u16 diff_t; + + if ((pfwinfo->rpt_en_map & + rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_FW_STEP_INFO)) == 0) + return; + + pcinfo = &pfwinfo->rpt_fbtc_step.cinfo; + if (!pcinfo->valid) + return; + + pstep = &pfwinfo->rpt_fbtc_step.finfo.v3; + if (pcinfo->req_fver != pstep->fver) + return; + + if (le32_to_cpu(pstep->cnt) <= FCXDEF_STEP) + n_begin = 1; + else + n_begin = le32_to_cpu(pstep->cnt) - FCXDEF_STEP + 1; + + n_end = le32_to_cpu(pstep->cnt); + + if (n_begin > n_end) + return; + + /* restore step info by using ring instead of FIFO */ + for (i = n_begin; i <= n_end; i++) { + array_idx = (i - 1) % FCXDEF_STEP; + type = pstep->step[array_idx].type; + val = pstep->step[array_idx].val; + diff_t = le16_to_cpu(pstep->step[array_idx].difft); + + if (type == CXSTEP_NONE || type >= CXSTEP_MAX) + continue; + + if (cnt % 10 == 0) + seq_printf(m, " %-15s : ", "[steps]"); + + seq_printf(m, "-> %s(%02d)", + (type == CXSTEP_SLOT ? + id_to_slot((u32)val) : + id_to_evt((u32)val)), diff_t); + + if (cnt % 10 == 9) + seq_puts(m, "\n"); + + cnt++; + } +} + static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM)) return; @@ -6601,13 +7008,20 @@ static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m) _show_fbtc_tdma(rtwdev, m); _show_fbtc_slots(rtwdev, m); - if (chip->chip_id == RTL8852A) - _show_fbtc_cysta(rtwdev, m); - else - _show_fbtc_cysta_v1(rtwdev, m); + if (ver->fcxcysta == 2) + _show_fbtc_cysta_v2(rtwdev, m); + else if (ver->fcxcysta == 3) + _show_fbtc_cysta_v3(rtwdev, m); + else if (ver->fcxcysta == 4) + _show_fbtc_cysta_v4(rtwdev, m); _show_fbtc_nullsta(rtwdev, m); - _show_fbtc_step(rtwdev, m); + + if (ver->fcxstep == 2) + _show_fbtc_step_v2(rtwdev, m); + else if (ver->fcxstep == 3) + _show_fbtc_step_v3(rtwdev, m); + } static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt_cfg) @@ -6680,10 +7094,7 @@ static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m) /* To avoid I/O if WL LPS or power-off */ if (!wl->status.map.lps && !wl->status.map.rf_off) { - if (chip->chip_id == RTL8852A) - btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); - else if (chip->chip_id == RTL8852C) - btc->dm.pta_owner = 0; + btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev); _get_gnt(rtwdev, &gnt_cfg); gnt = gnt_cfg.band[0]; @@ -6729,6 +7140,9 @@ static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m) if (cnt % 6 == 5) seq_puts(m, "\n"); cnt++; + + if (i >= pmreg->reg_num) + seq_puts(m, "\n"); } pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo; @@ -6754,12 +7168,12 @@ static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m) seq_puts(m, "\n"); } -static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_rpt_ctrl *prptctrl = NULL; + struct rtw89_btc_fbtc_rpt_ctrl_v1 *prptctrl = NULL; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_wl_info *wl = &cx->wl; @@ -6774,7 +7188,7 @@ static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m) pcinfo = &pfwinfo->rpt_ctrl.cinfo; if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) { - prptctrl = &pfwinfo->rpt_ctrl.finfo; + prptctrl = &pfwinfo->rpt_ctrl.finfo.v1; seq_printf(m, " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ", @@ -6858,11 +7272,11 @@ static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m) cnt[BTC_NCNT_CUSTOMERIZE]); } -static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) +static void _show_summary_v4(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; - struct rtw89_btc_fbtc_rpt_ctrl_v1 *prptctrl; + struct rtw89_btc_fbtc_rpt_ctrl_v4 *prptctrl; struct rtw89_btc_rpt_cmn_info *pcinfo; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_dm *dm = &btc->dm; @@ -6878,7 +7292,7 @@ static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) pcinfo = &pfwinfo->rpt_ctrl.cinfo; if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) { - prptctrl = &pfwinfo->rpt_ctrl.finfo_v1; + prptctrl = &pfwinfo->rpt_ctrl.finfo.v4; seq_printf(m, " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ", @@ -6970,11 +7384,127 @@ static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m) cnt[BTC_NCNT_CUSTOMERIZE]); } +static void _show_summary_v5(struct rtw89_dev *rtwdev, struct seq_file *m) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; + struct rtw89_btc_fbtc_rpt_ctrl_v5 *prptctrl; + struct rtw89_btc_rpt_cmn_info *pcinfo; + struct rtw89_btc_cx *cx = &btc->cx; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_wl_info *wl = &cx->wl; + u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify; + u8 i; + + if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY)) + return; + + seq_puts(m, "========== [Statistics] ==========\n"); + + pcinfo = &pfwinfo->rpt_ctrl.cinfo; + if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) { + prptctrl = &pfwinfo->rpt_ctrl.finfo.v5; + + seq_printf(m, + " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d), ", + "[summary]", pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail, + le16_to_cpu(prptctrl->rpt_info.cnt_h2c), + pfwinfo->cnt_c2h, + le16_to_cpu(prptctrl->rpt_info.cnt_c2h), + le16_to_cpu(prptctrl->rpt_info.len_c2h)); + + seq_printf(m, + "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x", + pfwinfo->event[BTF_EVNT_RPT], + le16_to_cpu(prptctrl->rpt_info.cnt), + le32_to_cpu(prptctrl->rpt_info.en)); + + if (dm->error.map.wl_fw_hang) + seq_puts(m, " (WL FW Hang!!)"); + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : send_ok:%d, send_fail:%d, recv:%d, ", + "[mailbox]", + le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok), + le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail), + le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv)); + + seq_printf(m, + "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n", + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack), + le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack)); + + seq_printf(m, + " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d]", + "[RFK/LPS]", cx->cnt_wl[BTC_WCNT_RFK_REQ], + cx->cnt_wl[BTC_WCNT_RFK_GO], + cx->cnt_wl[BTC_WCNT_RFK_REJECT], + cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]); + + seq_printf(m, + ", bt_rfk[req:%d]", + le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ])); + + seq_printf(m, + ", AOAC[RF_on:%d/RF_off:%d]", + le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on), + le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off)); + } else { + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d", + "[summary]", pfwinfo->cnt_h2c, + pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h); + } + + if (!pcinfo->valid || pfwinfo->len_mismch || pfwinfo->fver_mismch || + pfwinfo->err[BTFRE_EXCEPTION]) { + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : WL FW rpt error!![rpt_ctrl_valid:%d/len:" + "0x%x/ver:0x%x/ex:%d/lps=%d/rf_off=%d]", + "[ERROR]", pcinfo->valid, pfwinfo->len_mismch, + pfwinfo->fver_mismch, pfwinfo->err[BTFRE_EXCEPTION], + wl->status.map.lps, wl->status.map.rf_off); + } + + for (i = 0; i < BTC_NCNT_NUM; i++) + cnt_sum += dm->cnt_notify[i]; + + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ", + "[notify_cnt]", + cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO], + cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]); + + seq_printf(m, + "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d", + cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE], + cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK], + cnt[BTC_NCNT_WL_STA]); + + seq_puts(m, "\n"); + seq_printf(m, + " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ", + "[notify_cnt]", + cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH], + cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SPECIAL_PACKET]); + + seq_printf(m, + "timer=%d, control=%d, customerize=%d", + cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL], + cnt[BTC_NCNT_CUSTOMERIZE]); +} + void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; @@ -7003,8 +7533,41 @@ void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m) _show_dm_info(rtwdev, m); _show_fw_dm_msg(rtwdev, m); _show_mreg(rtwdev, m); - if (chip->chip_id == RTL8852A) - _show_summary(rtwdev, m); - else + if (ver->fcxbtcrpt == 1) _show_summary_v1(rtwdev, m); + else if (ver->fcxbtcrpt == 4) + _show_summary_v4(rtwdev, m); + else if (ver->fcxbtcrpt == 5) + _show_summary_v5(rtwdev, m); +} + +void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *btc_ver_def; + const struct rtw89_fw_suit *fw_suit; + u32 suit_ver_code; + int i; + + fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL); + suit_ver_code = RTW89_FW_SUIT_VER_CODE(fw_suit); + + for (i = 0; i < ARRAY_SIZE(rtw89_btc_ver_defs); i++) { + btc_ver_def = &rtw89_btc_ver_defs[i]; + + if (chip->chip_id != btc_ver_def->chip_id) + continue; + + if (suit_ver_code >= btc_ver_def->fw_ver_code) { + btc->ver = btc_ver_def; + goto out; + } + } + + btc->ver = &rtw89_btc_ver_defs[RTW89_DEFAULT_BTC_VER_IDX]; + +out: + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] use version def[%d] = 0x%08x\n", + (int)(btc->ver - rtw89_btc_ver_defs), btc->ver->fw_ver_code); } diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index ca16afa97ec0..401fb55df82b 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -164,6 +164,7 @@ void rtw89_coex_rfk_chk_work(struct work_struct *work); void rtw89_coex_power_on(struct rtw89_dev *rtwdev); void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type); void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type); +void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev); static inline u8 rtw89_btc_phymap(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 931aff8b5dc9..f09361bc4a4d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -498,7 +498,8 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); u16 lowest_rate; - if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE || vif->p2p) + if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE || + (vif && vif->p2p)) lowest_rate = RTW89_HW_RATE_OFDM6; else if (chan->band_type == RTW89_BAND_2G) lowest_rate = RTW89_HW_RATE_CCK1; @@ -511,6 +512,21 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, return __ffs(vif->bss_conf.basic_rates) + lowest_rate; } +static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct ieee80211_vif *vif = tx_req->vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_sta *sta = tx_req->sta; + struct rtw89_sta *rtwsta; + + if (!sta) + return rtwvif->mac_id; + + rtwsta = (struct rtw89_sta *)sta->drv_priv; + return rtwsta->mac_id; +} + static void rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) @@ -527,6 +543,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->ch_dma = ch_dma; desc_info->port = desc_info->hiq ? rtwvif->port : 0; + desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->hw_ssn_sel = RTW89_MGMT_HW_SSN_SEL; desc_info->hw_seq_mode = RTW89_MGMT_HW_SEQ_MODE; @@ -669,27 +686,14 @@ desc_bk: desc_info->bk = true; } -static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev, - struct rtw89_core_tx_request *tx_req) -{ - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta; - - if (!sta) - return rtwvif->mac_id; - - rtwsta = (struct rtw89_sta *)sta->drv_priv; - return rtwsta->mac_id; -} - static void rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { struct ieee80211_vif *vif = tx_req->vif; + struct ieee80211_sta *sta = tx_req->sta; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; @@ -707,6 +711,7 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->port = desc_info->hiq ? rtwvif->port : 0; + desc_info->er_cap = rtwsta ? rtwsta->er_cap : false; /* enable wd_info for AMPDU */ desc_info->en_wd_info = true; @@ -1006,7 +1011,9 @@ static __le32 rtw89_build_txwd_info0(struct rtw89_tx_desc_info *desc_info) static __le32 rtw89_build_txwd_info0_v1(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(RTW89_TXWD_INFO0_DISDATAFB, desc_info->dis_data_fb) | - FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port); + FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port) | + FIELD_PREP(RTW89_TXWD_INFO0_DATA_ER, desc_info->er_cap) | + FIELD_PREP(RTW89_TXWD_INFO0_DATA_BW_ER, 0); return cpu_to_le32(dword); } @@ -1757,7 +1764,8 @@ static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev) RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw)) return RTW89_PS_MODE_NONE; - if (chip->ps_mode_supported & BIT(RTW89_PS_MODE_PWR_GATED)) + if ((chip->ps_mode_supported & BIT(RTW89_PS_MODE_PWR_GATED)) && + !RTW89_CHK_FW_FEATURE(NO_LPS_PG, &rtwdev->fw)) return RTW89_PS_MODE_PWR_GATED; if (chip->ps_mode_supported & BIT(RTW89_PS_MODE_CLK_GATED)) @@ -2199,8 +2207,9 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev) static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && - rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) + if ((rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) || + rtwvif->tdls_peer) return; if (rtwvif->stats.tx_tfc_lv == RTW89_TFC_IDLE && @@ -2426,6 +2435,7 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; int i; + int ret; rtwsta->rtwdev = rtwdev; rtwsta->rtwvif = rtwvif; @@ -2450,6 +2460,21 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, RTW89_MAX_MAC_ID_NUM); if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM) return -ENOSPC; + + ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta->mac_id, false); + if (ret) { + rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwsta->mac_id); + rtw89_warn(rtwdev, "failed to send h2c macid pause\n"); + return ret; + } + + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + RTW89_ROLE_CREATE); + if (ret) { + rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwsta->mac_id); + rtw89_warn(rtwdev, "failed to send h2c role info\n"); + return ret; + } } return 0; @@ -2459,9 +2484,12 @@ int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; rtwdev->total_sta_assoc--; + if (sta->tdls) + rtwvif->tdls_peer--; rtwsta->disassoc = true; return 0; @@ -2484,8 +2512,10 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, if (sta->tdls) rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam); - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { rtw89_vif_type_mapping(vif, false); + rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true); + } ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta); if (ret) { @@ -2499,14 +2529,6 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, return ret; } - if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, RTW89_ROLE_REMOVE); - if (ret) { - rtw89_warn(rtwdev, "failed to send h2c role info\n"); - return ret; - } - } - /* update cam aid mac_id net_type */ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); if (ret) { @@ -2527,18 +2549,6 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, int ret; if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { - ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta->mac_id, false); - if (ret) { - rtw89_warn(rtwdev, "failed to send h2c macid pause\n"); - return ret; - } - - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, RTW89_ROLE_CREATE); - if (ret) { - rtw89_warn(rtwdev, "failed to send h2c role info\n"); - return ret; - } - if (sta->tdls) { ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, sta->addr); if (ret) { @@ -2573,22 +2583,30 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, return ret; } - ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwsta->mac_id); - if (ret) { - rtw89_warn(rtwdev, "failed to send h2c general packet\n"); - return ret; - } - rtwdev->total_sta_assoc++; + if (sta->tdls) + rtwvif->tdls_peer++; rtw89_phy_ra_assoc(rtwdev, sta); rtw89_mac_bf_assoc(rtwdev, vif, sta); rtw89_mac_bf_monitor_calc(rtwdev, sta, false); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + if (bss_conf->he_support && + !(bss_conf->he_oper.params & IEEE80211_HE_OPERATION_ER_SU_DISABLE)) + rtwsta->er_cap = true; + rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_CONN_END); rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template); rtw89_phy_ul_tb_assoc(rtwdev, rtwvif); + + ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c general packet\n"); + return ret; + } } return ret; @@ -2600,13 +2618,22 @@ int rtw89_core_sta_remove(struct rtw89_dev *rtwdev, { struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + int ret; if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_DIS_CONN); - else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) + else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwsta->mac_id); + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + RTW89_ROLE_REMOVE); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c role info\n"); + return ret; + } + } + return 0; } @@ -3113,7 +3140,6 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) continue; INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]); } - INIT_LIST_HEAD(&rtwdev->wow.pkt_list); INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work); INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); @@ -3124,6 +3150,8 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work); INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work); rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!rtwdev->txq_wq) + return -ENOMEM; spin_lock_init(&rtwdev->ba_lock); spin_lock_init(&rtwdev->rpwm_lock); mutex_init(&rtwdev->mutex); @@ -3138,7 +3166,6 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) rtw89_core_ppdu_sts_init(rtwdev); rtw89_traffic_stats_init(rtwdev, &rtwdev->stats); - rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev); rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR; INIT_WORK(&btc->eapol_notify_work, rtw89_btc_ntfy_eapol_packet_work); @@ -3149,6 +3176,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) ret = rtw89_load_firmware(rtwdev); if (ret) { rtw89_warn(rtwdev, "no firmware loaded\n"); + destroy_workqueue(rtwdev->txq_wq); return ret; } rtw89_ser_init(rtwdev); @@ -3293,6 +3321,8 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev) if (ret) return ret; + rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev); + return 0; } EXPORT_SYMBOL(rtw89_chip_info_setup); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2badb96d2ae3..41365ffb7e5e 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -816,6 +816,7 @@ struct rtw89_tx_desc_info { #define RTW89_MGMT_HW_SEQ_MODE 1 bool hiq; u8 port; + bool er_cap; }; struct rtw89_core_tx_request { @@ -1263,6 +1264,7 @@ union rtw89_btc_bt_state_map { #define BTC_BT_RSSI_THMAX 4 #define BTC_BT_AFH_GROUP 12 +#define BTC_BT_AFH_LE_GROUP 5 struct rtw89_btc_bt_link_info { struct rtw89_btc_u8_sta_chg profile_cnt; @@ -1278,6 +1280,7 @@ struct rtw89_btc_bt_link_info { u8 golden_rx_shift[BTC_PROFILE_MAX]; u8 rssi_state[BTC_BT_RSSI_THMAX]; u8 afh_map[BTC_BT_AFH_GROUP]; + u8 afh_map_le[BTC_BT_AFH_LE_GROUP]; u32 role_sw: 1; u32 slave_role: 1; @@ -1437,7 +1440,7 @@ struct rtw89_btc_cx { }; struct rtw89_btc_fbtc_tdma { - u8 type; /* chip_info::fcxtdma_ver */ + u8 type; /* btc_ver::fcxtdma */ u8 rxflctrl; u8 txpause; u8 wtgle_n; @@ -1447,13 +1450,18 @@ struct rtw89_btc_fbtc_tdma { u8 option_ctrl; } __packed; -struct rtw89_btc_fbtc_tdma_v1 { - u8 fver; /* chip_info::fcxtdma_ver */ +struct rtw89_btc_fbtc_tdma_v3 { + u8 fver; /* btc_ver::fcxtdma */ u8 rsvd; __le16 rsvd1; struct rtw89_btc_fbtc_tdma tdma; } __packed; +union rtw89_btc_fbtc_tdma_le32 { + struct rtw89_btc_fbtc_tdma v1; + struct rtw89_btc_fbtc_tdma_v3 v3; +}; + #define CXMREG_MAX 30 #define FCXMAX_STEP 255 /*STEP trace record cnt, Max:65535, default:255*/ #define BTC_CYCLE_SLOT_MAX 48 /* must be even number, non-zero */ @@ -1472,8 +1480,8 @@ enum rtw89_btc_bt_sta_counter { BTC_BCNT_STA_MAX }; -struct rtw89_btc_fbtc_rpt_ctrl { - u16 fver; /* chip_info::fcxbtcrpt_ver */ +struct rtw89_btc_fbtc_rpt_ctrl_v1 { + u16 fver; /* btc_ver::fcxbtcrpt */ u16 rpt_cnt; /* tmr counters */ u32 wl_fw_coex_ver; /* match which driver's coex version */ u32 wl_fw_cx_offload; @@ -1504,6 +1512,20 @@ struct rtw89_btc_fbtc_rpt_ctrl_info { __le32 cnt_aoac_rf_off; /* rf-off counter for aoac switch notify */ } __packed; +struct rtw89_btc_fbtc_rpt_ctrl_info_v5 { + __le32 cx_ver; /* match which driver's coex version */ + __le32 fw_ver; + __le32 en; /* report map */ + + __le16 cnt; /* fw report counter */ + __le16 cnt_c2h; /* fw send c2h counter */ + __le16 cnt_h2c; /* fw recv h2c counter */ + __le16 len_c2h; /* The total length of the last C2H */ + + __le16 cnt_aoac_rf_on; /* rf-on counter for aoac switch notify */ + __le16 cnt_aoac_rf_off; /* rf-off counter for aoac switch notify */ +} __packed; + struct rtw89_btc_fbtc_rpt_ctrl_wl_fw_info { __le32 cx_ver; /* match which driver's coex version */ __le32 cx_offload; @@ -1525,7 +1547,7 @@ struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox { struct rtw89_btc_fbtc_rpt_ctrl_a2dp_empty a2dp; } __packed; -struct rtw89_btc_fbtc_rpt_ctrl_v1 { +struct rtw89_btc_fbtc_rpt_ctrl_v4 { u8 fver; u8 rsvd; __le16 rsvd1; @@ -1536,6 +1558,24 @@ struct rtw89_btc_fbtc_rpt_ctrl_v1 { struct rtw89_mac_ax_gnt gnt_val[RTW89_PHY_MAX]; } __packed; +struct rtw89_btc_fbtc_rpt_ctrl_v5 { + u8 fver; + u8 rsvd; + __le16 rsvd1; + + u8 gnt_val[RTW89_PHY_MAX][4]; + __le16 bt_cnt[BTC_BCNT_STA_MAX]; + + struct rtw89_btc_fbtc_rpt_ctrl_info_v5 rpt_info; + struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox bt_mbx_info; +} __packed; + +union rtw89_btc_fbtc_rpt_ctrl_ver_info { + struct rtw89_btc_fbtc_rpt_ctrl_v1 v1; + struct rtw89_btc_fbtc_rpt_ctrl_v4 v4; + struct rtw89_btc_fbtc_rpt_ctrl_v5 v5; +}; + enum rtw89_fbtc_ext_ctrl_type { CXECTL_OFF = 0x0, /* tdma off */ CXECTL_B2 = 0x1, /* allow B2 (beacon-early) */ @@ -1571,6 +1611,36 @@ enum rtw89_btc_cxst_state { CXST_MAX = 0x12, }; +enum rtw89_btc_cxevnt { + CXEVNT_TDMA_ENTRY = 0x0, + CXEVNT_WL_TMR, + CXEVNT_B1_TMR, + CXEVNT_B2_TMR, + CXEVNT_B3_TMR, + CXEVNT_B4_TMR, + CXEVNT_W2B_TMR, + CXEVNT_B2W_TMR, + CXEVNT_BCN_EARLY, + CXEVNT_A2DP_EMPTY, + CXEVNT_LK_END, + CXEVNT_RX_ISR, + CXEVNT_RX_FC0, + CXEVNT_RX_FC1, + CXEVNT_BT_RELINK, + CXEVNT_BT_RETRY, + CXEVNT_E2G, + CXEVNT_E5G, + CXEVNT_EBT, + CXEVNT_ENULL, + CXEVNT_DRV_WLK, + CXEVNT_BCN_OK, + CXEVNT_BT_CHANGE, + CXEVNT_EBT_EXTEND, + CXEVNT_E2G_NULL1, + CXEVNT_B1FDD_TMR, + CXEVNT_MAX +}; + enum { CXBCN_ALL = 0x0, CXBCN_ALL_OK, @@ -1604,9 +1674,14 @@ enum { /* STEP TYPE */ CXSTEP_MAX, }; +enum rtw89_btc_afh_map_type { /*AFH MAP TYPE */ + RPT_BT_AFH_SEQ_LEGACY = 0x10, + RPT_BT_AFH_SEQ_LE = 0x20 +}; + #define BTC_DBG_MAX1 32 struct rtw89_btc_fbtc_gpio_dbg { - u8 fver; /* chip_info::fcxgpiodbg_ver */ + u8 fver; /* btc_ver::fcxgpiodbg */ u8 rsvd; u16 rsvd2; u32 en_map; /* which debug signal (see btc_wl_gpio_debug) is enable */ @@ -1615,7 +1690,7 @@ struct rtw89_btc_fbtc_gpio_dbg { } __packed; struct rtw89_btc_fbtc_mreg_val { - u8 fver; /* chip_info::fcxmreg_ver */ + u8 fver; /* btc_ver::fcxmreg */ u8 reg_num; __le16 rsvd; __le32 mreg_val[CXMREG_MAX]; @@ -1638,7 +1713,7 @@ struct rtw89_btc_fbtc_slot { } __packed; struct rtw89_btc_fbtc_slots { - u8 fver; /* chip_info::fcxslots_ver */ + u8 fver; /* btc_ver::fcxslots */ u8 tbl_num; __le16 rsvd; __le32 update_map; @@ -1651,8 +1726,8 @@ struct rtw89_btc_fbtc_step { __le16 difft; } __packed; -struct rtw89_btc_fbtc_steps { - u8 fver; /* chip_info::fcxstep_ver */ +struct rtw89_btc_fbtc_steps_v2 { + u8 fver; /* btc_ver::fcxstep */ u8 rsvd; __le16 cnt; __le16 pos_old; @@ -1660,7 +1735,7 @@ struct rtw89_btc_fbtc_steps { struct rtw89_btc_fbtc_step step[FCXMAX_STEP]; } __packed; -struct rtw89_btc_fbtc_steps_v1 { +struct rtw89_btc_fbtc_steps_v3 { u8 fver; u8 en; __le16 rsvd; @@ -1668,8 +1743,13 @@ struct rtw89_btc_fbtc_steps_v1 { struct rtw89_btc_fbtc_step step[FCXMAX_STEP]; } __packed; -struct rtw89_btc_fbtc_cysta { /* statistics for cycles */ - u8 fver; /* chip_info::fcxcysta_ver */ +union rtw89_btc_fbtc_steps_info { + struct rtw89_btc_fbtc_steps_v2 v2; + struct rtw89_btc_fbtc_steps_v3 v3; +}; + +struct rtw89_btc_fbtc_cysta_v2 { /* statistics for cycles */ + u8 fver; /* btc_ver::fcxcysta */ u8 rsvd; __le16 cycles; /* total cycle number */ __le16 cycles_a2dp[CXT_FLCTRL_MAX]; @@ -1717,6 +1797,17 @@ struct rtw89_btc_fbtc_a2dp_trx_stat { u8 rsvd2; } __packed; +struct rtw89_btc_fbtc_a2dp_trx_stat_v4 { + u8 empty_cnt; + u8 retry_cnt; + u8 tx_rate; + u8 tx_cnt; + u8 ack_cnt; + u8 nack_cnt; + u8 no_empty_cnt; + u8 rsvd; +} __packed; + struct rtw89_btc_fbtc_cycle_a2dp_empty_info { __le16 cnt; /* a2dp empty cnt */ __le16 cnt_timeout; /* a2dp empty timeout cnt*/ @@ -1730,7 +1821,35 @@ struct rtw89_btc_fbtc_cycle_leak_info { __le16 tmax; /* max leak-slot time */ } __packed; -struct rtw89_btc_fbtc_cysta_v1 { /* statistics for cycles */ +#define RTW89_BTC_FDDT_PHASE_CYCLE GENMASK(9, 0) +#define RTW89_BTC_FDDT_TRAIN_STEP GENMASK(15, 10) + +struct rtw89_btc_fbtc_cycle_fddt_info { + __le16 train_cycle; + __le16 tp; + + s8 tx_power; /* absolute Tx power (dBm), 0xff-> no BTC control */ + s8 bt_tx_power; /* decrease Tx power (dB) */ + s8 bt_rx_gain; /* LNA constrain level */ + u8 no_empty_cnt; + + u8 rssi; /* [7:4] -> bt_rssi_level, [3:0]-> wl_rssi_level */ + u8 cn; /* condition_num */ + u8 train_status; /* [7:4]-> train-state, [3:0]-> train-phase */ + u8 train_result; /* refer to enum btc_fddt_check_map */ +} __packed; + +#define RTW89_BTC_FDDT_CELL_TRAIN_STATE GENMASK(3, 0) +#define RTW89_BTC_FDDT_CELL_TRAIN_PHASE GENMASK(7, 4) + +struct rtw89_btc_fbtc_fddt_cell_status { + s8 wl_tx_pwr; + s8 bt_tx_pwr; + s8 bt_rx_gain; + u8 state_phase; /* [0:3] train state, [4:7] train phase */ +} __packed; + +struct rtw89_btc_fbtc_cysta_v3 { /* statistics for cycles */ u8 fver; u8 rsvd; __le16 cycles; /* total cycle number */ @@ -1748,8 +1867,41 @@ struct rtw89_btc_fbtc_cysta_v1 { /* statistics for cycles */ __le32 except_map; } __packed; -struct rtw89_btc_fbtc_cynullsta { /* cycle null statistics */ - u8 fver; /* chip_info::fcxnullsta_ver */ +#define FDD_TRAIN_WL_DIRECTION 2 +#define FDD_TRAIN_WL_RSSI_LEVEL 5 +#define FDD_TRAIN_BT_RSSI_LEVEL 5 + +struct rtw89_btc_fbtc_cysta_v4 { /* statistics for cycles */ + u8 fver; + u8 rsvd; + u8 collision_cnt; /* counter for event/timer occur at the same time */ + u8 except_cnt; + + __le16 skip_cnt; + __le16 cycles; /* total cycle number */ + + __le16 slot_step_time[BTC_CYCLE_SLOT_MAX]; /* record the wl/bt slot time */ + __le16 slot_cnt[CXST_MAX]; /* slot count */ + __le16 bcn_cnt[CXBCN_MAX]; + struct rtw89_btc_fbtc_cycle_time_info cycle_time; + struct rtw89_btc_fbtc_cycle_leak_info leak_slot; + struct rtw89_btc_fbtc_cycle_a2dp_empty_info a2dp_ept; + struct rtw89_btc_fbtc_a2dp_trx_stat_v4 a2dp_trx[BTC_CYCLE_SLOT_MAX]; + struct rtw89_btc_fbtc_cycle_fddt_info fddt_trx[BTC_CYCLE_SLOT_MAX]; + struct rtw89_btc_fbtc_fddt_cell_status fddt_cells[FDD_TRAIN_WL_DIRECTION] + [FDD_TRAIN_WL_RSSI_LEVEL] + [FDD_TRAIN_BT_RSSI_LEVEL]; + __le32 except_map; +} __packed; + +union rtw89_btc_fbtc_cysta_info { + struct rtw89_btc_fbtc_cysta_v2 v2; + struct rtw89_btc_fbtc_cysta_v3 v3; + struct rtw89_btc_fbtc_cysta_v4 v4; +}; + +struct rtw89_btc_fbtc_cynullsta_v1 { /* cycle null statistics */ + u8 fver; /* btc_ver::fcxnullsta */ u8 rsvd; __le16 rsvd2; __le32 max_t[2]; /* max_t for 0:null0/1:null1 */ @@ -1757,8 +1909,8 @@ struct rtw89_btc_fbtc_cynullsta { /* cycle null statistics */ __le32 result[2][4]; /* 0:fail, 1:ok, 2:on_time, 3:retry */ } __packed; -struct rtw89_btc_fbtc_cynullsta_v1 { /* cycle null statistics */ - u8 fver; /* chip_info::fcxnullsta_ver */ +struct rtw89_btc_fbtc_cynullsta_v2 { /* cycle null statistics */ + u8 fver; /* btc_ver::fcxnullsta */ u8 rsvd; __le16 rsvd2; __le32 max_t[2]; /* max_t for 0:null0/1:null1 */ @@ -1766,8 +1918,13 @@ struct rtw89_btc_fbtc_cynullsta_v1 { /* cycle null statistics */ __le32 result[2][5]; /* 0:fail, 1:ok, 2:on_time, 3:retry, 4:tx */ } __packed; +union rtw89_btc_fbtc_cynullsta_info { + struct rtw89_btc_fbtc_cynullsta_v1 v1; /* info from fw */ + struct rtw89_btc_fbtc_cynullsta_v2 v2; +}; + struct rtw89_btc_fbtc_btver { - u8 fver; /* chip_info::fcxbtver_ver */ + u8 fver; /* btc_ver::fcxbtver */ u8 rsvd; __le16 rsvd2; __le32 coex_ver; /*bit[15:8]->shared, bit[7:0]->non-shared */ @@ -1776,14 +1933,14 @@ struct rtw89_btc_fbtc_btver { } __packed; struct rtw89_btc_fbtc_btscan { - u8 fver; /* chip_info::fcxbtscan_ver */ + u8 fver; /* btc_ver::fcxbtscan */ u8 rsvd; __le16 rsvd2; u8 scan[6]; } __packed; struct rtw89_btc_fbtc_btafh { - u8 fver; /* chip_info::fcxbtafh_ver */ + u8 fver; /* btc_ver::fcxbtafh */ u8 rsvd; __le16 rsvd2; u8 afh_l[4]; /*bit0:2402, bit1: 2403.... bit31:2433 */ @@ -1791,8 +1948,20 @@ struct rtw89_btc_fbtc_btafh { u8 afh_h[4]; /*bit0:2466, bit1:2467......bit14:2480 */ } __packed; +struct rtw89_btc_fbtc_btafh_v2 { + u8 fver; /* btc_ver::fcxbtafh */ + u8 rsvd; + u8 rsvd2; + u8 map_type; + u8 afh_l[4]; + u8 afh_m[4]; + u8 afh_h[4]; + u8 afh_le_a[4]; + u8 afh_le_b[4]; +} __packed; + struct rtw89_btc_fbtc_btdevinfo { - u8 fver; /* chip_info::fcxbtdevinfo_ver */ + u8 fver; /* btc_ver::fcxbtdevinfo */ u8 rsvd; __le16 vendor_id; __le32 dev_name; /* only 24 bits valid */ @@ -1911,20 +2080,19 @@ struct rtw89_btc_rpt_cmn_info { u8 valid; } __packed; +union rtw89_btc_fbtc_btafh_info { + struct rtw89_btc_fbtc_btafh v1; + struct rtw89_btc_fbtc_btafh_v2 v2; +}; + struct rtw89_btc_report_ctrl_state { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_rpt_ctrl finfo; /* info from fw for 52A*/ - struct rtw89_btc_fbtc_rpt_ctrl_v1 finfo_v1; /* info from fw for 52C*/ - }; + union rtw89_btc_fbtc_rpt_ctrl_ver_info finfo; }; struct rtw89_btc_rpt_fbtc_tdma { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_tdma finfo; /* info from fw */ - struct rtw89_btc_fbtc_tdma_v1 finfo_v1; /* info from fw for 52C*/ - }; + union rtw89_btc_fbtc_tdma_le32 finfo; }; struct rtw89_btc_rpt_fbtc_slots { @@ -1934,26 +2102,17 @@ struct rtw89_btc_rpt_fbtc_slots { struct rtw89_btc_rpt_fbtc_cysta { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_cysta finfo; /* info from fw for 52A*/ - struct rtw89_btc_fbtc_cysta_v1 finfo_v1; /* info from fw for 52C*/ - }; + union rtw89_btc_fbtc_cysta_info finfo; }; struct rtw89_btc_rpt_fbtc_step { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_steps finfo; /* info from fw */ - struct rtw89_btc_fbtc_steps_v1 finfo_v1; /* info from fw */ - }; + union rtw89_btc_fbtc_steps_info finfo; /* info from fw */ }; struct rtw89_btc_rpt_fbtc_nullsta { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - union { - struct rtw89_btc_fbtc_cynullsta finfo; /* info from fw */ - struct rtw89_btc_fbtc_cynullsta_v1 finfo_v1; /* info from fw */ - }; + union rtw89_btc_fbtc_cynullsta_info finfo; }; struct rtw89_btc_rpt_fbtc_mreg { @@ -1978,7 +2137,7 @@ struct rtw89_btc_rpt_fbtc_btscan { struct rtw89_btc_rpt_fbtc_btafh { struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */ - struct rtw89_btc_fbtc_btafh finfo; /* info from fw */ + union rtw89_btc_fbtc_btafh_info finfo; }; struct rtw89_btc_rpt_fbtc_btdev { @@ -2018,9 +2177,35 @@ struct rtw89_btc_btf_fwinfo { struct rtw89_btc_rpt_fbtc_btdev rpt_fbtc_btdev; }; +struct rtw89_btc_ver { + enum rtw89_core_chip_id chip_id; + u32 fw_ver_code; + + u8 fcxbtcrpt; + u8 fcxtdma; + u8 fcxslots; + u8 fcxcysta; + u8 fcxstep; + u8 fcxnullsta; + u8 fcxmreg; + u8 fcxgpiodbg; + u8 fcxbtver; + u8 fcxbtscan; + u8 fcxbtafh; + u8 fcxbtdevinfo; + u8 fwlrole; + u8 frptmap; + u8 fcxctrl; + + u16 info_buf; + u8 max_role_num; +}; + #define RTW89_BTC_POLICY_MAXLEN 512 struct rtw89_btc { + const struct rtw89_btc_ver *ver; + struct rtw89_btc_cx cx; struct rtw89_btc_dm dm; struct rtw89_btc_ctrl ctrl; @@ -2194,6 +2379,7 @@ struct rtw89_sec_cam_entry { struct rtw89_sta { u8 mac_id; bool disassoc; + bool er_cap; struct rtw89_dev *rtwdev; struct rtw89_vif *rtwvif; struct rtw89_ra_info ra; @@ -2266,6 +2452,7 @@ struct rtw89_vif { bool last_a_ctrl; bool dyn_tb_bedge_en; u8 def_tri_idx; + u32 tdls_peer; struct work_struct update_beacon_work; struct rtw89_addr_cam_entry addr_cam; struct rtw89_bssid_cam_entry bssid_cam; @@ -2274,6 +2461,7 @@ struct rtw89_vif { struct rtw89_phy_rate_pattern rate_pattern; struct cfg80211_scan_request *scan_req; struct ieee80211_scan_ies *scan_ies; + struct list_head general_pkt_list; }; enum rtw89_lv1_rcvy_step { @@ -2660,6 +2848,7 @@ struct rtw89_chip_info { enum rtw89_core_chip_id chip_id; const struct rtw89_chip_ops *ops; const char *fw_name; + bool try_ce_fw; u32 fifo_size; u32 dle_scc_rsvd_size; u16 max_amsdu_limit; @@ -2728,20 +2917,6 @@ struct rtw89_chip_info { u8 btcx_desired; u8 scbd; u8 mailbox; - u16 btc_fwinfo_buf; - - u8 fcxbtcrpt_ver; - u8 fcxtdma_ver; - u8 fcxslots_ver; - u8 fcxcysta_ver; - u8 fcxstep_ver; - u8 fcxnullsta_ver; - u8 fcxmreg_ver; - u8 fcxgpiodbg_ver; - u8 fcxbtver_ver; - u8 fcxbtscan_ver; - u8 fcxbtafh_ver; - u8 fcxbtdevinfo_ver; u8 afh_guard_ch; const u8 *wl_rssi_thres; @@ -2771,6 +2946,7 @@ struct rtw89_chip_info { u8 dcfo_comp_sft; const struct rtw89_imr_info *imr_info; const struct rtw89_rrsr_cfgs *rrsr_cfgs; + u32 bss_clr_map_reg; u32 dma_ch_mask; const struct wiphy_wowlan_support *wowlan_stub; }; @@ -2839,6 +3015,7 @@ static inline void rtw89_init_wait(struct rtw89_wait_info *wait) enum rtw89_fw_type { RTW89_FW_NORMAL = 1, RTW89_FW_WOWLAN = 3, + RTW89_FW_NORMAL_CE = 5, }; enum rtw89_fw_feature { @@ -2848,6 +3025,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_CRASH_TRIGGER, RTW89_FW_FEATURE_PACKET_DROP, RTW89_FW_FEATURE_NO_DEEP_PS, + RTW89_FW_FEATURE_NO_LPS_PG, }; struct rtw89_fw_suit { @@ -3550,7 +3728,6 @@ struct rtw89_wow_param { DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM); struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM]; u8 pattern_cnt; - struct list_head pkt_list; }; struct rtw89_mcc_info { diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 8297e35bfa52..0e0e1483c099 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -615,6 +615,7 @@ rtw89_debug_priv_mac_reg_dump_select(struct file *filp, struct seq_file *m = (struct seq_file *)filp->private_data; struct rtw89_debugfs_priv *debugfs_priv = m->private; struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + const struct rtw89_chip_info *chip = rtwdev->chip; char buf[32]; size_t buf_size; int sel; @@ -634,6 +635,12 @@ rtw89_debug_priv_mac_reg_dump_select(struct file *filp, return -EINVAL; } + if (sel == RTW89_DBG_SEL_MAC_30 && chip->chip_id != RTL8852C) { + rtw89_info(rtwdev, "sel %d is address hole on chip %d\n", sel, + chip->chip_id); + return -EINVAL; + } + debugfs_priv->cb_data = sel; rtw89_info(rtwdev, "select mac page dump %d\n", debugfs_priv->cb_data); @@ -3347,6 +3354,31 @@ static void rtw89_dump_addr_cam(struct seq_file *m, } } +__printf(3, 4) +static void rtw89_dump_pkt_offload(struct seq_file *m, struct list_head *pkt_list, + const char *fmt, ...) +{ + struct rtw89_pktofld_info *info; + struct va_format vaf; + va_list args; + + if (list_empty(pkt_list)) + return; + + va_start(args, fmt); + vaf.va = &args; + vaf.fmt = fmt; + + seq_printf(m, "%pV", &vaf); + + va_end(args); + + list_for_each_entry(info, pkt_list, list) + seq_printf(m, "%d ", info->id); + + seq_puts(m, "\n"); +} + static void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -3357,6 +3389,7 @@ void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif) seq_printf(m, "VIF [%d] %pM\n", rtwvif->mac_id, rtwvif->mac_addr); seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx); rtw89_dump_addr_cam(m, &rtwvif->addr_cam); + rtw89_dump_pkt_offload(m, &rtwvif->general_pkt_list, "\tpkt_ofld[GENERAL]: "); } static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta) @@ -3395,6 +3428,7 @@ static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v) struct rtw89_debugfs_priv *debugfs_priv = m->private; struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; struct rtw89_cam_info *cam_info = &rtwdev->cam_info; + u8 idx; mutex_lock(&rtwdev->mutex); @@ -3409,6 +3443,15 @@ static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v) cam_info->sec_cam_map); seq_printf(m, "\tba_cam: %*ph\n", (int)sizeof(cam_info->ba_cam_map), cam_info->ba_cam_map); + seq_printf(m, "\tpkt_ofld: %*ph\n", (int)sizeof(rtwdev->pkt_offload), + rtwdev->pkt_offload); + + for (idx = NL80211_BAND_2GHZ; idx < NUM_NL80211_BANDS; idx++) { + if (!(rtwdev->chip->support_bands & BIT(idx))) + continue; + rtw89_dump_pkt_offload(m, &rtwdev->scan_info.pkt_list[idx], + "\t\t[SCAN %u]: ", idx); + } ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, IEEE80211_IFACE_ITER_NORMAL, rtw89_vif_ids_get_iter, m); diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index d1de5e600836..079269bb5251 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -28,6 +28,7 @@ enum rtw89_debug_mask { RTW89_DBG_STATE = BIT(17), RTW89_DBG_WOW = BIT(18), RTW89_DBG_UL_TB = BIT(19), + RTW89_DBG_CHAN = BIT(20), RTW89_DBG_UNEXP = BIT(31), }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index de1f23779fc6..0b73dc2e9ad7 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -10,6 +10,7 @@ #include "mac.h" #include "phy.h" #include "reg.h" +#include "util.h" static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb); @@ -91,6 +92,7 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, const u8 *fwdynhdr; const u8 *bin; u32 base_hdr_len; + u32 mssc_len = 0; u32 i; if (!info) @@ -120,6 +122,14 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, fw += RTW89_FW_HDR_SIZE; section_info = info->section_info; for (i = 0; i < info->section_num; i++) { + section_info->type = GET_FWSECTION_HDR_SECTIONTYPE(fw); + if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { + section_info->mssc = GET_FWSECTION_HDR_MSSC(fw); + mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; + } else { + section_info->mssc = 0; + } + section_info->len = GET_FWSECTION_HDR_SEC_SIZE(fw); if (GET_FWSECTION_HDR_CHECKSUM(fw)) section_info->len += FWDL_SECTION_CHKSUM_LEN; @@ -132,7 +142,7 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, section_info++; } - if (fw_end != bin) { + if (fw_end != bin + mssc_len) { rtw89_err(rtwdev, "[ERR]fw bin size\n"); return -EINVAL; } @@ -142,7 +152,7 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, static int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, - struct rtw89_fw_suit *fw_suit) + struct rtw89_fw_suit *fw_suit, bool nowarn) { struct rtw89_fw_info *fw_info = &rtwdev->fw; const u8 *mfw = fw_info->firmware->data; @@ -173,7 +183,8 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, return 0; } - rtw89_err(rtwdev, "no suitable firmware found\n"); + if (!nowarn) + rtw89_err(rtwdev, "no suitable firmware found\n"); return -ENOENT; } @@ -201,12 +212,13 @@ static void rtw89_fw_update_ver(struct rtw89_dev *rtwdev, } static -int __rtw89_fw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type) +int __rtw89_fw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, + bool nowarn) { struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type); int ret; - ret = rtw89_mfw_recognize(rtwdev, type, fw_suit); + ret = rtw89_mfw_recognize(rtwdev, type, fw_suit, nowarn); if (ret) return ret; @@ -245,6 +257,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 38, 0, PACKET_DROP), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 20, 0, PACKET_DROP), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), @@ -332,17 +345,27 @@ out: int rtw89_fw_recognize(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; int ret; - ret = __rtw89_fw_recognize(rtwdev, RTW89_FW_NORMAL); + if (chip->try_ce_fw) { + ret = __rtw89_fw_recognize(rtwdev, RTW89_FW_NORMAL_CE, true); + if (!ret) + goto normal_done; + } + + ret = __rtw89_fw_recognize(rtwdev, RTW89_FW_NORMAL, false); if (ret) return ret; +normal_done: /* It still works if wowlan firmware isn't existing. */ - __rtw89_fw_recognize(rtwdev, RTW89_FW_WOWLAN); + __rtw89_fw_recognize(rtwdev, RTW89_FW_WOWLAN, false); rtw89_fw_recognize_features(rtwdev); + rtw89_coex_recognize_ver(rtwdev); + return 0; } @@ -902,13 +925,12 @@ fail: return ret; } -static int rtw89_fw_h2c_add_wow_fw_ofld(struct rtw89_dev *rtwdev, +static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, enum rtw89_fw_pkt_ofld_type type, u8 *id) { struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_pktofld_info *info; struct sk_buff *skb; int ret; @@ -937,13 +959,13 @@ static int rtw89_fw_h2c_add_wow_fw_ofld(struct rtw89_dev *rtwdev, if (!skb) goto err; - list_add_tail(&info->list, &rtw_wow->pkt_list); ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, skb); kfree_skb(skb); if (ret) - return ret; + goto err; + list_add_tail(&info->list, &rtwvif->general_pkt_list); *id = info->id; return 0; @@ -952,13 +974,48 @@ err: return -ENOMEM; } +void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool notify_fw) +{ + struct list_head *pkt_list = &rtwvif->general_pkt_list; + struct rtw89_pktofld_info *info, *tmp; + + list_for_each_entry_safe(info, tmp, pkt_list, list) { + if (notify_fw) + rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); + rtw89_core_release_bit_map(rtwdev->pkt_offload, + info->id); + list_del(&info->list); + kfree(info); + } +} + +void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw) +{ + struct rtw89_vif *rtwvif; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) + rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, notify_fw); +} + #define H2C_GENERAL_PKT_LEN 6 #define H2C_GENERAL_PKT_ID_UND 0xff -int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid) +int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, u8 macid) { + u8 pkt_id_ps_poll = H2C_GENERAL_PKT_ID_UND; + u8 pkt_id_null = H2C_GENERAL_PKT_ID_UND; + u8 pkt_id_qos_null = H2C_GENERAL_PKT_ID_UND; struct sk_buff *skb; int ret; + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + RTW89_PKT_OFLD_TYPE_PS_POLL, &pkt_id_ps_poll); + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id_null); + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + RTW89_PKT_OFLD_TYPE_QOS_NULL, &pkt_id_qos_null); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_GENERAL_PKT_LEN); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); @@ -967,9 +1024,9 @@ int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid) skb_put(skb, H2C_GENERAL_PKT_LEN); SET_GENERAL_PKT_MACID(skb->data, macid); SET_GENERAL_PKT_PROBRSP_ID(skb->data, H2C_GENERAL_PKT_ID_UND); - SET_GENERAL_PKT_PSPOLL_ID(skb->data, H2C_GENERAL_PKT_ID_UND); - SET_GENERAL_PKT_NULL_ID(skb->data, H2C_GENERAL_PKT_ID_UND); - SET_GENERAL_PKT_QOS_NULL_ID(skb->data, H2C_GENERAL_PKT_ID_UND); + SET_GENERAL_PKT_PSPOLL_ID(skb->data, pkt_id_ps_poll); + SET_GENERAL_PKT_NULL_ID(skb->data, pkt_id_null); + SET_GENERAL_PKT_QOS_NULL_ID(skb->data, pkt_id_qos_null); SET_GENERAL_PKT_CTS2SELF_ID(skb->data, H2C_GENERAL_PKT_ID_UND); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -1807,33 +1864,36 @@ fail: #define PORT_DATA_OFFSET 4 #define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12 -#define H2C_LEN_CXDRVINFO_ROLE (4 + 12 * RTW89_PORT_NUM + H2C_LEN_CXDRVHDR) -#define H2C_LEN_CXDRVINFO_ROLE_V1 (4 + 16 * RTW89_PORT_NUM + \ - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + \ - H2C_LEN_CXDRVHDR) +#define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \ + (4 + 12 * (max_role_num) + H2C_LEN_CXDRVHDR) + int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info *role_info = &wl->role_info; struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; struct rtw89_btc_wl_active_role *active = role_info->active_role; struct sk_buff *skb; + u32 len; u8 offset = 0; u8 *cmd; int ret; int i; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_ROLE); + len = H2C_LEN_CXDRVINFO_ROLE_SIZE(ver->max_role_num); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); return -ENOMEM; } - skb_put(skb, H2C_LEN_CXDRVINFO_ROLE); + skb_put(skb, len); cmd = skb->data; RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); - RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_ROLE - H2C_LEN_CXDRVHDR); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); @@ -1870,7 +1930,7 @@ int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, BTFC_SET, SET_DRV_INFO, 0, 0, - H2C_LEN_CXDRVINFO_ROLE); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -1885,28 +1945,35 @@ fail: return ret; } +#define H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(max_role_num) \ + (4 + 16 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR) + int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info_v1 *role_info = &wl->role_info_v1; struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; struct rtw89_btc_wl_active_role_v1 *active = role_info->active_role_v1; struct sk_buff *skb; + u32 len; u8 *cmd, offset; int ret; int i; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_ROLE_V1); + len = H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(ver->max_role_num); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); return -ENOMEM; } - skb_put(skb, H2C_LEN_CXDRVINFO_ROLE_V1); + skb_put(skb, len); cmd = skb->data; RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); - RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_ROLE_V1 - H2C_LEN_CXDRVHDR); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR); RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); @@ -1942,7 +2009,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) RTW89_SET_FWCMD_CXROLE_ACT_NOA_DUR(cmd, active->noa_duration, i, offset); } - offset = H2C_LEN_CXDRVINFO_ROLE_V1 - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN; + offset = len - H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN; RTW89_SET_FWCMD_CXROLE_MROLE_TYPE(cmd, role_info->mrole_type, offset); RTW89_SET_FWCMD_CXROLE_MROLE_NOA(cmd, role_info->mrole_noa_duration, offset); RTW89_SET_FWCMD_CXROLE_DBCC_EN(cmd, role_info->dbcc_en, offset); @@ -1953,7 +2020,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev) rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, BTFC_SET, SET_DRV_INFO, 0, 0, - H2C_LEN_CXDRVINFO_ROLE_V1); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -1971,8 +2038,8 @@ fail: #define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR) int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_ctrl *ctrl = &btc->ctrl; struct sk_buff *skb; u8 *cmd; @@ -1992,7 +2059,7 @@ int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, ctrl->manual); RTW89_SET_FWCMD_CXCTRL_IGNORE_BT(cmd, ctrl->igno_bt); RTW89_SET_FWCMD_CXCTRL_ALWAYS_FREERUN(cmd, ctrl->always_freerun); - if (chip->chip_id == RTL8852A) + if (ver->fcxctrl == 0) RTW89_SET_FWCMD_CXCTRL_TRACE_STEP(cmd, ctrl->trace_step); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -2112,6 +2179,7 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_PKT_OFLD + skb_ofld->len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c pkt offload\n"); + rtw89_core_release_bit_map(rtwdev->pkt_offload, alloc_id); return -ENOMEM; } skb_put(skb, H2C_LEN_PKT_OFLD); @@ -2130,6 +2198,7 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { rtw89_err(rtwdev, "failed to send h2c\n"); + rtw89_core_release_bit_map(rtwdev->pkt_offload, alloc_id); goto fail; } @@ -2663,11 +2732,14 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, goto out; } - list_add_tail(&info->list, &scan_info->pkt_list[band]); ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new); - if (ret) + if (ret) { + kfree_skb(new); + kfree(info); goto out; + } + list_add_tail(&info->list, &scan_info->pkt_list[band]); kfree_skb(new); } out: @@ -2738,7 +2810,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, if (ssid_num == 1 && req->ssids[0].ssid_len == 0) { ch_info->tx_pkt = false; if (!req->duration_mandatory) - ch_info->period -= RTW89_DWELL_TIME; + ch_info->period -= RTW89_DWELL_TIME_6G; } } @@ -2791,7 +2863,8 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, if (req->duration_mandatory) ch_info->period = req->duration; else if (channel->band == NL80211_BAND_6GHZ) - ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME; + ch_info->period = RTW89_CHANNEL_TIME_6G + + RTW89_DWELL_TIME_6G; else ch_info->period = RTW89_CHANNEL_TIME; @@ -3072,8 +3145,9 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, int ret; if (enable) { - ret = rtw89_fw_h2c_add_wow_fw_ofld(rtwdev, rtwvif, - RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id); + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + RTW89_PKT_OFLD_TYPE_NULL_DATA, + &pkt_id); if (ret) return -EPERM; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 4d2f9ea9e002..cae07e325326 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -171,6 +171,8 @@ struct rtw89_fw_hdr_section_info { const u8 *addr; u32 len; u32 dladdr; + u32 mssc; + u8 type; }; struct rtw89_fw_bin_info { @@ -203,6 +205,7 @@ struct rtw89_h2creg_sch_tx_en { #define RTW89_DFS_CHAN_TIME 105 #define RTW89_OFF_CHAN_TIME 100 #define RTW89_DWELL_TIME 20 +#define RTW89_DWELL_TIME_6G 10 #define RTW89_SCAN_WIDTH 0 #define RTW89_SCANOFLD_MAX_SSID 8 #define RTW89_SCANOFLD_MAX_IE_LEN 512 @@ -480,14 +483,21 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) #define FW_EDCA_PARAM_CWMIN_MSK GENMASK(11, 8) #define FW_EDCA_PARAM_AIFS_MSK GENMASK(7, 0) +#define FWDL_SECURITY_SECTION_TYPE 9 +#define FWDL_SECURITY_SIGLEN 512 + +#define GET_FWSECTION_HDR_DL_ADDR(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr)), GENMASK(31, 0)) +#define GET_FWSECTION_HDR_SECTIONTYPE(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(27, 24)) #define GET_FWSECTION_HDR_SEC_SIZE(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 0)) #define GET_FWSECTION_HDR_CHECKSUM(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(28)) #define GET_FWSECTION_HDR_REDL(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(29)) -#define GET_FWSECTION_HDR_DL_ADDR(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr)), GENMASK(31, 0)) +#define GET_FWSECTION_HDR_MSSC(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 2), GENMASK(31, 0)) #define GET_FW_HDR_MAJOR_VERSION(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(7, 0)) @@ -3209,16 +3219,16 @@ static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb) le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(25, 24)) #define RTW89_GET_MAC_C2H_MCC_RCV_ACK_GROUP(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(1, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) #define RTW89_GET_MAC_C2H_MCC_RCV_ACK_H2C_FUNC(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 8)) #define RTW89_GET_MAC_C2H_MCC_REQ_ACK_GROUP(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(1, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) #define RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_RETURN(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 2)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 2)) #define RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_FUNC(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 8)) struct rtw89_mac_mcc_tsf_rpt { u32 macid_x; @@ -3232,30 +3242,30 @@ struct rtw89_mac_mcc_tsf_rpt { static_assert(sizeof(struct rtw89_mac_mcc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE); #define RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_X(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 0)) #define RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_Y(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 8)) #define RTW89_GET_MAC_C2H_MCC_TSF_RPT_GROUP(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(17, 16)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(17, 16)) #define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_X(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(31, 0)) #define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_X(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0)) #define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_Y(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(31, 0)) #define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_Y(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 6), GENMASK(31, 0)) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_STATUS(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(5, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(5, 0)) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_GROUP(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 6)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 6)) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_MACID(c2h) \ - le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 8)) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_LOW(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(31, 0)) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0)) #define RTW89_FW_HDR_SIZE 32 #define RTW89_FW_SECTION_HDR_SIZE 16 @@ -3508,7 +3518,11 @@ int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_raw(struct rtw89_dev *rtwdev, const u8 *buf, u16 len); void rtw89_fw_send_all_early_h2c(struct rtw89_dev *rtwdev); void rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid); +int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + u8 macid); +void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool notify_fw); +void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw); int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params); void rtw89_fw_h2c_init_ba_cam_v1(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index cf9a0a3120a7..2e2a2b6eab09 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -623,7 +623,8 @@ static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, if (err != MAC_AX_ERR_L1_ERR_DMAC && err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && err != MAC_AX_ERR_L0_ERR_CMAC0 && - err != MAC_AX_ERR_L0_ERR_CMAC1) + err != MAC_AX_ERR_L0_ERR_CMAC1 && + err != MAC_AX_ERR_RXI300) return; rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); @@ -663,6 +664,8 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) err = MAC_AX_ERR_CPU_EXCEPTION; else if (err_scnr == RTW89_WCPU_ASSERTION) err = MAC_AX_ERR_ASSERTION; + else if (err_scnr == RTW89_RXI300_ERROR) + err = MAC_AX_ERR_RXI300; rtw89_fw_st_dbg_dump(rtwdev); rtw89_mac_dump_err_status(rtwdev, err); @@ -3411,6 +3414,11 @@ int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw) val |= B_AX_WCPU_FWDL_EN; rtw89_write32(rtwdev, R_AX_WCPU_FW_CTRL, val); + + if (rtwdev->chip->chip_id == RTL8852B) + rtw89_write32_mask(rtwdev, R_AX_SEC_CTRL, + B_AX_SEC_IDMEM_SIZE_CONFIG_MASK, 0x2); + rtw89_write16_mask(rtwdev, R_AX_BOOT_REASON, B_AX_BOOT_REASON_MASK, boot_reason); rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_WCPU_EN); @@ -3918,19 +3926,14 @@ static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev, B_AX_TBTT_SHIFT_OFST_MASK, val); } -static void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_vif *rtwvif_src, u8 offset, - int *n_offset) +void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_vif *rtwvif_src, + u16 offset_tu) { u32 val, reg; - if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif == rtwvif_src) - return; - - /* adjust offset randomly to avoid beacon conflict */ - offset = offset - offset / 4 + get_random_u32() % (offset / 2); - val = RTW89_PORT_OFFSET_MS_TO_32US((*n_offset)++, offset); + val = RTW89_PORT_OFFSET_TU_TO_32US(offset_tu); reg = rtw89_mac_reg_by_idx(R_AX_PORT0_TSF_SYNC + rtwvif->port * 4, rtwvif->mac_idx); @@ -3939,6 +3942,22 @@ static void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, rtw89_write32_set(rtwdev, reg, B_AX_SYNC_NOW); } +static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_vif *rtwvif_src, + u8 offset, int *n_offset) +{ + if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif == rtwvif_src) + return; + + /* adjust offset randomly to avoid beacon conflict */ + offset = offset - offset / 4 + get_random_u32() % (offset / 2); + rtw89_mac_port_tsf_sync(rtwdev, rtwvif, rtwvif_src, + (*n_offset) * offset); + + (*n_offset)++; +} + static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev) { struct rtw89_vif *src = NULL, *tmp; @@ -3958,7 +3977,7 @@ static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev) offset /= (vif_aps + 1); rtw89_for_each_rtwvif(rtwdev, tmp) - rtw89_mac_port_tsf_sync(rtwdev, tmp, src, offset, &n_offset); + rtw89_mac_port_tsf_sync_rand(rtwdev, tmp, src, offset, &n_offset); } int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) @@ -4050,6 +4069,24 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) return 0; } +int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + u64 *tsf) +{ + const struct rtw89_port_reg *p = &rtw_port_base; + u32 tsf_low, tsf_high; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, rtwvif->mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + tsf_low = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_l); + tsf_high = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_h); + *tsf = (u64)tsf_high << 32 | tsf_low; + + return 0; +} + static void rtw89_mac_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, struct cfg80211_bss *bss, void *data) @@ -4263,12 +4300,12 @@ rtw89_mac_c2h_mcc_rcv_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len case H2C_FUNC_MCC_SET_DURATION: break; default: - rtw89_debug(rtwdev, RTW89_DBG_FW, + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "invalid MCC C2H RCV ACK: func %d\n", func); return; } - rtw89_debug(rtwdev, RTW89_DBG_FW, + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC C2H RCV ACK: group %d, func %d\n", group, func); } @@ -4296,12 +4333,12 @@ rtw89_mac_c2h_mcc_req_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len case H2C_FUNC_DEL_MCC_GROUP: case H2C_FUNC_RESET_MCC_GROUP: default: - rtw89_debug(rtwdev, RTW89_DBG_FW, + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "invalid MCC C2H REQ ACK: func %d\n", func); return; } - rtw89_debug(rtwdev, RTW89_DBG_FW, + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC C2H REQ ACK: group %d, func %d, return code %d\n", group, func, retcode); @@ -4329,6 +4366,11 @@ rtw89_mac_c2h_mcc_tsf_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len rpt->tsf_y_low = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_Y(c2h->data); rpt->tsf_y_high = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_Y(c2h->data); + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC C2H TSF RPT: macid %d> %llu, macid %d> %llu\n", + rpt->macid_x, (u64)rpt->tsf_x_high << 32 | rpt->tsf_x_low, + rpt->macid_y, (u64)rpt->tsf_y_high << 32 | rpt->tsf_y_low); + cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_REQ_TSF); rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data); } @@ -4386,14 +4428,14 @@ rtw89_mac_c2h_mcc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 rsp = false; break; default: - rtw89_debug(rtwdev, RTW89_DBG_FW, + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "invalid MCC C2H STS RPT: status %d\n", status); return; } - rtw89_debug(rtwdev, RTW89_DBG_FW, - "MCC C2H STS RPT: group %d, macid %d, status %d, tsf {%d, %d}\n", - group, macid, status, tsf_low, tsf_high); + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC C2H STS RPT: group %d, macid %d, status %d, tsf %llu\n", + group, macid, status, (u64)tsf_high << 32 | tsf_low); if (!rsp) return; @@ -4512,7 +4554,7 @@ EXPORT_SYMBOL(rtw89_mac_get_txpwr_cr); int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) { u32 reg = rtw89_mac_reg_by_idx(R_AX_PPDU_STAT, mac_idx); - int ret = 0; + int ret; ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) @@ -4520,7 +4562,7 @@ int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) if (!enable) { rtw89_write32_clr(rtwdev, reg, B_AX_PPDU_STAT_RPT_EN); - return ret; + return 0; } rtw89_write32(rtwdev, reg, B_AX_PPDU_STAT_RPT_EN | @@ -4530,7 +4572,7 @@ int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) rtw89_write32_mask(rtwdev, R_AX_HW_RPT_FWD, B_AX_FWD_PPDU_STAT_MASK, RTW89_PRPT_DEST_HOST); - return ret; + return 0; } EXPORT_SYMBOL(rtw89_mac_cfg_ppdu_status); @@ -4865,9 +4907,16 @@ EXPORT_SYMBOL(rtw89_mac_cfg_ctrl_path_v1); bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev) { - u8 val = rtw89_read8(rtwdev, R_AX_SYS_SDIO_CTRL + 3); + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 val = 0; + + if (chip->chip_id == RTL8852C) + return false; + else if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B) + val = rtw89_read8_mask(rtwdev, R_AX_SYS_SDIO_CTRL + 3, + B_AX_LTE_MUX_CTRL_PATH >> 24); - return FIELD_GET(B_AX_LTE_MUX_CTRL_PATH >> 24, val); + return !!val; } u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band) diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index f0b684b205f1..8064d3953d7f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -168,7 +168,7 @@ enum rtw89_mac_ax_l0_to_l1_event { MAC_AX_L0_TO_L1_EVENT_MAX = 15, }; -#define RTW89_PORT_OFFSET_MS_TO_32US(n, shift_ms) ((n) * (shift_ms) * 1000 / 32) +#define RTW89_PORT_OFFSET_TU_TO_32US(shift_tu) ((shift_tu) * 1024 / 32) enum rtw89_mac_dbg_port_sel { /* CMAC 0 related */ @@ -623,6 +623,7 @@ struct rtw89_mac_dle_dfi_qempty { }; enum rtw89_mac_error_scenario { + RTW89_RXI300_ERROR = 1, RTW89_WCPU_CPU_EXCEPTION = 2, RTW89_WCPU_ASSERTION = 3, }; @@ -769,6 +770,7 @@ enum mac_ax_err_info { MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT = 0x2599, MAC_AX_ERR_CPU_EXCEPTION = 0x3000, MAC_AX_ERR_ASSERTION = 0x4000, + MAC_AX_ERR_RXI300 = 0x5000, MAC_AX_GET_ERR_MAX, MAC_AX_DUMP_SHAREBUFF_INDICATOR = 0x80000000, @@ -828,6 +830,15 @@ static inline u32 rtw89_mac_reg_by_port(u32 base, u8 port, u8 mac_idx) } static inline u32 +rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base) +{ + u32 reg; + + reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx); + return rtw89_read32(rtwdev, reg); +} + +static inline u32 rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base, u32 mask) { @@ -906,6 +917,12 @@ int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val); int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val); int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_vif *rtwvif_src, + u16 offset_tu); +int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + u64 *tsf); void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index f9b95c52916b..d43281f7335b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -135,6 +135,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; rtwvif->hit_rule = 0; ether_addr_copy(rtwvif->mac_addr, vif->addr); + INIT_LIST_HEAD(&rtwvif->general_pkt_list); ret = rtw89_mac_add_vif(rtwdev, rtwvif); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 1c4500ba777c..ec8bb5f10482 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1384,7 +1384,7 @@ static int rtw89_pci_ops_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx return 0; } -static const struct rtw89_pci_bd_ram bd_ram_table[RTW89_TXCH_NUM] = { +const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM] = { [RTW89_TXCH_ACH0] = {.start_idx = 0, .max_num = 5, .min_num = 2}, [RTW89_TXCH_ACH1] = {.start_idx = 5, .max_num = 5, .min_num = 2}, [RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2}, @@ -1399,11 +1399,24 @@ static const struct rtw89_pci_bd_ram bd_ram_table[RTW89_TXCH_NUM] = { [RTW89_TXCH_CH11] = {.start_idx = 55, .max_num = 5, .min_num = 1}, [RTW89_TXCH_CH12] = {.start_idx = 60, .max_num = 4, .min_num = 1}, }; +EXPORT_SYMBOL(rtw89_bd_ram_table_dual); + +const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM] = { + [RTW89_TXCH_ACH0] = {.start_idx = 0, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_ACH1] = {.start_idx = 5, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_ACH2] = {.start_idx = 10, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_ACH3] = {.start_idx = 15, .max_num = 5, .min_num = 2}, + [RTW89_TXCH_CH8] = {.start_idx = 20, .max_num = 4, .min_num = 1}, + [RTW89_TXCH_CH9] = {.start_idx = 24, .max_num = 4, .min_num = 1}, + [RTW89_TXCH_CH12] = {.start_idx = 28, .max_num = 4, .min_num = 1}, +}; +EXPORT_SYMBOL(rtw89_bd_ram_table_single); static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_bd_ram *bd_ram_table = *info->bd_ram_table; struct rtw89_pci_tx_ring *tx_ring; struct rtw89_pci_rx_ring *rx_ring; struct rtw89_pci_dma_ring *bd_ring; @@ -3385,7 +3398,7 @@ static void rtw89_pci_clkreq_set(struct rtw89_dev *rtwdev, bool enable) if (ret) rtw89_err(rtwdev, "failed to set CLKREQ Delay\n"); - if (chip_id == RTL8852A) { + if (chip_id == RTL8852A || chip_id == RTL8852B) { if (enable) ret = rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 7d033501d4d9..1e19740db8c5 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -750,6 +750,12 @@ struct rtw89_pci_ch_dma_addr_set { struct rtw89_pci_ch_dma_addr rx[RTW89_RXCH_NUM]; }; +struct rtw89_pci_bd_ram { + u8 start_idx; + u8 max_num; + u8 min_num; +}; + struct rtw89_pci_info { enum mac_ax_bd_trunc_mode txbd_trunc_mode; enum mac_ax_bd_trunc_mode rxbd_trunc_mode; @@ -785,6 +791,7 @@ struct rtw89_pci_info { u32 tx_dma_ch_mask; const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power; const struct rtw89_pci_ch_dma_addr_set *dma_addr_set; + const struct rtw89_pci_bd_ram (*bd_ram_table)[RTW89_TXCH_NUM]; int (*ltr_set)(struct rtw89_dev *rtwdev, bool en); u32 (*fill_txaddr_info)(struct rtw89_dev *rtwdev, @@ -798,12 +805,6 @@ struct rtw89_pci_info { struct rtw89_pci_isrs *isrs); }; -struct rtw89_pci_bd_ram { - u8 start_idx; - u8 max_num; - u8 min_num; -}; - struct rtw89_pci_tx_data { dma_addr_t dma; }; @@ -1057,6 +1058,8 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) extern const struct dev_pm_ops rtw89_pm_ops; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; +extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM]; +extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM]; struct pci_device_id; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 017710c580c7..d9f61ba3d176 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -367,6 +367,7 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, } ra->bw_cap = bw_mode; + ra->er_cap = rtwsta->er_cap; ra->mode_ctrl = mode; ra->macid = rtwsta->mac_id; ra->stbc_cap = stbc_en; @@ -2041,6 +2042,7 @@ void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { + u8 max_nss_num = rtwdev->chip->rf_path_num; static const u8 rs[] = { RTW89_RS_CCK, RTW89_RS_OFDM, @@ -2063,7 +2065,7 @@ void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_HEDCM] % 4); addr = R_AX_PWR_BY_RATE; - for (cur.nss = 0; cur.nss <= RTW89_NSS_2; cur.nss++) { + for (cur.nss = 0; cur.nss < max_nss_num; cur.nss++) { for (i = 0; i < ARRAY_SIZE(rs); i++) { if (cur.nss >= rtw89_rs_nss_max[rs[i]]) continue; @@ -2126,6 +2128,7 @@ void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { + u8 max_ntx_num = rtwdev->chip->rf_path_num; struct rtw89_txpwr_limit lmt; u8 ch = chan->channel; u8 bw = chan->band_width; @@ -2140,7 +2143,7 @@ void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev, RTW89_TXPWR_LMT_PAGE_SIZE); addr = R_AX_PWR_LMT; - for (i = 0; i < RTW89_NTX_NUM; i++) { + for (i = 0; i < max_ntx_num; i++) { rtw89_phy_fill_txpwr_limit(rtwdev, chan, &lmt, i); ptr = (s8 *)&lmt; @@ -2161,6 +2164,7 @@ void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { + u8 max_ntx_num = rtwdev->chip->rf_path_num; struct rtw89_txpwr_limit_ru lmt_ru; u8 ch = chan->channel; u8 bw = chan->band_width; @@ -2175,7 +2179,7 @@ void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, RTW89_TXPWR_LMT_RU_PAGE_SIZE); addr = R_AX_PWR_RU_LMT; - for (i = 0; i < RTW89_NTX_NUM; i++) { + for (i = 0; i < max_ntx_num; i++) { rtw89_phy_fill_txpwr_limit_ru(rtwdev, chan, &lmt_ru, i); ptr = (s8 *)&lmt_ru; @@ -4116,6 +4120,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) { + const struct rtw89_chip_info *chip = rtwdev->chip; enum rtw89_phy_idx phy_idx = RTW89_PHY_0; u8 bss_color; @@ -4124,11 +4129,11 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif bss_color = vif->bss_conf.he_bss_color.color; - rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0, 0x1, - phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_TGT, bss_color, + rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_VLD0, 0x1, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_STAID, + rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_TGT, + bss_color, phy_idx); + rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_STAID, vif->cfg.aid, phy_idx); } diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 5324e645728b..600257909df2 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -275,6 +275,9 @@ #define B_AX_S1_LDO2PWRCUT_F BIT(23) #define B_AX_S0_LDO_VSEL_F_MASK GENMASK(22, 21) +#define R_AX_SEC_CTRL 0x0C00 +#define B_AX_SEC_IDMEM_SIZE_CONFIG_MASK GENMASK(17, 16) + #define R_AX_FILTER_MODEL_ADDR 0x0C04 #define R_AX_HAXI_INIT_CFG1 0x1000 @@ -3559,6 +3562,7 @@ #define RR_MOD_IQK GENMASK(19, 4) #define RR_MOD_DPK GENMASK(19, 5) #define RR_MOD_MASK GENMASK(19, 16) +#define RR_MOD_DCK GENMASK(14, 10) #define RR_MOD_RGM GENMASK(13, 4) #define RR_MOD_V_DOWN 0x0 #define RR_MOD_V_STANDBY 0x1 @@ -3572,6 +3576,7 @@ #define RR_MOD_NBW GENMASK(15, 14) #define RR_MOD_M_RXG GENMASK(13, 4) #define RR_MOD_M_RXBB GENMASK(9, 5) +#define RR_MOD_LO_SEL BIT(1) #define RR_MODOPT 0x01 #define RR_MODOPT_M_TXPWR GENMASK(5, 0) #define RR_WLSEL 0x02 @@ -3638,6 +3643,7 @@ #define RR_LUTWA_M2 GENMASK(4, 0) #define RR_LUTWD1 0x3e #define RR_LUTWD0 0x3f +#define RR_LUTWD0_MB GENMASK(11, 6) #define RR_LUTWD0_LB GENMASK(5, 0) #define RR_TM 0x42 #define RR_TM_TRI BIT(19) @@ -3671,6 +3677,8 @@ #define RR_TXRSV_GAPK BIT(19) #define RR_BIAS 0x5e #define RR_BIAS_GAPK BIT(19) +#define RR_TXAC 0x5f +#define RR_TXAC_IQG GENMASK(3, 0) #define RR_BIASA 0x60 #define RR_BIASA_TXG GENMASK(15, 12) #define RR_BIASA_TXA GENMASK(19, 16) @@ -3729,10 +3737,14 @@ #define RR_XALNA2_SW2 GENMASK(9, 8) #define RR_XALNA2_SW GENMASK(1, 0) #define RR_DCK 0x92 +#define RR_DCK_S1 GENMASK(19, 16) +#define RR_DCK_TIA GENMASK(15, 9) #define RR_DCK_DONE GENMASK(7, 5) #define RR_DCK_FINE BIT(1) #define RR_DCK_LV BIT(0) #define RR_DCK1 0x93 +#define RR_DCK1_S1 GENMASK(19, 16) +#define RR_DCK1_TIA GENMASK(15, 9) #define RR_DCK1_DONE BIT(5) #define RR_DCK1_CLR GENMASK(3, 0) #define RR_DCK1_SEL BIT(3) @@ -3781,11 +3793,14 @@ #define RR_LUTDBG 0xdf #define RR_LUTDBG_TIA BIT(12) #define RR_LUTDBG_LOK BIT(2) +#define RR_LUTPLL 0xec +#define RR_CAL_RW BIT(19) #define RR_LUTWE2 0xee #define RR_LUTWE2_RTXBW BIT(2) #define RR_LUTWE 0xef #define RR_LUTWE_LOK BIT(2) #define RR_RFC 0xf0 +#define RR_WCAL BIT(16) #define RR_RFC_CKEN BIT(1) #define R_UPD_P0 0x0000 @@ -4090,12 +4105,13 @@ #define R_MUIC 0x40F8 #define B_MUIC_EN BIT(0) #define R_DCFO 0x4264 -#define B_DCFO GENMASK(1, 0) +#define B_DCFO GENMASK(7, 0) #define R_SEG0CSI 0x42AC -#define B_SEG0CSI_IDX GENMASK(11, 0) +#define B_SEG0CSI_IDX GENMASK(10, 0) #define R_SEG0CSI_EN 0x42C4 #define B_SEG0CSI_EN BIT(23) #define R_BSS_CLR_MAP 0x43ac +#define R_BSS_CLR_MAP_V1 0x43B0 #define B_BSS_CLR_MAP_VLD0 BIT(28) #define B_BSS_CLR_MAP_TGT GENMASK(27, 22) #define B_BSS_CLR_MAP_STAID GENMASK(21, 11) @@ -4725,6 +4741,7 @@ #define R_DRCK_FH 0xC094 #define B_DRCK_LAT BIT(9) #define R_DRCK 0xC0C4 +#define B_DRCK_MUL GENMASK(21, 17) #define B_DRCK_IDLE BIT(9) #define B_DRCK_EN BIT(6) #define B_DRCK_VAL GENMASK(4, 0) @@ -4742,9 +4759,13 @@ #define B_PATH0_SAMPL_DLY_T_MSK_V1 GENMASK(27, 26) #define R_P0_CFCH_BW0 0xC0D4 #define B_P0_CFCH_BW0 GENMASK(27, 26) +#define B_P0_CFCH_EN GENMASK(14, 11) +#define B_P0_CFCH_CTL GENMASK(10, 7) #define R_P0_CFCH_BW1 0xC0D8 #define B_P0_CFCH_EX BIT(13) #define B_P0_CFCH_BW1 GENMASK(8, 5) +#define R_ADCMOD 0xC0E8 +#define B_ADCMOD_LP GENMASK(31, 16) #define R_ADDCK0D 0xC0F0 #define B_ADDCK0D_VAL2 GENMASK(31, 26) #define B_ADDCK0D_VAL GENMASK(25, 16) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index eff6519cf019..9c42b6abd223 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -1035,7 +1035,7 @@ static void rtw8852a_spur_elimination(struct rtw89_dev *rtwdev, u8 central_ch) 0x210); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, B_P1_NBIIDX_VAL, 0x210); - rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, 0xfff, 0x7c0); + rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, B_SEG0CSI_IDX, 0x7c0); rtw89_phy_write32_mask(rtwdev, R_P0_NBIIDX, B_P0_NBIIDX_NOTCH_EN, 0x1); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, @@ -1047,7 +1047,7 @@ static void rtw8852a_spur_elimination(struct rtw89_dev *rtwdev, u8 central_ch) 0x210); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, B_P1_NBIIDX_VAL, 0x210); - rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, 0xfff, 0x40); + rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, B_SEG0CSI_IDX, 0x40); rtw89_phy_write32_mask(rtwdev, R_P0_NBIIDX, B_P0_NBIIDX_NOTCH_EN, 0x1); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, @@ -1059,7 +1059,7 @@ static void rtw8852a_spur_elimination(struct rtw89_dev *rtwdev, u8 central_ch) 0x2d0); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, B_P1_NBIIDX_VAL, 0x2d0); - rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, 0xfff, 0x740); + rtw89_phy_write32_mask(rtwdev, R_SEG0CSI, B_SEG0CSI_IDX, 0x740); rtw89_phy_write32_mask(rtwdev, R_P0_NBIIDX, B_P0_NBIIDX_NOTCH_EN, 0x1); rtw89_phy_write32_mask(rtwdev, R_P1_NBIIDX, @@ -1878,9 +1878,13 @@ static void rtw8852a_btc_update_bt_cnt(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_cx *cx = &btc->cx; u32 val; + if (ver->fcxbtcrpt != 1) + return; + val = rtw89_read32(rtwdev, R_AX_BT_STAST_HIGH); cx->cnt_bt[BTC_BCNT_HIPRI_TX] = FIELD_GET(B_AX_STATIS_BT_HI_TX_MASK, val); cx->cnt_bt[BTC_BCNT_HIPRI_RX] = FIELD_GET(B_AX_STATIS_BT_HI_RX_MASK, val); @@ -2051,6 +2055,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .chip_id = RTL8852A, .ops = &rtw8852a_chip_ops, .fw_name = "rtw89/rtw8852a_fw.bin", + .try_ce_fw = false, .fifo_size = 458752, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 3500, @@ -2106,20 +2111,6 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, - .btc_fwinfo_buf = 1024, - - .fcxbtcrpt_ver = 1, - .fcxtdma_ver = 1, - .fcxslots_ver = 1, - .fcxcysta_ver = 2, - .fcxstep_ver = 2, - .fcxnullsta_ver = 1, - .fcxmreg_ver = 1, - .fcxgpiodbg_ver = 1, - .fcxbtver_ver = 1, - .fcxbtscan_ver = 1, - .fcxbtafh_ver = 1, - .fcxbtdevinfo_ver = 1, .afh_guard_ch = 6, .wl_rssi_thres = rtw89_btc_8852a_wl_rssi_thres, @@ -2149,6 +2140,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .dcfo_comp_sft = 3, .imr_info = &rtw8852a_imr_info, .rrsr_cfgs = &rtw8852a_rrsr_cfgs, + .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852a, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c index 582ff0d3a9ea..cd6c39b7f802 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c @@ -1643,7 +1643,7 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]==========IQK strat!!!!!==========\n"); + "[IQK]==========IQK start!!!!!==========\n"); iqk_info->iqk_times++; iqk_info->kcount = 0; iqk_info->version = RTW8852A_IQK_VER; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 0cd8c0c44d19..d835a44a1d0d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -44,6 +44,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, + .bd_ram_table = &rtw89_bd_ram_table_dual, .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index b635ac1d1ca2..ee8dba7e0074 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -1618,6 +1618,7 @@ static void rtw8852b_set_txpwr_ref(struct rtw89_dev *rtwdev, } static void rtw8852b_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 tx_shape_idx, enum rtw89_phy_idx phy_idx) { @@ -1637,7 +1638,6 @@ static void rtw8852b_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, __DECL_DFIR_PARAM(sharp_14, 0x023B13FF, 0x001C42DE, 0x00FDB0AD, 0x00F60F6E, 0x00FD8F92, 0x0602D011, 0x0001C02C, 0x00FFF00A); - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); u8 ch = chan->channel; const u32 *param; u32 addr; @@ -1678,7 +1678,7 @@ static void rtw8852b_set_tx_shape(struct rtw89_dev *rtwdev, u8 tx_shape_ofdm = rtw89_8852b_tx_shape[band][RTW89_RS_OFDM][regd]; if (band == RTW89_BAND_2G) - rtw8852b_bb_set_tx_shape_dfir(rtwdev, tx_shape_cck, phy_idx); + rtw8852b_bb_set_tx_shape_dfir(rtwdev, chan, tx_shape_cck, phy_idx); rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG, tx_shape_ofdm); @@ -1720,7 +1720,7 @@ void rtw8852b_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, pw_ofst = max_t(s8, pw_ofst - 3, -16); reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst); + rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MASK, pw_ofst); } static int @@ -2423,13 +2423,14 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .btc_update_bt_cnt = rtw8852b_btc_update_bt_cnt, .btc_wl_s1_standby = rtw8852b_btc_wl_s1_standby, .btc_set_wl_rx_gain = rtw8852b_btc_set_wl_rx_gain, - .btc_set_policy = rtw89_btc_set_policy, + .btc_set_policy = rtw89_btc_set_policy_v1, }; const struct rtw89_chip_info rtw8852b_chip_info = { .chip_id = RTL8852B, .ops = &rtw8852b_chip_ops, .fw_name = "rtw89/rtw8852b_fw.bin", + .try_ce_fw = true, .fifo_size = 196608, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 3500, @@ -2437,6 +2438,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, .dle_mem = rtw8852b_dle_mem_pcie, + .wde_qempty_acq_num = 4, + .wde_qempty_mgq_sel = 4, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, @@ -2483,20 +2486,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .btcx_desired = 0x5, .scbd = 0x1, .mailbox = 0x1, - .btc_fwinfo_buf = 1024, - - .fcxbtcrpt_ver = 1, - .fcxtdma_ver = 1, - .fcxslots_ver = 1, - .fcxcysta_ver = 2, - .fcxstep_ver = 2, - .fcxnullsta_ver = 1, - .fcxmreg_ver = 1, - .fcxgpiodbg_ver = 1, - .fcxbtver_ver = 1, - .fcxbtscan_ver = 1, - .fcxbtafh_ver = 1, - .fcxbtdevinfo_ver = 1, + .afh_guard_ch = 6, .wl_rssi_thres = rtw89_btc_8852b_wl_rssi_thres, .bt_rssi_thres = rtw89_btc_8852b_bt_rssi_thres, @@ -2525,6 +2515,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .dcfo_comp_sft = 3, .imr_info = &rtw8852b_imr_info, .rrsr_cfgs = &rtw8852b_rrsr_cfgs, + .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index 0ef2ca8efeb0..ecf39d2d9f81 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -46,6 +46,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), .bd_idx_addr_low_power = NULL, .dma_addr_set = &rtw89_pci_ch_dma_addr_set, + .bd_ram_table = &rtw89_bd_ram_table_single, .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index a87482cc25f5..d2dde21d3daf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -1968,6 +1968,7 @@ static void rtw8852c_set_txpwr_ref(struct rtw89_dev *rtwdev, } static void rtw8852c_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 tx_shape_idx, enum rtw89_phy_idx phy_idx) { @@ -1991,7 +1992,6 @@ static void rtw8852c_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, __DECL_DFIR_ADDR(filter, 0x45BC, 0x45CC, 0x45D0, 0x45D4, 0x45D8, 0x45C0, 0x45C4, 0x45C8); - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); u8 ch = chan->channel; const u32 *param; int i; @@ -2032,7 +2032,7 @@ static void rtw8852c_set_tx_shape(struct rtw89_dev *rtwdev, u8 tx_shape_ofdm = rtw89_8852c_tx_shape[band][RTW89_RS_OFDM][regd]; if (band == RTW89_BAND_2G) - rtw8852c_bb_set_tx_shape_dfir(rtwdev, tx_shape_cck, phy_idx); + rtw8852c_bb_set_tx_shape_dfir(rtwdev, chan, tx_shape_cck, phy_idx); rtw89_phy_tssi_ctrl_set_bandedge_cfg(rtwdev, (enum rtw89_mac_idx)phy_idx, @@ -2857,6 +2857,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .chip_id = RTL8852C, .ops = &rtw8852c_chip_ops, .fw_name = "rtw89/rtw8852c_fw.bin", + .try_ce_fw = false, .fifo_size = 458752, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 8000, @@ -2915,20 +2916,6 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, - .btc_fwinfo_buf = 1280, - - .fcxbtcrpt_ver = 4, - .fcxtdma_ver = 3, - .fcxslots_ver = 1, - .fcxcysta_ver = 3, - .fcxstep_ver = 3, - .fcxnullsta_ver = 2, - .fcxmreg_ver = 1, - .fcxgpiodbg_ver = 1, - .fcxbtver_ver = 1, - .fcxbtscan_ver = 1, - .fcxbtafh_ver = 1, - .fcxbtdevinfo_ver = 1, .afh_guard_ch = 6, .wl_rssi_thres = rtw89_btc_8852c_wl_rssi_thres, @@ -2959,6 +2946,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .dcfo_comp_sft = 5, .imr_info = &rtw8852c_imr_info, .rrsr_cfgs = &rtw8852c_rrsr_cfgs, + .bss_clr_map_reg = R_BSS_CLR_MAP, .dma_ch_mask = 0, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852c, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c index 60cd676fe22c..2c0bc3a4ab3b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c @@ -11,6 +11,15 @@ #include "rtw8852c_rfk_table.h" #include "rtw8852c_table.h" +struct rxck_def { + u32 ctl; + u32 en; + u32 bw0; + u32 bw1; + u32 mul; + u32 lp; +}; + #define _TSSI_DE_MASK GENMASK(21, 12) static const u32 _tssi_de_cck_long[RF_PATH_NUM_8852C] = {0x5858, 0x7858}; static const u32 _tssi_de_cck_short[RF_PATH_NUM_8852C] = {0x5860, 0x7860}; @@ -26,7 +35,7 @@ static const u32 rtw8852c_backup_bb_regs[] = { }; static const u32 rtw8852c_backup_rf_regs[] = { - 0xdf, 0x8f, 0x97, 0xa3, 0x5, 0x10005 + 0xdf, 0x5f, 0x8f, 0x97, 0xa3, 0x5, 0x10005 }; #define BACKUP_BB_REGS_NR ARRAY_SIZE(rtw8852c_backup_bb_regs) @@ -59,6 +68,13 @@ static const u32 dpk_par_regs[RTW89_DPK_RF_PATH][4] = { {0x81a8, 0x81c4, 0x81c8, 0x81e8}, }; +static const u8 _dck_addr_bs[RF_PATH_NUM_8852C] = {0x0, 0x10}; +static const u8 _dck_addr[RF_PATH_NUM_8852C] = {0xc, 0x1c}; + +static const struct rxck_def _ck480M = {0x8, 0x2, 0x3, 0xf, 0x0, 0x9}; +static const struct rxck_def _ck960M = {0x8, 0x2, 0x2, 0x8, 0x0, 0x9}; +static const struct rxck_def _ck1920M = {0x8, 0x0, 0x2, 0x4, 0x6, 0x9}; + static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]dbcc_en: %x, PHY%d\n", @@ -337,7 +353,7 @@ static void _dack_reload_by_path(struct rtw89_dev *rtwdev, (dack->dadck_d[path][index] << 14); addr = 0xc210 + offset; rtw89_phy_write32(rtwdev, addr, val32); - rtw89_phy_write32_set(rtwdev, addr, BIT(1)); + rtw89_phy_write32_set(rtwdev, addr, BIT(0)); } static void _dack_reload(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) @@ -437,6 +453,8 @@ static void rtw8852c_txck_force(struct rtw89_dev *rtwdev, u8 path, bool force, static void rtw8852c_rxck_force(struct rtw89_dev *rtwdev, u8 path, bool force, enum adc_ck ck) { + const struct rxck_def *def; + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x0); if (!force) @@ -444,6 +462,26 @@ static void rtw8852c_rxck_force(struct rtw89_dev *rtwdev, u8 path, bool force, rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_VAL, ck); rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x1); + + switch (ck) { + case ADC_480M: + def = &_ck480M; + break; + case ADC_960M: + def = &_ck960M; + break; + case ADC_1920M: + default: + def = &_ck1920M; + break; + } + + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_CTL, def->ctl); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_EN, def->en); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_BW0, def->bw0); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 | (path << 8), B_P0_CFCH_BW1, def->bw1); + rtw89_phy_write32_mask(rtwdev, R_DRCK | (path << 8), B_DRCK_MUL, def->mul); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD | (path << 8), B_ADCMOD_LP, def->lp); } static bool _check_dack_done(struct rtw89_dev *rtwdev, bool s0) @@ -627,8 +665,6 @@ static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_DPD_GDIS, 0x1); rtw8852c_rxck_force(rtwdev, path, true, ADC_480M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_ACK_VAL, 0x0); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x3); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xf); rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); break; @@ -636,8 +672,6 @@ static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_DPD_GDIS, 0x1); rtw8852c_rxck_force(rtwdev, path, true, ADC_960M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_ACK_VAL, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xd); rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); break; @@ -645,8 +679,6 @@ static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_DPD_GDIS, 0x1); rtw8852c_rxck_force(rtwdev, path, true, ADC_1920M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_ACK_VAL, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xb); rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); break; @@ -1410,8 +1442,6 @@ static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, rtw8852c_rxck_force(rtwdev, path, true, ADC_1920M); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK | (path << 13), B_ACK_VAL, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_BW0, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 | (path << 8), B_P0_CFCH_BW1, 0xb); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW | (path << 13), B_P0_NRBW_DBG, 0x1); rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x1f); rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x13); @@ -1536,6 +1566,155 @@ static void _iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool forc } } +static void _rx_dck_value_rewrite(struct rtw89_dev *rtwdev, u8 path, u8 addr, + u8 val_i, u8 val_q) +{ + u32 ofst_val; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] rewrite val_i = 0x%x, val_q = 0x%x\n", val_i, val_q); + + /* val_i and val_q are 7 bits, and target is 6 bits. */ + ofst_val = u32_encode_bits(val_q >> 1, RR_LUTWD0_MB) | + u32_encode_bits(val_i >> 1, RR_LUTWD0_LB); + + rtw89_write_rf(rtwdev, path, RR_LUTPLL, RR_CAL_RW, 0x1); + rtw89_write_rf(rtwdev, path, RR_RFC, RR_WCAL, 0x1); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, 0x1); + rtw89_write_rf(rtwdev, path, RR_LUTWA, MASKBYTE0, addr); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, ofst_val); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, ofst_val); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, 0x0); + rtw89_write_rf(rtwdev, path, RR_RFC, RR_WCAL, 0x0); + rtw89_write_rf(rtwdev, path, RR_LUTPLL, RR_CAL_RW, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] Final val_i = 0x%x, val_q = 0x%x\n", + u32_get_bits(ofst_val, RR_LUTWD0_LB) << 1, + u32_get_bits(ofst_val, RR_LUTWD0_MB) << 1); +} + +static bool _rx_dck_rek_check(struct rtw89_dev *rtwdev, u8 path) +{ + u8 i_even_bs, q_even_bs; + u8 i_odd_bs, q_odd_bs; + u8 i_even, q_even; + u8 i_odd, q_odd; + const u8 th = 10; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8852C; i++) { + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i]); + i_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even_bs/ q_even_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i], i_even_bs, q_even_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i]); + i_even = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even/ q_even = 0x%x/ 0x%x\n", + _dck_addr[i], i_even, q_even); + + if (abs(i_even_bs - i_even) > th || abs(q_even_bs - q_even) > th) + return true; + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i] + 1); + i_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd_bs/ q_odd_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i] + 1, i_odd_bs, q_odd_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i] + 1); + i_odd = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd/ q_odd = 0x%x/ 0x%x\n", + _dck_addr[i] + 1, i_odd, q_odd); + + if (abs(i_odd_bs - i_odd) > th || abs(q_odd_bs - q_odd) > th) + return true; + } + + return false; +} + +static void _rx_dck_fix_if_need(struct rtw89_dev *rtwdev, u8 path, u8 addr, + u8 val_i_bs, u8 val_q_bs, u8 val_i, u8 val_q) +{ + const u8 th = 10; + + if ((abs(val_i_bs - val_i) < th) && (abs(val_q_bs - val_q) <= th)) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] offset check PASS!!\n"); + return; + } + + if (abs(val_i_bs - val_i) > th) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] val_i over TH (0x%x / 0x%x)\n", val_i_bs, val_i); + val_i = val_i_bs; + } + + if (abs(val_q_bs - val_q) > th) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] val_q over TH (0x%x / 0x%x)\n", val_q_bs, val_q); + val_q = val_q_bs; + } + + _rx_dck_value_rewrite(rtwdev, path, addr, val_i, val_q); +} + +static void _rx_dck_recover(struct rtw89_dev *rtwdev, u8 path) +{ + u8 i_even_bs, q_even_bs; + u8 i_odd_bs, q_odd_bs; + u8 i_even, q_even; + u8 i_odd, q_odd; + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] ===> recovery\n"); + + for (i = 0; i < RF_PATH_NUM_8852C; i++) { + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i]); + i_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr_bs[i] + 1); + i_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd_bs = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even_bs/ q_even_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i], i_even_bs, q_even_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i]); + i_even = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_even = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_even/ q_even = 0x%x/ 0x%x\n", + _dck_addr[i], i_even, q_even); + _rx_dck_fix_if_need(rtwdev, path, _dck_addr[i], + i_even_bs, q_even_bs, i_even, q_even); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd_bs/ q_odd_bs = 0x%x/ 0x%x\n", + _dck_addr_bs[i] + 1, i_odd_bs, q_odd_bs); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_DCK, _dck_addr[i] + 1); + i_odd = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_TIA); + q_odd = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_TIA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] Gain[0x%x] i_odd/ q_odd = 0x%x/ 0x%x\n", + _dck_addr[i] + 1, i_odd, q_odd); + _rx_dck_fix_if_need(rtwdev, path, _dck_addr[i] + 1, + i_odd_bs, q_odd_bs, i_odd, q_odd); + } +} + static void _rx_dck_toggle(struct rtw89_dev *rtwdev, u8 path) { int ret; @@ -1573,11 +1752,42 @@ static void _set_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 pat } } +static +u8 _rx_dck_channel_calc(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan) +{ + u8 target_ch = 0; + + if (chan->band_type == RTW89_BAND_5G) { + if (chan->channel >= 36 && chan->channel <= 64) { + target_ch = 100; + } else if (chan->channel >= 100 && chan->channel <= 144) { + target_ch = chan->channel + 32; + if (target_ch > 144) + target_ch = chan->channel + 33; + } else if (chan->channel >= 149 && chan->channel <= 177) { + target_ch = chan->channel - 33; + } + } else if (chan->band_type == RTW89_BAND_6G) { + if (chan->channel >= 1 && chan->channel <= 125) + target_ch = chan->channel + 32; + else + target_ch = chan->channel - 32; + } else { + target_ch = chan->channel; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] cur_ch / target_ch = %d / %d\n", + chan->channel, target_ch); + + return target_ch; +} + #define RTW8852C_RF_REL_VERSION 34 -#define RTW8852C_DPK_VER 0x10 +#define RTW8852C_DPK_VER 0xf #define RTW8852C_DPK_TH_AVG_NUM 4 #define RTW8852C_DPK_RF_PATH 2 -#define RTW8852C_DPK_KIP_REG_NUM 5 +#define RTW8852C_DPK_KIP_REG_NUM 7 #define RTW8852C_DPK_RXSRAM_DBG 0 enum rtw8852c_dpk_id { @@ -1614,6 +1824,12 @@ enum dpk_agc_step { DPK_AGC_STEP_SET_TX_GAIN, }; +enum dpk_pas_result { + DPK_PAS_NOR, + DPK_PAS_GT, + DPK_PAS_LT, +}; + static void _rf_direct_cntrl(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool is_bybb) { @@ -1730,8 +1946,6 @@ static void _dpk_bb_afe_setting(struct rtw89_dev *rtwdev, /*4. Set ADC clk*/ rtw8852c_rxck_force(rtwdev, path, true, ADC_1920M); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 + (path << 8), B_P0_CFCH_BW0, 0x1); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 + (path << 8), B_P0_CFCH_BW1, 0xb); rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x1); rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, MASKBYTE3, 0x1f); @@ -1872,12 +2086,11 @@ static void _dpk_rf_setting(struct rtw89_dev *rtwdev, u8 gain, 0x50101 | BIT(rtwdev->dbcc_en)); rtw89_write_rf(rtwdev, path, RR_MOD_V1, RR_MOD_MASK, RF_DPK); - if (dpk->bp[path][kidx].band == RTW89_BAND_6G && dpk->bp[path][kidx].ch >= 161) { + if (dpk->bp[path][kidx].band == RTW89_BAND_6G && dpk->bp[path][kidx].ch >= 161) rtw89_write_rf(rtwdev, path, RR_IQGEN, RR_IQGEN_BIAS, 0x8); - rtw89_write_rf(rtwdev, path, RR_LOGEN, RR_LOGEN_RPT, 0xd); - } else { - rtw89_write_rf(rtwdev, path, RR_LOGEN, RR_LOGEN_RPT, 0xd); - } + + rtw89_write_rf(rtwdev, path, RR_LOGEN, RR_LOGEN_RPT, 0xd); + rtw89_write_rf(rtwdev, path, RR_TXAC, RR_TXAC_IQG, 0x8); rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_ATT, 0x0); rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT2, 0x3); @@ -2024,9 +2237,10 @@ static u8 _dpk_gainloss(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, return _dpk_gainloss_read(rtwdev); } -static bool _dpk_pas_read(struct rtw89_dev *rtwdev, bool is_check) +static enum dpk_pas_result _dpk_pas_read(struct rtw89_dev *rtwdev, bool is_check) { u32 val1_i = 0, val1_q = 0, val2_i = 0, val2_q = 0; + u32 val1_sqrt_sum, val2_sqrt_sum; u8 i; rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKBYTE2, 0x06); @@ -2057,15 +2271,25 @@ static bool _dpk_pas_read(struct rtw89_dev *rtwdev, bool is_check) } } - if (val1_i * val1_i + val1_q * val1_q >= (val2_i * val2_i + val2_q * val2_q) * 8 / 5) - return true; + val1_sqrt_sum = val1_i * val1_i + val1_q * val1_q; + val2_sqrt_sum = val2_i * val2_i + val2_q * val2_q; + + if (val1_sqrt_sum < val2_sqrt_sum) + return DPK_PAS_LT; + else if (val1_sqrt_sum >= val2_sqrt_sum * 8 / 5) + return DPK_PAS_GT; else - return false; + return DPK_PAS_NOR; } static bool _dpk_kip_set_rxagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, enum rtw89_rf_path path, u8 kidx) { + _dpk_kip_control_rfc(rtwdev, path, false); + rtw89_phy_write32_mask(rtwdev, R_KIP_MOD, B_KIP_MOD, + rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK)); + _dpk_kip_control_rfc(rtwdev, path, true); + _dpk_one_shot(rtwdev, phy, path, D_RXAGC); return _dpk_sync_check(rtwdev, path, kidx); @@ -2103,6 +2327,7 @@ static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 tmp_dbm = init_xdbm, tmp_gl_idx = 0; u8 tmp_rxbb; u8 goout = 0, agc_cnt = 0; + enum dpk_pas_result pas; u16 dgain = 0; bool is_fail = false; int limit = 200; @@ -2138,9 +2363,13 @@ static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, case DPK_AGC_STEP_GAIN_LOSS_IDX: tmp_gl_idx = _dpk_gainloss(rtwdev, phy, path, kidx); + pas = _dpk_pas_read(rtwdev, true); - if ((tmp_gl_idx == 0 && _dpk_pas_read(rtwdev, true)) || - tmp_gl_idx >= 7) + if (pas == DPK_PAS_LT && tmp_gl_idx > 0) + step = DPK_AGC_STEP_GL_LT_CRITERION; + else if (pas == DPK_PAS_GT && tmp_gl_idx == 0) + step = DPK_AGC_STEP_GL_GT_CRITERION; + else if (tmp_gl_idx >= 7) step = DPK_AGC_STEP_GL_GT_CRITERION; else if (tmp_gl_idx == 0) step = DPK_AGC_STEP_GL_LT_CRITERION; @@ -2467,12 +2696,14 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, enum rtw89_phy_idx phy, u8 kpath) { struct rtw89_dpk_info *dpk = &rtwdev->dpk; - static const u32 kip_reg[] = {0x813c, 0x8124, 0x8120, 0xc0d4, 0xc0d8}; + static const u32 kip_reg[] = {0x813c, 0x8124, 0x8120, 0xc0c4, 0xc0e8, 0xc0d4, 0xc0d8}; u32 backup_rf_val[RTW8852C_DPK_RF_PATH][BACKUP_RF_REGS_NR]; u32 kip_bkup[RTW8852C_DPK_RF_PATH][RTW8852C_DPK_KIP_REG_NUM] = {}; u8 path; bool is_fail = true, reloaded[RTW8852C_DPK_RF_PATH] = {false}; + static_assert(ARRAY_SIZE(kip_reg) == RTW8852C_DPK_KIP_REG_NUM); + if (dpk->is_dpk_reload_en) { for (path = 0; path < RTW8852C_DPK_RF_PATH; path++) { if (!(kpath & BIT(path))) @@ -3875,11 +4106,14 @@ void rtw8852c_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) #define RXDCK_VER_8852C 0xe -void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_afe) +static void _rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + bool is_afe, u8 retry_limit) { struct rtw89_rx_dck_info *rx_dck = &rtwdev->rx_dck; u8 path, kpath; u32 rf_reg5; + bool is_fail; + u8 rek_cnt; kpath = _kpath(rtwdev, phy); rtw89_debug(rtwdev, RTW89_DBG_RFK, @@ -3896,7 +4130,27 @@ void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_a B_P0_TSSI_TRK_EN, 0x1); rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); - _set_rx_dck(rtwdev, phy, path, is_afe); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_LO_SEL, rtwdev->dbcc_en); + + for (rek_cnt = 0; rek_cnt < retry_limit; rek_cnt++) { + _set_rx_dck(rtwdev, phy, path, is_afe); + + /* To reduce IO of dck_rek_check(), the last try is seen + * as failure always, and then do recovery procedure. + */ + if (rek_cnt == retry_limit - 1) { + _rx_dck_recover(rtwdev, path); + break; + } + + is_fail = _rx_dck_rek_check(rtwdev, path); + if (!is_fail) + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] rek_cnt[%d]=%d", + path, rek_cnt); + rx_dck->thermal[path] = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); @@ -3906,15 +4160,31 @@ void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_a } } -#define RTW8852C_RX_DCK_TH 8 +void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_afe) +{ + _rx_dck(rtwdev, phy, is_afe, 1); +} + +#define RTW8852C_RX_DCK_TH 12 void rtw8852c_rx_dck_track(struct rtw89_dev *rtwdev) { + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); struct rtw89_rx_dck_info *rx_dck = &rtwdev->rx_dck; + enum rtw89_phy_idx phy_idx = RTW89_PHY_0; + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); + u8 dck_channel; u8 cur_thermal; + u32 tx_en; int delta; int path; + if (chan->band_type == RTW89_BAND_2G) + return; + + if (rtwdev->scanning) + return; + for (path = 0; path < RF_PATH_NUM_8852C; path++) { cur_thermal = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); @@ -3924,11 +4194,28 @@ void rtw8852c_rx_dck_track(struct rtw89_dev *rtwdev) "[RX_DCK] path=%d current thermal=0x%x delta=0x%x\n", path, cur_thermal, delta); - if (delta >= RTW8852C_RX_DCK_TH) { - rtw8852c_rx_dck(rtwdev, RTW89_PHY_0, false); - return; - } + if (delta >= RTW8852C_RX_DCK_TH) + goto trigger_rx_dck; } + + return; + +trigger_rx_dck: + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + + for (path = 0; path < RF_PATH_NUM_8852C; path++) { + dck_channel = _rx_dck_channel_calc(rtwdev, chan); + _ctrl_ch(rtwdev, RTW89_PHY_0, dck_channel, chan->band_type); + } + + _rx_dck(rtwdev, RTW89_PHY_0, false, 20); + + for (path = 0; path < RF_PATH_NUM_8852C; path++) + _ctrl_ch(rtwdev, RTW89_PHY_0, chan->channel, chan->band_type); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_STOP); } void rtw8852c_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 35901f64d17d..80490a5437df 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -53,6 +53,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .tx_dma_ch_mask = 0, .bd_idx_addr_low_power = &rtw8852c_bd_idx_addr_low_power, .dma_addr_set = &rtw89_pci_ch_dma_addr_set_v1, + .bd_ram_table = &rtw89_bd_ram_table_dual, .ltr_set = rtw89_pci_ltr_set_v1, .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index c1a4bc1c64d1..61db7189fdab 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -611,6 +611,7 @@ bottom: ser_reset_mac_binding(rtwdev); rtw89_core_stop(rtwdev); rtw89_entity_init(rtwdev); + rtw89_fw_release_general_pkt_list(rtwdev, false); INIT_LIST_HEAD(&rtwdev->rtwvifs_list); } diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 9d4c6b6fa125..98eb9607cd21 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -75,7 +75,9 @@ #define RTW89_TXWD_INFO0_DATA_BW GENMASK(29, 28) #define RTW89_TXWD_INFO0_GI_LTF GENMASK(27, 25) #define RTW89_TXWD_INFO0_DATA_RATE GENMASK(24, 16) +#define RTW89_TXWD_INFO0_DATA_ER BIT(15) #define RTW89_TXWD_INFO0_DISDATAFB BIT(10) +#define RTW89_TXWD_INFO0_DATA_BW_ER BIT(8) #define RTW89_TXWD_INFO0_MULTIPORT_ID GENMASK(6, 4) /* TX WD INFO DWORD 1 */ diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index b2b826b2e09a..c78ee2ab732c 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -490,21 +490,6 @@ static int rtw89_wow_check_fw_status(struct rtw89_dev *rtwdev, bool wow_enable) return ret; } -static void rtw89_wow_release_pkt_list(struct rtw89_dev *rtwdev) -{ - struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct list_head *pkt_list = &rtw_wow->pkt_list; - struct rtw89_pktofld_info *info, *tmp; - - list_for_each_entry_safe(info, tmp, pkt_list, list) { - rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); - rtw89_core_release_bit_map(rtwdev->pkt_offload, - info->id); - list_del(&info->list); - kfree(info); - } -} - static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) { enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL; @@ -561,6 +546,11 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) } if (is_conn) { + ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c general packet\n"); + return ret; + } rtw89_phy_ra_assoc(rtwdev, wow_sta); rtw89_phy_set_bss_color(rtwdev, wow_vif); rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif); @@ -708,8 +698,6 @@ static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) goto out; } - rtw89_wow_release_pkt_list(rtwdev); - ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n"); @@ -722,6 +710,8 @@ static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) goto out; } + rtw89_fw_release_general_pkt_list(rtwdev, true); + ret = rtw89_wow_check_fw_status(rtwdev, false); if (ret) { rtw89_err(rtwdev, "wow: failed to check disable fw ready\n"); @@ -744,6 +734,8 @@ static int rtw89_wow_enable(struct rtw89_dev *rtwdev) goto out; } + rtw89_fw_release_general_pkt_list(rtwdev, true); + ret = rtw89_wow_swap_fw(rtwdev, true); if (ret) { rtw89_err(rtwdev, "wow: failed to swap to wow fw\n"); |