summaryrefslogtreecommitdiff
path: root/dhd_pktlog.h
blob: f4f9f26681f665db39a36e15f108d807762093cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/*
 * DHD debugability packet logging header file
 *
 * Copyright (C) 2022, 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;
	uint32 tx_status_ts_sec;
	uint32 tx_status_ts_usec;
	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 */
#ifdef DHD_PKT_LOGGING_DBGRING
	void *dbg_ring;
#endif /* DHD_PKT_LOGGING_DBGRING */
} 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 */
#ifdef DHD_PKT_LOGGING_DBGRING
	osl_atomic_t enable; /* logging suspend/resume */
#endif /* DHD_PKT_LOGGING_DBGRING */
} 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);
#ifdef DHD_PKT_LOGGING_DBGRING
extern int dhd_pktlog_is_enabled(dhd_pub_t *dhdp);
extern void dhd_pktlog_suspend(dhd_pub_t *dhdp);
extern void dhd_pktlog_resume(dhd_pub_t *dhdp);
extern int dhd_pktlog_ring_reinit(dhd_pub_t *dhdp);
#endif /* DHD_PKT_LOGGING_DBGRING */
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 int 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_ */