fwsignal.c revision 5491c11c67f2c83c95fa9a26172bc1994580aed7
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#include <linux/types.h>
17#include <linux/module.h>
18#include <linux/if_ether.h>
19#include <linux/spinlock.h>
20#include <linux/skbuff.h>
21#include <linux/netdevice.h>
22#include <linux/etherdevice.h>
23#include <linux/err.h>
24#include <linux/jiffies.h>
25#include <net/cfg80211.h>
26
27#include <brcmu_utils.h>
28#include <brcmu_wifi.h>
29#include "dhd.h"
30#include "dhd_proto.h"
31#include "dhd_dbg.h"
32#include "dhd_bus.h"
33#include "fwil.h"
34#include "fwil_types.h"
35#include "fweh.h"
36#include "fwsignal.h"
37#include "p2p.h"
38#include "wl_cfg80211.h"
39
40/**
41 * DOC: Firmware Signalling
42 *
43 * Firmware can send signals to host and vice versa, which are passed in the
44 * data packets using TLV based header. This signalling layer is on top of the
45 * BDC bus protocol layer.
46 */
47
48/*
49 * single definition for firmware-driver flow control tlv's.
50 *
51 * each tlv is specified by BRCMF_FWS_TLV_DEF(name, ID, length).
52 * A length value 0 indicates variable length tlv.
53 */
54#define BRCMF_FWS_TLV_DEFLIST \
55	BRCMF_FWS_TLV_DEF(MAC_OPEN, 1, 1) \
56	BRCMF_FWS_TLV_DEF(MAC_CLOSE, 2, 1) \
57	BRCMF_FWS_TLV_DEF(MAC_REQUEST_CREDIT, 3, 2) \
58	BRCMF_FWS_TLV_DEF(TXSTATUS, 4, 4) \
59	BRCMF_FWS_TLV_DEF(PKTTAG, 5, 4) \
60	BRCMF_FWS_TLV_DEF(MACDESC_ADD,	6, 8) \
61	BRCMF_FWS_TLV_DEF(MACDESC_DEL, 7, 8) \
62	BRCMF_FWS_TLV_DEF(RSSI, 8, 1) \
63	BRCMF_FWS_TLV_DEF(INTERFACE_OPEN, 9, 1) \
64	BRCMF_FWS_TLV_DEF(INTERFACE_CLOSE, 10, 1) \
65	BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 6) \
66	BRCMF_FWS_TLV_DEF(PENDING_TRAFFIC_BMP, 12, 2) \
67	BRCMF_FWS_TLV_DEF(MAC_REQUEST_PACKET, 13, 3) \
68	BRCMF_FWS_TLV_DEF(HOST_REORDER_RXPKTS, 14, 10) \
69	BRCMF_FWS_TLV_DEF(TRANS_ID, 18, 6) \
70	BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \
71	BRCMF_FWS_TLV_DEF(FILLER, 255, 0)
72
73/*
74 * enum brcmf_fws_tlv_type - definition of tlv identifiers.
75 */
76#define BRCMF_FWS_TLV_DEF(name, id, len) \
77	BRCMF_FWS_TYPE_ ## name =  id,
78enum brcmf_fws_tlv_type {
79	BRCMF_FWS_TLV_DEFLIST
80	BRCMF_FWS_TYPE_INVALID
81};
82#undef BRCMF_FWS_TLV_DEF
83
84/*
85 * enum brcmf_fws_tlv_len - definition of tlv lengths.
86 */
87#define BRCMF_FWS_TLV_DEF(name, id, len) \
88	BRCMF_FWS_TYPE_ ## name ## _LEN = (len),
89enum brcmf_fws_tlv_len {
90	BRCMF_FWS_TLV_DEFLIST
91};
92#undef BRCMF_FWS_TLV_DEF
93
94#ifdef DEBUG
95/*
96 * brcmf_fws_tlv_names - array of tlv names.
97 */
98#define BRCMF_FWS_TLV_DEF(name, id, len) \
99	{ id, #name },
100static struct {
101	enum brcmf_fws_tlv_type id;
102	const char *name;
103} brcmf_fws_tlv_names[] = {
104	BRCMF_FWS_TLV_DEFLIST
105};
106#undef BRCMF_FWS_TLV_DEF
107
108static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
109{
110	int i;
111
112	for (i = 0; i < ARRAY_SIZE(brcmf_fws_tlv_names); i++)
113		if (brcmf_fws_tlv_names[i].id == id)
114			return brcmf_fws_tlv_names[i].name;
115
116	return "INVALID";
117}
118#else
119static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
120{
121	return "NODEBUG";
122}
123#endif /* DEBUG */
124
125/*
126 * flags used to enable tlv signalling from firmware.
127 */
128#define BRCMF_FWS_FLAGS_RSSI_SIGNALS			0x0001
129#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS			0x0002
130#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS		0x0004
131#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE	0x0008
132#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE	0x0010
133#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE		0x0020
134#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE		0x0040
135
136#define BRCMF_FWS_MAC_DESC_TABLE_SIZE			32
137#define BRCMF_FWS_MAC_DESC_ID_INVALID			0xff
138
139#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF			0
140#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON			1
141#define BRCMF_FWS_FLOWCONTROL_HIWATER			128
142#define BRCMF_FWS_FLOWCONTROL_LOWATER			64
143
144#define BRCMF_FWS_PSQ_PREC_COUNT		((BRCMF_FWS_FIFO_COUNT + 1) * 2)
145#define BRCMF_FWS_PSQ_LEN				256
146
147#define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST			0x01
148#define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED		0x02
149
150#define BRCMF_FWS_RET_OK_NOSCHEDULE	0
151#define BRCMF_FWS_RET_OK_SCHEDULE	1
152
153/**
154 * enum brcmf_fws_skb_state - indicates processing state of skb.
155 *
156 * @BRCMF_FWS_SKBSTATE_NEW: sk_buff is newly arrived in the driver.
157 * @BRCMF_FWS_SKBSTATE_DELAYED: sk_buff had to wait on queue.
158 * @BRCMF_FWS_SKBSTATE_SUPPRESSED: sk_buff has been suppressed by firmware.
159 * @BRCMF_FWS_SKBSTATE_TIM: allocated for TIM update info.
160 */
161enum brcmf_fws_skb_state {
162	BRCMF_FWS_SKBSTATE_NEW,
163	BRCMF_FWS_SKBSTATE_DELAYED,
164	BRCMF_FWS_SKBSTATE_SUPPRESSED,
165	BRCMF_FWS_SKBSTATE_TIM
166};
167
168/**
169 * struct brcmf_skbuff_cb - control buffer associated with skbuff.
170 *
171 * @bus_flags: 2 bytes reserved for bus specific parameters
172 * @if_flags: holds interface index and packet related flags.
173 * @htod: host to device packet identifier (used in PKTTAG tlv).
174 * @state: transmit state of the packet.
175 * @mac: descriptor related to destination for this packet.
176 *
177 * This information is stored in control buffer struct sk_buff::cb, which
178 * provides 48 bytes of storage so this structure should not exceed that.
179 */
180struct brcmf_skbuff_cb {
181	u16 bus_flags;
182	u16 if_flags;
183	u32 htod;
184	enum brcmf_fws_skb_state state;
185	struct brcmf_fws_mac_descriptor *mac;
186};
187
188/*
189 * macro casting skbuff control buffer to struct brcmf_skbuff_cb.
190 */
191#define brcmf_skbcb(skb)	((struct brcmf_skbuff_cb *)((skb)->cb))
192
193/*
194 * sk_buff control if flags
195 *
196 *	b[11]  - packet sent upon firmware request.
197 *	b[10]  - packet only contains signalling data.
198 *	b[9]   - packet is a tx packet.
199 *	b[8]   - packet used requested credit
200 *	b[7]   - interface in AP mode.
201 *	b[3:0] - interface index.
202 */
203#define BRCMF_SKB_IF_FLAGS_REQUESTED_MASK	0x0800
204#define BRCMF_SKB_IF_FLAGS_REQUESTED_SHIFT	11
205#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_MASK	0x0400
206#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_SHIFT	10
207#define BRCMF_SKB_IF_FLAGS_TRANSMIT_MASK        0x0200
208#define BRCMF_SKB_IF_FLAGS_TRANSMIT_SHIFT	9
209#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_MASK	0x0100
210#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_SHIFT	8
211#define BRCMF_SKB_IF_FLAGS_IF_AP_MASK		0x0080
212#define BRCMF_SKB_IF_FLAGS_IF_AP_SHIFT		7
213#define BRCMF_SKB_IF_FLAGS_INDEX_MASK		0x000f
214#define BRCMF_SKB_IF_FLAGS_INDEX_SHIFT		0
215
216#define brcmf_skb_if_flags_set_field(skb, field, value) \
217	brcmu_maskset16(&(brcmf_skbcb(skb)->if_flags), \
218			BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
219			BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT, (value))
220#define brcmf_skb_if_flags_get_field(skb, field) \
221	brcmu_maskget16(brcmf_skbcb(skb)->if_flags, \
222			BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
223			BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT)
224
225/*
226 * sk_buff control packet identifier
227 *
228 * 32-bit packet identifier used in PKTTAG tlv from host to dongle.
229 *
230 * - Generated at the host (e.g. dhd)
231 * - Seen as a generic sequence number by firmware except for the flags field.
232 *
233 * Generation	: b[31]	=> generation number for this packet [host->fw]
234 *			   OR, current generation number [fw->host]
235 * Flags	: b[30:27] => command, status flags
236 * FIFO-AC	: b[26:24] => AC-FIFO id
237 * h-slot	: b[23:8] => hanger-slot
238 * freerun	: b[7:0] => A free running counter
239 */
240#define BRCMF_SKB_HTOD_TAG_GENERATION_MASK		0x80000000
241#define BRCMF_SKB_HTOD_TAG_GENERATION_SHIFT		31
242#define BRCMF_SKB_HTOD_TAG_FLAGS_MASK			0x78000000
243#define BRCMF_SKB_HTOD_TAG_FLAGS_SHIFT			27
244#define BRCMF_SKB_HTOD_TAG_FIFO_MASK			0x07000000
245#define BRCMF_SKB_HTOD_TAG_FIFO_SHIFT			24
246#define BRCMF_SKB_HTOD_TAG_HSLOT_MASK			0x00ffff00
247#define BRCMF_SKB_HTOD_TAG_HSLOT_SHIFT			8
248#define BRCMF_SKB_HTOD_TAG_FREERUN_MASK			0x000000ff
249#define BRCMF_SKB_HTOD_TAG_FREERUN_SHIFT		0
250
251#define brcmf_skb_htod_tag_set_field(skb, field, value) \
252	brcmu_maskset32(&(brcmf_skbcb(skb)->htod), \
253			BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
254			BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT, (value))
255#define brcmf_skb_htod_tag_get_field(skb, field) \
256	brcmu_maskget32(brcmf_skbcb(skb)->htod, \
257			BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
258			BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
259
260#define BRCMF_FWS_TXSTAT_GENERATION_MASK	0x80000000
261#define BRCMF_FWS_TXSTAT_GENERATION_SHIFT	31
262#define BRCMF_FWS_TXSTAT_FLAGS_MASK		0x78000000
263#define BRCMF_FWS_TXSTAT_FLAGS_SHIFT		27
264#define BRCMF_FWS_TXSTAT_FIFO_MASK		0x07000000
265#define BRCMF_FWS_TXSTAT_FIFO_SHIFT		24
266#define BRCMF_FWS_TXSTAT_HSLOT_MASK		0x00FFFF00
267#define BRCMF_FWS_TXSTAT_HSLOT_SHIFT		8
268#define BRCMF_FWS_TXSTAT_PKTID_MASK		0x00FFFFFF
269#define BRCMF_FWS_TXSTAT_PKTID_SHIFT		0
270
271#define brcmf_txstatus_get_field(txs, field) \
272	brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
273			BRCMF_FWS_TXSTAT_ ## field ## _SHIFT)
274
275/* How long to defer borrowing in jiffies */
276#define BRCMF_FWS_BORROW_DEFER_PERIOD		(HZ / 10)
277
278/**
279 * enum brcmf_fws_fifo - fifo indices used by dongle firmware.
280 *
281 * @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background.
282 * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
283 * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
284 * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
285 * @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
286 * @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
287 * @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
288 * @BRCMF_FWS_FIFO_COUNT: number of fifos.
289 */
290enum brcmf_fws_fifo {
291	BRCMF_FWS_FIFO_FIRST,
292	BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST,
293	BRCMF_FWS_FIFO_AC_BE,
294	BRCMF_FWS_FIFO_AC_VI,
295	BRCMF_FWS_FIFO_AC_VO,
296	BRCMF_FWS_FIFO_BCMC,
297	BRCMF_FWS_FIFO_ATIM,
298	BRCMF_FWS_FIFO_COUNT
299};
300
301/**
302 * enum brcmf_fws_txstatus - txstatus flag values.
303 *
304 * @BRCMF_FWS_TXSTATUS_DISCARD:
305 *	host is free to discard the packet.
306 * @BRCMF_FWS_TXSTATUS_CORE_SUPPRESS:
307 *	802.11 core suppressed the packet.
308 * @BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS:
309 *	firmware suppress the packet as device is already in PS mode.
310 * @BRCMF_FWS_TXSTATUS_FW_TOSSED:
311 *	firmware tossed the packet.
312 * @BRCMF_FWS_TXSTATUS_HOST_TOSSED:
313 *	host tossed the packet.
314 */
315enum brcmf_fws_txstatus {
316	BRCMF_FWS_TXSTATUS_DISCARD,
317	BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
318	BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
319	BRCMF_FWS_TXSTATUS_FW_TOSSED,
320	BRCMF_FWS_TXSTATUS_HOST_TOSSED
321};
322
323enum brcmf_fws_fcmode {
324	BRCMF_FWS_FCMODE_NONE,
325	BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
326	BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
327};
328
329enum brcmf_fws_mac_desc_state {
330	BRCMF_FWS_STATE_OPEN = 1,
331	BRCMF_FWS_STATE_CLOSE
332};
333
334/**
335 * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
336 *
337 * @occupied: slot is in use.
338 * @mac_handle: handle for mac entry determined by firmware.
339 * @interface_id: interface index.
340 * @state: current state.
341 * @suppressed: mac entry is suppressed.
342 * @generation: generation bit.
343 * @ac_bitmap: ac queue bitmap.
344 * @requested_credit: credits requested by firmware.
345 * @ea: ethernet address.
346 * @seq: per-node free-running sequence.
347 * @psq: power-save queue.
348 * @transit_count: packet in transit to firmware.
349 */
350struct brcmf_fws_mac_descriptor {
351	char name[16];
352	u8 occupied;
353	u8 mac_handle;
354	u8 interface_id;
355	u8 state;
356	bool suppressed;
357	u8 generation;
358	u8 ac_bitmap;
359	u8 requested_credit;
360	u8 requested_packet;
361	u8 ea[ETH_ALEN];
362	u8 seq[BRCMF_FWS_FIFO_COUNT];
363	struct pktq psq;
364	int transit_count;
365	int suppr_transit_count;
366	bool send_tim_signal;
367	u8 traffic_pending_bmp;
368	u8 traffic_lastreported_bmp;
369};
370
371#define BRCMF_FWS_HANGER_MAXITEMS	1024
372
373/**
374 * enum brcmf_fws_hanger_item_state - state of hanger item.
375 *
376 * @BRCMF_FWS_HANGER_ITEM_STATE_FREE: item is free for use.
377 * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE: item is in use.
378 * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed.
379 */
380enum brcmf_fws_hanger_item_state {
381	BRCMF_FWS_HANGER_ITEM_STATE_FREE = 1,
382	BRCMF_FWS_HANGER_ITEM_STATE_INUSE,
383	BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED
384};
385
386
387/**
388 * struct brcmf_fws_hanger_item - single entry for tx pending packet.
389 *
390 * @state: entry is either free or occupied.
391 * @pkt: packet itself.
392 */
393struct brcmf_fws_hanger_item {
394	enum brcmf_fws_hanger_item_state state;
395	struct sk_buff *pkt;
396};
397
398/**
399 * struct brcmf_fws_hanger - holds packets awaiting firmware txstatus.
400 *
401 * @pushed: packets pushed to await txstatus.
402 * @popped: packets popped upon handling txstatus.
403 * @failed_to_push: packets that could not be pushed.
404 * @failed_to_pop: packets that could not be popped.
405 * @failed_slotfind: packets for which failed to find an entry.
406 * @slot_pos: last returned item index for a free entry.
407 * @items: array of hanger items.
408 */
409struct brcmf_fws_hanger {
410	u32 pushed;
411	u32 popped;
412	u32 failed_to_push;
413	u32 failed_to_pop;
414	u32 failed_slotfind;
415	u32 slot_pos;
416	struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS];
417};
418
419struct brcmf_fws_macdesc_table {
420	struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
421	struct brcmf_fws_mac_descriptor iface[BRCMF_MAX_IFS];
422	struct brcmf_fws_mac_descriptor other;
423};
424
425struct brcmf_fws_info {
426	struct brcmf_pub *drvr;
427	spinlock_t spinlock;
428	ulong flags;
429	struct brcmf_fws_stats stats;
430	struct brcmf_fws_hanger hanger;
431	enum brcmf_fws_fcmode fcmode;
432	bool fw_signals;
433	bool bcmc_credit_check;
434	struct brcmf_fws_macdesc_table desc;
435	struct workqueue_struct *fws_wq;
436	struct work_struct fws_dequeue_work;
437	u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
438	int fifo_credit[BRCMF_FWS_FIFO_COUNT];
439	int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1];
440	int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
441	u32 fifo_credit_map;
442	u32 fifo_delay_map;
443	unsigned long borrow_defer_timestamp;
444	bool bus_flow_blocked;
445	bool creditmap_received;
446};
447
448/*
449 * brcmf_fws_prio2fifo - mapping from 802.1d priority to firmware fifo index.
450 */
451static const int brcmf_fws_prio2fifo[] = {
452	BRCMF_FWS_FIFO_AC_BE,
453	BRCMF_FWS_FIFO_AC_BK,
454	BRCMF_FWS_FIFO_AC_BK,
455	BRCMF_FWS_FIFO_AC_BE,
456	BRCMF_FWS_FIFO_AC_VI,
457	BRCMF_FWS_FIFO_AC_VI,
458	BRCMF_FWS_FIFO_AC_VO,
459	BRCMF_FWS_FIFO_AC_VO
460};
461
462static int fcmode;
463module_param(fcmode, int, S_IRUSR);
464MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control");
465
466#define BRCMF_FWS_TLV_DEF(name, id, len) \
467	case BRCMF_FWS_TYPE_ ## name: \
468		return len;
469
470/**
471 * brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
472 *
473 * @fws: firmware-signalling information.
474 * @id: identifier of the TLV.
475 *
476 * Return: the specified length for the given TLV; Otherwise -EINVAL.
477 */
478static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
479				 enum brcmf_fws_tlv_type id)
480{
481	switch (id) {
482	BRCMF_FWS_TLV_DEFLIST
483	default:
484		fws->stats.tlv_invalid_type++;
485		break;
486	}
487	return -EINVAL;
488}
489#undef BRCMF_FWS_TLV_DEF
490
491static void brcmf_fws_lock(struct brcmf_fws_info *fws)
492		__acquires(&fws->spinlock)
493{
494	spin_lock_irqsave(&fws->spinlock, fws->flags);
495}
496
497static void brcmf_fws_unlock(struct brcmf_fws_info *fws)
498		__releases(&fws->spinlock)
499{
500	spin_unlock_irqrestore(&fws->spinlock, fws->flags);
501}
502
503static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
504{
505	u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
506	return ifidx == *(int *)arg;
507}
508
509static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
510				int ifidx)
511{
512	bool (*matchfn)(struct sk_buff *, void *) = NULL;
513	struct sk_buff *skb;
514	int prec;
515
516	if (ifidx != -1)
517		matchfn = brcmf_fws_ifidx_match;
518	for (prec = 0; prec < q->num_prec; prec++) {
519		skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
520		while (skb) {
521			brcmu_pkt_buf_free_skb(skb);
522			skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
523		}
524	}
525}
526
527static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
528{
529	int i;
530
531	memset(hanger, 0, sizeof(*hanger));
532	for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
533		hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
534}
535
536static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
537{
538	u32 i;
539
540	i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
541
542	while (i != h->slot_pos) {
543		if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
544			h->slot_pos = i;
545			goto done;
546		}
547		i++;
548		if (i == BRCMF_FWS_HANGER_MAXITEMS)
549			i = 0;
550	}
551	brcmf_err("all slots occupied\n");
552	h->failed_slotfind++;
553	i = BRCMF_FWS_HANGER_MAXITEMS;
554done:
555	return i;
556}
557
558static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
559				    struct sk_buff *pkt, u32 slot_id)
560{
561	if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
562		return -ENOENT;
563
564	if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
565		brcmf_err("slot is not free\n");
566		h->failed_to_push++;
567		return -EINVAL;
568	}
569
570	h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
571	h->items[slot_id].pkt = pkt;
572	h->pushed++;
573	return 0;
574}
575
576static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
577					  u32 slot_id, struct sk_buff **pktout,
578					  bool remove_item)
579{
580	if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
581		return -ENOENT;
582
583	if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
584		brcmf_err("entry not in use\n");
585		h->failed_to_pop++;
586		return -EINVAL;
587	}
588
589	*pktout = h->items[slot_id].pkt;
590	if (remove_item) {
591		h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
592		h->items[slot_id].pkt = NULL;
593		h->popped++;
594	}
595	return 0;
596}
597
598static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
599					    u32 slot_id)
600{
601	if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
602		return -ENOENT;
603
604	if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
605		brcmf_err("entry not in use\n");
606		return -EINVAL;
607	}
608
609	h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
610	return 0;
611}
612
613static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
614				     bool (*fn)(struct sk_buff *, void *),
615				     int ifidx)
616{
617	struct brcmf_fws_hanger *h = &fws->hanger;
618	struct sk_buff *skb;
619	int i;
620	enum brcmf_fws_hanger_item_state s;
621
622	for (i = 0; i < ARRAY_SIZE(h->items); i++) {
623		s = h->items[i].state;
624		if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
625		    s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
626			skb = h->items[i].pkt;
627			if (fn == NULL || fn(skb, &ifidx)) {
628				/* suppress packets freed from psq */
629				if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
630					brcmu_pkt_buf_free_skb(skb);
631				h->items[i].state =
632					BRCMF_FWS_HANGER_ITEM_STATE_FREE;
633			}
634		}
635	}
636}
637
638static void brcmf_fws_macdesc_set_name(struct brcmf_fws_info *fws,
639				       struct brcmf_fws_mac_descriptor *desc)
640{
641	if (desc == &fws->desc.other)
642		strlcpy(desc->name, "MAC-OTHER", sizeof(desc->name));
643	else if (desc->mac_handle)
644		scnprintf(desc->name, sizeof(desc->name), "MAC-%d:%d",
645			  desc->mac_handle, desc->interface_id);
646	else
647		scnprintf(desc->name, sizeof(desc->name), "MACIF:%d",
648			  desc->interface_id);
649}
650
651static void brcmf_fws_macdesc_init(struct brcmf_fws_mac_descriptor *desc,
652				   u8 *addr, u8 ifidx)
653{
654	brcmf_dbg(TRACE,
655		  "enter: desc %p ea=%pM, ifidx=%u\n", desc, addr, ifidx);
656	desc->occupied = 1;
657	desc->state = BRCMF_FWS_STATE_OPEN;
658	desc->requested_credit = 0;
659	desc->requested_packet = 0;
660	/* depending on use may need ifp->bssidx instead */
661	desc->interface_id = ifidx;
662	desc->ac_bitmap = 0xff; /* update this when handling APSD */
663	if (addr)
664		memcpy(&desc->ea[0], addr, ETH_ALEN);
665}
666
667static
668void brcmf_fws_macdesc_deinit(struct brcmf_fws_mac_descriptor *desc)
669{
670	brcmf_dbg(TRACE,
671		  "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id);
672	desc->occupied = 0;
673	desc->state = BRCMF_FWS_STATE_CLOSE;
674	desc->requested_credit = 0;
675	desc->requested_packet = 0;
676}
677
678static struct brcmf_fws_mac_descriptor *
679brcmf_fws_macdesc_lookup(struct brcmf_fws_info *fws, u8 *ea)
680{
681	struct brcmf_fws_mac_descriptor *entry;
682	int i;
683
684	if (ea == NULL)
685		return ERR_PTR(-EINVAL);
686
687	entry = &fws->desc.nodes[0];
688	for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++) {
689		if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
690			return entry;
691		entry++;
692	}
693
694	return ERR_PTR(-ENOENT);
695}
696
697static struct brcmf_fws_mac_descriptor*
698brcmf_fws_macdesc_find(struct brcmf_fws_info *fws, struct brcmf_if *ifp, u8 *da)
699{
700	struct brcmf_fws_mac_descriptor *entry = &fws->desc.other;
701	bool multicast;
702
703	multicast = is_multicast_ether_addr(da);
704
705	/* Multicast destination, STA and P2P clients get the interface entry.
706	 * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations
707	 * have their own entry.
708	 */
709	if (multicast && ifp->fws_desc) {
710		entry = ifp->fws_desc;
711		goto done;
712	}
713
714	entry = brcmf_fws_macdesc_lookup(fws, da);
715	if (IS_ERR(entry))
716		entry = ifp->fws_desc;
717
718done:
719	return entry;
720}
721
722static bool brcmf_fws_macdesc_closed(struct brcmf_fws_info *fws,
723				     struct brcmf_fws_mac_descriptor *entry,
724				     int fifo)
725{
726	struct brcmf_fws_mac_descriptor *if_entry;
727	bool closed;
728
729	/* for unique destination entries the related interface
730	 * may be closed.
731	 */
732	if (entry->mac_handle) {
733		if_entry = &fws->desc.iface[entry->interface_id];
734		if (if_entry->state == BRCMF_FWS_STATE_CLOSE)
735			return true;
736	}
737	/* an entry is closed when the state is closed and
738	 * the firmware did not request anything.
739	 */
740	closed = entry->state == BRCMF_FWS_STATE_CLOSE &&
741		 !entry->requested_credit && !entry->requested_packet;
742
743	/* Or firmware does not allow traffic for given fifo */
744	return closed || !(entry->ac_bitmap & BIT(fifo));
745}
746
747static void brcmf_fws_macdesc_cleanup(struct brcmf_fws_info *fws,
748				      struct brcmf_fws_mac_descriptor *entry,
749				      int ifidx)
750{
751	if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
752		brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
753		entry->occupied = !!(entry->psq.len);
754	}
755}
756
757static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
758				      bool (*fn)(struct sk_buff *, void *),
759				      int ifidx)
760{
761	struct brcmf_fws_hanger_item *hi;
762	struct pktq *txq;
763	struct sk_buff *skb;
764	int prec;
765	u32 hslot;
766
767	txq = brcmf_bus_gettxq(fws->drvr->bus_if);
768	if (IS_ERR(txq)) {
769		brcmf_dbg(TRACE, "no txq to clean up\n");
770		return;
771	}
772
773	for (prec = 0; prec < txq->num_prec; prec++) {
774		skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
775		while (skb) {
776			hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
777			hi = &fws->hanger.items[hslot];
778			WARN_ON(skb != hi->pkt);
779			hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
780			brcmu_pkt_buf_free_skb(skb);
781			skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
782		}
783	}
784}
785
786static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
787{
788	int i;
789	struct brcmf_fws_mac_descriptor *table;
790	bool (*matchfn)(struct sk_buff *, void *) = NULL;
791
792	if (fws == NULL)
793		return;
794
795	if (ifidx != -1)
796		matchfn = brcmf_fws_ifidx_match;
797
798	/* cleanup individual nodes */
799	table = &fws->desc.nodes[0];
800	for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++)
801		brcmf_fws_macdesc_cleanup(fws, &table[i], ifidx);
802
803	brcmf_fws_macdesc_cleanup(fws, &fws->desc.other, ifidx);
804	brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
805	brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
806}
807
808static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
809{
810	struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
811	u8 *wlh;
812	u16 data_offset = 0;
813	u8 fillers;
814	__le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
815
816	brcmf_dbg(TRACE, "enter: %s, idx=%d pkttag=0x%08X, hslot=%d\n",
817		  entry->name, brcmf_skb_if_flags_get_field(skb, INDEX),
818		  le32_to_cpu(pkttag), (le32_to_cpu(pkttag) >> 8) & 0xffff);
819	if (entry->send_tim_signal)
820		data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
821
822	/* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
823	data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
824	fillers = round_up(data_offset, 4) - data_offset;
825	data_offset += fillers;
826
827	skb_push(skb, data_offset);
828	wlh = skb->data;
829
830	wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
831	wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
832	memcpy(&wlh[2], &pkttag, sizeof(pkttag));
833	wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
834
835	if (entry->send_tim_signal) {
836		entry->send_tim_signal = 0;
837		wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
838		wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
839		wlh[2] = entry->mac_handle;
840		wlh[3] = entry->traffic_pending_bmp;
841		brcmf_dbg(TRACE, "adding TIM info: handle %d bmp 0x%X\n",
842			  entry->mac_handle, entry->traffic_pending_bmp);
843		wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
844		entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
845	}
846	if (fillers)
847		memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
848
849	brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
850			    data_offset >> 2, skb);
851	return 0;
852}
853
854static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
855				 struct brcmf_fws_mac_descriptor *entry,
856				 int fifo, bool send_immediately)
857{
858	struct sk_buff *skb;
859	struct brcmf_bus *bus;
860	struct brcmf_skbuff_cb *skcb;
861	s32 err;
862	u32 len;
863
864	/* check delayedQ and suppressQ in one call using bitmap */
865	if (brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0)
866		entry->traffic_pending_bmp &= ~NBITVAL(fifo);
867	else
868		entry->traffic_pending_bmp |= NBITVAL(fifo);
869
870	entry->send_tim_signal = false;
871	if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
872		entry->send_tim_signal = true;
873	if (send_immediately && entry->send_tim_signal &&
874	    entry->state == BRCMF_FWS_STATE_CLOSE) {
875		/* create a dummy packet and sent that. The traffic          */
876		/* bitmap info will automatically be attached to that packet */
877		len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 +
878		      BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +
879		      4 + fws->drvr->hdrlen;
880		skb = brcmu_pkt_buf_get_skb(len);
881		if (skb == NULL)
882			return false;
883		skb_pull(skb, len);
884		skcb = brcmf_skbcb(skb);
885		skcb->mac = entry;
886		skcb->state = BRCMF_FWS_SKBSTATE_TIM;
887		bus = fws->drvr->bus_if;
888		err = brcmf_fws_hdrpush(fws, skb);
889		if (err == 0) {
890			brcmf_fws_unlock(fws);
891			err = brcmf_bus_txdata(bus, skb);
892			brcmf_fws_lock(fws);
893		}
894		if (err)
895			brcmu_pkt_buf_free_skb(skb);
896		return true;
897	}
898	return false;
899}
900
901static void
902brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
903			     u8 if_id)
904{
905	struct brcmf_if *ifp = fws->drvr->iflist[!if_id ? 0 : if_id + 1];
906
907	if (WARN_ON(!ifp))
908		return;
909
910	if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
911	    pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
912		brcmf_txflowblock_if(ifp,
913				     BRCMF_NETIF_STOP_REASON_FWS_FC, false);
914	if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
915	    pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER) {
916		fws->stats.fws_flow_block++;
917		brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
918	}
919	return;
920}
921
922static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
923{
924	brcmf_dbg(CTL, "rssi %d\n", rssi);
925	return 0;
926}
927
928static
929int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
930{
931	struct brcmf_fws_mac_descriptor *entry, *existing;
932	u8 mac_handle;
933	u8 ifidx;
934	u8 *addr;
935
936	mac_handle = *data++;
937	ifidx = *data++;
938	addr = data;
939
940	entry = &fws->desc.nodes[mac_handle & 0x1F];
941	if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
942		if (entry->occupied) {
943			brcmf_dbg(TRACE, "deleting %s mac %pM\n",
944				  entry->name, addr);
945			brcmf_fws_lock(fws);
946			brcmf_fws_macdesc_cleanup(fws, entry, -1);
947			brcmf_fws_macdesc_deinit(entry);
948			brcmf_fws_unlock(fws);
949		} else
950			fws->stats.mac_update_failed++;
951		return 0;
952	}
953
954	existing = brcmf_fws_macdesc_lookup(fws, addr);
955	if (IS_ERR(existing)) {
956		if (!entry->occupied) {
957			brcmf_fws_lock(fws);
958			entry->mac_handle = mac_handle;
959			brcmf_fws_macdesc_init(entry, addr, ifidx);
960			brcmf_fws_macdesc_set_name(fws, entry);
961			brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
962					BRCMF_FWS_PSQ_LEN);
963			brcmf_fws_unlock(fws);
964			brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
965		} else {
966			fws->stats.mac_update_failed++;
967		}
968	} else {
969		if (entry != existing) {
970			brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
971			brcmf_fws_lock(fws);
972			memcpy(entry, existing,
973			       offsetof(struct brcmf_fws_mac_descriptor, psq));
974			entry->mac_handle = mac_handle;
975			brcmf_fws_macdesc_deinit(existing);
976			brcmf_fws_macdesc_set_name(fws, entry);
977			brcmf_fws_unlock(fws);
978			brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
979				  addr);
980		} else {
981			brcmf_dbg(TRACE, "use existing\n");
982			WARN_ON(entry->mac_handle != mac_handle);
983			/* TODO: what should we do here: continue, reinit, .. */
984		}
985	}
986	return 0;
987}
988
989static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
990					    u8 type, u8 *data)
991{
992	struct brcmf_fws_mac_descriptor *entry;
993	u8 mac_handle;
994	int ret;
995
996	mac_handle = data[0];
997	entry = &fws->desc.nodes[mac_handle & 0x1F];
998	if (!entry->occupied) {
999		fws->stats.mac_ps_update_failed++;
1000		return -ESRCH;
1001	}
1002	brcmf_fws_lock(fws);
1003	/* a state update should wipe old credits */
1004	entry->requested_credit = 0;
1005	entry->requested_packet = 0;
1006	if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
1007		entry->state = BRCMF_FWS_STATE_OPEN;
1008		ret = BRCMF_FWS_RET_OK_SCHEDULE;
1009	} else {
1010		entry->state = BRCMF_FWS_STATE_CLOSE;
1011		brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false);
1012		brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false);
1013		brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false);
1014		brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
1015		ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1016	}
1017	brcmf_fws_unlock(fws);
1018	return ret;
1019}
1020
1021static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
1022					      u8 type, u8 *data)
1023{
1024	struct brcmf_fws_mac_descriptor *entry;
1025	u8 ifidx;
1026	int ret;
1027
1028	ifidx = data[0];
1029
1030	if (ifidx >= BRCMF_MAX_IFS) {
1031		ret = -ERANGE;
1032		goto fail;
1033	}
1034
1035	entry = &fws->desc.iface[ifidx];
1036	if (!entry->occupied) {
1037		ret = -ESRCH;
1038		goto fail;
1039	}
1040
1041	brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
1042		  entry->name);
1043	brcmf_fws_lock(fws);
1044	switch (type) {
1045	case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1046		entry->state = BRCMF_FWS_STATE_OPEN;
1047		ret = BRCMF_FWS_RET_OK_SCHEDULE;
1048		break;
1049	case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1050		entry->state = BRCMF_FWS_STATE_CLOSE;
1051		ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1052		break;
1053	default:
1054		ret = -EINVAL;
1055		brcmf_fws_unlock(fws);
1056		goto fail;
1057	}
1058	brcmf_fws_unlock(fws);
1059	return ret;
1060
1061fail:
1062	fws->stats.if_update_failed++;
1063	return ret;
1064}
1065
1066static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
1067				      u8 *data)
1068{
1069	struct brcmf_fws_mac_descriptor *entry;
1070
1071	entry = &fws->desc.nodes[data[1] & 0x1F];
1072	if (!entry->occupied) {
1073		if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1074			fws->stats.credit_request_failed++;
1075		else
1076			fws->stats.packet_request_failed++;
1077		return -ESRCH;
1078	}
1079
1080	brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
1081		  brcmf_fws_get_tlv_name(type), type, entry->name,
1082		  data[0], data[2]);
1083	brcmf_fws_lock(fws);
1084	if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1085		entry->requested_credit = data[0];
1086	else
1087		entry->requested_packet = data[0];
1088
1089	entry->ac_bitmap = data[2];
1090	brcmf_fws_unlock(fws);
1091	return BRCMF_FWS_RET_OK_SCHEDULE;
1092}
1093
1094static void
1095brcmf_fws_macdesc_use_req_credit(struct brcmf_fws_mac_descriptor *entry,
1096				 struct sk_buff *skb)
1097{
1098	if (entry->requested_credit > 0) {
1099		entry->requested_credit--;
1100		brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1101		brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 1);
1102		if (entry->state != BRCMF_FWS_STATE_CLOSE)
1103			brcmf_err("requested credit set while mac not closed!\n");
1104	} else if (entry->requested_packet > 0) {
1105		entry->requested_packet--;
1106		brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1107		brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1108		if (entry->state != BRCMF_FWS_STATE_CLOSE)
1109			brcmf_err("requested packet set while mac not closed!\n");
1110	} else {
1111		brcmf_skb_if_flags_set_field(skb, REQUESTED, 0);
1112		brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1113	}
1114}
1115
1116static void brcmf_fws_macdesc_return_req_credit(struct sk_buff *skb)
1117{
1118	struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1119
1120	if ((brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) &&
1121	    (entry->state == BRCMF_FWS_STATE_CLOSE))
1122		entry->requested_credit++;
1123}
1124
1125static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
1126				     u8 fifo, u8 credits)
1127{
1128	int lender_ac;
1129	int *borrowed;
1130	int *fifo_credit;
1131
1132	if (!credits)
1133		return;
1134
1135	fws->fifo_credit_map |= 1 << fifo;
1136
1137	if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
1138	    (fws->credits_borrowed[0])) {
1139		for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
1140		     lender_ac--) {
1141			borrowed = &fws->credits_borrowed[lender_ac];
1142			if (*borrowed) {
1143				fws->fifo_credit_map |= (1 << lender_ac);
1144				fifo_credit = &fws->fifo_credit[lender_ac];
1145				if (*borrowed >= credits) {
1146					*borrowed -= credits;
1147					*fifo_credit += credits;
1148					return;
1149				} else {
1150					credits -= *borrowed;
1151					*fifo_credit += *borrowed;
1152					*borrowed = 0;
1153				}
1154			}
1155		}
1156	}
1157
1158	fws->fifo_credit[fifo] += credits;
1159}
1160
1161static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
1162{
1163	/* only schedule dequeue when there are credits for delayed traffic */
1164	if ((fws->fifo_credit_map & fws->fifo_delay_map) ||
1165	    (!brcmf_fws_fc_active(fws) && fws->fifo_delay_map))
1166		queue_work(fws->fws_wq, &fws->fws_dequeue_work);
1167}
1168
1169static int brcmf_fws_enq(struct brcmf_fws_info *fws,
1170			 enum brcmf_fws_skb_state state, int fifo,
1171			 struct sk_buff *p)
1172{
1173	int prec = 2 * fifo;
1174	u32 *qfull_stat = &fws->stats.delayq_full_error;
1175
1176	struct brcmf_fws_mac_descriptor *entry;
1177
1178	entry = brcmf_skbcb(p)->mac;
1179	if (entry == NULL) {
1180		brcmf_err("no mac descriptor found for skb %p\n", p);
1181		return -ENOENT;
1182	}
1183
1184	brcmf_dbg(DATA, "enter: fifo %d skb %p\n", fifo, p);
1185	if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
1186		prec += 1;
1187		qfull_stat = &fws->stats.supprq_full_error;
1188	}
1189
1190	if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
1191		*qfull_stat += 1;
1192		return -ENFILE;
1193	}
1194
1195	/* increment total enqueued packet count */
1196	fws->fifo_delay_map |= 1 << fifo;
1197	fws->fifo_enqpkt[fifo]++;
1198
1199	/* update the sk_buff state */
1200	brcmf_skbcb(p)->state = state;
1201
1202	/*
1203	 * A packet has been pushed so update traffic
1204	 * availability bitmap, if applicable
1205	 */
1206	brcmf_fws_tim_update(fws, entry, fifo, true);
1207	brcmf_fws_flow_control_check(fws, &entry->psq,
1208				     brcmf_skb_if_flags_get_field(p, INDEX));
1209	return 0;
1210}
1211
1212static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
1213{
1214	struct brcmf_fws_mac_descriptor *table;
1215	struct brcmf_fws_mac_descriptor *entry;
1216	struct sk_buff *p;
1217	int num_nodes;
1218	int node_pos;
1219	int prec_out;
1220	int pmsk;
1221	int i;
1222
1223	table = (struct brcmf_fws_mac_descriptor *)&fws->desc;
1224	num_nodes = sizeof(fws->desc) / sizeof(struct brcmf_fws_mac_descriptor);
1225	node_pos = fws->deq_node_pos[fifo];
1226
1227	for (i = 0; i < num_nodes; i++) {
1228		entry = &table[(node_pos + i) % num_nodes];
1229		if (!entry->occupied ||
1230		    brcmf_fws_macdesc_closed(fws, entry, fifo))
1231			continue;
1232
1233		if (entry->suppressed)
1234			pmsk = 2;
1235		else
1236			pmsk = 3;
1237		p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
1238		if (p == NULL) {
1239			if (entry->suppressed) {
1240				if (entry->suppr_transit_count)
1241					continue;
1242				entry->suppressed = false;
1243				p = brcmu_pktq_mdeq(&entry->psq,
1244						    1 << (fifo * 2), &prec_out);
1245			}
1246		}
1247		if  (p == NULL)
1248			continue;
1249
1250		brcmf_fws_macdesc_use_req_credit(entry, p);
1251
1252		/* move dequeue position to ensure fair round-robin */
1253		fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
1254		brcmf_fws_flow_control_check(fws, &entry->psq,
1255					     brcmf_skb_if_flags_get_field(p,
1256									  INDEX)
1257					     );
1258		/*
1259		 * A packet has been picked up, update traffic
1260		 * availability bitmap, if applicable
1261		 */
1262		brcmf_fws_tim_update(fws, entry, fifo, false);
1263
1264		/*
1265		 * decrement total enqueued fifo packets and
1266		 * clear delay bitmap if done.
1267		 */
1268		fws->fifo_enqpkt[fifo]--;
1269		if (fws->fifo_enqpkt[fifo] == 0)
1270			fws->fifo_delay_map &= ~(1 << fifo);
1271		goto done;
1272	}
1273	p = NULL;
1274done:
1275	brcmf_dbg(DATA, "exit: fifo %d skb %p\n", fifo, p);
1276	return p;
1277}
1278
1279static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
1280					 struct sk_buff *skb, u32 genbit)
1281{
1282	struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1283	u32 hslot;
1284	int ret;
1285	u8 ifidx;
1286
1287	hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1288
1289	/* this packet was suppressed */
1290	if (!entry->suppressed) {
1291		entry->suppressed = true;
1292		entry->suppr_transit_count = entry->transit_count;
1293		brcmf_dbg(DATA, "suppress %s: transit %d\n",
1294			  entry->name, entry->transit_count);
1295	}
1296
1297	entry->generation = genbit;
1298
1299	ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
1300	if (ret == 0)
1301		ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo,
1302				    skb);
1303	if (ret != 0) {
1304		/* suppress q is full or hdrpull failed, drop this packet */
1305		brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
1306					true);
1307	} else {
1308		/*
1309		 * Mark suppressed to avoid a double free during
1310		 * wlfc cleanup
1311		 */
1312		brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);
1313	}
1314
1315	return ret;
1316}
1317
1318static int
1319brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
1320			   u32 genbit)
1321{
1322	u32 fifo;
1323	int ret;
1324	bool remove_from_hanger = true;
1325	struct sk_buff *skb;
1326	struct brcmf_skbuff_cb *skcb;
1327	struct brcmf_fws_mac_descriptor *entry = NULL;
1328
1329	brcmf_dbg(DATA, "flags %d\n", flags);
1330
1331	if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
1332		fws->stats.txs_discard++;
1333	else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
1334		fws->stats.txs_supp_core++;
1335		remove_from_hanger = false;
1336	} else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
1337		fws->stats.txs_supp_ps++;
1338		remove_from_hanger = false;
1339	} else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
1340		fws->stats.txs_tossed++;
1341	else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)
1342		fws->stats.txs_host_tossed++;
1343	else
1344		brcmf_err("unexpected txstatus\n");
1345
1346	ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
1347				      remove_from_hanger);
1348	if (ret != 0) {
1349		brcmf_err("no packet in hanger slot: hslot=%d\n", hslot);
1350		return ret;
1351	}
1352
1353	skcb = brcmf_skbcb(skb);
1354	entry = skcb->mac;
1355	if (WARN_ON(!entry)) {
1356		brcmu_pkt_buf_free_skb(skb);
1357		return -EINVAL;
1358	}
1359	entry->transit_count--;
1360	if (entry->suppressed && entry->suppr_transit_count)
1361		entry->suppr_transit_count--;
1362
1363	brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags,
1364		  skcb->htod);
1365
1366	/* pick up the implicit credit from this packet */
1367	fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
1368	if ((fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT) ||
1369	    (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
1370	    (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)) {
1371		brcmf_fws_return_credits(fws, fifo, 1);
1372		brcmf_fws_schedule_deq(fws);
1373	}
1374	brcmf_fws_macdesc_return_req_credit(skb);
1375
1376	if (!remove_from_hanger)
1377		ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
1378
1379	if (remove_from_hanger || ret)
1380		brcmf_txfinalize(fws->drvr, skb, true);
1381
1382	return 0;
1383}
1384
1385static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
1386					     u8 *data)
1387{
1388	int i;
1389
1390	if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
1391		brcmf_dbg(INFO, "ignored\n");
1392		return BRCMF_FWS_RET_OK_NOSCHEDULE;
1393	}
1394
1395	brcmf_dbg(DATA, "enter: data %pM\n", data);
1396	brcmf_fws_lock(fws);
1397	for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
1398		brcmf_fws_return_credits(fws, i, data[i]);
1399
1400	brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
1401		  fws->fifo_delay_map);
1402	brcmf_fws_unlock(fws);
1403	return BRCMF_FWS_RET_OK_SCHEDULE;
1404}
1405
1406static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
1407{
1408	__le32 status_le;
1409	u32 status;
1410	u32 hslot;
1411	u32 genbit;
1412	u8 flags;
1413
1414	fws->stats.txs_indicate++;
1415	memcpy(&status_le, data, sizeof(status_le));
1416	status = le32_to_cpu(status_le);
1417	flags = brcmf_txstatus_get_field(status, FLAGS);
1418	hslot = brcmf_txstatus_get_field(status, HSLOT);
1419	genbit = brcmf_txstatus_get_field(status, GENERATION);
1420
1421	brcmf_fws_lock(fws);
1422	brcmf_fws_txs_process(fws, flags, hslot, genbit);
1423	brcmf_fws_unlock(fws);
1424	return BRCMF_FWS_RET_OK_NOSCHEDULE;
1425}
1426
1427static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
1428{
1429	__le32 timestamp;
1430
1431	memcpy(&timestamp, &data[2], sizeof(timestamp));
1432	brcmf_dbg(CTL, "received: seq %d, timestamp %d\n", data[1],
1433		  le32_to_cpu(timestamp));
1434	return 0;
1435}
1436
1437static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
1438				       const struct brcmf_event_msg *e,
1439				       void *data)
1440{
1441	struct brcmf_fws_info *fws = ifp->drvr->fws;
1442	int i;
1443	u8 *credits = data;
1444
1445	if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
1446		brcmf_err("event payload too small (%d)\n", e->datalen);
1447		return -EINVAL;
1448	}
1449	if (fws->creditmap_received)
1450		return 0;
1451
1452	fws->creditmap_received = true;
1453
1454	brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
1455	brcmf_fws_lock(fws);
1456	for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
1457		if (*credits)
1458			fws->fifo_credit_map |= 1 << i;
1459		else
1460			fws->fifo_credit_map &= ~(1 << i);
1461		fws->fifo_credit[i] = *credits++;
1462	}
1463	brcmf_fws_schedule_deq(fws);
1464	brcmf_fws_unlock(fws);
1465	return 0;
1466}
1467
1468static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
1469						const struct brcmf_event_msg *e,
1470						void *data)
1471{
1472	struct brcmf_fws_info *fws = ifp->drvr->fws;
1473
1474	brcmf_fws_lock(fws);
1475	if (fws)
1476		fws->bcmc_credit_check = true;
1477	brcmf_fws_unlock(fws);
1478	return 0;
1479}
1480
1481int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
1482		      struct sk_buff *skb)
1483{
1484	struct brcmf_skb_reorder_data *rd;
1485	struct brcmf_fws_info *fws = drvr->fws;
1486	u8 *signal_data;
1487	s16 data_len;
1488	u8 type;
1489	u8 len;
1490	u8 *data;
1491	s32 status;
1492	s32 err;
1493
1494	brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
1495		  ifidx, skb->len, signal_len);
1496
1497	WARN_ON(signal_len > skb->len);
1498
1499	if (!signal_len)
1500		return 0;
1501	/* if flow control disabled, skip to packet data and leave */
1502	if (!fws->fw_signals) {
1503		skb_pull(skb, signal_len);
1504		return 0;
1505	}
1506
1507	fws->stats.header_pulls++;
1508	data_len = signal_len;
1509	signal_data = skb->data;
1510
1511	status = BRCMF_FWS_RET_OK_NOSCHEDULE;
1512	while (data_len > 0) {
1513		/* extract tlv info */
1514		type = signal_data[0];
1515
1516		/* FILLER type is actually not a TLV, but
1517		 * a single byte that can be skipped.
1518		 */
1519		if (type == BRCMF_FWS_TYPE_FILLER) {
1520			signal_data += 1;
1521			data_len -= 1;
1522			continue;
1523		}
1524		len = signal_data[1];
1525		data = signal_data + 2;
1526
1527		brcmf_dbg(HDRS, "tlv type=%s (%d), len=%d (%d)\n",
1528			  brcmf_fws_get_tlv_name(type), type, len,
1529			  brcmf_fws_get_tlv_len(fws, type));
1530
1531		/* abort parsing when length invalid */
1532		if (data_len < len + 2)
1533			break;
1534
1535		if (len < brcmf_fws_get_tlv_len(fws, type))
1536			break;
1537
1538		err = BRCMF_FWS_RET_OK_NOSCHEDULE;
1539		switch (type) {
1540		case BRCMF_FWS_TYPE_COMP_TXSTATUS:
1541			break;
1542		case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
1543			rd = (struct brcmf_skb_reorder_data *)skb->cb;
1544			rd->reorder = data;
1545			break;
1546		case BRCMF_FWS_TYPE_MACDESC_ADD:
1547		case BRCMF_FWS_TYPE_MACDESC_DEL:
1548			brcmf_fws_macdesc_indicate(fws, type, data);
1549			break;
1550		case BRCMF_FWS_TYPE_MAC_OPEN:
1551		case BRCMF_FWS_TYPE_MAC_CLOSE:
1552			err = brcmf_fws_macdesc_state_indicate(fws, type, data);
1553			break;
1554		case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1555		case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1556			err = brcmf_fws_interface_state_indicate(fws, type,
1557								 data);
1558			break;
1559		case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
1560		case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
1561			err = brcmf_fws_request_indicate(fws, type, data);
1562			break;
1563		case BRCMF_FWS_TYPE_TXSTATUS:
1564			brcmf_fws_txstatus_indicate(fws, data);
1565			break;
1566		case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
1567			err = brcmf_fws_fifocreditback_indicate(fws, data);
1568			break;
1569		case BRCMF_FWS_TYPE_RSSI:
1570			brcmf_fws_rssi_indicate(fws, *data);
1571			break;
1572		case BRCMF_FWS_TYPE_TRANS_ID:
1573			brcmf_fws_dbg_seqnum_check(fws, data);
1574			break;
1575		case BRCMF_FWS_TYPE_PKTTAG:
1576		case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
1577		default:
1578			fws->stats.tlv_invalid_type++;
1579			break;
1580		}
1581		if (err == BRCMF_FWS_RET_OK_SCHEDULE)
1582			status = BRCMF_FWS_RET_OK_SCHEDULE;
1583		signal_data += len + 2;
1584		data_len -= len + 2;
1585	}
1586
1587	if (data_len != 0)
1588		fws->stats.tlv_parse_failed++;
1589
1590	if (status == BRCMF_FWS_RET_OK_SCHEDULE)
1591		brcmf_fws_schedule_deq(fws);
1592
1593	/* signalling processing result does
1594	 * not affect the actual ethernet packet.
1595	 */
1596	skb_pull(skb, signal_len);
1597
1598	/* this may be a signal-only packet
1599	 */
1600	if (skb->len == 0)
1601		fws->stats.header_only_pkt++;
1602
1603	return 0;
1604}
1605
1606static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
1607				   struct sk_buff *p)
1608{
1609	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
1610	struct brcmf_fws_mac_descriptor *entry = skcb->mac;
1611	u8 flags;
1612
1613	brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
1614	brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
1615	flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
1616	if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
1617		/*
1618		 * Indicate that this packet is being sent in response to an
1619		 * explicit request from the firmware side.
1620		 */
1621		flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
1622	}
1623	brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
1624	brcmf_fws_hdrpush(fws, p);
1625}
1626
1627static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
1628				   struct sk_buff *skb, int fifo)
1629{
1630	struct brcmf_fws_mac_descriptor *entry;
1631	struct sk_buff *pktout;
1632	int qidx, hslot;
1633	int rc = 0;
1634
1635	entry = brcmf_skbcb(skb)->mac;
1636	if (entry->occupied) {
1637		qidx = 2 * fifo;
1638		if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
1639			qidx++;
1640
1641		pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb);
1642		if (pktout == NULL) {
1643			brcmf_err("%s queue %d full\n", entry->name, qidx);
1644			rc = -ENOSPC;
1645		}
1646	} else {
1647		brcmf_err("%s entry removed\n", entry->name);
1648		rc = -ENOENT;
1649	}
1650
1651	if (rc) {
1652		fws->stats.rollback_failed++;
1653		hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1654		brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
1655				      hslot, 0);
1656	} else {
1657		fws->stats.rollback_success++;
1658		brcmf_fws_return_credits(fws, fifo, 1);
1659		brcmf_fws_macdesc_return_req_credit(skb);
1660	}
1661}
1662
1663static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
1664{
1665	int lender_ac;
1666
1667	if (time_after(fws->borrow_defer_timestamp, jiffies)) {
1668		fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
1669		return -ENAVAIL;
1670	}
1671
1672	for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
1673		if (fws->fifo_credit[lender_ac]) {
1674			fws->credits_borrowed[lender_ac]++;
1675			fws->fifo_credit[lender_ac]--;
1676			if (fws->fifo_credit[lender_ac] == 0)
1677				fws->fifo_credit_map &= ~(1 << lender_ac);
1678			fws->fifo_credit_map |= (1 << BRCMF_FWS_FIFO_AC_BE);
1679			brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac);
1680			return 0;
1681		}
1682	}
1683	fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
1684	return -ENAVAIL;
1685}
1686
1687static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
1688				struct sk_buff *skb)
1689{
1690	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
1691	struct brcmf_fws_mac_descriptor *entry;
1692	struct brcmf_bus *bus = fws->drvr->bus_if;
1693	int rc;
1694	u8 ifidx;
1695
1696	entry = skcb->mac;
1697	if (IS_ERR(entry))
1698		return PTR_ERR(entry);
1699
1700	brcmf_fws_precommit_skb(fws, fifo, skb);
1701	entry->transit_count++;
1702	if (entry->suppressed)
1703		entry->suppr_transit_count++;
1704	brcmf_fws_unlock(fws);
1705	rc = brcmf_bus_txdata(bus, skb);
1706	brcmf_fws_lock(fws);
1707	brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
1708		  skcb->if_flags, skcb->htod, rc);
1709	if (rc < 0) {
1710		entry->transit_count--;
1711		if (entry->suppressed)
1712			entry->suppr_transit_count--;
1713		brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
1714		goto rollback;
1715	}
1716
1717	fws->stats.pkt2bus++;
1718	fws->stats.send_pkts[fifo]++;
1719	if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
1720		fws->stats.requested_sent[fifo]++;
1721
1722	return rc;
1723
1724rollback:
1725	brcmf_fws_rollback_toq(fws, skb, fifo);
1726	return rc;
1727}
1728
1729static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
1730				  int fifo)
1731{
1732	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
1733	int rc, hslot;
1734
1735	hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
1736	brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
1737	brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]);
1738	brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
1739	rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
1740	if (!rc)
1741		skcb->mac->seq[fifo]++;
1742	else
1743		fws->stats.generic_error++;
1744	return rc;
1745}
1746
1747int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1748{
1749	struct brcmf_pub *drvr = ifp->drvr;
1750	struct brcmf_fws_info *fws = drvr->fws;
1751	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
1752	struct ethhdr *eh = (struct ethhdr *)(skb->data);
1753	int fifo = BRCMF_FWS_FIFO_BCMC;
1754	bool multicast = is_multicast_ether_addr(eh->h_dest);
1755	bool pae = eh->h_proto == htons(ETH_P_PAE);
1756
1757	brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
1758	/* determine the priority */
1759	if (!skb->priority)
1760		skb->priority = cfg80211_classify8021d(skb);
1761
1762	drvr->tx_multicast += !!multicast;
1763	if (pae)
1764		atomic_inc(&ifp->pend_8021x_cnt);
1765
1766	/* set control buffer information */
1767	skcb->if_flags = 0;
1768	skcb->state = BRCMF_FWS_SKBSTATE_NEW;
1769	brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
1770	if (!multicast)
1771		fifo = brcmf_fws_prio2fifo[skb->priority];
1772
1773	brcmf_fws_lock(fws);
1774	if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
1775		fws->borrow_defer_timestamp = jiffies +
1776					      BRCMF_FWS_BORROW_DEFER_PERIOD;
1777
1778	skcb->mac = brcmf_fws_macdesc_find(fws, ifp, eh->h_dest);
1779	brcmf_dbg(DATA, "%s mac %pM multi %d fifo %d\n", skcb->mac->name,
1780		  eh->h_dest, multicast, fifo);
1781	if (!brcmf_fws_assign_htod(fws, skb, fifo)) {
1782		brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
1783		brcmf_fws_schedule_deq(fws);
1784	} else {
1785		brcmf_err("drop skb: no hanger slot\n");
1786		if (pae) {
1787			atomic_dec(&ifp->pend_8021x_cnt);
1788			if (waitqueue_active(&ifp->pend_8021x_wait))
1789				wake_up(&ifp->pend_8021x_wait);
1790		}
1791		brcmu_pkt_buf_free_skb(skb);
1792	}
1793	brcmf_fws_unlock(fws);
1794	return 0;
1795}
1796
1797void brcmf_fws_reset_interface(struct brcmf_if *ifp)
1798{
1799	struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
1800
1801	brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
1802	if (!entry)
1803		return;
1804
1805	brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
1806}
1807
1808void brcmf_fws_add_interface(struct brcmf_if *ifp)
1809{
1810	struct brcmf_fws_info *fws = ifp->drvr->fws;
1811	struct brcmf_fws_mac_descriptor *entry;
1812
1813	if (!ifp->ndev)
1814		return;
1815
1816	entry = &fws->desc.iface[ifp->ifidx];
1817	ifp->fws_desc = entry;
1818	brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
1819	brcmf_fws_macdesc_set_name(fws, entry);
1820	brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
1821			BRCMF_FWS_PSQ_LEN);
1822	brcmf_dbg(TRACE, "added %s\n", entry->name);
1823}
1824
1825void brcmf_fws_del_interface(struct brcmf_if *ifp)
1826{
1827	struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
1828
1829	if (!entry)
1830		return;
1831
1832	brcmf_fws_lock(ifp->drvr->fws);
1833	ifp->fws_desc = NULL;
1834	brcmf_dbg(TRACE, "deleting %s\n", entry->name);
1835	brcmf_fws_macdesc_deinit(entry);
1836	brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
1837	brcmf_fws_unlock(ifp->drvr->fws);
1838}
1839
1840static void brcmf_fws_dequeue_worker(struct work_struct *worker)
1841{
1842	struct brcmf_fws_info *fws;
1843	struct brcmf_pub *drvr;
1844	struct sk_buff *skb;
1845	int fifo;
1846	u32 hslot;
1847	u32 ifidx;
1848	int ret;
1849
1850	fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
1851	drvr = fws->drvr;
1852
1853	brcmf_fws_lock(fws);
1854	for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked;
1855	     fifo--) {
1856		if (!brcmf_fws_fc_active(fws)) {
1857			while ((skb = brcmf_fws_deq(fws, fifo)) != NULL) {
1858				hslot = brcmf_skb_htod_tag_get_field(skb,
1859								     HSLOT);
1860				brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
1861							&skb, true);
1862				ifidx = brcmf_skb_if_flags_get_field(skb,
1863								     INDEX);
1864				brcmf_proto_hdrpush(drvr, ifidx, 0, skb);
1865				/* Use bus module to send data frame */
1866				brcmf_fws_unlock(fws);
1867				ret = brcmf_bus_txdata(drvr->bus_if, skb);
1868				brcmf_fws_lock(fws);
1869				if (ret < 0)
1870					brcmf_txfinalize(drvr, skb, false);
1871				if (fws->bus_flow_blocked)
1872					break;
1873			}
1874			continue;
1875		}
1876		while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) &&
1877		       (fifo == BRCMF_FWS_FIFO_BCMC))) {
1878			skb = brcmf_fws_deq(fws, fifo);
1879			if (!skb)
1880				break;
1881			fws->fifo_credit[fifo]--;
1882			if (brcmf_fws_commit_skb(fws, fifo, skb))
1883				break;
1884			if (fws->bus_flow_blocked)
1885				break;
1886		}
1887		if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
1888		    (fws->fifo_credit[fifo] == 0) &&
1889		    (!fws->bus_flow_blocked)) {
1890			while (brcmf_fws_borrow_credit(fws) == 0) {
1891				skb = brcmf_fws_deq(fws, fifo);
1892				if (!skb) {
1893					brcmf_fws_return_credits(fws, fifo, 1);
1894					break;
1895				}
1896				if (brcmf_fws_commit_skb(fws, fifo, skb))
1897					break;
1898				if (fws->bus_flow_blocked)
1899					break;
1900			}
1901		}
1902	}
1903	brcmf_fws_unlock(fws);
1904}
1905
1906int brcmf_fws_init(struct brcmf_pub *drvr)
1907{
1908	struct brcmf_fws_info *fws;
1909	u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
1910	int rc;
1911
1912	drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
1913	if (!drvr->fws) {
1914		rc = -ENOMEM;
1915		goto fail;
1916	}
1917
1918	fws = drvr->fws;
1919
1920	spin_lock_init(&fws->spinlock);
1921
1922	/* set linkage back */
1923	fws->drvr = drvr;
1924	fws->fcmode = fcmode;
1925
1926	fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
1927	if (fws->fws_wq == NULL) {
1928		brcmf_err("workqueue creation failed\n");
1929		rc = -EBADF;
1930		goto fail;
1931	}
1932	INIT_WORK(&fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
1933
1934	/* enable firmware signalling if fcmode active */
1935	if (fws->fcmode != BRCMF_FWS_FCMODE_NONE)
1936		tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
1937		       BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
1938		       BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE |
1939		       BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE;
1940
1941	rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
1942				 brcmf_fws_notify_credit_map);
1943	if (rc < 0) {
1944		brcmf_err("register credit map handler failed\n");
1945		goto fail;
1946	}
1947	rc = brcmf_fweh_register(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT,
1948				 brcmf_fws_notify_bcmc_credit_support);
1949	if (rc < 0) {
1950		brcmf_err("register bcmc credit handler failed\n");
1951		brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
1952		goto fail;
1953	}
1954
1955	/* Setting the iovar may fail if feature is unsupported
1956	 * so leave the rc as is so driver initialization can
1957	 * continue. Set mode back to none indicating not enabled.
1958	 */
1959	fws->fw_signals = true;
1960	if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) {
1961		brcmf_err("failed to set bdcv2 tlv signaling\n");
1962		fws->fcmode = BRCMF_FWS_FCMODE_NONE;
1963		fws->fw_signals = false;
1964	}
1965
1966	if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
1967		brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
1968
1969	brcmf_fws_hanger_init(&fws->hanger);
1970	brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
1971	brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
1972	brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
1973			BRCMF_FWS_PSQ_LEN);
1974
1975	/* create debugfs file for statistics */
1976	brcmf_debugfs_create_fws_stats(drvr, &fws->stats);
1977
1978	brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
1979		  fws->fw_signals ? "enabled" : "disabled", tlv);
1980	return 0;
1981
1982fail:
1983	brcmf_fws_deinit(drvr);
1984	return rc;
1985}
1986
1987void brcmf_fws_deinit(struct brcmf_pub *drvr)
1988{
1989	struct brcmf_fws_info *fws = drvr->fws;
1990
1991	if (!fws)
1992		return;
1993
1994	if (drvr->fws->fws_wq)
1995		destroy_workqueue(drvr->fws->fws_wq);
1996
1997	/* cleanup */
1998	brcmf_fws_lock(fws);
1999	brcmf_fws_cleanup(fws, -1);
2000	drvr->fws = NULL;
2001	brcmf_fws_unlock(fws);
2002
2003	/* free top structure */
2004	kfree(fws);
2005}
2006
2007bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
2008{
2009	if (!fws->creditmap_received)
2010		return false;
2011
2012	return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
2013}
2014
2015void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
2016{
2017	u32 hslot;
2018
2019	if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
2020		brcmu_pkt_buf_free_skb(skb);
2021		return;
2022	}
2023	brcmf_fws_lock(fws);
2024	hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
2025	brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0);
2026	brcmf_fws_unlock(fws);
2027}
2028
2029void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
2030{
2031	struct brcmf_fws_info *fws = drvr->fws;
2032
2033	fws->bus_flow_blocked = flow_blocked;
2034	if (!flow_blocked)
2035		brcmf_fws_schedule_deq(fws);
2036	else
2037		fws->stats.bus_flow_block++;
2038}
2039