ath10k: Enable pktlog for WCN3990 target

WCN3990 target uses new connect service for pktlog.
Add pktlog service request and support for pktlog
rx handling.

CRs-Fixed: 2038976
Change-Id: I6f7dbd8f8cbeadd0e53844154a9c360011e2c798
Signed-off-by: Govind Singh <govinds@codeaurora.org>
Signed-off-by: Ashutosh Kumar <askuma@codeaurora.org>
This commit is contained in:
Govind Singh 2017-03-07 18:32:57 +05:30 committed by Rakesh Pillai
parent 39b5f76de0
commit 2e035860df
8 changed files with 269 additions and 3 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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_ */

View file

@ -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;
}