linux/drivers/net/wireless/ath/wil6210/wmi.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
   3 * Copyright (c) 2018, 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
  27static uint max_assoc_sta = WIL6210_MAX_CID;
  28module_param(max_assoc_sta, uint, 0644);
  29MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
  30
  31int agg_wsize; /* = 0; */
  32module_param(agg_wsize, int, 0644);
  33MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
  34                 " 0 - use default; < 0 - don't auto-establish");
  35
  36u8 led_id = WIL_LED_INVALID_ID;
  37module_param(led_id, byte, 0444);
  38MODULE_PARM_DESC(led_id,
  39                 " 60G device led enablement. Set the led ID (0-2) to enable");
  40
  41#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
  42#define WIL_WMI_CALL_GENERAL_TO_MS 100
  43
  44/**
  45 * WMI event receiving - theory of operations
  46 *
  47 * When firmware about to report WMI event, it fills memory area
  48 * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
  49 * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
  50 *
  51 * @wmi_recv_cmd reads event, allocates memory chunk  and attaches it to the
  52 * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up
  53 * and handles events within the @wmi_event_worker. Every event get detached
  54 * from list, processed and deleted.
  55 *
  56 * Purpose for this mechanism is to release IRQ thread; otherwise,
  57 * if WMI event handling involves another WMI command flow, this 2-nd flow
  58 * won't be completed because of blocked IRQ thread.
  59 */
  60
  61/**
  62 * Addressing - theory of operations
  63 *
  64 * There are several buses present on the WIL6210 card.
  65 * Same memory areas are visible at different address on
  66 * the different busses. There are 3 main bus masters:
  67 *  - MAC CPU (ucode)
  68 *  - User CPU (firmware)
  69 *  - AHB (host)
  70 *
  71 * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
  72 * AHB addresses starting from 0x880000
  73 *
  74 * Internally, firmware uses addresses that allow faster access but
  75 * are invisible from the host. To read from these addresses, alternative
  76 * AHB address must be used.
  77 */
  78
  79/**
  80 * @sparrow_fw_mapping provides memory remapping table for sparrow
  81 *
  82 * array size should be in sync with the declaration in the wil6210.h
  83 *
  84 * Sparrow memory mapping:
  85 * Linker address         PCI/Host address
  86 *                        0x880000 .. 0xa80000  2Mb BAR0
  87 * 0x800000 .. 0x808000   0x900000 .. 0x908000  32k DCCM
  88 * 0x840000 .. 0x860000   0x908000 .. 0x928000  128k PERIPH
  89 */
  90const struct fw_map sparrow_fw_mapping[] = {
  91        /* FW code RAM 256k */
  92        {0x000000, 0x040000, 0x8c0000, "fw_code", true},
  93        /* FW data RAM 32k */
  94        {0x800000, 0x808000, 0x900000, "fw_data", true},
  95        /* periph data 128k */
  96        {0x840000, 0x860000, 0x908000, "fw_peri", true},
  97        /* various RGF 40k */
  98        {0x880000, 0x88a000, 0x880000, "rgf", true},
  99        /* AGC table   4k */
 100        {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
 101        /* Pcie_ext_rgf 4k */
 102        {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
 103        /* mac_ext_rgf 512b */
 104        {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true},
 105        /* upper area 548k */
 106        {0x8c0000, 0x949000, 0x8c0000, "upper", true},
 107        /* UCODE areas - accessible by debugfs blobs but not by
 108         * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
 109         */
 110        /* ucode code RAM 128k */
 111        {0x000000, 0x020000, 0x920000, "uc_code", false},
 112        /* ucode data RAM 16k */
 113        {0x800000, 0x804000, 0x940000, "uc_data", false},
 114};
 115
 116/**
 117 * @sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0
 118 * it is a bit larger to support extra features
 119 */
 120const struct fw_map sparrow_d0_mac_rgf_ext = {
 121        0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true
 122};
 123
 124/**
 125 * @talyn_fw_mapping provides memory remapping table for Talyn
 126 *
 127 * array size should be in sync with the declaration in the wil6210.h
 128 *
 129 * Talyn memory mapping:
 130 * Linker address         PCI/Host address
 131 *                        0x880000 .. 0xc80000  4Mb BAR0
 132 * 0x800000 .. 0x820000   0xa00000 .. 0xa20000  128k DCCM
 133 * 0x840000 .. 0x858000   0xa20000 .. 0xa38000  96k PERIPH
 134 */
 135const struct fw_map talyn_fw_mapping[] = {
 136        /* FW code RAM 1M */
 137        {0x000000, 0x100000, 0x900000, "fw_code", true},
 138        /* FW data RAM 128k */
 139        {0x800000, 0x820000, 0xa00000, "fw_data", true},
 140        /* periph. data RAM 96k */
 141        {0x840000, 0x858000, 0xa20000, "fw_peri", true},
 142        /* various RGF 40k */
 143        {0x880000, 0x88a000, 0x880000, "rgf", true},
 144        /* AGC table 4k */
 145        {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
 146        /* Pcie_ext_rgf 4k */
 147        {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
 148        /* mac_ext_rgf 1344b */
 149        {0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true},
 150        /* ext USER RGF 4k */
 151        {0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true},
 152        /* OTP 4k */
 153        {0x8a0000, 0x8a1000, 0x8a0000, "otp", true},
 154        /* DMA EXT RGF 64k */
 155        {0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true},
 156        /* upper area 1536k */
 157        {0x900000, 0xa80000, 0x900000, "upper", true},
 158        /* UCODE areas - accessible by debugfs blobs but not by
 159         * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
 160         */
 161        /* ucode code RAM 256k */
 162        {0x000000, 0x040000, 0xa38000, "uc_code", false},
 163        /* ucode data RAM 32k */
 164        {0x800000, 0x808000, 0xa78000, "uc_data", false},
 165};
 166
 167struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
 168
 169struct blink_on_off_time led_blink_time[] = {
 170        {WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
 171        {WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
 172        {WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
 173};
 174
 175u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
 176
 177/**
 178 * return AHB address for given firmware internal (linker) address
 179 * @x - internal address
 180 * If address have no valid AHB mapping, return 0
 181 */
 182static u32 wmi_addr_remap(u32 x)
 183{
 184        uint i;
 185
 186        for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
 187                if (fw_mapping[i].fw &&
 188                    ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)))
 189                        return x + fw_mapping[i].host - fw_mapping[i].from;
 190        }
 191
 192        return 0;
 193}
 194
 195/**
 196 * find fw_mapping entry by section name
 197 * @section - section name
 198 *
 199 * Return pointer to section or NULL if not found
 200 */
 201struct fw_map *wil_find_fw_mapping(const char *section)
 202{
 203        int i;
 204
 205        for (i = 0; i < ARRAY_SIZE(fw_mapping); i++)
 206                if (fw_mapping[i].name &&
 207                    !strcmp(section, fw_mapping[i].name))
 208                        return &fw_mapping[i];
 209
 210        return NULL;
 211}
 212
 213/**
 214 * Check address validity for WMI buffer; remap if needed
 215 * @ptr - internal (linker) fw/ucode address
 216 * @size - if non zero, validate the block does not
 217 *  exceed the device memory (bar)
 218 *
 219 * Valid buffer should be DWORD aligned
 220 *
 221 * return address for accessing buffer from the host;
 222 * if buffer is not valid, return NULL.
 223 */
 224void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
 225{
 226        u32 off;
 227        u32 ptr = le32_to_cpu(ptr_);
 228
 229        if (ptr % 4)
 230                return NULL;
 231
 232        ptr = wmi_addr_remap(ptr);
 233        if (ptr < WIL6210_FW_HOST_OFF)
 234                return NULL;
 235
 236        off = HOSTADDR(ptr);
 237        if (off > wil->bar_size - 4)
 238                return NULL;
 239        if (size && ((off + size > wil->bar_size) || (off + size < off)))
 240                return NULL;
 241
 242        return wil->csr + off;
 243}
 244
 245void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
 246{
 247        return wmi_buffer_block(wil, ptr_, 0);
 248}
 249
 250/**
 251 * Check address validity
 252 */
 253void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
 254{
 255        u32 off;
 256
 257        if (ptr % 4)
 258                return NULL;
 259
 260        if (ptr < WIL6210_FW_HOST_OFF)
 261                return NULL;
 262
 263        off = HOSTADDR(ptr);
 264        if (off > wil->bar_size - 4)
 265                return NULL;
 266
 267        return wil->csr + off;
 268}
 269
 270int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
 271                 struct wil6210_mbox_hdr *hdr)
 272{
 273        void __iomem *src = wmi_buffer(wil, ptr);
 274
 275        if (!src)
 276                return -EINVAL;
 277
 278        wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
 279
 280        return 0;
 281}
 282
 283static const char *cmdid2name(u16 cmdid)
 284{
 285        switch (cmdid) {
 286        case WMI_NOTIFY_REQ_CMDID:
 287                return "WMI_NOTIFY_REQ_CMD";
 288        case WMI_START_SCAN_CMDID:
 289                return "WMI_START_SCAN_CMD";
 290        case WMI_CONNECT_CMDID:
 291                return "WMI_CONNECT_CMD";
 292        case WMI_DISCONNECT_CMDID:
 293                return "WMI_DISCONNECT_CMD";
 294        case WMI_SW_TX_REQ_CMDID:
 295                return "WMI_SW_TX_REQ_CMD";
 296        case WMI_GET_RF_SECTOR_PARAMS_CMDID:
 297                return "WMI_GET_RF_SECTOR_PARAMS_CMD";
 298        case WMI_SET_RF_SECTOR_PARAMS_CMDID:
 299                return "WMI_SET_RF_SECTOR_PARAMS_CMD";
 300        case WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID:
 301                return "WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD";
 302        case WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID:
 303                return "WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD";
 304        case WMI_BRP_SET_ANT_LIMIT_CMDID:
 305                return "WMI_BRP_SET_ANT_LIMIT_CMD";
 306        case WMI_TOF_SESSION_START_CMDID:
 307                return "WMI_TOF_SESSION_START_CMD";
 308        case WMI_AOA_MEAS_CMDID:
 309                return "WMI_AOA_MEAS_CMD";
 310        case WMI_PMC_CMDID:
 311                return "WMI_PMC_CMD";
 312        case WMI_TOF_GET_TX_RX_OFFSET_CMDID:
 313                return "WMI_TOF_GET_TX_RX_OFFSET_CMD";
 314        case WMI_TOF_SET_TX_RX_OFFSET_CMDID:
 315                return "WMI_TOF_SET_TX_RX_OFFSET_CMD";
 316        case WMI_VRING_CFG_CMDID:
 317                return "WMI_VRING_CFG_CMD";
 318        case WMI_BCAST_VRING_CFG_CMDID:
 319                return "WMI_BCAST_VRING_CFG_CMD";
 320        case WMI_TRAFFIC_SUSPEND_CMDID:
 321                return "WMI_TRAFFIC_SUSPEND_CMD";
 322        case WMI_TRAFFIC_RESUME_CMDID:
 323                return "WMI_TRAFFIC_RESUME_CMD";
 324        case WMI_ECHO_CMDID:
 325                return "WMI_ECHO_CMD";
 326        case WMI_SET_MAC_ADDRESS_CMDID:
 327                return "WMI_SET_MAC_ADDRESS_CMD";
 328        case WMI_LED_CFG_CMDID:
 329                return "WMI_LED_CFG_CMD";
 330        case WMI_PCP_START_CMDID:
 331                return "WMI_PCP_START_CMD";
 332        case WMI_PCP_STOP_CMDID:
 333                return "WMI_PCP_STOP_CMD";
 334        case WMI_SET_SSID_CMDID:
 335                return "WMI_SET_SSID_CMD";
 336        case WMI_GET_SSID_CMDID:
 337                return "WMI_GET_SSID_CMD";
 338        case WMI_SET_PCP_CHANNEL_CMDID:
 339                return "WMI_SET_PCP_CHANNEL_CMD";
 340        case WMI_GET_PCP_CHANNEL_CMDID:
 341                return "WMI_GET_PCP_CHANNEL_CMD";
 342        case WMI_P2P_CFG_CMDID:
 343                return "WMI_P2P_CFG_CMD";
 344        case WMI_START_LISTEN_CMDID:
 345                return "WMI_START_LISTEN_CMD";
 346        case WMI_START_SEARCH_CMDID:
 347                return "WMI_START_SEARCH_CMD";
 348        case WMI_DISCOVERY_STOP_CMDID:
 349                return "WMI_DISCOVERY_STOP_CMD";
 350        case WMI_DELETE_CIPHER_KEY_CMDID:
 351                return "WMI_DELETE_CIPHER_KEY_CMD";
 352        case WMI_ADD_CIPHER_KEY_CMDID:
 353                return "WMI_ADD_CIPHER_KEY_CMD";
 354        case WMI_SET_APPIE_CMDID:
 355                return "WMI_SET_APPIE_CMD";
 356        case WMI_CFG_RX_CHAIN_CMDID:
 357                return "WMI_CFG_RX_CHAIN_CMD";
 358        case WMI_TEMP_SENSE_CMDID:
 359                return "WMI_TEMP_SENSE_CMD";
 360        case WMI_DEL_STA_CMDID:
 361                return "WMI_DEL_STA_CMD";
 362        case WMI_DISCONNECT_STA_CMDID:
 363                return "WMI_DISCONNECT_STA_CMD";
 364        case WMI_VRING_BA_EN_CMDID:
 365                return "WMI_VRING_BA_EN_CMD";
 366        case WMI_VRING_BA_DIS_CMDID:
 367                return "WMI_VRING_BA_DIS_CMD";
 368        case WMI_RCP_DELBA_CMDID:
 369                return "WMI_RCP_DELBA_CMD";
 370        case WMI_RCP_ADDBA_RESP_CMDID:
 371                return "WMI_RCP_ADDBA_RESP_CMD";
 372        case WMI_PS_DEV_PROFILE_CFG_CMDID:
 373                return "WMI_PS_DEV_PROFILE_CFG_CMD";
 374        case WMI_SET_MGMT_RETRY_LIMIT_CMDID:
 375                return "WMI_SET_MGMT_RETRY_LIMIT_CMD";
 376        case WMI_GET_MGMT_RETRY_LIMIT_CMDID:
 377                return "WMI_GET_MGMT_RETRY_LIMIT_CMD";
 378        case WMI_ABORT_SCAN_CMDID:
 379                return "WMI_ABORT_SCAN_CMD";
 380        case WMI_NEW_STA_CMDID:
 381                return "WMI_NEW_STA_CMD";
 382        case WMI_SET_THERMAL_THROTTLING_CFG_CMDID:
 383                return "WMI_SET_THERMAL_THROTTLING_CFG_CMD";
 384        case WMI_GET_THERMAL_THROTTLING_CFG_CMDID:
 385                return "WMI_GET_THERMAL_THROTTLING_CFG_CMD";
 386        case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID:
 387                return "WMI_LINK_MAINTAIN_CFG_WRITE_CMD";
 388        case WMI_LO_POWER_CALIB_FROM_OTP_CMDID:
 389                return "WMI_LO_POWER_CALIB_FROM_OTP_CMD";
 390        case WMI_START_SCHED_SCAN_CMDID:
 391                return "WMI_START_SCHED_SCAN_CMD";
 392        case WMI_STOP_SCHED_SCAN_CMDID:
 393                return "WMI_STOP_SCHED_SCAN_CMD";
 394        default:
 395                return "Untracked CMD";
 396        }
 397}
 398
 399static const char *eventid2name(u16 eventid)
 400{
 401        switch (eventid) {
 402        case WMI_NOTIFY_REQ_DONE_EVENTID:
 403                return "WMI_NOTIFY_REQ_DONE_EVENT";
 404        case WMI_DISCONNECT_EVENTID:
 405                return "WMI_DISCONNECT_EVENT";
 406        case WMI_SW_TX_COMPLETE_EVENTID:
 407                return "WMI_SW_TX_COMPLETE_EVENT";
 408        case WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID:
 409                return "WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT";
 410        case WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID:
 411                return "WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT";
 412        case WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
 413                return "WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
 414        case WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
 415                return "WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
 416        case WMI_BRP_SET_ANT_LIMIT_EVENTID:
 417                return "WMI_BRP_SET_ANT_LIMIT_EVENT";
 418        case WMI_FW_READY_EVENTID:
 419                return "WMI_FW_READY_EVENT";
 420        case WMI_TRAFFIC_RESUME_EVENTID:
 421                return "WMI_TRAFFIC_RESUME_EVENT";
 422        case WMI_TOF_GET_TX_RX_OFFSET_EVENTID:
 423                return "WMI_TOF_GET_TX_RX_OFFSET_EVENT";
 424        case WMI_TOF_SET_TX_RX_OFFSET_EVENTID:
 425                return "WMI_TOF_SET_TX_RX_OFFSET_EVENT";
 426        case WMI_VRING_CFG_DONE_EVENTID:
 427                return "WMI_VRING_CFG_DONE_EVENT";
 428        case WMI_READY_EVENTID:
 429                return "WMI_READY_EVENT";
 430        case WMI_RX_MGMT_PACKET_EVENTID:
 431                return "WMI_RX_MGMT_PACKET_EVENT";
 432        case WMI_TX_MGMT_PACKET_EVENTID:
 433                return "WMI_TX_MGMT_PACKET_EVENT";
 434        case WMI_SCAN_COMPLETE_EVENTID:
 435                return "WMI_SCAN_COMPLETE_EVENT";
 436        case WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID:
 437                return "WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENT";
 438        case WMI_CONNECT_EVENTID:
 439                return "WMI_CONNECT_EVENT";
 440        case WMI_EAPOL_RX_EVENTID:
 441                return "WMI_EAPOL_RX_EVENT";
 442        case WMI_BA_STATUS_EVENTID:
 443                return "WMI_BA_STATUS_EVENT";
 444        case WMI_RCP_ADDBA_REQ_EVENTID:
 445                return "WMI_RCP_ADDBA_REQ_EVENT";
 446        case WMI_DELBA_EVENTID:
 447                return "WMI_DELBA_EVENT";
 448        case WMI_VRING_EN_EVENTID:
 449                return "WMI_VRING_EN_EVENT";
 450        case WMI_DATA_PORT_OPEN_EVENTID:
 451                return "WMI_DATA_PORT_OPEN_EVENT";
 452        case WMI_AOA_MEAS_EVENTID:
 453                return "WMI_AOA_MEAS_EVENT";
 454        case WMI_TOF_SESSION_END_EVENTID:
 455                return "WMI_TOF_SESSION_END_EVENT";
 456        case WMI_TOF_GET_CAPABILITIES_EVENTID:
 457                return "WMI_TOF_GET_CAPABILITIES_EVENT";
 458        case WMI_TOF_SET_LCR_EVENTID:
 459                return "WMI_TOF_SET_LCR_EVENT";
 460        case WMI_TOF_SET_LCI_EVENTID:
 461                return "WMI_TOF_SET_LCI_EVENT";
 462        case WMI_TOF_FTM_PER_DEST_RES_EVENTID:
 463                return "WMI_TOF_FTM_PER_DEST_RES_EVENT";
 464        case WMI_TOF_CHANNEL_INFO_EVENTID:
 465                return "WMI_TOF_CHANNEL_INFO_EVENT";
 466        case WMI_TRAFFIC_SUSPEND_EVENTID:
 467                return "WMI_TRAFFIC_SUSPEND_EVENT";
 468        case WMI_ECHO_RSP_EVENTID:
 469                return "WMI_ECHO_RSP_EVENT";
 470        case WMI_LED_CFG_DONE_EVENTID:
 471                return "WMI_LED_CFG_DONE_EVENT";
 472        case WMI_PCP_STARTED_EVENTID:
 473                return "WMI_PCP_STARTED_EVENT";
 474        case WMI_PCP_STOPPED_EVENTID:
 475                return "WMI_PCP_STOPPED_EVENT";
 476        case WMI_GET_SSID_EVENTID:
 477                return "WMI_GET_SSID_EVENT";
 478        case WMI_GET_PCP_CHANNEL_EVENTID:
 479                return "WMI_GET_PCP_CHANNEL_EVENT";
 480        case WMI_P2P_CFG_DONE_EVENTID:
 481                return "WMI_P2P_CFG_DONE_EVENT";
 482        case WMI_LISTEN_STARTED_EVENTID:
 483                return "WMI_LISTEN_STARTED_EVENT";
 484        case WMI_SEARCH_STARTED_EVENTID:
 485                return "WMI_SEARCH_STARTED_EVENT";
 486        case WMI_DISCOVERY_STOPPED_EVENTID:
 487                return "WMI_DISCOVERY_STOPPED_EVENT";
 488        case WMI_CFG_RX_CHAIN_DONE_EVENTID:
 489                return "WMI_CFG_RX_CHAIN_DONE_EVENT";
 490        case WMI_TEMP_SENSE_DONE_EVENTID:
 491                return "WMI_TEMP_SENSE_DONE_EVENT";
 492        case WMI_RCP_ADDBA_RESP_SENT_EVENTID:
 493                return "WMI_RCP_ADDBA_RESP_SENT_EVENT";
 494        case WMI_PS_DEV_PROFILE_CFG_EVENTID:
 495                return "WMI_PS_DEV_PROFILE_CFG_EVENT";
 496        case WMI_SET_MGMT_RETRY_LIMIT_EVENTID:
 497                return "WMI_SET_MGMT_RETRY_LIMIT_EVENT";
 498        case WMI_GET_MGMT_RETRY_LIMIT_EVENTID:
 499                return "WMI_GET_MGMT_RETRY_LIMIT_EVENT";
 500        case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID:
 501                return "WMI_SET_THERMAL_THROTTLING_CFG_EVENT";
 502        case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID:
 503                return "WMI_GET_THERMAL_THROTTLING_CFG_EVENT";
 504        case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID:
 505                return "WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT";
 506        case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID:
 507                return "WMI_LO_POWER_CALIB_FROM_OTP_EVENT";
 508        case WMI_START_SCHED_SCAN_EVENTID:
 509                return "WMI_START_SCHED_SCAN_EVENT";
 510        case WMI_STOP_SCHED_SCAN_EVENTID:
 511                return "WMI_STOP_SCHED_SCAN_EVENT";
 512        case WMI_SCHED_SCAN_RESULT_EVENTID:
 513                return "WMI_SCHED_SCAN_RESULT_EVENT";
 514        default:
 515                return "Untracked EVENT";
 516        }
 517}
 518
 519static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
 520{
 521        struct {
 522                struct wil6210_mbox_hdr hdr;
 523                struct wmi_cmd_hdr wmi;
 524        } __packed cmd = {
 525                .hdr = {
 526                        .type = WIL_MBOX_HDR_TYPE_WMI,
 527                        .flags = 0,
 528                        .len = cpu_to_le16(sizeof(cmd.wmi) + len),
 529                },
 530                .wmi = {
 531                        .mid = 0,
 532                        .command_id = cpu_to_le16(cmdid),
 533                },
 534        };
 535        struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
 536        struct wil6210_mbox_ring_desc d_head;
 537        u32 next_head;
 538        void __iomem *dst;
 539        void __iomem *head = wmi_addr(wil, r->head);
 540        uint retry;
 541        int rc = 0;
 542
 543        if (len > r->entry_size - sizeof(cmd)) {
 544                wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
 545                        (int)(sizeof(cmd) + len), r->entry_size);
 546                return -ERANGE;
 547        }
 548
 549        might_sleep();
 550
 551        if (!test_bit(wil_status_fwready, wil->status)) {
 552                wil_err(wil, "WMI: cannot send command while FW not ready\n");
 553                return -EAGAIN;
 554        }
 555
 556        /* Allow sending only suspend / resume commands during susepnd flow */
 557        if ((test_bit(wil_status_suspending, wil->status) ||
 558             test_bit(wil_status_suspended, wil->status) ||
 559             test_bit(wil_status_resuming, wil->status)) &&
 560             ((cmdid != WMI_TRAFFIC_SUSPEND_CMDID) &&
 561              (cmdid != WMI_TRAFFIC_RESUME_CMDID))) {
 562                wil_err(wil, "WMI: reject send_command during suspend\n");
 563                return -EINVAL;
 564        }
 565
 566        if (!head) {
 567                wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
 568                return -EINVAL;
 569        }
 570
 571        wil_halp_vote(wil);
 572
 573        /* read Tx head till it is not busy */
 574        for (retry = 5; retry > 0; retry--) {
 575                wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
 576                if (d_head.sync == 0)
 577                        break;
 578                msleep(20);
 579        }
 580        if (d_head.sync != 0) {
 581                wil_err(wil, "WMI head busy\n");
 582                rc = -EBUSY;
 583                goto out;
 584        }
 585        /* next head */
 586        next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
 587        wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
 588        /* wait till FW finish with previous command */
 589        for (retry = 5; retry > 0; retry--) {
 590                if (!test_bit(wil_status_fwready, wil->status)) {
 591                        wil_err(wil, "WMI: cannot send command while FW not ready\n");
 592                        rc = -EAGAIN;
 593                        goto out;
 594                }
 595                r->tail = wil_r(wil, RGF_MBOX +
 596                                offsetof(struct wil6210_mbox_ctl, tx.tail));
 597                if (next_head != r->tail)
 598                        break;
 599                msleep(20);
 600        }
 601        if (next_head == r->tail) {
 602                wil_err(wil, "WMI ring full\n");
 603                rc = -EBUSY;
 604                goto out;
 605        }
 606        dst = wmi_buffer(wil, d_head.addr);
 607        if (!dst) {
 608                wil_err(wil, "invalid WMI buffer: 0x%08x\n",
 609                        le32_to_cpu(d_head.addr));
 610                rc = -EAGAIN;
 611                goto out;
 612        }
 613        cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
 614        /* set command */
 615        wil_dbg_wmi(wil, "sending %s (0x%04x) [%d]\n",
 616                    cmdid2name(cmdid), cmdid, len);
 617        wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
 618                         sizeof(cmd), true);
 619        wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
 620                         len, true);
 621        wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
 622        wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
 623        /* mark entry as full */
 624        wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1);
 625        /* advance next ptr */
 626        wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head),
 627              r->head = next_head);
 628
 629        trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
 630
 631        /* interrupt to FW */
 632        wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS),
 633              SW_INT_MBOX);
 634
 635out:
 636        wil_halp_unvote(wil);
 637        return rc;
 638}
 639
 640int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
 641{
 642        int rc;
 643
 644        mutex_lock(&wil->wmi_mutex);
 645        rc = __wmi_send(wil, cmdid, buf, len);
 646        mutex_unlock(&wil->wmi_mutex);
 647
 648        return rc;
 649}
 650
 651/*=== Event handlers ===*/
 652static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
 653{
 654        struct wireless_dev *wdev = wil->wdev;
 655        struct wmi_ready_event *evt = d;
 656
 657        wil->n_mids = evt->numof_additional_mids;
 658
 659        wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
 660                 wil->fw_version, le32_to_cpu(evt->sw_version),
 661                 evt->mac, wil->n_mids);
 662        /* ignore MAC address, we already have it from the boot loader */
 663        strlcpy(wdev->wiphy->fw_version, wil->fw_version,
 664                sizeof(wdev->wiphy->fw_version));
 665
 666        if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
 667                wil_dbg_wmi(wil, "rfc calibration result %d\n",
 668                            evt->rfc_read_calib_result);
 669                wil->fw_calib_result = evt->rfc_read_calib_result;
 670        }
 671        wil_set_recovery_state(wil, fw_recovery_idle);
 672        set_bit(wil_status_fwready, wil->status);
 673        /* let the reset sequence continue */
 674        complete(&wil->wmi_ready);
 675}
 676
 677static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
 678{
 679        struct wmi_rx_mgmt_packet_event *data = d;
 680        struct wiphy *wiphy = wil_to_wiphy(wil);
 681        struct ieee80211_mgmt *rx_mgmt_frame =
 682                        (struct ieee80211_mgmt *)data->payload;
 683        int flen = len - offsetof(struct wmi_rx_mgmt_packet_event, payload);
 684        int ch_no;
 685        u32 freq;
 686        struct ieee80211_channel *channel;
 687        s32 signal;
 688        __le16 fc;
 689        u32 d_len;
 690        u16 d_status;
 691
 692        if (flen < 0) {
 693                wil_err(wil, "MGMT Rx: short event, len %d\n", len);
 694                return;
 695        }
 696
 697        d_len = le32_to_cpu(data->info.len);
 698        if (d_len != flen) {
 699                wil_err(wil,
 700                        "MGMT Rx: length mismatch, d_len %d should be %d\n",
 701                        d_len, flen);
 702                return;
 703        }
 704
 705        ch_no = data->info.channel + 1;
 706        freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
 707        channel = ieee80211_get_channel(wiphy, freq);
 708        if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
 709                signal = 100 * data->info.rssi;
 710        else
 711                signal = data->info.sqi;
 712        d_status = le16_to_cpu(data->info.status);
 713        fc = rx_mgmt_frame->frame_control;
 714
 715        wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n",
 716                    data->info.channel, data->info.mcs, data->info.rssi,
 717                    data->info.sqi);
 718        wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
 719                    le16_to_cpu(fc));
 720        wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
 721                    data->info.qid, data->info.mid, data->info.cid);
 722        wil_hex_dump_wmi("MGMT Rx ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
 723                         d_len, true);
 724
 725        if (!channel) {
 726                wil_err(wil, "Frame on unsupported channel\n");
 727                return;
 728        }
 729
 730        if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
 731                struct cfg80211_bss *bss;
 732                u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
 733                u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
 734                u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
 735                const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
 736                size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
 737                                                 u.beacon.variable);
 738                wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
 739                wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf);
 740                wil_dbg_wmi(wil, "Beacon interval : %d\n", bi);
 741                wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf,
 742                                 ie_len, true);
 743
 744                wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
 745
 746                bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
 747                                                d_len, signal, GFP_KERNEL);
 748                if (bss) {
 749                        wil_dbg_wmi(wil, "Added BSS %pM\n",
 750                                    rx_mgmt_frame->bssid);
 751                        cfg80211_put_bss(wiphy, bss);
 752                } else {
 753                        wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
 754                }
 755        } else {
 756                mutex_lock(&wil->p2p_wdev_mutex);
 757                cfg80211_rx_mgmt(wil->radio_wdev, freq, signal,
 758                                 (void *)rx_mgmt_frame, d_len, 0);
 759                mutex_unlock(&wil->p2p_wdev_mutex);
 760        }
 761}
 762
 763static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
 764{
 765        struct wmi_tx_mgmt_packet_event *data = d;
 766        struct ieee80211_mgmt *mgmt_frame =
 767                        (struct ieee80211_mgmt *)data->payload;
 768        int flen = len - offsetof(struct wmi_tx_mgmt_packet_event, payload);
 769
 770        wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame,
 771                         flen, true);
 772}
 773
 774static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
 775                                  void *d, int len)
 776{
 777        mutex_lock(&wil->p2p_wdev_mutex);
 778        if (wil->scan_request) {
 779                struct wmi_scan_complete_event *data = d;
 780                int status = le32_to_cpu(data->status);
 781                struct cfg80211_scan_info info = {
 782                        .aborted = ((status != WMI_SCAN_SUCCESS) &&
 783                                (status != WMI_SCAN_ABORT_REJECTED)),
 784                };
 785
 786                wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status);
 787                wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
 788                             wil->scan_request, info.aborted);
 789                del_timer_sync(&wil->scan_timer);
 790                cfg80211_scan_done(wil->scan_request, &info);
 791                wil->radio_wdev = wil->wdev;
 792                wil->scan_request = NULL;
 793                wake_up_interruptible(&wil->wq);
 794                if (wil->p2p.pending_listen_wdev) {
 795                        wil_dbg_misc(wil, "Scheduling delayed listen\n");
 796                        schedule_work(&wil->p2p.delayed_listen_work);
 797                }
 798        } else {
 799                wil_err(wil, "SCAN_COMPLETE while not scanning\n");
 800        }
 801        mutex_unlock(&wil->p2p_wdev_mutex);
 802}
 803
 804static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
 805{
 806        struct net_device *ndev = wil_to_ndev(wil);
 807        struct wireless_dev *wdev = wil->wdev;
 808        struct wmi_connect_event *evt = d;
 809        int ch; /* channel number */
 810        struct station_info sinfo;
 811        u8 *assoc_req_ie, *assoc_resp_ie;
 812        size_t assoc_req_ielen, assoc_resp_ielen;
 813        /* capinfo(u16) + listen_interval(u16) + IEs */
 814        const size_t assoc_req_ie_offset = sizeof(u16) * 2;
 815        /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
 816        const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
 817        int rc;
 818
 819        if (len < sizeof(*evt)) {
 820                wil_err(wil, "Connect event too short : %d bytes\n", len);
 821                return;
 822        }
 823        if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
 824                   evt->assoc_resp_len) {
 825                wil_err(wil,
 826                        "Connect event corrupted : %d != %d + %d + %d + %d\n",
 827                        len, (int)sizeof(*evt), evt->beacon_ie_len,
 828                        evt->assoc_req_len, evt->assoc_resp_len);
 829                return;
 830        }
 831        if (evt->cid >= WIL6210_MAX_CID) {
 832                wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
 833                return;
 834        }
 835
 836        ch = evt->channel + 1;
 837        wil_info(wil, "Connect %pM channel [%d] cid %d aid %d\n",
 838                 evt->bssid, ch, evt->cid, evt->aid);
 839        wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
 840                         evt->assoc_info, len - sizeof(*evt), true);
 841
 842        /* figure out IE's */
 843        assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
 844                                        assoc_req_ie_offset];
 845        assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
 846        if (evt->assoc_req_len <= assoc_req_ie_offset) {
 847                assoc_req_ie = NULL;
 848                assoc_req_ielen = 0;
 849        }
 850
 851        assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
 852                                         evt->assoc_req_len +
 853                                         assoc_resp_ie_offset];
 854        assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
 855        if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
 856                assoc_resp_ie = NULL;
 857                assoc_resp_ielen = 0;
 858        }
 859
 860        if (test_bit(wil_status_resetting, wil->status) ||
 861            !test_bit(wil_status_fwready, wil->status)) {
 862                wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
 863                        evt->cid);
 864                /* no need for cleanup, wil_reset will do that */
 865                return;
 866        }
 867
 868        mutex_lock(&wil->mutex);
 869
 870        if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
 871            (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
 872                if (!test_bit(wil_status_fwconnecting, wil->status)) {
 873                        wil_err(wil, "Not in connecting state\n");
 874                        mutex_unlock(&wil->mutex);
 875                        return;
 876                }
 877                del_timer_sync(&wil->connect_timer);
 878        } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
 879                   (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
 880                if (wil->sta[evt->cid].status != wil_sta_unused) {
 881                        wil_err(wil, "AP: Invalid status %d for CID %d\n",
 882                                wil->sta[evt->cid].status, evt->cid);
 883                        mutex_unlock(&wil->mutex);
 884                        return;
 885                }
 886        }
 887
 888        ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
 889        wil->sta[evt->cid].status = wil_sta_conn_pending;
 890
 891        rc = wil_tx_init(wil, evt->cid);
 892        if (rc) {
 893                wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n",
 894                        evt->cid, rc);
 895                wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
 896                                   WLAN_REASON_UNSPECIFIED, false, false);
 897        } else {
 898                wil_info(wil, "successful connection to CID %d\n", evt->cid);
 899        }
 900
 901        if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
 902            (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
 903                if (rc) {
 904                        netif_carrier_off(ndev);
 905                        wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
 906                        wil_err(wil, "cfg80211_connect_result with failure\n");
 907                        cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
 908                                                NULL, 0,
 909                                                WLAN_STATUS_UNSPECIFIED_FAILURE,
 910                                                GFP_KERNEL);
 911                        goto out;
 912                } else {
 913                        struct wiphy *wiphy = wil_to_wiphy(wil);
 914
 915                        cfg80211_ref_bss(wiphy, wil->bss);
 916                        cfg80211_connect_bss(ndev, evt->bssid, wil->bss,
 917                                             assoc_req_ie, assoc_req_ielen,
 918                                             assoc_resp_ie, assoc_resp_ielen,
 919                                             WLAN_STATUS_SUCCESS, GFP_KERNEL,
 920                                             NL80211_TIMEOUT_UNSPECIFIED);
 921                }
 922                wil->bss = NULL;
 923        } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
 924                   (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
 925                if (rc) {
 926                        if (disable_ap_sme)
 927                                /* notify new_sta has failed */
 928                                cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
 929                        goto out;
 930                }
 931
 932                memset(&sinfo, 0, sizeof(sinfo));
 933
 934                sinfo.generation = wil->sinfo_gen++;
 935
 936                if (assoc_req_ie) {
 937                        sinfo.assoc_req_ies = assoc_req_ie;
 938                        sinfo.assoc_req_ies_len = assoc_req_ielen;
 939                }
 940
 941                cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
 942        } else {
 943                wil_err(wil, "unhandled iftype %d for CID %d\n", wdev->iftype,
 944                        evt->cid);
 945                goto out;
 946        }
 947
 948        wil->sta[evt->cid].status = wil_sta_connected;
 949        wil->sta[evt->cid].aid = evt->aid;
 950        set_bit(wil_status_fwconnected, wil->status);
 951        wil_update_net_queues_bh(wil, NULL, false);
 952
 953out:
 954        if (rc)
 955                wil->sta[evt->cid].status = wil_sta_unused;
 956        clear_bit(wil_status_fwconnecting, wil->status);
 957        mutex_unlock(&wil->mutex);
 958}
 959
 960static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
 961                               void *d, int len)
 962{
 963        struct wmi_disconnect_event *evt = d;
 964        u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
 965
 966        wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
 967                 evt->bssid, reason_code, evt->disconnect_reason);
 968
 969        wil->sinfo_gen++;
 970
 971        if (test_bit(wil_status_resetting, wil->status) ||
 972            !test_bit(wil_status_fwready, wil->status)) {
 973                wil_err(wil, "status_resetting, cancel disconnect event\n");
 974                /* no need for cleanup, wil_reset will do that */
 975                return;
 976        }
 977
 978        mutex_lock(&wil->mutex);
 979        wil6210_disconnect(wil, evt->bssid, reason_code, true);
 980        mutex_unlock(&wil->mutex);
 981}
 982
 983/*
 984 * Firmware reports EAPOL frame using WME event.
 985 * Reconstruct Ethernet frame and deliver it via normal Rx
 986 */
 987static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
 988                             void *d, int len)
 989{
 990        struct net_device *ndev = wil_to_ndev(wil);
 991        struct wmi_eapol_rx_event *evt = d;
 992        u16 eapol_len = le16_to_cpu(evt->eapol_len);
 993        int sz = eapol_len + ETH_HLEN;
 994        struct sk_buff *skb;
 995        struct ethhdr *eth;
 996        int cid;
 997        struct wil_net_stats *stats = NULL;
 998
 999        wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
1000                    evt->src_mac);
1001
1002        cid = wil_find_cid(wil, evt->src_mac);
1003        if (cid >= 0)
1004                stats = &wil->sta[cid].stats;
1005
1006        if (eapol_len > 196) { /* TODO: revisit size limit */
1007                wil_err(wil, "EAPOL too large\n");
1008                return;
1009        }
1010
1011        skb = alloc_skb(sz, GFP_KERNEL);
1012        if (!skb) {
1013                wil_err(wil, "Failed to allocate skb\n");
1014                return;
1015        }
1016
1017        eth = skb_put(skb, ETH_HLEN);
1018        ether_addr_copy(eth->h_dest, ndev->dev_addr);
1019        ether_addr_copy(eth->h_source, evt->src_mac);
1020        eth->h_proto = cpu_to_be16(ETH_P_PAE);
1021        skb_put_data(skb, evt->eapol, eapol_len);
1022        skb->protocol = eth_type_trans(skb, ndev);
1023        if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
1024                ndev->stats.rx_packets++;
1025                ndev->stats.rx_bytes += sz;
1026                if (stats) {
1027                        stats->rx_packets++;
1028                        stats->rx_bytes += sz;
1029                }
1030        } else {
1031                ndev->stats.rx_dropped++;
1032                if (stats)
1033                        stats->rx_dropped++;
1034        }
1035}
1036
1037static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
1038{
1039        struct wmi_vring_en_event *evt = d;
1040        u8 vri = evt->vring_index;
1041        struct wireless_dev *wdev = wil_to_wdev(wil);
1042
1043        wil_dbg_wmi(wil, "Enable vring %d\n", vri);
1044
1045        if (vri >= ARRAY_SIZE(wil->vring_tx)) {
1046                wil_err(wil, "Enable for invalid vring %d\n", vri);
1047                return;
1048        }
1049
1050        if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
1051                /* in AP mode with disable_ap_sme, this is done by
1052                 * wil_cfg80211_change_station()
1053                 */
1054                wil->vring_tx_data[vri].dot1x_open = true;
1055        if (vri == wil->bcast_vring) /* no BA for bcast */
1056                return;
1057        if (agg_wsize >= 0)
1058                wil_addba_tx_request(wil, vri, agg_wsize);
1059}
1060
1061static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
1062                              int len)
1063{
1064        struct wmi_ba_status_event *evt = d;
1065        struct vring_tx_data *txdata;
1066
1067        wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
1068                    evt->ringid,
1069                    evt->status == WMI_BA_AGREED ? "OK" : "N/A",
1070                    evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
1071                    evt->amsdu ? "+" : "-");
1072
1073        if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
1074                wil_err(wil, "invalid ring id %d\n", evt->ringid);
1075                return;
1076        }
1077
1078        if (evt->status != WMI_BA_AGREED) {
1079                evt->ba_timeout = 0;
1080                evt->agg_wsize = 0;
1081                evt->amsdu = 0;
1082        }
1083
1084        txdata = &wil->vring_tx_data[evt->ringid];
1085
1086        txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
1087        txdata->agg_wsize = evt->agg_wsize;
1088        txdata->agg_amsdu = evt->amsdu;
1089        txdata->addba_in_progress = false;
1090}
1091
1092static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
1093                                 int len)
1094{
1095        struct wmi_rcp_addba_req_event *evt = d;
1096
1097        wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
1098                             evt->ba_param_set, evt->ba_timeout,
1099                             evt->ba_seq_ctrl);
1100}
1101
1102static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
1103__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
1104{
1105        struct wmi_delba_event *evt = d;
1106        u8 cid, tid;
1107        u16 reason = __le16_to_cpu(evt->reason);
1108        struct wil_sta_info *sta;
1109        struct wil_tid_ampdu_rx *r;
1110
1111        might_sleep();
1112        parse_cidxtid(evt->cidxtid, &cid, &tid);
1113        wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
1114                    cid, tid,
1115                    evt->from_initiator ? "originator" : "recipient",
1116                    reason);
1117        if (!evt->from_initiator) {
1118                int i;
1119                /* find Tx vring it belongs to */
1120                for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
1121                        if ((wil->vring2cid_tid[i][0] == cid) &&
1122                            (wil->vring2cid_tid[i][1] == tid)) {
1123                                struct vring_tx_data *txdata =
1124                                        &wil->vring_tx_data[i];
1125
1126                                wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
1127                                txdata->agg_timeout = 0;
1128                                txdata->agg_wsize = 0;
1129                                txdata->addba_in_progress = false;
1130
1131                                break; /* max. 1 matching ring */
1132                        }
1133                }
1134                if (i >= ARRAY_SIZE(wil->vring2cid_tid))
1135                        wil_err(wil, "DELBA: unable to find Tx vring\n");
1136                return;
1137        }
1138
1139        sta = &wil->sta[cid];
1140
1141        spin_lock_bh(&sta->tid_rx_lock);
1142
1143        r = sta->tid_rx[tid];
1144        sta->tid_rx[tid] = NULL;
1145        wil_tid_ampdu_rx_free(wil, r);
1146
1147        spin_unlock_bh(&sta->tid_rx_lock);
1148}
1149
1150static void
1151wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len)
1152{
1153        struct wmi_sched_scan_result_event *data = d;
1154        struct wiphy *wiphy = wil_to_wiphy(wil);
1155        struct ieee80211_mgmt *rx_mgmt_frame =
1156                (struct ieee80211_mgmt *)data->payload;
1157        int flen = len - offsetof(struct wmi_sched_scan_result_event, payload);
1158        int ch_no;
1159        u32 freq;
1160        struct ieee80211_channel *channel;
1161        s32 signal;
1162        __le16 fc;
1163        u32 d_len;
1164        struct cfg80211_bss *bss;
1165
1166        if (flen < 0) {
1167                wil_err(wil, "sched scan result event too short, len %d\n",
1168                        len);
1169                return;
1170        }
1171
1172        d_len = le32_to_cpu(data->info.len);
1173        if (d_len != flen) {
1174                wil_err(wil,
1175                        "sched scan result length mismatch, d_len %d should be %d\n",
1176                        d_len, flen);
1177                return;
1178        }
1179
1180        fc = rx_mgmt_frame->frame_control;
1181        if (!ieee80211_is_probe_resp(fc)) {
1182                wil_err(wil, "sched scan result invalid frame, fc 0x%04x\n",
1183                        fc);
1184                return;
1185        }
1186
1187        ch_no = data->info.channel + 1;
1188        freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
1189        channel = ieee80211_get_channel(wiphy, freq);
1190        if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
1191                signal = 100 * data->info.rssi;
1192        else
1193                signal = data->info.sqi;
1194
1195        wil_dbg_wmi(wil, "sched scan result: channel %d MCS %d RSSI %d\n",
1196                    data->info.channel, data->info.mcs, data->info.rssi);
1197        wil_dbg_wmi(wil, "len %d qid %d mid %d cid %d\n",
1198                    d_len, data->info.qid, data->info.mid, data->info.cid);
1199        wil_hex_dump_wmi("PROBE ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
1200                         d_len, true);
1201
1202        if (!channel) {
1203                wil_err(wil, "Frame on unsupported channel\n");
1204                return;
1205        }
1206
1207        bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
1208                                        d_len, signal, GFP_KERNEL);
1209        if (bss) {
1210                wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid);
1211                cfg80211_put_bss(wiphy, bss);
1212        } else {
1213                wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
1214        }
1215
1216        cfg80211_sched_scan_results(wiphy, 0);
1217}
1218
1219/**
1220 * Some events are ignored for purpose; and need not be interpreted as
1221 * "unhandled events"
1222 */
1223static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
1224{
1225        wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
1226}
1227
1228static const struct {
1229        int eventid;
1230        void (*handler)(struct wil6210_priv *wil, int eventid,
1231                        void *data, int data_len);
1232} wmi_evt_handlers[] = {
1233        {WMI_READY_EVENTID,             wmi_evt_ready},
1234        {WMI_FW_READY_EVENTID,                  wmi_evt_ignore},
1235        {WMI_RX_MGMT_PACKET_EVENTID,    wmi_evt_rx_mgmt},
1236        {WMI_TX_MGMT_PACKET_EVENTID,            wmi_evt_tx_mgmt},
1237        {WMI_SCAN_COMPLETE_EVENTID,     wmi_evt_scan_complete},
1238        {WMI_CONNECT_EVENTID,           wmi_evt_connect},
1239        {WMI_DISCONNECT_EVENTID,        wmi_evt_disconnect},
1240        {WMI_EAPOL_RX_EVENTID,          wmi_evt_eapol_rx},
1241        {WMI_BA_STATUS_EVENTID,         wmi_evt_ba_status},
1242        {WMI_RCP_ADDBA_REQ_EVENTID,     wmi_evt_addba_rx_req},
1243        {WMI_DELBA_EVENTID,             wmi_evt_delba},
1244        {WMI_VRING_EN_EVENTID,          wmi_evt_vring_en},
1245        {WMI_DATA_PORT_OPEN_EVENTID,            wmi_evt_ignore},
1246        {WMI_SCHED_SCAN_RESULT_EVENTID,         wmi_evt_sched_scan_result},
1247};
1248
1249/*
1250 * Run in IRQ context
1251 * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
1252 * that will be eventually handled by the @wmi_event_worker in the thread
1253 * context of thread "wil6210_wmi"
1254 */
1255void wmi_recv_cmd(struct wil6210_priv *wil)
1256{
1257        struct wil6210_mbox_ring_desc d_tail;
1258        struct wil6210_mbox_hdr hdr;
1259        struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
1260        struct pending_wmi_event *evt;
1261        u8 *cmd;
1262        void __iomem *src;
1263        ulong flags;
1264        unsigned n;
1265        unsigned int num_immed_reply = 0;
1266
1267        if (!test_bit(wil_status_mbox_ready, wil->status)) {
1268                wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
1269                return;
1270        }
1271
1272        if (test_bit(wil_status_suspended, wil->status)) {
1273                wil_err(wil, "suspended. cannot handle WMI event\n");
1274                return;
1275        }
1276
1277        for (n = 0;; n++) {
1278                u16 len;
1279                bool q;
1280                bool immed_reply = false;
1281
1282                r->head = wil_r(wil, RGF_MBOX +
1283                                offsetof(struct wil6210_mbox_ctl, rx.head));
1284                if (r->tail == r->head)
1285                        break;
1286
1287                wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
1288                            r->head, r->tail);
1289                /* read cmd descriptor from tail */
1290                wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
1291                                     sizeof(struct wil6210_mbox_ring_desc));
1292                if (d_tail.sync == 0) {
1293                        wil_err(wil, "Mbox evt not owned by FW?\n");
1294                        break;
1295                }
1296
1297                /* read cmd header from descriptor */
1298                if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
1299                        wil_err(wil, "Mbox evt at 0x%08x?\n",
1300                                le32_to_cpu(d_tail.addr));
1301                        break;
1302                }
1303                len = le16_to_cpu(hdr.len);
1304                wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
1305                            le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
1306                            hdr.flags);
1307
1308                /* read cmd buffer from descriptor */
1309                src = wmi_buffer(wil, d_tail.addr) +
1310                      sizeof(struct wil6210_mbox_hdr);
1311                evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
1312                                             event.wmi) + len, 4),
1313                              GFP_KERNEL);
1314                if (!evt)
1315                        break;
1316
1317                evt->event.hdr = hdr;
1318                cmd = (void *)&evt->event.wmi;
1319                wil_memcpy_fromio_32(cmd, src, len);
1320                /* mark entry as empty */
1321                wil_w(wil, r->tail +
1322                      offsetof(struct wil6210_mbox_ring_desc, sync), 0);
1323                /* indicate */
1324                if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
1325                    (len >= sizeof(struct wmi_cmd_hdr))) {
1326                        struct wmi_cmd_hdr *wmi = &evt->event.wmi;
1327                        u16 id = le16_to_cpu(wmi->command_id);
1328                        u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
1329                        if (test_bit(wil_status_resuming, wil->status)) {
1330                                if (id == WMI_TRAFFIC_RESUME_EVENTID)
1331                                        clear_bit(wil_status_resuming,
1332                                                  wil->status);
1333                                else
1334                                        wil_err(wil,
1335                                                "WMI evt %d while resuming\n",
1336                                                id);
1337                        }
1338                        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1339                        if (wil->reply_id && wil->reply_id == id) {
1340                                if (wil->reply_buf) {
1341                                        memcpy(wil->reply_buf, wmi,
1342                                               min(len, wil->reply_size));
1343                                        immed_reply = true;
1344                                }
1345                                if (id == WMI_TRAFFIC_SUSPEND_EVENTID) {
1346                                        wil_dbg_wmi(wil,
1347                                                    "set suspend_resp_rcvd\n");
1348                                        wil->suspend_resp_rcvd = true;
1349                                }
1350                        }
1351                        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1352
1353                        wil_dbg_wmi(wil, "recv %s (0x%04x) MID %d @%d msec\n",
1354                                    eventid2name(id), id, wmi->mid, tstamp);
1355                        trace_wil6210_wmi_event(wmi, &wmi[1],
1356                                                len - sizeof(*wmi));
1357                }
1358                wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
1359                                 &evt->event.hdr, sizeof(hdr) + len, true);
1360
1361                /* advance tail */
1362                r->tail = r->base + ((r->tail - r->base +
1363                          sizeof(struct wil6210_mbox_ring_desc)) % r->size);
1364                wil_w(wil, RGF_MBOX +
1365                      offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
1366
1367                if (immed_reply) {
1368                        wil_dbg_wmi(wil, "recv_cmd: Complete WMI 0x%04x\n",
1369                                    wil->reply_id);
1370                        kfree(evt);
1371                        num_immed_reply++;
1372                        complete(&wil->wmi_call);
1373                } else {
1374                        /* add to the pending list */
1375                        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1376                        list_add_tail(&evt->list, &wil->pending_wmi_ev);
1377                        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1378                        q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
1379                        wil_dbg_wmi(wil, "queue_work -> %d\n", q);
1380                }
1381        }
1382        /* normally, 1 event per IRQ should be processed */
1383        wil_dbg_wmi(wil, "recv_cmd: -> %d events queued, %d completed\n",
1384                    n - num_immed_reply, num_immed_reply);
1385}
1386
1387int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
1388             u16 reply_id, void *reply, u8 reply_size, int to_msec)
1389{
1390        int rc;
1391        unsigned long remain;
1392
1393        mutex_lock(&wil->wmi_mutex);
1394
1395        spin_lock(&wil->wmi_ev_lock);
1396        wil->reply_id = reply_id;
1397        wil->reply_buf = reply;
1398        wil->reply_size = reply_size;
1399        reinit_completion(&wil->wmi_call);
1400        spin_unlock(&wil->wmi_ev_lock);
1401
1402        rc = __wmi_send(wil, cmdid, buf, len);
1403        if (rc)
1404                goto out;
1405
1406        remain = wait_for_completion_timeout(&wil->wmi_call,
1407                                             msecs_to_jiffies(to_msec));
1408        if (0 == remain) {
1409                wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
1410                        cmdid, reply_id, to_msec);
1411                rc = -ETIME;
1412        } else {
1413                wil_dbg_wmi(wil,
1414                            "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
1415                            cmdid, reply_id,
1416                            to_msec - jiffies_to_msecs(remain));
1417        }
1418
1419out:
1420        spin_lock(&wil->wmi_ev_lock);
1421        wil->reply_id = 0;
1422        wil->reply_buf = NULL;
1423        wil->reply_size = 0;
1424        spin_unlock(&wil->wmi_ev_lock);
1425
1426        mutex_unlock(&wil->wmi_mutex);
1427
1428        return rc;
1429}
1430
1431int wmi_echo(struct wil6210_priv *wil)
1432{
1433        struct wmi_echo_cmd cmd = {
1434                .value = cpu_to_le32(0x12345678),
1435        };
1436
1437        return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
1438                        WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
1439}
1440
1441int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
1442{
1443        struct wmi_set_mac_address_cmd cmd;
1444
1445        ether_addr_copy(cmd.mac, addr);
1446
1447        wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
1448
1449        return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
1450}
1451
1452int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
1453{
1454        int rc = 0;
1455        struct wmi_led_cfg_cmd cmd = {
1456                .led_mode = enable,
1457                .id = led_id,
1458                .slow_blink_cfg.blink_on =
1459                        cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].on_ms),
1460                .slow_blink_cfg.blink_off =
1461                        cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].off_ms),
1462                .medium_blink_cfg.blink_on =
1463                        cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].on_ms),
1464                .medium_blink_cfg.blink_off =
1465                        cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].off_ms),
1466                .fast_blink_cfg.blink_on =
1467                        cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].on_ms),
1468                .fast_blink_cfg.blink_off =
1469                        cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].off_ms),
1470                .led_polarity = led_polarity,
1471        };
1472        struct {
1473                struct wmi_cmd_hdr wmi;
1474                struct wmi_led_cfg_done_event evt;
1475        } __packed reply;
1476
1477        if (led_id == WIL_LED_INVALID_ID)
1478                goto out;
1479
1480        if (led_id > WIL_LED_MAX_ID) {
1481                wil_err(wil, "Invalid led id %d\n", led_id);
1482                rc = -EINVAL;
1483                goto out;
1484        }
1485
1486        wil_dbg_wmi(wil,
1487                    "%s led %d\n",
1488                    enable ? "enabling" : "disabling", led_id);
1489
1490        rc = wmi_call(wil, WMI_LED_CFG_CMDID, &cmd, sizeof(cmd),
1491                      WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
1492                      100);
1493        if (rc)
1494                goto out;
1495
1496        if (reply.evt.status) {
1497                wil_err(wil, "led %d cfg failed with status %d\n",
1498                        led_id, le32_to_cpu(reply.evt.status));
1499                rc = -EINVAL;
1500        }
1501
1502out:
1503        return rc;
1504}
1505
1506int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
1507                  u8 chan, u8 hidden_ssid, u8 is_go)
1508{
1509        int rc;
1510
1511        struct wmi_pcp_start_cmd cmd = {
1512                .bcon_interval = cpu_to_le16(bi),
1513                .network_type = wmi_nettype,
1514                .disable_sec_offload = 1,
1515                .channel = chan - 1,
1516                .pcp_max_assoc_sta = max_assoc_sta,
1517                .hidden_ssid = hidden_ssid,
1518                .is_go = is_go,
1519                .disable_ap_sme = disable_ap_sme,
1520                .abft_len = wil->abft_len,
1521        };
1522        struct {
1523                struct wmi_cmd_hdr wmi;
1524                struct wmi_pcp_started_event evt;
1525        } __packed reply;
1526
1527        if (!wil->privacy)
1528                cmd.disable_sec = 1;
1529
1530        if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
1531            (cmd.pcp_max_assoc_sta <= 0)) {
1532                wil_info(wil,
1533                         "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
1534                         max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
1535                cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
1536        }
1537
1538        if (disable_ap_sme &&
1539            !test_bit(WMI_FW_CAPABILITY_DISABLE_AP_SME,
1540                      wil->fw_capabilities)) {
1541                wil_err(wil, "disable_ap_sme not supported by FW\n");
1542                return -EOPNOTSUPP;
1543        }
1544
1545        /*
1546         * Processing time may be huge, in case of secure AP it takes about
1547         * 3500ms for FW to start AP
1548         */
1549        rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
1550                      WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
1551        if (rc)
1552                return rc;
1553
1554        if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
1555                rc = -EINVAL;
1556
1557        if (wmi_nettype != WMI_NETTYPE_P2P)
1558                /* Don't fail due to error in the led configuration */
1559                wmi_led_cfg(wil, true);
1560
1561        return rc;
1562}
1563
1564int wmi_pcp_stop(struct wil6210_priv *wil)
1565{
1566        int rc;
1567
1568        rc = wmi_led_cfg(wil, false);
1569        if (rc)
1570                return rc;
1571
1572        return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
1573                        WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
1574}
1575
1576int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
1577{
1578        struct wmi_set_ssid_cmd cmd = {
1579                .ssid_len = cpu_to_le32(ssid_len),
1580        };
1581
1582        if (ssid_len > sizeof(cmd.ssid))
1583                return -EINVAL;
1584
1585        memcpy(cmd.ssid, ssid, ssid_len);
1586
1587        return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
1588}
1589
1590int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
1591{
1592        int rc;
1593        struct {
1594                struct wmi_cmd_hdr wmi;
1595                struct wmi_set_ssid_cmd cmd;
1596        } __packed reply;
1597        int len; /* reply.cmd.ssid_len in CPU order */
1598
1599        rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
1600                      &reply, sizeof(reply), 20);
1601        if (rc)
1602                return rc;
1603
1604        len = le32_to_cpu(reply.cmd.ssid_len);
1605        if (len > sizeof(reply.cmd.ssid))
1606                return -EINVAL;
1607
1608        *ssid_len = len;
1609        memcpy(ssid, reply.cmd.ssid, len);
1610
1611        return 0;
1612}
1613
1614int wmi_set_channel(struct wil6210_priv *wil, int channel)
1615{
1616        struct wmi_set_pcp_channel_cmd cmd = {
1617                .channel = channel - 1,
1618        };
1619
1620        return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
1621}
1622
1623int wmi_get_channel(struct wil6210_priv *wil, int *channel)
1624{
1625        int rc;
1626        struct {
1627                struct wmi_cmd_hdr wmi;
1628                struct wmi_set_pcp_channel_cmd cmd;
1629        } __packed reply;
1630
1631        rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
1632                      WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
1633        if (rc)
1634                return rc;
1635
1636        if (reply.cmd.channel > 3)
1637                return -EINVAL;
1638
1639        *channel = reply.cmd.channel + 1;
1640
1641        return 0;
1642}
1643
1644int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
1645{
1646        int rc;
1647        struct wmi_p2p_cfg_cmd cmd = {
1648                .discovery_mode = WMI_DISCOVERY_MODE_PEER2PEER,
1649                .bcon_interval = cpu_to_le16(bi),
1650                .channel = channel - 1,
1651        };
1652        struct {
1653                struct wmi_cmd_hdr wmi;
1654                struct wmi_p2p_cfg_done_event evt;
1655        } __packed reply;
1656
1657        wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n");
1658
1659        rc = wmi_call(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd),
1660                      WMI_P2P_CFG_DONE_EVENTID, &reply, sizeof(reply), 300);
1661        if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1662                wil_err(wil, "P2P_CFG failed. status %d\n", reply.evt.status);
1663                rc = -EINVAL;
1664        }
1665
1666        return rc;
1667}
1668
1669int wmi_start_listen(struct wil6210_priv *wil)
1670{
1671        int rc;
1672        struct {
1673                struct wmi_cmd_hdr wmi;
1674                struct wmi_listen_started_event evt;
1675        } __packed reply;
1676
1677        wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n");
1678
1679        rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
1680                      WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 300);
1681        if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1682                wil_err(wil, "device failed to start listen. status %d\n",
1683                        reply.evt.status);
1684                rc = -EINVAL;
1685        }
1686
1687        return rc;
1688}
1689
1690int wmi_start_search(struct wil6210_priv *wil)
1691{
1692        int rc;
1693        struct {
1694                struct wmi_cmd_hdr wmi;
1695                struct wmi_search_started_event evt;
1696        } __packed reply;
1697
1698        wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n");
1699
1700        rc = wmi_call(wil, WMI_START_SEARCH_CMDID, NULL, 0,
1701                      WMI_SEARCH_STARTED_EVENTID, &reply, sizeof(reply), 300);
1702        if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1703                wil_err(wil, "device failed to start search. status %d\n",
1704                        reply.evt.status);
1705                rc = -EINVAL;
1706        }
1707
1708        return rc;
1709}
1710
1711int wmi_stop_discovery(struct wil6210_priv *wil)
1712{
1713        int rc;
1714
1715        wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
1716
1717        rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
1718                      WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
1719
1720        if (rc)
1721                wil_err(wil, "Failed to stop discovery\n");
1722
1723        return rc;
1724}
1725
1726int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
1727                       const void *mac_addr, int key_usage)
1728{
1729        struct wmi_delete_cipher_key_cmd cmd = {
1730                .key_index = key_index,
1731        };
1732
1733        if (mac_addr)
1734                memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1735
1736        return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1737}
1738
1739int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
1740                       const void *mac_addr, int key_len, const void *key,
1741                       int key_usage)
1742{
1743        struct wmi_add_cipher_key_cmd cmd = {
1744                .key_index = key_index,
1745                .key_usage = key_usage,
1746                .key_len = key_len,
1747        };
1748
1749        if (!key || (key_len > sizeof(cmd.key)))
1750                return -EINVAL;
1751
1752        memcpy(cmd.key, key, key_len);
1753        if (mac_addr)
1754                memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1755
1756        return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1757}
1758
1759int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
1760{
1761        static const char *const names[] = {
1762                [WMI_FRAME_BEACON]      = "BEACON",
1763                [WMI_FRAME_PROBE_REQ]   = "PROBE_REQ",
1764                [WMI_FRAME_PROBE_RESP]  = "WMI_FRAME_PROBE_RESP",
1765                [WMI_FRAME_ASSOC_REQ]   = "WMI_FRAME_ASSOC_REQ",
1766                [WMI_FRAME_ASSOC_RESP]  = "WMI_FRAME_ASSOC_RESP",
1767        };
1768        int rc;
1769        u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
1770        struct wmi_set_appie_cmd *cmd;
1771
1772        if (len < ie_len) {
1773                rc = -EINVAL;
1774                goto out;
1775        }
1776
1777        cmd = kzalloc(len, GFP_KERNEL);
1778        if (!cmd) {
1779                rc = -ENOMEM;
1780                goto out;
1781        }
1782        if (!ie)
1783                ie_len = 0;
1784
1785        cmd->mgmt_frm_type = type;
1786        /* BUG: FW API define ieLen as u8. Will fix FW */
1787        cmd->ie_len = cpu_to_le16(ie_len);
1788        memcpy(cmd->ie_info, ie, ie_len);
1789        rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
1790        kfree(cmd);
1791out:
1792        if (rc) {
1793                const char *name = type < ARRAY_SIZE(names) ?
1794                                   names[type] : "??";
1795                wil_err(wil, "set_ie(%d %s) failed : %d\n", type, name, rc);
1796        }
1797
1798        return rc;
1799}
1800
1801/**
1802 * wmi_rxon - turn radio on/off
1803 * @on:         turn on if true, off otherwise
1804 *
1805 * Only switch radio. Channel should be set separately.
1806 * No timeout for rxon - radio turned on forever unless some other call
1807 * turns it off
1808 */
1809int wmi_rxon(struct wil6210_priv *wil, bool on)
1810{
1811        int rc;
1812        struct {
1813                struct wmi_cmd_hdr wmi;
1814                struct wmi_listen_started_event evt;
1815        } __packed reply;
1816
1817        wil_info(wil, "(%s)\n", on ? "on" : "off");
1818
1819        if (on) {
1820                rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
1821                              WMI_LISTEN_STARTED_EVENTID,
1822                              &reply, sizeof(reply), 100);
1823                if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
1824                        rc = -EINVAL;
1825        } else {
1826                rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
1827                              WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
1828        }
1829
1830        return rc;
1831}
1832
1833int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
1834{
1835        struct wireless_dev *wdev = wil->wdev;
1836        struct net_device *ndev = wil_to_ndev(wil);
1837        struct wmi_cfg_rx_chain_cmd cmd = {
1838                .action = WMI_RX_CHAIN_ADD,
1839                .rx_sw_ring = {
1840                        .max_mpdu_size = cpu_to_le16(
1841                                wil_mtu2macbuf(wil->rx_buf_len)),
1842                        .ring_mem_base = cpu_to_le64(vring->pa),
1843                        .ring_size = cpu_to_le16(vring->size),
1844                },
1845                .mid = 0, /* TODO - what is it? */
1846                .decap_trans_type = WMI_DECAP_TYPE_802_3,
1847                .reorder_type = WMI_RX_SW_REORDER,
1848                .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
1849        };
1850        struct {
1851                struct wmi_cmd_hdr wmi;
1852                struct wmi_cfg_rx_chain_done_event evt;
1853        } __packed evt;
1854        int rc;
1855
1856        if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
1857                struct ieee80211_channel *ch = wil->monitor_chandef.chan;
1858
1859                cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
1860                if (ch)
1861                        cmd.sniffer_cfg.channel = ch->hw_value - 1;
1862                cmd.sniffer_cfg.phy_info_mode =
1863                        cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
1864                cmd.sniffer_cfg.phy_support =
1865                        cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
1866                                    ? WMI_SNIFFER_CP : WMI_SNIFFER_BOTH_PHYS);
1867        } else {
1868                /* Initialize offload (in non-sniffer mode).
1869                 * Linux IP stack always calculates IP checksum
1870                 * HW always calculate TCP/UDP checksum
1871                 */
1872                cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
1873        }
1874
1875        if (rx_align_2)
1876                cmd.l2_802_3_offload_ctrl |=
1877                                L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK;
1878
1879        /* typical time for secure PCP is 840ms */
1880        rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
1881                      WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
1882        if (rc)
1883                return rc;
1884
1885        vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
1886
1887        wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
1888                     le32_to_cpu(evt.evt.status), vring->hwtail);
1889
1890        if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
1891                rc = -EINVAL;
1892
1893        return rc;
1894}
1895
1896int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
1897{
1898        int rc;
1899        struct wmi_temp_sense_cmd cmd = {
1900                .measure_baseband_en = cpu_to_le32(!!t_bb),
1901                .measure_rf_en = cpu_to_le32(!!t_rf),
1902                .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
1903        };
1904        struct {
1905                struct wmi_cmd_hdr wmi;
1906                struct wmi_temp_sense_done_event evt;
1907        } __packed reply;
1908
1909        rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
1910                      WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
1911        if (rc)
1912                return rc;
1913
1914        if (t_bb)
1915                *t_bb = le32_to_cpu(reply.evt.baseband_t1000);
1916        if (t_rf)
1917                *t_rf = le32_to_cpu(reply.evt.rf_t1000);
1918
1919        return 0;
1920}
1921
1922int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
1923                       u16 reason, bool full_disconnect, bool del_sta)
1924{
1925        int rc;
1926        u16 reason_code;
1927        struct wmi_disconnect_sta_cmd disc_sta_cmd = {
1928                .disconnect_reason = cpu_to_le16(reason),
1929        };
1930        struct wmi_del_sta_cmd del_sta_cmd = {
1931                .disconnect_reason = cpu_to_le16(reason),
1932        };
1933        struct {
1934                struct wmi_cmd_hdr wmi;
1935                struct wmi_disconnect_event evt;
1936        } __packed reply;
1937
1938        wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
1939
1940        wil->locally_generated_disc = true;
1941        if (del_sta) {
1942                ether_addr_copy(del_sta_cmd.dst_mac, mac);
1943                rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
1944                              sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID,
1945                              &reply, sizeof(reply), 1000);
1946        } else {
1947                ether_addr_copy(disc_sta_cmd.dst_mac, mac);
1948                rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &disc_sta_cmd,
1949                              sizeof(disc_sta_cmd), WMI_DISCONNECT_EVENTID,
1950                              &reply, sizeof(reply), 1000);
1951        }
1952        /* failure to disconnect in reasonable time treated as FW error */
1953        if (rc) {
1954                wil_fw_error_recovery(wil);
1955                return rc;
1956        }
1957
1958        if (full_disconnect) {
1959                /* call event handler manually after processing wmi_call,
1960                 * to avoid deadlock - disconnect event handler acquires
1961                 * wil->mutex while it is already held here
1962                 */
1963                reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
1964
1965                wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
1966                            reply.evt.bssid, reason_code,
1967                            reply.evt.disconnect_reason);
1968
1969                wil->sinfo_gen++;
1970                wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
1971        }
1972        return 0;
1973}
1974
1975int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
1976{
1977        struct wmi_vring_ba_en_cmd cmd = {
1978                .ringid = ringid,
1979                .agg_max_wsize = size,
1980                .ba_timeout = cpu_to_le16(timeout),
1981                .amsdu = 0,
1982        };
1983
1984        wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size,
1985                    timeout);
1986
1987        return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
1988}
1989
1990int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
1991{
1992        struct wmi_vring_ba_dis_cmd cmd = {
1993                .ringid = ringid,
1994                .reason = cpu_to_le16(reason),
1995        };
1996
1997        wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason);
1998
1999        return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
2000}
2001
2002int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
2003{
2004        struct wmi_rcp_delba_cmd cmd = {
2005                .cidxtid = cidxtid,
2006                .reason = cpu_to_le16(reason),
2007        };
2008
2009        wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf,
2010                    (cidxtid >> 4) & 0xf, reason);
2011
2012        return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
2013}
2014
2015int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
2016                      u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
2017{
2018        int rc;
2019        struct wmi_rcp_addba_resp_cmd cmd = {
2020                .cidxtid = mk_cidxtid(cid, tid),
2021                .dialog_token = token,
2022                .status_code = cpu_to_le16(status),
2023                /* bit 0: A-MSDU supported
2024                 * bit 1: policy (should be 0 for us)
2025                 * bits 2..5: TID
2026                 * bits 6..15: buffer size
2027                 */
2028                .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
2029                                            (agg_wsize << 6)),
2030                .ba_timeout = cpu_to_le16(timeout),
2031        };
2032        struct {
2033                struct wmi_cmd_hdr wmi;
2034                struct wmi_rcp_addba_resp_sent_event evt;
2035        } __packed reply;
2036
2037        wil_dbg_wmi(wil,
2038                    "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
2039                    cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
2040
2041        rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
2042                      WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
2043                      100);
2044        if (rc)
2045                return rc;
2046
2047        if (reply.evt.status) {
2048                wil_err(wil, "ADDBA response failed with status %d\n",
2049                        le16_to_cpu(reply.evt.status));
2050                rc = -EINVAL;
2051        }
2052
2053        return rc;
2054}
2055
2056int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
2057                           enum wmi_ps_profile_type ps_profile)
2058{
2059        int rc;
2060        struct wmi_ps_dev_profile_cfg_cmd cmd = {
2061                .ps_profile = ps_profile,
2062        };
2063        struct {
2064                struct wmi_cmd_hdr wmi;
2065                struct wmi_ps_dev_profile_cfg_event evt;
2066        } __packed reply;
2067        u32 status;
2068
2069        wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile);
2070
2071        reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR);
2072
2073        rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd),
2074                      WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
2075                      100);
2076        if (rc)
2077                return rc;
2078
2079        status = le32_to_cpu(reply.evt.status);
2080
2081        if (status != WMI_PS_CFG_CMD_STATUS_SUCCESS) {
2082                wil_err(wil, "ps dev profile cfg failed with status %d\n",
2083                        status);
2084                rc = -EINVAL;
2085        }
2086
2087        return rc;
2088}
2089
2090int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
2091{
2092        int rc;
2093        struct wmi_set_mgmt_retry_limit_cmd cmd = {
2094                .mgmt_retry_limit = retry_short,
2095        };
2096        struct {
2097                struct wmi_cmd_hdr wmi;
2098                struct wmi_set_mgmt_retry_limit_event evt;
2099        } __packed reply;
2100
2101        wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short);
2102
2103        if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2104                return -ENOTSUPP;
2105
2106        reply.evt.status = WMI_FW_STATUS_FAILURE;
2107
2108        rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd),
2109                      WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
2110                      100);
2111        if (rc)
2112                return rc;
2113
2114        if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
2115                wil_err(wil, "set mgmt retry limit failed with status %d\n",
2116                        reply.evt.status);
2117                rc = -EINVAL;
2118        }
2119
2120        return rc;
2121}
2122
2123int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
2124{
2125        int rc;
2126        struct {
2127                struct wmi_cmd_hdr wmi;
2128                struct wmi_get_mgmt_retry_limit_event evt;
2129        } __packed reply;
2130
2131        wil_dbg_wmi(wil, "getting mgmt retry short\n");
2132
2133        if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2134                return -ENOTSUPP;
2135
2136        reply.evt.mgmt_retry_limit = 0;
2137        rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0,
2138                      WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
2139                      100);
2140        if (rc)
2141                return rc;
2142
2143        if (retry_short)
2144                *retry_short = reply.evt.mgmt_retry_limit;
2145
2146        return 0;
2147}
2148
2149int wmi_abort_scan(struct wil6210_priv *wil)
2150{
2151        int rc;
2152
2153        wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
2154
2155        rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0);
2156        if (rc)
2157                wil_err(wil, "Failed to abort scan (%d)\n", rc);
2158
2159        return rc;
2160}
2161
2162int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
2163{
2164        int rc;
2165        struct wmi_new_sta_cmd cmd = {
2166                .aid = aid,
2167        };
2168
2169        wil_dbg_wmi(wil, "new sta %pM, aid %d\n", mac, aid);
2170
2171        ether_addr_copy(cmd.dst_mac, mac);
2172
2173        rc = wmi_send(wil, WMI_NEW_STA_CMDID, &cmd, sizeof(cmd));
2174        if (rc)
2175                wil_err(wil, "Failed to send new sta (%d)\n", rc);
2176
2177        return rc;
2178}
2179
2180void wmi_event_flush(struct wil6210_priv *wil)
2181{
2182        ulong flags;
2183        struct pending_wmi_event *evt, *t;
2184
2185        wil_dbg_wmi(wil, "event_flush\n");
2186
2187        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2188
2189        list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
2190                list_del(&evt->list);
2191                kfree(evt);
2192        }
2193
2194        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2195}
2196
2197static const char *suspend_status2name(u8 status)
2198{
2199        switch (status) {
2200        case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
2201                return "LINK_NOT_IDLE";
2202        default:
2203                return "Untracked status";
2204        }
2205}
2206
2207int wmi_suspend(struct wil6210_priv *wil)
2208{
2209        int rc;
2210        struct wmi_traffic_suspend_cmd cmd = {
2211                .wakeup_trigger = wil->wakeup_trigger,
2212        };
2213        struct {
2214                struct wmi_cmd_hdr wmi;
2215                struct wmi_traffic_suspend_event evt;
2216        } __packed reply;
2217        u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP;
2218
2219        wil->suspend_resp_rcvd = false;
2220        wil->suspend_resp_comp = false;
2221
2222        reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE;
2223
2224        rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd),
2225                      WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply),
2226                      suspend_to);
2227        if (rc) {
2228                wil_err(wil, "wmi_call for suspend req failed, rc=%d\n", rc);
2229                if (rc == -ETIME)
2230                        /* wmi_call TO */
2231                        wil->suspend_stats.rejected_by_device++;
2232                else
2233                        wil->suspend_stats.rejected_by_host++;
2234                goto out;
2235        }
2236
2237        wil_dbg_wmi(wil, "waiting for suspend_response_completed\n");
2238
2239        rc = wait_event_interruptible_timeout(wil->wq,
2240                                              wil->suspend_resp_comp,
2241                                              msecs_to_jiffies(suspend_to));
2242        if (rc == 0) {
2243                wil_err(wil, "TO waiting for suspend_response_completed\n");
2244                if (wil->suspend_resp_rcvd)
2245                        /* Device responded but we TO due to another reason */
2246                        wil->suspend_stats.rejected_by_host++;
2247                else
2248                        wil->suspend_stats.rejected_by_device++;
2249                rc = -EBUSY;
2250                goto out;
2251        }
2252
2253        wil_dbg_wmi(wil, "suspend_response_completed rcvd\n");
2254        if (reply.evt.status != WMI_TRAFFIC_SUSPEND_APPROVED) {
2255                wil_dbg_pm(wil, "device rejected the suspend, %s\n",
2256                           suspend_status2name(reply.evt.status));
2257                wil->suspend_stats.rejected_by_device++;
2258        }
2259        rc = reply.evt.status;
2260
2261out:
2262        wil->suspend_resp_rcvd = false;
2263        wil->suspend_resp_comp = false;
2264
2265        return rc;
2266}
2267
2268static void resume_triggers2string(u32 triggers, char *string, int str_size)
2269{
2270        string[0] = '\0';
2271
2272        if (!triggers) {
2273                strlcat(string, " UNKNOWN", str_size);
2274                return;
2275        }
2276
2277        if (triggers & WMI_RESUME_TRIGGER_HOST)
2278                strlcat(string, " HOST", str_size);
2279
2280        if (triggers & WMI_RESUME_TRIGGER_UCAST_RX)
2281                strlcat(string, " UCAST_RX", str_size);
2282
2283        if (triggers & WMI_RESUME_TRIGGER_BCAST_RX)
2284                strlcat(string, " BCAST_RX", str_size);
2285
2286        if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
2287                strlcat(string, " WMI_EVT", str_size);
2288}
2289
2290int wmi_resume(struct wil6210_priv *wil)
2291{
2292        int rc;
2293        char string[100];
2294        struct {
2295                struct wmi_cmd_hdr wmi;
2296                struct wmi_traffic_resume_event evt;
2297        } __packed reply;
2298
2299        reply.evt.status = WMI_TRAFFIC_RESUME_FAILED;
2300        reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN;
2301
2302        rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0,
2303                      WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply),
2304                      WIL_WAIT_FOR_SUSPEND_RESUME_COMP);
2305        if (rc)
2306                return rc;
2307        resume_triggers2string(le32_to_cpu(reply.evt.resume_triggers), string,
2308                               sizeof(string));
2309        wil_dbg_pm(wil, "device resume %s, resume triggers:%s (0x%x)\n",
2310                   reply.evt.status ? "failed" : "passed", string,
2311                   le32_to_cpu(reply.evt.resume_triggers));
2312
2313        return reply.evt.status;
2314}
2315
2316static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
2317                                 void *d, int len)
2318{
2319        uint i;
2320
2321        for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
2322                if (wmi_evt_handlers[i].eventid == id) {
2323                        wmi_evt_handlers[i].handler(wil, id, d, len);
2324                        return true;
2325                }
2326        }
2327
2328        return false;
2329}
2330
2331static void wmi_event_handle(struct wil6210_priv *wil,
2332                             struct wil6210_mbox_hdr *hdr)
2333{
2334        u16 len = le16_to_cpu(hdr->len);
2335
2336        if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
2337            (len >= sizeof(struct wmi_cmd_hdr))) {
2338                struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]);
2339                void *evt_data = (void *)(&wmi[1]);
2340                u16 id = le16_to_cpu(wmi->command_id);
2341
2342                wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x)\n",
2343                            eventid2name(id), id, wil->reply_id);
2344                /* check if someone waits for this event */
2345                if (wil->reply_id && wil->reply_id == id) {
2346                        WARN_ON(wil->reply_buf);
2347                        wmi_evt_call_handler(wil, id, evt_data,
2348                                             len - sizeof(*wmi));
2349                        wil_dbg_wmi(wil, "event_handle: Complete WMI 0x%04x\n",
2350                                    id);
2351                        complete(&wil->wmi_call);
2352                        return;
2353                }
2354                /* unsolicited event */
2355                /* search for handler */
2356                if (!wmi_evt_call_handler(wil, id, evt_data,
2357                                          len - sizeof(*wmi))) {
2358                        wil_info(wil, "Unhandled event 0x%04x\n", id);
2359                }
2360        } else {
2361                wil_err(wil, "Unknown event type\n");
2362                print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
2363                               hdr, sizeof(*hdr) + len, true);
2364        }
2365}
2366
2367/*
2368 * Retrieve next WMI event from the pending list
2369 */
2370static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
2371{
2372        ulong flags;
2373        struct list_head *ret = NULL;
2374
2375        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2376
2377        if (!list_empty(&wil->pending_wmi_ev)) {
2378                ret = wil->pending_wmi_ev.next;
2379                list_del(ret);
2380        }
2381
2382        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2383
2384        return ret;
2385}
2386
2387/*
2388 * Handler for the WMI events
2389 */
2390void wmi_event_worker(struct work_struct *work)
2391{
2392        struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
2393                                                 wmi_event_worker);
2394        struct pending_wmi_event *evt;
2395        struct list_head *lh;
2396
2397        wil_dbg_wmi(wil, "event_worker: Start\n");
2398        while ((lh = next_wmi_ev(wil)) != NULL) {
2399                evt = list_entry(lh, struct pending_wmi_event, list);
2400                wmi_event_handle(wil, &evt->event.hdr);
2401                kfree(evt);
2402        }
2403        wil_dbg_wmi(wil, "event_worker: Finished\n");
2404}
2405
2406bool wil_is_wmi_idle(struct wil6210_priv *wil)
2407{
2408        ulong flags;
2409        struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
2410        bool rc = false;
2411
2412        spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2413
2414        /* Check if there are pending WMI events in the events queue */
2415        if (!list_empty(&wil->pending_wmi_ev)) {
2416                wil_dbg_pm(wil, "Pending WMI events in queue\n");
2417                goto out;
2418        }
2419
2420        /* Check if there is a pending WMI call */
2421        if (wil->reply_id) {
2422                wil_dbg_pm(wil, "Pending WMI call\n");
2423                goto out;
2424        }
2425
2426        /* Check if there are pending RX events in mbox */
2427        r->head = wil_r(wil, RGF_MBOX +
2428                        offsetof(struct wil6210_mbox_ctl, rx.head));
2429        if (r->tail != r->head)
2430                wil_dbg_pm(wil, "Pending WMI mbox events\n");
2431        else
2432                rc = true;
2433
2434out:
2435        spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2436        return rc;
2437}
2438
2439static void
2440wmi_sched_scan_set_ssids(struct wil6210_priv *wil,
2441                         struct wmi_start_sched_scan_cmd *cmd,
2442                         struct cfg80211_ssid *ssids, int n_ssids,
2443                         struct cfg80211_match_set *match_sets,
2444                         int n_match_sets)
2445{
2446        int i;
2447
2448        if (n_match_sets > WMI_MAX_PNO_SSID_NUM) {
2449                wil_dbg_wmi(wil, "too many match sets (%d), use first %d\n",
2450                            n_match_sets, WMI_MAX_PNO_SSID_NUM);
2451                n_match_sets = WMI_MAX_PNO_SSID_NUM;
2452        }
2453        cmd->num_of_ssids = n_match_sets;
2454
2455        for (i = 0; i < n_match_sets; i++) {
2456                struct wmi_sched_scan_ssid_match *wmi_match =
2457                        &cmd->ssid_for_match[i];
2458                struct cfg80211_match_set *cfg_match = &match_sets[i];
2459                int j;
2460
2461                wmi_match->ssid_len = cfg_match->ssid.ssid_len;
2462                memcpy(wmi_match->ssid, cfg_match->ssid.ssid,
2463                       min_t(u8, wmi_match->ssid_len, WMI_MAX_SSID_LEN));
2464                wmi_match->rssi_threshold = S8_MIN;
2465                if (cfg_match->rssi_thold >= S8_MIN &&
2466                    cfg_match->rssi_thold <= S8_MAX)
2467                        wmi_match->rssi_threshold = cfg_match->rssi_thold;
2468
2469                for (j = 0; j < n_ssids; j++)
2470                        if (wmi_match->ssid_len == ssids[j].ssid_len &&
2471                            memcmp(wmi_match->ssid, ssids[j].ssid,
2472                                   wmi_match->ssid_len) == 0)
2473                                wmi_match->add_ssid_to_probe = true;
2474        }
2475}
2476
2477static void
2478wmi_sched_scan_set_channels(struct wil6210_priv *wil,
2479                            struct wmi_start_sched_scan_cmd *cmd,
2480                            u32 n_channels,
2481                            struct ieee80211_channel **channels)
2482{
2483        int i;
2484
2485        if (n_channels > WMI_MAX_CHANNEL_NUM) {
2486                wil_dbg_wmi(wil, "too many channels (%d), use first %d\n",
2487                            n_channels, WMI_MAX_CHANNEL_NUM);
2488                n_channels = WMI_MAX_CHANNEL_NUM;
2489        }
2490        cmd->num_of_channels = n_channels;
2491
2492        for (i = 0; i < n_channels; i++) {
2493                struct ieee80211_channel *cfg_chan = channels[i];
2494
2495                cmd->channel_list[i] = cfg_chan->hw_value - 1;
2496        }
2497}
2498
2499static void
2500wmi_sched_scan_set_plans(struct wil6210_priv *wil,
2501                         struct wmi_start_sched_scan_cmd *cmd,
2502                         struct cfg80211_sched_scan_plan *scan_plans,
2503                         int n_scan_plans)
2504{
2505        int i;
2506
2507        if (n_scan_plans > WMI_MAX_PLANS_NUM) {
2508                wil_dbg_wmi(wil, "too many plans (%d), use first %d\n",
2509                            n_scan_plans, WMI_MAX_PLANS_NUM);
2510                n_scan_plans = WMI_MAX_PLANS_NUM;
2511        }
2512
2513        for (i = 0; i < n_scan_plans; i++) {
2514                struct cfg80211_sched_scan_plan *cfg_plan = &scan_plans[i];
2515
2516                cmd->scan_plans[i].interval_sec =
2517                        cpu_to_le16(cfg_plan->interval);
2518                cmd->scan_plans[i].num_of_iterations =
2519                        cpu_to_le16(cfg_plan->iterations);
2520        }
2521}
2522
2523int wmi_start_sched_scan(struct wil6210_priv *wil,
2524                         struct cfg80211_sched_scan_request *request)
2525{
2526        int rc;
2527        struct wmi_start_sched_scan_cmd cmd = {
2528                .min_rssi_threshold = S8_MIN,
2529                .initial_delay_sec = cpu_to_le16(request->delay),
2530        };
2531        struct {
2532                struct wmi_cmd_hdr wmi;
2533                struct wmi_start_sched_scan_event evt;
2534        } __packed reply;
2535
2536        if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2537                return -ENOTSUPP;
2538
2539        if (request->min_rssi_thold >= S8_MIN &&
2540            request->min_rssi_thold <= S8_MAX)
2541                cmd.min_rssi_threshold = request->min_rssi_thold;
2542
2543        wmi_sched_scan_set_ssids(wil, &cmd, request->ssids, request->n_ssids,
2544                                 request->match_sets, request->n_match_sets);
2545        wmi_sched_scan_set_channels(wil, &cmd,
2546                                    request->n_channels, request->channels);
2547        wmi_sched_scan_set_plans(wil, &cmd,
2548                                 request->scan_plans, request->n_scan_plans);
2549
2550        reply.evt.result = WMI_PNO_REJECT;
2551
2552        rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, &cmd, sizeof(cmd),
2553                      WMI_START_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
2554                      WIL_WMI_CALL_GENERAL_TO_MS);
2555        if (rc)
2556                return rc;
2557
2558        if (reply.evt.result != WMI_PNO_SUCCESS) {
2559                wil_err(wil, "start sched scan failed, result %d\n",
2560                        reply.evt.result);
2561                return -EINVAL;
2562        }
2563
2564        return 0;
2565}
2566
2567int wmi_stop_sched_scan(struct wil6210_priv *wil)
2568{
2569        int rc;
2570        struct {
2571                struct wmi_cmd_hdr wmi;
2572                struct wmi_stop_sched_scan_event evt;
2573        } __packed reply;
2574
2575        if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2576                return -ENOTSUPP;
2577
2578        reply.evt.result = WMI_PNO_REJECT;
2579
2580        rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, NULL, 0,
2581                      WMI_STOP_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
2582                      WIL_WMI_CALL_GENERAL_TO_MS);
2583        if (rc)
2584                return rc;
2585
2586        if (reply.evt.result != WMI_PNO_SUCCESS) {
2587                wil_err(wil, "stop sched scan failed, result %d\n",
2588                        reply.evt.result);
2589                return -EINVAL;
2590        }
2591
2592        return 0;
2593}
2594