aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/dhd_wlfc.h
blob: 0eaaa0fa8c75f06d5beb78a0aa5feb6cc2e6fd08 (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
/*
* Copyright (C) 1999-2012, Broadcom Corporation
* 
*      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.
* 
*      Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
* $Id: dhd_wlfc.h 381116 2013-01-25 06:08:41Z $
*
*/
#ifndef __wlfc_host_driver_definitions_h__
#define __wlfc_host_driver_definitions_h__

/* 16 bits will provide an absolute max of 65536 slots */
#define WLFC_HANGER_MAXITEMS 1024

#define WLFC_HANGER_ITEM_STATE_FREE				1
#define WLFC_HANGER_ITEM_STATE_INUSE			2
#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED	3

#define WLFC_PKTID_HSLOT_MASK			0xffff /* allow 16 bits only */
#define WLFC_PKTID_HSLOT_SHIFT			8

/* x -> TXSTATUS TAG to/from firmware */
#define WLFC_PKTID_HSLOT_GET(x)			\
	(((x) >> WLFC_PKTID_HSLOT_SHIFT) & WLFC_PKTID_HSLOT_MASK)
#define WLFC_PKTID_HSLOT_SET(var, slot)	\
	((var) = ((var) & ~(WLFC_PKTID_HSLOT_MASK << WLFC_PKTID_HSLOT_SHIFT)) | \
	(((slot) & WLFC_PKTID_HSLOT_MASK) << WLFC_PKTID_HSLOT_SHIFT))

#define WLFC_PKTID_FREERUNCTR_MASK	0xff

#define WLFC_PKTID_FREERUNCTR_GET(x)	((x) & WLFC_PKTID_FREERUNCTR_MASK)
#define WLFC_PKTID_FREERUNCTR_SET(var, ctr)	\
	((var) = (((var) & ~WLFC_PKTID_FREERUNCTR_MASK) | \
	(((ctr) & WLFC_PKTID_FREERUNCTR_MASK))))

#define WLFC_PKTQ_PENQ(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec)))? \
	NULL : pktq_penq((pq), (prec), (p)))
#define WLFC_PKTQ_PENQ_HEAD(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec))) ? \
	NULL : pktq_penq_head((pq), (prec), (p)))

typedef enum ewlfc_packet_state {
	eWLFC_PKTTYPE_NEW,
	eWLFC_PKTTYPE_DELAYED,
	eWLFC_PKTTYPE_SUPPRESSED,
	eWLFC_PKTTYPE_MAX
} ewlfc_packet_state_t;

typedef enum ewlfc_mac_entry_action {
	eWLFC_MAC_ENTRY_ACTION_ADD,
	eWLFC_MAC_ENTRY_ACTION_DEL,
	eWLFC_MAC_ENTRY_ACTION_UPDATE,
	eWLFC_MAC_ENTRY_ACTION_MAX
} ewlfc_mac_entry_action_t;

typedef struct wlfc_hanger_item {
	uint8	state;
	uint8   gen;
	uint8	pad[2];
	uint32	identifier;
	void*	pkt;
#ifdef PROP_TXSTATUS_DEBUG
	uint32	push_time;
#endif
} wlfc_hanger_item_t;

typedef struct wlfc_hanger {
	int max_items;
	uint32 pushed;
	uint32 popped;
	uint32 failed_to_push;
	uint32 failed_to_pop;
	uint32 failed_slotfind;
	uint32 slot_pos;
	wlfc_hanger_item_t items[1];
} wlfc_hanger_t;

#define WLFC_HANGER_SIZE(n)	((sizeof(wlfc_hanger_t) - \
	sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t)))

#define WLFC_STATE_OPEN		1
#define WLFC_STATE_CLOSE	2

#define WLFC_PSQ_PREC_COUNT		((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */

#define WLFC_PSQ_LEN			2048

#define WLFC_FLOWCONTROL_HIWATER	(2048 - 256)
#define WLFC_FLOWCONTROL_LOWATER	256

typedef struct wlfc_mac_descriptor {
	uint8 occupied;
	uint8 interface_id;
	uint8 iftype;
	uint8 state;
	uint8 ac_bitmap; /* for APSD */
	uint8 requested_credit;
	uint8 requested_packet;
	uint8 ea[ETHER_ADDR_LEN];
	/*
	maintain (MAC,AC) based seq count for
	packets going to the device. As well as bc/mc.
	*/
	uint8 seq[AC_COUNT + 1];
	uint8 generation;
	struct pktq	psq;
	/* The AC pending bitmap that was reported to the fw at last change */
	uint8 traffic_lastreported_bmp;
	/* The new AC pending bitmap */
	uint8 traffic_pending_bmp;
	/* 1= send on next opportunity */
	uint8 send_tim_signal;
	uint8 mac_handle;
	/* Number of packets in transit for this entry. */
	uint transit_count;
	/* Numbe of suppression to wait before evict from delayQ */
	uint suppr_transit_count;
	/* Used when a new suppress is detected to track the number of
	 * packets getting suppressed
	 */
	uint suppress_count;
	/* flag. TRUE when in suppress state */
    uint8 suppressed;

#ifdef PROP_TXSTATUS_DEBUG
	uint32 dstncredit_sent_packets;
	uint32 dstncredit_acks;
	uint32 opened_ct;
	uint32 closed_ct;
#endif
} wlfc_mac_descriptor_t;

#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\
	entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0)

#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++
#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)]

typedef struct athost_wl_stat_counters {
	uint32	pktin;
	uint32	pkt2bus;
	uint32	pktdropped;
	uint32	tlv_parse_failed;
	uint32	rollback;
	uint32	rollback_failed;
	uint32	delayq_full_error;
	uint32	credit_request_failed;
	uint32	packet_request_failed;
	uint32	mac_update_failed;
	uint32	psmode_update_failed;
	uint32	interface_update_failed;
	uint32	wlfc_header_only_pkt;
	uint32	txstatus_in;
	uint32	d11_suppress;
	uint32	wl_suppress;
	uint32	bad_suppress;
	uint32	pkt_freed;
	uint32	pkt_free_err;
	uint32	psq_wlsup_retx;
	uint32	psq_wlsup_enq;
	uint32	psq_d11sup_retx;
	uint32	psq_d11sup_enq;
	uint32	psq_hostq_retx;
	uint32	psq_hostq_enq;
	uint32	mac_handle_notfound;
	uint32	wlc_tossed_pkts;
	uint32	dhd_hdrpulls;
	uint32	generic_error;
	/* an extra one for bc/mc traffic */
	uint32	send_pkts[AC_COUNT + 1];
#ifdef PROP_TXSTATUS_DEBUG
	/* all pkt2bus -> txstatus latency accumulated */
	uint32	latency_sample_count;
	uint32	total_status_latency;
	uint32	latency_most_recent;
	int		idx_delta;
	uint32	deltas[10];
	uint32	fifo_credits_sent[6];
	uint32	fifo_credits_back[6];
	uint32	dropped_qfull[6];
	uint32	signal_only_pkts_sent;
	uint32	signal_only_pkts_freed;
#endif
} athost_wl_stat_counters_t;

#ifdef PROP_TXSTATUS_DEBUG
#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \
	(ctx)->stats.fifo_credits_sent[(ac)]++;} while (0)
#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \
	(ctx)->stats.fifo_credits_back[(ac)]++;} while (0)
#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \
	(ctx)->stats.dropped_qfull[(ac)]++;} while (0)
#else
#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0)
#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0)
#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0)
#endif

#define WLFC_FCMODE_NONE				0
#define WLFC_FCMODE_IMPLIED_CREDIT		1
#define WLFC_FCMODE_EXPLICIT_CREDIT		2

/* How long to defer borrowing in milliseconds */
#define WLFC_BORROW_DEFER_PERIOD_MS 100

/* Mask to represent available ACs (note: BC/MC is ignored */
#define WLFC_AC_MASK 0xF

/* Mask to check for only on-going AC_BE traffic */
#define WLFC_AC_BE_TRAFFIC_ONLY 0xD

typedef struct athost_wl_status_info {
	uint8	last_seqid_to_wlc;

	/* OSL handle */
	osl_t*	osh;
	/* dhd pub */
	void*	dhdp;

	/* stats */
	athost_wl_stat_counters_t stats;

	/* the additional ones are for bc/mc and ATIM FIFO */
	int		FIFO_credit[AC_COUNT + 2];

	/* Credit borrow counts for each FIFO from each of the other FIFOs */
	int		credits_borrowed[AC_COUNT + 2][AC_COUNT + 2];

	/* packet hanger and MAC->handle lookup table */
	void*	hanger;
	struct {
		/* table for individual nodes */
		wlfc_mac_descriptor_t	nodes[WLFC_MAC_DESC_TABLE_SIZE];
		/* table for interfaces */
		wlfc_mac_descriptor_t	interfaces[WLFC_MAX_IFNUM];
		/* OS may send packets to unknown (unassociated) destinations */
		/* A place holder for bc/mc and packets to unknown destinations */
		wlfc_mac_descriptor_t	other;
	} destination_entries;
	/* token position for different priority packets */
	uint8   token_pos[AC_COUNT+1];
	/* ON/OFF state for flow control to the host network interface */
	uint8	hostif_flow_state[WLFC_MAX_IFNUM];
	uint8	host_ifidx;
	/* to flow control an OS interface */
	uint8	toggle_host_if;

	/*
	Mode in which the dhd flow control shall operate. Must be set before
	traffic starts to the device.
	0 - Do not do any proptxtstatus flow control
	1 - Use implied credit from a packet status
	2 - Use explicit credit
	*/
	uint8	proptxstatus_mode;

	/* To borrow credits */
	uint8   allow_credit_borrow;

	/* Timestamp to compute how long to defer borrowing for */
	uint32  borrow_defer_timestamp;

} athost_wl_status_info_t;

int dhd_wlfc_enable(dhd_pub_t *dhd);
int dhd_wlfc_interface_event(struct dhd_info *,
	ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea);
int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data);
int dhd_wlfc_event(struct dhd_info *dhd);
int dhd_os_wlfc_block(dhd_pub_t *pub);
int dhd_os_wlfc_unblock(dhd_pub_t *pub);

#endif /* __wlfc_host_driver_definitions_h__ */