--- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -34,3 +34,12 @@ config ATH11K_TRACING depends on ATH11K && EVENT_TRACING ---help--- Select this to use ath11k tracing infrastructure. + +config ATH11K_PKTLOG + bool "ath11k packet logging support" + depends on ATH11K_DEBUGFS + ---help--- + Say Y to dump frame information during frame transmission + and reception, rate information and ani state. The packet + log uses ring buffer to dump the data. The buffer size, + frame filters can be alterted by debugfs entries. --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -21,6 +21,7 @@ ath11k-$(CPTCFG_ATH11K_DEBUGFS) += debug ath11k-$(CPTCFG_NL80211_TESTMODE) += testmode.o ath11k-$(CPTCFG_ATH11K_TRACING) += trace.o ath11k-$(CONFIG_THERMAL) += thermal.o +ath11k-$(CPTCFG_ATH11K_PKTLOG) += pktlog.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -12,6 +12,7 @@ #include #include "qmi.h" #include "htc.h" +#include "pktlog.h" #include "wmi.h" #include "hal.h" #include "dp.h" @@ -392,6 +393,11 @@ struct ath11k_debug { u32 pktlog_mode; u32 pktlog_peer_valid; u8 pktlog_peer_addr[ETH_ALEN]; +#ifdef CPTCFG_ATH11K_PKTLOG + struct dentry *debugfs_pktlog; + struct ath_pktlog pktlog; + bool is_pkt_logging; +#endif u32 rx_filter; }; --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -11,6 +11,7 @@ #include "dp_tx.h" #include "debug_htt_stats.h" #include "peer.h" +#include "pktlog.h" void ath11k_info(struct ath11k_base *ab, const char *fmt, ...) { @@ -1051,6 +1052,7 @@ int ath11k_debug_register(struct ath11k ath11k_debug_htt_stats_init(ar); ath11k_debug_fw_stats_init(ar); + ath11k_init_pktlog(ar); debugfs_create_file("ext_tx_stats", 0644, ar->debug.debugfs_pdev, ar, @@ -1076,5 +1078,6 @@ int ath11k_debug_register(struct ath11k void ath11k_debug_unregister(struct ath11k *ar) { + ath11k_deinit_pktlog(ar); } #endif /* CPTCFG_ATH11K_DEBUGFS */ --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -301,4 +301,39 @@ do { \ __ath11k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \ } while (0) + +#ifdef CPTCFG_ATH11K_PKTLOG +void ath11k_init_pktlog(struct ath11k *ar); +void ath11k_deinit_pktlog(struct ath11k *ar); +void ath11k_htt_pktlog_process(struct ath11k *ar, u8 *data); +void ath11k_htt_ppdu_pktlog_process(struct ath11k *ar, u8 *data, u32 len); +void ath11k_rx_stats_buf_pktlog_process(struct ath11k *ar, u8 *data, u16 log_type, u32 len); + +#else /* CPTCFG_ATH11K_PKTLOG */ +static inline void ath11k_init_pktlog(struct ath11k *ar) +{ +} + +static inline void ath11k_deinit_pktlog(struct ath11k *ar) +{ +} + +static inline void ath11k_htt_pktlog_process(struct ath11k *ar, + u8 *data) +{ +} + +static inline void ath11k_htt_ppdu_pktlog_process(struct ath11k *ar, + u8 *data, u32 len) +{ +} + +static inline void ath11k_pktlog_rx(struct ath11k *ar, struct sk_buff_head *amsdu) +{ +} +static inline void ath11k_rx_stats_buf_pktlog_process(struct ath11k *ar, + u8 *data, u16 log_type, u32 len) +{ +} +#endif /* CONFIG_ATH11K_PKTLOG */ #endif /* _ATH11K_DEBUG_H_ */ --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1453,8 +1453,10 @@ static int ath11k_htt_pull_ppdu_stats(st goto exit; } - if (ath11k_debug_is_pktlog_lite_mode_enabled(ar)) + if (ath11k_debug_is_pktlog_lite_mode_enabled(ar)) { trace_ath11k_htt_ppdu_stats(ar, skb->data, len); + ath11k_htt_ppdu_pktlog_process(ar, (u8 *)skb->data, DP_RX_BUFFER_SIZE); + } ppdu_info = ath11k_dp_htt_get_ppdu_desc(ar, ppdu_id); if (!ppdu_info) { @@ -1493,6 +1495,7 @@ static void ath11k_htt_pktlog(struct ath trace_ath11k_htt_pktlog(ar, data->payload, hdr->size, ar->ab->pktlog_defs_checksum); + ath11k_htt_pktlog_process(ar, (u8 *)data->payload); } static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, @@ -2792,8 +2795,11 @@ int ath11k_dp_rx_process_mon_status(stru memset(&ppdu_info, 0, sizeof(ppdu_info)); ppdu_info.peer_id = HAL_INVALID_PEERID; - if (ath11k_debug_is_pktlog_rx_stats_enabled(ar)) + if (ath11k_debug_is_pktlog_rx_stats_enabled(ar)) { trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); + ath11k_rx_stats_buf_pktlog_process(ar, skb->data, + DP_RX_BUFFER_SIZE); + } hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb); @@ -2820,8 +2826,11 @@ int ath11k_dp_rx_process_mon_status(stru arsta = (struct ath11k_sta *)peer->sta->drv_priv; ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info); - if (ath11k_debug_is_pktlog_peer_valid(ar, peer->addr)) + if (ath11k_debug_is_pktlog_peer_valid(ar, peer->addr)) { trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); + ath11k_rx_stats_buf_pktlog_process(ar, skb->data, + DP_RX_BUFFER_SIZE); + } spin_unlock_bh(&ab->base_lock); rcu_read_unlock(); --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/pktlog.c @@ -0,0 +1,537 @@ + +#include +#include +#include +#include "core.h" +#include "wmi.h" +#include "debug.h" + +static struct page *pktlog_virt_to_logical(void *addr) +{ + struct page *page; + unsigned long vpage = 0UL; + + page = vmalloc_to_page(addr); + if (page) { + vpage = (unsigned long)page_address(page); + vpage |= ((unsigned long)addr & (PAGE_SIZE - 1)); + } + return virt_to_page((void *)vpage); +} + +static void ath_pktlog_release(struct ath_pktlog *pktlog) +{ + unsigned long page_cnt, vaddr; + struct page *page; + + page_cnt = + ((sizeof(*pktlog->buf) + + pktlog->buf_size) / PAGE_SIZE) + 1; + + for (vaddr = (unsigned long)(pktlog->buf); vaddr < + (unsigned long)(pktlog->buf) + + (page_cnt * PAGE_SIZE); + vaddr += PAGE_SIZE) { + page = pktlog_virt_to_logical((void *)vaddr); + clear_bit(PG_reserved, &page->flags); + } + + vfree(pktlog->buf); + pktlog->buf = NULL; +} + +static int ath_alloc_pktlog_buf(struct ath11k *ar) +{ + u32 page_cnt; + unsigned long vaddr; + struct page *page; + struct ath_pktlog *pktlog = &ar->debug.pktlog; + + if (pktlog->buf_size == 0) + return -EINVAL; + + page_cnt = (sizeof(*pktlog->buf) + + pktlog->buf_size) / PAGE_SIZE; + + pktlog->buf = vmalloc((page_cnt + 2) * PAGE_SIZE); + if (!pktlog->buf) + return -ENOMEM; + + pktlog->buf = (struct ath_pktlog_buf *) + (((unsigned long) + (pktlog->buf) + + PAGE_SIZE - 1) & PAGE_MASK); + + for (vaddr = (unsigned long)(pktlog->buf); + vaddr < ((unsigned long)(pktlog->buf) + + (page_cnt * PAGE_SIZE)); vaddr += PAGE_SIZE) { + page = pktlog_virt_to_logical((void *)vaddr); + set_bit(PG_reserved, &page->flags); + } + + return 0; +} + +static void ath_init_pktlog_buf(struct ath11k *ar, struct ath_pktlog *pktlog) +{ + if (!ar->ab->pktlog_defs_checksum) { + pktlog->buf->bufhdr.magic_num = PKTLOG_MAGIC_NUM; + pktlog->buf->bufhdr.version = CUR_PKTLOG_VER; + } else { + pktlog->buf->bufhdr.magic_num = PKTLOG_NEW_MAGIC_NUM; + pktlog->buf->bufhdr.version = ar->ab->pktlog_defs_checksum; + } + pktlog->buf->rd_offset = -1; + pktlog->buf->wr_offset = 0; +} + +static inline void ath_pktlog_mov_rd_idx(struct ath_pktlog *pl_info, + int32_t *rd_offset) +{ + int32_t boundary; + struct ath_pktlog_buf *log_buf = pl_info->buf; + struct ath_pktlog_hdr *log_hdr; + + log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + *rd_offset); + boundary = *rd_offset; + boundary += pl_info->hdr_size; + boundary += log_hdr->size; + + if (boundary <= pl_info->buf_size) + *rd_offset = boundary; + else + *rd_offset = log_hdr->size; + + if ((pl_info->buf_size - *rd_offset) < pl_info->hdr_size) + *rd_offset = 0; +} + +static char *ath_pktlog_getbuf(struct ath_pktlog *pl_info, + struct ath_pktlog_hdr_arg *hdr_arg) +{ + struct ath_pktlog_buf *log_buf; + int32_t cur_wr_offset, buf_size; + char *log_ptr; + + log_buf = pl_info->buf; + buf_size = pl_info->buf_size; + + spin_lock_bh(&pl_info->lock); + cur_wr_offset = log_buf->wr_offset; + /* Move read offset to the next entry if there is a buffer overlap */ + if (log_buf->rd_offset >= 0) { + if ((cur_wr_offset <= log_buf->rd_offset) && + (cur_wr_offset + pl_info->hdr_size) > + log_buf->rd_offset) + ath_pktlog_mov_rd_idx(pl_info, &log_buf->rd_offset); + } else { + log_buf->rd_offset = cur_wr_offset; + } + + memcpy(&log_buf->log_data[cur_wr_offset], + hdr_arg->pktlog_hdr, pl_info->hdr_size); + + cur_wr_offset += pl_info->hdr_size; + + if ((buf_size - cur_wr_offset) < hdr_arg->payload_size) { + while ((cur_wr_offset <= log_buf->rd_offset) && + (log_buf->rd_offset < buf_size)) + ath_pktlog_mov_rd_idx(pl_info, &log_buf->rd_offset); + cur_wr_offset = 0; + } + + while ((cur_wr_offset <= log_buf->rd_offset) && + ((cur_wr_offset + hdr_arg->payload_size) > log_buf->rd_offset)) + ath_pktlog_mov_rd_idx(pl_info, &log_buf->rd_offset); + + log_ptr = &log_buf->log_data[cur_wr_offset]; + cur_wr_offset += hdr_arg->payload_size; + + log_buf->wr_offset = + ((buf_size - cur_wr_offset) >= + pl_info->hdr_size) ? cur_wr_offset : 0; + spin_unlock_bh(&pl_info->lock); + + return log_ptr; +} + +static int pktlog_pgfault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + unsigned long address = (unsigned long)vmf->virtual_address; + + if (address == 0UL) + return VM_FAULT_NOPAGE; + + if (vmf->pgoff > vma->vm_end) + return VM_FAULT_SIGBUS; + + get_page(virt_to_page(address)); + vmf->page = virt_to_page(address); + return VM_FAULT_MINOR; +} + +static struct vm_operations_struct pktlog_vmops = { + .fault = pktlog_pgfault +}; + +static int ath_pktlog_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ath11k *ar = file->private_data; + + /* entire buffer should be mapped */ + if (vma->vm_pgoff != 0) + return -EINVAL; + + if (!ar->debug.pktlog.buf) { + pr_err("Can't allocate pktlog buf\n"); + return -ENOMEM; + } + + vma->vm_flags |= VM_LOCKED; + vma->vm_ops = &pktlog_vmops; + + return 0; +} + +static ssize_t ath_pktlog_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + size_t bufhdr_size; + size_t nbytes = 0, ret_val = 0; + int rem_len; + int start_offset, end_offset; + int fold_offset, ppos_data, cur_rd_offset; + struct ath11k *ar = file->private_data; + struct ath_pktlog *info = &ar->debug.pktlog; + struct ath_pktlog_buf *log_buf = info->buf; + + if (log_buf == NULL) + return 0; + + bufhdr_size = sizeof(log_buf->bufhdr); + + /* copy valid log entries from circular buffer into user space */ + rem_len = count; + + nbytes = 0; + + if (*ppos < bufhdr_size) { + nbytes = min((int)(bufhdr_size - *ppos), rem_len); + if (copy_to_user(userbuf, + ((char *)&log_buf->bufhdr) + *ppos, nbytes)) + return -EFAULT; + rem_len -= nbytes; + ret_val += nbytes; + } + + spin_lock_bh(&info->lock); + + start_offset = log_buf->rd_offset; + + if ((rem_len == 0) || (start_offset < 0)) + goto read_done; + + fold_offset = -1; + cur_rd_offset = start_offset; + + /* Find the last offset and fold-offset if the buffer is folded */ + do { + int log_data_offset; + struct ath_pktlog_hdr *log_hdr; + + log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + cur_rd_offset); + log_data_offset = cur_rd_offset + info->hdr_size; + + if ((fold_offset == -1) && + ((info->buf_size - log_data_offset) <= log_hdr->size)) + fold_offset = log_data_offset - 1; + + ath_pktlog_mov_rd_idx(info, &cur_rd_offset); + + if ((fold_offset == -1) && (cur_rd_offset == 0) && + (cur_rd_offset != log_buf->wr_offset)) + fold_offset = log_data_offset + log_hdr->size - 1; + + end_offset = log_data_offset + log_hdr->size - 1; + + } while (cur_rd_offset != log_buf->wr_offset); + + ppos_data = *ppos + ret_val - bufhdr_size + start_offset; + + if (fold_offset == -1) { + if (ppos_data > end_offset) + goto read_done; + + nbytes = min(rem_len, end_offset - ppos_data + 1); + if (copy_to_user(userbuf + ret_val, + log_buf->log_data + ppos_data, nbytes)) { + ret_val = -EFAULT; + goto out; + } + ret_val += nbytes; + rem_len -= nbytes; + } else { + if (ppos_data <= fold_offset) { + nbytes = min(rem_len, fold_offset - ppos_data + 1); + if (copy_to_user(userbuf + ret_val, + log_buf->log_data + ppos_data, nbytes)) { + ret_val = -EFAULT; + goto out; + } + ret_val += nbytes; + rem_len -= nbytes; + } + + if (rem_len == 0) + goto read_done; + + ppos_data = + *ppos + ret_val - (bufhdr_size + + (fold_offset - start_offset + 1)); + + if (ppos_data <= end_offset) { + nbytes = min(rem_len, end_offset - ppos_data + 1); + if (copy_to_user(userbuf + ret_val, log_buf->log_data + + ppos_data, + nbytes)) { + ret_val = -EFAULT; + goto out; + } + ret_val += nbytes; + rem_len -= nbytes; + } + } + +read_done: + *ppos += ret_val; +out: + spin_unlock_bh(&info->lock); + return ret_val; +} + +static const struct file_operations fops_pktlog_dump = { + .read = ath_pktlog_read, + .mmap = ath_pktlog_mmap, + .open = simple_open +}; + +static ssize_t write_pktlog_start(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + struct ath_pktlog *pktlog = &ar->debug.pktlog; + u32 start_pktlog; + int err; + + err = kstrtou32_from_user(ubuf, count, 0, &start_pktlog); + if (err) + return err; + + if (ar->debug.is_pkt_logging && start_pktlog) { + pr_err("packet logging is inprogress\n"); + return -EINVAL; + } + if (start_pktlog) { + if (pktlog->buf != NULL) + ath_pktlog_release(pktlog); + + err = ath_alloc_pktlog_buf(ar); + if (err != 0) + return err; + + ath_init_pktlog_buf(ar, pktlog); + ar->debug.is_pkt_logging = 1; + } else { + ar->debug.is_pkt_logging = 0; + } + + return count; +} + +static ssize_t read_pktlog_start(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char buf[32]; + struct ath11k *ar = file->private_data; + int len = 0; + + len = scnprintf(buf, sizeof(buf) - len, "%d\n", + ar->debug.is_pkt_logging); + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static const struct file_operations fops_pktlog_start = { + .read = read_pktlog_start, + .write = write_pktlog_start, + .open = simple_open +}; + +static ssize_t pktlog_size_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + u32 pktlog_size; + + if (kstrtou32_from_user(ubuf, count, 0, &pktlog_size)) + return -EINVAL; + + if (pktlog_size == ar->debug.pktlog.buf_size) + return count; + + if (ar->debug.is_pkt_logging) { + pr_debug("Stop packet logging before changing the size\n"); + return -EINVAL; + } + + ar->debug.pktlog.buf_size = pktlog_size; + + return count; +} + +static ssize_t pktlog_size_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char buf[32]; + struct ath11k *ar = file->private_data; + int len = 0; + + len = scnprintf(buf, sizeof(buf) - len, "%uL\n", + ar->debug.pktlog.buf_size); + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static const struct file_operations fops_pktlog_size = { + .read = pktlog_size_read, + .write = pktlog_size_write, + .open = simple_open +}; + +static void ath_pktlog_init(struct ath11k *ar) +{ + struct ath_pktlog *pktlog = &ar->debug.pktlog; + + spin_lock_init(&pktlog->lock); + pktlog->buf_size = ATH_DEBUGFS_PKTLOG_SIZE_DEFAULT; + pktlog->buf = NULL; + + pktlog->hdr_size = sizeof(struct ath_pktlog_hdr); + pktlog->hdr_size_field_offset = + offsetof(struct ath_pktlog_hdr, size); +} + +void ath11k_init_pktlog(struct ath11k *ar) +{ + ar->debug.debugfs_pktlog = debugfs_create_dir("pktlog", + ar->debug.debugfs_pdev); + debugfs_create_file("start", S_IRUGO | S_IWUSR, + ar->debug.debugfs_pktlog, ar, &fops_pktlog_start); + debugfs_create_file("size", S_IRUGO | S_IWUSR, + ar->debug.debugfs_pktlog, ar, &fops_pktlog_size); + debugfs_create_file("dump", S_IRUGO | S_IWUSR, + ar->debug.debugfs_pktlog, ar, &fops_pktlog_dump); + ath_pktlog_init(ar); +} + +void ath11k_deinit_pktlog(struct ath11k *ar) +{ + struct ath_pktlog *pktlog = &ar->debug.pktlog; + + if (pktlog->buf != NULL) + ath_pktlog_release(pktlog); +} + +static int ath_pktlog_pull_hdr(struct ath_pktlog_hdr_arg *arg, + u8 *data) +{ + struct ath_pktlog_hdr *hdr = (struct ath_pktlog_hdr *)data; + + hdr->flags = __le16_to_cpu(hdr->flags); + hdr->missed_cnt = __le16_to_cpu(hdr->missed_cnt); + hdr->log_type = __le16_to_cpu(hdr->log_type); + hdr->size = __le16_to_cpu(hdr->size); + hdr->timestamp = __le32_to_cpu(hdr->timestamp); + hdr->type_specific_data = __le32_to_cpu(hdr->type_specific_data); + + arg->log_type = hdr->log_type; + arg->payload = hdr->payload; + arg->payload_size = hdr->size; + arg->pktlog_hdr = data; + + return 0; +} + +static void ath_pktlog_write_buf(struct ath_pktlog *pl_info, + struct ath_pktlog_hdr_arg *hdr_arg) +{ + char *log_data; + + log_data = ath_pktlog_getbuf(pl_info, hdr_arg); + if (!log_data) + return; + + memcpy(log_data, hdr_arg->payload, hdr_arg->payload_size); +} + +void ath11k_htt_pktlog_process(struct ath11k *ar, u8 *data) +{ + struct ath_pktlog *pl_info = &ar->debug.pktlog; + struct ath_pktlog_hdr_arg hdr_arg; + int ret; + + if (!ar->debug.is_pkt_logging) + return; + + ret = ath_pktlog_pull_hdr(&hdr_arg, data); + if (ret) + return; + + ath_pktlog_write_buf(pl_info, &hdr_arg); +} + +void ath11k_htt_ppdu_pktlog_process(struct ath11k *ar, u8 *data, u32 len) +{ + struct ath_pktlog *pl_info = &ar->debug.pktlog; + struct ath_pktlog_hdr hdr; + struct ath_pktlog_hdr_arg hdr_arg; + + if (!ar->debug.is_pkt_logging) + return; + + hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S); + hdr.missed_cnt = 0; + hdr.log_type = ATH11K_PKTLOG_TYPE_PPDU_STATS; + hdr.timestamp = 0; + hdr.size = len; + hdr.type_specific_data = 0; + + hdr_arg.log_type = hdr.log_type; + hdr_arg.payload_size = hdr.size; + hdr_arg.payload = (u8 *)data; + hdr_arg.pktlog_hdr = (u8 *)&hdr; + + ath_pktlog_write_buf(pl_info, &hdr_arg); +} + +void ath11k_rx_stats_buf_pktlog_process(struct ath11k *ar, u8 *data, u16 log_type, u32 len) +{ + struct ath_pktlog *pl_info = &ar->debug.pktlog; + struct ath_pktlog_hdr hdr; + struct ath_pktlog_hdr_arg hdr_arg; + + if (!ar->debug.is_pkt_logging) + return; + + hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S); + hdr.missed_cnt = 0; + hdr.log_type = log_type; + hdr.timestamp = 0; + hdr.size = len; + hdr.type_specific_data = 0; + + hdr_arg.log_type = log_type; + hdr_arg.payload_size = len; + hdr_arg.payload = data; + hdr_arg.pktlog_hdr = (u8 *)&hdr; + + ath_pktlog_write_buf(pl_info, &hdr_arg); +} --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/pktlog.h @@ -0,0 +1,56 @@ +#ifndef _PKTLOG_H_ +#define _PKTLOG_H_ + +#ifdef CPTCFG_ATH11K_PKTLOG +#define CUR_PKTLOG_VER 10010 /* Packet log version */ +#define PKTLOG_MAGIC_NUM 7735225 +#define PKTLOG_NEW_MAGIC_NUM 2453506 + +/* Masks for setting pktlog events filters */ +#define ATH_PKTLOG_RX 0x000000001 +#define ATH_PKTLOG_TX 0x000000002 +#define ATH_PKTLOG_RCFIND 0x000000004 +#define ATH_PKTLOG_RCUPDATE 0x000000008 + +#define ATH_DEBUGFS_PKTLOG_SIZE_DEFAULT (8 * 1024 * 1024) +#define ATH_PKTLOG_FILTER_DEFAULT (ATH_PKTLOG_TX | ATH_PKTLOG_RX | \ + ATH_PKTLOG_RCFIND | ATH_PKTLOG_RCUPDATE) + +enum { + PKTLOG_FLG_FRM_TYPE_LOCAL_S = 0, + PKTLOG_FLG_FRM_TYPE_REMOTE_S, + PKTLOG_FLG_FRM_TYPE_CLONE_S, + PKTLOG_FLG_FRM_TYPE_UNKNOWN_S +}; + +struct ath_pktlog_hdr_arg { + u16 log_type; + u8 *payload; + u16 payload_size; + u8 *pktlog_hdr; +}; + +struct ath_pktlog_bufhdr { + u32 magic_num; /* Used by post processing scripts */ + u32 version; /* Set to CUR_PKTLOG_VER */ +}; + +struct ath_pktlog_buf { + struct ath_pktlog_bufhdr bufhdr; + int rd_offset; + int wr_offset; + char log_data[0]; +}; + +struct ath_pktlog { + struct ath_pktlog_buf *buf; + u32 filter; + u32 buf_size; /* Size of buffer in bytes */ + spinlock_t lock; + u8 hdr_size; + u8 hdr_size_field_offset; +}; + +#endif /* CONFIG_ATH10K_PKTLOG */ + +#endif /* _PKTLOG_H_ */ --- a/local-symbols +++ b/local-symbols @@ -135,3 +135,4 @@ ATH11K= ATH11K_DEBUG= ATH11K_DEBUGFS= ATH11K_TRACING= +ATH11K_PKTLOG=