linux/drivers/net/wireless/ath/wil6210/wmi.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
   3 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18#include <linux/moduleparam.h>
  19#include <linux/etherdevice.h>
  20#include <linux/if_arp.h>
  21
  22#include "wil6210.h"
  23#include "txrx.h"
  24#include "wmi.h"
  25#include "trace.h"
  26
  27/* set the default max assoc sta to max supported by driver */
  28uint max_assoc_sta = WIL6210_MAX_CID;
  29module_param(max_assoc_sta, uint, 0444);
  30MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
  31
  32int agg_wsize; /* = 0; */
  33module_param(agg_wsize, int, 0644);
  34MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
  35                 " 0 - use default; < 0 - don't auto-establish");
  36
  37u8 led_id = WIL_LED_INVALID_ID;
  38module_param(led_id, byte, 0444);
  39MODULE_PARM_DESC(led_id,
  40                 " 60G device led enablement. Set the led ID (0-2) to enable");
  41
  42#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
  43#define WIL_WMI_CALL_GENERAL_TO_MS 100
  44#define WIL_WMI_PCP_STOP_TO_MS 5000
  45
  46/**
  47 * WMI event receiving - theory of operations
  48 *
  49 * When firmware about to report WMI event, it fills memory area
  50 * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
  51 * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
  52 *
  53 * @wmi_recv_cmd reads event, allocates memory chunk  and attaches it to the
  54 * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up
  55 * and handles events within the @wmi_event_worker. Every event get detached
  56 * from list, processed and deleted.
  57 *
  58 * Purpose for this mechanism is to release IRQ thread; otherwise,
  59 * if WMI event handling involves another WMI command flow, this 2-nd flow
  60 * won't be completed because of blocked IRQ thread.
  61 */
  62
  63/**
  64 * Addressing - theory of operations
  65 *
  66 * There are several buses present on the WIL6210 card.
  67 * Same memory areas are visible at different address on
  68 * the different busses. There are 3 main bus masters:
  69 *  - MAC CPU (ucode)
  70 *  - User CPU (firmware)
  71 *  - AHB (host)
  72 *
  73 * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
  74 * AHB addresses starting from 0x880000
  75 *
  76 * Internally, firmware uses addresses that allow faster access but
  77 * are invisible from the host. To read from these addresses, alternative
  78 * AHB address must be used.
  79 */
  80
  81/**
  82 * @sparrow_fw_mapping provides memory remapping table for sparrow
  83 *
  84 * array size should be in sync with the declaration in the wil6210.h
  85 *
  86 * Sparrow memory mapping:
  87 * Linker address         PCI/Host address
  88 *                        0x880000 .. 0xa80000  2Mb BAR0
  89 * 0x800000 .. 0x808000   0x900000 .. 0x908000  32k DCCM
  90 * 0x840000 .. 0x860000   0x908000 .. 0x928000  128k PERIPH
  91 */
  92const struct fw_map sparrow_fw_mapping[] = {
  93        /* FW code RAM 256k */
  94        {0x000000, 0x040000, 0x8c0000, "fw_code", true, true},
  95        /* FW data RAM 32k */
  96        {0x800000, 0x808000, 0x900000, "fw_data", true, true},
  97        /* periph data 128k */
  98        {0x840000, 0x860000, 0x908000, "fw_peri", true, true},
  99        /* various RGF 40k */
 100        {0x880000, 0x88a000, 0x880000, "rgf", true, true},
 101        /* AGC table   4k */
 102        {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true, true},
 103        /* Pcie_ext_rgf 4k */
 104        {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true, true},
 105        /* mac_ext_rgf 512b */
 106        {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true, true},
 107        /* upper area 548k */
 108        {0x8c0000, 0x949000, 0x8c0000, "upper", true, true},
 109        /* UCODE areas - accessible by debugfs blobs but not by
 110         * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
 111         */
 112        /* ucode code RAM 128k */
 113        {0x000000, 0x020000, 0x920000, "uc_code", false, false},
 114        /* ucode data RAM 16k */
 115        {0x800000, 0x804000, 0x940000, "uc_data", false, false},
 116};
 117
 118/**
 119 * @sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0
 120 * it is a bit larger to support extra features
 121 */
 122const struct fw_map sparrow_d0_mac_rgf_ext = {
 123        0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true, true
 124};
 125
 126/**
 127 * @talyn_fw_mapping provides memory remapping table for Talyn
 128 *
 129 * array size should be in sync with the declaration in the wil6210.h
 130 *
 131 * Talyn memory mapping:
 132 * Linker address         PCI/Host address
 133 *                        0x880000 .. 0xc80000  4Mb BAR0
 134 * 0x800000 .. 0x820000   0xa00000 .. 0xa20000  128k DCCM
 135 * 0x840000 .. 0x858000   0xa20000 .. 0xa38000  96k PERIPH
 136 */
 137const struct fw_map talyn_fw_mapping[] = {
 138        /* FW code RAM 1M */
 139        {0x000000, 0x100000, 0x900000, "fw_code", true, true},
 140        /* FW data RAM 128k */
 141        {0x800000, 0x820000, 0xa00000, "fw_data", true, true},
 142        /* periph. data RAM 96k */
 143        {0x840000, 0x858000, 0xa20000, "fw_peri", true, true},
 144        /* various RGF 40k */
 145        {0x880000, 0x88a000, 0x880000, "rgf", true, true},
 146        /* AGC table 4k */
 147        {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true, true},
 148        /* Pcie_ext_rgf 4k */
 149        {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true, true},
 150        /* mac_ext_rgf 1344b */
 151        {0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true, true},
 152        /* ext USER RGF 4k */
 153        {0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true, true},
 154        /* OTP 4k */
 155        {0x8a0000, 0x8a1000, 0x8a0000, "otp", true, false},
 156        /* DMA EXT RGF 64k */
 157        {0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true, true},
 158        /* upper area 1536k */
 159        {0x900000, 0xa80000, 0x900000, "upper", true, true},
 160        /* UCODE areas - accessible by debugfs blobs but not by
 161         * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
 162         */
 163        /* ucode code RAM 256k */
 164        {0x000000, 0x040000, 0xa38000, "uc_code", false, false},
 165        /* ucode data RAM 32k */
 166        {0x800000, 0x808000, 0xa78000, "uc_data", false, false},
 167};
 168
 169/**
 170 * @talyn_mb_fw_mapping provides memory remapping table for Talyn-MB
 171 *
 172 * array size should be in sync with the declaration in the wil6210.h
 173 *
 174 * Talyn MB memory mapping:
 175 * Linker address         PCI/Host address
 176 *                        0x880000 .. 0xc80000  4Mb BAR0
 177 * 0x800000 .. 0x820000   0xa00000 .. 0xa20000  128k DCCM
 178 * 0x840000 .. 0x858000   0xa20000 .. 0xa38000  96k PERIPH
 179 */
 180const struct fw_map talyn_mb_fw_mapping[] = {
 181        /* FW code RAM 768k */
 182        {0x000000, 0x0c0000, 0x900000, "fw_code", true, true},
 183        /* FW data RAM 128k */
 184        {0x800000, 0x820000, 0xa00000, "fw_data", true, true},
 185        /* periph. data RAM 96k */
 186        {0x840000, 0x858000, 0xa20000, "fw_peri", true, true},
 187        /* various RGF 40k */
 188        {0x880000, 0x88a000, 0x880000, "rgf", true, true},
 189        /* AGC table 4k */
 190        {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true, true},
 191        /* Pcie_ext_rgf 4k */
 192        {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true, true},
 193        /* mac_ext_rgf 2256b */
 194        {0x88c000, 0x88c8d0, 0x88c000, "mac_rgf_ext", true, true},
 195        /* ext USER RGF 4k */
 196        {0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true, true},
 197        /* SEC PKA 16k */
 198        {0x890000, 0x894000, 0x890000, "sec_pka", true, true},
 199        /* SEC KDF RGF 3096b */
 200        {0x898000, 0x898c18, 0x898000, "sec_kdf_rgf", true, true},
 201        /* SEC MAIN 2124b */
 202        {0x89a000, 0x89a84c, 0x89a000, "sec_main", true, true},
 203        /* OTP 4k */
 204        {0x8a0000, 0x8a1000, 0x8a0000, "otp", true, false},
 205        /* DMA EXT RGF 64k */
 206        {0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true, true},
 207        /* DUM USER RGF 528b */
 208        {0x8c0000, 0x8c0210, 0x8c0000, "dum_user_rgf", true, true},
 209        /* DMA OFU 296b */
 210        {0x8c2000, 0x8c2128, 0x8c2000, "dma_ofu", true, true},
 211        /* ucode debug 4k */
 212        {0x8c3000, 0x8c4000, 0x8c3000, "ucode_debug", true, true},
 213        /* upper area 1536k */
 214        {0x900000, 0xa80000, 0x900000, "upper", true, true},
 215        /* UCODE areas - accessible by debugfs blobs but not by
 216         * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
 217         */
 218        /* ucode code RAM 256k */
 219        {0x000000, 0x040000, 0xa38000, "uc_code", false, false},
 220        /* ucode data RAM 32k */
 221        {0x800000, 0x808000, 0xa78000, "uc_data", false, false},
 222};
 223
 224struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
 225
 226struct blink_on_off_time led_blink_time[] = {
 227        {WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
 228        {WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
 229        {WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
 230};
 231
 232struct auth_no_hdr {
 233        __le16 auth_alg;
 234        __le16 auth_transaction;
 235        __le16 status_code;
 236        /* possibly followed by Challenge text */
 237        u8 variable[0];
 238} __packed;
 239
 240u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
 241
 242/**
 243 * return AHB address for given firmware internal (linker) address
 244 * @x - internal address
 245 * If address have no valid AHB mapping, return 0
 246 */
 247static u32 wmi_addr_remap(u32 x)
 248{
 249        uint i;
 250
 251        for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
 252                if (fw_mapping[i].fw &&
 253                    ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)))
 254                        return x + fw_mapping[i].host - fw_mapping[i].from;
 255        }
 256
 257        return 0;
 258}
 259
 260/**
 261 * find fw_mapping entry by section name
 262 * @section - section name
 263 *
 264 * Return pointer to section or NULL if not found
 265 */
 266struct fw_map *wil_find_fw_mapping(const char *section)
 267{
 268        int i;
 269
 270        for (i = 0; i < ARRAY_SIZE(fw_mapping); i++)
 271                if (fw_mapping[i].name &&
 272                    !strcmp(section, fw_mapping[i].name))
 273                        return &fw_mapping[i];
 274
 275        return NULL;
 276}
 277
 278/**
 279 * Check address validity for WMI buffer; remap if needed
 280 * @ptr - internal (linker) fw/ucode address
 281 * @size - if non zero, validate the block does not
 282 *  exceed the device memory (bar)
 283 *
 284 * Valid buffer should be DWORD aligned
 285 *
 286 * return address for accessing buffer from the host;
 287 * if buffer is not valid, return NULL.
 288 */
 289void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
 290{
 291        u32 off;
 292        u32 ptr = le32_to_cpu(ptr_);
 293
 294        if (ptr % 4)
 295                return NULL;
 296
 297        ptr = wmi_addr_remap(ptr);
 298        if (ptr < WIL6210_FW_HOST_OFF)
 299                return NULL;
 300
 301        off = HOSTADDR(ptr);
 302        if (off > wil->bar_size - 4)
 303                return NULL;
 304        if (size && ((off + size > wil->bar_size) || (off + size < off)))
 305                return NULL;
 306
 307        return wil->csr + off;
 308}
 309
 310void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
 311{
 312        return wmi_buffer_block(wil, ptr_, 0);
 313}
 314
 315/**
 316 * Check address validity
 317 */
 318void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
 319{
 320        u32 off;
 321
 322        if (ptr % 4)
 323                return NULL;
 324
 325        if (ptr < WIL6210_FW_HOST_OFF)
 326                return NULL;
 327
 328        off = HOSTADDR(ptr);
 329        if (off > wil->bar_size - 4)
 330                return NULL;
 331
 332        return wil->csr + off;
 333}
 334
 335int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
 336                 struct wil6210_mbox_hdr *hdr)
 337{
 338        void __iomem *src = wmi_buffer(wil, ptr);
 339
 340        if (!src)
 341                return -EINVAL;
 342
 343        wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
 344
 345        return 0;
 346}
 347
 348static const char *cmdid2name(u16 cmdid)
 349{
 350        switch (cmdid) {
 351        case WMI_NOTIFY_REQ_CMDID:
 352                return "WMI_NOTIFY_REQ_CMD";
 353        case WMI_START_SCAN_CMDID:
 354                return "WMI_START_SCAN_CMD";
 355        case WMI_CONNECT_CMDID:
 356                return "WMI_CONNECT_CMD";
 357        case WMI_DISCONNECT_CMDID:
 358                return "WMI_DISCONNECT_CMD";
 359        case WMI_SW_TX_REQ_CMDID:
 360                return "WMI_SW_TX_REQ_CMD";
 361        case WMI_GET_RF_SECTOR_PARAMS_CMDID:
 362                return "WMI_GET_RF_SECTOR_PARAMS_CMD";
 363        case WMI_SET_RF_SECTOR_PARAMS_CMDID:
 364                return "WMI_SET_RF_SECTOR_PARAMS_CMD";
 365        case WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID:
 366                return "WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD";
 367        case WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID:
 368                return "WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD";
 369        case WMI_BRP_SET_ANT_LIMIT_CMDID:
 370                return "WMI_BRP_SET_ANT_LIMIT_CMD";
 371        case WMI_TOF_SESSION_START_CMDID:
 372                return "WMI_TOF_SESSION_START_CMD";
 373        case WMI_AOA_MEAS_CMDID:
 374                return "WMI_AOA_MEAS_CMD";
 375        case WMI_PMC_CMDID:
 376                return "WMI_PMC_CMD";
 377        case WMI_TOF_GET_TX_RX_OFFSET_CMDID:
 378                return "WMI_TOF_GET_TX_RX_OFFSET_CMD";
 379        case WMI_TOF_SET_TX_RX_OFFSET_CMDID:
 380                return "WMI_TOF_SET_TX_RX_OFFSET_CMD";
 381        case WMI_VRING_CFG_CMDID:
 382                return "WMI_VRING_CFG_CMD";
 383        case WMI_BCAST_VRING_CFG_CMDID:
 384                return "WMI_BCAST_VRING_CFG_CMD";
 385        case WMI_TRAFFIC_SUSPEND_CMDID:
 386                return "WMI_TRAFFIC_SUSPEND_CMD";
 387        case WMI_TRAFFIC_RESUME_CMDID:
 388                return "WMI_TRAFFIC_RESUME_CMD";
 389        case WMI_ECHO_CMDID:
 390                return "WMI_ECHO_CMD";
 391        case WMI_SET_MAC_ADDRESS_CMDID:
 392                return "WMI_SET_MAC_ADDRESS_CMD";
 393        case WMI_LED_CFG_CMDID:
 394                return "WMI_LED_CFG_CMD";
 395        case WMI_PCP_START_CMDID:
 396                return "WMI_PCP_START_CMD";
 397        case WMI_PCP_STOP_CMDID:
 398                return "WMI_PCP_STOP_CMD";
 399        case WMI_SET_SSID_CMDID:
 400                return "WMI_SET_SSID_CMD";
 401        case WMI_GET_SSID_CMDID:
 402                return "WMI_GET_SSID_CMD";
 403        case WMI_SET_PCP_CHANNEL_CMDID:
 404                return "WMI_SET_PCP_CHANNEL_CMD";
 405        case WMI_GET_PCP_CHANNEL_CMDID:
 406                return "WMI_GET_PCP_CHANNEL_CMD";
 407        case WMI_P2P_CFG_CMDID:
 408                return "WMI_P2P_CFG_CMD";
 409        case WMI_PORT_ALLOCATE_CMDID:
 410                return "WMI_PORT_ALLOCATE_CMD";
 411        case WMI_PORT_DELETE_CMDID:
 412                return "WMI_PORT_DELETE_CMD";
 413        case WMI_START_LISTEN_CMDID:
 414                return "WMI_START_LISTEN_CMD";
 415        case WMI_START_SEARCH_CMDID:
 416                return "WMI_START_SEARCH_CMD";
 417        case WMI_DISCOVERY_STOP_CMDID:
 418                return "WMI_DISCOVERY_STOP_CMD";
 419        case WMI_DELETE_CIPHER_KEY_CMDID:
 420                return "WMI_DELETE_CIPHER_KEY_CMD";
 421        case WMI_ADD_CIPHER_KEY_CMDID:
 422                return "WMI_ADD_CIPHER_KEY_CMD";
 423        case WMI_SET_APPIE_CMDID:
 424                return "WMI_SET_APPIE_CMD";
 425        case WMI_CFG_RX_CHAIN_CMDID:
 426                return "WMI_CFG_RX_CHAIN_CMD";
 427        case WMI_TEMP_SENSE_CMDID:
 428                return "WMI_TEMP_SENSE_CMD";
 429        case WMI_DEL_STA_CMDID:
 430                return "WMI_DEL_STA_CMD";
 431        case WMI_DISCONNECT_STA_CMDID:
 432                return "WMI_DISCONNECT_STA_CMD";
 433        case WMI_RING_BA_EN_CMDID:
 434                return "WMI_RING_BA_EN_CMD";
 435        case WMI_RING_BA_DIS_CMDID:
 436                return "WMI_RING_BA_DIS_CMD";
 437        case WMI_RCP_DELBA_CMDID:
 438                return "WMI_RCP_DELBA_CMD";
 439        case WMI_RCP_ADDBA_RESP_CMDID:
 440                return "WMI_RCP_ADDBA_RESP_CMD";
 441        case WMI_RCP_ADDBA_RESP_EDMA_CMDID:
 442                return "WMI_RCP_ADDBA_RESP_EDMA_CMD";
 443        case WMI_PS_DEV_PROFILE_CFG_CMDID:
 444                return "WMI_PS_DEV_PROFILE_CFG_CMD";
 445        case WMI_SET_MGMT_RETRY_LIMIT_CMDID:
 446                return "WMI_SET_MGMT_RETRY_LIMIT_CMD";
 447        case WMI_GET_MGMT_RETRY_LIMIT_CMDID:
 448                return "WMI_GET_MGMT_RETRY_LIMIT_CMD";
 449        case WMI_ABORT_SCAN_CMDID:
 450                return "WMI_ABORT_SCAN_CMD";
 451        case WMI_NEW_STA_CMDID:
 452                return "WMI_NEW_STA_CMD";
 453        case WMI_SET_THERMAL_THROTTLING_CFG_CMDID:
 454                return "WMI_SET_THERMAL_THROTTLING_CFG_CMD";
 455        case WMI_GET_THERMAL_THROTTLING_CFG_CMDID:
 456                return "WMI_GET_THERMAL_THROTTLING_CFG_CMD";
 457        case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID:
 458                return "WMI_LINK_MAINTAIN_CFG_WRITE_CMD";
 459        case WMI_LO_POWER_CALIB_FROM_OTP_CMDID:
 460                return "WMI_LO_POWER_CALIB_FROM_OTP_CMD";
 461        case WMI_START_SCHED_SCAN_CMDID:
 462                return "WMI_START_SCHED_SCAN_CMD";
 463        case WMI_STOP_SCHED_SCAN_CMDID:
 464                return "WMI_STOP_SCHED_SCAN_CMD";
 465        case WMI_TX_STATUS_RING_ADD_CMDID:
 466                return "WMI_TX_STATUS_RING_ADD_CMD";
 467        case WMI_RX_STATUS_RING_ADD_CMDID:
 468                return "WMI_RX_STATUS_RING_ADD_CMD";
 469        case WMI_TX_DESC_RING_ADD_CMDID:
 470                return "WMI_TX_DESC_RING_ADD_CMD";
 471        case WMI_RX_DESC_RING_ADD_CMDID:
 472                return "WMI_RX_DESC_RING_ADD_CMD";
 473        case WMI_BCAST_DESC_RING_ADD_CMDID:
 474                return "WMI_BCAST_DESC_RING_ADD_CMD";
 475        case WMI_CFG_DEF_RX_OFFLOAD_CMDID:
 476                return "WMI_CFG_DEF_RX_OFFLOAD_CMD";
 477        case WMI_LINK_STATS_CMDID:
 478                return "WMI_LINK_STATS_CMD";
 479        case WMI_SW_TX_REQ_EXT_CMDID:
 480                return "WMI_SW_TX_REQ_EXT_CMDID";
 481        case WMI_FT_AUTH_CMDID:
 482                return "WMI_FT_AUTH_CMD";
 483        case WMI_FT_REASSOC_CMDID:
 484                return "WMI_FT_REASSOC_CMD";
 485        case WMI_UPDATE_FT_IES_CMDID:
 486                return "WMI_UPDATE_FT_IES_CMD";
 487        default:
 488                return "Untracked CMD";
 489        }
 490}
 491
 492static const char *eventid2name(u16 eventid)
 493{
 494        switch (eventid) {
 495        case WMI_NOTIFY_REQ_DONE_EVENTID:
 496                return "WMI_NOTIFY_REQ_DONE_EVENT";
 497        case WMI_DISCONNECT_EVENTID:
 498                return "WMI_DISCONNECT_EVENT";
 499        case WMI_SW_TX_COMPLETE_EVENTID:
 500                return "WMI_SW_TX_COMPLETE_EVENT";
 501        case WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID:
 502                return "WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT";
 503        case WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID:
 504                return "WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT";
 505        case WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
 506                return "WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
 507        case WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
 508                return "WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
 509        case WMI_BRP_SET_ANT_LIMIT_EVENTID:
 510                return "WMI_BRP_SET_ANT_LIMIT_EVENT";
 511        case WMI_FW_READY_EVENTID:
 512                return "WMI_FW_READY_EVENT";
 513        case WMI_TRAFFIC_RESUME_EVENTID:
 514                return "WMI_TRAFFIC_RESUME_EVENT";
 515        case WMI_TOF_GET_TX_RX_OFFSET_EVENTID:
 516                return "WMI_TOF_GET_TX_RX_OFFSET_EVENT";
 517        case WMI_TOF_SET_TX_RX_OFFSET_EVENTID:
 518                return "WMI_TOF_SET_TX_RX_OFFSET_EVENT";
 519        case WMI_VRING_CFG_DONE_EVENTID:
 520                return "WMI_VRING_CFG_DONE_EVENT";
 521        case WMI_READY_EVENTID:
 522                return "WMI_READY_EVENT";
 523        case WMI_RX_MGMT_PACKET_EVENTID:
 524                return "WMI_RX_MGMT_PACKET_EVENT";
 525        case WMI_TX_MGMT_PACKET_EVENTID:
 526                return "WMI_TX_MGMT_PACKET_EVENT";
 527        case WMI_SCAN_COMPLETE_EVENTID:
 528                return "WMI_SCAN_COMPLETE_EVENT";
 529        case WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID:
 530                return "WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENT";
 531        case WMI_CONNECT_EVENTID:
 532                return "WMI_CONNECT_EVENT";
 533        case WMI_EAPOL_RX_EVENTID:
 534                return "WMI_EAPOL_RX_EVENT";
 535        case WMI_BA_STATUS_EVENTID:
 536                return "WMI_BA_STATUS_EVENT";
 537        case WMI_RCP_ADDBA_REQ_EVENTID:
 538                return "WMI_RCP_ADDBA_REQ_EVENT";
 539        case WMI_DELBA_EVENTID:
 540                return "WMI_DELBA_EVENT";
 541        case WMI_RING_EN_EVENTID:
 542                return "WMI_RING_EN_EVENT";
 543        case WMI_DATA_PORT_OPEN_EVENTID:
 544                return "WMI_DATA_PORT_OPEN_EVENT";
 545        case WMI_AOA_MEAS_EVENTID:
 546                return "WMI_AOA_MEAS_EVENT";
 547        case WMI_TOF_SESSION_END_EVENTID:
 548                return "WMI_TOF_SESSION_END_EVENT";
 549        case WMI_TOF_GET_CAPABILITIES_EVENTID:
 550                return "WMI_TOF_GET_CAPABILITIES_EVENT";
 551        case WMI_TOF_SET_LCR_EVENTID:
 552                return "WMI_TOF_SET_LCR_EVENT";
 553        case WMI_TOF_SET_LCI_EVENTID:
 554                return "WMI_TOF_SET_LCI_EVENT";
 555        case WMI_TOF_FTM_PER_DEST_RES_EVENTID:
 556                return "WMI_TOF_FTM_PER_DEST_RES_EVENT";
 557        case WMI_TOF_CHANNEL_INFO_EVENTID:
 558                return "WMI_TOF_CHANNEL_INFO_EVENT";
 559        case WMI_TRAFFIC_SUSPEND_EVENTID:
 560                return "WMI_TRAFFIC_SUSPEND_EVENT";
 561        case WMI_ECHO_RSP_EVENTID:
 562                return "WMI_ECHO_RSP_EVENT";
 563        case WMI_LED_CFG_DONE_EVENTID:
 564                return "WMI_LED_CFG_DONE_EVENT";
 565        case WMI_PCP_STARTED_EVENTID:
 566                return "WMI_PCP_STARTED_EVENT";
 567        case WMI_PCP_STOPPED_EVENTID:
 568                return "WMI_PCP_STOPPED_EVENT";
 569        case WMI_GET_SSID_EVENTID:
 570                return "WMI_GET_SSID_EVENT";
 571        case WMI_GET_PCP_CHANNEL_EVENTID:
 572                return "WMI_GET_PCP_CHANNEL_EVENT";
 573        case WMI_P2P_CFG_DONE_EVENTID:
 574                return "WMI_P2P_CFG_DONE_EVENT";
 575        case WMI_PORT_ALLOCATED_EVENTID:
 576                return "WMI_PORT_ALLOCATED_EVENT";
 577        case WMI_PORT_DELETED_EVENTID:
 578                return "WMI_PORT_DELETED_EVENT";
 579        case WMI_LISTEN_STARTED_EVENTID:
 580                return "WMI_LISTEN_STARTED_EVENT";
 581        case WMI_SEARCH_STARTED_EVENTID:
 582                return "WMI_SEARCH_STARTED_EVENT";
 583        case WMI_DISCOVERY_STOPPED_EVENTID:
 584                return "WMI_DISCOVERY_STOPPED_EVENT";
 585        case WMI_CFG_RX_CHAIN_DONE_EVENTID:
 586                return "WMI_CFG_RX_CHAIN_DONE_EVENT";
 587        case WMI_TEMP_SENSE_DONE_EVENTID:
 588                return "WMI_TEMP_SENSE_DONE_EVENT";
 589        case WMI_RCP_ADDBA_RESP_SENT_EVENTID:
 590                return "WMI_RCP_ADDBA_RESP_SENT_EVENT";
 591        case WMI_PS_DEV_PROFILE_CFG_EVENTID:
 592                return "WMI_PS_DEV_PROFILE_CFG_EVENT";
 593        case WMI_SET_MGMT_RETRY_LIMIT_EVENTID:
 594                return "WMI_SET_MGMT_RETRY_LIMIT_EVENT";
 595        case WMI_GET_MGMT_RETRY_LIMIT_EVENTID:
 596                return "WMI_GET_MGMT_RETRY_LIMIT_EVENT";
 597        case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID:
 598                return "WMI_SET_THERMAL_THROTTLING_CFG_EVENT";
 599        case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID:
 600                return "WMI_GET_THERMAL_THROTTLING_CFG_EVENT";
 601        case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID:
 602                return "WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT";
 603        case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID:
 604                return "WMI_LO_POWER_CALIB_FROM_OTP_EVENT";
 605        case WMI_START_SCHED_SCAN_EVENTID:
 606                return "WMI_START_SCHED_SCAN_EVENT";
 607        case WMI_STOP_SCHED_SCAN_EVENTID:
 608                return "WMI_STOP_SCHED_SCAN_EVENT";
 609        case WMI_SCHED_SCAN_RESULT_EVENTID:
 610                return "WMI_SCHED_SCAN_RESULT_EVENT";
 611        case WMI_TX_STATUS_RING_CFG_DONE_EVENTID:
 612                return "WMI_TX_STATUS_RING_CFG_DONE_EVENT";
 613        case WMI_RX_STATUS_RING_CFG_DONE_EVENTID:
 614                return "WMI_RX_STATUS_RING_CFG_DONE_EVENT";
 615        case WMI_TX_DESC_RING_CFG_DONE_EVENTID:
 616                return "WMI_TX_DESC_RING_CFG_DONE_EVENT";
 617        case WMI_RX_DESC_RING_CFG_DONE_EVENTID:
 618                return "WMI_RX_DESC_RING_CFG_DONE_EVENT";
 619        case WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID:
 620                return "WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENT";
 621        case WMI_LINK_STATS_CONFIG_DONE_EVENTID:
 622                return "WMI_LINK_STATS_CONFIG_DONE_EVENT";
 623        case WMI_LINK_STATS_EVENTID:
 624                return "WMI_LINK_STATS_EVENT";
 625        case WMI_COMMAND_NOT_SUPPORTED_EVENTID:
 626                return "WMI_COMMAND_NOT_SUPPORTED_EVENT";
 627        case WMI_FT_AUTH_STATUS_EVENTID:
 628                return "WMI_FT_AUTH_STATUS_EVENT";
 629        case WMI_FT_REASSOC_STATUS_EVENTID:
 630                return "WMI_FT_REASSOC_STATUS_EVENT";
 631        default:
 632                return "Untracked EVENT";
 633        }
 634}
 635
 636static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid,
 637                      void *buf, u16 len)
 638{
 639        struct {
 640                struct wil6210_mbox_hdr hdr;
 641                struct wmi_cmd_hdr wmi;
 642        } __packed cmd = {
 643                .hdr = {
 644                        .type = WIL_MBOX_HDR_TYPE_WMI,
 645                        .flags = 0,
 646                        .len = cpu_to_le16(sizeof(cmd.wmi) + len),
 647                },
 648                .wmi = {
 649                        .mid = mid,
 650                        .command_id = cpu_to_le16(cmdid),
 651                },
 652        };
 653        struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
 654        struct wil6210_mbox_ring_desc d_head;
 655        u32 next_head;
 656        void __iomem *dst;
 657        void __iomem *head = wmi_addr(wil, r->head);
 658        uint retry;
 659        int rc = 0;
 660
 661        if (len > r->entry_size - sizeof(cmd)) {
 662                wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
 663                        (int)(sizeof(cmd) + len), r->entry_size);
 664                return -ERANGE;
 665        }
 666
 667        might_sleep();
 668
 669        if (!test_bit(wil_status_fwready, wil->status)) {
 670                wil_err(wil, "WMI: cannot send command while FW not ready\n");
 671                return -EAGAIN;
 672        }
 673
 674        /* Allow sending only suspend / resume commands during susepnd flow */
 675        if ((test_bit(wil_status_suspending, wil->status) ||
 676             test_bit(wil_status_suspended, wil->status) ||
 677             test_bit(wil_status_resuming, wil->status)) &&
 678             ((cmdid != WMI_TRAFFIC_SUSPEND_CMDID) &&
 679              (cmdid != WMI_TRAFFIC_RESUME_CMDID))) {
 680                wil_err(wil, "WMI: reject send_command during suspend\n");
 681                return -EINVAL;
 682        }
 683
 684        if (!head) {
 685                wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
 686                return -EINVAL;
 687        }
 688
 689        wil_halp_vote(wil);
 690
 691        /* read Tx head till it is not busy */
 692        for (retry = 5; retry > 0; retry--) {
 693                wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
 694                if (d_head.sync == 0)
 695                        break;
 696                msleep(20);
 697        }
 698        if (d_head.sync != 0) {
 699                wil_err(wil, "WMI head busy\n");
 700                rc = -EBUSY;
 701                goto out;
 702        }
 703        /* next head */
 704        next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
 705        wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
 706        /* wait till FW finish with previous command */
 707        for (retry = 5; retry > 0; retry--) {
 708                if (!test_bit(wil_status_fwready, wil->status)) {
 709                        wil_err(wil, "WMI: cannot send command while FW not ready\n");
 710                        rc = -EAGAIN;
 711                        goto out;
 712                }
 713                r->tail = wil_r(wil, RGF_MBOX +
 714                                offsetof(struct wil6210_mbox_ctl, tx.tail));
 715                if (next_head != r->tail)
 716                        break;
 717                msleep(20);
 718        }
 719        if (next_head == r->tail) {
 720                wil_err(wil, "WMI ring full\n");
 721                rc = -EBUSY;
 722                goto out;
 723        }
 724        dst = wmi_buffer(wil, d_head.addr);
 725        if (!dst) {
 726                wil_err(wil, "invalid WMI buffer: 0x%08x\n",
 727                        le32_to_cpu(d_head.addr));
 728                rc = -EAGAIN;
 729                goto out;
 730        }
 731        cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
 732        /* set command */
 733        wil_dbg_wmi(wil, "sending %s (0x%04x) [%d] mid %d\n",
 734                    cmdid2name(cmdid), cmdid, len, mid);
 735        wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
 736                         sizeof(cmd), true);
 737        wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
 738                         len, true);
 739        wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
 740        wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
 741        /* mark entry as full */
 742        wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1);
 743        /* advance next ptr */
 744        wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head),
 745              r->head = next_head);
 746
 747        trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
 748
 749        /* interrupt to FW */
 750        wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS),
 751              SW_INT_MBOX);
 752
 753out:
 754        wil_halp_unvote(wil);
 755        return rc;
 756}
 757
 758int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len)
 759{
 760        int rc;
 761
 762        mutex_lock(&wil->wmi_mutex);
 763        rc = __wmi_send(wil, cmdid, mid, buf, len);
 764        mutex_unlock(&wil->wmi_mutex);
 765
 766        return rc;
 767}
 768
 769/*=== Event handlers ===*/
 770static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len)
 771{
 772        struct wil6210_priv *wil = vif_to_wil(vif);
 773        struct wiphy *wiphy = wil_to_wiphy(wil);
 774        struct wmi_ready_event *evt = d;
 775        u8 fw_max_assoc_sta;
 776
 777        wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
 778                 wil->fw_version, le32_to_cpu(evt->sw_version),
 779                 evt->mac, evt->numof_additional_mids);
 780        if (evt->numof_additional_mids + 1 < wil->max_vifs) {
 781                wil_err(wil, "FW does not support enough MIDs (need %d)",
 782                        wil->max_vifs - 1);
 783                return; /* FW load will fail after timeout */
 784        }
 785        /* ignore MAC address, we already have it from the boot loader */
 786        strlcpy(wiphy->fw_version, wil->fw_version, sizeof(wiphy->fw_version));
 787
 788        if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
 789                wil_dbg_wmi(wil, "rfc calibration result %d\n",
 790                            evt->rfc_read_calib_result);
 791                wil->fw_calib_result = evt->rfc_read_calib_result;
 792        }
 793
 794        fw_max_assoc_sta = WIL6210_RX_DESC_MAX_CID;
 795        if (len > offsetof(struct wmi_ready_event, max_assoc_sta) &&
 796            evt->max_assoc_sta > 0) {
 797                fw_max_assoc_sta = evt->max_assoc_sta;
 798                wil_dbg_wmi(wil, "fw reported max assoc sta %d\n",
 799                            fw_max_assoc_sta);
 800
 801                if (fw_max_assoc_sta > WIL6210_MAX_CID) {
 802                        wil_dbg_wmi(wil,
 803                                    "fw max assoc sta %d exceeds max driver supported %d\n",
 804                                    fw_max_assoc_sta, WIL6210_MAX_CID);
 805                        fw_max_assoc_sta = WIL6210_MAX_CID;
 806                }
 807        }
 808
 809        max_assoc_sta = min_t(uint, max_assoc_sta, fw_max_assoc_sta);
 810        wil_dbg_wmi(wil, "setting max assoc sta to %d\n", max_assoc_sta);
 811
 812        wil_set_recovery_state(wil, fw_recovery_idle);
 813        set_bit(wil_status_fwready, wil->status);
 814        /* let the reset sequence continue */
 815        complete(&wil->wmi_ready);
 816}
 817
 818static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len)
 819{
 820        struct wil6210_priv *wil = vif_to_wil(vif);
 821        struct wmi_rx_mgmt_packet_event *data = d;
 822        struct wiphy *wiphy = wil_to_wiphy(wil);
 823        struct ieee80211_mgmt *rx_mgmt_frame =
 824                        (struct ieee80211_mgmt *)data->payload;
 825        int flen = len - offsetof(struct wmi_rx_mgmt_packet_event, payload);
 826        int ch_no;
 827        u32 freq;
 828        struct ieee80211_channel *channel;
 829        s32 signal;
 830        __le16 fc;
 831        u32 d_len;
 832        u16 d_status;
 833
 834        if (flen < 0) {
 835                wil_err(wil, "MGMT Rx: short event, len %d\n", len);
 836                return;
 837        }
 838
 839        d_len = le32_to_cpu(data->info.len);
 840        if (d_len != flen) {
 841                wil_err(wil,
 842                        "MGMT Rx: length mismatch, d_len %d should be %d\n",
 843                        d_len, flen);
 844                return;
 845        }
 846
 847        ch_no = data->info.channel + 1;
 848        freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
 849        channel = ieee80211_get_channel(wiphy, freq);
 850        if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
 851                signal = 100 * data->info.rssi;
 852        else
 853                signal = data->info.sqi;
 854        d_status = le16_to_cpu(data->info.status);
 855        fc = rx_mgmt_frame->frame_control;
 856
 857        wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n",
 858                    data->info.channel, data->info.mcs, data->info.rssi,
 859                    data->info.sqi);
 860        wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
 861                    le16_to_cpu(fc));
 862        wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
 863                    data->info.qid, data->info.mid, data->info.cid);
 864        wil_hex_dump_wmi("MGMT Rx ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
 865                         d_len, true);
 866
 867        if (!channel) {
 868                wil_err(wil, "Frame on unsupported channel\n");
 869                return;
 870        }
 871
 872        if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
 873                struct cfg80211_bss *bss;
 874                u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
 875                u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
 876                u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
 877                const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
 878                size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
 879                                                 u.beacon.variable);
 880                wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
 881                wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf);
 882                wil_dbg_wmi(wil, "Beacon interval : %d\n", bi);
 883                wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf,
 884                                 ie_len, true);
 885
 886                wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
 887
 888                bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
 889                                                d_len, signal, GFP_KERNEL);
 890                if (bss) {
 891                        wil_dbg_wmi(wil, "Added BSS %pM\n",
 892                                    rx_mgmt_frame->bssid);
 893                        cfg80211_put_bss(wiphy, bss);
 894                } else {
 895                        wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
 896                }
 897        } else {
 898                mutex_lock(&wil->vif_mutex);
 899                cfg80211_rx_mgmt(vif_to_radio_wdev(wil, vif), freq, signal,
 900                                 (void *)rx_mgmt_frame, d_len, 0);
 901                mutex_unlock(&wil->vif_mutex);
 902        }
 903}
 904
 905static void wmi_evt_tx_mgmt(struct wil6210_vif *vif, int id, void *d, int len)
 906{
 907        struct wmi_tx_mgmt_packet_event *data = d;
 908        struct ieee80211_mgmt *mgmt_frame =
 909                        (struct ieee80211_mgmt *)data->payload;
 910        int flen = len - offsetof(struct wmi_tx_mgmt_packet_event, payload);
 911
 912        wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame,
 913                         flen, true);
 914}
 915
 916static void wmi_evt_scan_complete(struct wil6210_vif *vif, int id,
 917                                  void *d, int len)
 918{
 919        struct wil6210_priv *wil = vif_to_wil(vif);
 920
 921        mutex_lock(&wil->vif_mutex);
 922        if (vif->scan_request) {
 923                struct wmi_scan_complete_event *data = d;
 924                int status = le32_to_cpu(data->status);
 925                struct cfg80211_scan_info info = {
 926                        .aborted = ((status != WMI_SCAN_SUCCESS) &&
 927                                (status != WMI_SCAN_ABORT_REJECTED)),
 928                };
 929
 930                wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status);
 931                wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
 932                             vif->scan_request, info.aborted);
 933                del_timer_sync(&vif->scan_timer);
 934                cfg80211_scan_done(vif->scan_request, &info);
 935                if (vif->mid == 0)
 936                        wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
 937                vif->scan_request = NULL;
 938                wake_up_interruptible(&wil->wq);
 939                if (vif->p2p.pending_listen_wdev) {
 940                        wil_dbg_misc(wil, "Scheduling delayed listen\n");
 941                        schedule_work(&vif->p2p.delayed_listen_work);
 942                }
 943        } else {
 944                wil_err(wil, "SCAN_COMPLETE while not scanning\n");
 945        }
 946        mutex_unlock(&wil->vif_mutex);
 947}
 948
 949static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
 950{
 951        struct wil6210_priv *wil = vif_to_wil(vif);
 952        struct net_device *ndev = vif_to_ndev(vif);
 953        struct wireless_dev *wdev = vif_to_wdev(vif);
 954        struct wmi_connect_event *evt = d;
 955        int ch; /* channel number */
 956        struct station_info *sinfo;
 957        u8 *assoc_req_ie, *assoc_resp_ie;
 958        size_t assoc_req_ielen, assoc_resp_ielen;
 959        /* capinfo(u16) + listen_interval(u16) + IEs */
 960        const size_t assoc_req_ie_offset = sizeof(u16) * 2;
 961        /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
 962        const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
 963        int rc;
 964
 965        if (len < sizeof(*evt)) {
 966                wil_err(wil, "Connect event too short : %d bytes\n", len);
 967                return;
 968        }
 969        if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
 970                   evt->assoc_resp_len) {
 971                wil_err(wil,
 972                        "Connect event corrupted : %d != %d + %d + %d + %d\n",
 973                        len, (int)sizeof(*evt), evt->beacon_ie_len,
 974                        evt->assoc_req_len, evt->assoc_resp_len);
 975                return;
 976        }
 977        if (evt->cid >= max_assoc_sta) {
 978                wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
 979                return;
 980        }
 981
 982        ch = evt->channel + 1;
 983        wil_info(wil, "Connect %pM channel [%d] cid %d aid %d\n",
 984                 evt->bssid, ch, evt->cid, evt->aid);
 985        wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
 986                         evt->assoc_info, len - sizeof(*evt), true);
 987
 988        /* figure out IE's */
 989        assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
 990                                        assoc_req_ie_offset];
 991        assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
 992        if (evt->assoc_req_len <= assoc_req_ie_offset) {
 993                assoc_req_ie = NULL;
 994                assoc_req_ielen = 0;
 995        }
 996
 997        assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
 998                                         evt->assoc_req_len +
 999                                         assoc_resp_ie_offset];
1000        assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
1001        if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
1002                assoc_resp_ie = NULL;
1003                assoc_resp_ielen = 0;
1004        }
1005
1006        if (test_bit(wil_status_resetting, wil->status) ||
1007            !test_bit(wil_status_fwready, wil->status)) {
1008                wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
1009                        evt->cid);
1010                /* no need for cleanup, wil_reset will do that */
1011                return;
1012        }
1013
1014        mutex_lock(&wil->mutex);
1015
1016        if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
1017            (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
1018                if (!test_bit(wil_vif_fwconnecting, vif->status)) {
1019                        wil_err(wil, "Not in connecting state\n");
1020                        mutex_unlock(&wil->mutex);
1021                        return;
1022                }
1023                del_timer_sync(&vif->connect_timer);
1024        } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
1025                   (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
1026                if (wil->sta[evt->cid].status != wil_sta_unused) {
1027                        wil_err(wil, "AP: Invalid status %d for CID %d\n",
1028                                wil->sta[evt->cid].status, evt->cid);
1029                        mutex_unlock(&wil->mutex);
1030                        return;
1031                }
1032        }
1033
1034        ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
1035        wil->sta[evt->cid].mid = vif->mid;
1036        wil->sta[evt->cid].status = wil_sta_conn_pending;
1037
1038        rc = wil_ring_init_tx(vif, evt->cid);
1039        if (rc) {
1040                wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n",
1041                        evt->cid, rc);
1042                wmi_disconnect_sta(vif, wil->sta[evt->cid].addr,
1043                                   WLAN_REASON_UNSPECIFIED, false);
1044        } else {
1045                wil_info(wil, "successful connection to CID %d\n", evt->cid);
1046        }
1047
1048        if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
1049            (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
1050                if (rc) {
1051                        netif_carrier_off(ndev);
1052                        wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
1053                        wil_err(wil, "cfg80211_connect_result with failure\n");
1054                        cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
1055                                                NULL, 0,
1056                                                WLAN_STATUS_UNSPECIFIED_FAILURE,
1057                                                GFP_KERNEL);
1058                        goto out;
1059                } else {
1060                        struct wiphy *wiphy = wil_to_wiphy(wil);
1061
1062                        cfg80211_ref_bss(wiphy, vif->bss);
1063                        cfg80211_connect_bss(ndev, evt->bssid, vif->bss,
1064                                             assoc_req_ie, assoc_req_ielen,
1065                                             assoc_resp_ie, assoc_resp_ielen,
1066                                             WLAN_STATUS_SUCCESS, GFP_KERNEL,
1067                                             NL80211_TIMEOUT_UNSPECIFIED);
1068                }
1069                vif->bss = NULL;
1070        } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
1071                   (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
1072
1073                if (rc) {
1074                        if (disable_ap_sme)
1075                                /* notify new_sta has failed */
1076                                cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
1077                        goto out;
1078                }
1079
1080                sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
1081                if (!sinfo) {
1082                        rc = -ENOMEM;
1083                        goto out;
1084                }
1085
1086                sinfo->generation = wil->sinfo_gen++;
1087
1088                if (assoc_req_ie) {
1089                        sinfo->assoc_req_ies = assoc_req_ie;
1090                        sinfo->assoc_req_ies_len = assoc_req_ielen;
1091                }
1092
1093                cfg80211_new_sta(ndev, evt->bssid, sinfo, GFP_KERNEL);
1094
1095                kfree(sinfo);
1096        } else {
1097                wil_err(wil, "unhandled iftype %d for CID %d\n", wdev->iftype,
1098                        evt->cid);
1099                goto out;
1100        }
1101
1102        wil->sta[evt->cid].status = wil_sta_connected;
1103        wil->sta[evt->cid].aid = evt->aid;
1104        if (!test_and_set_bit(wil_vif_fwconnected, vif->status))
1105                atomic_inc(&wil->connected_vifs);
1106        wil_update_net_queues_bh(wil, vif, NULL, false);
1107
1108out:
1109        if (rc) {
1110                wil->sta[evt->cid].status = wil_sta_unused;
1111                wil->sta[evt->cid].mid = U8_MAX;
1112        }
1113        clear_bit(wil_vif_fwconnecting, vif->status);
1114        mutex_unlock(&wil->mutex);
1115}
1116
1117static void wmi_evt_disconnect(struct wil6210_vif *vif, int id,
1118                               void *d, int len)
1119{
1120        struct wil6210_priv *wil = vif_to_wil(vif);
1121        struct wmi_disconnect_event *evt = d;
1122        u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
1123
1124        wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
1125                 evt->bssid, reason_code, evt->disconnect_reason);
1126
1127        wil->sinfo_gen++;
1128
1129        if (test_bit(wil_status_resetting, wil->status) ||
1130            !test_bit(wil_status_fwready, wil->status)) {
1131                wil_err(wil, "status_resetting, cancel disconnect event\n");
1132                /* no need for cleanup, wil_reset will do that */
1133                return;
1134        }
1135
1136        mutex_lock(&wil->mutex);
1137        wil6210_disconnect_complete(vif, evt->bssid, reason_code);
1138        if (disable_ap_sme) {
1139                struct wireless_dev *wdev = vif_to_wdev(vif);
1140                struct net_device *ndev = vif_to_ndev(vif);
1141
1142                /* disconnect event in disable_ap_sme mode means link loss */
1143                switch (wdev->iftype) {
1144                /* AP-like interface */
1145                case NL80211_IFTYPE_AP:
1146                case NL80211_IFTYPE_P2P_GO:
1147                        /* notify hostapd about link loss */
1148                        cfg80211_cqm_pktloss_notify(ndev, evt->bssid, 0,
1149                                                    GFP_KERNEL);
1150                        break;
1151                default:
1152                        break;
1153                }
1154        }
1155        mutex_unlock(&wil->mutex);
1156}
1157
1158/*
1159 * Firmware reports EAPOL frame using WME event.
1160 * Reconstruct Ethernet frame and deliver it via normal Rx
1161 */
1162static void wmi_evt_eapol_rx(struct wil6210_vif *vif, int id, void *d, int len)
1163{
1164        struct wil6210_priv *wil = vif_to_wil(vif);
1165        struct net_device *ndev = vif_to_ndev(vif);
1166        struct wmi_eapol_rx_event *evt = d;
1167        u16 eapol_len = le16_to_cpu(evt->eapol_len);
1168        int sz = eapol_len + ETH_HLEN;
1169        struct sk_buff *skb;
1170        struct ethhdr *eth;
1171        int cid;
1172        struct wil_net_stats *stats = NULL;
1173
1174        wil_dbg_wmi(wil, "EAPOL len %d from %pM MID %d\n", eapol_len,
1175                    evt->src_mac, vif->mid);
1176
1177        cid = wil_find_cid(wil, vif->mid, evt->src_mac);
1178        if (cid >= 0)
1179                stats = &wil->sta[cid].stats;
1180
1181        if (eapol_len > 196) { /* TODO: revisit size limit */
1182                wil_err(wil, "EAPOL too large\n");
1183                return;
1184        }
1185
1186        skb = alloc_skb(sz, GFP_KERNEL);
1187        if (!skb) {
1188                wil_err(wil, "Failed to allocate skb\n");
1189                return;
1190        }
1191
1192        eth = skb_put(skb, ETH_HLEN);
1193        ether_addr_copy(eth->h_dest, ndev->dev_addr);
1194        ether_addr_copy(eth->h_source, evt->src_mac);
1195        eth->h_proto = cpu_to_be16(ETH_P_PAE);
1196        skb_put_data(skb, evt->eapol, eapol_len);
1197        skb->protocol = eth_type_trans(skb, ndev);
1198        if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
1199                ndev->stats.rx_packets++;
1200                ndev->stats.rx_bytes += sz;
1201                if (stats) {
1202                        stats->rx_packets++;
1203                        stats->rx_bytes += sz;
1204                }
1205        } else {
1206                ndev->stats.rx_dropped++;
1207                if (stats)
1208                        stats->rx_dropped++;
1209        }
1210}
1211
1212static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
1213{
1214        struct wil6210_priv *wil = vif_to_wil(vif);
1215        struct wmi_ring_en_event *evt = d;
1216        u8 vri = evt->ring_index;
1217        struct wireless_dev *wdev = vif_to_wdev(vif);
1218        struct wil_sta_info *sta;
1219        u8 cid;
1220        struct key_params params;
1221
1222        wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid);
1223
1224        if (vri >= ARRAY_SIZE(wil->ring_tx)) {
1225                wil_err(wil, "Enable for invalid vring %d\n", vri);
1226                return;
1227        }
1228
1229        if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme ||
1230            test_bit(wil_vif_ft_roam, vif->status))
1231                /* in AP mode with disable_ap_sme that is not FT,
1232                 * this is done by wil_cfg80211_change_station()
1233                 */
1234                wil->ring_tx_data[vri].dot1x_open = true;
1235        if (vri == vif->bcast_ring) /* no BA for bcast */
1236                return;
1237
1238        cid = wil->ring2cid_tid[vri][0];
1239        if (!wil_cid_valid(cid)) {
1240                wil_err(wil, "invalid cid %d for vring %d\n", cid, vri);
1241                return;
1242        }
1243
1244        /* In FT mode we get key but not store it as it is received
1245         * before WMI_CONNECT_EVENT received from FW.
1246         * wil_set_crypto_rx is called here to reset the security PN
1247         */
1248        sta = &wil->sta[cid];
1249        if (test_bit(wil_vif_ft_roam, vif->status)) {
1250                memset(&params, 0, sizeof(params));
1251                wil_set_crypto_rx(0, WMI_KEY_USE_PAIRWISE, sta, &params);
1252                if (wdev->iftype != NL80211_IFTYPE_AP)
1253                        clear_bit(wil_vif_ft_roam, vif->status);
1254        }
1255
1256        if (agg_wsize >= 0)
1257                wil_addba_tx_request(wil, vri, agg_wsize);
1258}
1259
1260static void wmi_evt_ba_status(struct wil6210_vif *vif, int id,
1261                              void *d, int len)
1262{
1263        struct wil6210_priv *wil = vif_to_wil(vif);
1264        struct wmi_ba_status_event *evt = d;
1265        struct wil_ring_tx_data *txdata;
1266
1267        wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
1268                    evt->ringid,
1269                    evt->status == WMI_BA_AGREED ? "OK" : "N/A",
1270                    evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
1271                    evt->amsdu ? "+" : "-");
1272
1273        if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
1274                wil_err(wil, "invalid ring id %d\n", evt->ringid);
1275                return;
1276        }
1277
1278        if (evt->status != WMI_BA_AGREED) {
1279                evt->ba_timeout = 0;
1280                evt->agg_wsize = 0;
1281                evt->amsdu = 0;
1282        }
1283
1284        txdata = &wil->ring_tx_data[evt->ringid];
1285
1286        txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
1287        txdata->agg_wsize = evt->agg_wsize;
1288        txdata->agg_amsdu = evt->amsdu;
1289        txdata->addba_in_progress = false;
1290}
1291
1292static void wmi_evt_addba_rx_req(struct wil6210_vif *vif, int id,
1293                                 void *d, int len)
1294{
1295        struct wil6210_priv *wil = vif_to_wil(vif);
1296        u8 cid, tid;
1297        struct wmi_rcp_addba_req_event *evt = d;
1298
1299        if (evt->cidxtid != CIDXTID_EXTENDED_CID_TID) {
1300                parse_cidxtid(evt->cidxtid, &cid, &tid);
1301        } else {
1302                cid = evt->cid;
1303                tid = evt->tid;
1304        }
1305        wil_addba_rx_request(wil, vif->mid, cid, tid, evt->dialog_token,
1306                             evt->ba_param_set, evt->ba_timeout,
1307                             evt->ba_seq_ctrl);
1308}
1309
1310static void wmi_evt_delba(struct wil6210_vif *vif, int id, void *d, int len)
1311__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
1312{
1313        struct wil6210_priv *wil = vif_to_wil(vif);
1314        struct wmi_delba_event *evt = d;
1315        u8 cid, tid;
1316        u16 reason = __le16_to_cpu(evt->reason);
1317        struct wil_sta_info *sta;
1318        struct wil_tid_ampdu_rx *r;
1319
1320        might_sleep();
1321
1322        if (evt->cidxtid != CIDXTID_EXTENDED_CID_TID) {
1323                parse_cidxtid(evt->cidxtid, &cid, &tid);
1324        } else {
1325                cid = evt->cid;
1326                tid = evt->tid;
1327        }
1328        wil_dbg_wmi(wil, "DELBA MID %d CID %d TID %d from %s reason %d\n",
1329                    vif->mid, cid, tid,
1330                    evt->from_initiator ? "originator" : "recipient",
1331                    reason);
1332        if (!evt->from_initiator) {
1333                int i;
1334                /* find Tx vring it belongs to */
1335                for (i = 0; i < ARRAY_SIZE(wil->ring2cid_tid); i++) {
1336                        if (wil->ring2cid_tid[i][0] == cid &&
1337                            wil->ring2cid_tid[i][1] == tid) {
1338                                struct wil_ring_tx_data *txdata =
1339                                        &wil->ring_tx_data[i];
1340
1341                                wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
1342                                txdata->agg_timeout = 0;
1343                                txdata->agg_wsize = 0;
1344                                txdata->addba_in_progress = false;
1345
1346                                break; /* max. 1 matching ring */
1347                        }
1348                }
1349                if (i >= ARRAY_SIZE(wil->ring2cid_tid))
1350                        wil_err(wil, "DELBA: unable to find Tx vring\n");
1351                return;
1352        }
1353
1354        sta = &wil->sta[cid];
1355
1356        spin_lock_bh(&sta->tid_rx_lock);
1357
1358        r = sta->tid_rx[tid];
1359        sta->tid_rx[tid] = NULL;
1360        wil_tid_ampdu_rx_free(wil, r);
1361
1362        spin_unlock_bh(&sta->tid_rx_lock);
1363}
1364
1365static void
1366wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len)
1367{
1368        struct wil6210_priv *wil = vif_to_wil(vif);
1369        struct wmi_sched_scan_result_event *data = d;
1370        struct wiphy *wiphy = wil_to_wiphy(wil);
1371        struct ieee80211_mgmt *rx_mgmt_frame =
1372                (struct ieee80211_mgmt *)data->payload;
1373        int flen = len - offsetof(struct wmi_sched_scan_result_event, payload);
1374        int ch_no;
1375        u32 freq;
1376        struct ieee80211_channel *channel;
1377        s32 signal;
1378        __le16 fc;
1379        u32 d_len;
1380        struct cfg80211_bss *bss;
1381
1382        if (flen < 0) {
1383                wil_err(wil, "sched scan result event too short, len %d\n",
1384                        len);
1385                return;
1386        }
1387
1388        d_len = le32_to_cpu(data->info.len);
1389        if (d_len != flen) {
1390                wil_err(wil,
1391                        "sched scan result length mismatch, d_len %d should be %d\n",
1392                        d_len, flen);
1393                return;
1394        }
1395
1396        fc = rx_mgmt_frame->frame_control;
1397        if (!ieee80211_is_probe_resp(fc)) {
1398                wil_err(wil, "sched scan result invalid frame, fc 0x%04x\n",
1399                        fc);
1400                return;
1401        }
1402
1403        ch_no = data->info.channel + 1;
1404        freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
1405        channel = ieee80211_get_channel(wiphy, freq);
1406        if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
1407                signal = 100 * data->info.rssi;
1408        else
1409                signal = data->info.sqi;
1410
1411        wil_dbg_wmi(wil, "sched scan result: channel %d MCS %d RSSI %d\n",
1412                    data->info.channel, data->info.mcs, data->info.rssi);
1413        wil_dbg_wmi(wil, "len %d qid %d mid %d cid %d\n",
1414                    d_len, data->info.qid, data->info.mid, data->info.cid);
1415        wil_hex_dump_wmi("PROBE ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
1416                         d_len, true);
1417
1418        if (!channel) {
1419                wil_err(wil, "Frame on unsupported channel\n");
1420                return;
1421        }
1422
1423        bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
1424                                        d_len, signal, GFP_KERNEL);
1425        if (bss) {
1426                wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid);
1427                cfg80211_put_bss(wiphy, bss);
1428        } else {
1429                wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
1430        }
1431
1432        cfg80211_sched_scan_results(wiphy, 0);
1433}
1434
1435static void wil_link_stats_store_basic(struct wil6210_vif *vif,
1436                                       struct wmi_link_stats_basic *basic)
1437{
1438        struct wil6210_priv *wil = vif_to_wil(vif);
1439        u8 cid = basic->cid;
1440        struct wil_sta_info *sta;
1441
1442        if (cid < 0 || cid >= max_assoc_sta) {
1443                wil_err(wil, "invalid cid %d\n", cid);
1444                return;
1445        }
1446
1447        sta = &wil->sta[cid];
1448        sta->fw_stats_basic = *basic;
1449}
1450
1451static void wil_link_stats_store_global(struct wil6210_vif *vif,
1452                                        struct wmi_link_stats_global *global)
1453{
1454        struct wil6210_priv *wil = vif_to_wil(vif);
1455
1456        wil->fw_stats_global.stats = *global;
1457}
1458
1459static void wmi_link_stats_parse(struct wil6210_vif *vif, u64 tsf,
1460                                 bool has_next, void *payload,
1461                                 size_t payload_size)
1462{
1463        struct wil6210_priv *wil = vif_to_wil(vif);
1464        size_t hdr_size = sizeof(struct wmi_link_stats_record);
1465        size_t stats_size, record_size, expected_size;
1466        struct wmi_link_stats_record *hdr;
1467
1468        if (payload_size < hdr_size) {
1469                wil_err(wil, "link stats wrong event size %zu\n", payload_size);
1470                return;
1471        }
1472
1473        while (payload_size >= hdr_size) {
1474                hdr = payload;
1475                stats_size = le16_to_cpu(hdr->record_size);
1476                record_size = hdr_size + stats_size;
1477
1478                if (payload_size < record_size) {
1479                        wil_err(wil, "link stats payload ended unexpectedly, size %zu < %zu\n",
1480                                payload_size, record_size);
1481                        return;
1482                }
1483
1484                switch (hdr->record_type_id) {
1485                case WMI_LINK_STATS_TYPE_BASIC:
1486                        expected_size = sizeof(struct wmi_link_stats_basic);
1487                        if (stats_size < expected_size) {
1488                                wil_err(wil, "link stats invalid basic record size %zu < %zu\n",
1489                                        stats_size, expected_size);
1490                                return;
1491                        }
1492                        if (vif->fw_stats_ready) {
1493                                /* clean old statistics */
1494                                vif->fw_stats_tsf = 0;
1495                                vif->fw_stats_ready = 0;
1496                        }
1497
1498                        wil_link_stats_store_basic(vif, payload + hdr_size);
1499
1500                        if (!has_next) {
1501                                vif->fw_stats_tsf = tsf;
1502                                vif->fw_stats_ready = 1;
1503                        }
1504
1505                        break;
1506                case WMI_LINK_STATS_TYPE_GLOBAL:
1507                        expected_size = sizeof(struct wmi_link_stats_global);
1508                        if (stats_size < sizeof(struct wmi_link_stats_global)) {
1509                                wil_err(wil, "link stats invalid global record size %zu < %zu\n",
1510                                        stats_size, expected_size);
1511                                return;
1512                        }
1513
1514                        if (wil->fw_stats_global.ready) {
1515                                /* clean old statistics */
1516                                wil->fw_stats_global.tsf = 0;
1517                                wil->fw_stats_global.ready = 0;
1518                        }
1519
1520                        wil_link_stats_store_global(vif, payload + hdr_size);
1521
1522                        if (!has_next) {
1523                                wil->fw_stats_global.tsf = tsf;
1524                                wil->fw_stats_global.ready = 1;
1525                        }
1526
1527                        break;
1528                default:
1529                        break;
1530                }
1531
1532                /* skip to next record */
1533                payload += record_size;
1534                payload_size -= record_size;
1535        }
1536}
1537
1538static void
1539wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len)
1540{
1541        struct wil6210_priv *wil = vif_to_wil(vif);
1542        struct wmi_link_stats_event *evt = d;
1543        size_t payload_size;
1544
1545        if (len < offsetof(struct wmi_link_stats_event, payload)) {
1546                wil_err(wil, "stats event way too short %d\n", len);
1547                return;
1548        }
1549        payload_size = le16_to_cpu(evt->payload_size);
1550        if (len < sizeof(struct wmi_link_stats_event) + payload_size) {
1551                wil_err(wil, "stats event too short %d\n", len);
1552                return;
1553        }
1554
1555        wmi_link_stats_parse(vif, le64_to_cpu(evt->tsf), evt->has_next,
1556                             evt->payload, payload_size);
1557}
1558
1559/**
1560 * find cid and ringid for the station vif
1561 *
1562 * return error, if other interfaces are used or ring was not found
1563 */
1564static int wil_find_cid_ringid_sta(struct wil6210_priv *wil,
1565                                   struct wil6210_vif *vif,
1566                                   int *cid,
1567                                   int *ringid)
1568{
1569        struct wil_ring *ring;
1570        struct wil_ring_tx_data *txdata;
1571        int min_ring_id = wil_get_min_tx_ring_id(wil);
1572        int i;
1573        u8 lcid;
1574
1575        if (!(vif->wdev.iftype == NL80211_IFTYPE_STATION ||
1576              vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
1577                wil_err(wil, "invalid interface type %d\n", vif->wdev.iftype);
1578                return -EINVAL;
1579        }
1580
1581        /* In the STA mode, it is expected to have only one ring
1582         * for the AP we are connected to.
1583         * find it and return the cid associated with it.
1584         */
1585        for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
1586                ring = &wil->ring_tx[i];
1587                txdata = &wil->ring_tx_data[i];
1588                if (!ring->va || !txdata->enabled || txdata->mid != vif->mid)
1589                        continue;
1590
1591                lcid = wil->ring2cid_tid[i][0];
1592                if (lcid >= max_assoc_sta) /* skip BCAST */
1593                        continue;
1594
1595                wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid);
1596                *cid = lcid;
1597                *ringid = i;
1598                return 0;
1599        }
1600
1601        wil_dbg_wmi(wil, "find sta cid while no rings active?\n");
1602
1603        return -ENOENT;
1604}
1605
1606static void
1607wmi_evt_auth_status(struct wil6210_vif *vif, int id, void *d, int len)
1608{
1609        struct wil6210_priv *wil = vif_to_wil(vif);
1610        struct net_device *ndev = vif_to_ndev(vif);
1611        struct wmi_ft_auth_status_event *data = d;
1612        int ie_len = len - offsetof(struct wmi_ft_auth_status_event, ie_info);
1613        int rc, cid = 0, ringid = 0;
1614        struct cfg80211_ft_event_params ft;
1615        u16 d_len;
1616        /* auth_alg(u16) + auth_transaction(u16) + status_code(u16) */
1617        const size_t auth_ie_offset = sizeof(u16) * 3;
1618        struct auth_no_hdr *auth = (struct auth_no_hdr *)data->ie_info;
1619
1620        /* check the status */
1621        if (ie_len >= 0 && data->status != WMI_FW_STATUS_SUCCESS) {
1622                wil_err(wil, "FT: auth failed. status %d\n", data->status);
1623                goto fail;
1624        }
1625
1626        if (ie_len < auth_ie_offset) {
1627                wil_err(wil, "FT: auth event too short, len %d\n", len);
1628                goto fail;
1629        }
1630
1631        d_len = le16_to_cpu(data->ie_len);
1632        if (d_len != ie_len) {
1633                wil_err(wil,
1634                        "FT: auth ie length mismatch, d_len %d should be %d\n",
1635                        d_len, ie_len);
1636                goto fail;
1637        }
1638
1639        if (!test_bit(wil_vif_ft_roam, wil->status)) {
1640                wil_err(wil, "FT: Not in roaming state\n");
1641                goto fail;
1642        }
1643
1644        if (le16_to_cpu(auth->auth_transaction) != 2) {
1645                wil_err(wil, "FT: auth error. auth_transaction %d\n",
1646                        le16_to_cpu(auth->auth_transaction));
1647                goto fail;
1648        }
1649
1650        if (le16_to_cpu(auth->auth_alg) != WLAN_AUTH_FT) {
1651                wil_err(wil, "FT: auth error. auth_alg %d\n",
1652                        le16_to_cpu(auth->auth_alg));
1653                goto fail;
1654        }
1655
1656        wil_dbg_wmi(wil, "FT: Auth to %pM successfully\n", data->mac_addr);
1657        wil_hex_dump_wmi("FT Auth ies : ", DUMP_PREFIX_OFFSET, 16, 1,
1658                         data->ie_info, d_len, true);
1659
1660        /* find cid and ringid */
1661        rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
1662        if (rc) {
1663                wil_err(wil, "No valid cid found\n");
1664                goto fail;
1665        }
1666
1667        if (vif->privacy) {
1668                /* For secure assoc, remove old keys */
1669                rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
1670                                        WMI_KEY_USE_PAIRWISE);
1671                if (rc) {
1672                        wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
1673                        goto fail;
1674                }
1675                rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
1676                                        WMI_KEY_USE_RX_GROUP);
1677                if (rc) {
1678                        wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
1679                        goto fail;
1680                }
1681        }
1682
1683        memset(&ft, 0, sizeof(ft));
1684        ft.ies = data->ie_info + auth_ie_offset;
1685        ft.ies_len = d_len - auth_ie_offset;
1686        ft.target_ap = data->mac_addr;
1687        cfg80211_ft_event(ndev, &ft);
1688
1689        return;
1690
1691fail:
1692        wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID);
1693}
1694
1695static void
1696wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len)
1697{
1698        struct wil6210_priv *wil = vif_to_wil(vif);
1699        struct net_device *ndev = vif_to_ndev(vif);
1700        struct wiphy *wiphy = wil_to_wiphy(wil);
1701        struct wmi_ft_reassoc_status_event *data = d;
1702        int ies_len = len - offsetof(struct wmi_ft_reassoc_status_event,
1703                                     ie_info);
1704        int rc = -ENOENT, cid = 0, ringid = 0;
1705        int ch; /* channel number (primary) */
1706        size_t assoc_req_ie_len = 0, assoc_resp_ie_len = 0;
1707        u8 *assoc_req_ie = NULL, *assoc_resp_ie = NULL;
1708        /* capinfo(u16) + listen_interval(u16) + current_ap mac addr + IEs */
1709        const size_t assoc_req_ie_offset = sizeof(u16) * 2 + ETH_ALEN;
1710        /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
1711        const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
1712        u16 d_len;
1713        int freq;
1714        struct cfg80211_roam_info info;
1715
1716        if (ies_len < 0) {
1717                wil_err(wil, "ft reassoc event too short, len %d\n", len);
1718                goto fail;
1719        }
1720
1721        wil_dbg_wmi(wil, "Reasoc Status event: status=%d, aid=%d",
1722                    data->status, data->aid);
1723        wil_dbg_wmi(wil, "    mac_addr=%pM, beacon_ie_len=%d",
1724                    data->mac_addr, data->beacon_ie_len);
1725        wil_dbg_wmi(wil, "    reassoc_req_ie_len=%d, reassoc_resp_ie_len=%d",
1726                    le16_to_cpu(data->reassoc_req_ie_len),
1727                    le16_to_cpu(data->reassoc_resp_ie_len));
1728
1729        d_len = le16_to_cpu(data->beacon_ie_len) +
1730                le16_to_cpu(data->reassoc_req_ie_len) +
1731                le16_to_cpu(data->reassoc_resp_ie_len);
1732        if (d_len != ies_len) {
1733                wil_err(wil,
1734                        "ft reassoc ie length mismatch, d_len %d should be %d\n",
1735                        d_len, ies_len);
1736                goto fail;
1737        }
1738
1739        /* check the status */
1740        if (data->status != WMI_FW_STATUS_SUCCESS) {
1741                wil_err(wil, "ft reassoc failed. status %d\n", data->status);
1742                goto fail;
1743        }
1744
1745        /* find cid and ringid */
1746        rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
1747        if (rc) {
1748                wil_err(wil, "No valid cid found\n");
1749                goto fail;
1750        }
1751
1752        ch = data->channel + 1;
1753        wil_info(wil, "FT: Roam %pM channel [%d] cid %d aid %d\n",
1754                 data->mac_addr, ch, cid, data->aid);
1755
1756        wil_hex_dump_wmi("reassoc AI : ", DUMP_PREFIX_OFFSET, 16, 1,
1757                         data->ie_info, len - sizeof(*data), true);
1758
1759        /* figure out IE's */
1760        if (le16_to_cpu(data->reassoc_req_ie_len) > assoc_req_ie_offset) {
1761                assoc_req_ie = &data->ie_info[assoc_req_ie_offset];
1762                assoc_req_ie_len = le16_to_cpu(data->reassoc_req_ie_len) -
1763                        assoc_req_ie_offset;
1764        }
1765        if (le16_to_cpu(data->reassoc_resp_ie_len) <= assoc_resp_ie_offset) {
1766                wil_err(wil, "FT: reassoc resp ie len is too short, len %d\n",
1767                        le16_to_cpu(data->reassoc_resp_ie_len));
1768                goto fail;
1769        }
1770
1771        assoc_resp_ie = &data->ie_info[le16_to_cpu(data->reassoc_req_ie_len) +
1772                assoc_resp_ie_offset];
1773        assoc_resp_ie_len = le16_to_cpu(data->reassoc_resp_ie_len) -
1774                assoc_resp_ie_offset;
1775
1776        if (test_bit(wil_status_resetting, wil->status) ||
1777            !test_bit(wil_status_fwready, wil->status)) {
1778                wil_err(wil, "FT: status_resetting, cancel reassoc event\n");
1779                /* no need for cleanup, wil_reset will do that */
1780                return;
1781        }
1782
1783        mutex_lock(&wil->mutex);
1784
1785        /* ring modify to set the ring for the roamed AP settings */
1786        wil_dbg_wmi(wil,
1787                    "ft modify tx config for connection CID %d ring %d\n",
1788                    cid, ringid);
1789
1790        rc = wil->txrx_ops.tx_ring_modify(vif, ringid, cid, 0);
1791        if (rc) {
1792                wil_err(wil, "modify TX for CID %d MID %d ring %d failed (%d)\n",
1793                        cid, vif->mid, ringid, rc);
1794                mutex_unlock(&wil->mutex);
1795                goto fail;
1796        }
1797
1798        /* Update the driver STA members with the new bss */
1799        wil->sta[cid].aid = data->aid;
1800        wil->sta[cid].stats.ft_roams++;
1801        ether_addr_copy(wil->sta[cid].addr, vif->bss->bssid);
1802        mutex_unlock(&wil->mutex);
1803        del_timer_sync(&vif->connect_timer);
1804
1805        cfg80211_ref_bss(wiphy, vif->bss);
1806        freq = ieee80211_channel_to_frequency(ch, NL80211_BAND_60GHZ);
1807
1808        memset(&info, 0, sizeof(info));
1809        info.channel = ieee80211_get_channel(wiphy, freq);
1810        info.bss = vif->bss;
1811        info.req_ie = assoc_req_ie;
1812        info.req_ie_len = assoc_req_ie_len;
1813        info.resp_ie = assoc_resp_ie;
1814        info.resp_ie_len = assoc_resp_ie_len;
1815        cfg80211_roamed(ndev, &info, GFP_KERNEL);
1816        vif->bss = NULL;
1817
1818        return;
1819
1820fail:
1821        wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID);
1822}
1823
1824/**
1825 * Some events are ignored for purpose; and need not be interpreted as
1826 * "unhandled events"
1827 */
1828static void wmi_evt_ignore(struct wil6210_vif *vif, int id, void *d, int len)
1829{
1830        struct wil6210_priv *wil = vif_to_wil(vif);
1831
1832        wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
1833}
1834
1835static const struct {
1836        int eventid;
1837        void (*handler)(struct wil6210_vif *vif,
1838                        int eventid, void *data, int data_len);
1839} wmi_evt_handlers[] = {
1840        {WMI_READY_EVENTID,             wmi_evt_ready},
1841        {WMI_FW_READY_EVENTID,                  wmi_evt_ignore},
1842        {WMI_RX_MGMT_PACKET_EVENTID,    wmi_evt_rx_mgmt},
1843        {WMI_TX_MGMT_PACKET_EVENTID,            wmi_evt_tx_mgmt},
1844        {WMI_SCAN_COMPLETE_EVENTID,     wmi_evt_scan_complete},
1845        {WMI_CONNECT_EVENTID,           wmi_evt_connect},
1846        {WMI_DISCONNECT_EVENTID,        wmi_evt_disconnect},
1847        {WMI_EAPOL_RX_EVENTID,          wmi_evt_eapol_rx},
1848        {WMI_BA_STATUS_EVENTID,         wmi_evt_ba_status},
1849        {WMI_RCP_ADDBA_REQ_EVENTID,     wmi_evt_addba_rx_req},
1850        {WMI_DELBA_EVENTID,             wmi_evt_delba},
1851        {WMI_RING_EN_EVENTID,           wmi_evt_ring_en},
1852        {WMI_DATA_PORT_OPEN_EVENTID,            wmi_evt_ignore},
1853        {WMI_SCHED_SCAN_RESULT_EVENTID,         wmi_evt_sched_scan_result},
1854        {WMI_LINK_STATS_EVENTID,                wmi_evt_link_stats},
1855        {WMI_FT_AUTH_STATUS_EVENTID,            wmi_evt_auth_status},
1856        {WMI_FT_REASSOC_STATUS_EVENTID,         wmi_evt_reassoc_status},
1857};
1858
1859/*
1860 * Run in IRQ context
1861 * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
1862 * that will be eventually handled by the @wmi_event_worker in the thread
1863 * context of thread "wil6210_wmi"
1864 */
1865void wmi_recv_cmd(struct wil6210_priv *wil)
1866{
1867        struct wil6210_mbox_ring_desc d_tail;
1868        struct wil6210_mbox_hdr hdr;
1869        struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
1870        struct pending_wmi_event *evt;
1871        u8 *cmd;
1872        void __iomem *src;
1873        ulong flags;
1874        unsigned n;
1875        unsigned int num_immed_reply = 0;
1876
1877        if (!test_bit(wil_status_mbox_ready, wil->status)) {
1878                wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
1879                return;
1880        }
1881
1882        if (test_bit(wil_status_suspended, wil->status)) {
1883                wil_err(wil, "suspended. cannot handle WMI event\n");
1884                return;
1885        }
1886
1887        for (n = 0;; n++) {
1888                u16 len;
1889                bool q;
1890                bool immed_reply = false;
1891
1892                r->head = wil_r(wil, RGF_MBOX +
1893                                offsetof(struct wil6210_mbox_ctl, rx.head));
1894                if (r->tail == r->head)
1895                        break;
1896
1897                wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
1898                            r->head, r->tail);
1899                /* read cmd descriptor from tail */
1900                wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
1901                                     sizeof(struct wil6210_mbox_ring_desc));
1902                if (d_tail.sync == 0) {
1903                        wil_err(wil, "Mbox evt not owned by FW?\n");
1904                        break;
1905                }
1906
1907                /* read cmd header from descriptor */
1908                if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
1909                        wil_err(wil, "Mbox evt at 0x%08x?\n",
1910                                le32_to_cpu(d_tail.addr));
1911                        break;
1912                }
1913                len = le16_to_cpu(hdr.len);
1914                wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
1915                            le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
1916                            hdr.flags);
1917
1918                /* read cmd buffer from descriptor */
1919                src = wmi_buffer(wil, d_tail.addr) +
1920                      sizeof(struct wil6210_mbox_hdr);
1921                evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
1922                                             event.wmi) + len, 4),
1923                              GFP_KERNEL);
1924                if (!evt)
1925                        break;
1926
1927                evt->event.hdr = hdr;
1928                cmd = (void *)&evt->event.wmi;
1929                wil_memcpy_fromio_32(cmd, src, len);
1930                /* mark entry as empty */
1931                wil_w(wil, r->tail +
1932                      offsetof(struct wil6210_mbox_ring_desc, sync), 0);
1933                /* indicate */
1934                if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
1935                    (len >= sizeof(struct wmi_cmd_hdr))) {
1936                        struct wmi_cmd_hdr *wmi = &evt->event.wmi;
1937                        u16 id = le16_to_cpu(wmi->command_id);
1938                        u8 mid = wmi->mid;
1939                        u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
1940                        if (test_bit(wil_status_resuming, wil->status)) {
1941                                if (id == WMI_TRAFFIC_RESUME_EVENTID)
1942                                        clear_bit(wil_status_resuming,
1943                                                  wil->status);
1944                                else
1945                                        wil_err(wil,
1946                                                "WMI evt %d while resuming\n",
1947                                                id);
1948                        }
1949                        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1950                        if (wil->reply_id && wil->reply_id == id &&
1951                            wil->reply_mid == mid) {
1952                                if (wil->reply_buf) {
1953                                        memcpy(wil->reply_buf, wmi,
1954                                               min(len, wil->reply_size));
1955                                        immed_reply = true;
1956                                }
1957                                if (id == WMI_TRAFFIC_SUSPEND_EVENTID) {
1958                                        wil_dbg_wmi(wil,
1959                                                    "set suspend_resp_rcvd\n");
1960                                        wil->suspend_resp_rcvd = true;
1961                                }
1962                        }
1963                        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1964
1965                        wil_dbg_wmi(wil, "recv %s (0x%04x) MID %d @%d msec\n",
1966                                    eventid2name(id), id, wmi->mid, tstamp);
1967                        trace_wil6210_wmi_event(wmi, &wmi[1],
1968                                                len - sizeof(*wmi));
1969                }
1970                wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
1971                                 &evt->event.hdr, sizeof(hdr) + len, true);
1972
1973                /* advance tail */
1974                r->tail = r->base + ((r->tail - r->base +
1975                          sizeof(struct wil6210_mbox_ring_desc)) % r->size);
1976                wil_w(wil, RGF_MBOX +
1977                      offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
1978
1979                if (immed_reply) {
1980                        wil_dbg_wmi(wil, "recv_cmd: Complete WMI 0x%04x\n",
1981                                    wil->reply_id);
1982                        kfree(evt);
1983                        num_immed_reply++;
1984                        complete(&wil->wmi_call);
1985                } else {
1986                        /* add to the pending list */
1987                        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1988                        list_add_tail(&evt->list, &wil->pending_wmi_ev);
1989                        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1990                        q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
1991                        wil_dbg_wmi(wil, "queue_work -> %d\n", q);
1992                }
1993        }
1994        /* normally, 1 event per IRQ should be processed */
1995        wil_dbg_wmi(wil, "recv_cmd: -> %d events queued, %d completed\n",
1996                    n - num_immed_reply, num_immed_reply);
1997}
1998
1999int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
2000             u16 reply_id, void *reply, u16 reply_size, int to_msec)
2001{
2002        int rc;
2003        unsigned long remain;
2004        ulong flags;
2005
2006        mutex_lock(&wil->wmi_mutex);
2007
2008        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2009        wil->reply_id = reply_id;
2010        wil->reply_mid = mid;
2011        wil->reply_buf = reply;
2012        wil->reply_size = reply_size;
2013        reinit_completion(&wil->wmi_call);
2014        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2015
2016        rc = __wmi_send(wil, cmdid, mid, buf, len);
2017        if (rc)
2018                goto out;
2019
2020        remain = wait_for_completion_timeout(&wil->wmi_call,
2021                                             msecs_to_jiffies(to_msec));
2022        if (0 == remain) {
2023                wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
2024                        cmdid, reply_id, to_msec);
2025                rc = -ETIME;
2026        } else {
2027                wil_dbg_wmi(wil,
2028                            "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
2029                            cmdid, reply_id,
2030                            to_msec - jiffies_to_msecs(remain));
2031        }
2032
2033out:
2034        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2035        wil->reply_id = 0;
2036        wil->reply_mid = U8_MAX;
2037        wil->reply_buf = NULL;
2038        wil->reply_size = 0;
2039        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2040
2041        mutex_unlock(&wil->wmi_mutex);
2042
2043        return rc;
2044}
2045
2046int wmi_echo(struct wil6210_priv *wil)
2047{
2048        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2049        struct wmi_echo_cmd cmd = {
2050                .value = cpu_to_le32(0x12345678),
2051        };
2052
2053        return wmi_call(wil, WMI_ECHO_CMDID, vif->mid, &cmd, sizeof(cmd),
2054                        WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
2055}
2056
2057int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
2058{
2059        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2060        struct wmi_set_mac_address_cmd cmd;
2061
2062        ether_addr_copy(cmd.mac, addr);
2063
2064        wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
2065
2066        return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, vif->mid,
2067                        &cmd, sizeof(cmd));
2068}
2069
2070int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
2071{
2072        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2073        int rc = 0;
2074        struct wmi_led_cfg_cmd cmd = {
2075                .led_mode = enable,
2076                .id = led_id,
2077                .slow_blink_cfg.blink_on =
2078                        cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].on_ms),
2079                .slow_blink_cfg.blink_off =
2080                        cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].off_ms),
2081                .medium_blink_cfg.blink_on =
2082                        cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].on_ms),
2083                .medium_blink_cfg.blink_off =
2084                        cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].off_ms),
2085                .fast_blink_cfg.blink_on =
2086                        cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].on_ms),
2087                .fast_blink_cfg.blink_off =
2088                        cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].off_ms),
2089                .led_polarity = led_polarity,
2090        };
2091        struct {
2092                struct wmi_cmd_hdr wmi;
2093                struct wmi_led_cfg_done_event evt;
2094        } __packed reply = {
2095                .evt = {.status = cpu_to_le32(WMI_FW_STATUS_FAILURE)},
2096        };
2097
2098        if (led_id == WIL_LED_INVALID_ID)
2099                goto out;
2100
2101        if (led_id > WIL_LED_MAX_ID) {
2102                wil_err(wil, "Invalid led id %d\n", led_id);
2103                rc = -EINVAL;
2104                goto out;
2105        }
2106
2107        wil_dbg_wmi(wil,
2108                    "%s led %d\n",
2109                    enable ? "enabling" : "disabling", led_id);
2110
2111        rc = wmi_call(wil, WMI_LED_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
2112                      WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
2113                      100);
2114        if (rc)
2115                goto out;
2116
2117        if (reply.evt.status) {
2118                wil_err(wil, "led %d cfg failed with status %d\n",
2119                        led_id, le32_to_cpu(reply.evt.status));
2120                rc = -EINVAL;
2121        }
2122
2123out:
2124        return rc;
2125}
2126
2127int wmi_pcp_start(struct wil6210_vif *vif,
2128                  int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go)
2129{
2130        struct wil6210_priv *wil = vif_to_wil(vif);
2131        int rc;
2132
2133        struct wmi_pcp_start_cmd cmd = {
2134                .bcon_interval = cpu_to_le16(bi),
2135                .network_type = wmi_nettype,
2136                .disable_sec_offload = 1,
2137                .channel = chan - 1,
2138                .pcp_max_assoc_sta = max_assoc_sta,
2139                .hidden_ssid = hidden_ssid,
2140                .is_go = is_go,
2141                .ap_sme_offload_mode = disable_ap_sme ?
2142                                       WMI_AP_SME_OFFLOAD_PARTIAL :
2143                                       WMI_AP_SME_OFFLOAD_FULL,
2144                .abft_len = wil->abft_len,
2145        };
2146        struct {
2147                struct wmi_cmd_hdr wmi;
2148                struct wmi_pcp_started_event evt;
2149        } __packed reply = {
2150                .evt = {.status = WMI_FW_STATUS_FAILURE},
2151        };
2152
2153        if (!vif->privacy)
2154                cmd.disable_sec = 1;
2155
2156        if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
2157            (cmd.pcp_max_assoc_sta <= 0)) {
2158                wil_err(wil, "unexpected max_assoc_sta %d\n",
2159                        cmd.pcp_max_assoc_sta);
2160                return -EOPNOTSUPP;
2161        }
2162
2163        if (disable_ap_sme &&
2164            !test_bit(WMI_FW_CAPABILITY_AP_SME_OFFLOAD_PARTIAL,
2165                      wil->fw_capabilities)) {
2166                wil_err(wil, "disable_ap_sme not supported by FW\n");
2167                return -EOPNOTSUPP;
2168        }
2169
2170        /*
2171         * Processing time may be huge, in case of secure AP it takes about
2172         * 3500ms for FW to start AP
2173         */
2174        rc = wmi_call(wil, WMI_PCP_START_CMDID, vif->mid, &cmd, sizeof(cmd),
2175                      WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
2176        if (rc)
2177                return rc;
2178
2179        if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
2180                rc = -EINVAL;
2181
2182        if (wmi_nettype != WMI_NETTYPE_P2P)
2183                /* Don't fail due to error in the led configuration */
2184                wmi_led_cfg(wil, true);
2185
2186        return rc;
2187}
2188
2189int wmi_pcp_stop(struct wil6210_vif *vif)
2190{
2191        struct wil6210_priv *wil = vif_to_wil(vif);
2192        int rc;
2193
2194        rc = wmi_led_cfg(wil, false);
2195        if (rc)
2196                return rc;
2197
2198        return wmi_call(wil, WMI_PCP_STOP_CMDID, vif->mid, NULL, 0,
2199                        WMI_PCP_STOPPED_EVENTID, NULL, 0,
2200                        WIL_WMI_PCP_STOP_TO_MS);
2201}
2202
2203int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid)
2204{
2205        struct wil6210_priv *wil = vif_to_wil(vif);
2206        struct wmi_set_ssid_cmd cmd = {
2207                .ssid_len = cpu_to_le32(ssid_len),
2208        };
2209
2210        if (ssid_len > sizeof(cmd.ssid))
2211                return -EINVAL;
2212
2213        memcpy(cmd.ssid, ssid, ssid_len);
2214
2215        return wmi_send(wil, WMI_SET_SSID_CMDID, vif->mid, &cmd, sizeof(cmd));
2216}
2217
2218int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid)
2219{
2220        struct wil6210_priv *wil = vif_to_wil(vif);
2221        int rc;
2222        struct {
2223                struct wmi_cmd_hdr wmi;
2224                struct wmi_set_ssid_cmd cmd;
2225        } __packed reply;
2226        int len; /* reply.cmd.ssid_len in CPU order */
2227
2228        memset(&reply, 0, sizeof(reply));
2229
2230        rc = wmi_call(wil, WMI_GET_SSID_CMDID, vif->mid, NULL, 0,
2231                      WMI_GET_SSID_EVENTID, &reply, sizeof(reply), 20);
2232        if (rc)
2233                return rc;
2234
2235        len = le32_to_cpu(reply.cmd.ssid_len);
2236        if (len > sizeof(reply.cmd.ssid))
2237                return -EINVAL;
2238
2239        *ssid_len = len;
2240        memcpy(ssid, reply.cmd.ssid, len);
2241
2242        return 0;
2243}
2244
2245int wmi_set_channel(struct wil6210_priv *wil, int channel)
2246{
2247        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2248        struct wmi_set_pcp_channel_cmd cmd = {
2249                .channel = channel - 1,
2250        };
2251
2252        return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, vif->mid,
2253                        &cmd, sizeof(cmd));
2254}
2255
2256int wmi_get_channel(struct wil6210_priv *wil, int *channel)
2257{
2258        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2259        int rc;
2260        struct {
2261                struct wmi_cmd_hdr wmi;
2262                struct wmi_set_pcp_channel_cmd cmd;
2263        } __packed reply;
2264
2265        memset(&reply, 0, sizeof(reply));
2266
2267        rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, vif->mid, NULL, 0,
2268                      WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
2269        if (rc)
2270                return rc;
2271
2272        if (reply.cmd.channel > 3)
2273                return -EINVAL;
2274
2275        *channel = reply.cmd.channel + 1;
2276
2277        return 0;
2278}
2279
2280int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi)
2281{
2282        struct wil6210_priv *wil = vif_to_wil(vif);
2283        int rc;
2284        struct wmi_p2p_cfg_cmd cmd = {
2285                .discovery_mode = WMI_DISCOVERY_MODE_PEER2PEER,
2286                .bcon_interval = cpu_to_le16(bi),
2287                .channel = channel - 1,
2288        };
2289        struct {
2290                struct wmi_cmd_hdr wmi;
2291                struct wmi_p2p_cfg_done_event evt;
2292        } __packed reply = {
2293                .evt = {.status = WMI_FW_STATUS_FAILURE},
2294        };
2295
2296        wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n");
2297
2298        rc = wmi_call(wil, WMI_P2P_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
2299                      WMI_P2P_CFG_DONE_EVENTID, &reply, sizeof(reply), 300);
2300        if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
2301                wil_err(wil, "P2P_CFG failed. status %d\n", reply.evt.status);
2302                rc = -EINVAL;
2303        }
2304
2305        return rc;
2306}
2307
2308int wmi_start_listen(struct wil6210_vif *vif)
2309{
2310        struct wil6210_priv *wil = vif_to_wil(vif);
2311        int rc;
2312        struct {
2313                struct wmi_cmd_hdr wmi;
2314                struct wmi_listen_started_event evt;
2315        } __packed reply = {
2316                .evt = {.status = WMI_FW_STATUS_FAILURE},
2317        };
2318
2319        wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n");
2320
2321        rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0,
2322                      WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 300);
2323        if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
2324                wil_err(wil, "device failed to start listen. status %d\n",
2325                        reply.evt.status);
2326                rc = -EINVAL;
2327        }
2328
2329        return rc;
2330}
2331
2332int wmi_start_search(struct wil6210_vif *vif)
2333{
2334        struct wil6210_priv *wil = vif_to_wil(vif);
2335        int rc;
2336        struct {
2337                struct wmi_cmd_hdr wmi;
2338                struct wmi_search_started_event evt;
2339        } __packed reply = {
2340                .evt = {.status = WMI_FW_STATUS_FAILURE},
2341        };
2342
2343        wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n");
2344
2345        rc = wmi_call(wil, WMI_START_SEARCH_CMDID, vif->mid, NULL, 0,
2346                      WMI_SEARCH_STARTED_EVENTID, &reply, sizeof(reply), 300);
2347        if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
2348                wil_err(wil, "device failed to start search. status %d\n",
2349                        reply.evt.status);
2350                rc = -EINVAL;
2351        }
2352
2353        return rc;
2354}
2355
2356int wmi_stop_discovery(struct wil6210_vif *vif)
2357{
2358        struct wil6210_priv *wil = vif_to_wil(vif);
2359        int rc;
2360
2361        wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
2362
2363        rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0,
2364                      WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
2365
2366        if (rc)
2367                wil_err(wil, "Failed to stop discovery\n");
2368
2369        return rc;
2370}
2371
2372int wmi_del_cipher_key(struct wil6210_vif *vif, u8 key_index,
2373                       const void *mac_addr, int key_usage)
2374{
2375        struct wil6210_priv *wil = vif_to_wil(vif);
2376        struct wmi_delete_cipher_key_cmd cmd = {
2377                .key_index = key_index,
2378        };
2379
2380        if (mac_addr)
2381                memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
2382
2383        return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, vif->mid,
2384                        &cmd, sizeof(cmd));
2385}
2386
2387int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
2388                       const void *mac_addr, int key_len, const void *key,
2389                       int key_usage)
2390{
2391        struct wil6210_priv *wil = vif_to_wil(vif);
2392        struct wmi_add_cipher_key_cmd cmd = {
2393                .key_index = key_index,
2394                .key_usage = key_usage,
2395                .key_len = key_len,
2396        };
2397
2398        if (!key || (key_len > sizeof(cmd.key)))
2399                return -EINVAL;
2400
2401        memcpy(cmd.key, key, key_len);
2402        if (mac_addr)
2403                memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
2404
2405        return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, vif->mid,
2406                        &cmd, sizeof(cmd));
2407}
2408
2409int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie)
2410{
2411        struct wil6210_priv *wil = vif_to_wil(vif);
2412        static const char *const names[] = {
2413                [WMI_FRAME_BEACON]      = "BEACON",
2414                [WMI_FRAME_PROBE_REQ]   = "PROBE_REQ",
2415                [WMI_FRAME_PROBE_RESP]  = "WMI_FRAME_PROBE_RESP",
2416                [WMI_FRAME_ASSOC_REQ]   = "WMI_FRAME_ASSOC_REQ",
2417                [WMI_FRAME_ASSOC_RESP]  = "WMI_FRAME_ASSOC_RESP",
2418        };
2419        int rc;
2420        u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
2421        struct wmi_set_appie_cmd *cmd;
2422
2423        if (len < ie_len) {
2424                rc = -EINVAL;
2425                goto out;
2426        }
2427
2428        cmd = kzalloc(len, GFP_KERNEL);
2429        if (!cmd) {
2430                rc = -ENOMEM;
2431                goto out;
2432        }
2433        if (!ie)
2434                ie_len = 0;
2435
2436        cmd->mgmt_frm_type = type;
2437        /* BUG: FW API define ieLen as u8. Will fix FW */
2438        cmd->ie_len = cpu_to_le16(ie_len);
2439        memcpy(cmd->ie_info, ie, ie_len);
2440        rc = wmi_send(wil, WMI_SET_APPIE_CMDID, vif->mid, cmd, len);
2441        kfree(cmd);
2442out:
2443        if (rc) {
2444                const char *name = type < ARRAY_SIZE(names) ?
2445                                   names[type] : "??";
2446                wil_err(wil, "set_ie(%d %s) failed : %d\n", type, name, rc);
2447        }
2448
2449        return rc;
2450}
2451
2452int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie)
2453{
2454        struct wil6210_priv *wil = vif_to_wil(vif);
2455        u16 len;
2456        struct wmi_update_ft_ies_cmd *cmd;
2457        int rc;
2458
2459        if (!ie)
2460                ie_len = 0;
2461
2462        len = sizeof(struct wmi_update_ft_ies_cmd) + ie_len;
2463        if (len < ie_len) {
2464                wil_err(wil, "wraparound. ie len %d\n", ie_len);
2465                return -EINVAL;
2466        }
2467
2468        cmd = kzalloc(len, GFP_KERNEL);
2469        if (!cmd) {
2470                rc = -ENOMEM;
2471                goto out;
2472        }
2473
2474        cmd->ie_len = cpu_to_le16(ie_len);
2475        memcpy(cmd->ie_info, ie, ie_len);
2476        rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len);
2477        kfree(cmd);
2478
2479out:
2480        if (rc)
2481                wil_err(wil, "update ft ies failed : %d\n", rc);
2482
2483        return rc;
2484}
2485
2486/**
2487 * wmi_rxon - turn radio on/off
2488 * @on:         turn on if true, off otherwise
2489 *
2490 * Only switch radio. Channel should be set separately.
2491 * No timeout for rxon - radio turned on forever unless some other call
2492 * turns it off
2493 */
2494int wmi_rxon(struct wil6210_priv *wil, bool on)
2495{
2496        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2497        int rc;
2498        struct {
2499                struct wmi_cmd_hdr wmi;
2500                struct wmi_listen_started_event evt;
2501        } __packed reply = {
2502                .evt = {.status = WMI_FW_STATUS_FAILURE},
2503        };
2504
2505        wil_info(wil, "(%s)\n", on ? "on" : "off");
2506
2507        if (on) {
2508                rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0,
2509                              WMI_LISTEN_STARTED_EVENTID,
2510                              &reply, sizeof(reply), 100);
2511                if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
2512                        rc = -EINVAL;
2513        } else {
2514                rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0,
2515                              WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
2516        }
2517
2518        return rc;
2519}
2520
2521int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring)
2522{
2523        struct net_device *ndev = wil->main_ndev;
2524        struct wireless_dev *wdev = ndev->ieee80211_ptr;
2525        struct wil6210_vif *vif = ndev_to_vif(ndev);
2526        struct wmi_cfg_rx_chain_cmd cmd = {
2527                .action = WMI_RX_CHAIN_ADD,
2528                .rx_sw_ring = {
2529                        .max_mpdu_size = cpu_to_le16(
2530                                wil_mtu2macbuf(wil->rx_buf_len)),
2531                        .ring_mem_base = cpu_to_le64(vring->pa),
2532                        .ring_size = cpu_to_le16(vring->size),
2533                },
2534                .mid = 0, /* TODO - what is it? */
2535                .decap_trans_type = WMI_DECAP_TYPE_802_3,
2536                .reorder_type = WMI_RX_SW_REORDER,
2537                .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
2538        };
2539        struct {
2540                struct wmi_cmd_hdr wmi;
2541                struct wmi_cfg_rx_chain_done_event evt;
2542        } __packed evt;
2543        int rc;
2544
2545        memset(&evt, 0, sizeof(evt));
2546
2547        if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
2548                struct ieee80211_channel *ch = wil->monitor_chandef.chan;
2549
2550                cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
2551                if (ch)
2552                        cmd.sniffer_cfg.channel = ch->hw_value - 1;
2553                cmd.sniffer_cfg.phy_info_mode =
2554                        cpu_to_le32(WMI_SNIFFER_PHY_INFO_DISABLED);
2555                cmd.sniffer_cfg.phy_support =
2556                        cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
2557                                    ? WMI_SNIFFER_CP : WMI_SNIFFER_BOTH_PHYS);
2558        } else {
2559                /* Initialize offload (in non-sniffer mode).
2560                 * Linux IP stack always calculates IP checksum
2561                 * HW always calculate TCP/UDP checksum
2562                 */
2563                cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
2564        }
2565
2566        if (rx_align_2)
2567                cmd.l2_802_3_offload_ctrl |=
2568                                L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK;
2569
2570        /* typical time for secure PCP is 840ms */
2571        rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, vif->mid, &cmd, sizeof(cmd),
2572                      WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
2573        if (rc)
2574                return rc;
2575
2576        if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
2577                rc = -EINVAL;
2578
2579        vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
2580
2581        wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
2582                     le32_to_cpu(evt.evt.status), vring->hwtail);
2583
2584        return rc;
2585}
2586
2587int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
2588{
2589        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2590        int rc;
2591        struct wmi_temp_sense_cmd cmd = {
2592                .measure_baseband_en = cpu_to_le32(!!t_bb),
2593                .measure_rf_en = cpu_to_le32(!!t_rf),
2594                .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
2595        };
2596        struct {
2597                struct wmi_cmd_hdr wmi;
2598                struct wmi_temp_sense_done_event evt;
2599        } __packed reply;
2600
2601        memset(&reply, 0, sizeof(reply));
2602
2603        rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, vif->mid, &cmd, sizeof(cmd),
2604                      WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
2605        if (rc)
2606                return rc;
2607
2608        if (t_bb)
2609                *t_bb = le32_to_cpu(reply.evt.baseband_t1000);
2610        if (t_rf)
2611                *t_rf = le32_to_cpu(reply.evt.rf_t1000);
2612
2613        return 0;
2614}
2615
2616int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason,
2617                       bool del_sta)
2618{
2619        struct wil6210_priv *wil = vif_to_wil(vif);
2620        int rc;
2621        struct wmi_disconnect_sta_cmd disc_sta_cmd = {
2622                .disconnect_reason = cpu_to_le16(reason),
2623        };
2624        struct wmi_del_sta_cmd del_sta_cmd = {
2625                .disconnect_reason = cpu_to_le16(reason),
2626        };
2627        struct {
2628                struct wmi_cmd_hdr wmi;
2629                struct wmi_disconnect_event evt;
2630        } __packed reply;
2631
2632        wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
2633
2634        memset(&reply, 0, sizeof(reply));
2635        vif->locally_generated_disc = true;
2636        if (del_sta) {
2637                ether_addr_copy(del_sta_cmd.dst_mac, mac);
2638                rc = wmi_call(wil, WMI_DEL_STA_CMDID, vif->mid, &del_sta_cmd,
2639                              sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID,
2640                              &reply, sizeof(reply), 1000);
2641        } else {
2642                ether_addr_copy(disc_sta_cmd.dst_mac, mac);
2643                rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, vif->mid,
2644                              &disc_sta_cmd, sizeof(disc_sta_cmd),
2645                              WMI_DISCONNECT_EVENTID,
2646                              &reply, sizeof(reply), 1000);
2647        }
2648        /* failure to disconnect in reasonable time treated as FW error */
2649        if (rc) {
2650                wil_fw_error_recovery(wil);
2651                return rc;
2652        }
2653        wil->sinfo_gen++;
2654
2655        return 0;
2656}
2657
2658int wmi_addba(struct wil6210_priv *wil, u8 mid,
2659              u8 ringid, u8 size, u16 timeout)
2660{
2661        u8 amsdu = wil->use_enhanced_dma_hw && wil->use_rx_hw_reordering &&
2662                test_bit(WMI_FW_CAPABILITY_AMSDU, wil->fw_capabilities) &&
2663                wil->amsdu_en;
2664        struct wmi_ring_ba_en_cmd cmd = {
2665                .ring_id = ringid,
2666                .agg_max_wsize = size,
2667                .ba_timeout = cpu_to_le16(timeout),
2668                .amsdu = amsdu,
2669        };
2670
2671        wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d amsdu %d)\n",
2672                    ringid, size, timeout, amsdu);
2673
2674        return wmi_send(wil, WMI_RING_BA_EN_CMDID, mid, &cmd, sizeof(cmd));
2675}
2676
2677int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason)
2678{
2679        struct wmi_ring_ba_dis_cmd cmd = {
2680                .ring_id = ringid,
2681                .reason = cpu_to_le16(reason),
2682        };
2683
2684        wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason);
2685
2686        return wmi_send(wil, WMI_RING_BA_DIS_CMDID, mid, &cmd, sizeof(cmd));
2687}
2688
2689int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, u16 reason)
2690{
2691        struct wmi_rcp_delba_cmd cmd = {
2692                .reason = cpu_to_le16(reason),
2693        };
2694
2695        if (cid >= WIL6210_RX_DESC_MAX_CID) {
2696                cmd.cidxtid = CIDXTID_EXTENDED_CID_TID;
2697                cmd.cid = cid;
2698                cmd.tid = tid;
2699        } else {
2700                cmd.cidxtid = mk_cidxtid(cid, tid);
2701        }
2702
2703        wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cid,
2704                    tid, reason);
2705
2706        return wmi_send(wil, WMI_RCP_DELBA_CMDID, mid, &cmd, sizeof(cmd));
2707}
2708
2709int wmi_addba_rx_resp(struct wil6210_priv *wil,
2710                      u8 mid, u8 cid, u8 tid, u8 token,
2711                      u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
2712{
2713        int rc;
2714        struct wmi_rcp_addba_resp_cmd cmd = {
2715                .dialog_token = token,
2716                .status_code = cpu_to_le16(status),
2717                /* bit 0: A-MSDU supported
2718                 * bit 1: policy (should be 0 for us)
2719                 * bits 2..5: TID
2720                 * bits 6..15: buffer size
2721                 */
2722                .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
2723                                            (agg_wsize << 6)),
2724                .ba_timeout = cpu_to_le16(timeout),
2725        };
2726        struct {
2727                struct wmi_cmd_hdr wmi;
2728                struct wmi_rcp_addba_resp_sent_event evt;
2729        } __packed reply = {
2730                .evt = {.status = cpu_to_le16(WMI_FW_STATUS_FAILURE)},
2731        };
2732
2733        if (cid >= WIL6210_RX_DESC_MAX_CID) {
2734                cmd.cidxtid = CIDXTID_EXTENDED_CID_TID;
2735                cmd.cid = cid;
2736                cmd.tid = tid;
2737        } else {
2738                cmd.cidxtid = mk_cidxtid(cid, tid);
2739        }
2740
2741        wil_dbg_wmi(wil,
2742                    "ADDBA response for MID %d CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
2743                    mid, cid, tid, agg_wsize,
2744                    timeout, status, amsdu ? "+" : "-");
2745
2746        rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, mid, &cmd, sizeof(cmd),
2747                      WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
2748                      100);
2749        if (rc)
2750                return rc;
2751
2752        if (reply.evt.status) {
2753                wil_err(wil, "ADDBA response failed with status %d\n",
2754                        le16_to_cpu(reply.evt.status));
2755                rc = -EINVAL;
2756        }
2757
2758        return rc;
2759}
2760
2761int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
2762                           u8 token, u16 status, bool amsdu, u16 agg_wsize,
2763                           u16 timeout)
2764{
2765        int rc;
2766        struct wmi_rcp_addba_resp_edma_cmd cmd = {
2767                .cid = cid,
2768                .tid = tid,
2769                .dialog_token = token,
2770                .status_code = cpu_to_le16(status),
2771                /* bit 0: A-MSDU supported
2772                 * bit 1: policy (should be 0 for us)
2773                 * bits 2..5: TID
2774                 * bits 6..15: buffer size
2775                 */
2776                .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
2777                                            (agg_wsize << 6)),
2778                .ba_timeout = cpu_to_le16(timeout),
2779                /* route all the connections to status ring 0 */
2780                .status_ring_id = WIL_DEFAULT_RX_STATUS_RING_ID,
2781        };
2782        struct {
2783                struct wmi_cmd_hdr wmi;
2784                struct wmi_rcp_addba_resp_sent_event evt;
2785        } __packed reply = {
2786                .evt = {.status = cpu_to_le16(WMI_FW_STATUS_FAILURE)},
2787        };
2788
2789        wil_dbg_wmi(wil,
2790                    "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s, sring_id %d\n",
2791                    cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-",
2792                    WIL_DEFAULT_RX_STATUS_RING_ID);
2793
2794        rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_EDMA_CMDID, mid, &cmd,
2795                      sizeof(cmd), WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply,
2796                      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
2797        if (rc)
2798                return rc;
2799
2800        if (reply.evt.status) {
2801                wil_err(wil, "ADDBA response failed with status %d\n",
2802                        le16_to_cpu(reply.evt.status));
2803                rc = -EINVAL;
2804        }
2805
2806        return rc;
2807}
2808
2809int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
2810                           enum wmi_ps_profile_type ps_profile)
2811{
2812        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2813        int rc;
2814        struct wmi_ps_dev_profile_cfg_cmd cmd = {
2815                .ps_profile = ps_profile,
2816        };
2817        struct {
2818                struct wmi_cmd_hdr wmi;
2819                struct wmi_ps_dev_profile_cfg_event evt;
2820        } __packed reply = {
2821                .evt = {.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR)},
2822        };
2823        u32 status;
2824
2825        wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile);
2826
2827        rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, vif->mid,
2828                      &cmd, sizeof(cmd),
2829                      WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
2830                      100);
2831        if (rc)
2832                return rc;
2833
2834        status = le32_to_cpu(reply.evt.status);
2835
2836        if (status != WMI_PS_CFG_CMD_STATUS_SUCCESS) {
2837                wil_err(wil, "ps dev profile cfg failed with status %d\n",
2838                        status);
2839                rc = -EINVAL;
2840        }
2841
2842        return rc;
2843}
2844
2845int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
2846{
2847        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2848        int rc;
2849        struct wmi_set_mgmt_retry_limit_cmd cmd = {
2850                .mgmt_retry_limit = retry_short,
2851        };
2852        struct {
2853                struct wmi_cmd_hdr wmi;
2854                struct wmi_set_mgmt_retry_limit_event evt;
2855        } __packed reply = {
2856                .evt = {.status = WMI_FW_STATUS_FAILURE},
2857        };
2858
2859        wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short);
2860
2861        if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2862                return -ENOTSUPP;
2863
2864        rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, vif->mid,
2865                      &cmd, sizeof(cmd),
2866                      WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
2867                      100);
2868        if (rc)
2869                return rc;
2870
2871        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
2872                wil_err(wil, "set mgmt retry limit failed with status %d\n",
2873                        reply.evt.status);
2874                rc = -EINVAL;
2875        }
2876
2877        return rc;
2878}
2879
2880int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
2881{
2882        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2883        int rc;
2884        struct {
2885                struct wmi_cmd_hdr wmi;
2886                struct wmi_get_mgmt_retry_limit_event evt;
2887        } __packed reply;
2888
2889        wil_dbg_wmi(wil, "getting mgmt retry short\n");
2890
2891        if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2892                return -ENOTSUPP;
2893
2894        memset(&reply, 0, sizeof(reply));
2895        rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, vif->mid, NULL, 0,
2896                      WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
2897                      100);
2898        if (rc)
2899                return rc;
2900
2901        if (retry_short)
2902                *retry_short = reply.evt.mgmt_retry_limit;
2903
2904        return 0;
2905}
2906
2907int wmi_abort_scan(struct wil6210_vif *vif)
2908{
2909        struct wil6210_priv *wil = vif_to_wil(vif);
2910        int rc;
2911
2912        wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
2913
2914        rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, vif->mid, NULL, 0);
2915        if (rc)
2916                wil_err(wil, "Failed to abort scan (%d)\n", rc);
2917
2918        return rc;
2919}
2920
2921int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid)
2922{
2923        struct wil6210_priv *wil = vif_to_wil(vif);
2924        int rc;
2925        struct wmi_new_sta_cmd cmd = {
2926                .aid = aid,
2927        };
2928
2929        wil_dbg_wmi(wil, "new sta %pM, aid %d\n", mac, aid);
2930
2931        ether_addr_copy(cmd.dst_mac, mac);
2932
2933        rc = wmi_send(wil, WMI_NEW_STA_CMDID, vif->mid, &cmd, sizeof(cmd));
2934        if (rc)
2935                wil_err(wil, "Failed to send new sta (%d)\n", rc);
2936
2937        return rc;
2938}
2939
2940void wmi_event_flush(struct wil6210_priv *wil)
2941{
2942        ulong flags;
2943        struct pending_wmi_event *evt, *t;
2944
2945        wil_dbg_wmi(wil, "event_flush\n");
2946
2947        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2948
2949        list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
2950                list_del(&evt->list);
2951                kfree(evt);
2952        }
2953
2954        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2955}
2956
2957static const char *suspend_status2name(u8 status)
2958{
2959        switch (status) {
2960        case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
2961                return "LINK_NOT_IDLE";
2962        case WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT:
2963                return "DISCONNECT";
2964        case WMI_TRAFFIC_SUSPEND_REJECTED_OTHER:
2965                return "OTHER";
2966        default:
2967                return "Untracked status";
2968        }
2969}
2970
2971int wmi_suspend(struct wil6210_priv *wil)
2972{
2973        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
2974        int rc;
2975        struct wmi_traffic_suspend_cmd cmd = {
2976                .wakeup_trigger = wil->wakeup_trigger,
2977        };
2978        struct {
2979                struct wmi_cmd_hdr wmi;
2980                struct wmi_traffic_suspend_event evt;
2981        } __packed reply = {
2982                .evt = {.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE},
2983        };
2984
2985        u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP;
2986
2987        wil->suspend_resp_rcvd = false;
2988        wil->suspend_resp_comp = false;
2989
2990        rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, vif->mid,
2991                      &cmd, sizeof(cmd),
2992                      WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply),
2993                      suspend_to);
2994        if (rc) {
2995                wil_err(wil, "wmi_call for suspend req failed, rc=%d\n", rc);
2996                if (rc == -ETIME)
2997                        /* wmi_call TO */
2998                        wil->suspend_stats.rejected_by_device++;
2999                else
3000                        wil->suspend_stats.rejected_by_host++;
3001                goto out;
3002        }
3003
3004        wil_dbg_wmi(wil, "waiting for suspend_response_completed\n");
3005
3006        rc = wait_event_interruptible_timeout(wil->wq,
3007                                              wil->suspend_resp_comp,
3008                                              msecs_to_jiffies(suspend_to));
3009        if (rc == 0) {
3010                wil_err(wil, "TO waiting for suspend_response_completed\n");
3011                if (wil->suspend_resp_rcvd)
3012                        /* Device responded but we TO due to another reason */
3013                        wil->suspend_stats.rejected_by_host++;
3014                else
3015                        wil->suspend_stats.rejected_by_device++;
3016                rc = -EBUSY;
3017                goto out;
3018        }
3019
3020        wil_dbg_wmi(wil, "suspend_response_completed rcvd\n");
3021        if (reply.evt.status != WMI_TRAFFIC_SUSPEND_APPROVED) {
3022                wil_dbg_pm(wil, "device rejected the suspend, %s\n",
3023                           suspend_status2name(reply.evt.status));
3024                wil->suspend_stats.rejected_by_device++;
3025        }
3026        rc = reply.evt.status;
3027
3028out:
3029        wil->suspend_resp_rcvd = false;
3030        wil->suspend_resp_comp = false;
3031
3032        return rc;
3033}
3034
3035static void resume_triggers2string(u32 triggers, char *string, int str_size)
3036{
3037        string[0] = '\0';
3038
3039        if (!triggers) {
3040                strlcat(string, " UNKNOWN", str_size);
3041                return;
3042        }
3043
3044        if (triggers & WMI_RESUME_TRIGGER_HOST)
3045                strlcat(string, " HOST", str_size);
3046
3047        if (triggers & WMI_RESUME_TRIGGER_UCAST_RX)
3048                strlcat(string, " UCAST_RX", str_size);
3049
3050        if (triggers & WMI_RESUME_TRIGGER_BCAST_RX)
3051                strlcat(string, " BCAST_RX", str_size);
3052
3053        if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
3054                strlcat(string, " WMI_EVT", str_size);
3055
3056        if (triggers & WMI_RESUME_TRIGGER_DISCONNECT)
3057                strlcat(string, " DISCONNECT", str_size);
3058}
3059
3060int wmi_resume(struct wil6210_priv *wil)
3061{
3062        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
3063        int rc;
3064        char string[100];
3065        struct {
3066                struct wmi_cmd_hdr wmi;
3067                struct wmi_traffic_resume_event evt;
3068        } __packed reply = {
3069                .evt = {.status = WMI_TRAFFIC_RESUME_FAILED,
3070                        .resume_triggers =
3071                                cpu_to_le32(WMI_RESUME_TRIGGER_UNKNOWN)},
3072        };
3073
3074        rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, vif->mid, NULL, 0,
3075                      WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply),
3076                      WIL_WAIT_FOR_SUSPEND_RESUME_COMP);
3077        if (rc)
3078                return rc;
3079        resume_triggers2string(le32_to_cpu(reply.evt.resume_triggers), string,
3080                               sizeof(string));
3081        wil_dbg_pm(wil, "device resume %s, resume triggers:%s (0x%x)\n",
3082                   reply.evt.status ? "failed" : "passed", string,
3083                   le32_to_cpu(reply.evt.resume_triggers));
3084
3085        return reply.evt.status;
3086}
3087
3088int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
3089                      const u8 *mac, enum nl80211_iftype iftype)
3090{
3091        int rc;
3092        struct wmi_port_allocate_cmd cmd = {
3093                .mid = mid,
3094        };
3095        struct {
3096                struct wmi_cmd_hdr wmi;
3097                struct wmi_port_allocated_event evt;
3098        } __packed reply = {
3099                .evt = {.status = WMI_FW_STATUS_FAILURE},
3100        };
3101
3102        wil_dbg_misc(wil, "port allocate, mid %d iftype %d, mac %pM\n",
3103                     mid, iftype, mac);
3104
3105        ether_addr_copy(cmd.mac, mac);
3106        switch (iftype) {
3107        case NL80211_IFTYPE_STATION:
3108                cmd.port_role = WMI_PORT_STA;
3109                break;
3110        case NL80211_IFTYPE_AP:
3111                cmd.port_role = WMI_PORT_AP;
3112                break;
3113        case NL80211_IFTYPE_P2P_CLIENT:
3114                cmd.port_role = WMI_PORT_P2P_CLIENT;
3115                break;
3116        case NL80211_IFTYPE_P2P_GO:
3117                cmd.port_role = WMI_PORT_P2P_GO;
3118                break;
3119        /* what about monitor??? */
3120        default:
3121                wil_err(wil, "unsupported iftype: %d\n", iftype);
3122                return -EINVAL;
3123        }
3124
3125        rc = wmi_call(wil, WMI_PORT_ALLOCATE_CMDID, mid,
3126                      &cmd, sizeof(cmd),
3127                      WMI_PORT_ALLOCATED_EVENTID, &reply,
3128                      sizeof(reply), 300);
3129        if (rc) {
3130                wil_err(wil, "failed to allocate port, status %d\n", rc);
3131                return rc;
3132        }
3133        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3134                wil_err(wil, "WMI_PORT_ALLOCATE returned status %d\n",
3135                        reply.evt.status);
3136                return -EINVAL;
3137        }
3138
3139        return 0;
3140}
3141
3142int wmi_port_delete(struct wil6210_priv *wil, u8 mid)
3143{
3144        int rc;
3145        struct wmi_port_delete_cmd cmd = {
3146                .mid = mid,
3147        };
3148        struct {
3149                struct wmi_cmd_hdr wmi;
3150                struct wmi_port_deleted_event evt;
3151        } __packed reply = {
3152                .evt = {.status = WMI_FW_STATUS_FAILURE},
3153        };
3154
3155        wil_dbg_misc(wil, "port delete, mid %d\n", mid);
3156
3157        rc = wmi_call(wil, WMI_PORT_DELETE_CMDID, mid,
3158                      &cmd, sizeof(cmd),
3159                      WMI_PORT_DELETED_EVENTID, &reply,
3160                      sizeof(reply), 2000);
3161        if (rc) {
3162                wil_err(wil, "failed to delete port, status %d\n", rc);
3163                return rc;
3164        }
3165        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3166                wil_err(wil, "WMI_PORT_DELETE returned status %d\n",
3167                        reply.evt.status);
3168                return -EINVAL;
3169        }
3170
3171        return 0;
3172}
3173
3174static bool wmi_evt_call_handler(struct wil6210_vif *vif, int id,
3175                                 void *d, int len)
3176{
3177        uint i;
3178
3179        for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
3180                if (wmi_evt_handlers[i].eventid == id) {
3181                        wmi_evt_handlers[i].handler(vif, id, d, len);
3182                        return true;
3183                }
3184        }
3185
3186        return false;
3187}
3188
3189static void wmi_event_handle(struct wil6210_priv *wil,
3190                             struct wil6210_mbox_hdr *hdr)
3191{
3192        u16 len = le16_to_cpu(hdr->len);
3193        struct wil6210_vif *vif;
3194
3195        if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
3196            (len >= sizeof(struct wmi_cmd_hdr))) {
3197                struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]);
3198                void *evt_data = (void *)(&wmi[1]);
3199                u16 id = le16_to_cpu(wmi->command_id);
3200                u8 mid = wmi->mid;
3201
3202                wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x,%d)\n",
3203                            eventid2name(id), id, wil->reply_id,
3204                            wil->reply_mid);
3205
3206                if (mid == MID_BROADCAST)
3207                        mid = 0;
3208                if (mid >= GET_MAX_VIFS(wil)) {
3209                        wil_dbg_wmi(wil, "invalid mid %d, event skipped\n",
3210                                    mid);
3211                        return;
3212                }
3213                vif = wil->vifs[mid];
3214                if (!vif) {
3215                        wil_dbg_wmi(wil, "event for empty VIF(%d), skipped\n",
3216                                    mid);
3217                        return;
3218                }
3219
3220                /* check if someone waits for this event */
3221                if (wil->reply_id && wil->reply_id == id &&
3222                    wil->reply_mid == mid) {
3223                        WARN_ON(wil->reply_buf);
3224
3225                        wmi_evt_call_handler(vif, id, evt_data,
3226                                             len - sizeof(*wmi));
3227                        wil_dbg_wmi(wil, "event_handle: Complete WMI 0x%04x\n",
3228                                    id);
3229                        complete(&wil->wmi_call);
3230                        return;
3231                }
3232                /* unsolicited event */
3233                /* search for handler */
3234                if (!wmi_evt_call_handler(vif, id, evt_data,
3235                                          len - sizeof(*wmi))) {
3236                        wil_info(wil, "Unhandled event 0x%04x\n", id);
3237                }
3238        } else {
3239                wil_err(wil, "Unknown event type\n");
3240                print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
3241                               hdr, sizeof(*hdr) + len, true);
3242        }
3243}
3244
3245/*
3246 * Retrieve next WMI event from the pending list
3247 */
3248static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
3249{
3250        ulong flags;
3251        struct list_head *ret = NULL;
3252
3253        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
3254
3255        if (!list_empty(&wil->pending_wmi_ev)) {
3256                ret = wil->pending_wmi_ev.next;
3257                list_del(ret);
3258        }
3259
3260        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
3261
3262        return ret;
3263}
3264
3265/*
3266 * Handler for the WMI events
3267 */
3268void wmi_event_worker(struct work_struct *work)
3269{
3270        struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
3271                                                 wmi_event_worker);
3272        struct pending_wmi_event *evt;
3273        struct list_head *lh;
3274
3275        wil_dbg_wmi(wil, "event_worker: Start\n");
3276        while ((lh = next_wmi_ev(wil)) != NULL) {
3277                evt = list_entry(lh, struct pending_wmi_event, list);
3278                wmi_event_handle(wil, &evt->event.hdr);
3279                kfree(evt);
3280        }
3281        wil_dbg_wmi(wil, "event_worker: Finished\n");
3282}
3283
3284bool wil_is_wmi_idle(struct wil6210_priv *wil)
3285{
3286        ulong flags;
3287        struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
3288        bool rc = false;
3289
3290        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
3291
3292        /* Check if there are pending WMI events in the events queue */
3293        if (!list_empty(&wil->pending_wmi_ev)) {
3294                wil_dbg_pm(wil, "Pending WMI events in queue\n");
3295                goto out;
3296        }
3297
3298        /* Check if there is a pending WMI call */
3299        if (wil->reply_id) {
3300                wil_dbg_pm(wil, "Pending WMI call\n");
3301                goto out;
3302        }
3303
3304        /* Check if there are pending RX events in mbox */
3305        r->head = wil_r(wil, RGF_MBOX +
3306                        offsetof(struct wil6210_mbox_ctl, rx.head));
3307        if (r->tail != r->head)
3308                wil_dbg_pm(wil, "Pending WMI mbox events\n");
3309        else
3310                rc = true;
3311
3312out:
3313        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
3314        return rc;
3315}
3316
3317static void
3318wmi_sched_scan_set_ssids(struct wil6210_priv *wil,
3319                         struct wmi_start_sched_scan_cmd *cmd,
3320                         struct cfg80211_ssid *ssids, int n_ssids,
3321                         struct cfg80211_match_set *match_sets,
3322                         int n_match_sets)
3323{
3324        int i;
3325
3326        if (n_match_sets > WMI_MAX_PNO_SSID_NUM) {
3327                wil_dbg_wmi(wil, "too many match sets (%d), use first %d\n",
3328                            n_match_sets, WMI_MAX_PNO_SSID_NUM);
3329                n_match_sets = WMI_MAX_PNO_SSID_NUM;
3330        }
3331        cmd->num_of_ssids = n_match_sets;
3332
3333        for (i = 0; i < n_match_sets; i++) {
3334                struct wmi_sched_scan_ssid_match *wmi_match =
3335                        &cmd->ssid_for_match[i];
3336                struct cfg80211_match_set *cfg_match = &match_sets[i];
3337                int j;
3338
3339                wmi_match->ssid_len = cfg_match->ssid.ssid_len;
3340                memcpy(wmi_match->ssid, cfg_match->ssid.ssid,
3341                       min_t(u8, wmi_match->ssid_len, WMI_MAX_SSID_LEN));
3342                wmi_match->rssi_threshold = S8_MIN;
3343                if (cfg_match->rssi_thold >= S8_MIN &&
3344                    cfg_match->rssi_thold <= S8_MAX)
3345                        wmi_match->rssi_threshold = cfg_match->rssi_thold;
3346
3347                for (j = 0; j < n_ssids; j++)
3348                        if (wmi_match->ssid_len == ssids[j].ssid_len &&
3349                            memcmp(wmi_match->ssid, ssids[j].ssid,
3350                                   wmi_match->ssid_len) == 0)
3351                                wmi_match->add_ssid_to_probe = true;
3352        }
3353}
3354
3355static void
3356wmi_sched_scan_set_channels(struct wil6210_priv *wil,
3357                            struct wmi_start_sched_scan_cmd *cmd,
3358                            u32 n_channels,
3359                            struct ieee80211_channel **channels)
3360{
3361        int i;
3362
3363        if (n_channels > WMI_MAX_CHANNEL_NUM) {
3364                wil_dbg_wmi(wil, "too many channels (%d), use first %d\n",
3365                            n_channels, WMI_MAX_CHANNEL_NUM);
3366                n_channels = WMI_MAX_CHANNEL_NUM;
3367        }
3368        cmd->num_of_channels = n_channels;
3369
3370        for (i = 0; i < n_channels; i++) {
3371                struct ieee80211_channel *cfg_chan = channels[i];
3372
3373                cmd->channel_list[i] = cfg_chan->hw_value - 1;
3374        }
3375}
3376
3377static void
3378wmi_sched_scan_set_plans(struct wil6210_priv *wil,
3379                         struct wmi_start_sched_scan_cmd *cmd,
3380                         struct cfg80211_sched_scan_plan *scan_plans,
3381                         int n_scan_plans)
3382{
3383        int i;
3384
3385        if (n_scan_plans > WMI_MAX_PLANS_NUM) {
3386                wil_dbg_wmi(wil, "too many plans (%d), use first %d\n",
3387                            n_scan_plans, WMI_MAX_PLANS_NUM);
3388                n_scan_plans = WMI_MAX_PLANS_NUM;
3389        }
3390
3391        for (i = 0; i < n_scan_plans; i++) {
3392                struct cfg80211_sched_scan_plan *cfg_plan = &scan_plans[i];
3393
3394                cmd->scan_plans[i].interval_sec =
3395                        cpu_to_le16(cfg_plan->interval);
3396                cmd->scan_plans[i].num_of_iterations =
3397                        cpu_to_le16(cfg_plan->iterations);
3398        }
3399}
3400
3401int wmi_start_sched_scan(struct wil6210_priv *wil,
3402                         struct cfg80211_sched_scan_request *request)
3403{
3404        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
3405        int rc;
3406        struct wmi_start_sched_scan_cmd cmd = {
3407                .min_rssi_threshold = S8_MIN,
3408                .initial_delay_sec = cpu_to_le16(request->delay),
3409        };
3410        struct {
3411                struct wmi_cmd_hdr wmi;
3412                struct wmi_start_sched_scan_event evt;
3413        } __packed reply = {
3414                .evt = {.result = WMI_PNO_REJECT},
3415        };
3416
3417        if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
3418                return -ENOTSUPP;
3419
3420        if (request->min_rssi_thold >= S8_MIN &&
3421            request->min_rssi_thold <= S8_MAX)
3422                cmd.min_rssi_threshold = request->min_rssi_thold;
3423
3424        wmi_sched_scan_set_ssids(wil, &cmd, request->ssids, request->n_ssids,
3425                                 request->match_sets, request->n_match_sets);
3426        wmi_sched_scan_set_channels(wil, &cmd,
3427                                    request->n_channels, request->channels);
3428        wmi_sched_scan_set_plans(wil, &cmd,
3429                                 request->scan_plans, request->n_scan_plans);
3430
3431        rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, vif->mid,
3432                      &cmd, sizeof(cmd),
3433                      WMI_START_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
3434                      WIL_WMI_CALL_GENERAL_TO_MS);
3435        if (rc)
3436                return rc;
3437
3438        if (reply.evt.result != WMI_PNO_SUCCESS) {
3439                wil_err(wil, "start sched scan failed, result %d\n",
3440                        reply.evt.result);
3441                return -EINVAL;
3442        }
3443
3444        return 0;
3445}
3446
3447int wmi_stop_sched_scan(struct wil6210_priv *wil)
3448{
3449        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
3450        int rc;
3451        struct {
3452                struct wmi_cmd_hdr wmi;
3453                struct wmi_stop_sched_scan_event evt;
3454        } __packed reply = {
3455                .evt = {.result = WMI_PNO_REJECT},
3456        };
3457
3458        if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
3459                return -ENOTSUPP;
3460
3461        rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, vif->mid, NULL, 0,
3462                      WMI_STOP_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
3463                      WIL_WMI_CALL_GENERAL_TO_MS);
3464        if (rc)
3465                return rc;
3466
3467        if (reply.evt.result != WMI_PNO_SUCCESS) {
3468                wil_err(wil, "stop sched scan failed, result %d\n",
3469                        reply.evt.result);
3470                return -EINVAL;
3471        }
3472
3473        return 0;
3474}
3475
3476int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len)
3477{
3478        size_t total;
3479        struct wil6210_priv *wil = vif_to_wil(vif);
3480        struct ieee80211_mgmt *mgmt_frame = (void *)buf;
3481        struct wmi_sw_tx_req_cmd *cmd;
3482        struct {
3483                struct wmi_cmd_hdr wmi;
3484                struct wmi_sw_tx_complete_event evt;
3485        } __packed evt = {
3486                .evt = {.status = WMI_FW_STATUS_FAILURE},
3487        };
3488        int rc;
3489
3490        wil_dbg_misc(wil, "mgmt_tx mid %d\n", vif->mid);
3491        wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
3492                          len, true);
3493
3494        if (len < sizeof(struct ieee80211_hdr_3addr))
3495                return -EINVAL;
3496
3497        total = sizeof(*cmd) + len;
3498        if (total < len) {
3499                wil_err(wil, "mgmt_tx invalid len %zu\n", len);
3500                return -EINVAL;
3501        }
3502
3503        cmd = kmalloc(total, GFP_KERNEL);
3504        if (!cmd)
3505                return -ENOMEM;
3506
3507        memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
3508        cmd->len = cpu_to_le16(len);
3509        memcpy(cmd->payload, buf, len);
3510
3511        rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total,
3512                      WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
3513        if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
3514                wil_dbg_wmi(wil, "mgmt_tx failed with status %d\n",
3515                            evt.evt.status);
3516                rc = -EAGAIN;
3517        }
3518
3519        kfree(cmd);
3520
3521        return rc;
3522}
3523
3524int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
3525                    u8 channel, u16 duration_ms)
3526{
3527        size_t total;
3528        struct wil6210_priv *wil = vif_to_wil(vif);
3529        struct ieee80211_mgmt *mgmt_frame = (void *)buf;
3530        struct wmi_sw_tx_req_ext_cmd *cmd;
3531        struct {
3532                struct wmi_cmd_hdr wmi;
3533                struct wmi_sw_tx_complete_event evt;
3534        } __packed evt = {
3535                .evt = {.status = WMI_FW_STATUS_FAILURE},
3536        };
3537        int rc;
3538
3539        wil_dbg_wmi(wil, "mgmt_tx_ext mid %d channel %d duration %d\n",
3540                    vif->mid, channel, duration_ms);
3541        wil_hex_dump_wmi("mgmt_tx_ext frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
3542                         len, true);
3543
3544        if (len < sizeof(struct ieee80211_hdr_3addr)) {
3545                wil_err(wil, "short frame. len %zu\n", len);
3546                return -EINVAL;
3547        }
3548
3549        total = sizeof(*cmd) + len;
3550        if (total < len) {
3551                wil_err(wil, "mgmt_tx_ext invalid len %zu\n", len);
3552                return -EINVAL;
3553        }
3554
3555        cmd = kzalloc(total, GFP_KERNEL);
3556        if (!cmd)
3557                return -ENOMEM;
3558
3559        memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
3560        cmd->len = cpu_to_le16(len);
3561        memcpy(cmd->payload, buf, len);
3562        cmd->channel = channel - 1;
3563        cmd->duration_ms = cpu_to_le16(duration_ms);
3564
3565        rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total,
3566                      WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
3567        if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
3568                wil_dbg_wmi(wil, "mgmt_tx_ext failed with status %d\n",
3569                            evt.evt.status);
3570                rc = -EAGAIN;
3571        }
3572
3573        kfree(cmd);
3574
3575        return rc;
3576}
3577
3578int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
3579{
3580        int rc;
3581        struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
3582        struct wil_status_ring *sring = &wil->srings[ring_id];
3583        struct wmi_tx_status_ring_add_cmd cmd = {
3584                .ring_cfg = {
3585                        .ring_size = cpu_to_le16(sring->size),
3586                },
3587                .irq_index = WIL_TX_STATUS_IRQ_IDX
3588        };
3589        struct {
3590                struct wmi_cmd_hdr hdr;
3591                struct wmi_tx_status_ring_cfg_done_event evt;
3592        } __packed reply = {
3593                .evt = {.status = WMI_FW_STATUS_FAILURE},
3594        };
3595
3596        cmd.ring_cfg.ring_id = ring_id;
3597
3598        cmd.ring_cfg.ring_mem_base = cpu_to_le64(sring->pa);
3599        rc = wmi_call(wil, WMI_TX_STATUS_RING_ADD_CMDID, vif->mid, &cmd,
3600                      sizeof(cmd), WMI_TX_STATUS_RING_CFG_DONE_EVENTID,
3601                      &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
3602        if (rc) {
3603                wil_err(wil, "TX_STATUS_RING_ADD_CMD failed, rc %d\n", rc);
3604                return rc;
3605        }
3606
3607        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3608                wil_err(wil, "TX_STATUS_RING_ADD_CMD failed, status %d\n",
3609                        reply.evt.status);
3610                return -EINVAL;
3611        }
3612
3613        sring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr);
3614
3615        return 0;
3616}
3617
3618int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, u16 max_rx_pl_per_desc)
3619{
3620        struct net_device *ndev = wil->main_ndev;
3621        struct wil6210_vif *vif = ndev_to_vif(ndev);
3622        int rc;
3623        struct wmi_cfg_def_rx_offload_cmd cmd = {
3624                .max_msdu_size = cpu_to_le16(wil_mtu2macbuf(WIL_MAX_ETH_MTU)),
3625                .max_rx_pl_per_desc = cpu_to_le16(max_rx_pl_per_desc),
3626                .decap_trans_type = WMI_DECAP_TYPE_802_3,
3627                .l2_802_3_offload_ctrl = 0,
3628                .l3_l4_ctrl = 1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS,
3629        };
3630        struct {
3631                struct wmi_cmd_hdr hdr;
3632                struct wmi_cfg_def_rx_offload_done_event evt;
3633        } __packed reply = {
3634                .evt = {.status = WMI_FW_STATUS_FAILURE},
3635        };
3636
3637        rc = wmi_call(wil, WMI_CFG_DEF_RX_OFFLOAD_CMDID, vif->mid, &cmd,
3638                      sizeof(cmd), WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID, &reply,
3639                      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
3640        if (rc) {
3641                wil_err(wil, "WMI_CFG_DEF_RX_OFFLOAD_CMD failed, rc %d\n", rc);
3642                return rc;
3643        }
3644
3645        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3646                wil_err(wil, "WMI_CFG_DEF_RX_OFFLOAD_CMD failed, status %d\n",
3647                        reply.evt.status);
3648                return -EINVAL;
3649        }
3650
3651        return 0;
3652}
3653
3654int wil_wmi_rx_sring_add(struct wil6210_priv *wil, u16 ring_id)
3655{
3656        struct net_device *ndev = wil->main_ndev;
3657        struct wil6210_vif *vif = ndev_to_vif(ndev);
3658        struct wil_status_ring *sring = &wil->srings[ring_id];
3659        int rc;
3660        struct wmi_rx_status_ring_add_cmd cmd = {
3661                .ring_cfg = {
3662                        .ring_size = cpu_to_le16(sring->size),
3663                        .ring_id = ring_id,
3664                },
3665                .rx_msg_type = wil->use_compressed_rx_status ?
3666                        WMI_RX_MSG_TYPE_COMPRESSED :
3667                        WMI_RX_MSG_TYPE_EXTENDED,
3668                .irq_index = WIL_RX_STATUS_IRQ_IDX,
3669        };
3670        struct {
3671                struct wmi_cmd_hdr hdr;
3672                struct wmi_rx_status_ring_cfg_done_event evt;
3673        } __packed reply = {
3674                .evt = {.status = WMI_FW_STATUS_FAILURE},
3675        };
3676
3677        cmd.ring_cfg.ring_mem_base = cpu_to_le64(sring->pa);
3678        rc = wmi_call(wil, WMI_RX_STATUS_RING_ADD_CMDID, vif->mid, &cmd,
3679                      sizeof(cmd), WMI_RX_STATUS_RING_CFG_DONE_EVENTID, &reply,
3680                      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
3681        if (rc) {
3682                wil_err(wil, "RX_STATUS_RING_ADD_CMD failed, rc %d\n", rc);
3683                return rc;
3684        }
3685
3686        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3687                wil_err(wil, "RX_STATUS_RING_ADD_CMD failed, status %d\n",
3688                        reply.evt.status);
3689                return -EINVAL;
3690        }
3691
3692        sring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr);
3693
3694        return 0;
3695}
3696
3697int wil_wmi_rx_desc_ring_add(struct wil6210_priv *wil, int status_ring_id)
3698{
3699        struct net_device *ndev = wil->main_ndev;
3700        struct wil6210_vif *vif = ndev_to_vif(ndev);
3701        struct wil_ring *ring = &wil->ring_rx;
3702        int rc;
3703        struct wmi_rx_desc_ring_add_cmd cmd = {
3704                .ring_cfg = {
3705                        .ring_size = cpu_to_le16(ring->size),
3706                        .ring_id = WIL_RX_DESC_RING_ID,
3707                },
3708                .status_ring_id = status_ring_id,
3709                .irq_index = WIL_RX_STATUS_IRQ_IDX,
3710        };
3711        struct {
3712                struct wmi_cmd_hdr hdr;
3713                struct wmi_rx_desc_ring_cfg_done_event evt;
3714        } __packed reply = {
3715                .evt = {.status = WMI_FW_STATUS_FAILURE},
3716        };
3717
3718        cmd.ring_cfg.ring_mem_base = cpu_to_le64(ring->pa);
3719        cmd.sw_tail_host_addr = cpu_to_le64(ring->edma_rx_swtail.pa);
3720        rc = wmi_call(wil, WMI_RX_DESC_RING_ADD_CMDID, vif->mid, &cmd,
3721                      sizeof(cmd), WMI_RX_DESC_RING_CFG_DONE_EVENTID, &reply,
3722                      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
3723        if (rc) {
3724                wil_err(wil, "WMI_RX_DESC_RING_ADD_CMD failed, rc %d\n", rc);
3725                return rc;
3726        }
3727
3728        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3729                wil_err(wil, "WMI_RX_DESC_RING_ADD_CMD failed, status %d\n",
3730                        reply.evt.status);
3731                return -EINVAL;
3732        }
3733
3734        ring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr);
3735
3736        return 0;
3737}
3738
3739int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
3740                             int tid)
3741{
3742        struct wil6210_priv *wil = vif_to_wil(vif);
3743        int sring_id = wil->tx_sring_idx; /* there is only one TX sring */
3744        int rc;
3745        struct wil_ring *ring = &wil->ring_tx[ring_id];
3746        struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
3747        struct wmi_tx_desc_ring_add_cmd cmd = {
3748                .ring_cfg = {
3749                        .ring_size = cpu_to_le16(ring->size),
3750                        .ring_id = ring_id,
3751                },
3752                .status_ring_id = sring_id,
3753                .cid = cid,
3754                .tid = tid,
3755                .encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
3756                .max_msdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
3757                .schd_params = {
3758                        .priority = cpu_to_le16(0),
3759                        .timeslot_us = cpu_to_le16(0xfff),
3760                }
3761        };
3762        struct {
3763                struct wmi_cmd_hdr hdr;
3764                struct wmi_tx_desc_ring_cfg_done_event evt;
3765        } __packed reply = {
3766                .evt = {.status = WMI_FW_STATUS_FAILURE},
3767        };
3768
3769        cmd.ring_cfg.ring_mem_base = cpu_to_le64(ring->pa);
3770        rc = wmi_call(wil, WMI_TX_DESC_RING_ADD_CMDID, vif->mid, &cmd,
3771                      sizeof(cmd), WMI_TX_DESC_RING_CFG_DONE_EVENTID, &reply,
3772                      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
3773        if (rc) {
3774                wil_err(wil, "WMI_TX_DESC_RING_ADD_CMD failed, rc %d\n", rc);
3775                return rc;
3776        }
3777
3778        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3779                wil_err(wil, "WMI_TX_DESC_RING_ADD_CMD failed, status %d\n",
3780                        reply.evt.status);
3781                return -EINVAL;
3782        }
3783
3784        spin_lock_bh(&txdata->lock);
3785        ring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr);
3786        txdata->mid = vif->mid;
3787        txdata->enabled = 1;
3788        spin_unlock_bh(&txdata->lock);
3789
3790        return 0;
3791}
3792
3793int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id)
3794{
3795        struct wil6210_priv *wil = vif_to_wil(vif);
3796        struct wil_ring *ring = &wil->ring_tx[ring_id];
3797        int rc;
3798        struct wmi_bcast_desc_ring_add_cmd cmd = {
3799                .ring_cfg = {
3800                        .ring_size = cpu_to_le16(ring->size),
3801                        .ring_id = ring_id,
3802                },
3803                .status_ring_id = wil->tx_sring_idx,
3804                .encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
3805        };
3806        struct {
3807                struct wmi_cmd_hdr hdr;
3808                struct wmi_rx_desc_ring_cfg_done_event evt;
3809        } __packed reply = {
3810                .evt = {.status = WMI_FW_STATUS_FAILURE},
3811        };
3812        struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
3813
3814        cmd.ring_cfg.ring_mem_base = cpu_to_le64(ring->pa);
3815        rc = wmi_call(wil, WMI_BCAST_DESC_RING_ADD_CMDID, vif->mid, &cmd,
3816                      sizeof(cmd), WMI_TX_DESC_RING_CFG_DONE_EVENTID, &reply,
3817                      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
3818        if (rc) {
3819                wil_err(wil, "WMI_BCAST_DESC_RING_ADD_CMD failed, rc %d\n", rc);
3820                return rc;
3821        }
3822
3823        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3824                wil_err(wil, "Broadcast Tx config failed, status %d\n",
3825                        reply.evt.status);
3826                return -EINVAL;
3827        }
3828
3829        spin_lock_bh(&txdata->lock);
3830        ring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr);
3831        txdata->mid = vif->mid;
3832        txdata->enabled = 1;
3833        spin_unlock_bh(&txdata->lock);
3834
3835        return 0;
3836}
3837
3838int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval)
3839{
3840        struct wil6210_priv *wil = vif_to_wil(vif);
3841        struct wmi_link_stats_cmd cmd = {
3842                .record_type_mask = cpu_to_le32(type),
3843                .cid = cid,
3844                .action = WMI_LINK_STATS_SNAPSHOT,
3845                .interval_msec = cpu_to_le32(interval),
3846        };
3847        struct {
3848                struct wmi_cmd_hdr wmi;
3849                struct wmi_link_stats_config_done_event evt;
3850        } __packed reply = {
3851                .evt = {.status = WMI_FW_STATUS_FAILURE},
3852        };
3853        int rc;
3854
3855        rc = wmi_call(wil, WMI_LINK_STATS_CMDID, vif->mid, &cmd, sizeof(cmd),
3856                      WMI_LINK_STATS_CONFIG_DONE_EVENTID, &reply,
3857                      sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
3858        if (rc) {
3859                wil_err(wil, "WMI_LINK_STATS_CMDID failed, rc %d\n", rc);
3860                return rc;
3861        }
3862
3863        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
3864                wil_err(wil, "Link statistics config failed, status %d\n",
3865                        reply.evt.status);
3866                return -EINVAL;
3867        }
3868
3869        return 0;
3870}
3871