/*
|
* DHD debugability packet logging header file
|
*
|
* Copyright (C) 2020, Broadcom.
|
*
|
* Unless you and Broadcom execute a separate written software license
|
* agreement governing use of this software, this software is licensed to you
|
* under the terms of the GNU General Public License version 2 (the "GPL"),
|
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
|
* following added to such license:
|
*
|
* As a special exception, the copyright holders of this software give you
|
* permission to link this software with independent modules, and to copy and
|
* distribute the resulting executable under terms of your choice, provided that
|
* you also meet, for each linked independent module, the terms and conditions of
|
* the license of that module. An independent module is a module which is not
|
* derived from this software. The special exception does not apply to any
|
* modifications of the software.
|
*
|
*
|
* <<Broadcom-WL-IPTag/Open:>>
|
*
|
* $Id$
|
*/
|
|
#ifndef __DHD_PKTLOG_H_
|
#define __DHD_PKTLOG_H_
|
|
#include <dhd_debug.h>
|
#include <dhd.h>
|
#include <asm/atomic.h>
|
#ifdef DHD_COMPACT_PKT_LOG
|
#include <linux/rbtree.h>
|
#endif /* DHD_COMPACT_PKT_LOG */
|
|
#ifdef DHD_PKT_LOGGING
|
#define DHD_PKT_LOG(args) DHD_INFO(args)
|
#define DEFAULT_MULTIPLE_PKTLOG_BUF 1
|
#ifndef CUSTOM_MULTIPLE_PKTLOG_BUF
|
#define CUSTOM_MULTIPLE_PKTLOG_BUF DEFAULT_MULTIPLE_PKTLOG_BUF
|
#endif /* CUSTOM_MULTIPLE_PKTLOG_BUF */
|
#define MIN_PKTLOG_LEN (32 * 10 * 2 * CUSTOM_MULTIPLE_PKTLOG_BUF)
|
#define MAX_PKTLOG_LEN (32 * 10 * 2 * 10)
|
#define MAX_DHD_PKTLOG_FILTER_LEN 14
|
#define MAX_MASK_PATTERN_FILTER_LEN 64
|
#define PKTLOG_TXPKT_CASE 0x0001
|
#define PKTLOG_TXSTATUS_CASE 0x0002
|
#define PKTLOG_RXPKT_CASE 0x0004
|
/* MAX_FILTER_PATTERN_LEN is buf len to print bitmask/pattern with string */
|
#define MAX_FILTER_PATTERN_LEN \
|
((MAX_MASK_PATTERN_FILTER_LEN * HD_BYTE_SIZE) + HD_PREFIX_SIZE + 1) * 2
|
#define PKTLOG_DUMP_BUF_SIZE (64 * 1024)
|
|
typedef struct dhd_dbg_pktlog_info {
|
frame_type payload_type;
|
size_t pkt_len;
|
uint32 driver_ts_sec;
|
uint32 driver_ts_usec;
|
uint32 firmware_ts;
|
uint32 pkt_hash;
|
bool direction;
|
void *pkt;
|
} dhd_dbg_pktlog_info_t;
|
|
typedef struct dhd_pktlog_ring_info
|
{
|
dll_t p_info; /* list pointer */
|
union {
|
wifi_tx_packet_fate tx_fate;
|
wifi_rx_packet_fate rx_fate;
|
uint32 fate;
|
};
|
dhd_dbg_pktlog_info_t info;
|
} dhd_pktlog_ring_info_t;
|
|
typedef struct dhd_pktlog_ring
|
{
|
dll_t ring_info_head; /* ring_info list */
|
dll_t ring_info_free; /* ring_info free list */
|
osl_atomic_t start;
|
uint32 pktlog_minmize;
|
uint32 pktlog_len; /* size of pkts */
|
uint32 pktcount;
|
spinlock_t *pktlog_ring_lock;
|
dhd_pub_t *dhdp;
|
dhd_pktlog_ring_info_t *ring_info_mem; /* ring_info mem pointer */
|
} dhd_pktlog_ring_t;
|
|
typedef struct dhd_pktlog_filter_info
|
{
|
uint32 id;
|
uint32 offset;
|
uint32 size_bytes; /* Size of pattern. */
|
uint32 enable;
|
uint8 mask[MAX_MASK_PATTERN_FILTER_LEN];
|
uint8 pattern[MAX_MASK_PATTERN_FILTER_LEN];
|
} dhd_pktlog_filter_info_t;
|
|
typedef struct dhd_pktlog_filter
|
{
|
dhd_pktlog_filter_info_t *info;
|
uint32 list_cnt;
|
uint32 enable;
|
} dhd_pktlog_filter_t;
|
|
typedef struct dhd_pktlog
|
{
|
struct dhd_pktlog_ring *pktlog_ring;
|
struct dhd_pktlog_filter *pktlog_filter;
|
osl_atomic_t pktlog_status;
|
dhd_pub_t *dhdp;
|
#ifdef DHD_COMPACT_PKT_LOG
|
struct rb_root cpkt_log_tt_rbt;
|
#endif /* DHD_COMPACT_PKT_LOG */
|
} dhd_pktlog_t;
|
|
typedef struct dhd_pktlog_pcap_hdr
|
{
|
uint32 magic_number;
|
uint16 version_major;
|
uint16 version_minor;
|
uint16 thiszone;
|
uint32 sigfigs;
|
uint32 snaplen;
|
uint32 network;
|
} dhd_pktlog_pcap_hdr_t;
|
|
#define PKTLOG_PCAP_MAGIC_NUM 0xa1b2c3d4
|
#define PKTLOG_PCAP_MAJOR_VER 0x02
|
#define PKTLOG_PCAP_MINOR_VER 0x04
|
#define PKTLOG_PCAP_SNAP_LEN 0x40000
|
#define PKTLOG_PCAP_NETWORK_TYPE 147
|
|
extern int dhd_os_attach_pktlog(dhd_pub_t *dhdp);
|
extern int dhd_os_detach_pktlog(dhd_pub_t *dhdp);
|
extern dhd_pktlog_ring_t* dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size);
|
extern int dhd_pktlog_ring_deinit(dhd_pub_t *dhdp, dhd_pktlog_ring_t *ring);
|
extern int dhd_pktlog_ring_set_nextpos(dhd_pktlog_ring_t *ringbuf);
|
extern int dhd_pktlog_ring_get_nextbuf(dhd_pktlog_ring_t *ringbuf, void **data);
|
extern int dhd_pktlog_ring_set_prevpos(dhd_pktlog_ring_t *ringbuf);
|
extern int dhd_pktlog_ring_get_prevbuf(dhd_pktlog_ring_t *ringbuf, void **data);
|
extern int dhd_pktlog_ring_get_writebuf(dhd_pktlog_ring_t *ringbuf, void **data);
|
extern int dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid,
|
uint32 direction);
|
extern int dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid,
|
uint16 status);
|
extern dhd_pktlog_ring_t* dhd_pktlog_ring_change_size(dhd_pktlog_ring_t *ringbuf, int size);
|
extern void dhd_pktlog_filter_pull_forward(dhd_pktlog_filter_t *filter,
|
uint32 del_filter_id, uint32 list_cnt);
|
|
#define PKT_RX 0
|
#define PKT_TX 1
|
#define PKT_WAKERX 2
|
#define DHD_INVALID_PKTID (0U)
|
#define PKTLOG_TRANS_TX 0x01
|
#define PKTLOG_TRANS_RX 0x02
|
#define PKTLOG_TRANS_TXS 0x04
|
|
#define PKTLOG_SET_IN_TX(dhdp) \
|
{ \
|
do { \
|
OSL_ATOMIC_OR((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, PKTLOG_TRANS_TX); \
|
} while (0); \
|
}
|
|
#define PKTLOG_SET_IN_RX(dhdp) \
|
{ \
|
do { \
|
OSL_ATOMIC_OR((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, PKTLOG_TRANS_RX); \
|
} while (0); \
|
}
|
|
#define PKTLOG_SET_IN_TXS(dhdp) \
|
{ \
|
do { \
|
OSL_ATOMIC_OR((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, PKTLOG_TRANS_TXS); \
|
} while (0); \
|
}
|
|
#define PKTLOG_CLEAR_IN_TX(dhdp) \
|
{ \
|
do { \
|
OSL_ATOMIC_AND((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, ~PKTLOG_TRANS_TX); \
|
} while (0); \
|
}
|
|
#define PKTLOG_CLEAR_IN_RX(dhdp) \
|
{ \
|
do { \
|
OSL_ATOMIC_AND((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, ~PKTLOG_TRANS_RX); \
|
} while (0); \
|
}
|
|
#define PKTLOG_CLEAR_IN_TXS(dhdp) \
|
{ \
|
do { \
|
OSL_ATOMIC_AND((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, ~PKTLOG_TRANS_TXS); \
|
} while (0); \
|
}
|
|
#define DHD_PKTLOG_TX(dhdp, pkt, pktdata, pktid) \
|
{ \
|
do { \
|
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
|
PKTLOG_SET_IN_TX(dhdp); \
|
if ((dhdp)->pktlog->pktlog_ring && \
|
OSL_ATOMIC_READ((dhdp)->osh, \
|
(&(dhdp)->pktlog->pktlog_ring->start))) { \
|
dhd_pktlog_ring_add_pkts(dhdp, pkt, pktdata, pktid, PKT_TX); \
|
} \
|
PKTLOG_CLEAR_IN_TX(dhdp); \
|
} \
|
} while (0); \
|
}
|
|
#define DHD_PKTLOG_TXS(dhdp, pkt, pktdata, pktid, status) \
|
{ \
|
do { \
|
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
|
PKTLOG_SET_IN_TXS(dhdp); \
|
if ((dhdp)->pktlog->pktlog_ring && \
|
OSL_ATOMIC_READ((dhdp)->osh, \
|
(&(dhdp)->pktlog->pktlog_ring->start))) { \
|
dhd_pktlog_ring_tx_status(dhdp, pkt, pktdata, pktid, status); \
|
} \
|
PKTLOG_CLEAR_IN_TXS(dhdp); \
|
} \
|
} while (0); \
|
}
|
|
#define DHD_PKTLOG_RX(dhdp, pkt, pktdata) \
|
{ \
|
do { \
|
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
|
PKTLOG_SET_IN_RX(dhdp); \
|
if (ntoh16((pkt)->protocol) != ETHER_TYPE_BRCM) { \
|
if ((dhdp)->pktlog->pktlog_ring && \
|
OSL_ATOMIC_READ((dhdp)->osh, \
|
(&(dhdp)->pktlog->pktlog_ring->start))) { \
|
dhd_pktlog_ring_add_pkts(dhdp, pkt, pktdata, \
|
DHD_INVALID_PKTID, PKT_RX); \
|
} \
|
} \
|
PKTLOG_CLEAR_IN_RX(dhdp); \
|
} \
|
} while (0); \
|
}
|
|
#define DHD_PKTLOG_WAKERX(dhdp, pkt, pktdata) \
|
{ \
|
do { \
|
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
|
PKTLOG_SET_IN_RX(dhdp); \
|
if (ntoh16((pkt)->protocol) != ETHER_TYPE_BRCM) { \
|
if ((dhdp)->pktlog->pktlog_ring && \
|
OSL_ATOMIC_READ((dhdp)->osh, \
|
(&(dhdp)->pktlog->pktlog_ring->start))) { \
|
dhd_pktlog_ring_add_pkts(dhdp, pkt, pktdata, \
|
DHD_INVALID_PKTID, PKT_WAKERX); \
|
} \
|
} \
|
PKTLOG_CLEAR_IN_RX(dhdp); \
|
} \
|
} while (0); \
|
}
|
|
extern dhd_pktlog_filter_t* dhd_pktlog_filter_init(int size);
|
extern int dhd_pktlog_filter_deinit(dhd_pktlog_filter_t *filter);
|
extern int dhd_pktlog_filter_add(dhd_pktlog_filter_t *filter, char *arg);
|
extern int dhd_pktlog_filter_del(dhd_pktlog_filter_t *filter, char *arg);
|
extern int dhd_pktlog_filter_enable(dhd_pktlog_filter_t *filter, uint32 pktlog_case, uint32 enable);
|
extern int dhd_pktlog_filter_pattern_enable(dhd_pktlog_filter_t *filter, char *arg, uint32 enable);
|
extern int dhd_pktlog_filter_info(dhd_pktlog_filter_t *filter);
|
extern bool dhd_pktlog_filter_matched(dhd_pktlog_filter_t *filter, char *data, uint32 pktlog_case);
|
extern bool dhd_pktlog_filter_existed(dhd_pktlog_filter_t *filter, char *arg, uint32 *id);
|
|
#define DHD_PKTLOG_FILTER_ADD(pattern, filter_pattern, dhdp) \
|
{ \
|
do { \
|
if ((strlen(pattern) + 1) < sizeof(filter_pattern)) { \
|
strncpy(filter_pattern, pattern, sizeof(filter_pattern)); \
|
dhd_pktlog_filter_add(dhdp->pktlog->pktlog_filter, filter_pattern); \
|
} \
|
} while (0); \
|
}
|
|
#define DHD_PKTLOG_DUMP_PATH DHD_COMMON_DUMP_PATH
|
extern int dhd_pktlog_debug_dump(dhd_pub_t *dhdp);
|
extern void dhd_pktlog_dump(void *handle, void *event_info, u8 event);
|
extern void dhd_schedule_pktlog_dump(dhd_pub_t *dhdp);
|
extern int dhd_pktlog_dump_write_memory(dhd_pub_t *dhdp, const void *user_buf, uint32 size);
|
extern int dhd_pktlog_dump_write_file(dhd_pub_t *dhdp);
|
|
#define DHD_PKTLOG_FATE_INFO_STR_LEN 256
|
#define DHD_PKTLOG_FATE_INFO_FORMAT "BRCM_Packet_Fate"
|
#define DHD_PKTLOG_DUMP_TYPE "pktlog_dump"
|
#define DHD_PKTLOG_DEBUG_DUMP_TYPE "pktlog_debug_dump"
|
|
extern void dhd_pktlog_get_filename(dhd_pub_t *dhdp, char *dump_path, int len);
|
extern uint32 dhd_pktlog_get_item_length(dhd_pktlog_ring_info_t *report_ptr);
|
extern uint32 dhd_pktlog_get_dump_length(dhd_pub_t *dhdp);
|
extern uint32 __dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid);
|
|
#ifdef DHD_COMPACT_PKT_LOG
|
#define CPKT_LOG_BIT_SIZE 22
|
#define CPKT_LOG_MAX_NUM 80
|
extern int dhd_cpkt_log_proc(dhd_pub_t *dhdp, char *buf, int buf_len,
|
int bit_offset, int req_pkt_num);
|
#endif /* DHD_COMPACT_PKT_LOG */
|
#endif /* DHD_PKT_LOGGING */
|
#endif /* __DHD_PKTLOG_H_ */
|