15e3dd157SKalle Valo /* 25e3dd157SKalle Valo * Copyright (c) 2005-2011 Atheros Communications Inc. 35e3dd157SKalle Valo * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. 45e3dd157SKalle Valo * 55e3dd157SKalle Valo * Permission to use, copy, modify, and/or distribute this software for any 65e3dd157SKalle Valo * purpose with or without fee is hereby granted, provided that the above 75e3dd157SKalle Valo * copyright notice and this permission notice appear in all copies. 85e3dd157SKalle Valo * 95e3dd157SKalle Valo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 105e3dd157SKalle Valo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 115e3dd157SKalle Valo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 125e3dd157SKalle Valo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 135e3dd157SKalle Valo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 145e3dd157SKalle Valo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 155e3dd157SKalle Valo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 165e3dd157SKalle Valo */ 175e3dd157SKalle Valo 185e3dd157SKalle Valo #include <linux/skbuff.h> 195e3dd157SKalle Valo 205e3dd157SKalle Valo #include "core.h" 215e3dd157SKalle Valo #include "htc.h" 225e3dd157SKalle Valo #include "debug.h" 235e3dd157SKalle Valo #include "wmi.h" 245e3dd157SKalle Valo #include "mac.h" 255e3dd157SKalle Valo 265e3dd157SKalle Valo void ath10k_wmi_flush_tx(struct ath10k *ar) 275e3dd157SKalle Valo { 285e3dd157SKalle Valo int ret; 295e3dd157SKalle Valo 305e3dd157SKalle Valo ret = wait_event_timeout(ar->wmi.wq, 315e3dd157SKalle Valo atomic_read(&ar->wmi.pending_tx_count) == 0, 325e3dd157SKalle Valo 5*HZ); 335e3dd157SKalle Valo if (atomic_read(&ar->wmi.pending_tx_count) == 0) 345e3dd157SKalle Valo return; 355e3dd157SKalle Valo 365e3dd157SKalle Valo if (ret == 0) 375e3dd157SKalle Valo ret = -ETIMEDOUT; 385e3dd157SKalle Valo 395e3dd157SKalle Valo if (ret < 0) 405e3dd157SKalle Valo ath10k_warn("wmi flush failed (%d)\n", ret); 415e3dd157SKalle Valo } 425e3dd157SKalle Valo 435e3dd157SKalle Valo int ath10k_wmi_wait_for_service_ready(struct ath10k *ar) 445e3dd157SKalle Valo { 455e3dd157SKalle Valo int ret; 465e3dd157SKalle Valo ret = wait_for_completion_timeout(&ar->wmi.service_ready, 475e3dd157SKalle Valo WMI_SERVICE_READY_TIMEOUT_HZ); 485e3dd157SKalle Valo return ret; 495e3dd157SKalle Valo } 505e3dd157SKalle Valo 515e3dd157SKalle Valo int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar) 525e3dd157SKalle Valo { 535e3dd157SKalle Valo int ret; 545e3dd157SKalle Valo ret = wait_for_completion_timeout(&ar->wmi.unified_ready, 555e3dd157SKalle Valo WMI_UNIFIED_READY_TIMEOUT_HZ); 565e3dd157SKalle Valo return ret; 575e3dd157SKalle Valo } 585e3dd157SKalle Valo 595e3dd157SKalle Valo static struct sk_buff *ath10k_wmi_alloc_skb(u32 len) 605e3dd157SKalle Valo { 615e3dd157SKalle Valo struct sk_buff *skb; 625e3dd157SKalle Valo u32 round_len = roundup(len, 4); 635e3dd157SKalle Valo 645e3dd157SKalle Valo skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len); 655e3dd157SKalle Valo if (!skb) 665e3dd157SKalle Valo return NULL; 675e3dd157SKalle Valo 685e3dd157SKalle Valo skb_reserve(skb, WMI_SKB_HEADROOM); 695e3dd157SKalle Valo if (!IS_ALIGNED((unsigned long)skb->data, 4)) 705e3dd157SKalle Valo ath10k_warn("Unaligned WMI skb\n"); 715e3dd157SKalle Valo 725e3dd157SKalle Valo skb_put(skb, round_len); 735e3dd157SKalle Valo memset(skb->data, 0, round_len); 745e3dd157SKalle Valo 755e3dd157SKalle Valo return skb; 765e3dd157SKalle Valo } 775e3dd157SKalle Valo 785e3dd157SKalle Valo static void ath10k_wmi_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) 795e3dd157SKalle Valo { 805e3dd157SKalle Valo dev_kfree_skb(skb); 815e3dd157SKalle Valo 825e3dd157SKalle Valo if (atomic_sub_return(1, &ar->wmi.pending_tx_count) == 0) 835e3dd157SKalle Valo wake_up(&ar->wmi.wq); 845e3dd157SKalle Valo } 855e3dd157SKalle Valo 865e3dd157SKalle Valo /* WMI command API */ 875e3dd157SKalle Valo static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, 885e3dd157SKalle Valo enum wmi_cmd_id cmd_id) 895e3dd157SKalle Valo { 905e3dd157SKalle Valo struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); 915e3dd157SKalle Valo struct wmi_cmd_hdr *cmd_hdr; 925e3dd157SKalle Valo int status; 935e3dd157SKalle Valo u32 cmd = 0; 945e3dd157SKalle Valo 955e3dd157SKalle Valo if (skb_push(skb, sizeof(struct wmi_cmd_hdr)) == NULL) 965e3dd157SKalle Valo return -ENOMEM; 975e3dd157SKalle Valo 985e3dd157SKalle Valo cmd |= SM(cmd_id, WMI_CMD_HDR_CMD_ID); 995e3dd157SKalle Valo 1005e3dd157SKalle Valo cmd_hdr = (struct wmi_cmd_hdr *)skb->data; 1015e3dd157SKalle Valo cmd_hdr->cmd_id = __cpu_to_le32(cmd); 1025e3dd157SKalle Valo 1035e3dd157SKalle Valo if (atomic_add_return(1, &ar->wmi.pending_tx_count) > 1045e3dd157SKalle Valo WMI_MAX_PENDING_TX_COUNT) { 1055e3dd157SKalle Valo /* avoid using up memory when FW hangs */ 1065e3dd157SKalle Valo atomic_dec(&ar->wmi.pending_tx_count); 1075e3dd157SKalle Valo return -EBUSY; 1085e3dd157SKalle Valo } 1095e3dd157SKalle Valo 1105e3dd157SKalle Valo memset(skb_cb, 0, sizeof(*skb_cb)); 1115e3dd157SKalle Valo 1125e3dd157SKalle Valo trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len); 1135e3dd157SKalle Valo 1145e3dd157SKalle Valo status = ath10k_htc_send(ar->htc, ar->wmi.eid, skb); 1155e3dd157SKalle Valo if (status) { 1165e3dd157SKalle Valo dev_kfree_skb_any(skb); 1175e3dd157SKalle Valo atomic_dec(&ar->wmi.pending_tx_count); 1185e3dd157SKalle Valo return status; 1195e3dd157SKalle Valo } 1205e3dd157SKalle Valo 1215e3dd157SKalle Valo return 0; 1225e3dd157SKalle Valo } 1235e3dd157SKalle Valo 1245e3dd157SKalle Valo static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) 1255e3dd157SKalle Valo { 1265e3dd157SKalle Valo struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data; 1275e3dd157SKalle Valo enum wmi_scan_event_type event_type; 1285e3dd157SKalle Valo enum wmi_scan_completion_reason reason; 1295e3dd157SKalle Valo u32 freq; 1305e3dd157SKalle Valo u32 req_id; 1315e3dd157SKalle Valo u32 scan_id; 1325e3dd157SKalle Valo u32 vdev_id; 1335e3dd157SKalle Valo 1345e3dd157SKalle Valo event_type = __le32_to_cpu(event->event_type); 1355e3dd157SKalle Valo reason = __le32_to_cpu(event->reason); 1365e3dd157SKalle Valo freq = __le32_to_cpu(event->channel_freq); 1375e3dd157SKalle Valo req_id = __le32_to_cpu(event->scan_req_id); 1385e3dd157SKalle Valo scan_id = __le32_to_cpu(event->scan_id); 1395e3dd157SKalle Valo vdev_id = __le32_to_cpu(event->vdev_id); 1405e3dd157SKalle Valo 1415e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n"); 1425e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 1435e3dd157SKalle Valo "scan event type %d reason %d freq %d req_id %d " 1445e3dd157SKalle Valo "scan_id %d vdev_id %d\n", 1455e3dd157SKalle Valo event_type, reason, freq, req_id, scan_id, vdev_id); 1465e3dd157SKalle Valo 1475e3dd157SKalle Valo spin_lock_bh(&ar->data_lock); 1485e3dd157SKalle Valo 1495e3dd157SKalle Valo switch (event_type) { 1505e3dd157SKalle Valo case WMI_SCAN_EVENT_STARTED: 1515e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n"); 1525e3dd157SKalle Valo if (ar->scan.in_progress && ar->scan.is_roc) 1535e3dd157SKalle Valo ieee80211_ready_on_channel(ar->hw); 1545e3dd157SKalle Valo 1555e3dd157SKalle Valo complete(&ar->scan.started); 1565e3dd157SKalle Valo break; 1575e3dd157SKalle Valo case WMI_SCAN_EVENT_COMPLETED: 1585e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n"); 1595e3dd157SKalle Valo switch (reason) { 1605e3dd157SKalle Valo case WMI_SCAN_REASON_COMPLETED: 1615e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n"); 1625e3dd157SKalle Valo break; 1635e3dd157SKalle Valo case WMI_SCAN_REASON_CANCELLED: 1645e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n"); 1655e3dd157SKalle Valo break; 1665e3dd157SKalle Valo case WMI_SCAN_REASON_PREEMPTED: 1675e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n"); 1685e3dd157SKalle Valo break; 1695e3dd157SKalle Valo case WMI_SCAN_REASON_TIMEDOUT: 1705e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n"); 1715e3dd157SKalle Valo break; 1725e3dd157SKalle Valo default: 1735e3dd157SKalle Valo break; 1745e3dd157SKalle Valo } 1755e3dd157SKalle Valo 1765e3dd157SKalle Valo ar->scan_channel = NULL; 1775e3dd157SKalle Valo if (!ar->scan.in_progress) { 1785e3dd157SKalle Valo ath10k_warn("no scan requested, ignoring\n"); 1795e3dd157SKalle Valo break; 1805e3dd157SKalle Valo } 1815e3dd157SKalle Valo 1825e3dd157SKalle Valo if (ar->scan.is_roc) { 1835e3dd157SKalle Valo ath10k_offchan_tx_purge(ar); 1845e3dd157SKalle Valo 1855e3dd157SKalle Valo if (!ar->scan.aborting) 1865e3dd157SKalle Valo ieee80211_remain_on_channel_expired(ar->hw); 1875e3dd157SKalle Valo } else { 1885e3dd157SKalle Valo ieee80211_scan_completed(ar->hw, ar->scan.aborting); 1895e3dd157SKalle Valo } 1905e3dd157SKalle Valo 1915e3dd157SKalle Valo del_timer(&ar->scan.timeout); 1925e3dd157SKalle Valo complete_all(&ar->scan.completed); 1935e3dd157SKalle Valo ar->scan.in_progress = false; 1945e3dd157SKalle Valo break; 1955e3dd157SKalle Valo case WMI_SCAN_EVENT_BSS_CHANNEL: 1965e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n"); 1975e3dd157SKalle Valo ar->scan_channel = NULL; 1985e3dd157SKalle Valo break; 1995e3dd157SKalle Valo case WMI_SCAN_EVENT_FOREIGN_CHANNEL: 2005e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n"); 2015e3dd157SKalle Valo ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); 2025e3dd157SKalle Valo if (ar->scan.in_progress && ar->scan.is_roc && 2035e3dd157SKalle Valo ar->scan.roc_freq == freq) { 2045e3dd157SKalle Valo complete(&ar->scan.on_channel); 2055e3dd157SKalle Valo } 2065e3dd157SKalle Valo break; 2075e3dd157SKalle Valo case WMI_SCAN_EVENT_DEQUEUED: 2085e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n"); 2095e3dd157SKalle Valo break; 2105e3dd157SKalle Valo case WMI_SCAN_EVENT_PREEMPTED: 2115e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n"); 2125e3dd157SKalle Valo break; 2135e3dd157SKalle Valo case WMI_SCAN_EVENT_START_FAILED: 2145e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n"); 2155e3dd157SKalle Valo break; 2165e3dd157SKalle Valo default: 2175e3dd157SKalle Valo break; 2185e3dd157SKalle Valo } 2195e3dd157SKalle Valo 2205e3dd157SKalle Valo spin_unlock_bh(&ar->data_lock); 2215e3dd157SKalle Valo return 0; 2225e3dd157SKalle Valo } 2235e3dd157SKalle Valo 2245e3dd157SKalle Valo static inline enum ieee80211_band phy_mode_to_band(u32 phy_mode) 2255e3dd157SKalle Valo { 2265e3dd157SKalle Valo enum ieee80211_band band; 2275e3dd157SKalle Valo 2285e3dd157SKalle Valo switch (phy_mode) { 2295e3dd157SKalle Valo case MODE_11A: 2305e3dd157SKalle Valo case MODE_11NA_HT20: 2315e3dd157SKalle Valo case MODE_11NA_HT40: 2325e3dd157SKalle Valo case MODE_11AC_VHT20: 2335e3dd157SKalle Valo case MODE_11AC_VHT40: 2345e3dd157SKalle Valo case MODE_11AC_VHT80: 2355e3dd157SKalle Valo band = IEEE80211_BAND_5GHZ; 2365e3dd157SKalle Valo break; 2375e3dd157SKalle Valo case MODE_11G: 2385e3dd157SKalle Valo case MODE_11B: 2395e3dd157SKalle Valo case MODE_11GONLY: 2405e3dd157SKalle Valo case MODE_11NG_HT20: 2415e3dd157SKalle Valo case MODE_11NG_HT40: 2425e3dd157SKalle Valo case MODE_11AC_VHT20_2G: 2435e3dd157SKalle Valo case MODE_11AC_VHT40_2G: 2445e3dd157SKalle Valo case MODE_11AC_VHT80_2G: 2455e3dd157SKalle Valo default: 2465e3dd157SKalle Valo band = IEEE80211_BAND_2GHZ; 2475e3dd157SKalle Valo } 2485e3dd157SKalle Valo 2495e3dd157SKalle Valo return band; 2505e3dd157SKalle Valo } 2515e3dd157SKalle Valo 2525e3dd157SKalle Valo static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band) 2535e3dd157SKalle Valo { 2545e3dd157SKalle Valo u8 rate_idx = 0; 2555e3dd157SKalle Valo 2565e3dd157SKalle Valo /* rate in Kbps */ 2575e3dd157SKalle Valo switch (rate) { 2585e3dd157SKalle Valo case 1000: 2595e3dd157SKalle Valo rate_idx = 0; 2605e3dd157SKalle Valo break; 2615e3dd157SKalle Valo case 2000: 2625e3dd157SKalle Valo rate_idx = 1; 2635e3dd157SKalle Valo break; 2645e3dd157SKalle Valo case 5500: 2655e3dd157SKalle Valo rate_idx = 2; 2665e3dd157SKalle Valo break; 2675e3dd157SKalle Valo case 11000: 2685e3dd157SKalle Valo rate_idx = 3; 2695e3dd157SKalle Valo break; 2705e3dd157SKalle Valo case 6000: 2715e3dd157SKalle Valo rate_idx = 4; 2725e3dd157SKalle Valo break; 2735e3dd157SKalle Valo case 9000: 2745e3dd157SKalle Valo rate_idx = 5; 2755e3dd157SKalle Valo break; 2765e3dd157SKalle Valo case 12000: 2775e3dd157SKalle Valo rate_idx = 6; 2785e3dd157SKalle Valo break; 2795e3dd157SKalle Valo case 18000: 2805e3dd157SKalle Valo rate_idx = 7; 2815e3dd157SKalle Valo break; 2825e3dd157SKalle Valo case 24000: 2835e3dd157SKalle Valo rate_idx = 8; 2845e3dd157SKalle Valo break; 2855e3dd157SKalle Valo case 36000: 2865e3dd157SKalle Valo rate_idx = 9; 2875e3dd157SKalle Valo break; 2885e3dd157SKalle Valo case 48000: 2895e3dd157SKalle Valo rate_idx = 10; 2905e3dd157SKalle Valo break; 2915e3dd157SKalle Valo case 54000: 2925e3dd157SKalle Valo rate_idx = 11; 2935e3dd157SKalle Valo break; 2945e3dd157SKalle Valo default: 2955e3dd157SKalle Valo break; 2965e3dd157SKalle Valo } 2975e3dd157SKalle Valo 2985e3dd157SKalle Valo if (band == IEEE80211_BAND_5GHZ) { 2995e3dd157SKalle Valo if (rate_idx > 3) 3005e3dd157SKalle Valo /* Omit CCK rates */ 3015e3dd157SKalle Valo rate_idx -= 4; 3025e3dd157SKalle Valo else 3035e3dd157SKalle Valo rate_idx = 0; 3045e3dd157SKalle Valo } 3055e3dd157SKalle Valo 3065e3dd157SKalle Valo return rate_idx; 3075e3dd157SKalle Valo } 3085e3dd157SKalle Valo 3095e3dd157SKalle Valo static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) 3105e3dd157SKalle Valo { 3115e3dd157SKalle Valo struct wmi_mgmt_rx_event *event = (struct wmi_mgmt_rx_event *)skb->data; 3125e3dd157SKalle Valo struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 3135e3dd157SKalle Valo struct ieee80211_hdr *hdr; 3145e3dd157SKalle Valo u32 rx_status; 3155e3dd157SKalle Valo u32 channel; 3165e3dd157SKalle Valo u32 phy_mode; 3175e3dd157SKalle Valo u32 snr; 3185e3dd157SKalle Valo u32 rate; 3195e3dd157SKalle Valo u32 buf_len; 3205e3dd157SKalle Valo u16 fc; 3215e3dd157SKalle Valo 3225e3dd157SKalle Valo channel = __le32_to_cpu(event->hdr.channel); 3235e3dd157SKalle Valo buf_len = __le32_to_cpu(event->hdr.buf_len); 3245e3dd157SKalle Valo rx_status = __le32_to_cpu(event->hdr.status); 3255e3dd157SKalle Valo snr = __le32_to_cpu(event->hdr.snr); 3265e3dd157SKalle Valo phy_mode = __le32_to_cpu(event->hdr.phy_mode); 3275e3dd157SKalle Valo rate = __le32_to_cpu(event->hdr.rate); 3285e3dd157SKalle Valo 3295e3dd157SKalle Valo memset(status, 0, sizeof(*status)); 3305e3dd157SKalle Valo 3315e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, 3325e3dd157SKalle Valo "event mgmt rx status %08x\n", rx_status); 3335e3dd157SKalle Valo 3345e3dd157SKalle Valo if (rx_status & WMI_RX_STATUS_ERR_DECRYPT) { 3355e3dd157SKalle Valo dev_kfree_skb(skb); 3365e3dd157SKalle Valo return 0; 3375e3dd157SKalle Valo } 3385e3dd157SKalle Valo 3395e3dd157SKalle Valo if (rx_status & WMI_RX_STATUS_ERR_KEY_CACHE_MISS) { 3405e3dd157SKalle Valo dev_kfree_skb(skb); 3415e3dd157SKalle Valo return 0; 3425e3dd157SKalle Valo } 3435e3dd157SKalle Valo 3445e3dd157SKalle Valo if (rx_status & WMI_RX_STATUS_ERR_CRC) 3455e3dd157SKalle Valo status->flag |= RX_FLAG_FAILED_FCS_CRC; 3465e3dd157SKalle Valo if (rx_status & WMI_RX_STATUS_ERR_MIC) 3475e3dd157SKalle Valo status->flag |= RX_FLAG_MMIC_ERROR; 3485e3dd157SKalle Valo 3495e3dd157SKalle Valo status->band = phy_mode_to_band(phy_mode); 3505e3dd157SKalle Valo status->freq = ieee80211_channel_to_frequency(channel, status->band); 3515e3dd157SKalle Valo status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; 3525e3dd157SKalle Valo status->rate_idx = get_rate_idx(rate, status->band); 3535e3dd157SKalle Valo 3545e3dd157SKalle Valo skb_pull(skb, sizeof(event->hdr)); 3555e3dd157SKalle Valo 3565e3dd157SKalle Valo hdr = (struct ieee80211_hdr *)skb->data; 3575e3dd157SKalle Valo fc = le16_to_cpu(hdr->frame_control); 3585e3dd157SKalle Valo 3595e3dd157SKalle Valo if (fc & IEEE80211_FCTL_PROTECTED) { 3605e3dd157SKalle Valo status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | 3615e3dd157SKalle Valo RX_FLAG_MMIC_STRIPPED; 3625e3dd157SKalle Valo hdr->frame_control = __cpu_to_le16(fc & 3635e3dd157SKalle Valo ~IEEE80211_FCTL_PROTECTED); 3645e3dd157SKalle Valo } 3655e3dd157SKalle Valo 3665e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, 3675e3dd157SKalle Valo "event mgmt rx skb %p len %d ftype %02x stype %02x\n", 3685e3dd157SKalle Valo skb, skb->len, 3695e3dd157SKalle Valo fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); 3705e3dd157SKalle Valo 3715e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, 3725e3dd157SKalle Valo "event mgmt rx freq %d band %d snr %d, rate_idx %d\n", 3735e3dd157SKalle Valo status->freq, status->band, status->signal, 3745e3dd157SKalle Valo status->rate_idx); 3755e3dd157SKalle Valo 3765e3dd157SKalle Valo /* 3775e3dd157SKalle Valo * packets from HTC come aligned to 4byte boundaries 3785e3dd157SKalle Valo * because they can originally come in along with a trailer 3795e3dd157SKalle Valo */ 3805e3dd157SKalle Valo skb_trim(skb, buf_len); 3815e3dd157SKalle Valo 3825e3dd157SKalle Valo ieee80211_rx(ar->hw, skb); 3835e3dd157SKalle Valo return 0; 3845e3dd157SKalle Valo } 3855e3dd157SKalle Valo 3865e3dd157SKalle Valo static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) 3875e3dd157SKalle Valo { 3885e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_CHAN_INFO_EVENTID\n"); 3895e3dd157SKalle Valo } 3905e3dd157SKalle Valo 3915e3dd157SKalle Valo static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) 3925e3dd157SKalle Valo { 3935e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n"); 3945e3dd157SKalle Valo } 3955e3dd157SKalle Valo 3965e3dd157SKalle Valo static void ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) 3975e3dd157SKalle Valo { 3985e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_MESG_EVENTID\n"); 3995e3dd157SKalle Valo } 4005e3dd157SKalle Valo 4015e3dd157SKalle Valo static void ath10k_wmi_event_update_stats(struct ath10k *ar, 4025e3dd157SKalle Valo struct sk_buff *skb) 4035e3dd157SKalle Valo { 4045e3dd157SKalle Valo struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data; 4055e3dd157SKalle Valo 4065e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); 4075e3dd157SKalle Valo 4085e3dd157SKalle Valo ath10k_debug_read_target_stats(ar, ev); 4095e3dd157SKalle Valo } 4105e3dd157SKalle Valo 4115e3dd157SKalle Valo static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, 4125e3dd157SKalle Valo struct sk_buff *skb) 4135e3dd157SKalle Valo { 4145e3dd157SKalle Valo struct wmi_vdev_start_response_event *ev; 4155e3dd157SKalle Valo 4165e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); 4175e3dd157SKalle Valo 4185e3dd157SKalle Valo ev = (struct wmi_vdev_start_response_event *)skb->data; 4195e3dd157SKalle Valo 4205e3dd157SKalle Valo if (WARN_ON(__le32_to_cpu(ev->status))) 4215e3dd157SKalle Valo return; 4225e3dd157SKalle Valo 4235e3dd157SKalle Valo complete(&ar->vdev_setup_done); 4245e3dd157SKalle Valo } 4255e3dd157SKalle Valo 4265e3dd157SKalle Valo static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, 4275e3dd157SKalle Valo struct sk_buff *skb) 4285e3dd157SKalle Valo { 4295e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n"); 4305e3dd157SKalle Valo complete(&ar->vdev_setup_done); 4315e3dd157SKalle Valo } 4325e3dd157SKalle Valo 4335e3dd157SKalle Valo static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, 4345e3dd157SKalle Valo struct sk_buff *skb) 4355e3dd157SKalle Valo { 4365e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n"); 4375e3dd157SKalle Valo } 4385e3dd157SKalle Valo 4395e3dd157SKalle Valo /* 4405e3dd157SKalle Valo * FIXME 4415e3dd157SKalle Valo * 4425e3dd157SKalle Valo * We don't report to mac80211 sleep state of connected 4435e3dd157SKalle Valo * stations. Due to this mac80211 can't fill in TIM IE 4445e3dd157SKalle Valo * correctly. 4455e3dd157SKalle Valo * 4465e3dd157SKalle Valo * I know of no way of getting nullfunc frames that contain 4475e3dd157SKalle Valo * sleep transition from connected stations - these do not 4485e3dd157SKalle Valo * seem to be sent from the target to the host. There also 4495e3dd157SKalle Valo * doesn't seem to be a dedicated event for that. So the 4505e3dd157SKalle Valo * only way left to do this would be to read tim_bitmap 4515e3dd157SKalle Valo * during SWBA. 4525e3dd157SKalle Valo * 4535e3dd157SKalle Valo * We could probably try using tim_bitmap from SWBA to tell 4545e3dd157SKalle Valo * mac80211 which stations are asleep and which are not. The 4555e3dd157SKalle Valo * problem here is calling mac80211 functions so many times 4565e3dd157SKalle Valo * could take too long and make us miss the time to submit 4575e3dd157SKalle Valo * the beacon to the target. 4585e3dd157SKalle Valo * 4595e3dd157SKalle Valo * So as a workaround we try to extend the TIM IE if there 4605e3dd157SKalle Valo * is unicast buffered for stations with aid > 7 and fill it 4615e3dd157SKalle Valo * in ourselves. 4625e3dd157SKalle Valo */ 4635e3dd157SKalle Valo static void ath10k_wmi_update_tim(struct ath10k *ar, 4645e3dd157SKalle Valo struct ath10k_vif *arvif, 4655e3dd157SKalle Valo struct sk_buff *bcn, 4665e3dd157SKalle Valo struct wmi_bcn_info *bcn_info) 4675e3dd157SKalle Valo { 4685e3dd157SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; 4695e3dd157SKalle Valo struct ieee80211_tim_ie *tim; 4705e3dd157SKalle Valo u8 *ies, *ie; 4715e3dd157SKalle Valo u8 ie_len, pvm_len; 4725e3dd157SKalle Valo 4735e3dd157SKalle Valo /* if next SWBA has no tim_changed the tim_bitmap is garbage. 4745e3dd157SKalle Valo * we must copy the bitmap upon change and reuse it later */ 4755e3dd157SKalle Valo if (__le32_to_cpu(bcn_info->tim_info.tim_changed)) { 4765e3dd157SKalle Valo int i; 4775e3dd157SKalle Valo 4785e3dd157SKalle Valo BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != 4795e3dd157SKalle Valo sizeof(bcn_info->tim_info.tim_bitmap)); 4805e3dd157SKalle Valo 4815e3dd157SKalle Valo for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { 4825e3dd157SKalle Valo __le32 t = bcn_info->tim_info.tim_bitmap[i / 4]; 4835e3dd157SKalle Valo u32 v = __le32_to_cpu(t); 4845e3dd157SKalle Valo arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; 4855e3dd157SKalle Valo } 4865e3dd157SKalle Valo 4875e3dd157SKalle Valo /* FW reports either length 0 or 16 4885e3dd157SKalle Valo * so we calculate this on our own */ 4895e3dd157SKalle Valo arvif->u.ap.tim_len = 0; 4905e3dd157SKalle Valo for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) 4915e3dd157SKalle Valo if (arvif->u.ap.tim_bitmap[i]) 4925e3dd157SKalle Valo arvif->u.ap.tim_len = i; 4935e3dd157SKalle Valo 4945e3dd157SKalle Valo arvif->u.ap.tim_len++; 4955e3dd157SKalle Valo } 4965e3dd157SKalle Valo 4975e3dd157SKalle Valo ies = bcn->data; 4985e3dd157SKalle Valo ies += ieee80211_hdrlen(hdr->frame_control); 4995e3dd157SKalle Valo ies += 12; /* fixed parameters */ 5005e3dd157SKalle Valo 5015e3dd157SKalle Valo ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies, 5025e3dd157SKalle Valo (u8 *)skb_tail_pointer(bcn) - ies); 5035e3dd157SKalle Valo if (!ie) { 50409af8f85SMichal Kazior if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS) 5055e3dd157SKalle Valo ath10k_warn("no tim ie found;\n"); 5065e3dd157SKalle Valo return; 5075e3dd157SKalle Valo } 5085e3dd157SKalle Valo 5095e3dd157SKalle Valo tim = (void *)ie + 2; 5105e3dd157SKalle Valo ie_len = ie[1]; 5115e3dd157SKalle Valo pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */ 5125e3dd157SKalle Valo 5135e3dd157SKalle Valo if (pvm_len < arvif->u.ap.tim_len) { 5145e3dd157SKalle Valo int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len; 5155e3dd157SKalle Valo int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len); 5165e3dd157SKalle Valo void *next_ie = ie + 2 + ie_len; 5175e3dd157SKalle Valo 5185e3dd157SKalle Valo if (skb_put(bcn, expand_size)) { 5195e3dd157SKalle Valo memmove(next_ie + expand_size, next_ie, move_size); 5205e3dd157SKalle Valo 5215e3dd157SKalle Valo ie[1] += expand_size; 5225e3dd157SKalle Valo ie_len += expand_size; 5235e3dd157SKalle Valo pvm_len += expand_size; 5245e3dd157SKalle Valo } else { 5255e3dd157SKalle Valo ath10k_warn("tim expansion failed\n"); 5265e3dd157SKalle Valo } 5275e3dd157SKalle Valo } 5285e3dd157SKalle Valo 5295e3dd157SKalle Valo if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { 5305e3dd157SKalle Valo ath10k_warn("tim pvm length is too great (%d)\n", pvm_len); 5315e3dd157SKalle Valo return; 5325e3dd157SKalle Valo } 5335e3dd157SKalle Valo 5345e3dd157SKalle Valo tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); 5355e3dd157SKalle Valo memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); 5365e3dd157SKalle Valo 5375e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", 5385e3dd157SKalle Valo tim->dtim_count, tim->dtim_period, 5395e3dd157SKalle Valo tim->bitmap_ctrl, pvm_len); 5405e3dd157SKalle Valo } 5415e3dd157SKalle Valo 5425e3dd157SKalle Valo static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len, 5435e3dd157SKalle Valo struct wmi_p2p_noa_info *noa) 5445e3dd157SKalle Valo { 5455e3dd157SKalle Valo struct ieee80211_p2p_noa_attr *noa_attr; 5465e3dd157SKalle Valo u8 ctwindow_oppps = noa->ctwindow_oppps; 5475e3dd157SKalle Valo u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET; 5485e3dd157SKalle Valo bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT); 5495e3dd157SKalle Valo __le16 *noa_attr_len; 5505e3dd157SKalle Valo u16 attr_len; 5515e3dd157SKalle Valo u8 noa_descriptors = noa->num_descriptors; 5525e3dd157SKalle Valo int i; 5535e3dd157SKalle Valo 5545e3dd157SKalle Valo /* P2P IE */ 5555e3dd157SKalle Valo data[0] = WLAN_EID_VENDOR_SPECIFIC; 5565e3dd157SKalle Valo data[1] = len - 2; 5575e3dd157SKalle Valo data[2] = (WLAN_OUI_WFA >> 16) & 0xff; 5585e3dd157SKalle Valo data[3] = (WLAN_OUI_WFA >> 8) & 0xff; 5595e3dd157SKalle Valo data[4] = (WLAN_OUI_WFA >> 0) & 0xff; 5605e3dd157SKalle Valo data[5] = WLAN_OUI_TYPE_WFA_P2P; 5615e3dd157SKalle Valo 5625e3dd157SKalle Valo /* NOA ATTR */ 5635e3dd157SKalle Valo data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE; 5645e3dd157SKalle Valo noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */ 5655e3dd157SKalle Valo noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9]; 5665e3dd157SKalle Valo 5675e3dd157SKalle Valo noa_attr->index = noa->index; 5685e3dd157SKalle Valo noa_attr->oppps_ctwindow = ctwindow; 5695e3dd157SKalle Valo if (oppps) 5705e3dd157SKalle Valo noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; 5715e3dd157SKalle Valo 5725e3dd157SKalle Valo for (i = 0; i < noa_descriptors; i++) { 5735e3dd157SKalle Valo noa_attr->desc[i].count = 5745e3dd157SKalle Valo __le32_to_cpu(noa->descriptors[i].type_count); 5755e3dd157SKalle Valo noa_attr->desc[i].duration = noa->descriptors[i].duration; 5765e3dd157SKalle Valo noa_attr->desc[i].interval = noa->descriptors[i].interval; 5775e3dd157SKalle Valo noa_attr->desc[i].start_time = noa->descriptors[i].start_time; 5785e3dd157SKalle Valo } 5795e3dd157SKalle Valo 5805e3dd157SKalle Valo attr_len = 2; /* index + oppps_ctwindow */ 5815e3dd157SKalle Valo attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); 5825e3dd157SKalle Valo *noa_attr_len = __cpu_to_le16(attr_len); 5835e3dd157SKalle Valo } 5845e3dd157SKalle Valo 5855e3dd157SKalle Valo static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa) 5865e3dd157SKalle Valo { 5875e3dd157SKalle Valo u32 len = 0; 5885e3dd157SKalle Valo u8 noa_descriptors = noa->num_descriptors; 5895e3dd157SKalle Valo u8 opp_ps_info = noa->ctwindow_oppps; 5905e3dd157SKalle Valo bool opps_enabled = !!(opp_ps_info & WMI_P2P_OPPPS_ENABLE_BIT); 5915e3dd157SKalle Valo 5925e3dd157SKalle Valo 5935e3dd157SKalle Valo if (!noa_descriptors && !opps_enabled) 5945e3dd157SKalle Valo return len; 5955e3dd157SKalle Valo 5965e3dd157SKalle Valo len += 1 + 1 + 4; /* EID + len + OUI */ 5975e3dd157SKalle Valo len += 1 + 2; /* noa attr + attr len */ 5985e3dd157SKalle Valo len += 1 + 1; /* index + oppps_ctwindow */ 5995e3dd157SKalle Valo len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); 6005e3dd157SKalle Valo 6015e3dd157SKalle Valo return len; 6025e3dd157SKalle Valo } 6035e3dd157SKalle Valo 6045e3dd157SKalle Valo static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, 6055e3dd157SKalle Valo struct sk_buff *bcn, 6065e3dd157SKalle Valo struct wmi_bcn_info *bcn_info) 6075e3dd157SKalle Valo { 6085e3dd157SKalle Valo struct wmi_p2p_noa_info *noa = &bcn_info->p2p_noa_info; 6095e3dd157SKalle Valo u8 *new_data, *old_data = arvif->u.ap.noa_data; 6105e3dd157SKalle Valo u32 new_len; 6115e3dd157SKalle Valo 6125e3dd157SKalle Valo if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) 6135e3dd157SKalle Valo return; 6145e3dd157SKalle Valo 6155e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed); 6165e3dd157SKalle Valo if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) { 6175e3dd157SKalle Valo new_len = ath10k_p2p_calc_noa_ie_len(noa); 6185e3dd157SKalle Valo if (!new_len) 6195e3dd157SKalle Valo goto cleanup; 6205e3dd157SKalle Valo 6215e3dd157SKalle Valo new_data = kmalloc(new_len, GFP_ATOMIC); 6225e3dd157SKalle Valo if (!new_data) 6235e3dd157SKalle Valo goto cleanup; 6245e3dd157SKalle Valo 6255e3dd157SKalle Valo ath10k_p2p_fill_noa_ie(new_data, new_len, noa); 6265e3dd157SKalle Valo 6275e3dd157SKalle Valo spin_lock_bh(&ar->data_lock); 6285e3dd157SKalle Valo arvif->u.ap.noa_data = new_data; 6295e3dd157SKalle Valo arvif->u.ap.noa_len = new_len; 6305e3dd157SKalle Valo spin_unlock_bh(&ar->data_lock); 6315e3dd157SKalle Valo kfree(old_data); 6325e3dd157SKalle Valo } 6335e3dd157SKalle Valo 6345e3dd157SKalle Valo if (arvif->u.ap.noa_data) 6355e3dd157SKalle Valo if (!pskb_expand_head(bcn, 0, arvif->u.ap.noa_len, GFP_ATOMIC)) 6365e3dd157SKalle Valo memcpy(skb_put(bcn, arvif->u.ap.noa_len), 6375e3dd157SKalle Valo arvif->u.ap.noa_data, 6385e3dd157SKalle Valo arvif->u.ap.noa_len); 6395e3dd157SKalle Valo return; 6405e3dd157SKalle Valo 6415e3dd157SKalle Valo cleanup: 6425e3dd157SKalle Valo spin_lock_bh(&ar->data_lock); 6435e3dd157SKalle Valo arvif->u.ap.noa_data = NULL; 6445e3dd157SKalle Valo arvif->u.ap.noa_len = 0; 6455e3dd157SKalle Valo spin_unlock_bh(&ar->data_lock); 6465e3dd157SKalle Valo kfree(old_data); 6475e3dd157SKalle Valo } 6485e3dd157SKalle Valo 6495e3dd157SKalle Valo 6505e3dd157SKalle Valo static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) 6515e3dd157SKalle Valo { 6525e3dd157SKalle Valo struct wmi_host_swba_event *ev; 6535e3dd157SKalle Valo u32 map; 6545e3dd157SKalle Valo int i = -1; 6555e3dd157SKalle Valo struct wmi_bcn_info *bcn_info; 6565e3dd157SKalle Valo struct ath10k_vif *arvif; 6575e3dd157SKalle Valo struct wmi_bcn_tx_arg arg; 6585e3dd157SKalle Valo struct sk_buff *bcn; 6595e3dd157SKalle Valo int vdev_id = 0; 6605e3dd157SKalle Valo int ret; 6615e3dd157SKalle Valo 6625e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); 6635e3dd157SKalle Valo 6645e3dd157SKalle Valo ev = (struct wmi_host_swba_event *)skb->data; 6655e3dd157SKalle Valo map = __le32_to_cpu(ev->vdev_map); 6665e3dd157SKalle Valo 6675e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, "host swba:\n" 6685e3dd157SKalle Valo "-vdev map 0x%x\n", 6695e3dd157SKalle Valo ev->vdev_map); 6705e3dd157SKalle Valo 6715e3dd157SKalle Valo for (; map; map >>= 1, vdev_id++) { 6725e3dd157SKalle Valo if (!(map & 0x1)) 6735e3dd157SKalle Valo continue; 6745e3dd157SKalle Valo 6755e3dd157SKalle Valo i++; 6765e3dd157SKalle Valo 6775e3dd157SKalle Valo if (i >= WMI_MAX_AP_VDEV) { 6785e3dd157SKalle Valo ath10k_warn("swba has corrupted vdev map\n"); 6795e3dd157SKalle Valo break; 6805e3dd157SKalle Valo } 6815e3dd157SKalle Valo 6825e3dd157SKalle Valo bcn_info = &ev->bcn_info[i]; 6835e3dd157SKalle Valo 6845e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_MGMT, 6855e3dd157SKalle Valo "-bcn_info[%d]:\n" 6865e3dd157SKalle Valo "--tim_len %d\n" 6875e3dd157SKalle Valo "--tim_mcast %d\n" 6885e3dd157SKalle Valo "--tim_changed %d\n" 6895e3dd157SKalle Valo "--tim_num_ps_pending %d\n" 6905e3dd157SKalle Valo "--tim_bitmap 0x%08x%08x%08x%08x\n", 6915e3dd157SKalle Valo i, 6925e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_len), 6935e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_mcast), 6945e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_changed), 6955e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_num_ps_pending), 6965e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_bitmap[3]), 6975e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_bitmap[2]), 6985e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_bitmap[1]), 6995e3dd157SKalle Valo __le32_to_cpu(bcn_info->tim_info.tim_bitmap[0])); 7005e3dd157SKalle Valo 7015e3dd157SKalle Valo arvif = ath10k_get_arvif(ar, vdev_id); 7025e3dd157SKalle Valo if (arvif == NULL) { 7035e3dd157SKalle Valo ath10k_warn("no vif for vdev_id %d found\n", vdev_id); 7045e3dd157SKalle Valo continue; 7055e3dd157SKalle Valo } 7065e3dd157SKalle Valo 7075e3dd157SKalle Valo bcn = ieee80211_beacon_get(ar->hw, arvif->vif); 7085e3dd157SKalle Valo if (!bcn) { 7095e3dd157SKalle Valo ath10k_warn("could not get mac80211 beacon\n"); 7105e3dd157SKalle Valo continue; 7115e3dd157SKalle Valo } 7125e3dd157SKalle Valo 7135e3dd157SKalle Valo ath10k_tx_h_seq_no(bcn); 7145e3dd157SKalle Valo ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); 7155e3dd157SKalle Valo ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); 7165e3dd157SKalle Valo 7175e3dd157SKalle Valo arg.vdev_id = arvif->vdev_id; 7185e3dd157SKalle Valo arg.tx_rate = 0; 7195e3dd157SKalle Valo arg.tx_power = 0; 7205e3dd157SKalle Valo arg.bcn = bcn->data; 7215e3dd157SKalle Valo arg.bcn_len = bcn->len; 7225e3dd157SKalle Valo 7235e3dd157SKalle Valo ret = ath10k_wmi_beacon_send(ar, &arg); 7245e3dd157SKalle Valo if (ret) 7255e3dd157SKalle Valo ath10k_warn("could not send beacon (%d)\n", ret); 7265e3dd157SKalle Valo 7275e3dd157SKalle Valo dev_kfree_skb_any(bcn); 7285e3dd157SKalle Valo } 7295e3dd157SKalle Valo } 7305e3dd157SKalle Valo 7315e3dd157SKalle Valo static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, 7325e3dd157SKalle Valo struct sk_buff *skb) 7335e3dd157SKalle Valo { 7345e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); 7355e3dd157SKalle Valo } 7365e3dd157SKalle Valo 7375e3dd157SKalle Valo static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) 7385e3dd157SKalle Valo { 7395e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_PHYERR_EVENTID\n"); 7405e3dd157SKalle Valo } 7415e3dd157SKalle Valo 7425e3dd157SKalle Valo static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) 7435e3dd157SKalle Valo { 7445e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n"); 7455e3dd157SKalle Valo } 7465e3dd157SKalle Valo 7475e3dd157SKalle Valo static void ath10k_wmi_event_profile_match(struct ath10k *ar, 7485e3dd157SKalle Valo struct sk_buff *skb) 7495e3dd157SKalle Valo { 7505e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n"); 7515e3dd157SKalle Valo } 7525e3dd157SKalle Valo 7535e3dd157SKalle Valo static void ath10k_wmi_event_debug_print(struct ath10k *ar, 7545e3dd157SKalle Valo struct sk_buff *skb) 7555e3dd157SKalle Valo { 7565e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_PRINT_EVENTID\n"); 7575e3dd157SKalle Valo } 7585e3dd157SKalle Valo 7595e3dd157SKalle Valo static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) 7605e3dd157SKalle Valo { 7615e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n"); 7625e3dd157SKalle Valo } 7635e3dd157SKalle Valo 7645e3dd157SKalle Valo static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, 7655e3dd157SKalle Valo struct sk_buff *skb) 7665e3dd157SKalle Valo { 7675e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n"); 7685e3dd157SKalle Valo } 7695e3dd157SKalle Valo 7705e3dd157SKalle Valo static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, 7715e3dd157SKalle Valo struct sk_buff *skb) 7725e3dd157SKalle Valo { 7735e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n"); 7745e3dd157SKalle Valo } 7755e3dd157SKalle Valo 7765e3dd157SKalle Valo static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, 7775e3dd157SKalle Valo struct sk_buff *skb) 7785e3dd157SKalle Valo { 7795e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n"); 7805e3dd157SKalle Valo } 7815e3dd157SKalle Valo 7825e3dd157SKalle Valo static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, 7835e3dd157SKalle Valo struct sk_buff *skb) 7845e3dd157SKalle Valo { 7855e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n"); 7865e3dd157SKalle Valo } 7875e3dd157SKalle Valo 7885e3dd157SKalle Valo static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, 7895e3dd157SKalle Valo struct sk_buff *skb) 7905e3dd157SKalle Valo { 7915e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n"); 7925e3dd157SKalle Valo } 7935e3dd157SKalle Valo 7945e3dd157SKalle Valo static void ath10k_wmi_event_dcs_interference(struct ath10k *ar, 7955e3dd157SKalle Valo struct sk_buff *skb) 7965e3dd157SKalle Valo { 7975e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); 7985e3dd157SKalle Valo } 7995e3dd157SKalle Valo 8005e3dd157SKalle Valo static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, 8015e3dd157SKalle Valo struct sk_buff *skb) 8025e3dd157SKalle Valo { 8035e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); 8045e3dd157SKalle Valo } 8055e3dd157SKalle Valo 8065e3dd157SKalle Valo static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, 8075e3dd157SKalle Valo struct sk_buff *skb) 8085e3dd157SKalle Valo { 8095e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); 8105e3dd157SKalle Valo } 8115e3dd157SKalle Valo 8125e3dd157SKalle Valo static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, 8135e3dd157SKalle Valo struct sk_buff *skb) 8145e3dd157SKalle Valo { 8155e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n"); 8165e3dd157SKalle Valo } 8175e3dd157SKalle Valo 8185e3dd157SKalle Valo static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, 8195e3dd157SKalle Valo struct sk_buff *skb) 8205e3dd157SKalle Valo { 8215e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n"); 8225e3dd157SKalle Valo } 8235e3dd157SKalle Valo 8245e3dd157SKalle Valo static void ath10k_wmi_event_delba_complete(struct ath10k *ar, 8255e3dd157SKalle Valo struct sk_buff *skb) 8265e3dd157SKalle Valo { 8275e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n"); 8285e3dd157SKalle Valo } 8295e3dd157SKalle Valo 8305e3dd157SKalle Valo static void ath10k_wmi_event_addba_complete(struct ath10k *ar, 8315e3dd157SKalle Valo struct sk_buff *skb) 8325e3dd157SKalle Valo { 8335e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n"); 8345e3dd157SKalle Valo } 8355e3dd157SKalle Valo 8365e3dd157SKalle Valo static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, 8375e3dd157SKalle Valo struct sk_buff *skb) 8385e3dd157SKalle Valo { 8395e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n"); 8405e3dd157SKalle Valo } 8415e3dd157SKalle Valo 8425e3dd157SKalle Valo static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, 8435e3dd157SKalle Valo struct sk_buff *skb) 8445e3dd157SKalle Valo { 8455e3dd157SKalle Valo struct wmi_service_ready_event *ev = (void *)skb->data; 8465e3dd157SKalle Valo 8475e3dd157SKalle Valo if (skb->len < sizeof(*ev)) { 8485e3dd157SKalle Valo ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", 8495e3dd157SKalle Valo skb->len, sizeof(*ev)); 8505e3dd157SKalle Valo return; 8515e3dd157SKalle Valo } 8525e3dd157SKalle Valo 8535e3dd157SKalle Valo ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power); 8545e3dd157SKalle Valo ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power); 8555e3dd157SKalle Valo ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info); 8565e3dd157SKalle Valo ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info); 8575e3dd157SKalle Valo ar->fw_version_major = 8585e3dd157SKalle Valo (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24; 8595e3dd157SKalle Valo ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff); 8605e3dd157SKalle Valo ar->fw_version_release = 8615e3dd157SKalle Valo (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16; 8625e3dd157SKalle Valo ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff); 8635e3dd157SKalle Valo ar->phy_capability = __le32_to_cpu(ev->phy_capability); 8645e3dd157SKalle Valo 8655e3dd157SKalle Valo ar->ath_common.regulatory.current_rd = 8665e3dd157SKalle Valo __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); 8675e3dd157SKalle Valo 8685e3dd157SKalle Valo ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap, 8695e3dd157SKalle Valo sizeof(ev->wmi_service_bitmap)); 8705e3dd157SKalle Valo 8715e3dd157SKalle Valo if (strlen(ar->hw->wiphy->fw_version) == 0) { 8725e3dd157SKalle Valo snprintf(ar->hw->wiphy->fw_version, 8735e3dd157SKalle Valo sizeof(ar->hw->wiphy->fw_version), 8745e3dd157SKalle Valo "%u.%u.%u.%u", 8755e3dd157SKalle Valo ar->fw_version_major, 8765e3dd157SKalle Valo ar->fw_version_minor, 8775e3dd157SKalle Valo ar->fw_version_release, 8785e3dd157SKalle Valo ar->fw_version_build); 8795e3dd157SKalle Valo } 8805e3dd157SKalle Valo 8815e3dd157SKalle Valo /* FIXME: it probably should be better to support this */ 8825e3dd157SKalle Valo if (__le32_to_cpu(ev->num_mem_reqs) > 0) { 8835e3dd157SKalle Valo ath10k_warn("target requested %d memory chunks; ignoring\n", 8845e3dd157SKalle Valo __le32_to_cpu(ev->num_mem_reqs)); 8855e3dd157SKalle Valo } 8865e3dd157SKalle Valo 8875e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 8885e3dd157SKalle Valo "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u\n", 8895e3dd157SKalle Valo __le32_to_cpu(ev->sw_version), 8905e3dd157SKalle Valo __le32_to_cpu(ev->sw_version_1), 8915e3dd157SKalle Valo __le32_to_cpu(ev->abi_version), 8925e3dd157SKalle Valo __le32_to_cpu(ev->phy_capability), 8935e3dd157SKalle Valo __le32_to_cpu(ev->ht_cap_info), 8945e3dd157SKalle Valo __le32_to_cpu(ev->vht_cap_info), 8955e3dd157SKalle Valo __le32_to_cpu(ev->vht_supp_mcs), 8965e3dd157SKalle Valo __le32_to_cpu(ev->sys_cap_info), 8975e3dd157SKalle Valo __le32_to_cpu(ev->num_mem_reqs)); 8985e3dd157SKalle Valo 8995e3dd157SKalle Valo complete(&ar->wmi.service_ready); 9005e3dd157SKalle Valo } 9015e3dd157SKalle Valo 9025e3dd157SKalle Valo static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) 9035e3dd157SKalle Valo { 9045e3dd157SKalle Valo struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data; 9055e3dd157SKalle Valo 9065e3dd157SKalle Valo if (WARN_ON(skb->len < sizeof(*ev))) 9075e3dd157SKalle Valo return -EINVAL; 9085e3dd157SKalle Valo 9095e3dd157SKalle Valo memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN); 9105e3dd157SKalle Valo 9115e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 9125e3dd157SKalle Valo "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", 9135e3dd157SKalle Valo __le32_to_cpu(ev->sw_version), 9145e3dd157SKalle Valo __le32_to_cpu(ev->abi_version), 9155e3dd157SKalle Valo ev->mac_addr.addr, 9165e3dd157SKalle Valo __le32_to_cpu(ev->status)); 9175e3dd157SKalle Valo 9185e3dd157SKalle Valo complete(&ar->wmi.unified_ready); 9195e3dd157SKalle Valo return 0; 9205e3dd157SKalle Valo } 9215e3dd157SKalle Valo 9225e3dd157SKalle Valo static void ath10k_wmi_event_process(struct ath10k *ar, struct sk_buff *skb) 9235e3dd157SKalle Valo { 9245e3dd157SKalle Valo struct wmi_cmd_hdr *cmd_hdr; 9255e3dd157SKalle Valo enum wmi_event_id id; 9265e3dd157SKalle Valo u16 len; 9275e3dd157SKalle Valo 9285e3dd157SKalle Valo cmd_hdr = (struct wmi_cmd_hdr *)skb->data; 9295e3dd157SKalle Valo id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); 9305e3dd157SKalle Valo 9315e3dd157SKalle Valo if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) 9325e3dd157SKalle Valo return; 9335e3dd157SKalle Valo 9345e3dd157SKalle Valo len = skb->len; 9355e3dd157SKalle Valo 9365e3dd157SKalle Valo trace_ath10k_wmi_event(id, skb->data, skb->len); 9375e3dd157SKalle Valo 9385e3dd157SKalle Valo switch (id) { 9395e3dd157SKalle Valo case WMI_MGMT_RX_EVENTID: 9405e3dd157SKalle Valo ath10k_wmi_event_mgmt_rx(ar, skb); 9415e3dd157SKalle Valo /* mgmt_rx() owns the skb now! */ 9425e3dd157SKalle Valo return; 9435e3dd157SKalle Valo case WMI_SCAN_EVENTID: 9445e3dd157SKalle Valo ath10k_wmi_event_scan(ar, skb); 9455e3dd157SKalle Valo break; 9465e3dd157SKalle Valo case WMI_CHAN_INFO_EVENTID: 9475e3dd157SKalle Valo ath10k_wmi_event_chan_info(ar, skb); 9485e3dd157SKalle Valo break; 9495e3dd157SKalle Valo case WMI_ECHO_EVENTID: 9505e3dd157SKalle Valo ath10k_wmi_event_echo(ar, skb); 9515e3dd157SKalle Valo break; 9525e3dd157SKalle Valo case WMI_DEBUG_MESG_EVENTID: 9535e3dd157SKalle Valo ath10k_wmi_event_debug_mesg(ar, skb); 9545e3dd157SKalle Valo break; 9555e3dd157SKalle Valo case WMI_UPDATE_STATS_EVENTID: 9565e3dd157SKalle Valo ath10k_wmi_event_update_stats(ar, skb); 9575e3dd157SKalle Valo break; 9585e3dd157SKalle Valo case WMI_VDEV_START_RESP_EVENTID: 9595e3dd157SKalle Valo ath10k_wmi_event_vdev_start_resp(ar, skb); 9605e3dd157SKalle Valo break; 9615e3dd157SKalle Valo case WMI_VDEV_STOPPED_EVENTID: 9625e3dd157SKalle Valo ath10k_wmi_event_vdev_stopped(ar, skb); 9635e3dd157SKalle Valo break; 9645e3dd157SKalle Valo case WMI_PEER_STA_KICKOUT_EVENTID: 9655e3dd157SKalle Valo ath10k_wmi_event_peer_sta_kickout(ar, skb); 9665e3dd157SKalle Valo break; 9675e3dd157SKalle Valo case WMI_HOST_SWBA_EVENTID: 9685e3dd157SKalle Valo ath10k_wmi_event_host_swba(ar, skb); 9695e3dd157SKalle Valo break; 9705e3dd157SKalle Valo case WMI_TBTTOFFSET_UPDATE_EVENTID: 9715e3dd157SKalle Valo ath10k_wmi_event_tbttoffset_update(ar, skb); 9725e3dd157SKalle Valo break; 9735e3dd157SKalle Valo case WMI_PHYERR_EVENTID: 9745e3dd157SKalle Valo ath10k_wmi_event_phyerr(ar, skb); 9755e3dd157SKalle Valo break; 9765e3dd157SKalle Valo case WMI_ROAM_EVENTID: 9775e3dd157SKalle Valo ath10k_wmi_event_roam(ar, skb); 9785e3dd157SKalle Valo break; 9795e3dd157SKalle Valo case WMI_PROFILE_MATCH: 9805e3dd157SKalle Valo ath10k_wmi_event_profile_match(ar, skb); 9815e3dd157SKalle Valo break; 9825e3dd157SKalle Valo case WMI_DEBUG_PRINT_EVENTID: 9835e3dd157SKalle Valo ath10k_wmi_event_debug_print(ar, skb); 9845e3dd157SKalle Valo break; 9855e3dd157SKalle Valo case WMI_PDEV_QVIT_EVENTID: 9865e3dd157SKalle Valo ath10k_wmi_event_pdev_qvit(ar, skb); 9875e3dd157SKalle Valo break; 9885e3dd157SKalle Valo case WMI_WLAN_PROFILE_DATA_EVENTID: 9895e3dd157SKalle Valo ath10k_wmi_event_wlan_profile_data(ar, skb); 9905e3dd157SKalle Valo break; 9915e3dd157SKalle Valo case WMI_RTT_MEASUREMENT_REPORT_EVENTID: 9925e3dd157SKalle Valo ath10k_wmi_event_rtt_measurement_report(ar, skb); 9935e3dd157SKalle Valo break; 9945e3dd157SKalle Valo case WMI_TSF_MEASUREMENT_REPORT_EVENTID: 9955e3dd157SKalle Valo ath10k_wmi_event_tsf_measurement_report(ar, skb); 9965e3dd157SKalle Valo break; 9975e3dd157SKalle Valo case WMI_RTT_ERROR_REPORT_EVENTID: 9985e3dd157SKalle Valo ath10k_wmi_event_rtt_error_report(ar, skb); 9995e3dd157SKalle Valo break; 10005e3dd157SKalle Valo case WMI_WOW_WAKEUP_HOST_EVENTID: 10015e3dd157SKalle Valo ath10k_wmi_event_wow_wakeup_host(ar, skb); 10025e3dd157SKalle Valo break; 10035e3dd157SKalle Valo case WMI_DCS_INTERFERENCE_EVENTID: 10045e3dd157SKalle Valo ath10k_wmi_event_dcs_interference(ar, skb); 10055e3dd157SKalle Valo break; 10065e3dd157SKalle Valo case WMI_PDEV_TPC_CONFIG_EVENTID: 10075e3dd157SKalle Valo ath10k_wmi_event_pdev_tpc_config(ar, skb); 10085e3dd157SKalle Valo break; 10095e3dd157SKalle Valo case WMI_PDEV_FTM_INTG_EVENTID: 10105e3dd157SKalle Valo ath10k_wmi_event_pdev_ftm_intg(ar, skb); 10115e3dd157SKalle Valo break; 10125e3dd157SKalle Valo case WMI_GTK_OFFLOAD_STATUS_EVENTID: 10135e3dd157SKalle Valo ath10k_wmi_event_gtk_offload_status(ar, skb); 10145e3dd157SKalle Valo break; 10155e3dd157SKalle Valo case WMI_GTK_REKEY_FAIL_EVENTID: 10165e3dd157SKalle Valo ath10k_wmi_event_gtk_rekey_fail(ar, skb); 10175e3dd157SKalle Valo break; 10185e3dd157SKalle Valo case WMI_TX_DELBA_COMPLETE_EVENTID: 10195e3dd157SKalle Valo ath10k_wmi_event_delba_complete(ar, skb); 10205e3dd157SKalle Valo break; 10215e3dd157SKalle Valo case WMI_TX_ADDBA_COMPLETE_EVENTID: 10225e3dd157SKalle Valo ath10k_wmi_event_addba_complete(ar, skb); 10235e3dd157SKalle Valo break; 10245e3dd157SKalle Valo case WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID: 10255e3dd157SKalle Valo ath10k_wmi_event_vdev_install_key_complete(ar, skb); 10265e3dd157SKalle Valo break; 10275e3dd157SKalle Valo case WMI_SERVICE_READY_EVENTID: 10285e3dd157SKalle Valo ath10k_wmi_service_ready_event_rx(ar, skb); 10295e3dd157SKalle Valo break; 10305e3dd157SKalle Valo case WMI_READY_EVENTID: 10315e3dd157SKalle Valo ath10k_wmi_ready_event_rx(ar, skb); 10325e3dd157SKalle Valo break; 10335e3dd157SKalle Valo default: 10345e3dd157SKalle Valo ath10k_warn("Unknown eventid: %d\n", id); 10355e3dd157SKalle Valo break; 10365e3dd157SKalle Valo } 10375e3dd157SKalle Valo 10385e3dd157SKalle Valo dev_kfree_skb(skb); 10395e3dd157SKalle Valo } 10405e3dd157SKalle Valo 10415e3dd157SKalle Valo static void ath10k_wmi_event_work(struct work_struct *work) 10425e3dd157SKalle Valo { 10435e3dd157SKalle Valo struct ath10k *ar = container_of(work, struct ath10k, 10445e3dd157SKalle Valo wmi.wmi_event_work); 10455e3dd157SKalle Valo struct sk_buff *skb; 10465e3dd157SKalle Valo 10475e3dd157SKalle Valo for (;;) { 10485e3dd157SKalle Valo skb = skb_dequeue(&ar->wmi.wmi_event_list); 10495e3dd157SKalle Valo if (!skb) 10505e3dd157SKalle Valo break; 10515e3dd157SKalle Valo 10525e3dd157SKalle Valo ath10k_wmi_event_process(ar, skb); 10535e3dd157SKalle Valo } 10545e3dd157SKalle Valo } 10555e3dd157SKalle Valo 10565e3dd157SKalle Valo static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) 10575e3dd157SKalle Valo { 10585e3dd157SKalle Valo struct wmi_cmd_hdr *cmd_hdr = (struct wmi_cmd_hdr *)skb->data; 10595e3dd157SKalle Valo enum wmi_event_id event_id; 10605e3dd157SKalle Valo 10615e3dd157SKalle Valo event_id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); 10625e3dd157SKalle Valo 10635e3dd157SKalle Valo /* some events require to be handled ASAP 10645e3dd157SKalle Valo * thus can't be defered to a worker thread */ 10655e3dd157SKalle Valo switch (event_id) { 10665e3dd157SKalle Valo case WMI_HOST_SWBA_EVENTID: 10675e3dd157SKalle Valo case WMI_MGMT_RX_EVENTID: 10685e3dd157SKalle Valo ath10k_wmi_event_process(ar, skb); 10695e3dd157SKalle Valo return; 10705e3dd157SKalle Valo default: 10715e3dd157SKalle Valo break; 10725e3dd157SKalle Valo } 10735e3dd157SKalle Valo 10745e3dd157SKalle Valo skb_queue_tail(&ar->wmi.wmi_event_list, skb); 10755e3dd157SKalle Valo queue_work(ar->workqueue, &ar->wmi.wmi_event_work); 10765e3dd157SKalle Valo } 10775e3dd157SKalle Valo 10785e3dd157SKalle Valo /* WMI Initialization functions */ 10795e3dd157SKalle Valo int ath10k_wmi_attach(struct ath10k *ar) 10805e3dd157SKalle Valo { 10815e3dd157SKalle Valo init_completion(&ar->wmi.service_ready); 10825e3dd157SKalle Valo init_completion(&ar->wmi.unified_ready); 10835e3dd157SKalle Valo init_waitqueue_head(&ar->wmi.wq); 10845e3dd157SKalle Valo 10855e3dd157SKalle Valo skb_queue_head_init(&ar->wmi.wmi_event_list); 10865e3dd157SKalle Valo INIT_WORK(&ar->wmi.wmi_event_work, ath10k_wmi_event_work); 10875e3dd157SKalle Valo 10885e3dd157SKalle Valo return 0; 10895e3dd157SKalle Valo } 10905e3dd157SKalle Valo 10915e3dd157SKalle Valo void ath10k_wmi_detach(struct ath10k *ar) 10925e3dd157SKalle Valo { 10935e3dd157SKalle Valo /* HTC should've drained the packets already */ 10945e3dd157SKalle Valo if (WARN_ON(atomic_read(&ar->wmi.pending_tx_count) > 0)) 10955e3dd157SKalle Valo ath10k_warn("there are still pending packets\n"); 10965e3dd157SKalle Valo 10975e3dd157SKalle Valo cancel_work_sync(&ar->wmi.wmi_event_work); 10985e3dd157SKalle Valo skb_queue_purge(&ar->wmi.wmi_event_list); 10995e3dd157SKalle Valo } 11005e3dd157SKalle Valo 11015e3dd157SKalle Valo int ath10k_wmi_connect_htc_service(struct ath10k *ar) 11025e3dd157SKalle Valo { 11035e3dd157SKalle Valo int status; 11045e3dd157SKalle Valo struct ath10k_htc_svc_conn_req conn_req; 11055e3dd157SKalle Valo struct ath10k_htc_svc_conn_resp conn_resp; 11065e3dd157SKalle Valo 11075e3dd157SKalle Valo memset(&conn_req, 0, sizeof(conn_req)); 11085e3dd157SKalle Valo memset(&conn_resp, 0, sizeof(conn_resp)); 11095e3dd157SKalle Valo 11105e3dd157SKalle Valo /* these fields are the same for all service endpoints */ 11115e3dd157SKalle Valo conn_req.ep_ops.ep_tx_complete = ath10k_wmi_htc_tx_complete; 11125e3dd157SKalle Valo conn_req.ep_ops.ep_rx_complete = ath10k_wmi_process_rx; 11135e3dd157SKalle Valo 11145e3dd157SKalle Valo /* connect to control service */ 11155e3dd157SKalle Valo conn_req.service_id = ATH10K_HTC_SVC_ID_WMI_CONTROL; 11165e3dd157SKalle Valo 11175e3dd157SKalle Valo status = ath10k_htc_connect_service(ar->htc, &conn_req, &conn_resp); 11185e3dd157SKalle Valo if (status) { 11195e3dd157SKalle Valo ath10k_warn("failed to connect to WMI CONTROL service status: %d\n", 11205e3dd157SKalle Valo status); 11215e3dd157SKalle Valo return status; 11225e3dd157SKalle Valo } 11235e3dd157SKalle Valo 11245e3dd157SKalle Valo ar->wmi.eid = conn_resp.eid; 11255e3dd157SKalle Valo return 0; 11265e3dd157SKalle Valo } 11275e3dd157SKalle Valo 11285e3dd157SKalle Valo int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, 11295e3dd157SKalle Valo u16 rd5g, u16 ctl2g, u16 ctl5g) 11305e3dd157SKalle Valo { 11315e3dd157SKalle Valo struct wmi_pdev_set_regdomain_cmd *cmd; 11325e3dd157SKalle Valo struct sk_buff *skb; 11335e3dd157SKalle Valo 11345e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 11355e3dd157SKalle Valo if (!skb) 11365e3dd157SKalle Valo return -ENOMEM; 11375e3dd157SKalle Valo 11385e3dd157SKalle Valo cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data; 11395e3dd157SKalle Valo cmd->reg_domain = __cpu_to_le32(rd); 11405e3dd157SKalle Valo cmd->reg_domain_2G = __cpu_to_le32(rd2g); 11415e3dd157SKalle Valo cmd->reg_domain_5G = __cpu_to_le32(rd5g); 11425e3dd157SKalle Valo cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g); 11435e3dd157SKalle Valo cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); 11445e3dd157SKalle Valo 11455e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 11465e3dd157SKalle Valo "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n", 11475e3dd157SKalle Valo rd, rd2g, rd5g, ctl2g, ctl5g); 11485e3dd157SKalle Valo 11495e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_REGDOMAIN_CMDID); 11505e3dd157SKalle Valo } 11515e3dd157SKalle Valo 11525e3dd157SKalle Valo int ath10k_wmi_pdev_set_channel(struct ath10k *ar, 11535e3dd157SKalle Valo const struct wmi_channel_arg *arg) 11545e3dd157SKalle Valo { 11555e3dd157SKalle Valo struct wmi_set_channel_cmd *cmd; 11565e3dd157SKalle Valo struct sk_buff *skb; 11575e3dd157SKalle Valo 11585e3dd157SKalle Valo if (arg->passive) 11595e3dd157SKalle Valo return -EINVAL; 11605e3dd157SKalle Valo 11615e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 11625e3dd157SKalle Valo if (!skb) 11635e3dd157SKalle Valo return -ENOMEM; 11645e3dd157SKalle Valo 11655e3dd157SKalle Valo cmd = (struct wmi_set_channel_cmd *)skb->data; 11665e3dd157SKalle Valo cmd->chan.mhz = __cpu_to_le32(arg->freq); 11675e3dd157SKalle Valo cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq); 11685e3dd157SKalle Valo cmd->chan.mode = arg->mode; 11695e3dd157SKalle Valo cmd->chan.min_power = arg->min_power; 11705e3dd157SKalle Valo cmd->chan.max_power = arg->max_power; 11715e3dd157SKalle Valo cmd->chan.reg_power = arg->max_reg_power; 11725e3dd157SKalle Valo cmd->chan.reg_classid = arg->reg_class_id; 11735e3dd157SKalle Valo cmd->chan.antenna_max = arg->max_antenna_gain; 11745e3dd157SKalle Valo 11755e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 11765e3dd157SKalle Valo "wmi set channel mode %d freq %d\n", 11775e3dd157SKalle Valo arg->mode, arg->freq); 11785e3dd157SKalle Valo 11795e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_CHANNEL_CMDID); 11805e3dd157SKalle Valo } 11815e3dd157SKalle Valo 11825e3dd157SKalle Valo int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) 11835e3dd157SKalle Valo { 11845e3dd157SKalle Valo struct wmi_pdev_suspend_cmd *cmd; 11855e3dd157SKalle Valo struct sk_buff *skb; 11865e3dd157SKalle Valo 11875e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 11885e3dd157SKalle Valo if (!skb) 11895e3dd157SKalle Valo return -ENOMEM; 11905e3dd157SKalle Valo 11915e3dd157SKalle Valo cmd = (struct wmi_pdev_suspend_cmd *)skb->data; 11925e3dd157SKalle Valo cmd->suspend_opt = WMI_PDEV_SUSPEND; 11935e3dd157SKalle Valo 11945e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SUSPEND_CMDID); 11955e3dd157SKalle Valo } 11965e3dd157SKalle Valo 11975e3dd157SKalle Valo int ath10k_wmi_pdev_resume_target(struct ath10k *ar) 11985e3dd157SKalle Valo { 11995e3dd157SKalle Valo struct sk_buff *skb; 12005e3dd157SKalle Valo 12015e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(0); 12025e3dd157SKalle Valo if (skb == NULL) 12035e3dd157SKalle Valo return -ENOMEM; 12045e3dd157SKalle Valo 12055e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_RESUME_CMDID); 12065e3dd157SKalle Valo } 12075e3dd157SKalle Valo 12085e3dd157SKalle Valo int ath10k_wmi_pdev_set_param(struct ath10k *ar, enum wmi_pdev_param id, 12095e3dd157SKalle Valo u32 value) 12105e3dd157SKalle Valo { 12115e3dd157SKalle Valo struct wmi_pdev_set_param_cmd *cmd; 12125e3dd157SKalle Valo struct sk_buff *skb; 12135e3dd157SKalle Valo 12145e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 12155e3dd157SKalle Valo if (!skb) 12165e3dd157SKalle Valo return -ENOMEM; 12175e3dd157SKalle Valo 12185e3dd157SKalle Valo cmd = (struct wmi_pdev_set_param_cmd *)skb->data; 12195e3dd157SKalle Valo cmd->param_id = __cpu_to_le32(id); 12205e3dd157SKalle Valo cmd->param_value = __cpu_to_le32(value); 12215e3dd157SKalle Valo 12225e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n", 12235e3dd157SKalle Valo id, value); 12245e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_PARAM_CMDID); 12255e3dd157SKalle Valo } 12265e3dd157SKalle Valo 12275e3dd157SKalle Valo int ath10k_wmi_cmd_init(struct ath10k *ar) 12285e3dd157SKalle Valo { 12295e3dd157SKalle Valo struct wmi_init_cmd *cmd; 12305e3dd157SKalle Valo struct sk_buff *buf; 12315e3dd157SKalle Valo struct wmi_resource_config config = {}; 12325e3dd157SKalle Valo u32 val; 12335e3dd157SKalle Valo 12345e3dd157SKalle Valo config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); 12355e3dd157SKalle Valo config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); 12365e3dd157SKalle Valo config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS); 12375e3dd157SKalle Valo 12385e3dd157SKalle Valo config.num_offload_reorder_bufs = 12395e3dd157SKalle Valo __cpu_to_le32(TARGET_NUM_OFFLOAD_REORDER_BUFS); 12405e3dd157SKalle Valo 12415e3dd157SKalle Valo config.num_peer_keys = __cpu_to_le32(TARGET_NUM_PEER_KEYS); 12425e3dd157SKalle Valo config.num_tids = __cpu_to_le32(TARGET_NUM_TIDS); 12435e3dd157SKalle Valo config.ast_skid_limit = __cpu_to_le32(TARGET_AST_SKID_LIMIT); 12445e3dd157SKalle Valo config.tx_chain_mask = __cpu_to_le32(TARGET_TX_CHAIN_MASK); 12455e3dd157SKalle Valo config.rx_chain_mask = __cpu_to_le32(TARGET_RX_CHAIN_MASK); 12465e3dd157SKalle Valo config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI); 12475e3dd157SKalle Valo config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI); 12485e3dd157SKalle Valo config.rx_timeout_pri_be = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI); 12495e3dd157SKalle Valo config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_RX_TIMEOUT_HI_PRI); 12505e3dd157SKalle Valo config.rx_decap_mode = __cpu_to_le32(TARGET_RX_DECAP_MODE); 12515e3dd157SKalle Valo 12525e3dd157SKalle Valo config.scan_max_pending_reqs = 12535e3dd157SKalle Valo __cpu_to_le32(TARGET_SCAN_MAX_PENDING_REQS); 12545e3dd157SKalle Valo 12555e3dd157SKalle Valo config.bmiss_offload_max_vdev = 12565e3dd157SKalle Valo __cpu_to_le32(TARGET_BMISS_OFFLOAD_MAX_VDEV); 12575e3dd157SKalle Valo 12585e3dd157SKalle Valo config.roam_offload_max_vdev = 12595e3dd157SKalle Valo __cpu_to_le32(TARGET_ROAM_OFFLOAD_MAX_VDEV); 12605e3dd157SKalle Valo 12615e3dd157SKalle Valo config.roam_offload_max_ap_profiles = 12625e3dd157SKalle Valo __cpu_to_le32(TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES); 12635e3dd157SKalle Valo 12645e3dd157SKalle Valo config.num_mcast_groups = __cpu_to_le32(TARGET_NUM_MCAST_GROUPS); 12655e3dd157SKalle Valo config.num_mcast_table_elems = 12665e3dd157SKalle Valo __cpu_to_le32(TARGET_NUM_MCAST_TABLE_ELEMS); 12675e3dd157SKalle Valo 12685e3dd157SKalle Valo config.mcast2ucast_mode = __cpu_to_le32(TARGET_MCAST2UCAST_MODE); 12695e3dd157SKalle Valo config.tx_dbg_log_size = __cpu_to_le32(TARGET_TX_DBG_LOG_SIZE); 12705e3dd157SKalle Valo config.num_wds_entries = __cpu_to_le32(TARGET_NUM_WDS_ENTRIES); 12715e3dd157SKalle Valo config.dma_burst_size = __cpu_to_le32(TARGET_DMA_BURST_SIZE); 12725e3dd157SKalle Valo config.mac_aggr_delim = __cpu_to_le32(TARGET_MAC_AGGR_DELIM); 12735e3dd157SKalle Valo 12745e3dd157SKalle Valo val = TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; 12755e3dd157SKalle Valo config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val); 12765e3dd157SKalle Valo 12775e3dd157SKalle Valo config.vow_config = __cpu_to_le32(TARGET_VOW_CONFIG); 12785e3dd157SKalle Valo 12795e3dd157SKalle Valo config.gtk_offload_max_vdev = 12805e3dd157SKalle Valo __cpu_to_le32(TARGET_GTK_OFFLOAD_MAX_VDEV); 12815e3dd157SKalle Valo 12825e3dd157SKalle Valo config.num_msdu_desc = __cpu_to_le32(TARGET_NUM_MSDU_DESC); 12835e3dd157SKalle Valo config.max_frag_entries = __cpu_to_le32(TARGET_MAX_FRAG_ENTRIES); 12845e3dd157SKalle Valo 12855e3dd157SKalle Valo buf = ath10k_wmi_alloc_skb(sizeof(*cmd)); 12865e3dd157SKalle Valo if (!buf) 12875e3dd157SKalle Valo return -ENOMEM; 12885e3dd157SKalle Valo 12895e3dd157SKalle Valo cmd = (struct wmi_init_cmd *)buf->data; 12905e3dd157SKalle Valo cmd->num_host_mem_chunks = 0; 12915e3dd157SKalle Valo memcpy(&cmd->resource_config, &config, sizeof(config)); 12925e3dd157SKalle Valo 12935e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n"); 12945e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, buf, WMI_INIT_CMDID); 12955e3dd157SKalle Valo } 12965e3dd157SKalle Valo 12975e3dd157SKalle Valo static int ath10k_wmi_start_scan_calc_len(const struct wmi_start_scan_arg *arg) 12985e3dd157SKalle Valo { 12995e3dd157SKalle Valo int len; 13005e3dd157SKalle Valo 13015e3dd157SKalle Valo len = sizeof(struct wmi_start_scan_cmd); 13025e3dd157SKalle Valo 13035e3dd157SKalle Valo if (arg->ie_len) { 13045e3dd157SKalle Valo if (!arg->ie) 13055e3dd157SKalle Valo return -EINVAL; 13065e3dd157SKalle Valo if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN) 13075e3dd157SKalle Valo return -EINVAL; 13085e3dd157SKalle Valo 13095e3dd157SKalle Valo len += sizeof(struct wmi_ie_data); 13105e3dd157SKalle Valo len += roundup(arg->ie_len, 4); 13115e3dd157SKalle Valo } 13125e3dd157SKalle Valo 13135e3dd157SKalle Valo if (arg->n_channels) { 13145e3dd157SKalle Valo if (!arg->channels) 13155e3dd157SKalle Valo return -EINVAL; 13165e3dd157SKalle Valo if (arg->n_channels > ARRAY_SIZE(arg->channels)) 13175e3dd157SKalle Valo return -EINVAL; 13185e3dd157SKalle Valo 13195e3dd157SKalle Valo len += sizeof(struct wmi_chan_list); 13205e3dd157SKalle Valo len += sizeof(__le32) * arg->n_channels; 13215e3dd157SKalle Valo } 13225e3dd157SKalle Valo 13235e3dd157SKalle Valo if (arg->n_ssids) { 13245e3dd157SKalle Valo if (!arg->ssids) 13255e3dd157SKalle Valo return -EINVAL; 13265e3dd157SKalle Valo if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID) 13275e3dd157SKalle Valo return -EINVAL; 13285e3dd157SKalle Valo 13295e3dd157SKalle Valo len += sizeof(struct wmi_ssid_list); 13305e3dd157SKalle Valo len += sizeof(struct wmi_ssid) * arg->n_ssids; 13315e3dd157SKalle Valo } 13325e3dd157SKalle Valo 13335e3dd157SKalle Valo if (arg->n_bssids) { 13345e3dd157SKalle Valo if (!arg->bssids) 13355e3dd157SKalle Valo return -EINVAL; 13365e3dd157SKalle Valo if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID) 13375e3dd157SKalle Valo return -EINVAL; 13385e3dd157SKalle Valo 13395e3dd157SKalle Valo len += sizeof(struct wmi_bssid_list); 13405e3dd157SKalle Valo len += sizeof(struct wmi_mac_addr) * arg->n_bssids; 13415e3dd157SKalle Valo } 13425e3dd157SKalle Valo 13435e3dd157SKalle Valo return len; 13445e3dd157SKalle Valo } 13455e3dd157SKalle Valo 13465e3dd157SKalle Valo int ath10k_wmi_start_scan(struct ath10k *ar, 13475e3dd157SKalle Valo const struct wmi_start_scan_arg *arg) 13485e3dd157SKalle Valo { 13495e3dd157SKalle Valo struct wmi_start_scan_cmd *cmd; 13505e3dd157SKalle Valo struct sk_buff *skb; 13515e3dd157SKalle Valo struct wmi_ie_data *ie; 13525e3dd157SKalle Valo struct wmi_chan_list *channels; 13535e3dd157SKalle Valo struct wmi_ssid_list *ssids; 13545e3dd157SKalle Valo struct wmi_bssid_list *bssids; 13555e3dd157SKalle Valo u32 scan_id; 13565e3dd157SKalle Valo u32 scan_req_id; 13575e3dd157SKalle Valo int off; 13585e3dd157SKalle Valo int len = 0; 13595e3dd157SKalle Valo int i; 13605e3dd157SKalle Valo 13615e3dd157SKalle Valo len = ath10k_wmi_start_scan_calc_len(arg); 13625e3dd157SKalle Valo if (len < 0) 13635e3dd157SKalle Valo return len; /* len contains error code here */ 13645e3dd157SKalle Valo 13655e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(len); 13665e3dd157SKalle Valo if (!skb) 13675e3dd157SKalle Valo return -ENOMEM; 13685e3dd157SKalle Valo 13695e3dd157SKalle Valo scan_id = WMI_HOST_SCAN_REQ_ID_PREFIX; 13705e3dd157SKalle Valo scan_id |= arg->scan_id; 13715e3dd157SKalle Valo 13725e3dd157SKalle Valo scan_req_id = WMI_HOST_SCAN_REQUESTOR_ID_PREFIX; 13735e3dd157SKalle Valo scan_req_id |= arg->scan_req_id; 13745e3dd157SKalle Valo 13755e3dd157SKalle Valo cmd = (struct wmi_start_scan_cmd *)skb->data; 13765e3dd157SKalle Valo cmd->scan_id = __cpu_to_le32(scan_id); 13775e3dd157SKalle Valo cmd->scan_req_id = __cpu_to_le32(scan_req_id); 13785e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(arg->vdev_id); 13795e3dd157SKalle Valo cmd->scan_priority = __cpu_to_le32(arg->scan_priority); 13805e3dd157SKalle Valo cmd->notify_scan_events = __cpu_to_le32(arg->notify_scan_events); 13815e3dd157SKalle Valo cmd->dwell_time_active = __cpu_to_le32(arg->dwell_time_active); 13825e3dd157SKalle Valo cmd->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive); 13835e3dd157SKalle Valo cmd->min_rest_time = __cpu_to_le32(arg->min_rest_time); 13845e3dd157SKalle Valo cmd->max_rest_time = __cpu_to_le32(arg->max_rest_time); 13855e3dd157SKalle Valo cmd->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time); 13865e3dd157SKalle Valo cmd->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time); 13875e3dd157SKalle Valo cmd->idle_time = __cpu_to_le32(arg->idle_time); 13885e3dd157SKalle Valo cmd->max_scan_time = __cpu_to_le32(arg->max_scan_time); 13895e3dd157SKalle Valo cmd->probe_delay = __cpu_to_le32(arg->probe_delay); 13905e3dd157SKalle Valo cmd->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags); 13915e3dd157SKalle Valo 13925e3dd157SKalle Valo /* TLV list starts after fields included in the struct */ 13935e3dd157SKalle Valo off = sizeof(*cmd); 13945e3dd157SKalle Valo 13955e3dd157SKalle Valo if (arg->n_channels) { 13965e3dd157SKalle Valo channels = (void *)skb->data + off; 13975e3dd157SKalle Valo channels->tag = __cpu_to_le32(WMI_CHAN_LIST_TAG); 13985e3dd157SKalle Valo channels->num_chan = __cpu_to_le32(arg->n_channels); 13995e3dd157SKalle Valo 14005e3dd157SKalle Valo for (i = 0; i < arg->n_channels; i++) 14015e3dd157SKalle Valo channels->channel_list[i] = 14025e3dd157SKalle Valo __cpu_to_le32(arg->channels[i]); 14035e3dd157SKalle Valo 14045e3dd157SKalle Valo off += sizeof(*channels); 14055e3dd157SKalle Valo off += sizeof(__le32) * arg->n_channels; 14065e3dd157SKalle Valo } 14075e3dd157SKalle Valo 14085e3dd157SKalle Valo if (arg->n_ssids) { 14095e3dd157SKalle Valo ssids = (void *)skb->data + off; 14105e3dd157SKalle Valo ssids->tag = __cpu_to_le32(WMI_SSID_LIST_TAG); 14115e3dd157SKalle Valo ssids->num_ssids = __cpu_to_le32(arg->n_ssids); 14125e3dd157SKalle Valo 14135e3dd157SKalle Valo for (i = 0; i < arg->n_ssids; i++) { 14145e3dd157SKalle Valo ssids->ssids[i].ssid_len = 14155e3dd157SKalle Valo __cpu_to_le32(arg->ssids[i].len); 14165e3dd157SKalle Valo memcpy(&ssids->ssids[i].ssid, 14175e3dd157SKalle Valo arg->ssids[i].ssid, 14185e3dd157SKalle Valo arg->ssids[i].len); 14195e3dd157SKalle Valo } 14205e3dd157SKalle Valo 14215e3dd157SKalle Valo off += sizeof(*ssids); 14225e3dd157SKalle Valo off += sizeof(struct wmi_ssid) * arg->n_ssids; 14235e3dd157SKalle Valo } 14245e3dd157SKalle Valo 14255e3dd157SKalle Valo if (arg->n_bssids) { 14265e3dd157SKalle Valo bssids = (void *)skb->data + off; 14275e3dd157SKalle Valo bssids->tag = __cpu_to_le32(WMI_BSSID_LIST_TAG); 14285e3dd157SKalle Valo bssids->num_bssid = __cpu_to_le32(arg->n_bssids); 14295e3dd157SKalle Valo 14305e3dd157SKalle Valo for (i = 0; i < arg->n_bssids; i++) 14315e3dd157SKalle Valo memcpy(&bssids->bssid_list[i], 14325e3dd157SKalle Valo arg->bssids[i].bssid, 14335e3dd157SKalle Valo ETH_ALEN); 14345e3dd157SKalle Valo 14355e3dd157SKalle Valo off += sizeof(*bssids); 14365e3dd157SKalle Valo off += sizeof(struct wmi_mac_addr) * arg->n_bssids; 14375e3dd157SKalle Valo } 14385e3dd157SKalle Valo 14395e3dd157SKalle Valo if (arg->ie_len) { 14405e3dd157SKalle Valo ie = (void *)skb->data + off; 14415e3dd157SKalle Valo ie->tag = __cpu_to_le32(WMI_IE_TAG); 14425e3dd157SKalle Valo ie->ie_len = __cpu_to_le32(arg->ie_len); 14435e3dd157SKalle Valo memcpy(ie->ie_data, arg->ie, arg->ie_len); 14445e3dd157SKalle Valo 14455e3dd157SKalle Valo off += sizeof(*ie); 14465e3dd157SKalle Valo off += roundup(arg->ie_len, 4); 14475e3dd157SKalle Valo } 14485e3dd157SKalle Valo 14495e3dd157SKalle Valo if (off != skb->len) { 14505e3dd157SKalle Valo dev_kfree_skb(skb); 14515e3dd157SKalle Valo return -EINVAL; 14525e3dd157SKalle Valo } 14535e3dd157SKalle Valo 14545e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n"); 14555e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_START_SCAN_CMDID); 14565e3dd157SKalle Valo } 14575e3dd157SKalle Valo 14585e3dd157SKalle Valo void ath10k_wmi_start_scan_init(struct ath10k *ar, 14595e3dd157SKalle Valo struct wmi_start_scan_arg *arg) 14605e3dd157SKalle Valo { 14615e3dd157SKalle Valo /* setup commonly used values */ 14625e3dd157SKalle Valo arg->scan_req_id = 1; 14635e3dd157SKalle Valo arg->scan_priority = WMI_SCAN_PRIORITY_LOW; 14645e3dd157SKalle Valo arg->dwell_time_active = 50; 14655e3dd157SKalle Valo arg->dwell_time_passive = 150; 14665e3dd157SKalle Valo arg->min_rest_time = 50; 14675e3dd157SKalle Valo arg->max_rest_time = 500; 14685e3dd157SKalle Valo arg->repeat_probe_time = 0; 14695e3dd157SKalle Valo arg->probe_spacing_time = 0; 14705e3dd157SKalle Valo arg->idle_time = 0; 14715e3dd157SKalle Valo arg->max_scan_time = 5000; 14725e3dd157SKalle Valo arg->probe_delay = 5; 14735e3dd157SKalle Valo arg->notify_scan_events = WMI_SCAN_EVENT_STARTED 14745e3dd157SKalle Valo | WMI_SCAN_EVENT_COMPLETED 14755e3dd157SKalle Valo | WMI_SCAN_EVENT_BSS_CHANNEL 14765e3dd157SKalle Valo | WMI_SCAN_EVENT_FOREIGN_CHANNEL 14775e3dd157SKalle Valo | WMI_SCAN_EVENT_DEQUEUED; 14785e3dd157SKalle Valo arg->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES; 14795e3dd157SKalle Valo arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT; 14805e3dd157SKalle Valo arg->n_bssids = 1; 14815e3dd157SKalle Valo arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; 14825e3dd157SKalle Valo } 14835e3dd157SKalle Valo 14845e3dd157SKalle Valo int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) 14855e3dd157SKalle Valo { 14865e3dd157SKalle Valo struct wmi_stop_scan_cmd *cmd; 14875e3dd157SKalle Valo struct sk_buff *skb; 14885e3dd157SKalle Valo u32 scan_id; 14895e3dd157SKalle Valo u32 req_id; 14905e3dd157SKalle Valo 14915e3dd157SKalle Valo if (arg->req_id > 0xFFF) 14925e3dd157SKalle Valo return -EINVAL; 14935e3dd157SKalle Valo if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) 14945e3dd157SKalle Valo return -EINVAL; 14955e3dd157SKalle Valo 14965e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 14975e3dd157SKalle Valo if (!skb) 14985e3dd157SKalle Valo return -ENOMEM; 14995e3dd157SKalle Valo 15005e3dd157SKalle Valo scan_id = arg->u.scan_id; 15015e3dd157SKalle Valo scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX; 15025e3dd157SKalle Valo 15035e3dd157SKalle Valo req_id = arg->req_id; 15045e3dd157SKalle Valo req_id |= WMI_HOST_SCAN_REQUESTOR_ID_PREFIX; 15055e3dd157SKalle Valo 15065e3dd157SKalle Valo cmd = (struct wmi_stop_scan_cmd *)skb->data; 15075e3dd157SKalle Valo cmd->req_type = __cpu_to_le32(arg->req_type); 15085e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(arg->u.vdev_id); 15095e3dd157SKalle Valo cmd->scan_id = __cpu_to_le32(scan_id); 15105e3dd157SKalle Valo cmd->scan_req_id = __cpu_to_le32(req_id); 15115e3dd157SKalle Valo 15125e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 15135e3dd157SKalle Valo "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n", 15145e3dd157SKalle Valo arg->req_id, arg->req_type, arg->u.scan_id); 15155e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_STOP_SCAN_CMDID); 15165e3dd157SKalle Valo } 15175e3dd157SKalle Valo 15185e3dd157SKalle Valo int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, 15195e3dd157SKalle Valo enum wmi_vdev_type type, 15205e3dd157SKalle Valo enum wmi_vdev_subtype subtype, 15215e3dd157SKalle Valo const u8 macaddr[ETH_ALEN]) 15225e3dd157SKalle Valo { 15235e3dd157SKalle Valo struct wmi_vdev_create_cmd *cmd; 15245e3dd157SKalle Valo struct sk_buff *skb; 15255e3dd157SKalle Valo 15265e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 15275e3dd157SKalle Valo if (!skb) 15285e3dd157SKalle Valo return -ENOMEM; 15295e3dd157SKalle Valo 15305e3dd157SKalle Valo cmd = (struct wmi_vdev_create_cmd *)skb->data; 15315e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 15325e3dd157SKalle Valo cmd->vdev_type = __cpu_to_le32(type); 15335e3dd157SKalle Valo cmd->vdev_subtype = __cpu_to_le32(subtype); 15345e3dd157SKalle Valo memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN); 15355e3dd157SKalle Valo 15365e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 15375e3dd157SKalle Valo "WMI vdev create: id %d type %d subtype %d macaddr %pM\n", 15385e3dd157SKalle Valo vdev_id, type, subtype, macaddr); 15395e3dd157SKalle Valo 15405e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_CREATE_CMDID); 15415e3dd157SKalle Valo } 15425e3dd157SKalle Valo 15435e3dd157SKalle Valo int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) 15445e3dd157SKalle Valo { 15455e3dd157SKalle Valo struct wmi_vdev_delete_cmd *cmd; 15465e3dd157SKalle Valo struct sk_buff *skb; 15475e3dd157SKalle Valo 15485e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 15495e3dd157SKalle Valo if (!skb) 15505e3dd157SKalle Valo return -ENOMEM; 15515e3dd157SKalle Valo 15525e3dd157SKalle Valo cmd = (struct wmi_vdev_delete_cmd *)skb->data; 15535e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 15545e3dd157SKalle Valo 15555e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 15565e3dd157SKalle Valo "WMI vdev delete id %d\n", vdev_id); 15575e3dd157SKalle Valo 15585e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_DELETE_CMDID); 15595e3dd157SKalle Valo } 15605e3dd157SKalle Valo 15615e3dd157SKalle Valo static int ath10k_wmi_vdev_start_restart(struct ath10k *ar, 15625e3dd157SKalle Valo const struct wmi_vdev_start_request_arg *arg, 15635e3dd157SKalle Valo enum wmi_cmd_id cmd_id) 15645e3dd157SKalle Valo { 15655e3dd157SKalle Valo struct wmi_vdev_start_request_cmd *cmd; 15665e3dd157SKalle Valo struct sk_buff *skb; 15675e3dd157SKalle Valo const char *cmdname; 15685e3dd157SKalle Valo u32 flags = 0; 15695e3dd157SKalle Valo 15705e3dd157SKalle Valo if (cmd_id != WMI_VDEV_START_REQUEST_CMDID && 15715e3dd157SKalle Valo cmd_id != WMI_VDEV_RESTART_REQUEST_CMDID) 15725e3dd157SKalle Valo return -EINVAL; 15735e3dd157SKalle Valo if (WARN_ON(arg->ssid && arg->ssid_len == 0)) 15745e3dd157SKalle Valo return -EINVAL; 15755e3dd157SKalle Valo if (WARN_ON(arg->hidden_ssid && !arg->ssid)) 15765e3dd157SKalle Valo return -EINVAL; 15775e3dd157SKalle Valo if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) 15785e3dd157SKalle Valo return -EINVAL; 15795e3dd157SKalle Valo 15805e3dd157SKalle Valo if (cmd_id == WMI_VDEV_START_REQUEST_CMDID) 15815e3dd157SKalle Valo cmdname = "start"; 15825e3dd157SKalle Valo else if (cmd_id == WMI_VDEV_RESTART_REQUEST_CMDID) 15835e3dd157SKalle Valo cmdname = "restart"; 15845e3dd157SKalle Valo else 15855e3dd157SKalle Valo return -EINVAL; /* should not happen, we already check cmd_id */ 15865e3dd157SKalle Valo 15875e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 15885e3dd157SKalle Valo if (!skb) 15895e3dd157SKalle Valo return -ENOMEM; 15905e3dd157SKalle Valo 15915e3dd157SKalle Valo if (arg->hidden_ssid) 15925e3dd157SKalle Valo flags |= WMI_VDEV_START_HIDDEN_SSID; 15935e3dd157SKalle Valo if (arg->pmf_enabled) 15945e3dd157SKalle Valo flags |= WMI_VDEV_START_PMF_ENABLED; 15955e3dd157SKalle Valo 15965e3dd157SKalle Valo cmd = (struct wmi_vdev_start_request_cmd *)skb->data; 15975e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(arg->vdev_id); 15985e3dd157SKalle Valo cmd->disable_hw_ack = __cpu_to_le32(arg->disable_hw_ack); 15995e3dd157SKalle Valo cmd->beacon_interval = __cpu_to_le32(arg->bcn_intval); 16005e3dd157SKalle Valo cmd->dtim_period = __cpu_to_le32(arg->dtim_period); 16015e3dd157SKalle Valo cmd->flags = __cpu_to_le32(flags); 16025e3dd157SKalle Valo cmd->bcn_tx_rate = __cpu_to_le32(arg->bcn_tx_rate); 16035e3dd157SKalle Valo cmd->bcn_tx_power = __cpu_to_le32(arg->bcn_tx_power); 16045e3dd157SKalle Valo 16055e3dd157SKalle Valo if (arg->ssid) { 16065e3dd157SKalle Valo cmd->ssid.ssid_len = __cpu_to_le32(arg->ssid_len); 16075e3dd157SKalle Valo memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len); 16085e3dd157SKalle Valo } 16095e3dd157SKalle Valo 16105e3dd157SKalle Valo cmd->chan.mhz = __cpu_to_le32(arg->channel.freq); 16115e3dd157SKalle Valo 16125e3dd157SKalle Valo cmd->chan.band_center_freq1 = 16135e3dd157SKalle Valo __cpu_to_le32(arg->channel.band_center_freq1); 16145e3dd157SKalle Valo 16155e3dd157SKalle Valo cmd->chan.mode = arg->channel.mode; 16165e3dd157SKalle Valo cmd->chan.min_power = arg->channel.min_power; 16175e3dd157SKalle Valo cmd->chan.max_power = arg->channel.max_power; 16185e3dd157SKalle Valo cmd->chan.reg_power = arg->channel.max_reg_power; 16195e3dd157SKalle Valo cmd->chan.reg_classid = arg->channel.reg_class_id; 16205e3dd157SKalle Valo cmd->chan.antenna_max = arg->channel.max_antenna_gain; 16215e3dd157SKalle Valo 16225e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 16235e3dd157SKalle Valo "wmi vdev %s id 0x%x freq %d, mode %d, ch_flags: 0x%0X," 16245e3dd157SKalle Valo "max_power: %d\n", cmdname, arg->vdev_id, arg->channel.freq, 16255e3dd157SKalle Valo arg->channel.mode, flags, arg->channel.max_power); 16265e3dd157SKalle Valo 16275e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, cmd_id); 16285e3dd157SKalle Valo } 16295e3dd157SKalle Valo 16305e3dd157SKalle Valo int ath10k_wmi_vdev_start(struct ath10k *ar, 16315e3dd157SKalle Valo const struct wmi_vdev_start_request_arg *arg) 16325e3dd157SKalle Valo { 16335e3dd157SKalle Valo return ath10k_wmi_vdev_start_restart(ar, arg, 16345e3dd157SKalle Valo WMI_VDEV_START_REQUEST_CMDID); 16355e3dd157SKalle Valo } 16365e3dd157SKalle Valo 16375e3dd157SKalle Valo int ath10k_wmi_vdev_restart(struct ath10k *ar, 16385e3dd157SKalle Valo const struct wmi_vdev_start_request_arg *arg) 16395e3dd157SKalle Valo { 16405e3dd157SKalle Valo return ath10k_wmi_vdev_start_restart(ar, arg, 16415e3dd157SKalle Valo WMI_VDEV_RESTART_REQUEST_CMDID); 16425e3dd157SKalle Valo } 16435e3dd157SKalle Valo 16445e3dd157SKalle Valo int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) 16455e3dd157SKalle Valo { 16465e3dd157SKalle Valo struct wmi_vdev_stop_cmd *cmd; 16475e3dd157SKalle Valo struct sk_buff *skb; 16485e3dd157SKalle Valo 16495e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 16505e3dd157SKalle Valo if (!skb) 16515e3dd157SKalle Valo return -ENOMEM; 16525e3dd157SKalle Valo 16535e3dd157SKalle Valo cmd = (struct wmi_vdev_stop_cmd *)skb->data; 16545e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 16555e3dd157SKalle Valo 16565e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); 16575e3dd157SKalle Valo 16585e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_STOP_CMDID); 16595e3dd157SKalle Valo } 16605e3dd157SKalle Valo 16615e3dd157SKalle Valo int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) 16625e3dd157SKalle Valo { 16635e3dd157SKalle Valo struct wmi_vdev_up_cmd *cmd; 16645e3dd157SKalle Valo struct sk_buff *skb; 16655e3dd157SKalle Valo 16665e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 16675e3dd157SKalle Valo if (!skb) 16685e3dd157SKalle Valo return -ENOMEM; 16695e3dd157SKalle Valo 16705e3dd157SKalle Valo cmd = (struct wmi_vdev_up_cmd *)skb->data; 16715e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 16725e3dd157SKalle Valo cmd->vdev_assoc_id = __cpu_to_le32(aid); 16735e3dd157SKalle Valo memcpy(&cmd->vdev_bssid.addr, bssid, 6); 16745e3dd157SKalle Valo 16755e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 16765e3dd157SKalle Valo "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n", 16775e3dd157SKalle Valo vdev_id, aid, bssid); 16785e3dd157SKalle Valo 16795e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_UP_CMDID); 16805e3dd157SKalle Valo } 16815e3dd157SKalle Valo 16825e3dd157SKalle Valo int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) 16835e3dd157SKalle Valo { 16845e3dd157SKalle Valo struct wmi_vdev_down_cmd *cmd; 16855e3dd157SKalle Valo struct sk_buff *skb; 16865e3dd157SKalle Valo 16875e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 16885e3dd157SKalle Valo if (!skb) 16895e3dd157SKalle Valo return -ENOMEM; 16905e3dd157SKalle Valo 16915e3dd157SKalle Valo cmd = (struct wmi_vdev_down_cmd *)skb->data; 16925e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 16935e3dd157SKalle Valo 16945e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 16955e3dd157SKalle Valo "wmi mgmt vdev down id 0x%x\n", vdev_id); 16965e3dd157SKalle Valo 16975e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_DOWN_CMDID); 16985e3dd157SKalle Valo } 16995e3dd157SKalle Valo 17005e3dd157SKalle Valo int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, 17015e3dd157SKalle Valo enum wmi_vdev_param param_id, u32 param_value) 17025e3dd157SKalle Valo { 17035e3dd157SKalle Valo struct wmi_vdev_set_param_cmd *cmd; 17045e3dd157SKalle Valo struct sk_buff *skb; 17055e3dd157SKalle Valo 17065e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 17075e3dd157SKalle Valo if (!skb) 17085e3dd157SKalle Valo return -ENOMEM; 17095e3dd157SKalle Valo 17105e3dd157SKalle Valo cmd = (struct wmi_vdev_set_param_cmd *)skb->data; 17115e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 17125e3dd157SKalle Valo cmd->param_id = __cpu_to_le32(param_id); 17135e3dd157SKalle Valo cmd->param_value = __cpu_to_le32(param_value); 17145e3dd157SKalle Valo 17155e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 17165e3dd157SKalle Valo "wmi vdev id 0x%x set param %d value %d\n", 17175e3dd157SKalle Valo vdev_id, param_id, param_value); 17185e3dd157SKalle Valo 17195e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_SET_PARAM_CMDID); 17205e3dd157SKalle Valo } 17215e3dd157SKalle Valo 17225e3dd157SKalle Valo int ath10k_wmi_vdev_install_key(struct ath10k *ar, 17235e3dd157SKalle Valo const struct wmi_vdev_install_key_arg *arg) 17245e3dd157SKalle Valo { 17255e3dd157SKalle Valo struct wmi_vdev_install_key_cmd *cmd; 17265e3dd157SKalle Valo struct sk_buff *skb; 17275e3dd157SKalle Valo 17285e3dd157SKalle Valo if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) 17295e3dd157SKalle Valo return -EINVAL; 17305e3dd157SKalle Valo if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) 17315e3dd157SKalle Valo return -EINVAL; 17325e3dd157SKalle Valo 17335e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len); 17345e3dd157SKalle Valo if (!skb) 17355e3dd157SKalle Valo return -ENOMEM; 17365e3dd157SKalle Valo 17375e3dd157SKalle Valo cmd = (struct wmi_vdev_install_key_cmd *)skb->data; 17385e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(arg->vdev_id); 17395e3dd157SKalle Valo cmd->key_idx = __cpu_to_le32(arg->key_idx); 17405e3dd157SKalle Valo cmd->key_flags = __cpu_to_le32(arg->key_flags); 17415e3dd157SKalle Valo cmd->key_cipher = __cpu_to_le32(arg->key_cipher); 17425e3dd157SKalle Valo cmd->key_len = __cpu_to_le32(arg->key_len); 17435e3dd157SKalle Valo cmd->key_txmic_len = __cpu_to_le32(arg->key_txmic_len); 17445e3dd157SKalle Valo cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len); 17455e3dd157SKalle Valo 17465e3dd157SKalle Valo if (arg->macaddr) 17475e3dd157SKalle Valo memcpy(cmd->peer_macaddr.addr, arg->macaddr, ETH_ALEN); 17485e3dd157SKalle Valo if (arg->key_data) 17495e3dd157SKalle Valo memcpy(cmd->key_data, arg->key_data, arg->key_len); 17505e3dd157SKalle Valo 17515e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_INSTALL_KEY_CMDID); 17525e3dd157SKalle Valo } 17535e3dd157SKalle Valo 17545e3dd157SKalle Valo int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, 17555e3dd157SKalle Valo const u8 peer_addr[ETH_ALEN]) 17565e3dd157SKalle Valo { 17575e3dd157SKalle Valo struct wmi_peer_create_cmd *cmd; 17585e3dd157SKalle Valo struct sk_buff *skb; 17595e3dd157SKalle Valo 17605e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 17615e3dd157SKalle Valo if (!skb) 17625e3dd157SKalle Valo return -ENOMEM; 17635e3dd157SKalle Valo 17645e3dd157SKalle Valo cmd = (struct wmi_peer_create_cmd *)skb->data; 17655e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 17665e3dd157SKalle Valo memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); 17675e3dd157SKalle Valo 17685e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 17695e3dd157SKalle Valo "wmi peer create vdev_id %d peer_addr %pM\n", 17705e3dd157SKalle Valo vdev_id, peer_addr); 17715e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_CREATE_CMDID); 17725e3dd157SKalle Valo } 17735e3dd157SKalle Valo 17745e3dd157SKalle Valo int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, 17755e3dd157SKalle Valo const u8 peer_addr[ETH_ALEN]) 17765e3dd157SKalle Valo { 17775e3dd157SKalle Valo struct wmi_peer_delete_cmd *cmd; 17785e3dd157SKalle Valo struct sk_buff *skb; 17795e3dd157SKalle Valo 17805e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 17815e3dd157SKalle Valo if (!skb) 17825e3dd157SKalle Valo return -ENOMEM; 17835e3dd157SKalle Valo 17845e3dd157SKalle Valo cmd = (struct wmi_peer_delete_cmd *)skb->data; 17855e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 17865e3dd157SKalle Valo memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); 17875e3dd157SKalle Valo 17885e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 17895e3dd157SKalle Valo "wmi peer delete vdev_id %d peer_addr %pM\n", 17905e3dd157SKalle Valo vdev_id, peer_addr); 17915e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_DELETE_CMDID); 17925e3dd157SKalle Valo } 17935e3dd157SKalle Valo 17945e3dd157SKalle Valo int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, 17955e3dd157SKalle Valo const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) 17965e3dd157SKalle Valo { 17975e3dd157SKalle Valo struct wmi_peer_flush_tids_cmd *cmd; 17985e3dd157SKalle Valo struct sk_buff *skb; 17995e3dd157SKalle Valo 18005e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 18015e3dd157SKalle Valo if (!skb) 18025e3dd157SKalle Valo return -ENOMEM; 18035e3dd157SKalle Valo 18045e3dd157SKalle Valo cmd = (struct wmi_peer_flush_tids_cmd *)skb->data; 18055e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 18065e3dd157SKalle Valo cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap); 18075e3dd157SKalle Valo memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN); 18085e3dd157SKalle Valo 18095e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 18105e3dd157SKalle Valo "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n", 18115e3dd157SKalle Valo vdev_id, peer_addr, tid_bitmap); 18125e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_FLUSH_TIDS_CMDID); 18135e3dd157SKalle Valo } 18145e3dd157SKalle Valo 18155e3dd157SKalle Valo int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, 18165e3dd157SKalle Valo const u8 *peer_addr, enum wmi_peer_param param_id, 18175e3dd157SKalle Valo u32 param_value) 18185e3dd157SKalle Valo { 18195e3dd157SKalle Valo struct wmi_peer_set_param_cmd *cmd; 18205e3dd157SKalle Valo struct sk_buff *skb; 18215e3dd157SKalle Valo 18225e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 18235e3dd157SKalle Valo if (!skb) 18245e3dd157SKalle Valo return -ENOMEM; 18255e3dd157SKalle Valo 18265e3dd157SKalle Valo cmd = (struct wmi_peer_set_param_cmd *)skb->data; 18275e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 18285e3dd157SKalle Valo cmd->param_id = __cpu_to_le32(param_id); 18295e3dd157SKalle Valo cmd->param_value = __cpu_to_le32(param_value); 18305e3dd157SKalle Valo memcpy(&cmd->peer_macaddr.addr, peer_addr, 6); 18315e3dd157SKalle Valo 18325e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 18335e3dd157SKalle Valo "wmi vdev %d peer 0x%pM set param %d value %d\n", 18345e3dd157SKalle Valo vdev_id, peer_addr, param_id, param_value); 18355e3dd157SKalle Valo 18365e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_SET_PARAM_CMDID); 18375e3dd157SKalle Valo } 18385e3dd157SKalle Valo 18395e3dd157SKalle Valo int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, 18405e3dd157SKalle Valo enum wmi_sta_ps_mode psmode) 18415e3dd157SKalle Valo { 18425e3dd157SKalle Valo struct wmi_sta_powersave_mode_cmd *cmd; 18435e3dd157SKalle Valo struct sk_buff *skb; 18445e3dd157SKalle Valo 18455e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 18465e3dd157SKalle Valo if (!skb) 18475e3dd157SKalle Valo return -ENOMEM; 18485e3dd157SKalle Valo 18495e3dd157SKalle Valo cmd = (struct wmi_sta_powersave_mode_cmd *)skb->data; 18505e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 18515e3dd157SKalle Valo cmd->sta_ps_mode = __cpu_to_le32(psmode); 18525e3dd157SKalle Valo 18535e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 18545e3dd157SKalle Valo "wmi set powersave id 0x%x mode %d\n", 18555e3dd157SKalle Valo vdev_id, psmode); 18565e3dd157SKalle Valo 18575e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_STA_POWERSAVE_MODE_CMDID); 18585e3dd157SKalle Valo } 18595e3dd157SKalle Valo 18605e3dd157SKalle Valo int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, 18615e3dd157SKalle Valo enum wmi_sta_powersave_param param_id, 18625e3dd157SKalle Valo u32 value) 18635e3dd157SKalle Valo { 18645e3dd157SKalle Valo struct wmi_sta_powersave_param_cmd *cmd; 18655e3dd157SKalle Valo struct sk_buff *skb; 18665e3dd157SKalle Valo 18675e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 18685e3dd157SKalle Valo if (!skb) 18695e3dd157SKalle Valo return -ENOMEM; 18705e3dd157SKalle Valo 18715e3dd157SKalle Valo cmd = (struct wmi_sta_powersave_param_cmd *)skb->data; 18725e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 18735e3dd157SKalle Valo cmd->param_id = __cpu_to_le32(param_id); 18745e3dd157SKalle Valo cmd->param_value = __cpu_to_le32(value); 18755e3dd157SKalle Valo 18765e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 18775e3dd157SKalle Valo "wmi sta ps param vdev_id 0x%x param %d value %d\n", 18785e3dd157SKalle Valo vdev_id, param_id, value); 18795e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_STA_POWERSAVE_PARAM_CMDID); 18805e3dd157SKalle Valo } 18815e3dd157SKalle Valo 18825e3dd157SKalle Valo int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, 18835e3dd157SKalle Valo enum wmi_ap_ps_peer_param param_id, u32 value) 18845e3dd157SKalle Valo { 18855e3dd157SKalle Valo struct wmi_ap_ps_peer_cmd *cmd; 18865e3dd157SKalle Valo struct sk_buff *skb; 18875e3dd157SKalle Valo 18885e3dd157SKalle Valo if (!mac) 18895e3dd157SKalle Valo return -EINVAL; 18905e3dd157SKalle Valo 18915e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 18925e3dd157SKalle Valo if (!skb) 18935e3dd157SKalle Valo return -ENOMEM; 18945e3dd157SKalle Valo 18955e3dd157SKalle Valo cmd = (struct wmi_ap_ps_peer_cmd *)skb->data; 18965e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(vdev_id); 18975e3dd157SKalle Valo cmd->param_id = __cpu_to_le32(param_id); 18985e3dd157SKalle Valo cmd->param_value = __cpu_to_le32(value); 18995e3dd157SKalle Valo memcpy(&cmd->peer_macaddr, mac, ETH_ALEN); 19005e3dd157SKalle Valo 19015e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, 19025e3dd157SKalle Valo "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n", 19035e3dd157SKalle Valo vdev_id, param_id, value, mac); 19045e3dd157SKalle Valo 19055e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_AP_PS_PEER_PARAM_CMDID); 19065e3dd157SKalle Valo } 19075e3dd157SKalle Valo 19085e3dd157SKalle Valo int ath10k_wmi_scan_chan_list(struct ath10k *ar, 19095e3dd157SKalle Valo const struct wmi_scan_chan_list_arg *arg) 19105e3dd157SKalle Valo { 19115e3dd157SKalle Valo struct wmi_scan_chan_list_cmd *cmd; 19125e3dd157SKalle Valo struct sk_buff *skb; 19135e3dd157SKalle Valo struct wmi_channel_arg *ch; 19145e3dd157SKalle Valo struct wmi_channel *ci; 19155e3dd157SKalle Valo int len; 19165e3dd157SKalle Valo int i; 19175e3dd157SKalle Valo 19185e3dd157SKalle Valo len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel); 19195e3dd157SKalle Valo 19205e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(len); 19215e3dd157SKalle Valo if (!skb) 19225e3dd157SKalle Valo return -EINVAL; 19235e3dd157SKalle Valo 19245e3dd157SKalle Valo cmd = (struct wmi_scan_chan_list_cmd *)skb->data; 19255e3dd157SKalle Valo cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); 19265e3dd157SKalle Valo 19275e3dd157SKalle Valo for (i = 0; i < arg->n_channels; i++) { 19285e3dd157SKalle Valo u32 flags = 0; 19295e3dd157SKalle Valo 19305e3dd157SKalle Valo ch = &arg->channels[i]; 19315e3dd157SKalle Valo ci = &cmd->chan_info[i]; 19325e3dd157SKalle Valo 19335e3dd157SKalle Valo if (ch->passive) 19345e3dd157SKalle Valo flags |= WMI_CHAN_FLAG_PASSIVE; 19355e3dd157SKalle Valo if (ch->allow_ibss) 19365e3dd157SKalle Valo flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED; 19375e3dd157SKalle Valo if (ch->allow_ht) 19385e3dd157SKalle Valo flags |= WMI_CHAN_FLAG_ALLOW_HT; 19395e3dd157SKalle Valo if (ch->allow_vht) 19405e3dd157SKalle Valo flags |= WMI_CHAN_FLAG_ALLOW_VHT; 19415e3dd157SKalle Valo if (ch->ht40plus) 19425e3dd157SKalle Valo flags |= WMI_CHAN_FLAG_HT40_PLUS; 19435e3dd157SKalle Valo 19445e3dd157SKalle Valo ci->mhz = __cpu_to_le32(ch->freq); 19455e3dd157SKalle Valo ci->band_center_freq1 = __cpu_to_le32(ch->freq); 19465e3dd157SKalle Valo ci->band_center_freq2 = 0; 19475e3dd157SKalle Valo ci->min_power = ch->min_power; 19485e3dd157SKalle Valo ci->max_power = ch->max_power; 19495e3dd157SKalle Valo ci->reg_power = ch->max_reg_power; 19505e3dd157SKalle Valo ci->antenna_max = ch->max_antenna_gain; 19515e3dd157SKalle Valo ci->antenna_max = 0; 19525e3dd157SKalle Valo 19535e3dd157SKalle Valo /* mode & flags share storage */ 19545e3dd157SKalle Valo ci->mode = ch->mode; 19555e3dd157SKalle Valo ci->flags |= __cpu_to_le32(flags); 19565e3dd157SKalle Valo } 19575e3dd157SKalle Valo 19585e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_SCAN_CHAN_LIST_CMDID); 19595e3dd157SKalle Valo } 19605e3dd157SKalle Valo 19615e3dd157SKalle Valo int ath10k_wmi_peer_assoc(struct ath10k *ar, 19625e3dd157SKalle Valo const struct wmi_peer_assoc_complete_arg *arg) 19635e3dd157SKalle Valo { 19645e3dd157SKalle Valo struct wmi_peer_assoc_complete_cmd *cmd; 19655e3dd157SKalle Valo struct sk_buff *skb; 19665e3dd157SKalle Valo 19675e3dd157SKalle Valo if (arg->peer_mpdu_density > 16) 19685e3dd157SKalle Valo return -EINVAL; 19695e3dd157SKalle Valo if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) 19705e3dd157SKalle Valo return -EINVAL; 19715e3dd157SKalle Valo if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) 19725e3dd157SKalle Valo return -EINVAL; 19735e3dd157SKalle Valo 19745e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 19755e3dd157SKalle Valo if (!skb) 19765e3dd157SKalle Valo return -ENOMEM; 19775e3dd157SKalle Valo 19785e3dd157SKalle Valo cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data; 19795e3dd157SKalle Valo cmd->vdev_id = __cpu_to_le32(arg->vdev_id); 19805e3dd157SKalle Valo cmd->peer_new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1); 19815e3dd157SKalle Valo cmd->peer_associd = __cpu_to_le32(arg->peer_aid); 19825e3dd157SKalle Valo cmd->peer_flags = __cpu_to_le32(arg->peer_flags); 19835e3dd157SKalle Valo cmd->peer_caps = __cpu_to_le32(arg->peer_caps); 19845e3dd157SKalle Valo cmd->peer_listen_intval = __cpu_to_le32(arg->peer_listen_intval); 19855e3dd157SKalle Valo cmd->peer_ht_caps = __cpu_to_le32(arg->peer_ht_caps); 19865e3dd157SKalle Valo cmd->peer_max_mpdu = __cpu_to_le32(arg->peer_max_mpdu); 19875e3dd157SKalle Valo cmd->peer_mpdu_density = __cpu_to_le32(arg->peer_mpdu_density); 19885e3dd157SKalle Valo cmd->peer_rate_caps = __cpu_to_le32(arg->peer_rate_caps); 19895e3dd157SKalle Valo cmd->peer_nss = __cpu_to_le32(arg->peer_num_spatial_streams); 19905e3dd157SKalle Valo cmd->peer_vht_caps = __cpu_to_le32(arg->peer_vht_caps); 19915e3dd157SKalle Valo cmd->peer_phymode = __cpu_to_le32(arg->peer_phymode); 19925e3dd157SKalle Valo 19935e3dd157SKalle Valo memcpy(cmd->peer_macaddr.addr, arg->addr, ETH_ALEN); 19945e3dd157SKalle Valo 19955e3dd157SKalle Valo cmd->peer_legacy_rates.num_rates = 19965e3dd157SKalle Valo __cpu_to_le32(arg->peer_legacy_rates.num_rates); 19975e3dd157SKalle Valo memcpy(cmd->peer_legacy_rates.rates, arg->peer_legacy_rates.rates, 19985e3dd157SKalle Valo arg->peer_legacy_rates.num_rates); 19995e3dd157SKalle Valo 20005e3dd157SKalle Valo cmd->peer_ht_rates.num_rates = 20015e3dd157SKalle Valo __cpu_to_le32(arg->peer_ht_rates.num_rates); 20025e3dd157SKalle Valo memcpy(cmd->peer_ht_rates.rates, arg->peer_ht_rates.rates, 20035e3dd157SKalle Valo arg->peer_ht_rates.num_rates); 20045e3dd157SKalle Valo 20055e3dd157SKalle Valo cmd->peer_vht_rates.rx_max_rate = 20065e3dd157SKalle Valo __cpu_to_le32(arg->peer_vht_rates.rx_max_rate); 20075e3dd157SKalle Valo cmd->peer_vht_rates.rx_mcs_set = 20085e3dd157SKalle Valo __cpu_to_le32(arg->peer_vht_rates.rx_mcs_set); 20095e3dd157SKalle Valo cmd->peer_vht_rates.tx_max_rate = 20105e3dd157SKalle Valo __cpu_to_le32(arg->peer_vht_rates.tx_max_rate); 20115e3dd157SKalle Valo cmd->peer_vht_rates.tx_mcs_set = 20125e3dd157SKalle Valo __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); 20135e3dd157SKalle Valo 20145e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID); 20155e3dd157SKalle Valo } 20165e3dd157SKalle Valo 20175e3dd157SKalle Valo int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg) 20185e3dd157SKalle Valo { 20195e3dd157SKalle Valo struct wmi_bcn_tx_cmd *cmd; 20205e3dd157SKalle Valo struct sk_buff *skb; 20215e3dd157SKalle Valo 20225e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); 20235e3dd157SKalle Valo if (!skb) 20245e3dd157SKalle Valo return -ENOMEM; 20255e3dd157SKalle Valo 20265e3dd157SKalle Valo cmd = (struct wmi_bcn_tx_cmd *)skb->data; 20275e3dd157SKalle Valo cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); 20285e3dd157SKalle Valo cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate); 20295e3dd157SKalle Valo cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); 20305e3dd157SKalle Valo cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); 20315e3dd157SKalle Valo memcpy(cmd->bcn, arg->bcn, arg->bcn_len); 20325e3dd157SKalle Valo 20335e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_BCN_TX_CMDID); 20345e3dd157SKalle Valo } 20355e3dd157SKalle Valo 20365e3dd157SKalle Valo static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, 20375e3dd157SKalle Valo const struct wmi_wmm_params_arg *arg) 20385e3dd157SKalle Valo { 20395e3dd157SKalle Valo params->cwmin = __cpu_to_le32(arg->cwmin); 20405e3dd157SKalle Valo params->cwmax = __cpu_to_le32(arg->cwmax); 20415e3dd157SKalle Valo params->aifs = __cpu_to_le32(arg->aifs); 20425e3dd157SKalle Valo params->txop = __cpu_to_le32(arg->txop); 20435e3dd157SKalle Valo params->acm = __cpu_to_le32(arg->acm); 20445e3dd157SKalle Valo params->no_ack = __cpu_to_le32(arg->no_ack); 20455e3dd157SKalle Valo } 20465e3dd157SKalle Valo 20475e3dd157SKalle Valo int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, 20485e3dd157SKalle Valo const struct wmi_pdev_set_wmm_params_arg *arg) 20495e3dd157SKalle Valo { 20505e3dd157SKalle Valo struct wmi_pdev_set_wmm_params *cmd; 20515e3dd157SKalle Valo struct sk_buff *skb; 20525e3dd157SKalle Valo 20535e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 20545e3dd157SKalle Valo if (!skb) 20555e3dd157SKalle Valo return -ENOMEM; 20565e3dd157SKalle Valo 20575e3dd157SKalle Valo cmd = (struct wmi_pdev_set_wmm_params *)skb->data; 20585e3dd157SKalle Valo ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be); 20595e3dd157SKalle Valo ath10k_wmi_pdev_set_wmm_param(&cmd->ac_bk, &arg->ac_bk); 20605e3dd157SKalle Valo ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); 20615e3dd157SKalle Valo ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); 20625e3dd157SKalle Valo 20635e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); 20645e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_WMM_PARAMS_CMDID); 20655e3dd157SKalle Valo } 20665e3dd157SKalle Valo 20675e3dd157SKalle Valo int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) 20685e3dd157SKalle Valo { 20695e3dd157SKalle Valo struct wmi_request_stats_cmd *cmd; 20705e3dd157SKalle Valo struct sk_buff *skb; 20715e3dd157SKalle Valo 20725e3dd157SKalle Valo skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); 20735e3dd157SKalle Valo if (!skb) 20745e3dd157SKalle Valo return -ENOMEM; 20755e3dd157SKalle Valo 20765e3dd157SKalle Valo cmd = (struct wmi_request_stats_cmd *)skb->data; 20775e3dd157SKalle Valo cmd->stats_id = __cpu_to_le32(stats_id); 20785e3dd157SKalle Valo 20795e3dd157SKalle Valo ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); 20805e3dd157SKalle Valo return ath10k_wmi_cmd_send(ar, skb, WMI_REQUEST_STATS_CMDID); 20815e3dd157SKalle Valo } 2082