diff options
author | Rakesh Pillai <pillair@codeaurora.org> | 2019-01-25 09:40:01 +0530 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2019-02-07 16:36:50 +0200 |
commit | cc123fac978f468e419b7bbd2e153e54196254de (patch) | |
tree | a61c687164b70c27c0705ea03002eefaf12a4cf0 | |
parent | 768ec4c012ac8b32d8062e599f105f57a6f4c01b (diff) |
ath10k: Handle bundled tx completion for management frames
WCN3990 supports sending tx completion for multiple
management frames bundled together in a single event.
Add support to handle the bundled tx completion
event for WCN3990.
Tested HW: WCN3990
Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1
Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-ops.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.c | 63 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 7 |
5 files changed, 107 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 04663076d27a..e92d00a6a2a1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -33,6 +33,9 @@ struct wmi_ops { struct wmi_mgmt_rx_ev_arg *arg); int (*pull_mgmt_tx_compl)(struct ath10k *ar, struct sk_buff *skb, struct wmi_tlv_mgmt_tx_compl_ev_arg *arg); + int (*pull_mgmt_tx_bundle_compl)( + struct ath10k *ar, struct sk_buff *skb, + struct wmi_tlv_mgmt_tx_bundle_compl_ev_arg *arg); int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb, struct wmi_ch_info_ev_arg *arg); int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb, @@ -280,6 +283,16 @@ ath10k_wmi_pull_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb, } static inline int +ath10k_wmi_pull_mgmt_tx_bundle_compl(struct ath10k *ar, struct sk_buff *skb, + struct wmi_tlv_mgmt_tx_bundle_compl_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_mgmt_tx_bundle_compl) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_mgmt_tx_bundle_compl(ar, skb, arg); +} + +static inline int ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb, struct wmi_mgmt_rx_ev_arg *arg) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 892bd8c30dd9..e85d6be1fb90 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -620,6 +620,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_MGMT_TX_COMPLETION_EVENTID: ath10k_wmi_event_mgmt_tx_compl(ar, skb); break; + case WMI_TLV_MGMT_TX_BUNDLE_COMPLETION_EVENTID: + ath10k_wmi_event_mgmt_tx_bundle_compl(ar, skb); + break; default: ath10k_dbg(ar, ATH10K_DBG_WMI, "Unknown eventid: %d\n", id); break; @@ -686,6 +689,65 @@ ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +struct wmi_tlv_tx_bundle_compl_parse { + const __le32 *num_reports; + const __le32 *desc_ids; + const __le32 *status; + bool desc_ids_done; + bool status_done; +}; + +static int +ath10k_wmi_tlv_mgmt_tx_bundle_compl_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_tx_bundle_compl_parse *bundle_tx_compl = data; + + switch (tag) { + case WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_BUNDLE_EVENT: + bundle_tx_compl->num_reports = ptr; + break; + case WMI_TLV_TAG_ARRAY_UINT32: + if (!bundle_tx_compl->desc_ids_done) { + bundle_tx_compl->desc_ids_done = true; + bundle_tx_compl->desc_ids = ptr; + } else if (!bundle_tx_compl->status_done) { + bundle_tx_compl->status_done = true; + bundle_tx_compl->status = ptr; + } + break; + default: + break; + } + return 0; +} + +static int ath10k_wmi_tlv_op_pull_mgmt_tx_bundle_compl_ev( + struct ath10k *ar, struct sk_buff *skb, + struct wmi_tlv_mgmt_tx_bundle_compl_ev_arg *arg) +{ + struct wmi_tlv_tx_bundle_compl_parse bundle_tx_compl = { }; + int ret; + + ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len, + ath10k_wmi_tlv_mgmt_tx_bundle_compl_parse, + &bundle_tx_compl); + if (ret) { + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + if (!bundle_tx_compl.num_reports || !bundle_tx_compl.desc_ids || + !bundle_tx_compl.status) + return -EPROTO; + + arg->num_reports = *bundle_tx_compl.num_reports; + arg->desc_ids = bundle_tx_compl.desc_ids; + arg->status = bundle_tx_compl.status; + + return 0; +} + static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, struct wmi_mgmt_rx_ev_arg *arg) @@ -4093,6 +4155,7 @@ static const struct wmi_ops wmi_tlv_ops = { .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, .pull_mgmt_tx_compl = ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev, + .pull_mgmt_tx_bundle_compl = ath10k_wmi_tlv_op_pull_mgmt_tx_bundle_compl_ev, .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev, .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index e07e9907e355..5941961bec9c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -321,6 +321,7 @@ enum wmi_tlv_event_id { WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID, WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID, WMI_TLV_MGMT_TX_COMPLETION_EVENTID, + WMI_TLV_MGMT_TX_BUNDLE_COMPLETION_EVENTID, WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG), WMI_TLV_TX_ADDBA_COMPLETE_EVENTID, WMI_TLV_BA_RSP_SSN_EVENTID, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ba837403e266..971ff364d8b1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2383,6 +2383,29 @@ int ath10k_wmi_event_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb) return 0; } +int ath10k_wmi_event_mgmt_tx_bundle_compl(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_tlv_mgmt_tx_bundle_compl_ev_arg arg; + u32 num_reports; + int i, ret; + + ret = ath10k_wmi_pull_mgmt_tx_bundle_compl(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse bundle mgmt compl event: %d\n", ret); + return ret; + } + + num_reports = __le32_to_cpu(arg.num_reports); + + for (i = 0; i < num_reports; i++) + wmi_process_mgmt_tx_comp(ar, __le32_to_cpu(arg.desc_ids[i]), + __le32_to_cpu(arg.status[i])); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv event bundle mgmt tx completion\n"); + + return 0; +} + int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_ev_arg arg = {}; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 2034ccc7cc72..ac04077c4e69 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6688,6 +6688,12 @@ struct wmi_tlv_mgmt_tx_compl_ev_arg { __le32 pdev_id; }; +struct wmi_tlv_mgmt_tx_bundle_compl_ev_arg { + __le32 num_reports; + const __le32 *desc_ids; + const __le32 *status; +}; + struct wmi_mgmt_rx_ev_arg { __le32 channel; __le32 snr; @@ -7244,6 +7250,7 @@ int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg); int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_event_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_event_mgmt_tx_bundle_compl(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb); |