LCOV - code coverage report
Current view: top level - drivers/net/wireless/realtek/rtw88 - fw.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 42 655 6.4 %
Date: 2022-03-28 16:04:14 Functions: 2 45 4.4 %
Branches: 4 243 1.6 %

           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 "coex.h"
       7                 :            : #include "fw.h"
       8                 :            : #include "tx.h"
       9                 :            : #include "reg.h"
      10                 :            : #include "sec.h"
      11                 :            : #include "debug.h"
      12                 :            : #include "util.h"
      13                 :            : #include "wow.h"
      14                 :            : 
      15                 :          0 : static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
      16                 :            :                                       struct sk_buff *skb)
      17                 :            : {
      18                 :          0 :         struct rtw_c2h_cmd *c2h;
      19                 :          0 :         u8 sub_cmd_id;
      20                 :            : 
      21                 :          0 :         c2h = get_c2h_from_skb(skb);
      22                 :          0 :         sub_cmd_id = c2h->payload[0];
      23                 :            : 
      24         [ #  # ]:          0 :         switch (sub_cmd_id) {
      25                 :          0 :         case C2H_CCX_RPT:
      26                 :          0 :                 rtw_tx_report_handle(rtwdev, skb);
      27                 :          0 :                 break;
      28                 :            :         default:
      29                 :            :                 break;
      30                 :            :         }
      31                 :            : }
      32                 :            : 
      33                 :          0 : static u16 get_max_amsdu_len(u32 bit_rate)
      34                 :            : {
      35                 :            :         /* lower than ofdm, do not aggregate */
      36                 :          0 :         if (bit_rate < 550)
      37                 :            :                 return 1;
      38                 :            : 
      39                 :            :         /* lower than 20M 2ss mcs8, make it small */
      40         [ #  # ]:          0 :         if (bit_rate < 1800)
      41                 :            :                 return 1200;
      42                 :            : 
      43                 :            :         /* lower than 40M 2ss mcs9, make it medium */
      44         [ #  # ]:          0 :         if (bit_rate < 4000)
      45                 :            :                 return 2600;
      46                 :            : 
      47                 :            :         /* not yet 80M 2ss mcs8/9, make it twice regular packet size */
      48         [ #  # ]:          0 :         if (bit_rate < 7000)
      49                 :          0 :                 return 3500;
      50                 :            : 
      51                 :            :         /* unlimited */
      52                 :            :         return 0;
      53                 :            : }
      54                 :            : 
      55                 :            : struct rtw_fw_iter_ra_data {
      56                 :            :         struct rtw_dev *rtwdev;
      57                 :            :         u8 *payload;
      58                 :            : };
      59                 :            : 
      60                 :          0 : static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta)
      61                 :            : {
      62                 :          0 :         struct rtw_fw_iter_ra_data *ra_data = data;
      63                 :          0 :         struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
      64                 :          0 :         u8 mac_id, rate, sgi, bw;
      65                 :          0 :         u8 mcs, nss;
      66                 :          0 :         u32 bit_rate;
      67                 :            : 
      68                 :          0 :         mac_id = GET_RA_REPORT_MACID(ra_data->payload);
      69         [ #  # ]:          0 :         if (si->mac_id != mac_id)
      70                 :          0 :                 return;
      71                 :            : 
      72                 :          0 :         si->ra_report.txrate.flags = 0;
      73                 :            : 
      74                 :          0 :         rate = GET_RA_REPORT_RATE(ra_data->payload);
      75                 :          0 :         sgi = GET_RA_REPORT_SGI(ra_data->payload);
      76                 :          0 :         bw = GET_RA_REPORT_BW(ra_data->payload);
      77                 :            : 
      78         [ #  # ]:          0 :         if (rate < DESC_RATEMCS0) {
      79                 :          0 :                 si->ra_report.txrate.legacy = rtw_desc_to_bitrate(rate);
      80                 :          0 :                 goto legacy;
      81                 :            :         }
      82                 :            : 
      83                 :          0 :         rtw_desc_to_mcsrate(rate, &mcs, &nss);
      84         [ #  # ]:          0 :         if (rate >= DESC_RATEVHT1SS_MCS0)
      85                 :          0 :                 si->ra_report.txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
      86                 :          0 :         else if (rate >= DESC_RATEMCS0)
      87                 :          0 :                 si->ra_report.txrate.flags |= RATE_INFO_FLAGS_MCS;
      88                 :            : 
      89                 :          0 :         if (rate >= DESC_RATEMCS0) {
      90                 :          0 :                 si->ra_report.txrate.mcs = mcs;
      91                 :          0 :                 si->ra_report.txrate.nss = nss;
      92                 :            :         }
      93                 :            : 
      94         [ #  # ]:          0 :         if (sgi)
      95                 :          0 :                 si->ra_report.txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
      96                 :            : 
      97         [ #  # ]:          0 :         if (bw == RTW_CHANNEL_WIDTH_80)
      98                 :          0 :                 si->ra_report.txrate.bw = RATE_INFO_BW_80;
      99         [ #  # ]:          0 :         else if (bw == RTW_CHANNEL_WIDTH_40)
     100                 :          0 :                 si->ra_report.txrate.bw = RATE_INFO_BW_40;
     101                 :            :         else
     102                 :          0 :                 si->ra_report.txrate.bw = RATE_INFO_BW_20;
     103                 :            : 
     104                 :          0 : legacy:
     105                 :          0 :         bit_rate = cfg80211_calculate_bitrate(&si->ra_report.txrate);
     106                 :            : 
     107                 :          0 :         si->ra_report.desc_rate = rate;
     108                 :          0 :         si->ra_report.bit_rate = bit_rate;
     109                 :            : 
     110         [ #  # ]:          0 :         sta->max_rc_amsdu_len = get_max_amsdu_len(bit_rate);
     111                 :            : }
     112                 :            : 
     113                 :          0 : static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload,
     114                 :            :                                     u8 length)
     115                 :            : {
     116                 :          0 :         struct rtw_fw_iter_ra_data ra_data;
     117                 :            : 
     118   [ #  #  #  # ]:          0 :         if (WARN(length < 7, "invalid ra report c2h length\n"))
     119                 :          0 :                 return;
     120                 :            : 
     121                 :          0 :         rtwdev->dm_info.tx_rate = GET_RA_REPORT_RATE(payload);
     122                 :          0 :         ra_data.rtwdev = rtwdev;
     123                 :          0 :         ra_data.payload = payload;
     124                 :          0 :         rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data);
     125                 :            : }
     126                 :            : 
     127                 :          0 : void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
     128                 :            : {
     129                 :          0 :         struct rtw_c2h_cmd *c2h;
     130                 :          0 :         u32 pkt_offset;
     131                 :          0 :         u8 len;
     132                 :            : 
     133                 :          0 :         pkt_offset = *((u32 *)skb->cb);
     134                 :          0 :         c2h = (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
     135                 :          0 :         len = skb->len - pkt_offset - 2;
     136                 :            : 
     137                 :          0 :         mutex_lock(&rtwdev->mutex);
     138                 :            : 
     139   [ #  #  #  #  :          0 :         switch (c2h->id) {
                      # ]
     140                 :          0 :         case C2H_BT_INFO:
     141                 :          0 :                 rtw_coex_bt_info_notify(rtwdev, c2h->payload, len);
     142                 :          0 :                 break;
     143                 :          0 :         case C2H_WLAN_INFO:
     144                 :          0 :                 rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len);
     145                 :          0 :                 break;
     146                 :            :         case C2H_HALMAC:
     147         [ #  # ]:          0 :                 rtw_fw_c2h_cmd_handle_ext(rtwdev, skb);
     148                 :            :                 break;
     149                 :          0 :         case C2H_RA_RPT:
     150                 :          0 :                 rtw_fw_ra_report_handle(rtwdev, c2h->payload, len);
     151                 :          0 :                 break;
     152                 :            :         default:
     153                 :            :                 break;
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         mutex_unlock(&rtwdev->mutex);
     157                 :          0 : }
     158                 :            : 
     159                 :          0 : void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
     160                 :            :                                struct sk_buff *skb)
     161                 :            : {
     162                 :          0 :         struct rtw_c2h_cmd *c2h;
     163                 :          0 :         u8 len;
     164                 :            : 
     165                 :          0 :         c2h = (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
     166                 :          0 :         len = skb->len - pkt_offset - 2;
     167                 :          0 :         *((u32 *)skb->cb) = pkt_offset;
     168                 :            : 
     169                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_FW, "recv C2H, id=0x%02x, seq=0x%02x, len=%d\n",
     170                 :            :                 c2h->id, c2h->seq, len);
     171                 :            : 
     172         [ #  # ]:          0 :         switch (c2h->id) {
     173                 :          0 :         case C2H_BT_MP_INFO:
     174                 :          0 :                 rtw_coex_info_response(rtwdev, skb);
     175                 :          0 :                 break;
     176                 :          0 :         default:
     177                 :            :                 /* pass offset for further operation */
     178                 :          0 :                 *((u32 *)skb->cb) = pkt_offset;
     179                 :          0 :                 skb_queue_tail(&rtwdev->c2h_queue, skb);
     180                 :          0 :                 ieee80211_queue_work(rtwdev->hw, &rtwdev->c2h_work);
     181                 :          0 :                 break;
     182                 :            :         }
     183                 :          0 : }
     184                 :            : EXPORT_SYMBOL(rtw_fw_c2h_cmd_rx_irqsafe);
     185                 :            : 
     186                 :          0 : static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
     187                 :            :                                     u8 *h2c)
     188                 :            : {
     189                 :          0 :         u8 box;
     190                 :          0 :         u8 box_state;
     191                 :          0 :         u32 box_reg, box_ex_reg;
     192                 :          0 :         u32 h2c_wait;
     193                 :          0 :         int idx;
     194                 :            : 
     195                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_FW,
     196                 :            :                 "send H2C content %02x%02x%02x%02x %02x%02x%02x%02x\n",
     197                 :            :                 h2c[3], h2c[2], h2c[1], h2c[0],
     198                 :            :                 h2c[7], h2c[6], h2c[5], h2c[4]);
     199                 :            : 
     200                 :          0 :         spin_lock(&rtwdev->h2c.lock);
     201                 :            : 
     202                 :          0 :         box = rtwdev->h2c.last_box_num;
     203         [ #  # ]:          0 :         switch (box) {
     204                 :            :         case 0:
     205                 :            :                 box_reg = REG_HMEBOX0;
     206                 :            :                 box_ex_reg = REG_HMEBOX0_EX;
     207                 :            :                 break;
     208                 :            :         case 1:
     209                 :            :                 box_reg = REG_HMEBOX1;
     210                 :            :                 box_ex_reg = REG_HMEBOX1_EX;
     211                 :            :                 break;
     212                 :            :         case 2:
     213                 :            :                 box_reg = REG_HMEBOX2;
     214                 :            :                 box_ex_reg = REG_HMEBOX2_EX;
     215                 :            :                 break;
     216                 :            :         case 3:
     217                 :            :                 box_reg = REG_HMEBOX3;
     218                 :            :                 box_ex_reg = REG_HMEBOX3_EX;
     219                 :            :                 break;
     220                 :            :         default:
     221                 :          0 :                 WARN(1, "invalid h2c mail box number\n");
     222                 :          0 :                 goto out;
     223                 :            :         }
     224                 :            : 
     225                 :          0 :         h2c_wait = 20;
     226                 :          0 :         do {
     227                 :          0 :                 box_state = rtw_read8(rtwdev, REG_HMETFR);
     228   [ #  #  #  # ]:          0 :         } while ((box_state >> box) & 0x1 && --h2c_wait > 0);
     229                 :            : 
     230         [ #  # ]:          0 :         if (!h2c_wait) {
     231                 :          0 :                 rtw_err(rtwdev, "failed to send h2c command\n");
     232                 :          0 :                 goto out;
     233                 :            :         }
     234                 :            : 
     235         [ #  # ]:          0 :         for (idx = 0; idx < 4; idx++)
     236                 :          0 :                 rtw_write8(rtwdev, box_reg + idx, h2c[idx]);
     237         [ #  # ]:          0 :         for (idx = 0; idx < 4; idx++)
     238                 :          0 :                 rtw_write8(rtwdev, box_ex_reg + idx, h2c[idx + 4]);
     239                 :            : 
     240         [ #  # ]:          0 :         if (++rtwdev->h2c.last_box_num >= 4)
     241                 :          0 :                 rtwdev->h2c.last_box_num = 0;
     242                 :            : 
     243                 :          0 : out:
     244                 :          0 :         spin_unlock(&rtwdev->h2c.lock);
     245                 :          0 : }
     246                 :            : 
     247                 :          0 : static void rtw_fw_send_h2c_packet(struct rtw_dev *rtwdev, u8 *h2c_pkt)
     248                 :            : {
     249                 :          0 :         int ret;
     250                 :            : 
     251                 :          0 :         spin_lock(&rtwdev->h2c.lock);
     252                 :            : 
     253         [ #  # ]:          0 :         FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, rtwdev->h2c.seq);
     254                 :          0 :         ret = rtw_hci_write_data_h2c(rtwdev, h2c_pkt, H2C_PKT_SIZE);
     255         [ #  # ]:          0 :         if (ret)
     256                 :          0 :                 rtw_err(rtwdev, "failed to send h2c packet\n");
     257                 :          0 :         rtwdev->h2c.seq++;
     258                 :            : 
     259                 :          0 :         spin_unlock(&rtwdev->h2c.lock);
     260                 :          0 : }
     261                 :            : 
     262                 :            : void
     263                 :          0 : rtw_fw_send_general_info(struct rtw_dev *rtwdev)
     264                 :            : {
     265                 :          0 :         struct rtw_fifo_conf *fifo = &rtwdev->fifo;
     266                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     267                 :          0 :         u16 total_size = H2C_PKT_HDR_SIZE + 4;
     268                 :            : 
     269         [ #  # ]:          0 :         rtw_h2c_pkt_set_header(h2c_pkt, H2C_PKT_GENERAL_INFO);
     270                 :            : 
     271                 :          0 :         SET_PKT_H2C_TOTAL_LEN(h2c_pkt, total_size);
     272                 :            : 
     273         [ #  # ]:          0 :         GENERAL_INFO_SET_FW_TX_BOUNDARY(h2c_pkt,
     274                 :            :                                         fifo->rsvd_fw_txbuf_addr -
     275                 :            :                                         fifo->rsvd_boundary);
     276                 :            : 
     277                 :          0 :         rtw_fw_send_h2c_packet(rtwdev, h2c_pkt);
     278                 :          0 : }
     279                 :            : 
     280                 :            : void
     281                 :          0 : rtw_fw_send_phydm_info(struct rtw_dev *rtwdev)
     282                 :            : {
     283                 :          0 :         struct rtw_hal *hal = &rtwdev->hal;
     284                 :          0 :         struct rtw_efuse *efuse = &rtwdev->efuse;
     285                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     286                 :          0 :         u16 total_size = H2C_PKT_HDR_SIZE + 8;
     287                 :          0 :         u8 fw_rf_type = 0;
     288                 :            : 
     289         [ #  # ]:          0 :         if (hal->rf_type == RF_1T1R)
     290                 :            :                 fw_rf_type = FW_RF_1T1R;
     291         [ #  # ]:          0 :         else if (hal->rf_type == RF_2T2R)
     292                 :          0 :                 fw_rf_type = FW_RF_2T2R;
     293                 :            : 
     294         [ #  # ]:          0 :         rtw_h2c_pkt_set_header(h2c_pkt, H2C_PKT_PHYDM_INFO);
     295                 :            : 
     296                 :          0 :         SET_PKT_H2C_TOTAL_LEN(h2c_pkt, total_size);
     297                 :          0 :         PHYDM_INFO_SET_REF_TYPE(h2c_pkt, efuse->rfe_option);
     298                 :          0 :         PHYDM_INFO_SET_RF_TYPE(h2c_pkt, fw_rf_type);
     299                 :          0 :         PHYDM_INFO_SET_CUT_VER(h2c_pkt, hal->cut_version);
     300         [ #  # ]:          0 :         PHYDM_INFO_SET_RX_ANT_STATUS(h2c_pkt, hal->antenna_tx);
     301         [ #  # ]:          0 :         PHYDM_INFO_SET_TX_ANT_STATUS(h2c_pkt, hal->antenna_rx);
     302                 :            : 
     303                 :          0 :         rtw_fw_send_h2c_packet(rtwdev, h2c_pkt);
     304                 :          0 : }
     305                 :            : 
     306                 :          0 : void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para)
     307                 :            : {
     308                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     309                 :          0 :         u16 total_size = H2C_PKT_HDR_SIZE + 1;
     310                 :            : 
     311         [ #  # ]:          0 :         rtw_h2c_pkt_set_header(h2c_pkt, H2C_PKT_IQK);
     312                 :          0 :         SET_PKT_H2C_TOTAL_LEN(h2c_pkt, total_size);
     313         [ #  # ]:          0 :         IQK_SET_CLEAR(h2c_pkt, para->clear);
     314         [ #  # ]:          0 :         IQK_SET_SEGMENT_IQK(h2c_pkt, para->segment_iqk);
     315                 :            : 
     316                 :          0 :         rtw_fw_send_h2c_packet(rtwdev, h2c_pkt);
     317                 :          0 : }
     318                 :            : 
     319                 :          0 : void rtw_fw_query_bt_info(struct rtw_dev *rtwdev)
     320                 :            : {
     321                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     322                 :            : 
     323                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_QUERY_BT_INFO);
     324                 :            : 
     325                 :          0 :         SET_QUERY_BT_INFO(h2c_pkt, true);
     326                 :            : 
     327                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     328                 :          0 : }
     329                 :            : 
     330                 :          0 : void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw)
     331                 :            : {
     332                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     333                 :            : 
     334                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_WL_CH_INFO);
     335                 :            : 
     336                 :          0 :         SET_WL_CH_INFO_LINK(h2c_pkt, link);
     337                 :          0 :         SET_WL_CH_INFO_CHNL(h2c_pkt, ch);
     338                 :          0 :         SET_WL_CH_INFO_BW(h2c_pkt, bw);
     339                 :            : 
     340                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     341                 :          0 : }
     342                 :            : 
     343                 :          0 : void rtw_fw_query_bt_mp_info(struct rtw_dev *rtwdev,
     344                 :            :                              struct rtw_coex_info_req *req)
     345                 :            : {
     346                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     347                 :            : 
     348         [ #  # ]:          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_QUERY_BT_MP_INFO);
     349                 :            : 
     350         [ #  # ]:          0 :         SET_BT_MP_INFO_SEQ(h2c_pkt, req->seq);
     351                 :          0 :         SET_BT_MP_INFO_OP_CODE(h2c_pkt, req->op_code);
     352                 :          0 :         SET_BT_MP_INFO_PARA1(h2c_pkt, req->para1);
     353                 :          0 :         SET_BT_MP_INFO_PARA2(h2c_pkt, req->para2);
     354                 :          0 :         SET_BT_MP_INFO_PARA3(h2c_pkt, req->para3);
     355                 :            : 
     356                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     357                 :          0 : }
     358                 :            : 
     359                 :          0 : void rtw_fw_force_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl)
     360                 :            : {
     361                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     362                 :          0 :         u8 index = 0 - bt_pwr_dec_lvl;
     363                 :            : 
     364                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_FORCE_BT_TX_POWER);
     365                 :            : 
     366                 :          0 :         SET_BT_TX_POWER_INDEX(h2c_pkt, index);
     367                 :            : 
     368                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     369                 :          0 : }
     370                 :            : 
     371                 :          0 : void rtw_fw_bt_ignore_wlan_action(struct rtw_dev *rtwdev, bool enable)
     372                 :            : {
     373                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     374                 :            : 
     375                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_IGNORE_WLAN_ACTION);
     376                 :            : 
     377                 :          0 :         SET_IGNORE_WLAN_ACTION_EN(h2c_pkt, enable);
     378                 :            : 
     379                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     380                 :          0 : }
     381                 :            : 
     382                 :          0 : void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
     383                 :            :                            u8 para1, u8 para2, u8 para3, u8 para4, u8 para5)
     384                 :            : {
     385                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     386                 :            : 
     387                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_COEX_TDMA_TYPE);
     388                 :            : 
     389                 :          0 :         SET_COEX_TDMA_TYPE_PARA1(h2c_pkt, para1);
     390                 :          0 :         SET_COEX_TDMA_TYPE_PARA2(h2c_pkt, para2);
     391                 :          0 :         SET_COEX_TDMA_TYPE_PARA3(h2c_pkt, para3);
     392                 :          0 :         SET_COEX_TDMA_TYPE_PARA4(h2c_pkt, para4);
     393                 :          0 :         SET_COEX_TDMA_TYPE_PARA5(h2c_pkt, para5);
     394                 :            : 
     395                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     396                 :          0 : }
     397                 :            : 
     398                 :          0 : void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data)
     399                 :            : {
     400                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     401                 :            : 
     402                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BT_WIFI_CONTROL);
     403                 :            : 
     404                 :          0 :         SET_BT_WIFI_CONTROL_OP_CODE(h2c_pkt, op_code);
     405                 :            : 
     406                 :          0 :         SET_BT_WIFI_CONTROL_DATA1(h2c_pkt, *data);
     407                 :          0 :         SET_BT_WIFI_CONTROL_DATA2(h2c_pkt, *(data + 1));
     408                 :          0 :         SET_BT_WIFI_CONTROL_DATA3(h2c_pkt, *(data + 2));
     409                 :          0 :         SET_BT_WIFI_CONTROL_DATA4(h2c_pkt, *(data + 3));
     410                 :          0 :         SET_BT_WIFI_CONTROL_DATA5(h2c_pkt, *(data + 4));
     411                 :            : 
     412                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     413                 :          0 : }
     414                 :            : 
     415                 :          0 : void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si)
     416                 :            : {
     417                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     418                 :          0 :         u8 rssi = ewma_rssi_read(&si->avg_rssi);
     419                 :          0 :         bool stbc_en = si->stbc_en ? true : false;
     420                 :            : 
     421                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RSSI_MONITOR);
     422                 :            : 
     423                 :          0 :         SET_RSSI_INFO_MACID(h2c_pkt, si->mac_id);
     424                 :          0 :         SET_RSSI_INFO_RSSI(h2c_pkt, rssi);
     425                 :          0 :         SET_RSSI_INFO_STBC(h2c_pkt, stbc_en);
     426                 :            : 
     427                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     428                 :          0 : }
     429                 :            : 
     430                 :          0 : void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si)
     431                 :            : {
     432                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     433                 :          0 :         bool no_update = si->updated;
     434                 :          0 :         bool disable_pt = true;
     435                 :            : 
     436         [ #  # ]:          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RA_INFO);
     437                 :            : 
     438                 :          0 :         SET_RA_INFO_MACID(h2c_pkt, si->mac_id);
     439         [ #  # ]:          0 :         SET_RA_INFO_RATE_ID(h2c_pkt, si->rate_id);
     440         [ #  # ]:          0 :         SET_RA_INFO_INIT_RA_LVL(h2c_pkt, si->init_ra_lv);
     441                 :          0 :         SET_RA_INFO_SGI_EN(h2c_pkt, si->sgi_enable);
     442         [ #  # ]:          0 :         SET_RA_INFO_BW_MODE(h2c_pkt, si->bw_mode);
     443         [ #  # ]:          0 :         SET_RA_INFO_LDPC(h2c_pkt, si->ldpc_en);
     444                 :          0 :         SET_RA_INFO_NO_UPDATE(h2c_pkt, no_update);
     445                 :          0 :         SET_RA_INFO_VHT_EN(h2c_pkt, si->vht_enable);
     446                 :          0 :         SET_RA_INFO_DIS_PT(h2c_pkt, disable_pt);
     447                 :          0 :         SET_RA_INFO_RA_MASK0(h2c_pkt, (si->ra_mask & 0xff));
     448                 :          0 :         SET_RA_INFO_RA_MASK1(h2c_pkt, (si->ra_mask & 0xff00) >> 8);
     449                 :          0 :         SET_RA_INFO_RA_MASK2(h2c_pkt, (si->ra_mask & 0xff0000) >> 16);
     450                 :          0 :         SET_RA_INFO_RA_MASK3(h2c_pkt, (si->ra_mask & 0xff000000) >> 24);
     451                 :            : 
     452                 :          0 :         si->init_ra_lv = 0;
     453                 :          0 :         si->updated = true;
     454                 :            : 
     455                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     456                 :          0 : }
     457                 :            : 
     458                 :          0 : void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool connect)
     459                 :            : {
     460                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     461                 :            : 
     462                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_MEDIA_STATUS_RPT);
     463                 :          0 :         MEDIA_STATUS_RPT_SET_OP_MODE(h2c_pkt, connect);
     464                 :          0 :         MEDIA_STATUS_RPT_SET_MACID(h2c_pkt, mac_id);
     465                 :            : 
     466                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     467                 :          0 : }
     468                 :            : 
     469                 :          0 : void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev)
     470                 :            : {
     471                 :          0 :         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
     472                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     473                 :            : 
     474         [ #  # ]:          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_SET_PWR_MODE);
     475                 :            : 
     476         [ #  # ]:          0 :         SET_PWR_MODE_SET_MODE(h2c_pkt, conf->mode);
     477         [ #  # ]:          0 :         SET_PWR_MODE_SET_RLBM(h2c_pkt, conf->rlbm);
     478         [ #  # ]:          0 :         SET_PWR_MODE_SET_SMART_PS(h2c_pkt, conf->smart_ps);
     479                 :          0 :         SET_PWR_MODE_SET_AWAKE_INTERVAL(h2c_pkt, conf->awake_interval);
     480         [ #  # ]:          0 :         SET_PWR_MODE_SET_PORT_ID(h2c_pkt, conf->port_id);
     481         [ #  # ]:          0 :         SET_PWR_MODE_SET_PWR_STATE(h2c_pkt, conf->state);
     482                 :            : 
     483                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     484                 :          0 : }
     485                 :            : 
     486                 :          0 : void rtw_fw_set_keep_alive_cmd(struct rtw_dev *rtwdev, bool enable)
     487                 :            : {
     488                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     489                 :          0 :         struct rtw_fw_wow_keep_alive_para mode = {
     490                 :            :                 .adopt = true,
     491                 :            :                 .pkt_type = KEEP_ALIVE_NULL_PKT,
     492                 :            :                 .period = 5,
     493                 :            :         };
     494                 :            : 
     495                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_KEEP_ALIVE);
     496                 :          0 :         SET_KEEP_ALIVE_ENABLE(h2c_pkt, enable);
     497                 :          0 :         SET_KEEP_ALIVE_ADOPT(h2c_pkt, mode.adopt);
     498                 :          0 :         SET_KEEP_ALIVE_PKT_TYPE(h2c_pkt, mode.pkt_type);
     499                 :          0 :         SET_KEEP_ALIVE_CHECK_PERIOD(h2c_pkt, mode.period);
     500                 :            : 
     501                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     502                 :          0 : }
     503                 :            : 
     504                 :          0 : void rtw_fw_set_disconnect_decision_cmd(struct rtw_dev *rtwdev, bool enable)
     505                 :            : {
     506                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     507                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     508                 :          0 :         struct rtw_fw_wow_disconnect_para mode = {
     509                 :            :                 .adopt = true,
     510                 :            :                 .period = 30,
     511                 :            :                 .retry_count = 5,
     512                 :            :         };
     513                 :            : 
     514                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_DISCONNECT_DECISION);
     515                 :            : 
     516         [ #  # ]:          0 :         if (test_bit(RTW_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags)) {
     517                 :          0 :                 SET_DISCONNECT_DECISION_ENABLE(h2c_pkt, enable);
     518                 :          0 :                 SET_DISCONNECT_DECISION_ADOPT(h2c_pkt, mode.adopt);
     519                 :          0 :                 SET_DISCONNECT_DECISION_CHECK_PERIOD(h2c_pkt, mode.period);
     520                 :          0 :                 SET_DISCONNECT_DECISION_TRY_PKT_NUM(h2c_pkt, mode.retry_count);
     521                 :            :         }
     522                 :            : 
     523                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     524                 :          0 : }
     525                 :            : 
     526                 :          0 : void rtw_fw_set_wowlan_ctrl_cmd(struct rtw_dev *rtwdev, bool enable)
     527                 :            : {
     528                 :          0 :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     529                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     530                 :            : 
     531         [ #  # ]:          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_WOWLAN);
     532                 :            : 
     533                 :          0 :         SET_WOWLAN_FUNC_ENABLE(h2c_pkt, enable);
     534         [ #  # ]:          0 :         if (rtw_wow_mgd_linked(rtwdev)) {
     535         [ #  # ]:          0 :                 if (test_bit(RTW_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags))
     536                 :          0 :                         SET_WOWLAN_MAGIC_PKT_ENABLE(h2c_pkt, enable);
     537         [ #  # ]:          0 :                 if (test_bit(RTW_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags))
     538                 :          0 :                         SET_WOWLAN_DEAUTH_WAKEUP_ENABLE(h2c_pkt, enable);
     539         [ #  # ]:          0 :                 if (test_bit(RTW_WOW_FLAG_EN_REKEY_PKT, rtw_wow->flags))
     540                 :          0 :                         SET_WOWLAN_REKEY_WAKEUP_ENABLE(h2c_pkt, enable);
     541         [ #  # ]:          0 :                 if (rtw_wow->pattern_cnt)
     542                 :          0 :                         SET_WOWLAN_PATTERN_MATCH_ENABLE(h2c_pkt, enable);
     543                 :            :         }
     544                 :            : 
     545                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     546                 :          0 : }
     547                 :            : 
     548                 :          0 : void rtw_fw_set_aoac_global_info_cmd(struct rtw_dev *rtwdev,
     549                 :            :                                      u8 pairwise_key_enc,
     550                 :            :                                      u8 group_key_enc)
     551                 :            : {
     552                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     553                 :            : 
     554                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_AOAC_GLOBAL_INFO);
     555                 :            : 
     556                 :          0 :         SET_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(h2c_pkt, pairwise_key_enc);
     557                 :          0 :         SET_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(h2c_pkt, group_key_enc);
     558                 :            : 
     559                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     560                 :          0 : }
     561                 :            : 
     562                 :          0 : void rtw_fw_set_remote_wake_ctrl_cmd(struct rtw_dev *rtwdev, bool enable)
     563                 :            : {
     564                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     565                 :            : 
     566         [ #  # ]:          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_REMOTE_WAKE_CTRL);
     567                 :            : 
     568                 :          0 :         SET_REMOTE_WAKECTRL_ENABLE(h2c_pkt, enable);
     569                 :            : 
     570         [ #  # ]:          0 :         if (rtw_wow_no_link(rtwdev))
     571                 :          0 :                 SET_REMOTE_WAKE_CTRL_NLO_OFFLOAD_EN(h2c_pkt, enable);
     572                 :            : 
     573                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     574                 :          0 : }
     575                 :            : 
     576                 :          0 : static u8 rtw_get_rsvd_page_location(struct rtw_dev *rtwdev,
     577                 :            :                                      enum rtw_rsvd_packet_type type)
     578                 :            : {
     579                 :          0 :         struct rtw_rsvd_page *rsvd_pkt;
     580                 :          0 :         u8 location = 0;
     581                 :            : 
     582   [ #  #  #  #  :          0 :         list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     583   [ #  #  #  #  :          0 :                 if (type == rsvd_pkt->type)
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     584                 :          0 :                         location = rsvd_pkt->page;
     585                 :            :         }
     586                 :            : 
     587                 :          0 :         return location;
     588                 :            : }
     589                 :            : 
     590                 :          0 : void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable)
     591                 :            : {
     592                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     593                 :          0 :         u8 loc_nlo;
     594                 :            : 
     595                 :          0 :         loc_nlo = rtw_get_rsvd_page_location(rtwdev, RSVD_NLO_INFO);
     596                 :            : 
     597         [ #  # ]:          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_NLO_INFO);
     598                 :            : 
     599                 :          0 :         SET_NLO_FUN_EN(h2c_pkt, enable);
     600         [ #  # ]:          0 :         if (enable) {
     601         [ #  # ]:          0 :                 if (rtw_fw_lps_deep_mode)
     602                 :          0 :                         SET_NLO_PS_32K(h2c_pkt, enable);
     603                 :          0 :                 SET_NLO_IGNORE_SECURITY(h2c_pkt, enable);
     604                 :          0 :                 SET_NLO_LOC_NLO_INFO(h2c_pkt, loc_nlo);
     605                 :            :         }
     606                 :            : 
     607                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     608                 :          0 : }
     609                 :            : 
     610                 :          0 : void rtw_fw_set_pg_info(struct rtw_dev *rtwdev)
     611                 :            : {
     612                 :          0 :         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
     613                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     614                 :          0 :         u8 loc_pg, loc_dpk;
     615                 :            : 
     616                 :          0 :         loc_pg = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_INFO);
     617                 :            :         loc_dpk = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_DPK);
     618                 :            : 
     619                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_LPS_PG_INFO);
     620                 :            : 
     621                 :          0 :         LPS_PG_INFO_LOC(h2c_pkt, loc_pg);
     622                 :          0 :         LPS_PG_DPK_LOC(h2c_pkt, loc_dpk);
     623                 :          0 :         LPS_PG_SEC_CAM_EN(h2c_pkt, conf->sec_cam_backup);
     624                 :          0 :         LPS_PG_PATTERN_CAM_EN(h2c_pkt, conf->pattern_cam_backup);
     625                 :            : 
     626                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     627                 :          0 : }
     628                 :            : 
     629                 :          0 : u8 rtw_get_rsvd_page_probe_req_location(struct rtw_dev *rtwdev,
     630                 :            :                                         struct cfg80211_ssid *ssid)
     631                 :            : {
     632                 :          0 :         struct rtw_rsvd_page *rsvd_pkt;
     633                 :          0 :         u8 location = 0;
     634                 :            : 
     635         [ #  # ]:          0 :         list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) {
     636         [ #  # ]:          0 :                 if (rsvd_pkt->type != RSVD_PROBE_REQ)
     637                 :          0 :                         continue;
     638   [ #  #  #  # ]:          0 :                 if ((!ssid && !rsvd_pkt->ssid) ||
     639         [ #  # ]:          0 :                     rtw_ssid_equal(rsvd_pkt->ssid, ssid))
     640                 :          0 :                         location = rsvd_pkt->page;
     641                 :            :         }
     642                 :            : 
     643                 :          0 :         return location;
     644                 :            : }
     645                 :            : 
     646                 :          0 : u16 rtw_get_rsvd_page_probe_req_size(struct rtw_dev *rtwdev,
     647                 :            :                                      struct cfg80211_ssid *ssid)
     648                 :            : {
     649                 :          0 :         struct rtw_rsvd_page *rsvd_pkt;
     650                 :          0 :         u16 size = 0;
     651                 :            : 
     652         [ #  # ]:          0 :         list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) {
     653         [ #  # ]:          0 :                 if (rsvd_pkt->type != RSVD_PROBE_REQ)
     654                 :          0 :                         continue;
     655   [ #  #  #  # ]:          0 :                 if ((!ssid && !rsvd_pkt->ssid) ||
     656         [ #  # ]:          0 :                     rtw_ssid_equal(rsvd_pkt->ssid, ssid))
     657                 :          0 :                         size = rsvd_pkt->skb->len;
     658                 :            :         }
     659                 :            : 
     660                 :          0 :         return size;
     661                 :            : }
     662                 :            : 
     663                 :          0 : void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev)
     664                 :            : {
     665                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
     666                 :          0 :         u8 location = 0;
     667                 :            : 
     668                 :          0 :         SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RSVD_PAGE);
     669                 :            : 
     670                 :          0 :         location = rtw_get_rsvd_page_location(rtwdev, RSVD_PROBE_RESP);
     671                 :          0 :         *(h2c_pkt + 1) = location;
     672                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_FW, "RSVD_PROBE_RESP loc: %d\n", location);
     673                 :            : 
     674                 :          0 :         location = rtw_get_rsvd_page_location(rtwdev, RSVD_PS_POLL);
     675                 :          0 :         *(h2c_pkt + 2) = location;
     676                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_FW, "RSVD_PS_POLL loc: %d\n", location);
     677                 :            : 
     678                 :          0 :         location = rtw_get_rsvd_page_location(rtwdev, RSVD_NULL);
     679                 :          0 :         *(h2c_pkt + 3) = location;
     680                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_FW, "RSVD_NULL loc: %d\n", location);
     681                 :            : 
     682                 :          0 :         location = rtw_get_rsvd_page_location(rtwdev, RSVD_QOS_NULL);
     683                 :          0 :         *(h2c_pkt + 4) = location;
     684                 :          0 :         rtw_dbg(rtwdev, RTW_DBG_FW, "RSVD_QOS_NULL loc: %d\n", location);
     685                 :            : 
     686                 :          0 :         rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
     687                 :          0 : }
     688                 :            : 
     689                 :            : static struct sk_buff *
     690                 :          0 : rtw_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
     691                 :            : {
     692                 :          0 :         struct sk_buff *skb_new;
     693                 :            : 
     694   [ #  #  #  # ]:          0 :         if (vif->type != NL80211_IFTYPE_AP &&
     695                 :            :             vif->type != NL80211_IFTYPE_ADHOC &&
     696                 :            :             !ieee80211_vif_is_mesh(vif)) {
     697                 :          0 :                 skb_new = alloc_skb(1, GFP_KERNEL);
     698         [ #  # ]:          0 :                 if (!skb_new)
     699                 :            :                         return NULL;
     700                 :          0 :                 skb_put(skb_new, 1);
     701                 :            :         } else {
     702                 :          0 :                 skb_new = ieee80211_beacon_get(hw, vif);
     703                 :            :         }
     704                 :            : 
     705                 :            :         return skb_new;
     706                 :            : }
     707                 :            : 
     708                 :            : static struct sk_buff *rtw_nlo_info_get(struct ieee80211_hw *hw)
     709                 :            : {
     710                 :            :         struct rtw_dev *rtwdev = hw->priv;
     711                 :            :         struct rtw_chip_info *chip = rtwdev->chip;
     712                 :            :         struct rtw_pno_request *pno_req = &rtwdev->wow.pno_req;
     713                 :            :         struct rtw_nlo_info_hdr *nlo_hdr;
     714                 :            :         struct cfg80211_ssid *ssid;
     715                 :            :         struct sk_buff *skb;
     716                 :            :         u8 *pos, loc;
     717                 :            :         u32 size;
     718                 :            :         int i;
     719                 :            : 
     720                 :            :         if (!pno_req->inited || !pno_req->match_set_cnt)
     721                 :            :                 return NULL;
     722                 :            : 
     723                 :            :         size = sizeof(struct rtw_nlo_info_hdr) + pno_req->match_set_cnt *
     724                 :            :                       IEEE80211_MAX_SSID_LEN + chip->tx_pkt_desc_sz;
     725                 :            : 
     726                 :            :         skb = alloc_skb(size, GFP_KERNEL);
     727                 :            :         if (!skb)
     728                 :            :                 return NULL;
     729                 :            : 
     730                 :            :         skb_reserve(skb, chip->tx_pkt_desc_sz);
     731                 :            : 
     732                 :            :         nlo_hdr = skb_put_zero(skb, sizeof(struct rtw_nlo_info_hdr));
     733                 :            : 
     734                 :            :         nlo_hdr->nlo_count = pno_req->match_set_cnt;
     735                 :            :         nlo_hdr->hidden_ap_count = pno_req->match_set_cnt;
     736                 :            : 
     737                 :            :         /* pattern check for firmware */
     738                 :            :         memset(nlo_hdr->pattern_check, 0xA5, FW_NLO_INFO_CHECK_SIZE);
     739                 :            : 
     740                 :            :         for (i = 0; i < pno_req->match_set_cnt; i++)
     741                 :            :                 nlo_hdr->ssid_len[i] = pno_req->match_sets[i].ssid.ssid_len;
     742                 :            : 
     743                 :            :         for (i = 0; i < pno_req->match_set_cnt; i++) {
     744                 :            :                 ssid = &pno_req->match_sets[i].ssid;
     745                 :            :                 loc  = rtw_get_rsvd_page_probe_req_location(rtwdev, ssid);
     746                 :            :                 if (!loc) {
     747                 :            :                         rtw_err(rtwdev, "failed to get probe req rsvd loc\n");
     748                 :            :                         kfree(skb);
     749                 :            :                         return NULL;
     750                 :            :                 }
     751                 :            :                 nlo_hdr->location[i] = loc;
     752                 :            :         }
     753                 :            : 
     754                 :            :         for (i = 0; i < pno_req->match_set_cnt; i++) {
     755                 :            :                 pos = skb_put_zero(skb, IEEE80211_MAX_SSID_LEN);
     756                 :            :                 memcpy(pos, pno_req->match_sets[i].ssid.ssid,
     757                 :            :                        pno_req->match_sets[i].ssid.ssid_len);
     758                 :            :         }
     759                 :            : 
     760                 :            :         return skb;
     761                 :            : }
     762                 :            : 
     763                 :            : static struct sk_buff *rtw_cs_channel_info_get(struct ieee80211_hw *hw)
     764                 :            : {
     765                 :            :         struct rtw_dev *rtwdev = hw->priv;
     766                 :            :         struct rtw_chip_info *chip = rtwdev->chip;
     767                 :            :         struct rtw_pno_request *pno_req = &rtwdev->wow.pno_req;
     768                 :            :         struct ieee80211_channel *channels = pno_req->channels;
     769                 :            :         struct sk_buff *skb;
     770                 :            :         int count =  pno_req->channel_cnt;
     771                 :            :         u8 *pos;
     772                 :            :         int i = 0;
     773                 :            : 
     774                 :            :         skb = alloc_skb(4 * count + chip->tx_pkt_desc_sz, GFP_KERNEL);
     775                 :            :         if (!skb)
     776                 :            :                 return NULL;
     777                 :            : 
     778                 :            :         skb_reserve(skb, chip->tx_pkt_desc_sz);
     779                 :            : 
     780                 :            :         for (i = 0; i < count; i++) {
     781                 :            :                 pos = skb_put_zero(skb, 4);
     782                 :            : 
     783                 :            :                 CHSW_INFO_SET_CH(pos, channels[i].hw_value);
     784                 :            : 
     785                 :            :                 if (channels[i].flags & IEEE80211_CHAN_RADAR)
     786                 :            :                         CHSW_INFO_SET_ACTION_ID(pos, 0);
     787                 :            :                 else
     788                 :            :                         CHSW_INFO_SET_ACTION_ID(pos, 1);
     789                 :            :                 CHSW_INFO_SET_TIMEOUT(pos, 1);
     790                 :            :                 CHSW_INFO_SET_PRI_CH_IDX(pos, 1);
     791                 :            :                 CHSW_INFO_SET_BW(pos, 0);
     792                 :            :         }
     793                 :            : 
     794                 :            :         return skb;
     795                 :            : }
     796                 :            : 
     797                 :            : static struct sk_buff *rtw_lps_pg_dpk_get(struct ieee80211_hw *hw)
     798                 :            : {
     799                 :            :         struct rtw_dev *rtwdev = hw->priv;
     800                 :            :         struct rtw_chip_info *chip = rtwdev->chip;
     801                 :            :         struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info;
     802                 :            :         struct rtw_lps_pg_dpk_hdr *dpk_hdr;
     803                 :            :         struct sk_buff *skb;
     804                 :            :         u32 size;
     805                 :            : 
     806                 :            :         size = chip->tx_pkt_desc_sz + sizeof(*dpk_hdr);
     807                 :            :         skb = alloc_skb(size, GFP_KERNEL);
     808                 :            :         if (!skb)
     809                 :            :                 return NULL;
     810                 :            : 
     811                 :            :         skb_reserve(skb, chip->tx_pkt_desc_sz);
     812                 :            :         dpk_hdr = skb_put_zero(skb, sizeof(*dpk_hdr));
     813                 :            :         dpk_hdr->dpk_ch = dpk_info->dpk_ch;
     814                 :            :         dpk_hdr->dpk_path_ok = dpk_info->dpk_path_ok[0];
     815                 :            :         memcpy(dpk_hdr->dpk_txagc, dpk_info->dpk_txagc, 2);
     816                 :            :         memcpy(dpk_hdr->dpk_gs, dpk_info->dpk_gs, 4);
     817                 :            :         memcpy(dpk_hdr->coef, dpk_info->coef, 160);
     818                 :            : 
     819                 :            :         return skb;
     820                 :            : }
     821                 :            : 
     822                 :            : static struct sk_buff *rtw_lps_pg_info_get(struct ieee80211_hw *hw,
     823                 :            :                                            struct ieee80211_vif *vif)
     824                 :            : {
     825                 :            :         struct rtw_dev *rtwdev = hw->priv;
     826                 :            :         struct rtw_chip_info *chip = rtwdev->chip;
     827                 :            :         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
     828                 :            :         struct rtw_lps_pg_info_hdr *pg_info_hdr;
     829                 :            :         struct rtw_wow_param *rtw_wow = &rtwdev->wow;
     830                 :            :         struct sk_buff *skb;
     831                 :            :         u32 size;
     832                 :            : 
     833                 :            :         size = chip->tx_pkt_desc_sz + sizeof(*pg_info_hdr);
     834                 :            :         skb = alloc_skb(size, GFP_KERNEL);
     835                 :            :         if (!skb)
     836                 :            :                 return NULL;
     837                 :            : 
     838                 :            :         skb_reserve(skb, chip->tx_pkt_desc_sz);
     839                 :            :         pg_info_hdr = skb_put_zero(skb, sizeof(*pg_info_hdr));
     840                 :            :         pg_info_hdr->tx_bu_page_count = rtwdev->fifo.rsvd_drv_pg_num;
     841                 :            :         pg_info_hdr->macid = find_first_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM);
     842                 :            :         pg_info_hdr->sec_cam_count =
     843                 :            :                 rtw_sec_cam_pg_backup(rtwdev, pg_info_hdr->sec_cam);
     844                 :            :         pg_info_hdr->pattern_count = rtw_wow->pattern_cnt;
     845                 :            : 
     846                 :            :         conf->sec_cam_backup = pg_info_hdr->sec_cam_count != 0;
     847                 :            :         conf->pattern_cam_backup = rtw_wow->pattern_cnt != 0;
     848                 :            : 
     849                 :            :         return skb;
     850                 :            : }
     851                 :            : 
     852                 :            : static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw,
     853                 :            :                                              struct ieee80211_vif *vif,
     854                 :            :                                              struct rtw_rsvd_page *rsvd_pkt)
     855                 :            : {
     856                 :            :         struct sk_buff *skb_new;
     857                 :            :         struct cfg80211_ssid *ssid;
     858                 :            : 
     859                 :            :         switch (rsvd_pkt->type) {
     860                 :            :         case RSVD_BEACON:
     861                 :            :                 skb_new = rtw_beacon_get(hw, vif);
     862                 :            :                 break;
     863                 :            :         case RSVD_PS_POLL:
     864                 :            :                 skb_new = ieee80211_pspoll_get(hw, vif);
     865                 :            :                 break;
     866                 :            :         case RSVD_PROBE_RESP:
     867                 :            :                 skb_new = ieee80211_proberesp_get(hw, vif);
     868                 :            :                 break;
     869                 :            :         case RSVD_NULL:
     870                 :            :                 skb_new = ieee80211_nullfunc_get(hw, vif, false);
     871                 :            :                 break;
     872                 :            :         case RSVD_QOS_NULL:
     873                 :            :                 skb_new = ieee80211_nullfunc_get(hw, vif, true);
     874                 :            :                 break;
     875                 :            :         case RSVD_LPS_PG_DPK:
     876                 :            :                 skb_new = rtw_lps_pg_dpk_get(hw);
     877                 :            :                 break;
     878                 :            :         case RSVD_LPS_PG_INFO:
     879                 :            :                 skb_new = rtw_lps_pg_info_get(hw, vif);
     880                 :            :                 break;
     881                 :            :         case RSVD_PROBE_REQ:
     882                 :            :                 ssid = (struct cfg80211_ssid *)rsvd_pkt->ssid;
     883                 :            :                 if (ssid)
     884                 :            :                         skb_new = ieee80211_probereq_get(hw, vif->addr,
     885                 :            :                                                          ssid->ssid,
     886                 :            :                                                          ssid->ssid_len, 0);
     887                 :            :                 else
     888                 :            :                         skb_new = ieee80211_probereq_get(hw, vif->addr, NULL, 0, 0);
     889                 :            :                 break;
     890                 :            :         case RSVD_NLO_INFO:
     891                 :            :                 skb_new = rtw_nlo_info_get(hw);
     892                 :            :                 break;
     893                 :            :         case RSVD_CH_INFO:
     894                 :            :                 skb_new = rtw_cs_channel_info_get(hw);
     895                 :            :                 break;
     896                 :            :         default:
     897                 :            :                 return NULL;
     898                 :            :         }
     899                 :            : 
     900                 :            :         if (!skb_new)
     901                 :            :                 return NULL;
     902                 :            : 
     903                 :            :         return skb_new;
     904                 :            : }
     905                 :            : 
     906                 :          0 : static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb)
     907                 :            : {
     908                 :          0 :         struct rtw_tx_pkt_info pkt_info;
     909                 :          0 :         struct rtw_chip_info *chip = rtwdev->chip;
     910                 :          0 :         u8 *pkt_desc;
     911                 :            : 
     912                 :          0 :         memset(&pkt_info, 0, sizeof(pkt_info));
     913                 :          0 :         rtw_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb);
     914                 :          0 :         pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
     915                 :          0 :         memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
     916                 :          0 :         rtw_tx_fill_tx_desc(&pkt_info, skb);
     917                 :          0 : }
     918                 :            : 
     919                 :          0 : static inline u8 rtw_len_to_page(unsigned int len, u8 page_size)
     920                 :            : {
     921                 :          0 :         return DIV_ROUND_UP(len, page_size);
     922                 :            : }
     923                 :            : 
     924                 :          0 : static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u8 page_size,
     925                 :            :                                       u8 page_margin, u32 page, u8 *buf,
     926                 :            :                                       struct rtw_rsvd_page *rsvd_pkt)
     927                 :            : {
     928                 :          0 :         struct sk_buff *skb = rsvd_pkt->skb;
     929                 :            : 
     930         [ #  # ]:          0 :         if (page >= 1)
     931                 :          0 :                 memcpy(buf + page_margin + page_size * (page - 1),
     932                 :          0 :                        skb->data, skb->len);
     933                 :            :         else
     934                 :          0 :                 memcpy(buf, skb->data, skb->len);
     935                 :          0 : }
     936                 :            : 
     937                 :         13 : static struct rtw_rsvd_page *rtw_alloc_rsvd_page(struct rtw_dev *rtwdev,
     938                 :            :                                                  enum rtw_rsvd_packet_type type,
     939                 :            :                                                  bool txdesc)
     940                 :            : {
     941                 :         13 :         struct rtw_rsvd_page *rsvd_pkt = NULL;
     942                 :            : 
     943                 :         13 :         rsvd_pkt = kzalloc(sizeof(*rsvd_pkt), GFP_KERNEL);
     944                 :            : 
     945   [ -  -  +  - ]:         13 :         if (!rsvd_pkt)
     946                 :            :                 return NULL;
     947                 :            : 
     948                 :         13 :         rsvd_pkt->type = type;
     949                 :         13 :         rsvd_pkt->add_txdesc = txdesc;
     950                 :            : 
     951                 :         13 :         return rsvd_pkt;
     952                 :            : }
     953                 :            : 
     954                 :         13 : static void rtw_insert_rsvd_page(struct rtw_dev *rtwdev,
     955                 :            :                                  struct rtw_rsvd_page *rsvd_pkt)
     956                 :            : {
     957                 :         13 :         lockdep_assert_held(&rtwdev->mutex);
     958                 :         13 :         list_add_tail(&rsvd_pkt->list, &rtwdev->rsvd_page_list);
     959                 :         13 : }
     960                 :            : 
     961                 :         13 : void rtw_add_rsvd_page(struct rtw_dev *rtwdev, enum rtw_rsvd_packet_type type,
     962                 :            :                        bool txdesc)
     963                 :            : {
     964                 :         13 :         struct rtw_rsvd_page *rsvd_pkt;
     965                 :            : 
     966                 :         13 :         rsvd_pkt = rtw_alloc_rsvd_page(rtwdev, type, txdesc);
     967                 :         13 :         if (!rsvd_pkt)
     968                 :            :                 return;
     969                 :            : 
     970                 :         13 :         rtw_insert_rsvd_page(rtwdev, rsvd_pkt);
     971                 :            : }
     972                 :            : 
     973                 :          0 : void rtw_add_rsvd_page_probe_req(struct rtw_dev *rtwdev,
     974                 :            :                                  struct cfg80211_ssid *ssid)
     975                 :            : {
     976                 :          0 :         struct rtw_rsvd_page *rsvd_pkt;
     977                 :            : 
     978                 :          0 :         rsvd_pkt = rtw_alloc_rsvd_page(rtwdev, RSVD_PROBE_REQ, true);
     979                 :          0 :         if (!rsvd_pkt)
     980                 :            :                 return;
     981                 :            : 
     982                 :          0 :         rsvd_pkt->ssid = ssid;
     983                 :          0 :         rtw_insert_rsvd_page(rtwdev, rsvd_pkt);
     984                 :            : }
     985                 :            : 
     986                 :          0 : void rtw_reset_rsvd_page(struct rtw_dev *rtwdev)
     987                 :            : {
     988                 :          0 :         struct rtw_rsvd_page *rsvd_pkt, *tmp;
     989                 :            : 
     990                 :          0 :         lockdep_assert_held(&rtwdev->mutex);
     991                 :            : 
     992         [ #  # ]:          0 :         list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list, list) {
     993         [ #  # ]:          0 :                 if (rsvd_pkt->type == RSVD_BEACON)
     994                 :          0 :                         continue;
     995                 :          0 :                 list_del(&rsvd_pkt->list);
     996                 :          0 :                 kfree(rsvd_pkt);
     997                 :            :         }
     998                 :          0 : }
     999                 :            : 
    1000                 :        380 : int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
    1001                 :            :                                 u8 *buf, u32 size)
    1002                 :            : {
    1003                 :        380 :         u8 bckp[2];
    1004                 :        380 :         u8 val;
    1005                 :        380 :         u16 rsvd_pg_head;
    1006                 :        380 :         int ret;
    1007                 :            : 
    1008                 :        380 :         lockdep_assert_held(&rtwdev->mutex);
    1009                 :            : 
    1010         [ +  - ]:        380 :         if (!size)
    1011                 :            :                 return -EINVAL;
    1012                 :            : 
    1013                 :        380 :         pg_addr &= BIT_MASK_BCN_HEAD_1_V1;
    1014                 :        380 :         rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2, pg_addr | BIT_BCN_VALID_V1);
    1015                 :            : 
    1016                 :        380 :         val = rtw_read8(rtwdev, REG_CR + 1);
    1017                 :        380 :         bckp[0] = val;
    1018                 :        380 :         val |= BIT_ENSWBCN >> 8;
    1019                 :        380 :         rtw_write8(rtwdev, REG_CR + 1, val);
    1020                 :            : 
    1021                 :        380 :         val = rtw_read8(rtwdev, REG_FWHW_TXQ_CTRL + 2);
    1022                 :        380 :         bckp[1] = val;
    1023                 :        380 :         val &= ~(BIT_EN_BCNQ_DL >> 16);
    1024                 :        380 :         rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 2, val);
    1025                 :            : 
    1026                 :        380 :         ret = rtw_hci_write_data_rsvd_page(rtwdev, buf, size);
    1027         [ -  + ]:        380 :         if (ret) {
    1028                 :          0 :                 rtw_err(rtwdev, "failed to write data to rsvd page\n");
    1029                 :          0 :                 goto restore;
    1030                 :            :         }
    1031                 :            : 
    1032         [ +  - ]:        380 :         if (!check_hw_ready(rtwdev, REG_FIFOPAGE_CTRL_2, BIT_BCN_VALID_V1, 1)) {
    1033                 :          0 :                 rtw_err(rtwdev, "error beacon valid\n");
    1034                 :          0 :                 ret = -EBUSY;
    1035                 :            :         }
    1036                 :            : 
    1037                 :        380 : restore:
    1038                 :        380 :         rsvd_pg_head = rtwdev->fifo.rsvd_boundary;
    1039                 :        380 :         rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2,
    1040                 :            :                     rsvd_pg_head | BIT_BCN_VALID_V1);
    1041                 :        380 :         rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 2, bckp[1]);
    1042                 :        380 :         rtw_write8(rtwdev, REG_CR + 1, bckp[0]);
    1043                 :            : 
    1044                 :        380 :         return ret;
    1045                 :            : }
    1046                 :            : 
    1047                 :          0 : static int rtw_download_drv_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
    1048                 :            : {
    1049                 :          0 :         u32 pg_size;
    1050                 :          0 :         u32 pg_num = 0;
    1051                 :          0 :         u16 pg_addr = 0;
    1052                 :            : 
    1053                 :          0 :         pg_size = rtwdev->chip->page_size;
    1054         [ #  # ]:          0 :         pg_num = size / pg_size + ((size & (pg_size - 1)) ? 1 : 0);
    1055         [ #  # ]:          0 :         if (pg_num > rtwdev->fifo.rsvd_drv_pg_num)
    1056                 :            :                 return -ENOMEM;
    1057                 :            : 
    1058                 :          0 :         pg_addr = rtwdev->fifo.rsvd_drv_addr;
    1059                 :            : 
    1060                 :          0 :         return rtw_fw_write_data_rsvd_page(rtwdev, pg_addr, buf, size);
    1061                 :            : }
    1062                 :            : 
    1063                 :          0 : static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev,
    1064                 :            :                                struct ieee80211_vif *vif, u32 *size)
    1065                 :            : {
    1066                 :          0 :         struct ieee80211_hw *hw = rtwdev->hw;
    1067                 :          0 :         struct rtw_chip_info *chip = rtwdev->chip;
    1068                 :          0 :         struct sk_buff *iter;
    1069                 :          0 :         struct rtw_rsvd_page *rsvd_pkt;
    1070                 :          0 :         u32 page = 0;
    1071                 :          0 :         u8 total_page = 0;
    1072                 :          0 :         u8 page_size, page_margin, tx_desc_sz;
    1073                 :          0 :         u8 *buf;
    1074                 :            : 
    1075                 :          0 :         page_size = chip->page_size;
    1076                 :          0 :         tx_desc_sz = chip->tx_pkt_desc_sz;
    1077                 :          0 :         page_margin = page_size - tx_desc_sz;
    1078                 :            : 
    1079         [ #  # ]:          0 :         list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) {
    1080                 :          0 :                 iter = rtw_get_rsvd_page_skb(hw, vif, rsvd_pkt);
    1081         [ #  # ]:          0 :                 if (!iter) {
    1082                 :          0 :                         rtw_err(rtwdev, "failed to build rsvd packet\n");
    1083                 :          0 :                         goto release_skb;
    1084                 :            :                 }
    1085                 :            : 
    1086                 :            :                 /* Fill the tx_desc for the rsvd pkt that requires one.
    1087                 :            :                  * And iter->len will be added with size of tx_desc_sz.
    1088                 :            :                  */
    1089         [ #  # ]:          0 :                 if (rsvd_pkt->add_txdesc)
    1090                 :          0 :                         rtw_fill_rsvd_page_desc(rtwdev, iter);
    1091                 :            : 
    1092                 :          0 :                 rsvd_pkt->skb = iter;
    1093                 :          0 :                 rsvd_pkt->page = total_page;
    1094                 :            : 
    1095                 :            :                 /* Reserved page is downloaded via TX path, and TX path will
    1096                 :            :                  * generate a tx_desc at the header to describe length of
    1097                 :            :                  * the buffer. If we are not counting page numbers with the
    1098                 :            :                  * size of tx_desc added at the first rsvd_pkt (usually a
    1099                 :            :                  * beacon, firmware default refer to the first page as the
    1100                 :            :                  * content of beacon), we could generate a buffer which size
    1101                 :            :                  * is smaller than the actual size of the whole rsvd_page
    1102                 :            :                  */
    1103         [ #  # ]:          0 :                 if (total_page == 0) {
    1104         [ #  # ]:          0 :                         if (rsvd_pkt->type != RSVD_BEACON) {
    1105                 :          0 :                                 rtw_err(rtwdev, "first page should be a beacon\n");
    1106                 :          0 :                                 goto release_skb;
    1107                 :            :                         }
    1108                 :          0 :                         total_page += rtw_len_to_page(iter->len + tx_desc_sz,
    1109                 :            :                                                       page_size);
    1110                 :            :                 } else {
    1111                 :          0 :                         total_page += rtw_len_to_page(iter->len, page_size);
    1112                 :            :                 }
    1113                 :            :         }
    1114                 :            : 
    1115         [ #  # ]:          0 :         if (total_page > rtwdev->fifo.rsvd_drv_pg_num) {
    1116                 :          0 :                 rtw_err(rtwdev, "rsvd page over size: %d\n", total_page);
    1117                 :          0 :                 goto release_skb;
    1118                 :            :         }
    1119                 :            : 
    1120                 :          0 :         *size = (total_page - 1) * page_size + page_margin;
    1121                 :          0 :         buf = kzalloc(*size, GFP_KERNEL);
    1122         [ #  # ]:          0 :         if (!buf)
    1123                 :          0 :                 goto release_skb;
    1124                 :            : 
    1125                 :            :         /* Copy the content of each rsvd_pkt to the buf, and they should
    1126                 :            :          * be aligned to the pages.
    1127                 :            :          *
    1128                 :            :          * Note that the first rsvd_pkt is a beacon no matter what vif->type.
    1129                 :            :          * And that rsvd_pkt does not require tx_desc because when it goes
    1130                 :            :          * through TX path, the TX path will generate one for it.
    1131                 :            :          */
    1132         [ #  # ]:          0 :         list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) {
    1133                 :          0 :                 rtw_rsvd_page_list_to_buf(rtwdev, page_size, page_margin,
    1134                 :            :                                           page, buf, rsvd_pkt);
    1135         [ #  # ]:          0 :                 if (page == 0)
    1136                 :          0 :                         page += rtw_len_to_page(rsvd_pkt->skb->len +
    1137                 :            :                                                 tx_desc_sz, page_size);
    1138                 :            :                 else
    1139                 :          0 :                         page += rtw_len_to_page(rsvd_pkt->skb->len, page_size);
    1140                 :            : 
    1141                 :          0 :                 kfree_skb(rsvd_pkt->skb);
    1142                 :          0 :                 rsvd_pkt->skb = NULL;
    1143                 :            :         }
    1144                 :            : 
    1145                 :            :         return buf;
    1146                 :            : 
    1147                 :          0 : release_skb:
    1148         [ #  # ]:          0 :         list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) {
    1149                 :          0 :                 kfree_skb(rsvd_pkt->skb);
    1150                 :          0 :                 rsvd_pkt->skb = NULL;
    1151                 :            :         }
    1152                 :            : 
    1153                 :            :         return NULL;
    1154                 :            : }
    1155                 :            : 
    1156                 :            : static int
    1157                 :          0 : rtw_download_beacon(struct rtw_dev *rtwdev, struct ieee80211_vif *vif)
    1158                 :            : {
    1159                 :          0 :         struct ieee80211_hw *hw = rtwdev->hw;
    1160                 :          0 :         struct sk_buff *skb;
    1161                 :          0 :         int ret = 0;
    1162                 :            : 
    1163                 :          0 :         skb = rtw_beacon_get(hw, vif);
    1164         [ #  # ]:          0 :         if (!skb) {
    1165                 :          0 :                 rtw_err(rtwdev, "failed to get beacon skb\n");
    1166                 :          0 :                 ret = -ENOMEM;
    1167                 :          0 :                 goto out;
    1168                 :            :         }
    1169                 :            : 
    1170                 :          0 :         ret = rtw_download_drv_rsvd_page(rtwdev, skb->data, skb->len);
    1171         [ #  # ]:          0 :         if (ret)
    1172                 :          0 :                 rtw_err(rtwdev, "failed to download drv rsvd page\n");
    1173                 :            : 
    1174                 :          0 :         dev_kfree_skb(skb);
    1175                 :            : 
    1176                 :          0 : out:
    1177                 :          0 :         return ret;
    1178                 :            : }
    1179                 :            : 
    1180                 :          0 : int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev, struct ieee80211_vif *vif)
    1181                 :            : {
    1182                 :          0 :         u8 *buf;
    1183                 :          0 :         u32 size;
    1184                 :          0 :         int ret;
    1185                 :            : 
    1186                 :          0 :         buf = rtw_build_rsvd_page(rtwdev, vif, &size);
    1187         [ #  # ]:          0 :         if (!buf) {
    1188                 :          0 :                 rtw_err(rtwdev, "failed to build rsvd page pkt\n");
    1189                 :          0 :                 return -ENOMEM;
    1190                 :            :         }
    1191                 :            : 
    1192                 :          0 :         ret = rtw_download_drv_rsvd_page(rtwdev, buf, size);
    1193         [ #  # ]:          0 :         if (ret) {
    1194                 :          0 :                 rtw_err(rtwdev, "failed to download drv rsvd page\n");
    1195                 :          0 :                 goto free;
    1196                 :            :         }
    1197                 :            : 
    1198                 :            :         /* The last thing is to download the *ONLY* beacon again, because
    1199                 :            :          * the previous tx_desc is to describe the total rsvd page. Download
    1200                 :            :          * the beacon again to replace the TX desc header, and we will get
    1201                 :            :          * a correct tx_desc for the beacon in the rsvd page.
    1202                 :            :          */
    1203                 :          0 :         ret = rtw_download_beacon(rtwdev, vif);
    1204         [ #  # ]:          0 :         if (ret) {
    1205                 :          0 :                 rtw_err(rtwdev, "failed to download beacon\n");
    1206                 :          0 :                 goto free;
    1207                 :            :         }
    1208                 :            : 
    1209                 :          0 : free:
    1210                 :          0 :         kfree(buf);
    1211                 :            : 
    1212                 :          0 :         return ret;
    1213                 :            : }
    1214                 :            : 
    1215                 :          0 : int rtw_dump_drv_rsvd_page(struct rtw_dev *rtwdev,
    1216                 :            :                            u32 offset, u32 size, u32 *buf)
    1217                 :            : {
    1218                 :          0 :         struct rtw_fifo_conf *fifo = &rtwdev->fifo;
    1219                 :          0 :         u32 residue, i;
    1220                 :          0 :         u16 start_pg;
    1221                 :          0 :         u16 idx = 0;
    1222                 :          0 :         u16 ctl;
    1223                 :          0 :         u8 rcr;
    1224                 :            : 
    1225         [ #  # ]:          0 :         if (size & 0x3) {
    1226                 :          0 :                 rtw_warn(rtwdev, "should be 4-byte aligned\n");
    1227                 :          0 :                 return -EINVAL;
    1228                 :            :         }
    1229                 :            : 
    1230                 :          0 :         offset += fifo->rsvd_boundary << TX_PAGE_SIZE_SHIFT;
    1231                 :          0 :         residue = offset & (FIFO_PAGE_SIZE - 1);
    1232                 :          0 :         start_pg = offset >> FIFO_PAGE_SIZE_SHIFT;
    1233                 :          0 :         start_pg += RSVD_PAGE_START_ADDR;
    1234                 :            : 
    1235                 :          0 :         rcr = rtw_read8(rtwdev, REG_RCR + 2);
    1236                 :          0 :         ctl = rtw_read16(rtwdev, REG_PKTBUF_DBG_CTRL) & 0xf000;
    1237                 :            : 
    1238                 :            :         /* disable rx clock gate */
    1239                 :          0 :         rtw_write8(rtwdev, REG_RCR, rcr | BIT(3));
    1240                 :            : 
    1241                 :          0 :         do {
    1242                 :          0 :                 rtw_write16(rtwdev, REG_PKTBUF_DBG_CTRL, start_pg | ctl);
    1243                 :            : 
    1244                 :          0 :                 for (i = FIFO_DUMP_ADDR + residue;
    1245         [ #  # ]:          0 :                      i < FIFO_DUMP_ADDR + FIFO_PAGE_SIZE; i += 4) {
    1246                 :          0 :                         buf[idx++] = rtw_read32(rtwdev, i);
    1247                 :          0 :                         size -= 4;
    1248         [ #  # ]:          0 :                         if (size == 0)
    1249                 :          0 :                                 goto out;
    1250                 :            :                 }
    1251                 :            : 
    1252                 :          0 :                 residue = 0;
    1253                 :          0 :                 start_pg++;
    1254         [ #  # ]:          0 :         } while (size);
    1255                 :            : 
    1256                 :          0 : out:
    1257                 :          0 :         rtw_write16(rtwdev, REG_PKTBUF_DBG_CTRL, ctl);
    1258                 :          0 :         rtw_write8(rtwdev, REG_RCR + 2, rcr);
    1259                 :          0 :         return 0;
    1260                 :            : }
    1261                 :            : 
    1262                 :          0 : static void __rtw_fw_update_pkt(struct rtw_dev *rtwdev, u8 pkt_id, u16 size,
    1263                 :            :                                 u8 location)
    1264                 :            : {
    1265                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
    1266                 :          0 :         u16 total_size = H2C_PKT_HDR_SIZE + H2C_PKT_UPDATE_PKT_LEN;
    1267                 :            : 
    1268                 :          0 :         rtw_h2c_pkt_set_header(h2c_pkt, H2C_PKT_UPDATE_PKT);
    1269                 :            : 
    1270                 :          0 :         SET_PKT_H2C_TOTAL_LEN(h2c_pkt, total_size);
    1271                 :          0 :         UPDATE_PKT_SET_PKT_ID(h2c_pkt, pkt_id);
    1272                 :          0 :         UPDATE_PKT_SET_LOCATION(h2c_pkt, location);
    1273                 :            : 
    1274                 :            :         /* include txdesc size */
    1275                 :          0 :         UPDATE_PKT_SET_SIZE(h2c_pkt, size);
    1276                 :            : 
    1277                 :          0 :         rtw_fw_send_h2c_packet(rtwdev, h2c_pkt);
    1278                 :          0 : }
    1279                 :            : 
    1280                 :          0 : void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev,
    1281                 :            :                                  struct cfg80211_ssid *ssid)
    1282                 :            : {
    1283                 :          0 :         u8 loc;
    1284                 :          0 :         u32 size;
    1285                 :            : 
    1286                 :          0 :         loc = rtw_get_rsvd_page_probe_req_location(rtwdev, ssid);
    1287         [ #  # ]:          0 :         if (!loc) {
    1288                 :          0 :                 rtw_err(rtwdev, "failed to get probe_req rsvd loc\n");
    1289                 :          0 :                 return;
    1290                 :            :         }
    1291                 :            : 
    1292                 :          0 :         size = rtw_get_rsvd_page_probe_req_size(rtwdev, ssid);
    1293         [ #  # ]:          0 :         if (!size) {
    1294                 :          0 :                 rtw_err(rtwdev, "failed to get probe_req rsvd size\n");
    1295                 :          0 :                 return;
    1296                 :            :         }
    1297                 :            : 
    1298                 :          0 :         __rtw_fw_update_pkt(rtwdev, RTW_PACKET_PROBE_REQ, size, loc);
    1299                 :            : }
    1300                 :            : 
    1301                 :          0 : void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable)
    1302                 :            : {
    1303                 :          0 :         struct rtw_pno_request *rtw_pno_req = &rtwdev->wow.pno_req;
    1304                 :          0 :         u8 h2c_pkt[H2C_PKT_SIZE] = {0};
    1305                 :          0 :         u16 total_size = H2C_PKT_HDR_SIZE + H2C_PKT_CH_SWITCH_LEN;
    1306                 :          0 :         u8 loc_ch_info;
    1307                 :          0 :         const struct rtw_ch_switch_option cs_option = {
    1308                 :            :                 .dest_ch_en = 1,
    1309                 :            :                 .dest_ch = 1,
    1310                 :            :                 .periodic_option = 2,
    1311                 :            :                 .normal_period = 5,
    1312                 :            :                 .normal_period_sel = 0,
    1313                 :            :                 .normal_cycle = 10,
    1314                 :            :                 .slow_period = 1,
    1315                 :            :                 .slow_period_sel = 1,
    1316                 :            :         };
    1317                 :            : 
    1318                 :          0 :         rtw_h2c_pkt_set_header(h2c_pkt, H2C_PKT_CH_SWITCH);
    1319                 :          0 :         SET_PKT_H2C_TOTAL_LEN(h2c_pkt, total_size);
    1320                 :            : 
    1321                 :          0 :         CH_SWITCH_SET_START(h2c_pkt, enable);
    1322                 :          0 :         CH_SWITCH_SET_DEST_CH_EN(h2c_pkt, cs_option.dest_ch_en);
    1323                 :          0 :         CH_SWITCH_SET_DEST_CH(h2c_pkt, cs_option.dest_ch);
    1324                 :          0 :         CH_SWITCH_SET_NORMAL_PERIOD(h2c_pkt, cs_option.normal_period);
    1325                 :          0 :         CH_SWITCH_SET_NORMAL_PERIOD_SEL(h2c_pkt, cs_option.normal_period_sel);
    1326                 :          0 :         CH_SWITCH_SET_SLOW_PERIOD(h2c_pkt, cs_option.slow_period);
    1327                 :          0 :         CH_SWITCH_SET_SLOW_PERIOD_SEL(h2c_pkt, cs_option.slow_period_sel);
    1328                 :          0 :         CH_SWITCH_SET_NORMAL_CYCLE(h2c_pkt, cs_option.normal_cycle);
    1329                 :          0 :         CH_SWITCH_SET_PERIODIC_OPT(h2c_pkt, cs_option.periodic_option);
    1330                 :            : 
    1331                 :          0 :         CH_SWITCH_SET_CH_NUM(h2c_pkt, rtw_pno_req->channel_cnt);
    1332                 :          0 :         CH_SWITCH_SET_INFO_SIZE(h2c_pkt, rtw_pno_req->channel_cnt * 4);
    1333                 :            : 
    1334                 :          0 :         loc_ch_info = rtw_get_rsvd_page_location(rtwdev, RSVD_CH_INFO);
    1335                 :          0 :         CH_SWITCH_SET_INFO_LOC(h2c_pkt, loc_ch_info);
    1336                 :            : 
    1337                 :          0 :         rtw_fw_send_h2c_packet(rtwdev, h2c_pkt);
    1338                 :          0 : }

Generated by: LCOV version 1.14