Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

wifi: rtw89: add WoWLAN function support

WoWLAN is a feature which allows devices to be woken up from suspend
state through WLAN events.

When user enables WoWLAN feature and then let the device enter suspend
state, WoWLAN firmware will be loaded by the driver and periodically
monitors WiFi packets. Power consumption of WiFi chip will be reduced
in this state.

We now implement WoWLAN function in rtw8852ae and rtw8852ce chip.
Currently supported WLAN events include receiving magic packet,
rekey packet and deauth packet, and disconnecting from AP.

Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20221027052707.14605-7-pkshih@realtek.com

authored by

Chin-Yen Lee and committed by
Kalle Valo
19e28c7f ee88d748

+874 -7
+2
drivers/net/wireless/realtek/rtw89/Makefile
··· 15 15 chan.o \ 16 16 ser.o 17 17 18 + rtw89_core-$(CONFIG_PM) += wow.o 19 + 18 20 obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o 19 21 rtw89_8852a-objs := rtw8852a.o \ 20 22 rtw8852a_table.o \
+8
drivers/net/wireless/realtek/rtw89/core.c
··· 2204 2204 track_work.work); 2205 2205 bool tfc_changed; 2206 2206 2207 + if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags)) 2208 + return; 2209 + 2207 2210 mutex_lock(&rtwdev->mutex); 2208 2211 2209 2212 if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) ··· 3045 3042 continue; 3046 3043 INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]); 3047 3044 } 3045 + INIT_LIST_HEAD(&rtwdev->wow.pkt_list); 3048 3046 INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work); 3049 3047 INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); 3050 3048 INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); ··· 3276 3272 3277 3273 hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID; 3278 3274 hw->wiphy->max_scan_ie_len = RTW89_SCANOFLD_MAX_IE_LEN; 3275 + 3276 + #ifdef CONFIG_PM 3277 + hw->wiphy->wowlan = rtwdev->chip->wowlan_stub; 3278 + #endif 3279 3279 3280 3280 hw->wiphy->tid_config_support.vif |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); 3281 3281 hw->wiphy->tid_config_support.peer |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
+76 -1
drivers/net/wireless/realtek/rtw89/core.h
··· 178 178 RTW89_ROLE_REMOVE, 179 179 RTW89_ROLE_TYPE_CHANGE, 180 180 RTW89_ROLE_INFO_CHANGE, 181 - RTW89_ROLE_CON_DISCONN 181 + RTW89_ROLE_CON_DISCONN, 182 + RTW89_ROLE_BAND_SW, 183 + RTW89_ROLE_FW_RESTORE, 182 184 }; 183 185 184 186 enum rtw89_self_role { ··· 2309 2307 */ 2310 2308 void (*recovery_start)(struct rtw89_dev *rtwdev); 2311 2309 void (*recovery_complete)(struct rtw89_dev *rtwdev); 2310 + 2311 + void (*ctrl_txdma_ch)(struct rtw89_dev *rtwdev, bool enable); 2312 + void (*ctrl_txdma_fw_ch)(struct rtw89_dev *rtwdev, bool enable); 2313 + void (*ctrl_trxhci)(struct rtw89_dev *rtwdev, bool enable); 2314 + int (*poll_txdma_ch)(struct rtw89_dev *rtwdev); 2315 + void (*clr_idx_all)(struct rtw89_dev *rtwdev); 2316 + void (*clear)(struct rtw89_dev *rtwdev, struct pci_dev *pdev); 2317 + void (*disable_intr)(struct rtw89_dev *rtwdev); 2318 + void (*enable_intr)(struct rtw89_dev *rtwdev); 2319 + int (*rst_bdram)(struct rtw89_dev *rtwdev); 2312 2320 }; 2313 2321 2314 2322 struct rtw89_hci_info { ··· 2760 2748 const struct rtw89_imr_info *imr_info; 2761 2749 const struct rtw89_rrsr_cfgs *rrsr_cfgs; 2762 2750 u32 dma_ch_mask; 2751 + const struct wiphy_wowlan_support *wowlan_stub; 2763 2752 }; 2764 2753 2765 2754 union rtw89_bus_info { ··· 2957 2944 RTW89_FLAG_LOW_POWER_MODE, 2958 2945 RTW89_FLAG_INACTIVE_PS, 2959 2946 RTW89_FLAG_CRASH_SIMULATING, 2947 + RTW89_FLAG_WOWLAN, 2948 + RTW89_FLAG_FORBIDDEN_TRACK_WROK, 2960 2949 2961 2950 NUM_OF_RTW89_FLAGS, 2962 2951 }; ··· 3666 3651 { 3667 3652 if (rtwdev->hci.ops->recovery_complete) 3668 3653 rtwdev->hci.ops->recovery_complete(rtwdev); 3654 + } 3655 + 3656 + static inline void rtw89_hci_enable_intr(struct rtw89_dev *rtwdev) 3657 + { 3658 + if (rtwdev->hci.ops->enable_intr) 3659 + rtwdev->hci.ops->enable_intr(rtwdev); 3660 + } 3661 + 3662 + static inline void rtw89_hci_disable_intr(struct rtw89_dev *rtwdev) 3663 + { 3664 + if (rtwdev->hci.ops->disable_intr) 3665 + rtwdev->hci.ops->disable_intr(rtwdev); 3666 + } 3667 + 3668 + static inline void rtw89_hci_ctrl_txdma_ch(struct rtw89_dev *rtwdev, bool enable) 3669 + { 3670 + if (rtwdev->hci.ops->ctrl_txdma_ch) 3671 + rtwdev->hci.ops->ctrl_txdma_ch(rtwdev, enable); 3672 + } 3673 + 3674 + static inline void rtw89_hci_ctrl_txdma_fw_ch(struct rtw89_dev *rtwdev, bool enable) 3675 + { 3676 + if (rtwdev->hci.ops->ctrl_txdma_fw_ch) 3677 + rtwdev->hci.ops->ctrl_txdma_fw_ch(rtwdev, enable); 3678 + } 3679 + 3680 + static inline void rtw89_hci_ctrl_trxhci(struct rtw89_dev *rtwdev, bool enable) 3681 + { 3682 + if (rtwdev->hci.ops->ctrl_trxhci) 3683 + rtwdev->hci.ops->ctrl_trxhci(rtwdev, enable); 3684 + } 3685 + 3686 + static inline int rtw89_hci_poll_txdma_ch(struct rtw89_dev *rtwdev) 3687 + { 3688 + int ret = 0; 3689 + 3690 + if (rtwdev->hci.ops->poll_txdma_ch) 3691 + ret = rtwdev->hci.ops->poll_txdma_ch(rtwdev); 3692 + return ret; 3693 + } 3694 + 3695 + static inline void rtw89_hci_clr_idx_all(struct rtw89_dev *rtwdev) 3696 + { 3697 + if (rtwdev->hci.ops->clr_idx_all) 3698 + rtwdev->hci.ops->clr_idx_all(rtwdev); 3699 + } 3700 + 3701 + static inline int rtw89_hci_rst_bdram(struct rtw89_dev *rtwdev) 3702 + { 3703 + int ret = 0; 3704 + 3705 + if (rtwdev->hci.ops->rst_bdram) 3706 + ret = rtwdev->hci.ops->rst_bdram(rtwdev); 3707 + return ret; 3708 + } 3709 + 3710 + static inline void rtw89_hci_clear(struct rtw89_dev *rtwdev, struct pci_dev *pdev) 3711 + { 3712 + if (rtwdev->hci.ops->clear) 3713 + rtwdev->hci.ops->clear(rtwdev, pdev); 3669 3714 } 3670 3715 3671 3716 static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr)
+1
drivers/net/wireless/realtek/rtw89/debug.h
··· 26 26 RTW89_DBG_HW_SCAN = BIT(15), 27 27 RTW89_DBG_SAR = BIT(16), 28 28 RTW89_DBG_STATE = BIT(17), 29 + RTW89_DBG_WOW = BIT(18), 29 30 30 31 RTW89_DBG_UNEXP = BIT(31), 31 32 };
+14 -4
drivers/net/wireless/realtek/rtw89/mac.c
··· 1566 1566 } 1567 1567 #undef SET_QUOTA 1568 1568 1569 + void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool enable) 1570 + { 1571 + u32 msk32 = B_AX_UC_MGNT_DEC | B_AX_BMC_MGNT_DEC; 1572 + 1573 + if (enable) 1574 + rtw89_write32_set(rtwdev, R_AX_SEC_ENG_CTRL, msk32); 1575 + else 1576 + rtw89_write32_clr(rtwdev, R_AX_SEC_ENG_CTRL, msk32); 1577 + } 1578 + 1569 1579 static void dle_quota_cfg(struct rtw89_dev *rtwdev, 1570 1580 const struct rtw89_dle_mem *cfg, 1571 1581 u16 ext_wde_min_qt_wcpu) ··· 1925 1915 return 0; 1926 1916 } 1927 1917 1928 - static int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, 1929 - enum rtw89_machdr_frame_type type, 1930 - enum rtw89_mac_fwd_target fwd_target, 1931 - u8 mac_idx) 1918 + int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, 1919 + enum rtw89_machdr_frame_type type, 1920 + enum rtw89_mac_fwd_target fwd_target, 1921 + u8 mac_idx) 1932 1922 { 1933 1923 u32 reg; 1934 1924 u32 val;
+14
drivers/net/wireless/realtek/rtw89/mac.h
··· 980 980 B_AX_HCI_TXDMA_EN | B_AX_HCI_RXDMA_EN); 981 981 } 982 982 983 + static inline bool rtw89_mac_get_power_state(struct rtw89_dev *rtwdev) 984 + { 985 + u32 val; 986 + 987 + val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, 988 + B_AX_WLMAC_PWR_STE_MASK); 989 + 990 + return !!val; 991 + } 992 + 983 993 int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, 984 994 bool resume, u32 tx_time); 985 995 int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, ··· 1048 1038 u16 rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd); 1049 1039 int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, 1050 1040 struct rtw89_cpuio_ctrl *ctrl_para, bool wd); 1041 + int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, 1042 + enum rtw89_machdr_frame_type type, 1043 + enum rtw89_mac_fwd_target fwd_target, u8 mac_idx); 1051 1044 int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow); 1052 1045 int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, 1053 1046 enum rtw89_mac_idx band); 1047 + void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow); 1054 1048 1055 1049 #endif
+55
drivers/net/wireless/realtek/rtw89/mac80211.c
··· 14 14 #include "sar.h" 15 15 #include "ser.h" 16 16 #include "util.h" 17 + #include "wow.h" 17 18 18 19 static void rtw89_ops_tx(struct ieee80211_hw *hw, 19 20 struct ieee80211_tx_control *control, ··· 917 916 return 0; 918 917 } 919 918 919 + #ifdef CONFIG_PM 920 + static int rtw89_ops_suspend(struct ieee80211_hw *hw, 921 + struct cfg80211_wowlan *wowlan) 922 + { 923 + struct rtw89_dev *rtwdev = hw->priv; 924 + int ret; 925 + 926 + set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 927 + cancel_delayed_work_sync(&rtwdev->track_work); 928 + 929 + mutex_lock(&rtwdev->mutex); 930 + ret = rtw89_wow_suspend(rtwdev, wowlan); 931 + mutex_unlock(&rtwdev->mutex); 932 + 933 + if (ret) { 934 + rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); 935 + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 936 + return 1; 937 + } 938 + 939 + return 0; 940 + } 941 + 942 + static int rtw89_ops_resume(struct ieee80211_hw *hw) 943 + { 944 + struct rtw89_dev *rtwdev = hw->priv; 945 + int ret; 946 + 947 + mutex_lock(&rtwdev->mutex); 948 + ret = rtw89_wow_resume(rtwdev); 949 + if (ret) 950 + rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); 951 + mutex_unlock(&rtwdev->mutex); 952 + 953 + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 954 + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, 955 + RTW89_TRACK_WORK_PERIOD); 956 + 957 + return ret ? 1 : 0; 958 + } 959 + 960 + static void rtw89_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled) 961 + { 962 + struct rtw89_dev *rtwdev = hw->priv; 963 + 964 + device_set_wakeup_enable(rtwdev->dev, enabled); 965 + } 966 + #endif 967 + 920 968 const struct ieee80211_ops rtw89_ops = { 921 969 .tx = rtw89_ops_tx, 922 970 .wake_tx_queue = rtw89_ops_wake_tx_queue, ··· 1003 953 .set_sar_specs = rtw89_ops_set_sar_specs, 1004 954 .sta_rc_update = rtw89_ops_sta_rc_update, 1005 955 .set_tid_config = rtw89_ops_set_tid_config, 956 + #ifdef CONFIG_PM 957 + .suspend = rtw89_ops_suspend, 958 + .resume = rtw89_ops_resume, 959 + .set_wakeup = rtw89_ops_set_wakeup, 960 + #endif 1006 961 }; 1007 962 EXPORT_SYMBOL(rtw89_ops);
+22 -1
drivers/net/wireless/realtek/rtw89/pci.c
··· 186 186 } 187 187 } 188 188 189 + static void rtw89_pci_ctrl_txdma_fw_ch_pcie(struct rtw89_dev *rtwdev, bool enable) 190 + { 191 + const struct rtw89_pci_info *info = rtwdev->pci_info; 192 + const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1; 193 + 194 + if (enable) 195 + rtw89_write32_clr(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); 196 + else 197 + rtw89_write32_set(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); 198 + } 199 + 189 200 static bool 190 201 rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls, 191 202 struct sk_buff *new, ··· 2524 2513 2525 2514 /* disable all channels except to FW CMD channel to download firmware */ 2526 2515 rtw89_pci_ctrl_txdma_ch_pcie(rtwdev, false); 2527 - rtw89_write32_clr(rtwdev, info->dma_stop1.addr, B_AX_STOP_CH12); 2516 + rtw89_pci_ctrl_txdma_fw_ch_pcie(rtwdev, true); 2528 2517 2529 2518 /* start DMA activities */ 2530 2519 rtw89_pci_ctrl_dma_all(rtwdev, true); ··· 3782 3771 3783 3772 .recovery_start = rtw89_pci_ops_recovery_start, 3784 3773 .recovery_complete = rtw89_pci_ops_recovery_complete, 3774 + 3775 + .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_pcie, 3776 + .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_pcie, 3777 + .ctrl_trxhci = rtw89_pci_ctrl_dma_trx, 3778 + .poll_txdma_ch = rtw89_poll_txdma_ch_idle_pcie, 3779 + .clr_idx_all = rtw89_pci_clr_idx_all, 3780 + .clear = rtw89_pci_clear_resource, 3781 + .disable_intr = rtw89_pci_disable_intr_lock, 3782 + .enable_intr = rtw89_pci_enable_intr_lock, 3783 + .rst_bdram = rtw89_pci_rst_bdram_pcie, 3785 3784 }; 3786 3785 3787 3786 int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+1 -1
drivers/net/wireless/realtek/rtw89/ps.c
··· 59 59 rtw89_mac_power_mode_change(rtwdev, enter); 60 60 } 61 61 62 - static void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 62 + void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 63 63 { 64 64 if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) 65 65 return;
+1
drivers/net/wireless/realtek/rtw89/ps.h
··· 8 8 void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); 9 9 void rtw89_leave_lps(struct rtw89_dev *rtwdev); 10 10 void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); 11 + void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); 11 12 void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); 12 13 void rtw89_enter_ips(struct rtw89_dev *rtwdev); 13 14 void rtw89_leave_ips(struct rtw89_dev *rtwdev);
+8
drivers/net/wireless/realtek/rtw89/reg.h
··· 952 952 B_AX_STF_OQT_OVERFLOW_ERR_INT_EN | \ 953 953 B_AX_STF_OQT_UNDERFLOW_ERR_INT_EN) 954 954 955 + #define R_AX_RX_FUNCTION_STOP 0x8920 956 + #define B_AX_HDR_RX_STOP BIT(0) 957 + 955 958 #define R_AX_HCI_FC_CTRL 0x8A00 956 959 #define B_AX_HCI_FC_CH12_FULL_COND_MASK GENMASK(11, 10) 957 960 #define B_AX_HCI_FC_WP_CH811_FULL_COND_MASK GENMASK(9, 8) ··· 1573 1570 #define R_AX_ACTION_FWD0 0x9C04 1574 1571 #define TRXCFG_MPDU_PROC_ACT_FRWD 0x02A95A95 1575 1572 1573 + #define R_AX_ACTION_FWD1 0x9C08 1574 + 1576 1575 #define R_AX_TF_FWD 0x9C14 1577 1576 #define TRXCFG_MPDU_PROC_TF_FRWD 0x0000AA55 1578 1577 ··· 1585 1580 1586 1581 #define R_AX_CUT_AMSDU_CTRL 0x9C40 1587 1582 #define TRXCFG_MPDU_PROC_CUT_CTRL 0x010E05F0 1583 + 1584 + #define R_AX_WOW_CTRL 0x9C50 1585 + #define B_AX_WOW_WOWEN BIT(1) 1588 1586 1589 1587 #define R_AX_MPDU_RX_ERR_ISR 0x9CF0 1590 1588 #define R_AX_MPDU_RX_ERR_IMR 0x9CF4
+9
drivers/net/wireless/realtek/rtw89/rtw8852a.c
··· 1990 1990 rtw8852a_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); 1991 1991 } 1992 1992 1993 + #ifdef CONFIG_PM 1994 + static const struct wiphy_wowlan_support rtw_wowlan_stub_8852a = { 1995 + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, 1996 + }; 1997 + #endif 1998 + 1993 1999 static const struct rtw89_chip_ops rtw8852a_chip_ops = { 1994 2000 .enable_bb_rf = rtw89_mac_enable_bb_rf, 1995 2001 .disable_bb_rf = rtw89_mac_disable_bb_rf, ··· 2145 2139 .imr_info = &rtw8852a_imr_info, 2146 2140 .rrsr_cfgs = &rtw8852a_rrsr_cfgs, 2147 2141 .dma_ch_mask = 0, 2142 + #ifdef CONFIG_PM 2143 + .wowlan_stub = &rtw_wowlan_stub_8852a, 2144 + #endif 2148 2145 }; 2149 2146 EXPORT_SYMBOL(rtw8852a_chip_info); 2150 2147
+9
drivers/net/wireless/realtek/rtw89/rtw8852c.c
··· 2796 2796 return 0; 2797 2797 } 2798 2798 2799 + #ifdef CONFIG_PM 2800 + static const struct wiphy_wowlan_support rtw_wowlan_stub_8852c = { 2801 + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, 2802 + }; 2803 + #endif 2804 + 2799 2805 static const struct rtw89_chip_ops rtw8852c_chip_ops = { 2800 2806 .enable_bb_rf = rtw8852c_mac_enable_bb_rf, 2801 2807 .disable_bb_rf = rtw8852c_mac_disable_bb_rf, ··· 2955 2949 .imr_info = &rtw8852c_imr_info, 2956 2950 .rrsr_cfgs = &rtw8852c_rrsr_cfgs, 2957 2951 .dma_ch_mask = 0, 2952 + #ifdef CONFIG_PM 2953 + .wowlan_stub = &rtw_wowlan_stub_8852c, 2954 + #endif 2958 2955 }; 2959 2956 EXPORT_SYMBOL(rtw8852c_chip_info); 2960 2957
+633
drivers/net/wireless/realtek/rtw89/wow.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 + /* Copyright(c) 2019-2022 Realtek Corporation 3 + */ 4 + #include "cam.h" 5 + #include "core.h" 6 + #include "debug.h" 7 + #include "fw.h" 8 + #include "mac.h" 9 + #include "phy.h" 10 + #include "ps.h" 11 + #include "reg.h" 12 + #include "util.h" 13 + #include "wow.h" 14 + 15 + static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev) 16 + { 17 + __rtw89_leave_ps_mode(rtwdev); 18 + } 19 + 20 + static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev) 21 + { 22 + struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; 23 + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; 24 + 25 + __rtw89_enter_ps_mode(rtwdev, rtwvif); 26 + } 27 + 28 + static void rtw89_wow_enter_lps(struct rtw89_dev *rtwdev) 29 + { 30 + struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; 31 + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; 32 + 33 + rtw89_enter_lps(rtwdev, rtwvif); 34 + } 35 + 36 + static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev) 37 + { 38 + rtw89_leave_lps(rtwdev); 39 + } 40 + 41 + static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow) 42 + { 43 + int ret; 44 + 45 + if (enable_wow) { 46 + ret = rtw89_mac_resize_ple_rx_quota(rtwdev, true); 47 + if (ret) { 48 + rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); 49 + return ret; 50 + } 51 + rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); 52 + rtw89_write32_clr(rtwdev, R_AX_RX_FLTR_OPT, B_AX_SNIFFER_MODE); 53 + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); 54 + rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0); 55 + rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0); 56 + rtw89_write32(rtwdev, R_AX_TF_FWD, 0); 57 + rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); 58 + } else { 59 + ret = rtw89_mac_resize_ple_rx_quota(rtwdev, false); 60 + if (ret) { 61 + rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); 62 + return ret; 63 + } 64 + rtw89_write32_clr(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); 65 + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); 66 + rtw89_write32(rtwdev, R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD); 67 + rtw89_write32(rtwdev, R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD); 68 + } 69 + 70 + return 0; 71 + } 72 + 73 + static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) 74 + { 75 + enum rtw89_mac_fwd_target fwd_target = enable ? 76 + RTW89_FWD_DONT_CARE : 77 + RTW89_FWD_TO_HOST; 78 + 79 + rtw89_mac_typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0); 80 + rtw89_mac_typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0); 81 + rtw89_mac_typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0); 82 + } 83 + 84 + static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) 85 + { 86 + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; 87 + struct cfg80211_wowlan_nd_info nd_info; 88 + struct cfg80211_wowlan_wakeup wakeup = { 89 + .pattern_idx = -1, 90 + }; 91 + u32 wow_reason_reg; 92 + u8 reason; 93 + 94 + if (chip_id == RTL8852A || chip_id == RTL8852B) 95 + wow_reason_reg = R_AX_C2HREG_DATA3 + 3; 96 + else 97 + wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3; 98 + 99 + reason = rtw89_read8(rtwdev, wow_reason_reg); 100 + 101 + switch (reason) { 102 + case RTW89_WOW_RSN_RX_DEAUTH: 103 + wakeup.disconnect = true; 104 + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx deauth\n"); 105 + break; 106 + case RTW89_WOW_RSN_DISCONNECT: 107 + wakeup.disconnect = true; 108 + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: AP is off\n"); 109 + break; 110 + case RTW89_WOW_RSN_RX_MAGIC_PKT: 111 + wakeup.magic_pkt = true; 112 + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx magic packet\n"); 113 + break; 114 + case RTW89_WOW_RSN_RX_GTK_REKEY: 115 + wakeup.gtk_rekey_failure = true; 116 + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx gtk rekey\n"); 117 + break; 118 + case RTW89_WOW_RSN_RX_PATTERN_MATCH: 119 + /* Current firmware and driver don't report pattern index 120 + * Use pattern_idx to 0 defaultly. 121 + */ 122 + wakeup.pattern_idx = 0; 123 + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx pattern match packet\n"); 124 + break; 125 + case RTW89_WOW_RSN_RX_NLO: 126 + /* Current firmware and driver don't report ssid index. 127 + * Use 0 for n_matches based on its comment. 128 + */ 129 + nd_info.n_matches = 0; 130 + wakeup.net_detect = &nd_info; 131 + rtw89_debug(rtwdev, RTW89_DBG_WOW, "Rx NLO\n"); 132 + break; 133 + default: 134 + rtw89_warn(rtwdev, "Unknown wakeup reason %x\n", reason); 135 + ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL, 136 + GFP_KERNEL); 137 + return; 138 + } 139 + 140 + ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup, 141 + GFP_KERNEL); 142 + } 143 + 144 + static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 145 + { 146 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 147 + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 148 + 149 + /* Current wowlan function support setting of only one STATION vif. 150 + * So when one suitable vif is found, stop the iteration. 151 + */ 152 + if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION) 153 + return; 154 + 155 + switch (rtwvif->net_type) { 156 + case RTW89_NET_TYPE_INFRA: 157 + rtw_wow->wow_vif = vif; 158 + break; 159 + case RTW89_NET_TYPE_NO_LINK: 160 + default: 161 + break; 162 + } 163 + } 164 + 165 + static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev) 166 + { 167 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 168 + 169 + rtw_wow->wow_vif = NULL; 170 + rtw89_core_release_all_bits_map(rtw_wow->flags, RTW89_WOW_FLAG_NUM); 171 + rtw_wow->pattern_cnt = 0; 172 + } 173 + 174 + static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev, 175 + struct cfg80211_wowlan *wowlan) 176 + { 177 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 178 + struct rtw89_vif *rtwvif; 179 + 180 + if (wowlan->disconnect) 181 + set_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags); 182 + if (wowlan->magic_pkt) 183 + set_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags); 184 + 185 + rtw89_for_each_rtwvif(rtwdev, rtwvif) 186 + rtw89_wow_vif_iter(rtwdev, rtwvif); 187 + 188 + if (!rtw_wow->wow_vif) 189 + return -EPERM; 190 + 191 + return 0; 192 + } 193 + 194 + static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) 195 + { 196 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 197 + struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; 198 + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; 199 + struct ieee80211_sta *wow_sta; 200 + struct rtw89_sta *rtwsta = NULL; 201 + bool is_conn = true; 202 + int ret; 203 + 204 + wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); 205 + if (wow_sta) 206 + rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; 207 + else 208 + is_conn = false; 209 + 210 + if (wow) { 211 + if (rtw_wow->pattern_cnt) 212 + rtwvif->wowlan_pattern = true; 213 + if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) 214 + rtwvif->wowlan_magic = true; 215 + } else { 216 + rtwvif->wowlan_pattern = false; 217 + rtwvif->wowlan_magic = false; 218 + } 219 + 220 + ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow); 221 + if (ret) { 222 + rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n"); 223 + return ret; 224 + } 225 + 226 + if (wow) { 227 + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); 228 + if (ret) { 229 + rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", 230 + ret); 231 + return ret; 232 + } 233 + } 234 + 235 + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); 236 + if (ret) { 237 + rtw89_warn(rtwdev, "failed to send h2c join info\n"); 238 + return ret; 239 + } 240 + 241 + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); 242 + if (ret) { 243 + rtw89_warn(rtwdev, "failed to send h2c cam\n"); 244 + return ret; 245 + } 246 + 247 + ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow); 248 + if (ret) { 249 + rtw89_err(rtwdev, "failed to fw wow global\n"); 250 + return ret; 251 + } 252 + 253 + return 0; 254 + } 255 + 256 + static int rtw89_wow_check_fw_status(struct rtw89_dev *rtwdev, bool wow_enable) 257 + { 258 + u8 polling; 259 + int ret; 260 + 261 + ret = read_poll_timeout_atomic(rtw89_read8_mask, polling, 262 + wow_enable == !!polling, 263 + 50, 50000, false, rtwdev, 264 + R_AX_WOW_CTRL, B_AX_WOW_WOWEN); 265 + if (ret) 266 + rtw89_err(rtwdev, "failed to check wow status %s\n", 267 + wow_enable ? "enabled" : "disabled"); 268 + return ret; 269 + } 270 + 271 + static void rtw89_wow_release_pkt_list(struct rtw89_dev *rtwdev) 272 + { 273 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 274 + struct list_head *pkt_list = &rtw_wow->pkt_list; 275 + struct rtw89_pktofld_info *info, *tmp; 276 + 277 + list_for_each_entry_safe(info, tmp, pkt_list, list) { 278 + rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); 279 + rtw89_core_release_bit_map(rtwdev->pkt_offload, 280 + info->id); 281 + list_del(&info->list); 282 + kfree(info); 283 + } 284 + } 285 + 286 + static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) 287 + { 288 + enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL; 289 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 290 + struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; 291 + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; 292 + struct ieee80211_sta *wow_sta; 293 + struct rtw89_sta *rtwsta = NULL; 294 + bool is_conn = true; 295 + int ret; 296 + 297 + rtw89_hci_disable_intr(rtwdev); 298 + 299 + wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); 300 + if (wow_sta) 301 + rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; 302 + else 303 + is_conn = false; 304 + 305 + ret = rtw89_fw_download(rtwdev, fw_type); 306 + if (ret) { 307 + rtw89_warn(rtwdev, "download fw failed\n"); 308 + return ret; 309 + } 310 + 311 + rtw89_phy_init_rf_reg(rtwdev, true); 312 + 313 + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, 314 + RTW89_ROLE_FW_RESTORE); 315 + if (ret) { 316 + rtw89_warn(rtwdev, "failed to send h2c role maintain\n"); 317 + return ret; 318 + } 319 + 320 + ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); 321 + if (ret) { 322 + rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n"); 323 + return ret; 324 + } 325 + 326 + if (!is_conn) 327 + rtw89_cam_reset_keys(rtwdev); 328 + 329 + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); 330 + if (ret) { 331 + rtw89_warn(rtwdev, "failed to send h2c join info\n"); 332 + return ret; 333 + } 334 + 335 + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); 336 + if (ret) { 337 + rtw89_warn(rtwdev, "failed to send h2c cam\n"); 338 + return ret; 339 + } 340 + 341 + if (is_conn) { 342 + rtw89_phy_ra_assoc(rtwdev, wow_sta); 343 + rtw89_phy_set_bss_color(rtwdev, wow_vif); 344 + rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif); 345 + } 346 + 347 + rtw89_mac_hw_mgnt_sec(rtwdev, wow); 348 + rtw89_hci_enable_intr(rtwdev); 349 + 350 + return 0; 351 + } 352 + 353 + static int rtw89_wow_enable_trx_pre(struct rtw89_dev *rtwdev) 354 + { 355 + int ret; 356 + 357 + rtw89_hci_ctrl_txdma_ch(rtwdev, false); 358 + rtw89_hci_ctrl_txdma_fw_ch(rtwdev, true); 359 + 360 + rtw89_mac_ptk_drop_by_band_and_wait(rtwdev, RTW89_MAC_0); 361 + 362 + ret = rtw89_hci_poll_txdma_ch(rtwdev); 363 + if (ret) { 364 + rtw89_err(rtwdev, "txdma ch busy\n"); 365 + return ret; 366 + } 367 + rtw89_wow_set_rx_filter(rtwdev, true); 368 + 369 + ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); 370 + if (ret) { 371 + rtw89_err(rtwdev, "cfg ppdu status\n"); 372 + return ret; 373 + } 374 + 375 + return 0; 376 + } 377 + 378 + static int rtw89_wow_enable_trx_post(struct rtw89_dev *rtwdev) 379 + { 380 + int ret; 381 + 382 + rtw89_hci_disable_intr(rtwdev); 383 + rtw89_hci_ctrl_trxhci(rtwdev, false); 384 + 385 + ret = rtw89_hci_poll_txdma_ch(rtwdev); 386 + if (ret) { 387 + rtw89_err(rtwdev, "failed to poll txdma ch idle pcie\n"); 388 + return ret; 389 + } 390 + 391 + ret = rtw89_wow_config_mac(rtwdev, true); 392 + if (ret) { 393 + rtw89_err(rtwdev, "failed to config mac\n"); 394 + return ret; 395 + } 396 + 397 + rtw89_wow_set_rx_filter(rtwdev, false); 398 + rtw89_hci_reset(rtwdev); 399 + 400 + return 0; 401 + } 402 + 403 + static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev) 404 + { 405 + int ret; 406 + 407 + rtw89_hci_clr_idx_all(rtwdev); 408 + 409 + ret = rtw89_hci_rst_bdram(rtwdev); 410 + if (ret) { 411 + rtw89_warn(rtwdev, "reset bdram busy\n"); 412 + return ret; 413 + } 414 + 415 + rtw89_hci_ctrl_trxhci(rtwdev, true); 416 + rtw89_hci_ctrl_txdma_ch(rtwdev, true); 417 + 418 + ret = rtw89_wow_config_mac(rtwdev, false); 419 + if (ret) { 420 + rtw89_err(rtwdev, "failed to config mac\n"); 421 + return ret; 422 + } 423 + rtw89_hci_enable_intr(rtwdev); 424 + 425 + return 0; 426 + } 427 + 428 + static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev) 429 + { 430 + int ret; 431 + 432 + ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); 433 + if (ret) 434 + rtw89_err(rtwdev, "cfg ppdu status\n"); 435 + 436 + return ret; 437 + } 438 + 439 + static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) 440 + { 441 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 442 + struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; 443 + int ret; 444 + 445 + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true); 446 + if (ret) { 447 + rtw89_err(rtwdev, "wow: failed to enable keep alive\n"); 448 + return ret; 449 + } 450 + 451 + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true); 452 + if (ret) { 453 + rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n"); 454 + goto out; 455 + } 456 + 457 + ret = rtw89_wow_cfg_wake(rtwdev, true); 458 + if (ret) { 459 + rtw89_err(rtwdev, "wow: failed to config wake\n"); 460 + goto out; 461 + } 462 + 463 + ret = rtw89_wow_check_fw_status(rtwdev, true); 464 + if (ret) { 465 + rtw89_err(rtwdev, "wow: failed to check enable fw ready\n"); 466 + goto out; 467 + } 468 + 469 + out: 470 + return ret; 471 + } 472 + 473 + static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) 474 + { 475 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 476 + struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; 477 + int ret; 478 + 479 + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false); 480 + if (ret) { 481 + rtw89_err(rtwdev, "wow: failed to disable keep alive\n"); 482 + goto out; 483 + } 484 + 485 + rtw89_wow_release_pkt_list(rtwdev); 486 + 487 + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false); 488 + if (ret) { 489 + rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n"); 490 + goto out; 491 + } 492 + 493 + ret = rtw89_wow_cfg_wake(rtwdev, false); 494 + if (ret) { 495 + rtw89_err(rtwdev, "wow: failed to disable config wake\n"); 496 + goto out; 497 + } 498 + 499 + ret = rtw89_wow_check_fw_status(rtwdev, false); 500 + if (ret) { 501 + rtw89_err(rtwdev, "wow: failed to check disable fw ready\n"); 502 + goto out; 503 + } 504 + 505 + out: 506 + return ret; 507 + } 508 + 509 + static int rtw89_wow_enable(struct rtw89_dev *rtwdev) 510 + { 511 + int ret; 512 + 513 + set_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); 514 + 515 + ret = rtw89_wow_enable_trx_pre(rtwdev); 516 + if (ret) { 517 + rtw89_err(rtwdev, "wow: failed to enable trx_pre\n"); 518 + goto out; 519 + } 520 + 521 + rtw89_wow_swap_fw(rtwdev, true); 522 + if (ret) { 523 + rtw89_err(rtwdev, "wow: failed to swap to wow fw\n"); 524 + goto out; 525 + } 526 + 527 + rtw89_wow_fw_start(rtwdev); 528 + if (ret) { 529 + rtw89_err(rtwdev, "wow: failed to let wow fw start\n"); 530 + goto out; 531 + } 532 + 533 + rtw89_wow_enter_lps(rtwdev); 534 + 535 + rtw89_wow_enable_trx_post(rtwdev); 536 + if (ret) { 537 + rtw89_err(rtwdev, "wow: failed to enable trx_post\n"); 538 + goto out; 539 + } 540 + 541 + return 0; 542 + 543 + out: 544 + clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); 545 + return ret; 546 + } 547 + 548 + static int rtw89_wow_disable(struct rtw89_dev *rtwdev) 549 + { 550 + int ret; 551 + 552 + ret = rtw89_wow_disable_trx_pre(rtwdev); 553 + if (ret) { 554 + rtw89_err(rtwdev, "wow: failed to disable trx_pre\n"); 555 + goto out; 556 + } 557 + 558 + rtw89_wow_leave_lps(rtwdev); 559 + 560 + ret = rtw89_wow_fw_stop(rtwdev); 561 + if (ret) { 562 + rtw89_err(rtwdev, "wow: failed to swap to normal fw\n"); 563 + goto out; 564 + } 565 + 566 + ret = rtw89_wow_swap_fw(rtwdev, false); 567 + if (ret) { 568 + rtw89_err(rtwdev, "wow: failed to disable trx_post\n"); 569 + goto out; 570 + } 571 + 572 + ret = rtw89_wow_disable_trx_post(rtwdev); 573 + if (ret) { 574 + rtw89_err(rtwdev, "wow: failed to disable trx_pre\n"); 575 + goto out; 576 + } 577 + 578 + out: 579 + clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); 580 + return ret; 581 + } 582 + 583 + int rtw89_wow_resume(struct rtw89_dev *rtwdev) 584 + { 585 + int ret; 586 + 587 + if (!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) { 588 + rtw89_err(rtwdev, "wow is not enabled\n"); 589 + ret = -EPERM; 590 + goto out; 591 + } 592 + 593 + if (!rtw89_mac_get_power_state(rtwdev)) { 594 + rtw89_err(rtwdev, "chip is no power when resume\n"); 595 + ret = -EPERM; 596 + goto out; 597 + } 598 + 599 + rtw89_wow_leave_deep_ps(rtwdev); 600 + 601 + rtw89_wow_show_wakeup_reason(rtwdev); 602 + 603 + ret = rtw89_wow_disable(rtwdev); 604 + if (ret) 605 + rtw89_err(rtwdev, "failed to disable wow\n"); 606 + 607 + out: 608 + rtw89_wow_clear_wakeups(rtwdev); 609 + return ret; 610 + } 611 + 612 + int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan) 613 + { 614 + int ret; 615 + 616 + ret = rtw89_wow_set_wakeups(rtwdev, wowlan); 617 + if (ret) { 618 + rtw89_err(rtwdev, "failed to set wakeup event\n"); 619 + return ret; 620 + } 621 + 622 + rtw89_wow_leave_lps(rtwdev); 623 + 624 + ret = rtw89_wow_enable(rtwdev); 625 + if (ret) { 626 + rtw89_err(rtwdev, "failed to enable wow\n"); 627 + return ret; 628 + } 629 + 630 + rtw89_wow_enter_deep_ps(rtwdev); 631 + 632 + return 0; 633 + }
+21
drivers/net/wireless/realtek/rtw89/wow.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 2 + /* Copyright(c) 2019-2022 Realtek Corporation 3 + */ 4 + 5 + #ifndef __RTW89_WOW_H__ 6 + #define __RTW89_WOW_H__ 7 + 8 + enum rtw89_wake_reason { 9 + RTW89_WOW_RSN_RX_PTK_REKEY = 0x1, 10 + RTW89_WOW_RSN_RX_GTK_REKEY = 0x2, 11 + RTW89_WOW_RSN_RX_DEAUTH = 0x8, 12 + RTW89_WOW_RSN_DISCONNECT = 0x10, 13 + RTW89_WOW_RSN_RX_MAGIC_PKT = 0x21, 14 + RTW89_WOW_RSN_RX_PATTERN_MATCH = 0x23, 15 + RTW89_WOW_RSN_RX_NLO = 0x55, 16 + }; 17 + 18 + int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); 19 + int rtw89_wow_resume(struct rtw89_dev *rtwdev); 20 + 21 + #endif