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