aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-03 06:40:40 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-03 15:07:06 -0400
commit3edc1cff02a40a76ad6a5e2b9cb00a29584f33ad (patch)
tree77c0d0825f08cd12326f92c92a0e272459d4fd06 /drivers
parentc7f34a69a2e32b139a6b66c8599252c46f37abba (diff)
brcmfmac: enable tx status signalling
Enabling the tx status signalling, which requires packet tagging before sending to the firmware and handling the tx status signal. Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Piotr Haber <phaber@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c30
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c18
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c485
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h1
5 files changed, 455 insertions, 87 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
index f0949b1e3073..757701d57e5a 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -138,16 +138,34 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
138 return 0; 138 return 0;
139 139
140 res = scnprintf(buf, sizeof(buf), 140 res = scnprintf(buf, sizeof(buf),
141 "header_pulls: %u\n" 141 "header_pulls: %u\n"
142 "header_only_pkt: %u\n" 142 "header_only_pkt: %u\n"
143 "tlv_parse_failed: %u\n" 143 "tlv_parse_failed: %u\n"
144 "tlv_invalid_type: %u\n" 144 "tlv_invalid_type: %u\n"
145 "mac_update_fails: %u\n", 145 "mac_update_fails: %u\n"
146 "pkt2bus: %u\n"
147 "generic_error: %u\n"
148 "txs_indicate: %u\n"
149 "txs_discard: %u\n"
150 "txs_suppr_core: %u\n"
151 "txs_suppr_ps: %u\n"
152 "txs_tossed: %u\n"
153 "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
146 fwstats->header_pulls, 154 fwstats->header_pulls,
147 fwstats->header_only_pkt, 155 fwstats->header_only_pkt,
148 fwstats->tlv_parse_failed, 156 fwstats->tlv_parse_failed,
149 fwstats->tlv_invalid_type, 157 fwstats->tlv_invalid_type,
150 fwstats->mac_update_failed); 158 fwstats->mac_update_failed,
159 fwstats->pkt2bus,
160 fwstats->generic_error,
161 fwstats->txs_indicate,
162 fwstats->txs_discard,
163 fwstats->txs_supp_core,
164 fwstats->txs_supp_ps,
165 fwstats->txs_tossed,
166 fwstats->send_pkts[0], fwstats->send_pkts[1],
167 fwstats->send_pkts[2], fwstats->send_pkts[3],
168 fwstats->send_pkts[4]);
151 169
152 return simple_read_from_buffer(data, count, ppos, buf, res); 170 return simple_read_from_buffer(data, count, ppos, buf, res);
153} 171}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index 371ae5b546af..ef93fe449d1c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -137,7 +137,15 @@ struct brcmf_fws_stats {
137 u32 tlv_invalid_type; 137 u32 tlv_invalid_type;
138 u32 header_only_pkt; 138 u32 header_only_pkt;
139 u32 header_pulls; 139 u32 header_pulls;
140 u32 pkt2bus;
141 u32 send_pkts[5];
142 u32 generic_error;
140 u32 mac_update_failed; 143 u32 mac_update_failed;
144 u32 txs_indicate;
145 u32 txs_discard;
146 u32 txs_supp_core;
147 u32 txs_supp_ps;
148 u32 txs_tossed;
141}; 149};
142 150
143struct brcmf_pub; 151struct brcmf_pub;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 05c8840392e5..0299ab6731b2 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -223,18 +223,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
223 goto done; 223 goto done;
224 } 224 }
225 225
226 /* handle ethernet header */ 226 ret = brcmf_fws_process_skb(ifp, skb);
227 eh = (struct ethhdr *)(skb->data);
228 if (is_multicast_ether_addr(eh->h_dest))
229 drvr->tx_multicast++;
230 if (ntohs(eh->h_proto) == ETH_P_PAE)
231 atomic_inc(&ifp->pend_8021x_cnt);
232
233 /* If the protocol uses a data header, apply it */
234 brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb);
235
236 /* Use bus module to send data frame */
237 ret = brcmf_bus_txdata(drvr->bus_if, skb);
238 227
239done: 228done:
240 if (ret) { 229 if (ret) {
@@ -376,7 +365,7 @@ void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
376 365
377 ifp = drvr->iflist[ifidx]; 366 ifp = drvr->iflist[ifidx];
378 if (!ifp) 367 if (!ifp)
379 return; 368 goto done;
380 369
381 if (res == 0) { 370 if (res == 0) {
382 eh = (struct ethhdr *)(txp->data); 371 eh = (struct ethhdr *)(txp->data);
@@ -390,6 +379,8 @@ void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
390 } 379 }
391 if (!success) 380 if (!success)
392 ifp->stats.tx_errors++; 381 ifp->stats.tx_errors++;
382done:
383 brcmu_pkt_buf_free_skb(txp);
393} 384}
394 385
395void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) 386void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
@@ -402,7 +393,6 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
402 return; 393 return;
403 394
404 brcmf_txfinalize(drvr, txp, success); 395 brcmf_txfinalize(drvr, txp, success);
405 brcmu_pkt_buf_free_skb(txp);
406} 396}
407 397
408static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) 398static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index cb1414d93a67..9389bf7b7696 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -19,12 +19,15 @@
19#include <linux/spinlock.h> 19#include <linux/spinlock.h>
20#include <linux/skbuff.h> 20#include <linux/skbuff.h>
21#include <linux/netdevice.h> 21#include <linux/netdevice.h>
22#include <linux/etherdevice.h>
22#include <linux/err.h> 23#include <linux/err.h>
23#include <uapi/linux/nl80211.h> 24#include <uapi/linux/nl80211.h>
25#include <net/cfg80211.h>
24 26
25#include <brcmu_utils.h> 27#include <brcmu_utils.h>
26#include <brcmu_wifi.h> 28#include <brcmu_wifi.h>
27#include "dhd.h" 29#include "dhd.h"
30#include "dhd_proto.h"
28#include "dhd_dbg.h" 31#include "dhd_dbg.h"
29#include "dhd_bus.h" 32#include "dhd_bus.h"
30#include "fwil.h" 33#include "fwil.h"
@@ -64,7 +67,7 @@
64 BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \ 67 BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \
65 BRCMF_FWS_TLV_DEF(FILLER, 255, 0) 68 BRCMF_FWS_TLV_DEF(FILLER, 255, 0)
66 69
67/** 70/*
68 * enum brcmf_fws_tlv_type - definition of tlv identifiers. 71 * enum brcmf_fws_tlv_type - definition of tlv identifiers.
69 */ 72 */
70#define BRCMF_FWS_TLV_DEF(name, id, len) \ 73#define BRCMF_FWS_TLV_DEF(name, id, len) \
@@ -75,8 +78,18 @@ enum brcmf_fws_tlv_type {
75}; 78};
76#undef BRCMF_FWS_TLV_DEF 79#undef BRCMF_FWS_TLV_DEF
77 80
81/*
82 * enum brcmf_fws_tlv_len - definition of tlv lengths.
83 */
84#define BRCMF_FWS_TLV_DEF(name, id, len) \
85 BRCMF_FWS_TYPE_ ## name ## _LEN = (len),
86enum brcmf_fws_tlv_len {
87 BRCMF_FWS_TLV_DEFLIST
88};
89#undef BRCMF_FWS_TLV_DEF
90
78#ifdef DEBUG 91#ifdef DEBUG
79/** 92/*
80 * brcmf_fws_tlv_names - array of tlv names. 93 * brcmf_fws_tlv_names - array of tlv names.
81 */ 94 */
82#define BRCMF_FWS_TLV_DEF(name, id, len) \ 95#define BRCMF_FWS_TLV_DEF(name, id, len) \
@@ -106,7 +119,7 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
106} 119}
107#endif /* DEBUG */ 120#endif /* DEBUG */
108 121
109/** 122/*
110 * flags used to enable tlv signalling from firmware. 123 * flags used to enable tlv signalling from firmware.
111 */ 124 */
112#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001 125#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
@@ -117,11 +130,6 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
117#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 130#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
118#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040 131#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
119 132
120#define BRCMF_FWS_HANGER_MAXITEMS 1024
121#define BRCMF_FWS_HANGER_ITEM_STATE_FREE 1
122#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE 2
123#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3
124
125#define BRCMF_FWS_STATE_OPEN 1 133#define BRCMF_FWS_STATE_OPEN 1
126#define BRCMF_FWS_STATE_CLOSE 2 134#define BRCMF_FWS_STATE_CLOSE 2
127 135
@@ -135,23 +143,27 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
135#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2) 143#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2)
136#define BRCMF_FWS_PSQ_LEN 256 144#define BRCMF_FWS_PSQ_LEN 256
137 145
146#define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST 0x01
147#define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED 0x02
148
138/** 149/**
139 * enum brcmf_fws_skb_state - indicates processing state of skb. 150 * enum brcmf_fws_skb_state - indicates processing state of skb.
151 *
152 * @BRCMF_FWS_SKBSTATE_NEW: sk_buff is newly arrived in the driver.
153 * @BRCMF_FWS_SKBSTATE_DELAYED: sk_buff had to wait on queue.
154 * @BRCMF_FWS_SKBSTATE_SUPPRESSED: sk_buff has been suppressed by firmware.
140 */ 155 */
141enum brcmf_fws_skb_state { 156enum brcmf_fws_skb_state {
142 WLFC_PKTTYPE_NEW, 157 BRCMF_FWS_SKBSTATE_NEW,
143 WLFC_PKTTYPE_DELAYED, 158 BRCMF_FWS_SKBSTATE_DELAYED,
144 WLFC_PKTTYPE_SUPPRESSED, 159 BRCMF_FWS_SKBSTATE_SUPPRESSED
145 WLFC_PKTTYPE_MAX
146}; 160};
147 161
148/** 162/**
149 * struct brcmf_skbuff_cb - control buffer associated with skbuff. 163 * struct brcmf_skbuff_cb - control buffer associated with skbuff.
150 * 164 *
151 * @if_flags: holds interface index and packet related flags. 165 * @if_flags: holds interface index and packet related flags.
152 * @da: destination MAC address extracted from skbuff once.
153 * @htod: host to device packet identifier (used in PKTTAG tlv). 166 * @htod: host to device packet identifier (used in PKTTAG tlv).
154 * @needs_hdr: the packet does not yet have a BDC header.
155 * @state: transmit state of the packet. 167 * @state: transmit state of the packet.
156 * @mac: descriptor related to destination for this packet. 168 * @mac: descriptor related to destination for this packet.
157 * 169 *
@@ -160,19 +172,17 @@ enum brcmf_fws_skb_state {
160 */ 172 */
161struct brcmf_skbuff_cb { 173struct brcmf_skbuff_cb {
162 u16 if_flags; 174 u16 if_flags;
163 u8 da[ETH_ALEN];
164 u32 htod; 175 u32 htod;
165 u8 needs_hdr;
166 enum brcmf_fws_skb_state state; 176 enum brcmf_fws_skb_state state;
167 struct brcmf_fws_mac_descriptor *mac; 177 struct brcmf_fws_mac_descriptor *mac;
168}; 178};
169 179
170/** 180/*
171 * macro casting skbuff control buffer to struct brcmf_skbuff_cb. 181 * macro casting skbuff control buffer to struct brcmf_skbuff_cb.
172 */ 182 */
173#define brcmf_skbcb(skb) ((struct brcmf_skbuff_cb *)((skb)->cb)) 183#define brcmf_skbcb(skb) ((struct brcmf_skbuff_cb *)((skb)->cb))
174 184
175/** 185/*
176 * sk_buff control if flags 186 * sk_buff control if flags
177 * 187 *
178 * b[11] - packet sent upon firmware request. 188 * b[11] - packet sent upon firmware request.
@@ -207,7 +217,7 @@ struct brcmf_skbuff_cb {
207 BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \ 217 BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
208 BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT) 218 BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT)
209 219
210/** 220/*
211 * sk_buff control packet identifier 221 * sk_buff control packet identifier
212 * 222 *
213 * 32-bit packet identifier used in PKTTAG tlv from host to dongle. 223 * 32-bit packet identifier used in PKTTAG tlv from host to dongle.
@@ -242,6 +252,61 @@ struct brcmf_skbuff_cb {
242 BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \ 252 BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
243 BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT) 253 BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
244 254
255#define BRCMF_FWS_TXSTAT_GENERATION_MASK 0x80000000
256#define BRCMF_FWS_TXSTAT_GENERATION_SHIFT 31
257#define BRCMF_FWS_TXSTAT_FLAGS_MASK 0x78000000
258#define BRCMF_FWS_TXSTAT_FLAGS_SHIFT 27
259#define BRCMF_FWS_TXSTAT_FIFO_MASK 0x07000000
260#define BRCMF_FWS_TXSTAT_FIFO_SHIFT 24
261#define BRCMF_FWS_TXSTAT_HSLOT_MASK 0x00FFFF00
262#define BRCMF_FWS_TXSTAT_HSLOT_SHIFT 8
263#define BRCMF_FWS_TXSTAT_PKTID_MASK 0x00FFFFFF
264#define BRCMF_FWS_TXSTAT_PKTID_SHIFT 0
265
266#define brcmf_txstatus_get_field(txs, field) \
267 brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
268 BRCMF_FWS_TXSTAT_ ## field ## _SHIFT)
269
270/**
271 * enum brcmf_fws_fifo - fifo indices used by dongle firmware.
272 *
273 * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
274 * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
275 * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
276 * @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
277 * @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
278 * @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
279 * @BRCMF_FWS_FIFO_COUNT: number of fifos.
280 */
281enum brcmf_fws_fifo {
282 BRCMF_FWS_FIFO_AC_BK,
283 BRCMF_FWS_FIFO_AC_BE,
284 BRCMF_FWS_FIFO_AC_VI,
285 BRCMF_FWS_FIFO_AC_VO,
286 BRCMF_FWS_FIFO_BCMC,
287 BRCMF_FWS_FIFO_ATIM,
288 BRCMF_FWS_FIFO_COUNT
289};
290
291/**
292 * enum brcmf_fws_txstatus - txstatus flag values.
293 *
294 * @BRCMF_FWS_TXSTATUS_DISCARD:
295 * host is free to discard the packet.
296 * @BRCMF_FWS_TXSTATUS_CORE_SUPPRESS:
297 * 802.11 core suppressed the packet.
298 * @BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS:
299 * firmware suppress the packet as device is already in PS mode.
300 * @BRCMF_FWS_TXSTATUS_FW_TOSSED:
301 * firmware tossed the packet.
302 */
303enum brcmf_fws_txstatus {
304 BRCMF_FWS_TXSTATUS_DISCARD,
305 BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
306 BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
307 BRCMF_FWS_TXSTATUS_FW_TOSSED
308};
309
245enum brcmf_fws_fcmode { 310enum brcmf_fws_fcmode {
246 BRCMF_FWS_FCMODE_NONE, 311 BRCMF_FWS_FCMODE_NONE,
247 BRCMF_FWS_FCMODE_IMPLIED_CREDIT, 312 BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
@@ -255,20 +320,28 @@ enum brcmf_fws_fcmode {
255 * @mac_handle: handle for mac entry determined by firmware. 320 * @mac_handle: handle for mac entry determined by firmware.
256 * @interface_id: interface index. 321 * @interface_id: interface index.
257 * @state: current state. 322 * @state: current state.
323 * @suppressed: mac entry is suppressed.
324 * @generation: generation bit.
258 * @ac_bitmap: ac queue bitmap. 325 * @ac_bitmap: ac queue bitmap.
259 * @requested_credit: credits requested by firmware. 326 * @requested_credit: credits requested by firmware.
260 * @ea: ethernet address. 327 * @ea: ethernet address.
328 * @seq: per-node free-running sequence.
261 * @psq: power-save queue. 329 * @psq: power-save queue.
330 * @transit_count: packet in transit to firmware.
262 */ 331 */
263struct brcmf_fws_mac_descriptor { 332struct brcmf_fws_mac_descriptor {
264 u8 occupied; 333 u8 occupied;
265 u8 mac_handle; 334 u8 mac_handle;
266 u8 interface_id; 335 u8 interface_id;
267 u8 state; 336 u8 state;
337 bool suppressed;
338 u8 generation;
268 u8 ac_bitmap; 339 u8 ac_bitmap;
269 u8 requested_credit; 340 u8 requested_credit;
270 u8 ea[ETH_ALEN]; 341 u8 ea[ETH_ALEN];
342 u8 seq[BRCMF_FWS_FIFO_COUNT];
271 struct pktq psq; 343 struct pktq psq;
344 int transit_count;
272}; 345};
273 346
274#define BRCMF_FWS_HANGER_MAXITEMS 1024 347#define BRCMF_FWS_HANGER_MAXITEMS 1024
@@ -276,14 +349,14 @@ struct brcmf_fws_mac_descriptor {
276/** 349/**
277 * enum brcmf_fws_hanger_item_state - state of hanger item. 350 * enum brcmf_fws_hanger_item_state - state of hanger item.
278 * 351 *
279 * @WLFC_HANGER_ITEM_STATE_FREE: item is free for use. 352 * @BRCMF_FWS_HANGER_ITEM_STATE_FREE: item is free for use.
280 * @WLFC_HANGER_ITEM_STATE_INUSE: item is in use. 353 * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE: item is in use.
281 * @WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed. 354 * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed.
282 */ 355 */
283enum brcmf_fws_hanger_item_state { 356enum brcmf_fws_hanger_item_state {
284 WLFC_HANGER_ITEM_STATE_FREE = 1, 357 BRCMF_FWS_HANGER_ITEM_STATE_FREE = 1,
285 WLFC_HANGER_ITEM_STATE_INUSE, 358 BRCMF_FWS_HANGER_ITEM_STATE_INUSE,
286 WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 359 BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED
287}; 360};
288 361
289 362
@@ -292,21 +365,17 @@ enum brcmf_fws_hanger_item_state {
292 * 365 *
293 * @state: entry is either free or occupied. 366 * @state: entry is either free or occupied.
294 * @gen: generation. 367 * @gen: generation.
295 * @identifier: packet identifier.
296 * @pkt: packet itself. 368 * @pkt: packet itself.
297 */ 369 */
298struct brcmf_fws_hanger_item { 370struct brcmf_fws_hanger_item {
299 enum brcmf_fws_hanger_item_state state; 371 enum brcmf_fws_hanger_item_state state;
300 u8 gen; 372 u8 gen;
301 u8 pad[2];
302 u32 identifier;
303 struct sk_buff *pkt; 373 struct sk_buff *pkt;
304}; 374};
305 375
306/** 376/**
307 * struct brcmf_fws_hanger - holds packets awaiting firmware txstatus. 377 * struct brcmf_fws_hanger - holds packets awaiting firmware txstatus.
308 * 378 *
309 * @max_items: number of packets it can hold.
310 * @pushed: packets pushed to await txstatus. 379 * @pushed: packets pushed to await txstatus.
311 * @popped: packets popped upon handling txstatus. 380 * @popped: packets popped upon handling txstatus.
312 * @failed_to_push: packets that could not be pushed. 381 * @failed_to_push: packets that could not be pushed.
@@ -332,20 +401,39 @@ struct brcmf_fws_info {
332 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE]; 401 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
333 struct brcmf_fws_mac_descriptor other; 402 struct brcmf_fws_mac_descriptor other;
334 enum brcmf_fws_fcmode fcmode; 403 enum brcmf_fws_fcmode fcmode;
335 int fifo_credit[NL80211_NUM_ACS+1+1]; 404 int fifo_credit[BRCMF_FWS_FIFO_COUNT];
405};
406
407/*
408 * brcmf_fws_prio2fifo - mapping from 802.1d priority to firmware fifo index.
409 */
410static const int brcmf_fws_prio2fifo[] = {
411 BRCMF_FWS_FIFO_AC_BE,
412 BRCMF_FWS_FIFO_AC_BK,
413 BRCMF_FWS_FIFO_AC_BK,
414 BRCMF_FWS_FIFO_AC_BE,
415 BRCMF_FWS_FIFO_AC_VI,
416 BRCMF_FWS_FIFO_AC_VI,
417 BRCMF_FWS_FIFO_AC_VO,
418 BRCMF_FWS_FIFO_AC_VO
336}; 419};
337 420
338static int fcmode; 421static int fcmode;
339module_param(fcmode, int, S_IRUSR); 422module_param(fcmode, int, S_IRUSR);
340MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control"); 423MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control");
341 424
342/**
343 * brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
344 */
345#define BRCMF_FWS_TLV_DEF(name, id, len) \ 425#define BRCMF_FWS_TLV_DEF(name, id, len) \
346 case BRCMF_FWS_TYPE_ ## name: \ 426 case BRCMF_FWS_TYPE_ ## name: \
347 return len; 427 return len;
348 428
429/**
430 * brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
431 *
432 * @fws: firmware-signalling information.
433 * @id: identifier of the TLV.
434 *
435 * Return: the specified length for the given TLV; Otherwise -EINVAL.
436 */
349static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws, 437static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
350 enum brcmf_fws_tlv_type id) 438 enum brcmf_fws_tlv_type id)
351{ 439{
@@ -360,6 +448,30 @@ static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
360} 448}
361#undef BRCMF_FWS_TLV_DEF 449#undef BRCMF_FWS_TLV_DEF
362 450
451static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
452{
453 u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
454 return ifidx == *(int *)arg;
455}
456
457static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
458 int ifidx)
459{
460 bool (*matchfn)(struct sk_buff *, void *) = NULL;
461 struct sk_buff *skb;
462 int prec;
463
464 if (ifidx != -1)
465 matchfn = brcmf_fws_ifidx_match;
466 for (prec = 0; prec < q->num_prec; prec++) {
467 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
468 while (skb) {
469 brcmf_txfinalize(fws->drvr, skb, false);
470 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
471 }
472 }
473}
474
363static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger) 475static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
364{ 476{
365 int i; 477 int i;
@@ -367,10 +479,10 @@ static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
367 brcmf_dbg(TRACE, "enter\n"); 479 brcmf_dbg(TRACE, "enter\n");
368 memset(hanger, 0, sizeof(*hanger)); 480 memset(hanger, 0, sizeof(*hanger));
369 for (i = 0; i < ARRAY_SIZE(hanger->items); i++) 481 for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
370 hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; 482 hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
371} 483}
372 484
373static __used u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h) 485static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
374{ 486{
375 u32 i; 487 u32 i;
376 488
@@ -378,7 +490,7 @@ static __used u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
378 i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS; 490 i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
379 491
380 while (i != h->slot_pos) { 492 while (i != h->slot_pos) {
381 if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { 493 if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
382 h->slot_pos = i; 494 h->slot_pos = i;
383 return i; 495 return i;
384 } 496 }
@@ -391,7 +503,7 @@ static __used u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
391 return BRCMF_FWS_HANGER_MAXITEMS; 503 return BRCMF_FWS_HANGER_MAXITEMS;
392} 504}
393 505
394static __used int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h, 506static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
395 struct sk_buff *pkt, u32 slot_id) 507 struct sk_buff *pkt, u32 slot_id)
396{ 508{
397 brcmf_dbg(TRACE, "enter\n"); 509 brcmf_dbg(TRACE, "enter\n");
@@ -406,12 +518,11 @@ static __used int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
406 518
407 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE; 519 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
408 h->items[slot_id].pkt = pkt; 520 h->items[slot_id].pkt = pkt;
409 h->items[slot_id].identifier = slot_id;
410 h->pushed++; 521 h->pushed++;
411 return 0; 522 return 0;
412} 523}
413 524
414static __used int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h, 525static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
415 u32 slot_id, struct sk_buff **pktout, 526 u32 slot_id, struct sk_buff **pktout,
416 bool remove_item) 527 bool remove_item)
417{ 528{
@@ -429,7 +540,6 @@ static __used int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
429 if (remove_item) { 540 if (remove_item) {
430 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE; 541 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
431 h->items[slot_id].pkt = NULL; 542 h->items[slot_id].pkt = NULL;
432 h->items[slot_id].identifier = 0;
433 h->items[slot_id].gen = 0xff; 543 h->items[slot_id].gen = 0xff;
434 h->popped++; 544 h->popped++;
435 } 545 }
@@ -446,16 +556,16 @@ static __used int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
446 556
447 h->items[slot_id].gen = gen; 557 h->items[slot_id].gen = gen;
448 558
449 if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_INUSE) { 559 if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_INUSE) {
450 brcmf_err("entry not in use\n"); 560 brcmf_err("entry not in use\n");
451 return -EINVAL; 561 return -EINVAL;
452 } 562 }
453 563
454 h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; 564 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
455 return 0; 565 return 0;
456} 566}
457 567
458static __used int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger, 568static int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger,
459 struct sk_buff *pkt, u32 slot_id, 569 struct sk_buff *pkt, u32 slot_id,
460 int *gen) 570 int *gen)
461{ 571{
@@ -542,17 +652,50 @@ brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea)
542 return ERR_PTR(-ENOENT); 652 return ERR_PTR(-ENOENT);
543} 653}
544 654
545static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_mac_descriptor *entry, 655static struct brcmf_fws_mac_descriptor*
546 bool (*fn)(struct sk_buff *, void *), 656brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, int ifidx, u8 *da)
657{
658 struct brcmf_fws_mac_descriptor *entry = &fws->other;
659 struct brcmf_if *ifp;
660 bool multicast;
661
662 brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
663
664 multicast = is_multicast_ether_addr(da);
665 ifp = fws->drvr->iflist[ifidx ? ifidx + 1 : 0];
666 if (WARN_ON(!ifp))
667 goto done;
668
669 /* Multicast destination and P2P clients get the interface entry.
670 * STA gets the interface entry if there is no exact match. For
671 * example, TDLS destinations have their own entry.
672 */
673 entry = NULL;
674 if ((/* ifp->iftype == 0 ||*/ multicast) && ifp->fws_desc)
675 entry = ifp->fws_desc;
676
677 if (entry != NULL && multicast)
678 goto done;
679
680 entry = brcmf_fws_mac_descriptor_lookup(fws, da);
681 if (IS_ERR(entry))
682 entry = &fws->other;
683
684done:
685 brcmf_dbg(TRACE, "exit: entry=%p\n", entry);
686 return entry;
687}
688
689static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_info *fws,
690 struct brcmf_fws_mac_descriptor *entry,
547 int ifidx) 691 int ifidx)
548{ 692{
549 brcmf_dbg(TRACE, "enter: entry=(ea=%pM,ifid=%d), ifidx=%d\n", 693 brcmf_dbg(TRACE, "enter: entry=(ea=%pM, ifid=%d), ifidx=%d\n",
550 entry->ea, entry->interface_id, ifidx); 694 entry->ea, entry->interface_id, ifidx);
551 if (entry->occupied && (fn == NULL || (ifidx == entry->interface_id))) { 695 if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
552 brcmf_dbg(TRACE, "flush delayQ: ifidx=%d, qlen=%d\n", 696 brcmf_dbg(TRACE, "flush psq: ifidx=%d, qlen=%d\n",
553 ifidx, entry->psq.len); 697 ifidx, entry->psq.len);
554 /* release packets held in DELAYQ */ 698 brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
555 brcmu_pktq_flush(&entry->psq, true, fn, &ifidx);
556 entry->occupied = !!(entry->psq.len); 699 entry->occupied = !!(entry->psq.len);
557 } 700 }
558} 701}
@@ -587,12 +730,6 @@ static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
587 } 730 }
588} 731}
589 732
590static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
591{
592 u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
593 return ifidx == *(int *)arg;
594}
595
596static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx) 733static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
597{ 734{
598 int i; 735 int i;
@@ -609,9 +746,9 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
609 /* cleanup individual nodes */ 746 /* cleanup individual nodes */
610 table = &fws->nodes[0]; 747 table = &fws->nodes[0];
611 for (i = 0; i < ARRAY_SIZE(fws->nodes); i++) 748 for (i = 0; i < ARRAY_SIZE(fws->nodes); i++)
612 brcmf_fws_mac_desc_cleanup(&table[i], matchfn, ifidx); 749 brcmf_fws_mac_desc_cleanup(fws, &table[i], ifidx);
613 750
614 brcmf_fws_mac_desc_cleanup(&fws->other, matchfn, ifidx); 751 brcmf_fws_mac_desc_cleanup(fws, &fws->other, ifidx);
615 brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx); 752 brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
616 brcmf_fws_hanger_cleanup(&fws->hanger, matchfn, ifidx); 753 brcmf_fws_hanger_cleanup(&fws->hanger, matchfn, ifidx);
617} 754}
@@ -637,17 +774,15 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
637 entry = &fws->nodes[mac_handle & 0x1F]; 774 entry = &fws->nodes[mac_handle & 0x1F];
638 if (type == BRCMF_FWS_TYPE_MACDESC_DEL) { 775 if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
639 brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx); 776 brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx);
640 if (entry->occupied) { 777 if (entry->occupied)
641 entry->occupied = 0; 778 brcmf_fws_clear_mac_descriptor(entry);
642 entry->state = BRCMF_FWS_STATE_CLOSE; 779 else
643 entry->requested_credit = 0;
644 } else {
645 fws->stats.mac_update_failed++; 780 fws->stats.mac_update_failed++;
646 }
647 return 0; 781 return 0;
648 } 782 }
649 783
650 brcmf_dbg(TRACE, "add mac %pM idx %d\n", addr, ifidx); 784 brcmf_dbg(TRACE,
785 "add mac %pM handle %u idx %d\n", addr, mac_handle, ifidx);
651 existing = brcmf_fws_mac_descriptor_lookup(fws, addr); 786 existing = brcmf_fws_mac_descriptor_lookup(fws, addr);
652 if (IS_ERR(existing)) { 787 if (IS_ERR(existing)) {
653 if (!entry->occupied) { 788 if (!entry->occupied) {
@@ -674,6 +809,51 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
674 return 0; 809 return 0;
675} 810}
676 811
812static int
813brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
814{
815 u8 flags;
816 u32 status;
817 u32 hslot;
818 int ret;
819 struct sk_buff *skb;
820 struct brcmf_fws_mac_descriptor *entry = NULL;
821
822 status = le32_to_cpu(*(__le32 *)data);
823 flags = brcmf_txstatus_get_field(status, FLAGS);
824 hslot = brcmf_txstatus_get_field(status, HSLOT);
825 fws->stats.txs_indicate++;
826
827 brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n",
828 flags, hslot);
829
830 if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
831 fws->stats.txs_discard++;
832 else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
833 fws->stats.txs_tossed++;
834 else
835 brcmf_err("unexpected txstatus\n");
836
837 ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
838 true);
839 if (ret != 0) {
840 brcmf_err("no packet in hanger slot: hslot=%d\n", hslot);
841 return ret;
842 }
843
844 entry = brcmf_skbcb(skb)->mac;
845 if (WARN_ON(!entry)) {
846 ret = -EINVAL;
847 goto done;
848 }
849
850 entry->transit_count--;
851
852done:
853 brcmf_txfinalize(fws->drvr, skb, true);
854 return ret;
855}
856
677static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) 857static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
678{ 858{
679 __le32 timestamp; 859 __le32 timestamp;
@@ -723,7 +903,8 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
723 /* enable rssi signals */ 903 /* enable rssi signals */
724 if (drvr->fw_signals) 904 if (drvr->fw_signals)
725 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS | 905 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS |
726 BRCMF_FWS_FLAGS_XONXOFF_SIGNALS; 906 BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
907 BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS;
727 908
728 spin_lock_init(&drvr->fws_spinlock); 909 spin_lock_init(&drvr->fws_spinlock);
729 910
@@ -839,7 +1020,6 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
839 case BRCMF_FWS_TYPE_MAC_OPEN: 1020 case BRCMF_FWS_TYPE_MAC_OPEN:
840 case BRCMF_FWS_TYPE_MAC_CLOSE: 1021 case BRCMF_FWS_TYPE_MAC_CLOSE:
841 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT: 1022 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
842 case BRCMF_FWS_TYPE_TXSTATUS:
843 case BRCMF_FWS_TYPE_PKTTAG: 1023 case BRCMF_FWS_TYPE_PKTTAG:
844 case BRCMF_FWS_TYPE_INTERFACE_OPEN: 1024 case BRCMF_FWS_TYPE_INTERFACE_OPEN:
845 case BRCMF_FWS_TYPE_INTERFACE_CLOSE: 1025 case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
@@ -853,6 +1033,9 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
853 case BRCMF_FWS_TYPE_MACDESC_DEL: 1033 case BRCMF_FWS_TYPE_MACDESC_DEL:
854 brcmf_fws_macdesc_indicate(fws, type, data); 1034 brcmf_fws_macdesc_indicate(fws, type, data);
855 break; 1035 break;
1036 case BRCMF_FWS_TYPE_TXSTATUS:
1037 brcmf_fws_txstatus_indicate(fws, data);
1038 break;
856 case BRCMF_FWS_TYPE_RSSI: 1039 case BRCMF_FWS_TYPE_RSSI:
857 brcmf_fws_rssi_indicate(fws, *data); 1040 brcmf_fws_rssi_indicate(fws, *data);
858 break; 1041 break;
@@ -885,6 +1068,174 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
885 return 0; 1068 return 0;
886} 1069}
887 1070
1071static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
1072{
1073 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1074 u8 *wlh;
1075 u16 data_offset;
1076 u8 fillers;
1077 __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
1078
1079 brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u, pkttag=0x%08X\n",
1080 entry->ea, entry->interface_id, le32_to_cpu(pkttag));
1081 /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
1082 data_offset = 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
1083 fillers = round_up(data_offset, 4) - data_offset;
1084 data_offset += fillers;
1085
1086 skb_push(skb, data_offset);
1087 wlh = skb->data;
1088
1089 wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
1090 wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
1091 memcpy(&wlh[2], &pkttag, sizeof(pkttag));
1092 wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
1093
1094 if (fillers)
1095 memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
1096
1097 brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
1098 data_offset >> 2, skb);
1099 return 0;
1100}
1101
1102static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
1103 struct sk_buff *p)
1104{
1105 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
1106 struct brcmf_fws_mac_descriptor *entry = skcb->mac;
1107 int rc = 0;
1108 bool header_needed;
1109 int hslot = BRCMF_FWS_HANGER_MAXITEMS;
1110 u8 free_ctr;
1111 u8 ifidx;
1112 u8 flags;
1113
1114 header_needed = skcb->state == BRCMF_FWS_SKBSTATE_NEW;
1115
1116 if (header_needed) {
1117 /* obtaining free slot may fail, but that will be caught
1118 * by the hanger push. This assures the packet has a BDC
1119 * header upon return.
1120 */
1121 hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
1122 free_ctr = entry->seq[fifo];
1123 brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
1124 brcmf_skb_htod_tag_set_field(p, FREERUN, free_ctr);
1125 brcmf_skb_htod_tag_set_field(p, GENERATION, 1);
1126 entry->transit_count++;
1127 }
1128 brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
1129 brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
1130
1131 flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
1132 if (!(skcb->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)) {
1133 /*
1134 Indicate that this packet is being sent in response to an
1135 explicit request from the firmware side.
1136 */
1137 flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
1138 }
1139 brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
1140 if (header_needed) {
1141 brcmf_fws_hdrpush(fws, p);
1142 rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
1143 if (rc)
1144 brcmf_err("hanger push failed: rc=%d\n", rc);
1145 } else {
1146 int gen;
1147
1148 /* remove old header */
1149 rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, p);
1150 if (rc == 0) {
1151 hslot = brcmf_skb_htod_tag_get_field(p, HSLOT);
1152 brcmf_fws_hanger_get_genbit(&fws->hanger, p,
1153 hslot, &gen);
1154 brcmf_skb_htod_tag_set_field(p, GENERATION, gen);
1155
1156 /* push new header */
1157 brcmf_fws_hdrpush(fws, p);
1158 }
1159 }
1160
1161 return rc;
1162}
1163
1164static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
1165 struct sk_buff *skb)
1166{
1167 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
1168 struct brcmf_fws_mac_descriptor *entry;
1169 struct brcmf_bus *bus = fws->drvr->bus_if;
1170 int rc;
1171
1172 entry = skcb->mac;
1173 if (IS_ERR(entry))
1174 return PTR_ERR(entry);
1175
1176 rc = brcmf_fws_precommit_skb(fws, fifo, skb);
1177 if (rc < 0) {
1178 fws->stats.generic_error++;
1179 goto done;
1180 }
1181
1182 rc = brcmf_bus_txdata(bus, skb);
1183 if (rc < 0)
1184 goto done;
1185
1186 entry->seq[fifo]++;
1187 fws->stats.pkt2bus++;
1188 return rc;
1189
1190done:
1191 brcmf_txfinalize(fws->drvr, skb, false);
1192 return rc;
1193}
1194
1195int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1196{
1197 struct brcmf_pub *drvr = ifp->drvr;
1198 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
1199 struct ethhdr *eh = (struct ethhdr *)(skb->data);
1200 ulong flags;
1201 u8 ifidx = ifp->ifidx;
1202 int fifo = BRCMF_FWS_FIFO_BCMC;
1203 bool multicast = is_multicast_ether_addr(eh->h_dest);
1204
1205 /* determine the priority */
1206 if (!skb->priority)
1207 skb->priority = cfg80211_classify8021d(skb);
1208
1209 drvr->tx_multicast += !!multicast;
1210 if (ntohs(eh->h_proto) == ETH_P_PAE)
1211 atomic_inc(&ifp->pend_8021x_cnt);
1212
1213 if (!brcmf_fws_fc_active(drvr->fws)) {
1214 /* If the protocol uses a data header, apply it */
1215 brcmf_proto_hdrpush(drvr, ifidx, 0, skb);
1216
1217 /* Use bus module to send data frame */
1218 return brcmf_bus_txdata(drvr->bus_if, skb);
1219 }
1220
1221 /* set control buffer information */
1222 skcb->mac = brcmf_fws_find_mac_desc(drvr->fws, ifidx, eh->h_dest);
1223 skcb->state = BRCMF_FWS_SKBSTATE_NEW;
1224 brcmf_skb_if_flags_set_field(skb, INDEX, ifidx);
1225 if (!multicast)
1226 fifo = brcmf_fws_prio2fifo[skb->priority];
1227 brcmf_skb_if_flags_set_field(skb, FIFO, fifo);
1228 brcmf_skb_if_flags_set_field(skb, CREDITCHECK, 0);
1229
1230 brcmf_dbg(TRACE, "ea=%pM, multi=%d, fifo=%d\n", eh->h_dest,
1231 multicast, fifo);
1232
1233 brcmf_fws_lock(drvr, flags);
1234 brcmf_fws_commit_skb(drvr->fws, fifo, skb);
1235 brcmf_fws_unlock(drvr, flags);
1236 return 0;
1237}
1238
888void brcmf_fws_reset_interface(struct brcmf_if *ifp) 1239void brcmf_fws_reset_interface(struct brcmf_if *ifp)
889{ 1240{
890 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc; 1241 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
index 1566f4de0eda..7778e02d7581 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
@@ -23,6 +23,7 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr);
23bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); 23bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
24int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, 24int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
25 struct sk_buff *skb); 25 struct sk_buff *skb);
26int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
26 27
27void brcmf_fws_reset_interface(struct brcmf_if *ifp); 28void brcmf_fws_reset_interface(struct brcmf_if *ifp);
28void brcmf_fws_add_interface(struct brcmf_if *ifp); 29void brcmf_fws_add_interface(struct brcmf_if *ifp);