ath10k: deduplicate wmi service ready logic
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / wmi.c
index 4f66a58..a7c11b2 100644 (file)
@@ -609,6 +609,40 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
        .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
 };
 
+static void
+ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+                          const struct wmi_channel_arg *arg)
+{
+       u32 flags = 0;
+
+       memset(ch, 0, sizeof(*ch));
+
+       if (arg->passive)
+               flags |= WMI_CHAN_FLAG_PASSIVE;
+       if (arg->allow_ibss)
+               flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
+       if (arg->allow_ht)
+               flags |= WMI_CHAN_FLAG_ALLOW_HT;
+       if (arg->allow_vht)
+               flags |= WMI_CHAN_FLAG_ALLOW_VHT;
+       if (arg->ht40plus)
+               flags |= WMI_CHAN_FLAG_HT40_PLUS;
+       if (arg->chan_radar)
+               flags |= WMI_CHAN_FLAG_DFS;
+
+       ch->mhz = __cpu_to_le32(arg->freq);
+       ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
+       ch->band_center_freq2 = 0;
+       ch->min_power = arg->min_power;
+       ch->max_power = arg->max_power;
+       ch->reg_power = arg->max_reg_power;
+       ch->antenna_max = arg->max_antenna_gain;
+
+       /* mode & flags share storage */
+       ch->mode = arg->mode;
+       ch->flags |= __cpu_to_le32(flags);
+}
+
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
 {
        int ret;
@@ -2171,30 +2205,113 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
        return 0;
 }
 
+static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
+                                          struct wmi_svc_rdy_ev_arg *arg)
+{
+       struct wmi_service_ready_event *ev;
+       size_t i, n;
+
+       if (skb->len < sizeof(*ev))
+               return -EPROTO;
+
+       ev = (void *)skb->data;
+       skb_pull(skb, sizeof(*ev));
+       arg->min_tx_power = ev->hw_min_tx_power;
+       arg->max_tx_power = ev->hw_max_tx_power;
+       arg->ht_cap = ev->ht_cap_info;
+       arg->vht_cap = ev->vht_cap_info;
+       arg->sw_ver0 = ev->sw_version;
+       arg->sw_ver1 = ev->sw_version_1;
+       arg->phy_capab = ev->phy_capability;
+       arg->num_rf_chains = ev->num_rf_chains;
+       arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+       arg->num_mem_reqs = ev->num_mem_reqs;
+       arg->service_map = ev->wmi_service_bitmap;
+
+       n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
+                 ARRAY_SIZE(arg->mem_reqs));
+       for (i = 0; i < n; i++)
+               arg->mem_reqs[i] = &ev->mem_reqs[i];
+
+       if (skb->len <
+           __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
+               return -EPROTO;
+
+       return 0;
+}
+
+static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
+                                         struct wmi_svc_rdy_ev_arg *arg)
+{
+       struct wmi_10x_service_ready_event *ev;
+       int i, n;
+
+       if (skb->len < sizeof(*ev))
+               return -EPROTO;
+
+       ev = (void *)skb->data;
+       skb_pull(skb, sizeof(*ev));
+       arg->min_tx_power = ev->hw_min_tx_power;
+       arg->max_tx_power = ev->hw_max_tx_power;
+       arg->ht_cap = ev->ht_cap_info;
+       arg->vht_cap = ev->vht_cap_info;
+       arg->sw_ver0 = ev->sw_version;
+       arg->phy_capab = ev->phy_capability;
+       arg->num_rf_chains = ev->num_rf_chains;
+       arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+       arg->num_mem_reqs = ev->num_mem_reqs;
+       arg->service_map = ev->wmi_service_bitmap;
+
+       n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
+                 ARRAY_SIZE(arg->mem_reqs));
+       for (i = 0; i < n; i++)
+               arg->mem_reqs[i] = &ev->mem_reqs[i];
+
+       if (skb->len <
+           __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
+               return -EPROTO;
+
+       return 0;
+}
+
 static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
                                              struct sk_buff *skb)
 {
-       struct wmi_service_ready_event *ev = (void *)skb->data;
+       struct wmi_svc_rdy_ev_arg arg = {};
+       u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
        DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
+       int ret;
 
-       if (skb->len < sizeof(*ev)) {
-               ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
-                           skb->len, sizeof(*ev));
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
+               wmi_10x_svc_map(arg.service_map, svc_bmap);
+       } else {
+               ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
+               wmi_main_svc_map(arg.service_map, svc_bmap);
+       }
+
+       if (ret) {
+               ath10k_warn(ar, "failed to parse service ready: %d\n", ret);
                return;
        }
 
-       ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
-       ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
-       ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
-       ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
+       ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power);
+       ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power);
+       ar->ht_cap_info = __le32_to_cpu(arg.ht_cap);
+       ar->vht_cap_info = __le32_to_cpu(arg.vht_cap);
        ar->fw_version_major =
-               (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
-       ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
+               (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24;
+       ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff);
        ar->fw_version_release =
-               (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16;
-       ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff);
-       ar->phy_capability = __le32_to_cpu(ev->phy_capability);
-       ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
+               (__le32_to_cpu(arg.sw_ver1) & 0xffff0000) >> 16;
+       ar->fw_version_build = (__le32_to_cpu(arg.sw_ver1) & 0x0000ffff);
+       ar->phy_capability = __le32_to_cpu(arg.phy_capab);
+       ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
+       ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd);
+
+       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+                       arg.service_map, sizeof(arg.service_map));
 
        /* only manually set fw features when not using FW IE format */
        if (ar->fw_api == 1 && ar->fw_version_build > 636)
@@ -2209,14 +2326,6 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
        ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1;
        ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1;
 
-       ar->ath_common.regulatory.current_rd =
-               __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
-
-       wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap);
-       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
-       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
-                       ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
-
        if (strlen(ar->hw->wiphy->fw_version) == 0) {
                snprintf(ar->hw->wiphy->fw_version,
                         sizeof(ar->hw->wiphy->fw_version),
@@ -2227,96 +2336,18 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
                         ar->fw_version_build);
        }
 
-       /* FIXME: it probably should be better to support this */
-       if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
-               ath10k_warn(ar, "target requested %d memory chunks; ignoring\n",
-                           __le32_to_cpu(ev->num_mem_reqs));
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI,
-                  "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 num_rf_chains %u\n",
-                  __le32_to_cpu(ev->sw_version),
-                  __le32_to_cpu(ev->sw_version_1),
-                  __le32_to_cpu(ev->abi_version),
-                  __le32_to_cpu(ev->phy_capability),
-                  __le32_to_cpu(ev->ht_cap_info),
-                  __le32_to_cpu(ev->vht_cap_info),
-                  __le32_to_cpu(ev->vht_supp_mcs),
-                  __le32_to_cpu(ev->sys_cap_info),
-                  __le32_to_cpu(ev->num_mem_reqs),
-                  __le32_to_cpu(ev->num_rf_chains));
-
-       complete(&ar->wmi.service_ready);
-}
-
-static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
-                                                 struct sk_buff *skb)
-{
-       u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
-       int ret;
-       struct wmi_service_ready_event_10x *ev = (void *)skb->data;
-       DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
-
-       if (skb->len < sizeof(*ev)) {
-               ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
-                           skb->len, sizeof(*ev));
-               return;
-       }
-
-       ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
-       ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
-       ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
-       ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
-       ar->fw_version_major =
-               (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
-       ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
-       ar->phy_capability = __le32_to_cpu(ev->phy_capability);
-       ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
-
-       if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
-               ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
-                           ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
-               ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
-       }
-
-       ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1;
-       ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1;
-
-       ar->ath_common.regulatory.current_rd =
-               __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
-
-       wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap);
-       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
-       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
-                       ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
-
-       if (strlen(ar->hw->wiphy->fw_version) == 0) {
-               snprintf(ar->hw->wiphy->fw_version,
-                        sizeof(ar->hw->wiphy->fw_version),
-                        "%u.%u",
-                        ar->fw_version_major,
-                        ar->fw_version_minor);
-       }
-
-       num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
-
-       if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
+       num_mem_reqs = __le32_to_cpu(arg.num_mem_reqs);
+       if (num_mem_reqs > WMI_MAX_MEM_REQS) {
                ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
                            num_mem_reqs);
                return;
        }
 
-       if (!num_mem_reqs)
-               goto exit;
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
-                  num_mem_reqs);
-
        for (i = 0; i < num_mem_reqs; ++i) {
-               req_id = __le32_to_cpu(ev->mem_reqs[i].req_id);
-               num_units = __le32_to_cpu(ev->mem_reqs[i].num_units);
-               unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size);
-               num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info);
+               req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id);
+               num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units);
+               unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size);
+               num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info);
 
                if (num_unit_info & NUM_UNITS_IS_NUM_PEERS)
                        /* number of units to allocate is number of
@@ -2330,7 +2361,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
                ath10k_dbg(ar, ATH10K_DBG_WMI,
                           "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
                           req_id,
-                          __le32_to_cpu(ev->mem_reqs[i].num_units),
+                          __le32_to_cpu(arg.mem_reqs[i]->num_units),
                           num_unit_info,
                           unit_size,
                           num_units);
@@ -2341,18 +2372,18 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
                        return;
        }
 
-exit:
        ath10k_dbg(ar, ATH10K_DBG_WMI,
-                  "wmi event service ready sw_ver 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 num_rf_chains %u\n",
-                  __le32_to_cpu(ev->sw_version),
-                  __le32_to_cpu(ev->abi_version),
-                  __le32_to_cpu(ev->phy_capability),
-                  __le32_to_cpu(ev->ht_cap_info),
-                  __le32_to_cpu(ev->vht_cap_info),
-                  __le32_to_cpu(ev->vht_supp_mcs),
-                  __le32_to_cpu(ev->sys_cap_info),
-                  __le32_to_cpu(ev->num_mem_reqs),
-                  __le32_to_cpu(ev->num_rf_chains));
+                  "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
+                  __le32_to_cpu(arg.min_tx_power),
+                  __le32_to_cpu(arg.max_tx_power),
+                  __le32_to_cpu(arg.ht_cap),
+                  __le32_to_cpu(arg.vht_cap),
+                  __le32_to_cpu(arg.sw_ver0),
+                  __le32_to_cpu(arg.sw_ver1),
+                  __le32_to_cpu(arg.phy_capab),
+                  __le32_to_cpu(arg.num_rf_chains),
+                  __le32_to_cpu(arg.eeprom_rd),
+                  __le32_to_cpu(arg.num_mem_reqs));
 
        complete(&ar->wmi.service_ready);
 }
@@ -2600,7 +2631,7 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_event_vdev_resume_req(ar, skb);
                break;
        case WMI_10X_SERVICE_READY_EVENTID:
-               ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+               ath10k_wmi_service_ready_event_rx(ar, skb);
                break;
        case WMI_10X_READY_EVENTID:
                ath10k_wmi_ready_event_rx(ar, skb);
@@ -2711,7 +2742,7 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_event_vdev_resume_req(ar, skb);
                break;
        case WMI_10_2_SERVICE_READY_EVENTID:
-               ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+               ath10k_wmi_service_ready_event_rx(ar, skb);
                break;
        case WMI_10_2_READY_EVENTID:
                ath10k_wmi_ready_event_rx(ar, skb);
@@ -2746,45 +2777,6 @@ static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
        }
 }
 
-/* WMI Initialization functions */
-int ath10k_wmi_attach(struct ath10k *ar)
-{
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
-                       ar->wmi.cmd = &wmi_10_2_cmd_map;
-               else
-                       ar->wmi.cmd = &wmi_10x_cmd_map;
-
-               ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
-               ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
-       } else {
-               ar->wmi.cmd = &wmi_cmd_map;
-               ar->wmi.vdev_param = &wmi_vdev_param_map;
-               ar->wmi.pdev_param = &wmi_pdev_param_map;
-       }
-
-       init_completion(&ar->wmi.service_ready);
-       init_completion(&ar->wmi.unified_ready);
-       init_waitqueue_head(&ar->wmi.tx_credits_wq);
-
-       return 0;
-}
-
-void ath10k_wmi_detach(struct ath10k *ar)
-{
-       int i;
-
-       /* free the host memory chunks requested by firmware */
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               dma_free_coherent(ar->dev,
-                                 ar->wmi.mem_chunks[i].len,
-                                 ar->wmi.mem_chunks[i].vaddr,
-                                 ar->wmi.mem_chunks[i].paddr);
-       }
-
-       ar->wmi.num_mem_chunks = 0;
-}
-
 int ath10k_wmi_connect(struct ath10k *ar)
 {
        int status;
@@ -2929,13 +2921,34 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
 }
 
+static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
+                                          struct wmi_host_mem_chunks *chunks)
+{
+       struct host_memory_chunk *chunk;
+       int i;
+
+       chunks->count = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+               chunk = &chunks->items[i];
+               chunk->ptr = __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
+               chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len);
+               chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
+
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
+                          "wmi chunk %d len %d requested, addr 0x%llx\n",
+                          i,
+                          ar->wmi.mem_chunks[i].len,
+                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
+       }
+}
+
 static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 {
        struct wmi_init_cmd *cmd;
        struct sk_buff *buf;
        struct wmi_resource_config config = {};
        u32 len, val;
-       int i;
 
        config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
        config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
@@ -2997,32 +3010,8 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 
        cmd = (struct wmi_init_cmd *)buf->data;
 
-       if (ar->wmi.num_mem_chunks == 0) {
-               cmd->num_host_mem_chunks = 0;
-               goto out;
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
-                  ar->wmi.num_mem_chunks);
-
-       cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               cmd->host_mem_chunks[i].ptr =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
-               cmd->host_mem_chunks[i].size =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].len);
-               cmd->host_mem_chunks[i].req_id =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
-               ath10k_dbg(ar, ATH10K_DBG_WMI,
-                          "wmi chunk %d len %d requested, addr 0x%llx\n",
-                          i,
-                          ar->wmi.mem_chunks[i].len,
-                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
-       }
-out:
        memcpy(&cmd->resource_config, &config, sizeof(config));
+       ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
@@ -3034,7 +3023,6 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
        struct sk_buff *buf;
        struct wmi_resource_config_10x config = {};
        u32 len, val;
-       int i;
 
        config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
        config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
@@ -3088,32 +3076,8 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
 
        cmd = (struct wmi_init_cmd_10x *)buf->data;
 
-       if (ar->wmi.num_mem_chunks == 0) {
-               cmd->num_host_mem_chunks = 0;
-               goto out;
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
-                  ar->wmi.num_mem_chunks);
-
-       cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               cmd->host_mem_chunks[i].ptr =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
-               cmd->host_mem_chunks[i].size =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].len);
-               cmd->host_mem_chunks[i].req_id =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
-               ath10k_dbg(ar, ATH10K_DBG_WMI,
-                          "wmi chunk %d len %d requested, addr 0x%llx\n",
-                          i,
-                          ar->wmi.mem_chunks[i].len,
-                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
-       }
-out:
        memcpy(&cmd->resource_config, &config, sizeof(config));
+       ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
@@ -3125,7 +3089,6 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
        struct sk_buff *buf;
        struct wmi_resource_config_10x config = {};
        u32 len, val;
-       int i;
 
        config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
        config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
@@ -3179,32 +3142,8 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
 
        cmd = (struct wmi_init_cmd_10_2 *)buf->data;
 
-       if (ar->wmi.num_mem_chunks == 0) {
-               cmd->num_host_mem_chunks = 0;
-               goto out;
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
-                  ar->wmi.num_mem_chunks);
-
-       cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               cmd->host_mem_chunks[i].ptr =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
-               cmd->host_mem_chunks[i].size =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].len);
-               cmd->host_mem_chunks[i].req_id =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
-               ath10k_dbg(ar, ATH10K_DBG_WMI,
-                          "wmi chunk %d len %d requested, addr 0x%llx\n",
-                          i,
-                          ar->wmi.mem_chunks[i].len,
-                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
-       }
-out:
        memcpy(&cmd->resource_config.common, &config, sizeof(config));
+       ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
@@ -3510,7 +3449,6 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
        struct sk_buff *skb;
        const char *cmdname;
        u32 flags = 0;
-       u32 ch_flags = 0;
 
        if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid &&
            cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)
@@ -3537,8 +3475,6 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
                flags |= WMI_VDEV_START_HIDDEN_SSID;
        if (arg->pmf_enabled)
                flags |= WMI_VDEV_START_PMF_ENABLED;
-       if (arg->channel.chan_radar)
-               ch_flags |= WMI_CHAN_FLAG_DFS;
 
        cmd = (struct wmi_vdev_start_request_cmd *)skb->data;
        cmd->vdev_id         = __cpu_to_le32(arg->vdev_id);
@@ -3554,18 +3490,7 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
                memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
        }
 
-       cmd->chan.mhz = __cpu_to_le32(arg->channel.freq);
-
-       cmd->chan.band_center_freq1 =
-               __cpu_to_le32(arg->channel.band_center_freq1);
-
-       cmd->chan.mode = arg->channel.mode;
-       cmd->chan.flags |= __cpu_to_le32(ch_flags);
-       cmd->chan.min_power = arg->channel.min_power;
-       cmd->chan.max_power = arg->channel.max_power;
-       cmd->chan.reg_power = arg->channel.max_reg_power;
-       cmd->chan.reg_classid = arg->channel.reg_class_id;
-       cmd->chan.antenna_max = arg->channel.max_antenna_gain;
+       ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n",
@@ -3946,35 +3871,10 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
        cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
 
        for (i = 0; i < arg->n_channels; i++) {
-               u32 flags = 0;
-
                ch = &arg->channels[i];
                ci = &cmd->chan_info[i];
 
-               if (ch->passive)
-                       flags |= WMI_CHAN_FLAG_PASSIVE;
-               if (ch->allow_ibss)
-                       flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
-               if (ch->allow_ht)
-                       flags |= WMI_CHAN_FLAG_ALLOW_HT;
-               if (ch->allow_vht)
-                       flags |= WMI_CHAN_FLAG_ALLOW_VHT;
-               if (ch->ht40plus)
-                       flags |= WMI_CHAN_FLAG_HT40_PLUS;
-               if (ch->chan_radar)
-                       flags |= WMI_CHAN_FLAG_DFS;
-
-               ci->mhz               = __cpu_to_le32(ch->freq);
-               ci->band_center_freq1 = __cpu_to_le32(ch->freq);
-               ci->band_center_freq2 = 0;
-               ci->min_power         = ch->min_power;
-               ci->max_power         = ch->max_power;
-               ci->reg_power         = ch->max_reg_power;
-               ci->antenna_max       = ch->max_antenna_gain;
-
-               /* mode & flags share storage */
-               ci->mode              = ch->mode;
-               ci->flags            |= __cpu_to_le32(flags);
+               ath10k_wmi_put_wmi_channel(ci, ch);
        }
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
@@ -4245,3 +4145,41 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
 }
+
+int ath10k_wmi_attach(struct ath10k *ar)
+{
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+                       ar->wmi.cmd = &wmi_10_2_cmd_map;
+               else
+                       ar->wmi.cmd = &wmi_10x_cmd_map;
+
+               ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
+               ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+       } else {
+               ar->wmi.cmd = &wmi_cmd_map;
+               ar->wmi.vdev_param = &wmi_vdev_param_map;
+               ar->wmi.pdev_param = &wmi_pdev_param_map;
+       }
+
+       init_completion(&ar->wmi.service_ready);
+       init_completion(&ar->wmi.unified_ready);
+       init_waitqueue_head(&ar->wmi.tx_credits_wq);
+
+       return 0;
+}
+
+void ath10k_wmi_detach(struct ath10k *ar)
+{
+       int i;
+
+       /* free the host memory chunks requested by firmware */
+       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+               dma_free_coherent(ar->dev,
+                                 ar->wmi.mem_chunks[i].len,
+                                 ar->wmi.mem_chunks[i].vaddr,
+                                 ar->wmi.mem_chunks[i].paddr);
+       }
+
+       ar->wmi.num_mem_chunks = 0;
+}