xref: /freebsd/sys/contrib/dev/broadcom/brcm80211/brcmfmac/flowring.c (revision 902136e0fe112383ec64d2ef43a446063b5e6417)
1b4c3e9b5SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2b4c3e9b5SBjoern A. Zeeb /*
3b4c3e9b5SBjoern A. Zeeb  * Copyright (c) 2014 Broadcom Corporation
4b4c3e9b5SBjoern A. Zeeb  */
5b4c3e9b5SBjoern A. Zeeb 
6b4c3e9b5SBjoern A. Zeeb 
7b4c3e9b5SBjoern A. Zeeb #include <linux/types.h>
8b4c3e9b5SBjoern A. Zeeb #include <linux/netdevice.h>
9b4c3e9b5SBjoern A. Zeeb #include <linux/etherdevice.h>
10b4c3e9b5SBjoern A. Zeeb #include <brcmu_utils.h>
11b4c3e9b5SBjoern A. Zeeb 
12b4c3e9b5SBjoern A. Zeeb #include "core.h"
13b4c3e9b5SBjoern A. Zeeb #include "debug.h"
14b4c3e9b5SBjoern A. Zeeb #include "bus.h"
15b4c3e9b5SBjoern A. Zeeb #include "proto.h"
16b4c3e9b5SBjoern A. Zeeb #include "flowring.h"
17b4c3e9b5SBjoern A. Zeeb #include "msgbuf.h"
18b4c3e9b5SBjoern A. Zeeb #include "common.h"
19b4c3e9b5SBjoern A. Zeeb 
20b4c3e9b5SBjoern A. Zeeb 
21b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_HIGH		1024
22b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_LOW		(BRCMF_FLOWRING_HIGH - 256)
23b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_INVALID_IFIDX	0xff
24b4c3e9b5SBjoern A. Zeeb 
25b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
26b4c3e9b5SBjoern A. Zeeb #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
27b4c3e9b5SBjoern A. Zeeb 
28b4c3e9b5SBjoern A. Zeeb static const u8 brcmf_flowring_prio2fifo[] = {
29b4c3e9b5SBjoern A. Zeeb 	0,
30b4c3e9b5SBjoern A. Zeeb 	1,
31b4c3e9b5SBjoern A. Zeeb 	1,
32b4c3e9b5SBjoern A. Zeeb 	0,
33b4c3e9b5SBjoern A. Zeeb 	2,
34b4c3e9b5SBjoern A. Zeeb 	2,
35b4c3e9b5SBjoern A. Zeeb 	3,
36b4c3e9b5SBjoern A. Zeeb 	3
37b4c3e9b5SBjoern A. Zeeb };
38b4c3e9b5SBjoern A. Zeeb 
39b4c3e9b5SBjoern A. Zeeb static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
40b4c3e9b5SBjoern A. Zeeb 
41b4c3e9b5SBjoern A. Zeeb 
42b4c3e9b5SBjoern A. Zeeb static bool
brcmf_flowring_is_tdls_mac(struct brcmf_flowring * flow,u8 mac[ETH_ALEN])43b4c3e9b5SBjoern A. Zeeb brcmf_flowring_is_tdls_mac(struct brcmf_flowring *flow, u8 mac[ETH_ALEN])
44b4c3e9b5SBjoern A. Zeeb {
45b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_tdls_entry *search;
46b4c3e9b5SBjoern A. Zeeb 
47b4c3e9b5SBjoern A. Zeeb 	search = flow->tdls_entry;
48b4c3e9b5SBjoern A. Zeeb 
49b4c3e9b5SBjoern A. Zeeb 	while (search) {
50b4c3e9b5SBjoern A. Zeeb 		if (memcmp(search->mac, mac, ETH_ALEN) == 0)
51b4c3e9b5SBjoern A. Zeeb 			return true;
52b4c3e9b5SBjoern A. Zeeb 		search = search->next;
53b4c3e9b5SBjoern A. Zeeb 	}
54b4c3e9b5SBjoern A. Zeeb 
55b4c3e9b5SBjoern A. Zeeb 	return false;
56b4c3e9b5SBjoern A. Zeeb }
57b4c3e9b5SBjoern A. Zeeb 
58b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_lookup(struct brcmf_flowring * flow,u8 da[ETH_ALEN],u8 prio,u8 ifidx)59b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
60b4c3e9b5SBjoern A. Zeeb 			  u8 prio, u8 ifidx)
61b4c3e9b5SBjoern A. Zeeb {
62b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_hash *hash;
63b4c3e9b5SBjoern A. Zeeb 	u16 hash_idx;
64b4c3e9b5SBjoern A. Zeeb 	u32 i;
65b4c3e9b5SBjoern A. Zeeb 	bool found;
66b4c3e9b5SBjoern A. Zeeb 	bool sta;
67b4c3e9b5SBjoern A. Zeeb 	u8 fifo;
68*902136e0SBjoern A. Zeeb #if defined(__linux__)
69b4c3e9b5SBjoern A. Zeeb 	u8 *mac;
70*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
71*902136e0SBjoern A. Zeeb 	const u8 *mac;
72*902136e0SBjoern A. Zeeb #endif
73b4c3e9b5SBjoern A. Zeeb 
74b4c3e9b5SBjoern A. Zeeb 	fifo = brcmf_flowring_prio2fifo[prio];
75b4c3e9b5SBjoern A. Zeeb 	sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
76b4c3e9b5SBjoern A. Zeeb 	mac = da;
77b4c3e9b5SBjoern A. Zeeb 	if ((!sta) && (is_multicast_ether_addr(da))) {
78*902136e0SBjoern A. Zeeb #if defined(__linux__)
79b4c3e9b5SBjoern A. Zeeb 		mac = (u8 *)ALLFFMAC;
80*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
81*902136e0SBjoern A. Zeeb 		mac = ALLFFMAC;
82*902136e0SBjoern A. Zeeb #endif
83b4c3e9b5SBjoern A. Zeeb 		fifo = 0;
84b4c3e9b5SBjoern A. Zeeb 	}
85b4c3e9b5SBjoern A. Zeeb 	if ((sta) && (flow->tdls_active) &&
86b4c3e9b5SBjoern A. Zeeb 	    (brcmf_flowring_is_tdls_mac(flow, da))) {
87b4c3e9b5SBjoern A. Zeeb 		sta = false;
88b4c3e9b5SBjoern A. Zeeb 	}
89b4c3e9b5SBjoern A. Zeeb 	hash_idx =  sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
90b4c3e9b5SBjoern A. Zeeb 			  BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
91b4c3e9b5SBjoern A. Zeeb 	hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
92b4c3e9b5SBjoern A. Zeeb 	found = false;
93b4c3e9b5SBjoern A. Zeeb 	hash = flow->hash;
94b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
95b4c3e9b5SBjoern A. Zeeb 		if ((sta || (memcmp(hash[hash_idx].mac, mac, ETH_ALEN) == 0)) &&
96b4c3e9b5SBjoern A. Zeeb 		    (hash[hash_idx].fifo == fifo) &&
97b4c3e9b5SBjoern A. Zeeb 		    (hash[hash_idx].ifidx == ifidx)) {
98b4c3e9b5SBjoern A. Zeeb 			found = true;
99b4c3e9b5SBjoern A. Zeeb 			break;
100b4c3e9b5SBjoern A. Zeeb 		}
101b4c3e9b5SBjoern A. Zeeb 		hash_idx++;
102b4c3e9b5SBjoern A. Zeeb 		hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
103b4c3e9b5SBjoern A. Zeeb 	}
104b4c3e9b5SBjoern A. Zeeb 	if (found)
105b4c3e9b5SBjoern A. Zeeb 		return hash[hash_idx].flowid;
106b4c3e9b5SBjoern A. Zeeb 
107b4c3e9b5SBjoern A. Zeeb 	return BRCMF_FLOWRING_INVALID_ID;
108b4c3e9b5SBjoern A. Zeeb }
109b4c3e9b5SBjoern A. Zeeb 
110b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_create(struct brcmf_flowring * flow,u8 da[ETH_ALEN],u8 prio,u8 ifidx)111b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
112b4c3e9b5SBjoern A. Zeeb 			  u8 prio, u8 ifidx)
113b4c3e9b5SBjoern A. Zeeb {
114b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
115b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_hash *hash;
116b4c3e9b5SBjoern A. Zeeb 	u16 hash_idx;
117b4c3e9b5SBjoern A. Zeeb 	u32 i;
118b4c3e9b5SBjoern A. Zeeb 	bool found;
119b4c3e9b5SBjoern A. Zeeb 	u8 fifo;
120b4c3e9b5SBjoern A. Zeeb 	bool sta;
121*902136e0SBjoern A. Zeeb #if defined(__linux__)
122b4c3e9b5SBjoern A. Zeeb 	u8 *mac;
123*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
124*902136e0SBjoern A. Zeeb 	const u8 *mac;
125*902136e0SBjoern A. Zeeb #endif
126b4c3e9b5SBjoern A. Zeeb 
127b4c3e9b5SBjoern A. Zeeb 	fifo = brcmf_flowring_prio2fifo[prio];
128b4c3e9b5SBjoern A. Zeeb 	sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
129b4c3e9b5SBjoern A. Zeeb 	mac = da;
130b4c3e9b5SBjoern A. Zeeb 	if ((!sta) && (is_multicast_ether_addr(da))) {
131*902136e0SBjoern A. Zeeb #if defined(__linux__)
132b4c3e9b5SBjoern A. Zeeb 		mac = (u8 *)ALLFFMAC;
133*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
134*902136e0SBjoern A. Zeeb 		mac = ALLFFMAC;
135*902136e0SBjoern A. Zeeb #endif
136b4c3e9b5SBjoern A. Zeeb 		fifo = 0;
137b4c3e9b5SBjoern A. Zeeb 	}
138b4c3e9b5SBjoern A. Zeeb 	if ((sta) && (flow->tdls_active) &&
139b4c3e9b5SBjoern A. Zeeb 	    (brcmf_flowring_is_tdls_mac(flow, da))) {
140b4c3e9b5SBjoern A. Zeeb 		sta = false;
141b4c3e9b5SBjoern A. Zeeb 	}
142b4c3e9b5SBjoern A. Zeeb 	hash_idx =  sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
143b4c3e9b5SBjoern A. Zeeb 			  BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
144b4c3e9b5SBjoern A. Zeeb 	hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
145b4c3e9b5SBjoern A. Zeeb 	found = false;
146b4c3e9b5SBjoern A. Zeeb 	hash = flow->hash;
147b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
148b4c3e9b5SBjoern A. Zeeb 		if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) &&
149b4c3e9b5SBjoern A. Zeeb 		    (is_zero_ether_addr(hash[hash_idx].mac))) {
150b4c3e9b5SBjoern A. Zeeb 			found = true;
151b4c3e9b5SBjoern A. Zeeb 			break;
152b4c3e9b5SBjoern A. Zeeb 		}
153b4c3e9b5SBjoern A. Zeeb 		hash_idx++;
154b4c3e9b5SBjoern A. Zeeb 		hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
155b4c3e9b5SBjoern A. Zeeb 	}
156b4c3e9b5SBjoern A. Zeeb 	if (found) {
157b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < flow->nrofrings; i++) {
158b4c3e9b5SBjoern A. Zeeb 			if (flow->rings[i] == NULL)
159b4c3e9b5SBjoern A. Zeeb 				break;
160b4c3e9b5SBjoern A. Zeeb 		}
161b4c3e9b5SBjoern A. Zeeb 		if (i == flow->nrofrings)
162b4c3e9b5SBjoern A. Zeeb 			return -ENOMEM;
163b4c3e9b5SBjoern A. Zeeb 
164b4c3e9b5SBjoern A. Zeeb 		ring = kzalloc(sizeof(*ring), GFP_ATOMIC);
165b4c3e9b5SBjoern A. Zeeb 		if (!ring)
166b4c3e9b5SBjoern A. Zeeb 			return -ENOMEM;
167b4c3e9b5SBjoern A. Zeeb 
168b4c3e9b5SBjoern A. Zeeb 		memcpy(hash[hash_idx].mac, mac, ETH_ALEN);
169b4c3e9b5SBjoern A. Zeeb 		hash[hash_idx].fifo = fifo;
170b4c3e9b5SBjoern A. Zeeb 		hash[hash_idx].ifidx = ifidx;
171b4c3e9b5SBjoern A. Zeeb 		hash[hash_idx].flowid = i;
172b4c3e9b5SBjoern A. Zeeb 
173b4c3e9b5SBjoern A. Zeeb 		ring->hash_id = hash_idx;
174b4c3e9b5SBjoern A. Zeeb 		ring->status = RING_CLOSED;
175b4c3e9b5SBjoern A. Zeeb 		skb_queue_head_init(&ring->skblist);
176b4c3e9b5SBjoern A. Zeeb 		flow->rings[i] = ring;
177b4c3e9b5SBjoern A. Zeeb 
178b4c3e9b5SBjoern A. Zeeb 		return i;
179b4c3e9b5SBjoern A. Zeeb 	}
180b4c3e9b5SBjoern A. Zeeb 	return BRCMF_FLOWRING_INVALID_ID;
181b4c3e9b5SBjoern A. Zeeb }
182b4c3e9b5SBjoern A. Zeeb 
183b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_tid(struct brcmf_flowring * flow,u16 flowid)184b4c3e9b5SBjoern A. Zeeb u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
185b4c3e9b5SBjoern A. Zeeb {
186b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
187b4c3e9b5SBjoern A. Zeeb 
188b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
189b4c3e9b5SBjoern A. Zeeb 
190b4c3e9b5SBjoern A. Zeeb 	return flow->hash[ring->hash_id].fifo;
191b4c3e9b5SBjoern A. Zeeb }
192b4c3e9b5SBjoern A. Zeeb 
193b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_block(struct brcmf_flowring * flow,u16 flowid,bool blocked)194b4c3e9b5SBjoern A. Zeeb static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
195b4c3e9b5SBjoern A. Zeeb 				 bool blocked)
196b4c3e9b5SBjoern A. Zeeb {
197b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
198b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if;
199b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr;
200b4c3e9b5SBjoern A. Zeeb 	struct brcmf_if *ifp;
201b4c3e9b5SBjoern A. Zeeb 	bool currently_blocked;
202b4c3e9b5SBjoern A. Zeeb 	int i;
203b4c3e9b5SBjoern A. Zeeb 	u8 ifidx;
204b4c3e9b5SBjoern A. Zeeb 	unsigned long flags;
205b4c3e9b5SBjoern A. Zeeb 
206b4c3e9b5SBjoern A. Zeeb 	spin_lock_irqsave(&flow->block_lock, flags);
207b4c3e9b5SBjoern A. Zeeb 
208b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
209b4c3e9b5SBjoern A. Zeeb 	if (ring->blocked == blocked) {
210b4c3e9b5SBjoern A. Zeeb 		spin_unlock_irqrestore(&flow->block_lock, flags);
211b4c3e9b5SBjoern A. Zeeb 		return;
212b4c3e9b5SBjoern A. Zeeb 	}
213b4c3e9b5SBjoern A. Zeeb 	ifidx = brcmf_flowring_ifidx_get(flow, flowid);
214b4c3e9b5SBjoern A. Zeeb 
215b4c3e9b5SBjoern A. Zeeb 	currently_blocked = false;
216b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < flow->nrofrings; i++) {
217b4c3e9b5SBjoern A. Zeeb 		if ((flow->rings[i]) && (i != flowid)) {
218b4c3e9b5SBjoern A. Zeeb 			ring = flow->rings[i];
219b4c3e9b5SBjoern A. Zeeb 			if ((ring->status == RING_OPEN) &&
220b4c3e9b5SBjoern A. Zeeb 			    (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
221b4c3e9b5SBjoern A. Zeeb 				if (ring->blocked) {
222b4c3e9b5SBjoern A. Zeeb 					currently_blocked = true;
223b4c3e9b5SBjoern A. Zeeb 					break;
224b4c3e9b5SBjoern A. Zeeb 				}
225b4c3e9b5SBjoern A. Zeeb 			}
226b4c3e9b5SBjoern A. Zeeb 		}
227b4c3e9b5SBjoern A. Zeeb 	}
228b4c3e9b5SBjoern A. Zeeb 	flow->rings[flowid]->blocked = blocked;
229b4c3e9b5SBjoern A. Zeeb 	if (currently_blocked) {
230b4c3e9b5SBjoern A. Zeeb 		spin_unlock_irqrestore(&flow->block_lock, flags);
231b4c3e9b5SBjoern A. Zeeb 		return;
232b4c3e9b5SBjoern A. Zeeb 	}
233b4c3e9b5SBjoern A. Zeeb 
234b4c3e9b5SBjoern A. Zeeb 	bus_if = dev_get_drvdata(flow->dev);
235b4c3e9b5SBjoern A. Zeeb 	drvr = bus_if->drvr;
236b4c3e9b5SBjoern A. Zeeb 	ifp = brcmf_get_ifp(drvr, ifidx);
237b4c3e9b5SBjoern A. Zeeb 	brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
238b4c3e9b5SBjoern A. Zeeb 
239b4c3e9b5SBjoern A. Zeeb 	spin_unlock_irqrestore(&flow->block_lock, flags);
240b4c3e9b5SBjoern A. Zeeb }
241b4c3e9b5SBjoern A. Zeeb 
242b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_delete(struct brcmf_flowring * flow,u16 flowid)243b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
244b4c3e9b5SBjoern A. Zeeb {
245b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
246b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
247b4c3e9b5SBjoern A. Zeeb 	struct brcmf_if *ifp;
248b4c3e9b5SBjoern A. Zeeb 	u16 hash_idx;
249b4c3e9b5SBjoern A. Zeeb 	u8 ifidx;
250b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *skb;
251b4c3e9b5SBjoern A. Zeeb 
252b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
253b4c3e9b5SBjoern A. Zeeb 	if (!ring)
254b4c3e9b5SBjoern A. Zeeb 		return;
255b4c3e9b5SBjoern A. Zeeb 
256b4c3e9b5SBjoern A. Zeeb 	ifidx = brcmf_flowring_ifidx_get(flow, flowid);
257b4c3e9b5SBjoern A. Zeeb 	ifp = brcmf_get_ifp(bus_if->drvr, ifidx);
258b4c3e9b5SBjoern A. Zeeb 
259b4c3e9b5SBjoern A. Zeeb 	brcmf_flowring_block(flow, flowid, false);
260b4c3e9b5SBjoern A. Zeeb 	hash_idx = ring->hash_id;
261b4c3e9b5SBjoern A. Zeeb 	flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
262b4c3e9b5SBjoern A. Zeeb 	eth_zero_addr(flow->hash[hash_idx].mac);
263b4c3e9b5SBjoern A. Zeeb 	flow->rings[flowid] = NULL;
264b4c3e9b5SBjoern A. Zeeb 
265b4c3e9b5SBjoern A. Zeeb 	skb = skb_dequeue(&ring->skblist);
266b4c3e9b5SBjoern A. Zeeb 	while (skb) {
267b4c3e9b5SBjoern A. Zeeb 		brcmf_txfinalize(ifp, skb, false);
268b4c3e9b5SBjoern A. Zeeb 		skb = skb_dequeue(&ring->skblist);
269b4c3e9b5SBjoern A. Zeeb 	}
270b4c3e9b5SBjoern A. Zeeb 
271b4c3e9b5SBjoern A. Zeeb 	kfree(ring);
272b4c3e9b5SBjoern A. Zeeb }
273b4c3e9b5SBjoern A. Zeeb 
274b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_enqueue(struct brcmf_flowring * flow,u16 flowid,struct sk_buff * skb)275b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
276b4c3e9b5SBjoern A. Zeeb 			   struct sk_buff *skb)
277b4c3e9b5SBjoern A. Zeeb {
278b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
279b4c3e9b5SBjoern A. Zeeb 
280b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
281b4c3e9b5SBjoern A. Zeeb 
282b4c3e9b5SBjoern A. Zeeb 	skb_queue_tail(&ring->skblist, skb);
283b4c3e9b5SBjoern A. Zeeb 
284b4c3e9b5SBjoern A. Zeeb 	if (!ring->blocked &&
285b4c3e9b5SBjoern A. Zeeb 	    (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
286b4c3e9b5SBjoern A. Zeeb 		brcmf_flowring_block(flow, flowid, true);
287b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
288b4c3e9b5SBjoern A. Zeeb 		/* To prevent (work around) possible race condition, check
289b4c3e9b5SBjoern A. Zeeb 		 * queue len again. It is also possible to use locking to
290b4c3e9b5SBjoern A. Zeeb 		 * protect, but that is undesirable for every enqueue and
291b4c3e9b5SBjoern A. Zeeb 		 * dequeue. This simple check will solve a possible race
292b4c3e9b5SBjoern A. Zeeb 		 * condition if it occurs.
293b4c3e9b5SBjoern A. Zeeb 		 */
294b4c3e9b5SBjoern A. Zeeb 		if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
295b4c3e9b5SBjoern A. Zeeb 			brcmf_flowring_block(flow, flowid, false);
296b4c3e9b5SBjoern A. Zeeb 	}
297b4c3e9b5SBjoern A. Zeeb 	return skb_queue_len(&ring->skblist);
298b4c3e9b5SBjoern A. Zeeb }
299b4c3e9b5SBjoern A. Zeeb 
300b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_dequeue(struct brcmf_flowring * flow,u16 flowid)301b4c3e9b5SBjoern A. Zeeb struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
302b4c3e9b5SBjoern A. Zeeb {
303b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
304b4c3e9b5SBjoern A. Zeeb 	struct sk_buff *skb;
305b4c3e9b5SBjoern A. Zeeb 
306b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
307b4c3e9b5SBjoern A. Zeeb 	if (ring->status != RING_OPEN)
308b4c3e9b5SBjoern A. Zeeb 		return NULL;
309b4c3e9b5SBjoern A. Zeeb 
310b4c3e9b5SBjoern A. Zeeb 	skb = skb_dequeue(&ring->skblist);
311b4c3e9b5SBjoern A. Zeeb 
312b4c3e9b5SBjoern A. Zeeb 	if (ring->blocked &&
313b4c3e9b5SBjoern A. Zeeb 	    (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
314b4c3e9b5SBjoern A. Zeeb 		brcmf_flowring_block(flow, flowid, false);
315b4c3e9b5SBjoern A. Zeeb 		brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
316b4c3e9b5SBjoern A. Zeeb 	}
317b4c3e9b5SBjoern A. Zeeb 
318b4c3e9b5SBjoern A. Zeeb 	return skb;
319b4c3e9b5SBjoern A. Zeeb }
320b4c3e9b5SBjoern A. Zeeb 
321b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_reinsert(struct brcmf_flowring * flow,u16 flowid,struct sk_buff * skb)322b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
323b4c3e9b5SBjoern A. Zeeb 			     struct sk_buff *skb)
324b4c3e9b5SBjoern A. Zeeb {
325b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
326b4c3e9b5SBjoern A. Zeeb 
327b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
328b4c3e9b5SBjoern A. Zeeb 
329b4c3e9b5SBjoern A. Zeeb 	skb_queue_head(&ring->skblist, skb);
330b4c3e9b5SBjoern A. Zeeb }
331b4c3e9b5SBjoern A. Zeeb 
332b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_qlen(struct brcmf_flowring * flow,u16 flowid)333b4c3e9b5SBjoern A. Zeeb u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
334b4c3e9b5SBjoern A. Zeeb {
335b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
336b4c3e9b5SBjoern A. Zeeb 
337b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
338b4c3e9b5SBjoern A. Zeeb 	if (!ring)
339b4c3e9b5SBjoern A. Zeeb 		return 0;
340b4c3e9b5SBjoern A. Zeeb 
341b4c3e9b5SBjoern A. Zeeb 	if (ring->status != RING_OPEN)
342b4c3e9b5SBjoern A. Zeeb 		return 0;
343b4c3e9b5SBjoern A. Zeeb 
344b4c3e9b5SBjoern A. Zeeb 	return skb_queue_len(&ring->skblist);
345b4c3e9b5SBjoern A. Zeeb }
346b4c3e9b5SBjoern A. Zeeb 
347b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_open(struct brcmf_flowring * flow,u16 flowid)348b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
349b4c3e9b5SBjoern A. Zeeb {
350b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
351b4c3e9b5SBjoern A. Zeeb 
352b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
353b4c3e9b5SBjoern A. Zeeb 	if (!ring) {
354b4c3e9b5SBjoern A. Zeeb 		brcmf_err("Ring NULL, for flowid %d\n", flowid);
355b4c3e9b5SBjoern A. Zeeb 		return;
356b4c3e9b5SBjoern A. Zeeb 	}
357b4c3e9b5SBjoern A. Zeeb 
358b4c3e9b5SBjoern A. Zeeb 	ring->status = RING_OPEN;
359b4c3e9b5SBjoern A. Zeeb }
360b4c3e9b5SBjoern A. Zeeb 
361b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_ifidx_get(struct brcmf_flowring * flow,u16 flowid)362b4c3e9b5SBjoern A. Zeeb u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
363b4c3e9b5SBjoern A. Zeeb {
364b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_ring *ring;
365b4c3e9b5SBjoern A. Zeeb 	u16 hash_idx;
366b4c3e9b5SBjoern A. Zeeb 
367b4c3e9b5SBjoern A. Zeeb 	ring = flow->rings[flowid];
368b4c3e9b5SBjoern A. Zeeb 	hash_idx = ring->hash_id;
369b4c3e9b5SBjoern A. Zeeb 
370b4c3e9b5SBjoern A. Zeeb 	return flow->hash[hash_idx].ifidx;
371b4c3e9b5SBjoern A. Zeeb }
372b4c3e9b5SBjoern A. Zeeb 
373b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_attach(struct device * dev,u16 nrofrings)374b4c3e9b5SBjoern A. Zeeb struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
375b4c3e9b5SBjoern A. Zeeb {
376b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring *flow;
377b4c3e9b5SBjoern A. Zeeb 	u32 i;
378b4c3e9b5SBjoern A. Zeeb 
379b4c3e9b5SBjoern A. Zeeb 	flow = kzalloc(sizeof(*flow), GFP_KERNEL);
380b4c3e9b5SBjoern A. Zeeb 	if (flow) {
381b4c3e9b5SBjoern A. Zeeb 		flow->dev = dev;
382b4c3e9b5SBjoern A. Zeeb 		flow->nrofrings = nrofrings;
383b4c3e9b5SBjoern A. Zeeb 		spin_lock_init(&flow->block_lock);
384b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
385b4c3e9b5SBjoern A. Zeeb 			flow->addr_mode[i] = ADDR_INDIRECT;
386b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
387b4c3e9b5SBjoern A. Zeeb 			flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
388b4c3e9b5SBjoern A. Zeeb 		flow->rings = kcalloc(nrofrings, sizeof(*flow->rings),
389b4c3e9b5SBjoern A. Zeeb 				      GFP_KERNEL);
390b4c3e9b5SBjoern A. Zeeb 		if (!flow->rings) {
391b4c3e9b5SBjoern A. Zeeb 			kfree(flow);
392b4c3e9b5SBjoern A. Zeeb 			flow = NULL;
393b4c3e9b5SBjoern A. Zeeb 		}
394b4c3e9b5SBjoern A. Zeeb 	}
395b4c3e9b5SBjoern A. Zeeb 
396b4c3e9b5SBjoern A. Zeeb 	return flow;
397b4c3e9b5SBjoern A. Zeeb }
398b4c3e9b5SBjoern A. Zeeb 
399b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_detach(struct brcmf_flowring * flow)400b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_detach(struct brcmf_flowring *flow)
401b4c3e9b5SBjoern A. Zeeb {
402b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
403b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = bus_if->drvr;
404b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_tdls_entry *search;
405b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_tdls_entry *remove;
406b4c3e9b5SBjoern A. Zeeb 	u16 flowid;
407b4c3e9b5SBjoern A. Zeeb 
408b4c3e9b5SBjoern A. Zeeb 	for (flowid = 0; flowid < flow->nrofrings; flowid++) {
409b4c3e9b5SBjoern A. Zeeb 		if (flow->rings[flowid])
410b4c3e9b5SBjoern A. Zeeb 			brcmf_msgbuf_delete_flowring(drvr, flowid);
411b4c3e9b5SBjoern A. Zeeb 	}
412b4c3e9b5SBjoern A. Zeeb 
413b4c3e9b5SBjoern A. Zeeb 	search = flow->tdls_entry;
414b4c3e9b5SBjoern A. Zeeb 	while (search) {
415b4c3e9b5SBjoern A. Zeeb 		remove = search;
416b4c3e9b5SBjoern A. Zeeb 		search = search->next;
417b4c3e9b5SBjoern A. Zeeb 		kfree(remove);
418b4c3e9b5SBjoern A. Zeeb 	}
419b4c3e9b5SBjoern A. Zeeb 	kfree(flow->rings);
420b4c3e9b5SBjoern A. Zeeb 	kfree(flow);
421b4c3e9b5SBjoern A. Zeeb }
422b4c3e9b5SBjoern A. Zeeb 
423b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_configure_addr_mode(struct brcmf_flowring * flow,int ifidx,enum proto_addr_mode addr_mode)424b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
425b4c3e9b5SBjoern A. Zeeb 					enum proto_addr_mode addr_mode)
426b4c3e9b5SBjoern A. Zeeb {
427b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
428b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = bus_if->drvr;
429b4c3e9b5SBjoern A. Zeeb 	u32 i;
430b4c3e9b5SBjoern A. Zeeb 	u16 flowid;
431b4c3e9b5SBjoern A. Zeeb 
432b4c3e9b5SBjoern A. Zeeb 	if (flow->addr_mode[ifidx] != addr_mode) {
433b4c3e9b5SBjoern A. Zeeb 		for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
434b4c3e9b5SBjoern A. Zeeb 			if (flow->hash[i].ifidx == ifidx) {
435b4c3e9b5SBjoern A. Zeeb 				flowid = flow->hash[i].flowid;
436b4c3e9b5SBjoern A. Zeeb 				if (flow->rings[flowid]->status != RING_OPEN)
437b4c3e9b5SBjoern A. Zeeb 					continue;
438b4c3e9b5SBjoern A. Zeeb 				brcmf_msgbuf_delete_flowring(drvr, flowid);
439b4c3e9b5SBjoern A. Zeeb 			}
440b4c3e9b5SBjoern A. Zeeb 		}
441b4c3e9b5SBjoern A. Zeeb 		flow->addr_mode[ifidx] = addr_mode;
442b4c3e9b5SBjoern A. Zeeb 	}
443b4c3e9b5SBjoern A. Zeeb }
444b4c3e9b5SBjoern A. Zeeb 
445b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_delete_peer(struct brcmf_flowring * flow,int ifidx,u8 peer[ETH_ALEN])446b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
447*902136e0SBjoern A. Zeeb #if defined(__linux__)
448b4c3e9b5SBjoern A. Zeeb 				u8 peer[ETH_ALEN])
449*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
450*902136e0SBjoern A. Zeeb 				const u8 peer[ETH_ALEN])
451*902136e0SBjoern A. Zeeb #endif
452b4c3e9b5SBjoern A. Zeeb {
453b4c3e9b5SBjoern A. Zeeb 	struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
454b4c3e9b5SBjoern A. Zeeb 	struct brcmf_pub *drvr = bus_if->drvr;
455b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_hash *hash;
456b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_tdls_entry *prev;
457b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_tdls_entry *search;
458b4c3e9b5SBjoern A. Zeeb 	u32 i;
459b4c3e9b5SBjoern A. Zeeb 	u16 flowid;
460b4c3e9b5SBjoern A. Zeeb 	bool sta;
461b4c3e9b5SBjoern A. Zeeb 
462b4c3e9b5SBjoern A. Zeeb 	sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
463b4c3e9b5SBjoern A. Zeeb 
464b4c3e9b5SBjoern A. Zeeb 	search = flow->tdls_entry;
465b4c3e9b5SBjoern A. Zeeb 	prev = NULL;
466b4c3e9b5SBjoern A. Zeeb 	while (search) {
467b4c3e9b5SBjoern A. Zeeb 		if (memcmp(search->mac, peer, ETH_ALEN) == 0) {
468b4c3e9b5SBjoern A. Zeeb 			sta = false;
469b4c3e9b5SBjoern A. Zeeb 			break;
470b4c3e9b5SBjoern A. Zeeb 		}
471b4c3e9b5SBjoern A. Zeeb 		prev = search;
472b4c3e9b5SBjoern A. Zeeb 		search = search->next;
473b4c3e9b5SBjoern A. Zeeb 	}
474b4c3e9b5SBjoern A. Zeeb 
475b4c3e9b5SBjoern A. Zeeb 	hash = flow->hash;
476b4c3e9b5SBjoern A. Zeeb 	for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
477b4c3e9b5SBjoern A. Zeeb 		if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
478b4c3e9b5SBjoern A. Zeeb 		    (hash[i].ifidx == ifidx)) {
479b4c3e9b5SBjoern A. Zeeb 			flowid = flow->hash[i].flowid;
480b4c3e9b5SBjoern A. Zeeb 			if (flow->rings[flowid]->status == RING_OPEN)
481b4c3e9b5SBjoern A. Zeeb 				brcmf_msgbuf_delete_flowring(drvr, flowid);
482b4c3e9b5SBjoern A. Zeeb 		}
483b4c3e9b5SBjoern A. Zeeb 	}
484b4c3e9b5SBjoern A. Zeeb 
485b4c3e9b5SBjoern A. Zeeb 	if (search) {
486b4c3e9b5SBjoern A. Zeeb 		if (prev)
487b4c3e9b5SBjoern A. Zeeb 			prev->next = search->next;
488b4c3e9b5SBjoern A. Zeeb 		else
489b4c3e9b5SBjoern A. Zeeb 			flow->tdls_entry = search->next;
490b4c3e9b5SBjoern A. Zeeb 		kfree(search);
491b4c3e9b5SBjoern A. Zeeb 		if (flow->tdls_entry == NULL)
492b4c3e9b5SBjoern A. Zeeb 			flow->tdls_active = false;
493b4c3e9b5SBjoern A. Zeeb 	}
494b4c3e9b5SBjoern A. Zeeb }
495b4c3e9b5SBjoern A. Zeeb 
496b4c3e9b5SBjoern A. Zeeb 
brcmf_flowring_add_tdls_peer(struct brcmf_flowring * flow,int ifidx,u8 peer[ETH_ALEN])497b4c3e9b5SBjoern A. Zeeb void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx,
498*902136e0SBjoern A. Zeeb #if defined(__linux__)
499b4c3e9b5SBjoern A. Zeeb 				  u8 peer[ETH_ALEN])
500*902136e0SBjoern A. Zeeb #elif defined(__FreeBSD__)
501*902136e0SBjoern A. Zeeb 				  const u8 peer[ETH_ALEN])
502*902136e0SBjoern A. Zeeb #endif
503b4c3e9b5SBjoern A. Zeeb {
504b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_tdls_entry *tdls_entry;
505b4c3e9b5SBjoern A. Zeeb 	struct brcmf_flowring_tdls_entry *search;
506b4c3e9b5SBjoern A. Zeeb 
507b4c3e9b5SBjoern A. Zeeb 	tdls_entry = kzalloc(sizeof(*tdls_entry), GFP_ATOMIC);
508b4c3e9b5SBjoern A. Zeeb 	if (tdls_entry == NULL)
509b4c3e9b5SBjoern A. Zeeb 		return;
510b4c3e9b5SBjoern A. Zeeb 
511b4c3e9b5SBjoern A. Zeeb 	memcpy(tdls_entry->mac, peer, ETH_ALEN);
512b4c3e9b5SBjoern A. Zeeb 	tdls_entry->next = NULL;
513b4c3e9b5SBjoern A. Zeeb 	if (flow->tdls_entry == NULL) {
514b4c3e9b5SBjoern A. Zeeb 		flow->tdls_entry = tdls_entry;
515b4c3e9b5SBjoern A. Zeeb 	} else {
516b4c3e9b5SBjoern A. Zeeb 		search = flow->tdls_entry;
517b4c3e9b5SBjoern A. Zeeb 		if (memcmp(search->mac, peer, ETH_ALEN) == 0)
518b4c3e9b5SBjoern A. Zeeb 			goto free_entry;
519b4c3e9b5SBjoern A. Zeeb 		while (search->next) {
520b4c3e9b5SBjoern A. Zeeb 			search = search->next;
521b4c3e9b5SBjoern A. Zeeb 			if (memcmp(search->mac, peer, ETH_ALEN) == 0)
522b4c3e9b5SBjoern A. Zeeb 				goto free_entry;
523b4c3e9b5SBjoern A. Zeeb 		}
524b4c3e9b5SBjoern A. Zeeb 		search->next = tdls_entry;
525b4c3e9b5SBjoern A. Zeeb 	}
526b4c3e9b5SBjoern A. Zeeb 
527b4c3e9b5SBjoern A. Zeeb 	flow->tdls_active = true;
528b4c3e9b5SBjoern A. Zeeb 	return;
529b4c3e9b5SBjoern A. Zeeb 
530b4c3e9b5SBjoern A. Zeeb free_entry:
531b4c3e9b5SBjoern A. Zeeb 	kfree(tdls_entry);
532b4c3e9b5SBjoern A. Zeeb }
533