LCOV - code coverage report
Current view: top level - drivers/net/wireless/realtek/rtw88 - wow.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 475 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 36 0.0 %
Branches: 0 185 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 "fw.h"
       7                 :            : #include "wow.h"
       8                 :            : #include "reg.h"
       9                 :            : #include "debug.h"
      10                 :            : #include "mac.h"
      11                 :            : #include "ps.h"
      12                 :            : 
      13                 :          0 : static void rtw_wow_show_wakeup_reason(struct rtw_dev *rtwdev)
      14                 :            : {
      15                 :          0 :         u8 reason;
      16                 :            : 
      17                 :          0 :         reason = rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON);
      18                 :            : 
      19         [ #  # ]:          0 :         if (reason == RTW_WOW_RSN_RX_DEAUTH)
      20                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx deauth\n");
      21         [ #  # ]:          0 :         else if (reason == RTW_WOW_RSN_DISCONNECT)
      22                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: AP is off\n");
      23         [ #  # ]:          0 :         else if (reason == RTW_WOW_RSN_RX_MAGIC_PKT)
      24                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx magic packet\n");
      25         [ #  # ]:          0 :         else if (reason == RTW_WOW_RSN_RX_GTK_REKEY)
      26                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx gtk rekey\n");
      27         [ #  # ]:          0 :         else if (reason == RTW_WOW_RSN_RX_PTK_REKEY)
      28                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx ptk rekey\n");
      29         [ #  # ]:          0 :         else if (reason == RTW_WOW_RSN_RX_PATTERN_MATCH)
      30                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx pattern match packet\n");
      31         [ #  # ]:          0 :         else if (reason == RTW_WOW_RSN_RX_NLO)
      32                 :          0 :                 rtw_dbg(rtwdev, RTW_DBG_WOW, "Rx NLO\n");
      33                 :            :         else
      34                 :          0 :                 rtw_warn(rtwdev, "Unknown wakeup reason %x\n", reason);
      35                 :          0 : }
      36                 :            : 
      37                 :          0 : static void rtw_wow_pattern_write_cam(struct rtw_dev *rtwdev, u8 addr,
      38                 :            :                                       u32 wdata)
      39                 :            : {
      40                 :          0 :         rtw_write32(rtwdev, REG_WKFMCAM_RWD, wdata);
      41                 :          0 :         rtw_write32(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 |
      42                 :          0 :                     BIT_WKFCAM_WE | BIT_WKFCAM_ADDR_V2(addr));
      43                 :            : 
      44         [ #  # ]:          0 :         if (!check_hw_ready(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1, 0))
      45                 :          0 :                 rtw_err(rtwdev, "failed to write pattern cam\n");
      46                 :          0 : }
      47                 :            : 
      48                 :          0 : static void rtw_wow_pattern_write_cam_ent(struct rtw_dev *rtwdev, u8 id,
      49                 :            :                                           struct rtw_wow_pattern *rtw_pattern)
      50                 :            : {
      51                 :          0 :         int i;
      52                 :          0 :         u8 addr;
      53                 :          0 :         u32 wdata;
      54                 :            : 
      55         [ #  # ]:          0 :         for (i = 0; i < RTW_MAX_PATTERN_MASK_SIZE / 4; i++) {
      56                 :          0 :                 addr = (id << 3) + i;
      57                 :          0 :                 wdata = rtw_pattern->mask[i * 4];
      58                 :          0 :                 wdata |= rtw_pattern->mask[i * 4 + 1] << 8;
      59                 :          0 :                 wdata |= rtw_pattern->mask[i * 4 + 2] << 16;
      60                 :          0 :                 wdata |= rtw_pattern->mask[i * 4 + 3] << 24;
      61                 :          0 :                 rtw_wow_pattern_write_cam(rtwdev, addr, wdata);
      62                 :            :         }
      63                 :            : 
      64                 :          0 :         wdata = rtw_pattern->crc;
      65                 :          0 :         addr = (id << 3) + RTW_MAX_PATTERN_MASK_SIZE / 4;
      66                 :            : 
      67   [ #  #  #  # ]:          0 :         switch (rtw_pattern->type) {
      68                 :          0 :         case RTW_PATTERN_BROADCAST:
      69                 :          0 :                 wdata |= BIT_WKFMCAM_BC | BIT_WKFMCAM_VALID;
      70                 :          0 :                 break;
      71                 :          0 :         case RTW_PATTERN_MULTICAST:
      72                 :          0 :                 wdata |= BIT_WKFMCAM_MC | BIT_WKFMCAM_VALID;
      73                 :          0 :                 break;
      74                 :          0 :         case RTW_PATTERN_UNICAST:
      75                 :          0 :                 wdata |= BIT_WKFMCAM_UC | BIT_WKFMCAM_VALID;
      76                 :          0 :                 break;
      77                 :            :         default:
      78                 :            :                 break;
      79                 :            :         }
      80                 :          0 :         rtw_wow_pattern_write_cam(rtwdev, addr, wdata);
      81                 :          0 : }
      82                 :            : 
      83                 :            : /* RTK internal CRC16 for Pattern Cam */
      84                 :          0 : static u16 __rtw_cal_crc16(u8 data, u16 crc)
      85                 :            : {
      86                 :          0 :         u8 shift_in, data_bit;
      87                 :          0 :         u8 crc_bit4, crc_bit11, crc_bit15;
      88                 :          0 :         u16 crc_result;
      89                 :          0 :         int index;
      90                 :            : 
      91         [ #  # ]:          0 :         for (index = 0; index < 8; index++) {
      92                 :          0 :                 crc_bit15 = ((crc & BIT(15)) ? 1 : 0);
      93                 :          0 :                 data_bit = (data & (BIT(0) << index) ? 1 : 0);
      94                 :          0 :                 shift_in = crc_bit15 ^ data_bit;
      95                 :            : 
      96                 :          0 :                 crc_result = crc << 1;
      97                 :            : 
      98         [ #  # ]:          0 :                 if (shift_in == 0)
      99                 :            :                         crc_result &= (~BIT(0));
     100                 :            :                 else
     101                 :          0 :                         crc_result |= BIT(0);
     102                 :            : 
     103                 :          0 :                 crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in;
     104                 :            : 
     105         [ #  # ]:          0 :                 if (crc_bit11 == 0)
     106                 :          0 :                         crc_result &= (~BIT(12));
     107                 :            :                 else
     108                 :          0 :                         crc_result |= BIT(12);
     109                 :            : 
     110                 :          0 :                 crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in;
     111                 :            : 
     112         [ #  # ]:          0 :                 if (crc_bit4 == 0)
     113                 :          0 :                         crc_result &= (~BIT(5));
     114                 :            :                 else
     115                 :          0 :                         crc_result |= BIT(5);
     116                 :            : 
     117                 :          0 :                 crc = crc_result;
     118                 :            :         }
     119                 :          0 :         return crc;
     120                 :            : }
     121                 :            : 
     122                 :            : static u16 rtw_calc_crc(u8 *pdata, int length)
     123                 :            : {
     124                 :            :         u16 crc = 0xffff;
     125                 :            :         int i;
     126                 :            : 
     127                 :            :         for (i = 0; i < length; i++)
     128                 :            :                 crc = __rtw_cal_crc16(pdata[i], crc);
     129                 :            : 
     130                 :            :         /* get 1' complement */
     131                 :            :         return ~crc;
     132                 :            : }
     133                 :            : 
     134                 :            : static void rtw_wow_pattern_generate(struct rtw_dev *rtwdev,
     135                 :            :                                      struct rtw_vif *rtwvif,
     136                 :            :                                      const struct cfg80211_pkt_pattern *pkt_pattern,
     137                 :            :                                      struct rtw_wow_pattern *rtw_pattern)
     138                 :            : {
     139                 :            :         const u8 *mask;
     140                 :            :         const u8 *pattern;
     141                 :            :         u8 mask_hw[RTW_MAX_PATTERN_MASK_SIZE] = {0};
     142                 :            :         u8 content[RTW_MAX_PATTERN_SIZE] = {0};
     143                 :            :         u8 mac_addr[ETH_ALEN] = {0};
     144                 :            :         u8 mask_len;
     145                 :            :         u16 count;
     146                 :            :         int len;
     147                 :            :         int i;
     148                 :            : 
     149                 :            :         pattern = pkt_pattern->pattern;
     150                 :            :         len = pkt_pattern->pattern_len;
     151                 :            :         mask = pkt_pattern->mask;
     152                 :            : 
     153                 :            :         ether_addr_copy(mac_addr, rtwvif->mac_addr);
     154                 :            :         memset(rtw_pattern, 0, sizeof(*rtw_pattern));
     155                 :            : 
     156                 :            :         mask_len = DIV_ROUND_UP(len, 8);
     157                 :            : 
     158                 :            :         if (is_broadcast_ether_addr(pattern))
     159                 :            :                 rtw_pattern->type = RTW_PATTERN_BROADCAST;
     160                 :            :         else if (is_multicast_ether_addr(pattern))
     161                 :            :                 rtw_pattern->type = RTW_PATTERN_MULTICAST;
     162                 :            :         else if (ether_addr_equal(pattern, mac_addr))
     163                 :            :                 rtw_pattern->type = RTW_PATTERN_UNICAST;
     164                 :            :         else
     165                 :            :                 rtw_pattern->type = RTW_PATTERN_INVALID;
     166                 :            : 
     167                 :            :         /* translate mask from os to mask for hw
     168                 :            :          * pattern from OS uses 'ethenet frame', like this:
     169                 :            :          * |    6   |    6   |   2  |     20    |  Variable  |  4  |
     170                 :            :          * |--------+--------+------+-----------+------------+-----|
     171                 :            :          * |    802.3 Mac Header    | IP Header | TCP Packet | FCS |
     172                 :            :          * |   DA   |   SA   | Type |
     173                 :            :          *
     174                 :            :          * BUT, packet catched by our HW is in '802.11 frame', begin from LLC
     175                 :            :          * |     24 or 30      |    6   |   2  |     20    |  Variable  |  4  |
     176                 :            :          * |-------------------+--------+------+-----------+------------+-----|
     177                 :            :          * | 802.11 MAC Header |       LLC     | IP Header | TCP Packet | FCS |
     178                 :            :          *                     | Others | Tpye |
     179                 :            :          *
     180                 :            :          * Therefore, we need translate mask_from_OS to mask_to_hw.
     181                 :            :          * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0,
     182                 :            :          * because new mask[0~5] means 'SA', but our HW packet begins from LLC,
     183                 :            :          * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match.
     184                 :            :          */
     185                 :            : 
     186                 :            :         /* Shift 6 bits */
     187                 :            :         for (i = 0; i < mask_len - 1; i++) {
     188                 :            :                 mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6));
     189                 :            :                 mask_hw[i] |= u8_get_bits(mask[i + 1], GENMASK(5, 0)) << 2;
     190                 :            :         }
     191                 :            :         mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6));
     192                 :            : 
     193                 :            :         /* Set bit 0-5 to zero */
     194                 :            :         mask_hw[0] &= (~GENMASK(5, 0));
     195                 :            : 
     196                 :            :         memcpy(rtw_pattern->mask, mask_hw, RTW_MAX_PATTERN_MASK_SIZE);
     197                 :            : 
     198                 :            :         /* To get the wake up pattern from the mask.
     199                 :            :          * We do not count first 12 bits which means
     200                 :            :          * DA[6] and SA[6] in the pattern to match HW design.
     201                 :            :          */
     202                 :            :         count = 0;
     203                 :            :         for (i = 12; i < len; i++) {
     204                 :            :                 if ((mask[i / 8] >> (i % 8)) & 0x01) {
     205                 :            :                         content[count] = pattern[i];
     206                 :            :                         count++;
     207                 :            :                 }
     208                 :            :         }
     209                 :            : 
     210                 :            :         rtw_pattern->crc = rtw_calc_crc(content, count);
     211                 :            : }
     212                 :            : 
     213                 :          0 : static void rtw_wow_pattern_clear_cam(struct rtw_dev *rtwdev)
     214                 :            : {
     215                 :          0 :         bool ret;
     216                 :            : 
     217                 :          0 :         rtw_write32(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 |
     218                 :            :                     BIT_WKFCAM_CLR_V1);
     219                 :            : 
     220                 :          0 :         ret = check_hw_ready(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1, 0);
     221         [ #  # ]:          0 :         if (!ret)
     222                 :          0 :                 rtw_err(rtwdev, "failed to clean pattern cam\n");
     223                 :          0 : }
     224                 :            : 
     225                 :          0 : static void rtw_wow_pattern_write(struct rtw_dev *rtwdev)
     226                 :            : {
     227                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     228                 :          0 :         struct rtw_wow_pattern *rtw_pattern = rtw_wow->patterns;
     229                 :          0 :         int i = 0;
     230                 :            : 
     231         [ #  # ]:          0 :         for (i = 0; i < rtw_wow->pattern_cnt; i++)
     232                 :          0 :                 rtw_wow_pattern_write_cam_ent(rtwdev, i, rtw_pattern + i);
     233                 :          0 : }
     234                 :            : 
     235                 :          0 : static void rtw_wow_pattern_clear(struct rtw_dev *rtwdev)
     236                 :            : {
     237                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     238                 :            : 
     239                 :          0 :         rtw_wow_pattern_clear_cam(rtwdev);
     240                 :            : 
     241                 :          0 :         rtw_wow->pattern_cnt = 0;
     242                 :          0 :         memset(rtw_wow->patterns, 0, sizeof(rtw_wow->patterns));
     243                 :          0 : }
     244                 :            : 
     245                 :          0 : static void rtw_wow_bb_stop(struct rtw_dev *rtwdev)
     246                 :            : {
     247                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     248                 :            : 
     249                 :            :         /* wait 100ms for firmware to finish TX */
     250                 :          0 :         msleep(100);
     251                 :            : 
     252         [ #  # ]:          0 :         if (!rtw_read32_mask(rtwdev, REG_BCNQ_INFO, BIT_MGQ_CPU_EMPTY))
     253                 :          0 :                 rtw_warn(rtwdev, "Wrong status of MGQ_CPU empty!\n");
     254                 :            : 
     255                 :          0 :         rtw_wow->txpause = rtw_read8(rtwdev, REG_TXPAUSE);
     256                 :          0 :         rtw_write8(rtwdev, REG_TXPAUSE, 0xff);
     257                 :          0 :         rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB);
     258                 :          0 : }
     259                 :            : 
     260                 :          0 : static void rtw_wow_bb_start(struct rtw_dev *rtwdev)
     261                 :            : {
     262                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     263                 :            : 
     264                 :          0 :         rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB);
     265                 :          0 :         rtw_write8(rtwdev, REG_TXPAUSE, rtw_wow->txpause);
     266                 :          0 : }
     267                 :            : 
     268                 :          0 : static void rtw_wow_rx_dma_stop(struct rtw_dev *rtwdev)
     269                 :            : {
     270                 :            :         /* wait 100ms for HW to finish rx dma */
     271                 :          0 :         msleep(100);
     272                 :            : 
     273                 :          0 :         rtw_write32_set(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE);
     274                 :            : 
     275         [ #  # ]:          0 :         if (!check_hw_ready(rtwdev, REG_RXPKT_NUM, BIT_RXDMA_IDLE, 1))
     276                 :          0 :                 rtw_err(rtwdev, "failed to stop rx dma\n");
     277                 :          0 : }
     278                 :            : 
     279                 :          0 : static void rtw_wow_rx_dma_start(struct rtw_dev *rtwdev)
     280                 :            : {
     281                 :          0 :         rtw_write32_clr(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE);
     282                 :            : }
     283                 :            : 
     284                 :          0 : static int rtw_wow_check_fw_status(struct rtw_dev *rtwdev, bool wow_enable)
     285                 :            : {
     286                 :            :         /* wait 100ms for wow firmware to finish work */
     287                 :          0 :         msleep(100);
     288                 :            : 
     289         [ #  # ]:          0 :         if (wow_enable) {
     290         [ #  # ]:          0 :                 if (rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON))
     291                 :          0 :                         goto wow_fail;
     292                 :            :         } else {
     293   [ #  #  #  # ]:          0 :                 if (rtw_read32_mask(rtwdev, REG_FE1IMR, BIT_FS_RXDONE) ||
     294                 :            :                     rtw_read32_mask(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE))
     295                 :          0 :                         goto wow_fail;
     296                 :            :         }
     297                 :            : 
     298                 :            :         return 0;
     299                 :            : 
     300                 :          0 : wow_fail:
     301         [ #  # ]:          0 :         rtw_err(rtwdev, "failed to check wow status %s\n",
     302                 :            :                 wow_enable ? "enabled" : "disabled");
     303                 :          0 :         return -EBUSY;
     304                 :            : }
     305                 :            : 
     306                 :          0 : static void rtw_wow_fw_security_type_iter(struct ieee80211_hw *hw,
     307                 :            :                                           struct ieee80211_vif *vif,
     308                 :            :                                           struct ieee80211_sta *sta,
     309                 :            :                                           struct ieee80211_key_conf *key,
     310                 :            :                                           void *data)
     311                 :            : {
     312                 :          0 :         struct rtw_fw_key_type_iter_data *iter_data = data;
     313                 :          0 :         struct rtw_dev *rtwdev = hw->priv;
     314                 :          0 :         u8 hw_key_type;
     315                 :            : 
     316         [ #  # ]:          0 :         if (vif != rtwdev->wow.wow_vif)
     317                 :            :                 return;
     318                 :            : 
     319   [ #  #  #  #  :          0 :         switch (key->cipher) {
                      # ]
     320                 :            :         case WLAN_CIPHER_SUITE_WEP40:
     321                 :            :                 hw_key_type = RTW_CAM_WEP40;
     322                 :            :                 break;
     323                 :          0 :         case WLAN_CIPHER_SUITE_WEP104:
     324                 :          0 :                 hw_key_type = RTW_CAM_WEP104;
     325                 :          0 :                 break;
     326                 :          0 :         case WLAN_CIPHER_SUITE_TKIP:
     327                 :          0 :                 hw_key_type = RTW_CAM_TKIP;
     328                 :          0 :                 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
     329                 :          0 :                 break;
     330                 :          0 :         case WLAN_CIPHER_SUITE_CCMP:
     331                 :          0 :                 hw_key_type = RTW_CAM_AES;
     332                 :          0 :                 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
     333                 :          0 :                 break;
     334                 :          0 :         default:
     335                 :          0 :                 rtw_err(rtwdev, "Unsupported key type for wowlan mode\n");
     336                 :          0 :                 hw_key_type = 0;
     337                 :          0 :                 break;
     338                 :            :         }
     339                 :            : 
     340         [ #  # ]:          0 :         if (sta)
     341                 :          0 :                 iter_data->pairwise_key_type = hw_key_type;
     342                 :            :         else
     343                 :          0 :                 iter_data->group_key_type = hw_key_type;
     344                 :            : }
     345                 :            : 
     346                 :          0 : static void rtw_wow_fw_security_type(struct rtw_dev *rtwdev)
     347                 :            : {
     348                 :          0 :         struct rtw_fw_key_type_iter_data data = {};
     349                 :          0 :         struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
     350                 :            : 
     351                 :          0 :         data.rtwdev = rtwdev;
     352                 :          0 :         rtw_iterate_keys(rtwdev, wow_vif,
     353                 :            :                          rtw_wow_fw_security_type_iter, &data);
     354                 :          0 :         rtw_fw_set_aoac_global_info_cmd(rtwdev, data.pairwise_key_type,
     355                 :          0 :                                         data.group_key_type);
     356                 :          0 : }
     357                 :            : 
     358                 :          0 : static int rtw_wow_fw_start(struct rtw_dev *rtwdev)
     359                 :            : {
     360         [ #  # ]:          0 :         if (rtw_wow_mgd_linked(rtwdev)) {
     361                 :          0 :                 rtw_send_rsvd_page_h2c(rtwdev);
     362                 :          0 :                 rtw_wow_pattern_write(rtwdev);
     363                 :          0 :                 rtw_wow_fw_security_type(rtwdev);
     364                 :          0 :                 rtw_fw_set_disconnect_decision_cmd(rtwdev, true);
     365                 :          0 :                 rtw_fw_set_keep_alive_cmd(rtwdev, true);
     366         [ #  # ]:          0 :         } else if (rtw_wow_no_link(rtwdev)) {
     367                 :          0 :                 rtw_fw_set_nlo_info(rtwdev, true);
     368                 :          0 :                 rtw_fw_update_pkt_probe_req(rtwdev, NULL);
     369                 :          0 :                 rtw_fw_channel_switch(rtwdev, true);
     370                 :            :         }
     371                 :            : 
     372                 :          0 :         rtw_fw_set_wowlan_ctrl_cmd(rtwdev, true);
     373                 :          0 :         rtw_fw_set_remote_wake_ctrl_cmd(rtwdev, true);
     374                 :            : 
     375                 :          0 :         return rtw_wow_check_fw_status(rtwdev, true);
     376                 :            : }
     377                 :            : 
     378                 :          0 : static int rtw_wow_fw_stop(struct rtw_dev *rtwdev)
     379                 :            : {
     380         [ #  # ]:          0 :         if (rtw_wow_mgd_linked(rtwdev)) {
     381                 :          0 :                 rtw_fw_set_disconnect_decision_cmd(rtwdev, false);
     382                 :          0 :                 rtw_fw_set_keep_alive_cmd(rtwdev, false);
     383                 :          0 :                 rtw_wow_pattern_clear(rtwdev);
     384         [ #  # ]:          0 :         } else if (rtw_wow_no_link(rtwdev)) {
     385                 :          0 :                 rtw_fw_channel_switch(rtwdev, false);
     386                 :          0 :                 rtw_fw_set_nlo_info(rtwdev, false);
     387                 :            :         }
     388                 :            : 
     389                 :          0 :         rtw_fw_set_wowlan_ctrl_cmd(rtwdev, false);
     390                 :          0 :         rtw_fw_set_remote_wake_ctrl_cmd(rtwdev, false);
     391                 :            : 
     392                 :          0 :         return rtw_wow_check_fw_status(rtwdev, false);
     393                 :            : }
     394                 :            : 
     395                 :          0 : static void rtw_wow_avoid_reset_mac(struct rtw_dev *rtwdev)
     396                 :            : {
     397                 :            :         /* When resuming from wowlan mode, some hosts issue signal
     398                 :            :          * (PCIE: PREST, USB: SE0RST) to device, and lead to reset
     399                 :            :          * mac core. If it happens, the connection to AP will be lost.
     400                 :            :          * Setting REG_RSV_CTRL Register can avoid this process.
     401                 :            :          */
     402         [ #  # ]:          0 :         switch (rtw_hci_type(rtwdev)) {
     403                 :            :         case RTW_HCI_TYPE_PCIE:
     404                 :            :         case RTW_HCI_TYPE_USB:
     405                 :          0 :                 rtw_write8(rtwdev, REG_RSV_CTRL, BIT_WLOCK_1C_B6);
     406                 :          0 :                 rtw_write8(rtwdev, REG_RSV_CTRL,
     407                 :            :                            BIT_WLOCK_1C_B6 | BIT_R_DIS_PRST);
     408                 :            :                 break;
     409                 :          0 :         default:
     410                 :          0 :                 rtw_warn(rtwdev, "Unsupported hci type to disable reset MAC\n");
     411                 :          0 :                 break;
     412                 :            :         }
     413                 :          0 : }
     414                 :            : 
     415                 :          0 : static void rtw_wow_fw_media_status_iter(void *data, struct ieee80211_sta *sta)
     416                 :            : {
     417                 :          0 :         struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
     418                 :          0 :         struct rtw_fw_media_status_iter_data *iter_data = data;
     419                 :          0 :         struct rtw_dev *rtwdev = iter_data->rtwdev;
     420                 :            : 
     421                 :          0 :         rtw_fw_media_status_report(rtwdev, si->mac_id, iter_data->connect);
     422                 :          0 : }
     423                 :            : 
     424                 :          0 : static void rtw_wow_fw_media_status(struct rtw_dev *rtwdev, bool connect)
     425                 :            : {
     426                 :          0 :         struct rtw_fw_media_status_iter_data data;
     427                 :            : 
     428                 :          0 :         data.rtwdev = rtwdev;
     429                 :          0 :         data.connect = connect;
     430                 :            : 
     431                 :          0 :         rtw_iterate_stas_atomic(rtwdev, rtw_wow_fw_media_status_iter, &data);
     432                 :          0 : }
     433                 :            : 
     434                 :          0 : static void rtw_wow_config_pno_rsvd_page(struct rtw_dev *rtwdev)
     435                 :            : {
     436                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     437                 :          0 :         struct rtw_pno_request *rtw_pno_req = &rtw_wow->pno_req;
     438                 :          0 :         struct cfg80211_ssid *ssid;
     439                 :          0 :         int i;
     440                 :            : 
     441         [ #  # ]:          0 :         for (i = 0 ; i < rtw_pno_req->match_set_cnt; i++) {
     442                 :          0 :                 ssid = &rtw_pno_req->match_sets[i].ssid;
     443                 :          0 :                 rtw_add_rsvd_page_probe_req(rtwdev, ssid);
     444                 :            :         }
     445                 :          0 :         rtw_add_rsvd_page_probe_req(rtwdev, NULL);
     446                 :          0 :         rtw_add_rsvd_page(rtwdev, RSVD_NLO_INFO, false);
     447                 :          0 :         rtw_add_rsvd_page(rtwdev, RSVD_CH_INFO, true);
     448                 :          0 : }
     449                 :            : 
     450                 :          0 : static void rtw_wow_config_linked_rsvd_page(struct rtw_dev *rtwdev)
     451                 :            : {
     452                 :          0 :         rtw_add_rsvd_page(rtwdev, RSVD_PS_POLL, true);
     453                 :          0 :         rtw_add_rsvd_page(rtwdev, RSVD_QOS_NULL, true);
     454                 :          0 :         rtw_add_rsvd_page(rtwdev, RSVD_NULL, true);
     455                 :          0 :         rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_DPK, true);
     456                 :          0 :         rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_INFO, true);
     457                 :          0 : }
     458                 :            : 
     459                 :          0 : static void rtw_wow_config_rsvd_page(struct rtw_dev *rtwdev)
     460                 :            : {
     461                 :          0 :         rtw_reset_rsvd_page(rtwdev);
     462                 :            : 
     463         [ #  # ]:          0 :         if (rtw_wow_mgd_linked(rtwdev)) {
     464                 :          0 :                 rtw_wow_config_linked_rsvd_page(rtwdev);
     465   [ #  #  #  # ]:          0 :         } else if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags) &&
     466         [ #  # ]:          0 :                    rtw_wow_no_link(rtwdev)) {
     467                 :          0 :                 rtw_wow_config_pno_rsvd_page(rtwdev);
     468                 :            :         }
     469                 :          0 : }
     470                 :            : 
     471                 :          0 : static int rtw_wow_dl_fw_rsvd_page(struct rtw_dev *rtwdev)
     472                 :            : {
     473                 :          0 :         struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
     474                 :            : 
     475                 :          0 :         rtw_wow_config_rsvd_page(rtwdev);
     476                 :            : 
     477                 :          0 :         return rtw_fw_download_rsvd_page(rtwdev, wow_vif);
     478                 :            : }
     479                 :            : 
     480                 :          0 : static int rtw_wow_swap_fw(struct rtw_dev *rtwdev, enum rtw_fw_type type)
     481                 :            : {
     482                 :          0 :         struct rtw_fw_state *fw;
     483                 :          0 :         int ret;
     484                 :            : 
     485      [ #  #  # ]:          0 :         switch (type) {
     486                 :          0 :         case RTW_WOWLAN_FW:
     487                 :          0 :                 fw = &rtwdev->wow_fw;
     488                 :          0 :                 break;
     489                 :            : 
     490                 :          0 :         case RTW_NORMAL_FW:
     491                 :          0 :                 fw = &rtwdev->fw;
     492                 :          0 :                 break;
     493                 :            : 
     494                 :          0 :         default:
     495                 :          0 :                 rtw_warn(rtwdev, "unsupported firmware type to swap\n");
     496                 :          0 :                 return -ENOENT;
     497                 :            :         }
     498                 :            : 
     499                 :          0 :         ret = rtw_download_firmware(rtwdev, fw);
     500         [ #  # ]:          0 :         if (ret)
     501                 :          0 :                 goto out;
     502                 :            : 
     503                 :          0 :         rtw_fw_send_general_info(rtwdev);
     504                 :          0 :         rtw_fw_send_phydm_info(rtwdev);
     505                 :          0 :         rtw_wow_fw_media_status(rtwdev, true);
     506                 :            : 
     507                 :            : out:
     508                 :            :         return ret;
     509                 :            : }
     510                 :            : 
     511                 :          0 : static void rtw_wow_check_pno(struct rtw_dev *rtwdev,
     512                 :            :                               struct cfg80211_sched_scan_request *nd_config)
     513                 :            : {
     514                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     515                 :          0 :         struct rtw_pno_request *pno_req = &rtw_wow->pno_req;
     516                 :          0 :         struct ieee80211_channel *channel;
     517                 :          0 :         int i, size;
     518                 :            : 
     519   [ #  #  #  # ]:          0 :         if (!nd_config->n_match_sets || !nd_config->n_channels)
     520                 :          0 :                 goto err;
     521                 :            : 
     522                 :          0 :         pno_req->match_set_cnt = nd_config->n_match_sets;
     523                 :          0 :         size = sizeof(*pno_req->match_sets) * pno_req->match_set_cnt;
     524                 :          0 :         pno_req->match_sets = kmemdup(nd_config->match_sets, size, GFP_KERNEL);
     525         [ #  # ]:          0 :         if (!pno_req->match_sets)
     526                 :          0 :                 goto err;
     527                 :            : 
     528                 :          0 :         pno_req->channel_cnt = nd_config->n_channels;
     529                 :          0 :         size = sizeof(*nd_config->channels[0]) * nd_config->n_channels;
     530         [ #  # ]:          0 :         pno_req->channels = kmalloc(size, GFP_KERNEL);
     531         [ #  # ]:          0 :         if (!pno_req->channels)
     532                 :          0 :                 goto channel_err;
     533                 :            : 
     534         [ #  # ]:          0 :         for (i = 0 ; i < pno_req->channel_cnt; i++) {
     535                 :          0 :                 channel = pno_req->channels + i;
     536                 :          0 :                 memcpy(channel, nd_config->channels[i], sizeof(*channel));
     537                 :            :         }
     538                 :            : 
     539                 :          0 :         pno_req->scan_plan = *nd_config->scan_plans;
     540                 :          0 :         pno_req->inited = true;
     541                 :            : 
     542                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: net-detect is enabled\n");
     543                 :            : 
     544                 :          0 :         return;
     545                 :            : 
     546                 :            : channel_err:
     547                 :          0 :         kfree(pno_req->match_sets);
     548                 :            : 
     549                 :          0 : err:
     550                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: net-detect is disabled\n");
     551                 :            : }
     552                 :            : 
     553                 :          0 : static int rtw_wow_leave_linked_ps(struct rtw_dev *rtwdev)
     554                 :            : {
     555         [ #  # ]:          0 :         if (!test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
     556                 :          0 :                 cancel_delayed_work_sync(&rtwdev->watch_dog_work);
     557                 :            : 
     558                 :          0 :         rtw_leave_lps(rtwdev);
     559                 :            : 
     560                 :          0 :         return 0;
     561                 :            : }
     562                 :            : 
     563                 :          0 : static int rtw_wow_leave_no_link_ps(struct rtw_dev *rtwdev)
     564                 :            : {
     565                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     566                 :          0 :         int ret = 0;
     567                 :            : 
     568         [ #  # ]:          0 :         if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) {
     569         [ #  # ]:          0 :                 if (rtw_fw_lps_deep_mode)
     570                 :          0 :                         rtw_leave_lps_deep(rtwdev);
     571                 :            :         } else {
     572         [ #  # ]:          0 :                 if (test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags)) {
     573                 :          0 :                         rtw_wow->ips_enabled = true;
     574                 :          0 :                         ret = rtw_leave_ips(rtwdev);
     575         [ #  # ]:          0 :                         if (ret)
     576                 :          0 :                                 return ret;
     577                 :            :                 }
     578                 :            :         }
     579                 :            : 
     580                 :            :         return 0;
     581                 :            : }
     582                 :            : 
     583                 :          0 : static int rtw_wow_leave_ps(struct rtw_dev *rtwdev)
     584                 :            : {
     585                 :          0 :         int ret = 0;
     586                 :            : 
     587         [ #  # ]:          0 :         if (rtw_wow_mgd_linked(rtwdev))
     588                 :          0 :                 ret = rtw_wow_leave_linked_ps(rtwdev);
     589         [ #  # ]:          0 :         else if (rtw_wow_no_link(rtwdev))
     590                 :          0 :                 ret = rtw_wow_leave_no_link_ps(rtwdev);
     591                 :            : 
     592                 :          0 :         return ret;
     593                 :            : }
     594                 :            : 
     595                 :          0 : static int rtw_wow_restore_ps(struct rtw_dev *rtwdev)
     596                 :            : {
     597                 :          0 :         int ret = 0;
     598                 :            : 
     599   [ #  #  #  # ]:          0 :         if (rtw_wow_no_link(rtwdev) && rtwdev->wow.ips_enabled)
     600                 :          0 :                 ret = rtw_enter_ips(rtwdev);
     601                 :            : 
     602                 :          0 :         return ret;
     603                 :            : }
     604                 :            : 
     605                 :          0 : static int rtw_wow_enter_linked_ps(struct rtw_dev *rtwdev)
     606                 :            : {
     607                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     608                 :          0 :         struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
     609                 :          0 :         struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv;
     610                 :            : 
     611                 :          0 :         rtw_enter_lps(rtwdev, rtwvif->port);
     612                 :            : 
     613                 :          0 :         return 0;
     614                 :            : }
     615                 :            : 
     616                 :          0 : static int rtw_wow_enter_no_link_ps(struct rtw_dev *rtwdev)
     617                 :            : {
     618                 :            :         /* firmware enters deep ps by itself if supported */
     619                 :          0 :         set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags);
     620                 :            : 
     621                 :          0 :         return 0;
     622                 :            : }
     623                 :            : 
     624                 :          0 : static int rtw_wow_enter_ps(struct rtw_dev *rtwdev)
     625                 :            : {
     626                 :          0 :         int ret = 0;
     627                 :            : 
     628         [ #  # ]:          0 :         if (rtw_wow_mgd_linked(rtwdev))
     629                 :          0 :                 ret = rtw_wow_enter_linked_ps(rtwdev);
     630   [ #  #  #  # ]:          0 :         else if (rtw_wow_no_link(rtwdev) && rtw_fw_lps_deep_mode)
     631                 :          0 :                 ret = rtw_wow_enter_no_link_ps(rtwdev);
     632                 :            : 
     633                 :          0 :         return ret;
     634                 :            : }
     635                 :            : 
     636                 :          0 : static void rtw_wow_stop_trx(struct rtw_dev *rtwdev)
     637                 :            : {
     638                 :          0 :         rtw_wow_bb_stop(rtwdev);
     639                 :          0 :         rtw_wow_rx_dma_stop(rtwdev);
     640                 :            : }
     641                 :            : 
     642                 :          0 : static int rtw_wow_start(struct rtw_dev *rtwdev)
     643                 :            : {
     644                 :          0 :         int ret;
     645                 :            : 
     646                 :          0 :         ret = rtw_wow_fw_start(rtwdev);
     647         [ #  # ]:          0 :         if (ret)
     648                 :          0 :                 goto out;
     649                 :            : 
     650                 :          0 :         rtw_hci_stop(rtwdev);
     651                 :          0 :         rtw_wow_bb_start(rtwdev);
     652                 :          0 :         rtw_wow_avoid_reset_mac(rtwdev);
     653                 :            : 
     654                 :          0 : out:
     655                 :          0 :         return ret;
     656                 :            : }
     657                 :            : 
     658                 :          0 : static int rtw_wow_enable(struct rtw_dev *rtwdev)
     659                 :            : {
     660                 :          0 :         int ret = 0;
     661                 :            : 
     662                 :          0 :         rtw_wow_stop_trx(rtwdev);
     663                 :            : 
     664                 :          0 :         ret = rtw_wow_swap_fw(rtwdev, RTW_WOWLAN_FW);
     665         [ #  # ]:          0 :         if (ret) {
     666                 :          0 :                 rtw_err(rtwdev, "failed to swap wow fw\n");
     667                 :          0 :                 goto error;
     668                 :            :         }
     669                 :            : 
     670                 :          0 :         set_bit(RTW_FLAG_WOWLAN, rtwdev->flags);
     671                 :            : 
     672                 :          0 :         ret = rtw_wow_dl_fw_rsvd_page(rtwdev);
     673         [ #  # ]:          0 :         if (ret) {
     674                 :          0 :                 rtw_err(rtwdev, "failed to download wowlan rsvd page\n");
     675                 :          0 :                 goto error;
     676                 :            :         }
     677                 :            : 
     678                 :          0 :         ret = rtw_wow_start(rtwdev);
     679         [ #  # ]:          0 :         if (ret) {
     680                 :          0 :                 rtw_err(rtwdev, "failed to start wow\n");
     681                 :          0 :                 goto error;
     682                 :            :         }
     683                 :            : 
     684                 :            :         return ret;
     685                 :            : 
     686                 :          0 : error:
     687                 :          0 :         clear_bit(RTW_FLAG_WOWLAN, rtwdev->flags);
     688                 :          0 :         return ret;
     689                 :            : }
     690                 :            : 
     691                 :          0 : static int rtw_wow_stop(struct rtw_dev *rtwdev)
     692                 :            : {
     693                 :          0 :         int ret;
     694                 :            : 
     695                 :            :         /* some HCI related registers will be reset after resume,
     696                 :            :          * need to set them again.
     697                 :            :          */
     698                 :          0 :         ret = rtw_hci_setup(rtwdev);
     699         [ #  # ]:          0 :         if (ret) {
     700                 :          0 :                 rtw_err(rtwdev, "failed to setup hci\n");
     701                 :          0 :                 return ret;
     702                 :            :         }
     703                 :            : 
     704                 :          0 :         ret = rtw_hci_start(rtwdev);
     705         [ #  # ]:          0 :         if (ret) {
     706                 :          0 :                 rtw_err(rtwdev, "failed to start hci\n");
     707                 :          0 :                 return ret;
     708                 :            :         }
     709                 :            : 
     710                 :          0 :         ret = rtw_wow_fw_stop(rtwdev);
     711         [ #  # ]:          0 :         if (ret)
     712                 :          0 :                 rtw_err(rtwdev, "failed to stop wowlan fw\n");
     713                 :            : 
     714                 :          0 :         rtw_wow_bb_stop(rtwdev);
     715                 :            : 
     716                 :          0 :         return ret;
     717                 :            : }
     718                 :            : 
     719                 :          0 : static void rtw_wow_resume_trx(struct rtw_dev *rtwdev)
     720                 :            : {
     721                 :          0 :         rtw_wow_rx_dma_start(rtwdev);
     722                 :          0 :         rtw_wow_bb_start(rtwdev);
     723                 :          0 :         ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work,
     724                 :            :                                      RTW_WATCH_DOG_DELAY_TIME);
     725                 :          0 : }
     726                 :            : 
     727                 :          0 : static int rtw_wow_disable(struct rtw_dev *rtwdev)
     728                 :            : {
     729                 :          0 :         int ret;
     730                 :            : 
     731                 :          0 :         clear_bit(RTW_FLAG_WOWLAN, rtwdev->flags);
     732                 :            : 
     733                 :          0 :         ret = rtw_wow_stop(rtwdev);
     734         [ #  # ]:          0 :         if (ret) {
     735                 :          0 :                 rtw_err(rtwdev, "failed to stop wow\n");
     736                 :          0 :                 goto out;
     737                 :            :         }
     738                 :            : 
     739                 :          0 :         ret = rtw_wow_swap_fw(rtwdev, RTW_NORMAL_FW);
     740         [ #  # ]:          0 :         if (ret) {
     741                 :          0 :                 rtw_err(rtwdev, "failed to swap normal fw\n");
     742                 :          0 :                 goto out;
     743                 :            :         }
     744                 :            : 
     745                 :          0 :         ret = rtw_wow_dl_fw_rsvd_page(rtwdev);
     746         [ #  # ]:          0 :         if (ret)
     747                 :          0 :                 rtw_err(rtwdev, "failed to download normal rsvd page\n");
     748                 :            : 
     749                 :          0 : out:
     750                 :          0 :         rtw_wow_resume_trx(rtwdev);
     751                 :          0 :         return ret;
     752                 :            : }
     753                 :            : 
     754                 :          0 : static void rtw_wow_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
     755                 :            : {
     756                 :          0 :         struct rtw_dev *rtwdev = data;
     757                 :          0 :         struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
     758                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     759                 :            : 
     760                 :            :         /* Current wowlan function support setting of only one STATION vif.
     761                 :            :          * So when one suitable vif is found, stop the iteration.
     762                 :            :          */
     763   [ #  #  #  # ]:          0 :         if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION)
     764                 :            :                 return;
     765                 :            : 
     766      [ #  #  # ]:          0 :         switch (rtwvif->net_type) {
     767                 :          0 :         case RTW_NET_MGD_LINKED:
     768                 :          0 :                 rtw_wow->wow_vif = vif;
     769                 :          0 :                 break;
     770                 :          0 :         case RTW_NET_NO_LINK:
     771         [ #  # ]:          0 :                 if (rtw_wow->pno_req.inited)
     772                 :          0 :                         rtwdev->wow.wow_vif = vif;
     773                 :            :                 break;
     774                 :            :         default:
     775                 :            :                 break;
     776                 :            :         }
     777                 :            : }
     778                 :            : 
     779                 :          0 : static int rtw_wow_set_wakeups(struct rtw_dev *rtwdev,
     780                 :            :                                struct cfg80211_wowlan *wowlan)
     781                 :            : {
     782                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     783                 :          0 :         struct rtw_wow_pattern *rtw_patterns = rtw_wow->patterns;
     784                 :          0 :         struct rtw_vif *rtwvif;
     785                 :          0 :         int i;
     786                 :            : 
     787         [ #  # ]:          0 :         if (wowlan->disconnect)
     788                 :          0 :                 set_bit(RTW_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags);
     789         [ #  # ]:          0 :         if (wowlan->magic_pkt)
     790                 :          0 :                 set_bit(RTW_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags);
     791         [ #  # ]:          0 :         if (wowlan->gtk_rekey_failure)
     792                 :          0 :                 set_bit(RTW_WOW_FLAG_EN_REKEY_PKT, rtw_wow->flags);
     793                 :            : 
     794         [ #  # ]:          0 :         if (wowlan->nd_config)
     795                 :          0 :                 rtw_wow_check_pno(rtwdev, wowlan->nd_config);
     796                 :            : 
     797                 :          0 :         rtw_iterate_vifs_atomic(rtwdev, rtw_wow_vif_iter, rtwdev);
     798         [ #  # ]:          0 :         if (!rtw_wow->wow_vif)
     799                 :            :                 return -EPERM;
     800                 :            : 
     801                 :          0 :         rtwvif = (struct rtw_vif *)rtw_wow->wow_vif->drv_priv;
     802   [ #  #  #  # ]:          0 :         if (wowlan->n_patterns && wowlan->patterns) {
     803                 :          0 :                 rtw_wow->pattern_cnt = wowlan->n_patterns;
     804         [ #  # ]:          0 :                 for (i = 0; i < wowlan->n_patterns; i++)
     805                 :          0 :                         rtw_wow_pattern_generate(rtwdev, rtwvif,
     806                 :          0 :                                                  wowlan->patterns + i,
     807                 :          0 :                                                  rtw_patterns + i);
     808                 :            :         }
     809                 :            : 
     810                 :            :         return 0;
     811                 :            : }
     812                 :            : 
     813                 :          0 : static void rtw_wow_clear_wakeups(struct rtw_dev *rtwdev)
     814                 :            : {
     815                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     816                 :          0 :         struct rtw_pno_request *pno_req = &rtw_wow->pno_req;
     817                 :            : 
     818         [ #  # ]:          0 :         if (pno_req->inited) {
     819                 :          0 :                 kfree(pno_req->channels);
     820                 :          0 :                 kfree(pno_req->match_sets);
     821                 :            :         }
     822                 :            : 
     823                 :          0 :         memset(rtw_wow, 0, sizeof(rtwdev->wow));
     824                 :          0 : }
     825                 :            : 
     826                 :          0 : int rtw_wow_suspend(struct rtw_dev *rtwdev, struct cfg80211_wowlan *wowlan)
     827                 :            : {
     828                 :          0 :         int ret = 0;
     829                 :            : 
     830                 :          0 :         ret = rtw_wow_set_wakeups(rtwdev, wowlan);
     831         [ #  # ]:          0 :         if (ret) {
     832                 :          0 :                 rtw_err(rtwdev, "failed to set wakeup event\n");
     833                 :          0 :                 goto out;
     834                 :            :         }
     835                 :            : 
     836                 :          0 :         ret = rtw_wow_leave_ps(rtwdev);
     837         [ #  # ]:          0 :         if (ret) {
     838                 :          0 :                 rtw_err(rtwdev, "failed to leave ps from normal mode\n");
     839                 :          0 :                 goto out;
     840                 :            :         }
     841                 :            : 
     842                 :          0 :         ret = rtw_wow_enable(rtwdev);
     843         [ #  # ]:          0 :         if (ret) {
     844                 :          0 :                 rtw_err(rtwdev, "failed to enable wow\n");
     845         [ #  # ]:          0 :                 rtw_wow_restore_ps(rtwdev);
     846                 :          0 :                 goto out;
     847                 :            :         }
     848                 :            : 
     849                 :          0 :         ret = rtw_wow_enter_ps(rtwdev);
     850         [ #  # ]:          0 :         if (ret)
     851                 :          0 :                 rtw_err(rtwdev, "failed to enter ps for wow\n");
     852                 :            : 
     853                 :          0 : out:
     854                 :          0 :         return ret;
     855                 :            : }
     856                 :            : 
     857                 :          0 : int rtw_wow_resume(struct rtw_dev *rtwdev)
     858                 :            : {
     859                 :          0 :         int ret;
     860                 :            : 
     861                 :            :         /* If wowlan mode is not enabled, do nothing */
     862         [ #  # ]:          0 :         if (!test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) {
     863                 :          0 :                 rtw_err(rtwdev, "wow is not enabled\n");
     864                 :          0 :                 ret = -EPERM;
     865                 :          0 :                 goto out;
     866                 :            :         }
     867                 :            : 
     868                 :          0 :         ret = rtw_wow_leave_ps(rtwdev);
     869         [ #  # ]:          0 :         if (ret) {
     870                 :          0 :                 rtw_err(rtwdev, "failed to leave ps from wowlan mode\n");
     871                 :          0 :                 goto out;
     872                 :            :         }
     873                 :            : 
     874                 :          0 :         rtw_wow_show_wakeup_reason(rtwdev);
     875                 :            : 
     876                 :          0 :         ret = rtw_wow_disable(rtwdev);
     877         [ #  # ]:          0 :         if (ret) {
     878                 :          0 :                 rtw_err(rtwdev, "failed to disable wow\n");
     879                 :          0 :                 goto out;
     880                 :            :         }
     881                 :            : 
     882         [ #  # ]:          0 :         ret = rtw_wow_restore_ps(rtwdev);
     883         [ #  # ]:          0 :         if (ret)
     884                 :          0 :                 rtw_err(rtwdev, "failed to restore ps to normal mode\n");
     885                 :            : 
     886                 :          0 : out:
     887                 :          0 :         rtw_wow_clear_wakeups(rtwdev);
     888                 :          0 :         return ret;
     889                 :            : }

Generated by: LCOV version 1.14