LCOV - code coverage report
Current view: top level - drivers/net/wireless/realtek/rtw88 - ps.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 120 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 14 0.0 %
Branches: 0 34 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
       2                 :            : /* Copyright(c) 2018-2019  Realtek Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "main.h"
       6                 :            : #include "reg.h"
       7                 :            : #include "fw.h"
       8                 :            : #include "ps.h"
       9                 :            : #include "mac.h"
      10                 :            : #include "coex.h"
      11                 :            : #include "debug.h"
      12                 :            : 
      13                 :          0 : static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
      14                 :            : {
      15                 :          0 :         int ret;
      16                 :            : 
      17                 :          0 :         ret = rtw_core_start(rtwdev);
      18         [ #  # ]:          0 :         if (ret)
      19                 :          0 :                 rtw_err(rtwdev, "leave idle state failed\n");
      20                 :            : 
      21                 :          0 :         rtw_set_channel(rtwdev);
      22                 :          0 :         clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
      23                 :            : 
      24                 :          0 :         return ret;
      25                 :            : }
      26                 :            : 
      27                 :          0 : int rtw_enter_ips(struct rtw_dev *rtwdev)
      28                 :            : {
      29                 :          0 :         set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
      30                 :            : 
      31                 :          0 :         rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
      32                 :            : 
      33                 :          0 :         rtw_core_stop(rtwdev);
      34                 :          0 :         rtw_hci_link_ps(rtwdev, true);
      35                 :            : 
      36                 :          0 :         return 0;
      37                 :            : }
      38                 :            : 
      39                 :          0 : static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
      40                 :            :                                       struct ieee80211_vif *vif)
      41                 :            : {
      42                 :          0 :         struct rtw_dev *rtwdev = data;
      43                 :          0 :         struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
      44                 :          0 :         u32 config = ~0;
      45                 :            : 
      46                 :          0 :         rtw_vif_port_config(rtwdev, rtwvif, config);
      47                 :          0 : }
      48                 :            : 
      49                 :          0 : int rtw_leave_ips(struct rtw_dev *rtwdev)
      50                 :            : {
      51                 :          0 :         int ret;
      52                 :            : 
      53                 :          0 :         rtw_hci_link_ps(rtwdev, false);
      54                 :            : 
      55                 :          0 :         ret = rtw_ips_pwr_up(rtwdev);
      56         [ #  # ]:          0 :         if (ret) {
      57                 :          0 :                 rtw_err(rtwdev, "failed to leave ips state\n");
      58                 :          0 :                 return ret;
      59                 :            :         }
      60                 :            : 
      61                 :          0 :         rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
      62                 :            : 
      63                 :          0 :         rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
      64                 :            : 
      65                 :          0 :         return 0;
      66                 :            : }
      67                 :            : 
      68                 :          0 : void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
      69                 :            : {
      70                 :          0 :         u8 request, confirm, polling;
      71                 :          0 :         u8 polling_cnt;
      72                 :          0 :         u8 retry_cnt = 0;
      73                 :            : 
      74         [ #  # ]:          0 :         for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) {
      75                 :          0 :                 request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
      76                 :          0 :                 confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
      77                 :            : 
      78                 :            :                 /* toggle to request power mode, others remain 0 */
      79                 :          0 :                 request ^= request | BIT_RPWM_TOGGLE;
      80         [ #  # ]:          0 :                 if (!enter) {
      81                 :          0 :                         request |= POWER_MODE_ACK;
      82                 :            :                 } else {
      83                 :          0 :                         request |= POWER_MODE_LCLK;
      84         [ #  # ]:          0 :                         if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
      85                 :          0 :                                 request |= POWER_MODE_PG;
      86                 :            :                 }
      87                 :            : 
      88                 :          0 :                 rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
      89                 :            : 
      90         [ #  # ]:          0 :                 if (enter)
      91                 :            :                         return;
      92                 :            : 
      93                 :            :                 /* check confirm power mode has left power save state */
      94         [ #  # ]:          0 :                 for (polling_cnt = 0; polling_cnt < 50; polling_cnt++) {
      95                 :          0 :                         polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
      96         [ #  # ]:          0 :                         if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
      97                 :            :                                 return;
      98                 :          0 :                         udelay(100);
      99                 :            :                 }
     100                 :            : 
     101                 :            :                 /* in case of fw/hw missed the request, retry */
     102                 :          0 :                 rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n",
     103                 :            :                          retry_cnt);
     104                 :            :         }
     105                 :            : 
     106                 :            :         /* Hit here means that driver failed to change hardware power mode to
     107                 :            :          * active state after retry 3 times. If the power state is locked at
     108                 :            :          * Deep sleep, most of the hardware circuits is not working, even
     109                 :            :          * register read/write. It should be treated as fatal error and
     110                 :            :          * requires an entire analysis about the firmware/hardware
     111                 :            :          */
     112                 :          0 :         WARN(1, "Hardware power state locked\n");
     113                 :            : }
     114                 :            : EXPORT_SYMBOL(rtw_power_mode_change);
     115                 :            : 
     116                 :          0 : static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
     117                 :            : {
     118                 :          0 :         rtw_hci_deep_ps(rtwdev, false);
     119                 :          0 : }
     120                 :            : 
     121                 :          0 : static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
     122                 :            : {
     123                 :          0 :         int i;
     124                 :            : 
     125                 :            :         /* Driver needs to wait for firmware to leave LPS state
     126                 :            :          * successfully. Firmware will send null packet to inform AP,
     127                 :            :          * and see if AP sends an ACK back, then firmware will restore
     128                 :            :          * the REG_TCR register.
     129                 :            :          *
     130                 :            :          * If driver does not wait for firmware, null packet with
     131                 :            :          * PS bit could be sent due to incorrect REG_TCR setting.
     132                 :            :          *
     133                 :            :          * In our test, 100ms should be enough for firmware to finish
     134                 :            :          * the flow. If REG_TCR Register is still incorrect after 100ms,
     135                 :            :          * just modify it directly, and throw a warn message.
     136                 :            :          */
     137         [ #  # ]:          0 :         for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
     138         [ #  # ]:          0 :                 if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
     139                 :            :                         return;
     140                 :          0 :                 msleep(20);
     141                 :            :         }
     142                 :            : 
     143                 :          0 :         rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
     144                 :          0 :         rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
     145                 :            : }
     146                 :            : 
     147                 :          0 : static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
     148                 :            : {
     149                 :          0 :         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
     150                 :            : 
     151                 :          0 :         conf->state = RTW_ALL_ON;
     152                 :          0 :         conf->awake_interval = 1;
     153                 :          0 :         conf->rlbm = 0;
     154                 :          0 :         conf->smart_ps = 0;
     155                 :            : 
     156                 :          0 :         rtw_hci_link_ps(rtwdev, false);
     157                 :          0 :         rtw_fw_set_pwr_mode(rtwdev);
     158                 :          0 :         rtw_fw_leave_lps_state_check(rtwdev);
     159                 :            : 
     160                 :          0 :         clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
     161                 :            : 
     162                 :          0 :         rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
     163                 :          0 : }
     164                 :            : 
     165                 :          0 : static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
     166                 :            : {
     167         [ #  # ]:          0 :         if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE)
     168                 :            :                 return;
     169                 :            : 
     170         [ #  # ]:          0 :         if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
     171                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_PS,
     172                 :            :                         "Should enter LPS before entering deep PS\n");
     173                 :          0 :                 return;
     174                 :            :         }
     175                 :            : 
     176         [ #  # ]:          0 :         if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
     177                 :          0 :                 rtw_fw_set_pg_info(rtwdev);
     178                 :            : 
     179                 :          0 :         rtw_hci_deep_ps(rtwdev, true);
     180                 :            : }
     181                 :            : 
     182                 :          0 : static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
     183                 :            : {
     184                 :          0 :         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
     185                 :            : 
     186                 :          0 :         conf->state = RTW_RF_OFF;
     187                 :          0 :         conf->awake_interval = 1;
     188                 :          0 :         conf->rlbm = 1;
     189                 :          0 :         conf->smart_ps = 2;
     190                 :            : 
     191                 :          0 :         rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
     192                 :            : 
     193                 :          0 :         rtw_fw_set_pwr_mode(rtwdev);
     194                 :          0 :         rtw_hci_link_ps(rtwdev, true);
     195                 :            : 
     196                 :          0 :         set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
     197                 :          0 : }
     198                 :            : 
     199                 :          0 : static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
     200                 :            : {
     201                 :          0 :         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
     202                 :            : 
     203         [ #  # ]:          0 :         if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
     204                 :            :                 return;
     205                 :            : 
     206                 :          0 :         conf->mode = RTW_MODE_LPS;
     207                 :          0 :         conf->port_id = port_id;
     208                 :            : 
     209                 :          0 :         rtw_enter_lps_core(rtwdev);
     210                 :            : }
     211                 :            : 
     212                 :          0 : static void __rtw_leave_lps(struct rtw_dev *rtwdev)
     213                 :            : {
     214                 :          0 :         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
     215                 :            : 
     216         [ #  # ]:          0 :         if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
     217                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_PS,
     218                 :            :                         "Should leave deep PS before leaving LPS\n");
     219                 :          0 :                 __rtw_leave_lps_deep(rtwdev);
     220                 :            :         }
     221                 :            : 
     222         [ #  # ]:          0 :         if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
     223                 :            :                 return;
     224                 :            : 
     225                 :          0 :         conf->mode = RTW_MODE_ACTIVE;
     226                 :            : 
     227                 :          0 :         rtw_leave_lps_core(rtwdev);
     228                 :            : }
     229                 :            : 
     230                 :          0 : void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
     231                 :            : {
     232                 :          0 :         lockdep_assert_held(&rtwdev->mutex);
     233                 :            : 
     234         [ #  # ]:          0 :         if (rtwdev->coex.stat.wl_force_lps_ctrl)
     235                 :            :                 return;
     236                 :            : 
     237                 :          0 :         __rtw_enter_lps(rtwdev, port_id);
     238                 :          0 :         __rtw_enter_lps_deep(rtwdev);
     239                 :            : }
     240                 :            : 
     241                 :          0 : void rtw_leave_lps(struct rtw_dev *rtwdev)
     242                 :            : {
     243                 :          0 :         lockdep_assert_held(&rtwdev->mutex);
     244                 :            : 
     245                 :          0 :         __rtw_leave_lps_deep(rtwdev);
     246                 :          0 :         __rtw_leave_lps(rtwdev);
     247                 :          0 : }
     248                 :            : 
     249                 :          0 : void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
     250                 :            : {
     251                 :          0 :         lockdep_assert_held(&rtwdev->mutex);
     252                 :            : 
     253                 :          0 :         __rtw_leave_lps_deep(rtwdev);
     254                 :          0 : }

Generated by: LCOV version 1.14