diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 10b33840e5e5..041d1d5eb718 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -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); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 8ddbae96794d..ffcf30756b9e 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -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; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index ec8063e7986a..cb152bb4a222 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -25,6 +25,7 @@ #include "core.h" #include "debug.h" #include "hif.h" +#include "htt.h" #include "wmi-ops.h" /* ms */ @@ -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)); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index f963391e3544..f9e90e1227de 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -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) @@ -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) { @@ -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 diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index b0d6c2614731..2df7fcb4a5ea 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -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 diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 1b59721a91ac..6579eb2b410c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -218,6 +218,27 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) return ret; } +struct sk_buff *ath10k_htt_tx_find_msdu_by_id(struct ath10k_htt *htt, + u16 msdu_id) +{ + struct ath10k *ar; + struct sk_buff *ret; + + if (!htt) + return NULL; + + ar = htt->ar; + + lockdep_assert_held(&htt->tx_lock); + + ret = (struct sk_buff *)idr_find(&htt->pending_tx, msdu_id); + + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx find msdu by msdu_id %s\n", + !ret ? "Failed" : "Success"); + + return ret; +} + void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) { struct ath10k *ar = htt->ar; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 0f2422480c4e..3e1917a6a8e8 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -984,4 +984,27 @@ struct ath10k_shadow_reg_address { extern struct ath10k_shadow_reg_value wcn3990_shadow_reg_value; extern struct ath10k_shadow_reg_address wcn3990_shadow_reg_address; +enum ath10k_pktlog_type { + ATH10K_PKTLOG_TYPE_TX_CTRL = 1, + ATH10K_PKTLOG_TYPE_TX_STAT, + ATH10K_PKTLOG_TYPE_TX_MSDU_ID, + ATH10K_PKTLOG_TYPE_TX_FRM_HDR, + ATH10K_PKTLOG_TYPE_RX_STAT, + ATH10K_PKTLOG_TYPE_RC_FIND, + ATH10K_PKTLOG_TYPE_RC_UPDATE, + ATH10K_PKTLOG_TYPE_TX_VIRT_ADDR, + ATH10K_PKTLOG_TYPE_DBG_PRINT, + ATH10K_PKTLOG_TYPE_SW_EVENT, + ATH10K_PKTLOG_TYPE_MAX, +}; + +struct ath10k_pktlog_hdr { + __le16 flags; + __le16 missed_cnt; + __le16 log_type; + __le16 size; + __le32 timestamp; + u8 payload[0]; +} __packed; + #endif /* _HW_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 0c60a7baae82..13736750e463 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -775,9 +775,6 @@ static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, } } - if (WARN_ON(!ul_set || !dl_set)) - return -ENOENT; - return 0; }