]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ath10k: deduplicate wmi service ready logic
authorMichal Kazior <michal.kazior@tieto.com>
Thu, 18 Sep 2014 13:21:24 +0000 (15:21 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Tue, 23 Sep 2014 09:31:25 +0000 (12:31 +0300)
The logic responsible for processing the event is
no different across different firmware binaries.
The difference that needs to be dealt with is the
ABI of data structures.

The intermediate structure uses __le32 to avoid
extra memory allocations to byteswap
variable-length substructures (i.e. host mem
chunks).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h

index d1ea936d14b7cec3109244b1a0288465dc376ad3..8a997b6e11c307193c89e3cf3ac0add8154ad91e 100644 (file)
@@ -96,8 +96,6 @@ struct ath10k_bmi {
        bool done_sent;
 };
 
-#define ATH10K_MAX_MEM_REQS 16
-
 struct ath10k_mem_chunk {
        void *vaddr;
        dma_addr_t paddr;
@@ -115,7 +113,7 @@ struct ath10k_wmi {
        struct wmi_pdev_param_map *pdev_param;
 
        u32 num_mem_chunks;
-       struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];
+       struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
 };
 
 struct ath10k_peer_stat {
index 3756feba32231cffcddd112575163d1a7cf6cc67..101c6f9cf2a82d628f12db11f0a03b946a79dafa 100644 (file)
@@ -182,7 +182,7 @@ EXPORT_SYMBOL(ath10k_warn);
 #ifdef CONFIG_ATH10K_DEBUGFS
 
 void ath10k_debug_read_service_map(struct ath10k *ar,
-                                  void *service_map,
+                                  const void *service_map,
                                   size_t map_size)
 {
        memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
index b3774f7f492c480d941a300a81b15a2c8a6cb234..d6276fea1adf035f236f9937d0c642d1a5b13285 100644 (file)
@@ -53,7 +53,7 @@ void ath10k_debug_destroy(struct ath10k *ar);
 int ath10k_debug_register(struct ath10k *ar);
 void ath10k_debug_unregister(struct ath10k *ar);
 void ath10k_debug_read_service_map(struct ath10k *ar,
-                                  void *service_map,
+                                  const void *service_map,
                                   size_t map_size);
 void ath10k_debug_read_target_stats(struct ath10k *ar,
                                    struct wmi_stats_event *ev);
@@ -93,7 +93,7 @@ static inline void ath10k_debug_unregister(struct ath10k *ar)
 }
 
 static inline void ath10k_debug_read_service_map(struct ath10k *ar,
-                                                void *service_map,
+                                                const void *service_map,
                                                 size_t map_size)
 {
 }
index cec0c2839e5b643c197be34f478a435b1831f940..a7c11b292bf445eab6b0544be2d6a3e881148a39 100644 (file)
@@ -2205,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)
@@ -2243,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),
@@ -2261,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
@@ -2364,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);
@@ -2375,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);
 }
@@ -2634,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);
@@ -2745,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);
index fc8bc9dd362945c81baf6e677decc50d69fb8220..ca31cdbac557342c39a393f411c1f542ecd38444 100644 (file)
@@ -1428,11 +1428,11 @@ struct wmi_service_ready_event {
         * where FW can access this memory directly (or) by DMA.
         */
        __le32 num_mem_reqs;
-       struct wlan_host_mem_req mem_reqs[1];
+       struct wlan_host_mem_req mem_reqs[0];
 } __packed;
 
 /* This is the definition from 10.X firmware branch */
-struct wmi_service_ready_event_10x {
+struct wmi_10x_service_ready_event {
        __le32 sw_version;
        __le32 abi_version;
 
@@ -1467,7 +1467,7 @@ struct wmi_service_ready_event_10x {
         */
        __le32 num_mem_reqs;
 
-       struct wlan_host_mem_req mem_reqs[1];
+       struct wlan_host_mem_req mem_reqs[0];
 } __packed;
 
 #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
@@ -4702,6 +4702,23 @@ struct wmi_dbglog_cfg_cmd {
 /* By default disable power save for IBSS */
 #define ATH10K_DEFAULT_ATIM 0
 
+#define WMI_MAX_MEM_REQS 16
+
+struct wmi_svc_rdy_ev_arg {
+       __le32 min_tx_power;
+       __le32 max_tx_power;
+       __le32 ht_cap;
+       __le32 vht_cap;
+       __le32 sw_ver0;
+       __le32 sw_ver1;
+       __le32 phy_capab;
+       __le32 num_rf_chains;
+       __le32 eeprom_rd;
+       __le32 num_mem_reqs;
+       const __le32 *service_map;
+       const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
+};
+
 struct ath10k;
 struct ath10k_vif;