Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / wmi.c
index d246288..54df425 100644 (file)
@@ -29,6 +29,9 @@
 #include "p2p.h"
 #include "hw.h"
 
+#define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9
+#define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ)
+
 /* MAIN WMI cmd track */
 static struct wmi_cmd_map wmi_cmd_map = {
        .init_cmdid = WMI_INIT_CMDID,
@@ -1874,7 +1877,7 @@ ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
        ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr));
        memcpy(cmd->buf, msdu->data, msdu->len);
 
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %pK len %d ftype %02x stype %02x\n",
                   msdu, skb->len, fc & IEEE80211_FCTL_FTYPE,
                   fc & IEEE80211_FCTL_STYPE);
        trace_ath10k_tx_hdr(ar, skb->data, skb->len);
@@ -2240,6 +2243,29 @@ static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar,
        return 0;
 }
 
+static bool ath10k_wmi_rx_is_decrypted(struct ath10k *ar,
+                                      struct ieee80211_hdr *hdr)
+{
+       if (!ieee80211_has_protected(hdr->frame_control))
+               return false;
+
+       /* FW delivers WEP Shared Auth frame with Protected Bit set and
+        * encrypted payload. However in case of PMF it delivers decrypted
+        * frames with Protected Bit set.
+        */
+       if (ieee80211_is_auth(hdr->frame_control))
+               return false;
+
+       /* qca99x0 based FW delivers broadcast or multicast management frames
+        * (ex: group privacy action frames in mesh) as encrypted payload.
+        */
+       if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) &&
+           ar->hw_params.sw_decrypt_mcast_mgmt)
+               return false;
+
+       return true;
+}
+
 int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 {
        struct wmi_mgmt_rx_ev_arg arg = {};
@@ -2326,11 +2352,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 
        ath10k_wmi_handle_wep_reauth(ar, skb, status);
 
-       /* FW delivers WEP Shared Auth frame with Protected Bit set and
-        * encrypted payload. However in case of PMF it delivers decrypted
-        * frames with Protected Bit set. */
-       if (ieee80211_has_protected(hdr->frame_control) &&
-           !ieee80211_is_auth(hdr->frame_control)) {
+       if (ath10k_wmi_rx_is_decrypted(ar, hdr)) {
                status->flag |= RX_FLAG_DECRYPTED;
 
                if (!ieee80211_is_action(hdr->frame_control) &&
@@ -2347,7 +2369,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_mac_handle_beacon(ar, skb);
 
        ath10k_dbg(ar, ATH10K_DBG_MGMT,
-                  "event mgmt rx skb %p len %d ftype %02x stype %02x\n",
+                  "event mgmt rx skb %pK len %d ftype %02x stype %02x\n",
                   skb, skb->len,
                   fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
 
@@ -2495,7 +2517,21 @@ exit:
 
 void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
 {
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
+       struct wmi_echo_ev_arg arg = {};
+       int ret;
+
+       ret = ath10k_wmi_pull_echo_ev(ar, skb, &arg);
+       if (ret) {
+               ath10k_warn(ar, "failed to parse echo: %d\n", ret);
+               return;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
+                  "wmi event echo value 0x%08x\n",
+                  le32_to_cpu(arg.value));
+
+       if (le32_to_cpu(arg.value) == ATH10K_WMI_BARRIER_ECHO_ID)
+               complete(&ar->wmi.barrier);
 }
 
 int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
@@ -3478,6 +3514,12 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                        continue;
                }
 
+               /* mac80211 would have already asked us to stop beaconing and
+                * bring the vdev down, so continue in that case
+                */
+               if (!arvif->is_up)
+                       continue;
+
                /* There are no completions for beacons so wait for next SWBA
                 * before telling mac80211 to decrement CSA counter
                 *
@@ -3527,7 +3569,6 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                                ath10k_warn(ar, "failed to map beacon: %d\n",
                                            ret);
                                dev_kfree_skb_any(bcn);
-                               ret = -EIO;
                                goto skip;
                        }
 
@@ -4792,6 +4833,17 @@ static int ath10k_wmi_op_pull_roam_ev(struct ath10k *ar, struct sk_buff *skb,
        return 0;
 }
 
+static int ath10k_wmi_op_pull_echo_ev(struct ath10k *ar,
+                                     struct sk_buff *skb,
+                                     struct wmi_echo_ev_arg *arg)
+{
+       struct wmi_echo_event *ev = (void *)skb->data;
+
+       arg->value = ev->value;
+
+       return 0;
+}
+
 int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
 {
        struct wmi_rdy_ev_arg arg = {};
@@ -5124,6 +5176,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
        struct wmi_cmd_hdr *cmd_hdr;
        enum wmi_10_2_event_id id;
+       bool consumed;
 
        cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
        id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
@@ -5133,6 +5186,18 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 
        trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
 
+       consumed = ath10k_tm_event_wmi(ar, id, skb);
+
+       /* Ready event must be handled normally also in UTF mode so that we
+        * know the UTF firmware has booted, others we are just bypass WMI
+        * events to testmode.
+        */
+       if (consumed && id != WMI_10_2_READY_EVENTID) {
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
+                          "wmi testmode consumed 0x%x\n", id);
+               goto out;
+       }
+
        switch (id) {
        case WMI_10_2_MGMT_RX_EVENTID:
                ath10k_wmi_event_mgmt_rx(ar, skb);
@@ -5248,6 +5313,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
        struct wmi_cmd_hdr *cmd_hdr;
        enum wmi_10_4_event_id id;
+       bool consumed;
 
        cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
        id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
@@ -5257,6 +5323,18 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 
        trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
 
+       consumed = ath10k_tm_event_wmi(ar, id, skb);
+
+       /* Ready event must be handled normally also in UTF mode so that we
+        * know the UTF firmware has booted, others we are just bypass WMI
+        * events to testmode.
+        */
+       if (consumed && id != WMI_10_4_READY_EVENTID) {
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
+                          "wmi testmode consumed 0x%x\n", id);
+               goto out;
+       }
+
        switch (id) {
        case WMI_10_4_MGMT_RX_EVENTID:
                ath10k_wmi_event_mgmt_rx(ar, skb);
@@ -5306,6 +5384,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
                break;
        case WMI_10_4_WOW_WAKEUP_HOST_EVENTID:
        case WMI_10_4_PEER_RATECODE_LIST_EVENTID:
+       case WMI_10_4_WDS_PEER_EVENTID:
                ath10k_dbg(ar, ATH10K_DBG_WMI,
                           "received event id %d not implemented\n", id);
                break;
@@ -6863,7 +6942,7 @@ ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar,
 }
 
 static struct sk_buff *
-ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable,
+ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u64 module_enable,
                             u32 log_level)
 {
        struct wmi_dbglog_cfg_cmd *cmd;
@@ -6900,6 +6979,44 @@ ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable,
        return skb;
 }
 
+static struct sk_buff *
+ath10k_wmi_10_4_op_gen_dbglog_cfg(struct ath10k *ar, u64 module_enable,
+                                 u32 log_level)
+{
+       struct wmi_10_4_dbglog_cfg_cmd *cmd;
+       struct sk_buff *skb;
+       u32 cfg;
+
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+       if (!skb)
+               return ERR_PTR(-ENOMEM);
+
+       cmd = (struct wmi_10_4_dbglog_cfg_cmd *)skb->data;
+
+       if (module_enable) {
+               cfg = SM(log_level,
+                        ATH10K_DBGLOG_CFG_LOG_LVL);
+       } else {
+               /* set back defaults, all modules with WARN level */
+               cfg = SM(ATH10K_DBGLOG_LEVEL_WARN,
+                        ATH10K_DBGLOG_CFG_LOG_LVL);
+               module_enable = ~0;
+       }
+
+       cmd->module_enable = __cpu_to_le64(module_enable);
+       cmd->module_valid = __cpu_to_le64(~0);
+       cmd->config_enable = __cpu_to_le32(cfg);
+       cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
+
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
+                  "wmi dbglog cfg modules 0x%016llx 0x%016llx config %08x %08x\n",
+                  __le64_to_cpu(cmd->module_enable),
+                  __le64_to_cpu(cmd->module_valid),
+                  __le32_to_cpu(cmd->config_enable),
+                  __le32_to_cpu(cmd->config_valid));
+       return skb;
+}
+
 static struct sk_buff *
 ath10k_wmi_op_gen_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
 {
@@ -7649,6 +7766,48 @@ ath10k_wmi_10_4_ext_resource_config(struct ath10k *ar,
        return skb;
 }
 
+static struct sk_buff *
+ath10k_wmi_op_gen_echo(struct ath10k *ar, u32 value)
+{
+       struct wmi_echo_cmd *cmd;
+       struct sk_buff *skb;
+
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+       if (!skb)
+               return ERR_PTR(-ENOMEM);
+
+       cmd = (struct wmi_echo_cmd *)skb->data;
+       cmd->value = cpu_to_le32(value);
+
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
+                  "wmi echo value 0x%08x\n", value);
+       return skb;
+}
+
+int
+ath10k_wmi_barrier(struct ath10k *ar)
+{
+       int ret;
+       int time_left;
+
+       spin_lock_bh(&ar->data_lock);
+       reinit_completion(&ar->wmi.barrier);
+       spin_unlock_bh(&ar->data_lock);
+
+       ret = ath10k_wmi_echo(ar, ATH10K_WMI_BARRIER_ECHO_ID);
+       if (ret) {
+               ath10k_warn(ar, "failed to submit wmi echo: %d\n", ret);
+               return ret;
+       }
+
+       time_left = wait_for_completion_timeout(&ar->wmi.barrier,
+                                               ATH10K_WMI_BARRIER_TIMEOUT_HZ);
+       if (!time_left)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 static const struct wmi_ops wmi_ops = {
        .rx = ath10k_wmi_op_rx,
        .map_svc = wmi_main_svc_map,
@@ -7665,6 +7824,7 @@ static const struct wmi_ops wmi_ops = {
        .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
        .pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats,
        .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
+       .pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
 
        .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
        .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -7709,6 +7869,7 @@ static const struct wmi_ops wmi_ops = {
        .gen_delba_send = ath10k_wmi_op_gen_delba_send,
        .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
        .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
+       .gen_echo = ath10k_wmi_op_gen_echo,
        /* .gen_bcn_tmpl not implemented */
        /* .gen_prb_tmpl not implemented */
        /* .gen_p2p_go_bcn_ie not implemented */
@@ -7738,6 +7899,7 @@ static const struct wmi_ops wmi_10_1_ops = {
        .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
        .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
        .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
+       .pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
 
        .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
        .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -7777,6 +7939,7 @@ static const struct wmi_ops wmi_10_1_ops = {
        .gen_delba_send = ath10k_wmi_op_gen_delba_send,
        .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
        .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
+       .gen_echo = ath10k_wmi_op_gen_echo,
        /* .gen_bcn_tmpl not implemented */
        /* .gen_prb_tmpl not implemented */
        /* .gen_p2p_go_bcn_ie not implemented */
@@ -7796,6 +7959,7 @@ static const struct wmi_ops wmi_10_2_ops = {
        .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
        .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
        .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
+       .gen_echo = ath10k_wmi_op_gen_echo,
 
        .pull_scan = ath10k_wmi_op_pull_scan_ev,
        .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
@@ -7807,6 +7971,7 @@ static const struct wmi_ops wmi_10_2_ops = {
        .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
        .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
        .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
+       .pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
 
        .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
        .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -7862,6 +8027,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
        .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
        .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
        .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
+       .gen_echo = ath10k_wmi_op_gen_echo,
 
        .pull_scan = ath10k_wmi_op_pull_scan_ev,
        .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
@@ -7873,6 +8039,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
        .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
        .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
        .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
+       .pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
 
        .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
        .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -7968,7 +8135,7 @@ static const struct wmi_ops wmi_10_4_ops = {
        .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
        .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
        .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
-       .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+       .gen_dbglog_cfg = ath10k_wmi_10_4_op_gen_dbglog_cfg,
        .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
        .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
        .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
@@ -7980,10 +8147,12 @@ static const struct wmi_ops wmi_10_4_ops = {
        .ext_resource_config = ath10k_wmi_10_4_ext_resource_config,
 
        /* shared with 10.2 */
+       .pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
        .gen_request_stats = ath10k_wmi_op_gen_request_stats,
        .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
        .get_vdev_subtype = ath10k_wmi_10_4_op_get_vdev_subtype,
        .gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
+       .gen_echo = ath10k_wmi_op_gen_echo,
 };
 
 int ath10k_wmi_attach(struct ath10k *ar)
@@ -8036,6 +8205,7 @@ int ath10k_wmi_attach(struct ath10k *ar)
 
        init_completion(&ar->wmi.service_ready);
        init_completion(&ar->wmi.unified_ready);
+       init_completion(&ar->wmi.barrier);
 
        INIT_WORK(&ar->svc_rdy_work, ath10k_wmi_event_service_ready_work);