cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ps.c (4066B)


      1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
      2/* Copyright(c) 2019-2020  Realtek Corporation
      3 */
      4
      5#include "coex.h"
      6#include "core.h"
      7#include "debug.h"
      8#include "fw.h"
      9#include "mac.h"
     10#include "ps.h"
     11#include "reg.h"
     12#include "util.h"
     13
     14static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid)
     15{
     16	u32 pwr_en_bit = 0xE;
     17	u32 chk_msk = pwr_en_bit << (4 * macid);
     18	u32 polling;
     19	int ret;
     20
     21	ret = read_poll_timeout_atomic(rtw89_read32_mask, polling, !polling,
     22				       1000, 50000, false, rtwdev,
     23				       R_AX_PPWRBIT_SETTING, chk_msk);
     24	if (ret) {
     25		rtw89_info(rtwdev, "rtw89: failed to leave lps state\n");
     26		return -EBUSY;
     27	}
     28
     29	return 0;
     30}
     31
     32static void rtw89_ps_power_mode_change_with_hci(struct rtw89_dev *rtwdev,
     33						bool enter)
     34{
     35	ieee80211_stop_queues(rtwdev->hw);
     36	rtwdev->hci.paused = true;
     37	flush_work(&rtwdev->txq_work);
     38	ieee80211_wake_queues(rtwdev->hw);
     39
     40	rtw89_hci_pause(rtwdev, true);
     41	rtw89_mac_power_mode_change(rtwdev, enter);
     42	rtw89_hci_switch_mode(rtwdev, enter);
     43	rtw89_hci_pause(rtwdev, false);
     44
     45	rtwdev->hci.paused = false;
     46
     47	if (!enter) {
     48		local_bh_disable();
     49		napi_schedule(&rtwdev->napi);
     50		local_bh_enable();
     51	}
     52}
     53
     54static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter)
     55{
     56	if (rtwdev->chip->low_power_hci_modes & BIT(rtwdev->ps_mode))
     57		rtw89_ps_power_mode_change_with_hci(rtwdev, enter);
     58	else
     59		rtw89_mac_power_mode_change(rtwdev, enter);
     60}
     61
     62static void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev)
     63{
     64	if (!rtwdev->ps_mode)
     65		return;
     66
     67	if (test_and_set_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
     68		return;
     69
     70	rtw89_ps_power_mode_change(rtwdev, true);
     71}
     72
     73void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
     74{
     75	if (!rtwdev->ps_mode)
     76		return;
     77
     78	if (test_and_clear_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
     79		rtw89_ps_power_mode_change(rtwdev, false);
     80}
     81
     82static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id)
     83{
     84	struct rtw89_lps_parm lps_param = {
     85		.macid = mac_id,
     86		.psmode = RTW89_MAC_AX_PS_MODE_LEGACY,
     87		.lastrpwm = RTW89_LAST_RPWM_PS,
     88	};
     89
     90	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL);
     91	rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
     92}
     93
     94static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, u8 mac_id)
     95{
     96	struct rtw89_lps_parm lps_param = {
     97		.macid = mac_id,
     98		.psmode = RTW89_MAC_AX_PS_MODE_ACTIVE,
     99		.lastrpwm = RTW89_LAST_RPWM_ACTIVE,
    100	};
    101
    102	rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
    103	rtw89_fw_leave_lps_check(rtwdev, 0);
    104	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
    105}
    106
    107void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
    108{
    109	lockdep_assert_held(&rtwdev->mutex);
    110
    111	__rtw89_leave_ps_mode(rtwdev);
    112}
    113
    114void rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id)
    115{
    116	lockdep_assert_held(&rtwdev->mutex);
    117
    118	if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags))
    119		return;
    120
    121	__rtw89_enter_lps(rtwdev, mac_id);
    122	__rtw89_enter_ps_mode(rtwdev);
    123}
    124
    125static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
    126{
    127	if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION)
    128		return;
    129
    130	__rtw89_leave_ps_mode(rtwdev);
    131	__rtw89_leave_lps(rtwdev, rtwvif->mac_id);
    132}
    133
    134void rtw89_leave_lps(struct rtw89_dev *rtwdev)
    135{
    136	struct rtw89_vif *rtwvif;
    137
    138	lockdep_assert_held(&rtwdev->mutex);
    139
    140	if (!test_and_clear_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags))
    141		return;
    142
    143	rtw89_for_each_rtwvif(rtwdev, rtwvif)
    144		rtw89_leave_lps_vif(rtwdev, rtwvif);
    145}
    146
    147void rtw89_enter_ips(struct rtw89_dev *rtwdev)
    148{
    149	struct rtw89_vif *rtwvif;
    150
    151	set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
    152
    153	rtw89_for_each_rtwvif(rtwdev, rtwvif)
    154		rtw89_mac_vif_deinit(rtwdev, rtwvif);
    155
    156	rtw89_core_stop(rtwdev);
    157}
    158
    159void rtw89_leave_ips(struct rtw89_dev *rtwdev)
    160{
    161	struct rtw89_vif *rtwvif;
    162	int ret;
    163
    164	ret = rtw89_core_start(rtwdev);
    165	if (ret)
    166		rtw89_err(rtwdev, "failed to leave idle state\n");
    167
    168	rtw89_set_channel(rtwdev);
    169
    170	rtw89_for_each_rtwvif(rtwdev, rtwvif)
    171		rtw89_mac_vif_init(rtwdev, rtwvif);
    172
    173	clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
    174}
    175
    176void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl)
    177{
    178	if (btc_ctrl)
    179		rtw89_leave_lps(rtwdev);
    180}