From 716ca530e1c4515d8683c9d5be3d56b301758b66 Mon Sep 17 00:00:00 2001 From: James <> Date: Wed, 4 Nov 2015 11:49:21 +0000 Subject: trunk-47381 --- ...10k-add-fw_stats-support-to-10.4-firmware.patch | 468 +++++++++++++++++++++ 1 file changed, 468 insertions(+) create mode 100644 package/kernel/mac80211/patches/305-ath10k-add-fw_stats-support-to-10.4-firmware.patch (limited to 'package/kernel/mac80211/patches/305-ath10k-add-fw_stats-support-to-10.4-firmware.patch') diff --git a/package/kernel/mac80211/patches/305-ath10k-add-fw_stats-support-to-10.4-firmware.patch b/package/kernel/mac80211/patches/305-ath10k-add-fw_stats-support-to-10.4-firmware.patch new file mode 100644 index 0000000..7deb19c --- /dev/null +++ b/package/kernel/mac80211/patches/305-ath10k-add-fw_stats-support-to-10.4-firmware.patch @@ -0,0 +1,468 @@ +From: Manikanta Pubbisetty +Date: Wed, 28 Oct 2015 21:38:33 +0200 +Subject: [PATCH] ath10k: add fw_stats support to 10.4 firmware + +This patch adds support for getting firmware debug stats in 10.4 fw. + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Tamizh chelvam +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/ath/ath10k/core.h ++++ b/drivers/net/wireless/ath/ath10k/core.h +@@ -214,6 +214,7 @@ struct ath10k_fw_stats_pdev { + s32 hw_queued; + s32 hw_reaped; + s32 underrun; ++ u32 hw_paused; + s32 tx_abort; + s32 mpdus_requed; + u32 tx_ko; +@@ -226,6 +227,16 @@ struct ath10k_fw_stats_pdev { + u32 pdev_resets; + u32 phy_underrun; + u32 txop_ovf; ++ u32 seq_posted; ++ u32 seq_failed_queueing; ++ u32 seq_completed; ++ u32 seq_restarted; ++ u32 mu_seq_posted; ++ u32 mpdus_sw_flush; ++ u32 mpdus_hw_filter; ++ u32 mpdus_truncated; ++ u32 mpdus_ack_failed; ++ u32 mpdus_expired; + + /* PDEV RX stats */ + s32 mid_ppdu_route_change; +@@ -242,6 +253,7 @@ struct ath10k_fw_stats_pdev { + s32 phy_errs; + s32 phy_err_drop; + s32 mpdu_errs; ++ s32 rx_ovfl_errs; + }; + + struct ath10k_fw_stats { +--- a/drivers/net/wireless/ath/ath10k/wmi.c ++++ b/drivers/net/wireless/ath/ath10k/wmi.c +@@ -2479,6 +2479,47 @@ void ath10k_wmi_pull_pdev_stats_tx(const + dst->txop_ovf = __le32_to_cpu(src->txop_ovf); + } + ++static void ++ath10k_wmi_10_4_pull_pdev_stats_tx(const struct wmi_10_4_pdev_stats_tx *src, ++ struct ath10k_fw_stats_pdev *dst) ++{ ++ dst->comp_queued = __le32_to_cpu(src->comp_queued); ++ dst->comp_delivered = __le32_to_cpu(src->comp_delivered); ++ dst->msdu_enqued = __le32_to_cpu(src->msdu_enqued); ++ dst->mpdu_enqued = __le32_to_cpu(src->mpdu_enqued); ++ dst->wmm_drop = __le32_to_cpu(src->wmm_drop); ++ dst->local_enqued = __le32_to_cpu(src->local_enqued); ++ dst->local_freed = __le32_to_cpu(src->local_freed); ++ dst->hw_queued = __le32_to_cpu(src->hw_queued); ++ dst->hw_reaped = __le32_to_cpu(src->hw_reaped); ++ dst->underrun = __le32_to_cpu(src->underrun); ++ dst->tx_abort = __le32_to_cpu(src->tx_abort); ++ dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed); ++ dst->tx_ko = __le32_to_cpu(src->tx_ko); ++ dst->data_rc = __le32_to_cpu(src->data_rc); ++ dst->self_triggers = __le32_to_cpu(src->self_triggers); ++ dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure); ++ dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err); ++ dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry); ++ dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout); ++ dst->pdev_resets = __le32_to_cpu(src->pdev_resets); ++ dst->phy_underrun = __le32_to_cpu(src->phy_underrun); ++ dst->txop_ovf = __le32_to_cpu(src->txop_ovf); ++ dst->hw_paused = __le32_to_cpu(src->hw_paused); ++ dst->seq_posted = __le32_to_cpu(src->seq_posted); ++ dst->seq_failed_queueing = ++ __le32_to_cpu(src->seq_failed_queueing); ++ dst->seq_completed = __le32_to_cpu(src->seq_completed); ++ dst->seq_restarted = __le32_to_cpu(src->seq_restarted); ++ dst->mu_seq_posted = __le32_to_cpu(src->mu_seq_posted); ++ dst->mpdus_sw_flush = __le32_to_cpu(src->mpdus_sw_flush); ++ dst->mpdus_hw_filter = __le32_to_cpu(src->mpdus_hw_filter); ++ dst->mpdus_truncated = __le32_to_cpu(src->mpdus_truncated); ++ dst->mpdus_ack_failed = __le32_to_cpu(src->mpdus_ack_failed); ++ dst->mpdus_hw_filter = __le32_to_cpu(src->mpdus_hw_filter); ++ dst->mpdus_expired = __le32_to_cpu(src->mpdus_expired); ++} ++ + void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, + struct ath10k_fw_stats_pdev *dst) + { +@@ -2789,6 +2830,86 @@ static int ath10k_wmi_10_2_4_op_pull_fw_ + return 0; + } + ++static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, ++ struct sk_buff *skb, ++ struct ath10k_fw_stats *stats) ++{ ++ const struct wmi_10_2_stats_event *ev = (void *)skb->data; ++ u32 num_pdev_stats; ++ u32 num_pdev_ext_stats; ++ u32 num_vdev_stats; ++ u32 num_peer_stats; ++ int i; ++ ++ if (!skb_pull(skb, sizeof(*ev))) ++ return -EPROTO; ++ ++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); ++ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); ++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); ++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats); ++ ++ for (i = 0; i < num_pdev_stats; i++) { ++ const struct wmi_10_4_pdev_stats *src; ++ struct ath10k_fw_stats_pdev *dst; ++ ++ src = (void *)skb->data; ++ if (!skb_pull(skb, sizeof(*src))) ++ return -EPROTO; ++ ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); ++ if (!dst) ++ continue; ++ ++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst); ++ ath10k_wmi_10_4_pull_pdev_stats_tx(&src->tx, dst); ++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); ++ dst->rx_ovfl_errs = __le32_to_cpu(src->rx_ovfl_errs); ++ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); ++ ++ list_add_tail(&dst->list, &stats->pdevs); ++ } ++ ++ for (i = 0; i < num_pdev_ext_stats; i++) { ++ const struct wmi_10_2_pdev_ext_stats *src; ++ ++ src = (void *)skb->data; ++ if (!skb_pull(skb, sizeof(*src))) ++ return -EPROTO; ++ ++ /* FIXME: expose values to userspace ++ * ++ * Note: Even though this loop seems to do nothing it is ++ * required to parse following sub-structures properly. ++ */ ++ } ++ ++ /* fw doesn't implement vdev stats */ ++ ++ for (i = 0; i < num_peer_stats; i++) { ++ const struct wmi_10_4_peer_stats *src; ++ struct ath10k_fw_stats_peer *dst; ++ ++ src = (void *)skb->data; ++ if (!skb_pull(skb, sizeof(*src))) ++ return -EPROTO; ++ ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC); ++ if (!dst) ++ continue; ++ ++ ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); ++ dst->peer_rssi = __le32_to_cpu(src->peer_rssi); ++ dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate); ++ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); ++ /* FIXME: expose 10.4 specific values */ ++ ++ list_add_tail(&dst->list, &stats->peers); ++ } ++ ++ return 0; ++} ++ + void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb) + { + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); +@@ -4935,6 +5056,9 @@ static void ath10k_wmi_10_4_op_rx(struct + ath10k_dbg(ar, ATH10K_DBG_WMI, + "received event id %d not implemented\n", id); + break; ++ case WMI_10_4_UPDATE_STATS_EVENTID: ++ ath10k_wmi_event_update_stats(ar, skb); ++ break; + default: + ath10k_warn(ar, "Unknown eventid: %d\n", id); + break; +@@ -7022,6 +7146,90 @@ ath10k_wmi_op_gen_pdev_enable_adaptive_c + return skb; + } + ++void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, ++ struct ath10k_fw_stats *fw_stats, ++ char *buf) ++{ ++ u32 len = 0; ++ u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; ++ const struct ath10k_fw_stats_pdev *pdev; ++ const struct ath10k_fw_stats_vdev *vdev; ++ const struct ath10k_fw_stats_peer *peer; ++ size_t num_peers; ++ size_t num_vdevs; ++ ++ spin_lock_bh(&ar->data_lock); ++ ++ pdev = list_first_entry_or_null(&fw_stats->pdevs, ++ struct ath10k_fw_stats_pdev, list); ++ if (!pdev) { ++ ath10k_warn(ar, "failed to get pdev stats\n"); ++ goto unlock; ++ } ++ ++ num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers); ++ num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs); ++ ++ ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len); ++ ath10k_wmi_fw_pdev_extra_stats_fill(pdev, buf, &len); ++ ath10k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len); ++ ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "HW paused", pdev->hw_paused); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Seqs posted", pdev->seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Seqs failed queueing", pdev->seq_failed_queueing); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Seqs completed", pdev->seq_completed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Seqs restarted", pdev->seq_restarted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "MU Seqs posted", pdev->mu_seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "MPDUs SW flushed", pdev->mpdus_sw_flush); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "MPDUs HW filtered", pdev->mpdus_hw_filter); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "MPDUs truncated", pdev->mpdus_truncated); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "MPDUs receive no ACK", pdev->mpdus_ack_failed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "MPDUs expired", pdev->mpdus_expired); ++ ++ ath10k_wmi_fw_pdev_rx_stats_fill(pdev, buf, &len); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Num Rx Overflow errors", pdev->rx_ovfl_errs); ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", ++ "ath10k VDEV stats", num_vdevs); ++ len += scnprintf(buf + len, buf_len - len, "%30s\n\n", ++ "================="); ++ ++ list_for_each_entry(vdev, &fw_stats->vdevs, list) { ++ ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len); ++ } ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", ++ "ath10k PEER stats", num_peers); ++ len += scnprintf(buf + len, buf_len - len, "%30s\n\n", ++ "================="); ++ ++ list_for_each_entry(peer, &fw_stats->peers, list) { ++ ath10k_wmi_fw_peer_stats_fill(peer, buf, &len); ++ } ++ ++unlock: ++ spin_unlock_bh(&ar->data_lock); ++ ++ if (len >= buf_len) ++ buf[len - 1] = 0; ++ else ++ buf[len] = 0; ++} ++ + static const struct wmi_ops wmi_ops = { + .rx = ath10k_wmi_op_rx, + .map_svc = wmi_main_svc_map, +@@ -7292,6 +7500,7 @@ static const struct wmi_ops wmi_10_4_ops + .rx = ath10k_wmi_10_4_op_rx, + .map_svc = wmi_10_4_svc_map, + ++ .pull_fw_stats = ath10k_wmi_10_4_op_pull_fw_stats, + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_10_4_op_pull_ch_info_ev, +@@ -7341,9 +7550,11 @@ static const struct wmi_ops wmi_10_4_ops + .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, ++ .fw_stats_fill = ath10k_wmi_10_4_op_fw_stats_fill, + + /* shared with 10.2 */ + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, ++ .gen_request_stats = ath10k_wmi_op_gen_request_stats, + }; + + int ath10k_wmi_attach(struct ath10k *ar) +--- a/drivers/net/wireless/ath/ath10k/wmi.h ++++ b/drivers/net/wireless/ath/ath10k/wmi.h +@@ -3866,6 +3866,111 @@ struct wmi_pdev_stats_tx { + __le32 txop_ovf; + } __packed; + ++struct wmi_10_4_pdev_stats_tx { ++ /* Num HTT cookies queued to dispatch list */ ++ __le32 comp_queued; ++ ++ /* Num HTT cookies dispatched */ ++ __le32 comp_delivered; ++ ++ /* Num MSDU queued to WAL */ ++ __le32 msdu_enqued; ++ ++ /* Num MPDU queue to WAL */ ++ __le32 mpdu_enqued; ++ ++ /* Num MSDUs dropped by WMM limit */ ++ __le32 wmm_drop; ++ ++ /* Num Local frames queued */ ++ __le32 local_enqued; ++ ++ /* Num Local frames done */ ++ __le32 local_freed; ++ ++ /* Num queued to HW */ ++ __le32 hw_queued; ++ ++ /* Num PPDU reaped from HW */ ++ __le32 hw_reaped; ++ ++ /* Num underruns */ ++ __le32 underrun; ++ ++ /* HW Paused. */ ++ __le32 hw_paused; ++ ++ /* Num PPDUs cleaned up in TX abort */ ++ __le32 tx_abort; ++ ++ /* Num MPDUs requed by SW */ ++ __le32 mpdus_requed; ++ ++ /* excessive retries */ ++ __le32 tx_ko; ++ ++ /* data hw rate code */ ++ __le32 data_rc; ++ ++ /* Scheduler self triggers */ ++ __le32 self_triggers; ++ ++ /* frames dropped due to excessive sw retries */ ++ __le32 sw_retry_failure; ++ ++ /* illegal rate phy errors */ ++ __le32 illgl_rate_phy_err; ++ ++ /* wal pdev continuous xretry */ ++ __le32 pdev_cont_xretry; ++ ++ /* wal pdev tx timeouts */ ++ __le32 pdev_tx_timeout; ++ ++ /* wal pdev resets */ ++ __le32 pdev_resets; ++ ++ /* frames dropped due to non-availability of stateless TIDs */ ++ __le32 stateless_tid_alloc_failure; ++ ++ __le32 phy_underrun; ++ ++ /* MPDU is more than txop limit */ ++ __le32 txop_ovf; ++ ++ /* Number of Sequences posted */ ++ __le32 seq_posted; ++ ++ /* Number of Sequences failed queueing */ ++ __le32 seq_failed_queueing; ++ ++ /* Number of Sequences completed */ ++ __le32 seq_completed; ++ ++ /* Number of Sequences restarted */ ++ __le32 seq_restarted; ++ ++ /* Number of MU Sequences posted */ ++ __le32 mu_seq_posted; ++ ++ /* Num MPDUs flushed by SW, HWPAUSED,SW TXABORT(Reset,channel change) */ ++ __le32 mpdus_sw_flush; ++ ++ /* Num MPDUs filtered by HW, all filter condition (TTL expired) */ ++ __le32 mpdus_hw_filter; ++ ++ /* Num MPDUs truncated by PDG ++ * (TXOP, TBTT, PPDU_duration based on rate, dyn_bw) ++ */ ++ __le32 mpdus_truncated; ++ ++ /* Num MPDUs that was tried but didn't receive ACK or BA */ ++ __le32 mpdus_ack_failed; ++ ++ /* Num MPDUs that was dropped due to expiry. */ ++ __le32 mpdus_expired; ++} __packed; ++ + struct wmi_pdev_stats_rx { + /* Cnts any change in ring routing mid-ppdu */ + __le32 mid_ppdu_route_change; +@@ -4039,6 +4144,16 @@ struct wmi_10_2_pdev_stats { + struct wmi_pdev_stats_extra extra; + } __packed; + ++struct wmi_10_4_pdev_stats { ++ struct wmi_pdev_stats_base base; ++ struct wmi_10_4_pdev_stats_tx tx; ++ struct wmi_pdev_stats_rx rx; ++ __le32 rx_ovfl_errs; ++ struct wmi_pdev_stats_mem mem; ++ __le32 sram_free_size; ++ struct wmi_pdev_stats_extra extra; ++} __packed; ++ + /* + * VDEV statistics + * TODO: add all VDEV stats here +@@ -4080,6 +4195,23 @@ struct wmi_10_2_4_peer_stats { + __le32 unknown_value; /* FIXME: what is this word? */ + } __packed; + ++struct wmi_10_4_peer_stats { ++ struct wmi_mac_addr peer_macaddr; ++ __le32 peer_rssi; ++ __le32 peer_rssi_seq_num; ++ __le32 peer_tx_rate; ++ __le32 peer_rx_rate; ++ __le32 current_per; ++ __le32 retries; ++ __le32 tx_rate_count; ++ __le32 max_4ms_frame_len; ++ __le32 total_sub_frames; ++ __le32 tx_bytes; ++ __le32 num_pkt_loss_overflow[4]; ++ __le32 num_pkt_loss_excess_retry[4]; ++ __le32 peer_rssi_changed; ++} __packed; ++ + struct wmi_10_2_pdev_ext_stats { + __le32 rx_rssi_comb; + __le32 rx_rssi[4]; +@@ -6201,5 +6333,8 @@ void ath10k_wmi_10x_op_fw_stats_fill(str + char *buf); + size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head); + size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head); ++void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, ++ struct ath10k_fw_stats *fw_stats, ++ char *buf); + + #endif /* _WMI_H_ */ -- cgit v1.2.3