Loading drivers/net/wireless/ath/ath10k/core.c +6 −0 Original line number Diff line number Diff line Loading @@ -1924,6 +1924,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_hif_stop; } status = ath10k_pktlog_connect(ar); if (status) { ath10k_err(ar, "could not connect pktlog: %d\n", status); goto err_hif_stop; } status = ath10k_htc_start(&ar->htc); if (status) { ath10k_err(ar, "failed to start htc: %d\n", status); Loading drivers/net/wireless/ath/ath10k/core.h +1 −0 Original line number Diff line number Diff line Loading @@ -467,6 +467,7 @@ struct ath10k_debug { u64 fw_dbglog_mask; u32 fw_dbglog_level; u32 pktlog_filter; enum ath10k_htc_ep_id eid; u32 reg_addr; u32 nf_cal_period; void *cal_data; Loading drivers/net/wireless/ath/ath10k/debug.c +133 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "core.h" #include "debug.h" #include "hif.h" #include "htt.h" #include "wmi-ops.h" /* ms */ Loading Loading @@ -2617,6 +2618,138 @@ static const struct file_operations fops_fw_checksums = { .llseek = default_llseek, }; static struct txctl_frm_hdr frm_hdr; static void ath10k_extract_frame_header(u8 *addr1, u8 *addr2, u8 *addr3) { frm_hdr.bssid_tail = (addr1[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) | (addr1[IEEE80211_ADDR_LEN - 1]); frm_hdr.sa_tail = (addr2[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) | (addr2[IEEE80211_ADDR_LEN - 1]); frm_hdr.da_tail = (addr3[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) | (addr3[IEEE80211_ADDR_LEN - 1]); } static void ath10k_process_ieee_hdr(void *data) { u8 dir; struct ieee80211_frame *wh; if (!data) return; wh = (struct ieee80211_frame *)(data); frm_hdr.framectrl = *(u_int16_t *)(wh->i_fc); frm_hdr.seqctrl = *(u_int16_t *)(wh->i_seq); dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK); if (dir == IEEE80211_FC1_DIR_TODS) ath10k_extract_frame_header(&wh->i_addr1, &wh->i_addr2, &wh->i_addr3); else if (dir == IEEE80211_FC1_DIR_FROMDS) ath10k_extract_frame_header(&wh->i_addr2, &wh->i_addr3, &wh->i_addr1); else ath10k_extract_frame_header(&wh->i_addr3, &wh->i_addr2, &wh->i_addr1); } static void ath10k_pktlog_process_rx(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_pktlog_hdr *hdr = (void *)skb->data; struct ath_pktlog_txctl pktlog_tx_ctrl; switch (hdr->log_type) { case ATH10K_PKTLOG_TYPE_TX_CTRL: { spin_lock_bh(&ar->htt.tx_lock); memcpy((void *)(&pktlog_tx_ctrl.hdr), (void *)hdr, sizeof(pktlog_tx_ctrl.hdr)); pktlog_tx_ctrl.frm_hdr = frm_hdr; memcpy((void *)pktlog_tx_ctrl.txdesc_ctl, (void *)hdr->payload, __le16_to_cpu(hdr->size)); pktlog_tx_ctrl.hdr.size = sizeof(pktlog_tx_ctrl) - sizeof(pktlog_tx_ctrl.hdr); spin_unlock_bh(&ar->htt.tx_lock); trace_ath10k_htt_pktlog(ar, (void *)&pktlog_tx_ctrl, sizeof(pktlog_tx_ctrl)); break; } case ATH10K_PKTLOG_TYPE_TX_MSDU_ID: break; case ATH10K_PKTLOG_TYPE_TX_FRM_HDR: { ath10k_process_ieee_hdr((void *)(hdr->payload)); trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + __le16_to_cpu(hdr->size)); break; } case ATH10K_PKTLOG_TYPE_RX_STAT: case ATH10K_PKTLOG_TYPE_RC_FIND: case ATH10K_PKTLOG_TYPE_RC_UPDATE: case ATH10K_PKTLOG_TYPE_DBG_PRINT: case ATH10K_PKTLOG_TYPE_TX_STAT: case ATH10K_PKTLOG_TYPE_SW_EVENT: trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + __le16_to_cpu(hdr->size)); break; case ATH10K_PKTLOG_TYPE_TX_VIRT_ADDR: { u32 desc_id = (u32)*((u32 *)(hdr->payload)); struct sk_buff *msdu; spin_lock_bh(&ar->htt.tx_lock); msdu = ath10k_htt_tx_find_msdu_by_id(&ar->htt, desc_id); if (!msdu) { ath10k_info(ar, "Failed to get msdu, id: %d\n", desc_id); spin_unlock_bh(&ar->htt.tx_lock); return; } ath10k_process_ieee_hdr((void *)msdu->data); spin_unlock_bh(&ar->htt.tx_lock); trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + __le16_to_cpu(hdr->size)); break; } } } static void ath10k_pktlog_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) { ath10k_info(ar, "PKTLOG htc completed\n"); } int ath10k_pktlog_connect(struct ath10k *ar) { int status; struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; memset(&conn_req, 0, sizeof(conn_req)); memset(&conn_resp, 0, sizeof(conn_resp)); conn_req.ep_ops.ep_tx_complete = ath10k_pktlog_htc_tx_complete; conn_req.ep_ops.ep_rx_complete = ath10k_pktlog_process_rx; conn_req.ep_ops.ep_tx_credits = NULL; /* connect to control service */ conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_LOG_MSG; status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp); if (status) { ath10k_warn(ar, "failed to connect to PKTLOG service: %d\n", status); return status; } ar->debug.eid = conn_resp.eid; return 0; } int ath10k_debug_create(struct ath10k *ar) { ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); Loading drivers/net/wireless/ath/ath10k/debug.h +83 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,84 @@ enum ath10k_dbg_aggr_mode { ATH10K_DBG_AGGR_MODE_MAX, }; #define IEEE80211_FC1_DIR_MASK 0x03 #define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ #define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ #define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ #define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ #define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ #define MAX_PKT_INFO_MSDU_ID 192 #define MSDU_ID_INFO_ID_OFFSET \ ((MAX_PKT_INFO_MSDU_ID >> 3) + 4) #define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ #define HTT_TX_MSDU_LEN_MASK 0xffff struct txctl_frm_hdr { __le16 framectrl; /* frame control field from header */ __le16 seqctrl; /* frame control field from header */ __le16 bssid_tail; /* last two octets of bssid */ __le16 sa_tail; /* last two octets of SA */ __le16 da_tail; /* last two octets of DA */ __le16 resvd; } __packed; struct ath_pktlog_hdr { __le16 flags; __le16 missed_cnt; u8 log_type; u8 macId; __le16 size; __le32 timestamp; __le32 type_specific_data; } __packed; /* generic definitions for IEEE 802.11 frames */ struct ieee80211_frame { u8 i_fc[2]; u8 i_dur[2]; union { struct { u8 i_addr1[IEEE80211_ADDR_LEN]; u8 i_addr2[IEEE80211_ADDR_LEN]; u8 i_addr3[IEEE80211_ADDR_LEN]; }; u8 i_addr_all[3 * IEEE80211_ADDR_LEN]; }; u8 i_seq[2]; } __packed; struct fw_pktlog_msdu_info { __le32 num_msdu; u8 bound_bmap[MAX_PKT_INFO_MSDU_ID >> 3]; __le16 id[MAX_PKT_INFO_MSDU_ID]; } __packed; struct ath_pktlog_txctl { struct ath_pktlog_hdr hdr; struct txctl_frm_hdr frm_hdr; __le32 txdesc_ctl[PKTLOG_MAX_TXCTL_WORDS]; } __packed; struct ath_pktlog_msdu_id { struct ath_pktlog_hdr hdr; struct fw_pktlog_msdu_info msdu_info; } __packed; struct ath_pktlog_rx_info { struct ath_pktlog_hdr pl_hdr; struct rx_attention attention; struct rx_frag_info frag_info; struct rx_mpdu_start mpdu_start; struct rx_msdu_start msdu_start; struct rx_msdu_end msdu_end; struct rx_mpdu_end mpdu_end; struct rx_ppdu_start ppdu_start; struct rx_ppdu_end ppdu_end; u8 rx_hdr_status[RX_HTT_HDR_STATUS_LEN]; } __packed; /* FIXME: How to calculate the buffer size sanely? */ #define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024) #define ATH10K_DATAPATH_BUF_SIZE (1024 * 1024) Loading Loading @@ -98,6 +176,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, struct ethtool_stats *stats, u64 *data); void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status); size_t get_datapath_stat(char *buf, struct ath10k *ar); int ath10k_pktlog_connect(struct ath10k *ar); #else static inline int ath10k_debug_start(struct ath10k *ar) { Loading Loading @@ -158,6 +237,10 @@ static inline size_t get_datapath_stat(char *buf, struct ath10k *ar) return 0; } static inline int ath10k_pktlog_connect(struct ath10k *ar) { return 0; } #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) #define ath10k_debug_get_et_strings NULL Loading drivers/net/wireless/ath/ath10k/htt.h +2 −0 Original line number Diff line number Diff line Loading @@ -1847,5 +1847,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget); struct sk_buff *ath10k_htt_tx_find_msdu_by_id(struct ath10k_htt *htt, u16 msdu_id); #endif Loading
drivers/net/wireless/ath/ath10k/core.c +6 −0 Original line number Diff line number Diff line Loading @@ -1924,6 +1924,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_hif_stop; } status = ath10k_pktlog_connect(ar); if (status) { ath10k_err(ar, "could not connect pktlog: %d\n", status); goto err_hif_stop; } status = ath10k_htc_start(&ar->htc); if (status) { ath10k_err(ar, "failed to start htc: %d\n", status); Loading
drivers/net/wireless/ath/ath10k/core.h +1 −0 Original line number Diff line number Diff line Loading @@ -467,6 +467,7 @@ struct ath10k_debug { u64 fw_dbglog_mask; u32 fw_dbglog_level; u32 pktlog_filter; enum ath10k_htc_ep_id eid; u32 reg_addr; u32 nf_cal_period; void *cal_data; Loading
drivers/net/wireless/ath/ath10k/debug.c +133 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "core.h" #include "debug.h" #include "hif.h" #include "htt.h" #include "wmi-ops.h" /* ms */ Loading Loading @@ -2617,6 +2618,138 @@ static const struct file_operations fops_fw_checksums = { .llseek = default_llseek, }; static struct txctl_frm_hdr frm_hdr; static void ath10k_extract_frame_header(u8 *addr1, u8 *addr2, u8 *addr3) { frm_hdr.bssid_tail = (addr1[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) | (addr1[IEEE80211_ADDR_LEN - 1]); frm_hdr.sa_tail = (addr2[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) | (addr2[IEEE80211_ADDR_LEN - 1]); frm_hdr.da_tail = (addr3[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) | (addr3[IEEE80211_ADDR_LEN - 1]); } static void ath10k_process_ieee_hdr(void *data) { u8 dir; struct ieee80211_frame *wh; if (!data) return; wh = (struct ieee80211_frame *)(data); frm_hdr.framectrl = *(u_int16_t *)(wh->i_fc); frm_hdr.seqctrl = *(u_int16_t *)(wh->i_seq); dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK); if (dir == IEEE80211_FC1_DIR_TODS) ath10k_extract_frame_header(&wh->i_addr1, &wh->i_addr2, &wh->i_addr3); else if (dir == IEEE80211_FC1_DIR_FROMDS) ath10k_extract_frame_header(&wh->i_addr2, &wh->i_addr3, &wh->i_addr1); else ath10k_extract_frame_header(&wh->i_addr3, &wh->i_addr2, &wh->i_addr1); } static void ath10k_pktlog_process_rx(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_pktlog_hdr *hdr = (void *)skb->data; struct ath_pktlog_txctl pktlog_tx_ctrl; switch (hdr->log_type) { case ATH10K_PKTLOG_TYPE_TX_CTRL: { spin_lock_bh(&ar->htt.tx_lock); memcpy((void *)(&pktlog_tx_ctrl.hdr), (void *)hdr, sizeof(pktlog_tx_ctrl.hdr)); pktlog_tx_ctrl.frm_hdr = frm_hdr; memcpy((void *)pktlog_tx_ctrl.txdesc_ctl, (void *)hdr->payload, __le16_to_cpu(hdr->size)); pktlog_tx_ctrl.hdr.size = sizeof(pktlog_tx_ctrl) - sizeof(pktlog_tx_ctrl.hdr); spin_unlock_bh(&ar->htt.tx_lock); trace_ath10k_htt_pktlog(ar, (void *)&pktlog_tx_ctrl, sizeof(pktlog_tx_ctrl)); break; } case ATH10K_PKTLOG_TYPE_TX_MSDU_ID: break; case ATH10K_PKTLOG_TYPE_TX_FRM_HDR: { ath10k_process_ieee_hdr((void *)(hdr->payload)); trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + __le16_to_cpu(hdr->size)); break; } case ATH10K_PKTLOG_TYPE_RX_STAT: case ATH10K_PKTLOG_TYPE_RC_FIND: case ATH10K_PKTLOG_TYPE_RC_UPDATE: case ATH10K_PKTLOG_TYPE_DBG_PRINT: case ATH10K_PKTLOG_TYPE_TX_STAT: case ATH10K_PKTLOG_TYPE_SW_EVENT: trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + __le16_to_cpu(hdr->size)); break; case ATH10K_PKTLOG_TYPE_TX_VIRT_ADDR: { u32 desc_id = (u32)*((u32 *)(hdr->payload)); struct sk_buff *msdu; spin_lock_bh(&ar->htt.tx_lock); msdu = ath10k_htt_tx_find_msdu_by_id(&ar->htt, desc_id); if (!msdu) { ath10k_info(ar, "Failed to get msdu, id: %d\n", desc_id); spin_unlock_bh(&ar->htt.tx_lock); return; } ath10k_process_ieee_hdr((void *)msdu->data); spin_unlock_bh(&ar->htt.tx_lock); trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + __le16_to_cpu(hdr->size)); break; } } } static void ath10k_pktlog_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) { ath10k_info(ar, "PKTLOG htc completed\n"); } int ath10k_pktlog_connect(struct ath10k *ar) { int status; struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; memset(&conn_req, 0, sizeof(conn_req)); memset(&conn_resp, 0, sizeof(conn_resp)); conn_req.ep_ops.ep_tx_complete = ath10k_pktlog_htc_tx_complete; conn_req.ep_ops.ep_rx_complete = ath10k_pktlog_process_rx; conn_req.ep_ops.ep_tx_credits = NULL; /* connect to control service */ conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_LOG_MSG; status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp); if (status) { ath10k_warn(ar, "failed to connect to PKTLOG service: %d\n", status); return status; } ar->debug.eid = conn_resp.eid; return 0; } int ath10k_debug_create(struct ath10k *ar) { ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); Loading
drivers/net/wireless/ath/ath10k/debug.h +83 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,84 @@ enum ath10k_dbg_aggr_mode { ATH10K_DBG_AGGR_MODE_MAX, }; #define IEEE80211_FC1_DIR_MASK 0x03 #define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ #define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ #define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ #define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ #define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ #define MAX_PKT_INFO_MSDU_ID 192 #define MSDU_ID_INFO_ID_OFFSET \ ((MAX_PKT_INFO_MSDU_ID >> 3) + 4) #define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ #define HTT_TX_MSDU_LEN_MASK 0xffff struct txctl_frm_hdr { __le16 framectrl; /* frame control field from header */ __le16 seqctrl; /* frame control field from header */ __le16 bssid_tail; /* last two octets of bssid */ __le16 sa_tail; /* last two octets of SA */ __le16 da_tail; /* last two octets of DA */ __le16 resvd; } __packed; struct ath_pktlog_hdr { __le16 flags; __le16 missed_cnt; u8 log_type; u8 macId; __le16 size; __le32 timestamp; __le32 type_specific_data; } __packed; /* generic definitions for IEEE 802.11 frames */ struct ieee80211_frame { u8 i_fc[2]; u8 i_dur[2]; union { struct { u8 i_addr1[IEEE80211_ADDR_LEN]; u8 i_addr2[IEEE80211_ADDR_LEN]; u8 i_addr3[IEEE80211_ADDR_LEN]; }; u8 i_addr_all[3 * IEEE80211_ADDR_LEN]; }; u8 i_seq[2]; } __packed; struct fw_pktlog_msdu_info { __le32 num_msdu; u8 bound_bmap[MAX_PKT_INFO_MSDU_ID >> 3]; __le16 id[MAX_PKT_INFO_MSDU_ID]; } __packed; struct ath_pktlog_txctl { struct ath_pktlog_hdr hdr; struct txctl_frm_hdr frm_hdr; __le32 txdesc_ctl[PKTLOG_MAX_TXCTL_WORDS]; } __packed; struct ath_pktlog_msdu_id { struct ath_pktlog_hdr hdr; struct fw_pktlog_msdu_info msdu_info; } __packed; struct ath_pktlog_rx_info { struct ath_pktlog_hdr pl_hdr; struct rx_attention attention; struct rx_frag_info frag_info; struct rx_mpdu_start mpdu_start; struct rx_msdu_start msdu_start; struct rx_msdu_end msdu_end; struct rx_mpdu_end mpdu_end; struct rx_ppdu_start ppdu_start; struct rx_ppdu_end ppdu_end; u8 rx_hdr_status[RX_HTT_HDR_STATUS_LEN]; } __packed; /* FIXME: How to calculate the buffer size sanely? */ #define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024) #define ATH10K_DATAPATH_BUF_SIZE (1024 * 1024) Loading Loading @@ -98,6 +176,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, struct ethtool_stats *stats, u64 *data); void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status); size_t get_datapath_stat(char *buf, struct ath10k *ar); int ath10k_pktlog_connect(struct ath10k *ar); #else static inline int ath10k_debug_start(struct ath10k *ar) { Loading Loading @@ -158,6 +237,10 @@ static inline size_t get_datapath_stat(char *buf, struct ath10k *ar) return 0; } static inline int ath10k_pktlog_connect(struct ath10k *ar) { return 0; } #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) #define ath10k_debug_get_et_strings NULL Loading
drivers/net/wireless/ath/ath10k/htt.h +2 −0 Original line number Diff line number Diff line Loading @@ -1847,5 +1847,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget); struct sk_buff *ath10k_htt_tx_find_msdu_by_id(struct ath10k_htt *htt, u16 msdu_id); #endif