fwsignal.c revision c7f34a69a2e32b139a6b66c8599252c46f37abba
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/err.h> 23#include <uapi/linux/nl80211.h> 24 25#include <brcmu_utils.h> 26#include <brcmu_wifi.h> 27#include "dhd.h" 28#include "dhd_dbg.h" 29#include "dhd_bus.h" 30#include "fwil.h" 31#include "fweh.h" 32#include "fwsignal.h" 33 34/** 35 * DOC: Firmware Signalling 36 * 37 * Firmware can send signals to host and vice versa, which are passed in the 38 * data packets using TLV based header. This signalling layer is on top of the 39 * BDC bus protocol layer. 40 */ 41 42/* 43 * single definition for firmware-driver flow control tlv's. 44 * 45 * each tlv is specified by BRCMF_FWS_TLV_DEF(name, ID, length). 46 * A length value 0 indicates variable length tlv. 47 */ 48#define BRCMF_FWS_TLV_DEFLIST \ 49 BRCMF_FWS_TLV_DEF(MAC_OPEN, 1, 1) \ 50 BRCMF_FWS_TLV_DEF(MAC_CLOSE, 2, 1) \ 51 BRCMF_FWS_TLV_DEF(MAC_REQUEST_CREDIT, 3, 2) \ 52 BRCMF_FWS_TLV_DEF(TXSTATUS, 4, 4) \ 53 BRCMF_FWS_TLV_DEF(PKTTAG, 5, 4) \ 54 BRCMF_FWS_TLV_DEF(MACDESC_ADD, 6, 8) \ 55 BRCMF_FWS_TLV_DEF(MACDESC_DEL, 7, 8) \ 56 BRCMF_FWS_TLV_DEF(RSSI, 8, 1) \ 57 BRCMF_FWS_TLV_DEF(INTERFACE_OPEN, 9, 1) \ 58 BRCMF_FWS_TLV_DEF(INTERFACE_CLOSE, 10, 1) \ 59 BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 8) \ 60 BRCMF_FWS_TLV_DEF(PENDING_TRAFFIC_BMP, 12, 2) \ 61 BRCMF_FWS_TLV_DEF(MAC_REQUEST_PACKET, 13, 3) \ 62 BRCMF_FWS_TLV_DEF(HOST_REORDER_RXPKTS, 14, 10) \ 63 BRCMF_FWS_TLV_DEF(TRANS_ID, 18, 6) \ 64 BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \ 65 BRCMF_FWS_TLV_DEF(FILLER, 255, 0) 66 67/** 68 * enum brcmf_fws_tlv_type - definition of tlv identifiers. 69 */ 70#define BRCMF_FWS_TLV_DEF(name, id, len) \ 71 BRCMF_FWS_TYPE_ ## name = id, 72enum brcmf_fws_tlv_type { 73 BRCMF_FWS_TLV_DEFLIST 74 BRCMF_FWS_TYPE_INVALID 75}; 76#undef BRCMF_FWS_TLV_DEF 77 78#ifdef DEBUG 79/** 80 * brcmf_fws_tlv_names - array of tlv names. 81 */ 82#define BRCMF_FWS_TLV_DEF(name, id, len) \ 83 { id, #name }, 84static struct { 85 enum brcmf_fws_tlv_type id; 86 const char *name; 87} brcmf_fws_tlv_names[] = { 88 BRCMF_FWS_TLV_DEFLIST 89}; 90#undef BRCMF_FWS_TLV_DEF 91 92static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) 93{ 94 int i; 95 96 for (i = 0; i < ARRAY_SIZE(brcmf_fws_tlv_names); i++) 97 if (brcmf_fws_tlv_names[i].id == id) 98 return brcmf_fws_tlv_names[i].name; 99 100 return "INVALID"; 101} 102#else 103static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) 104{ 105 return "NODEBUG"; 106} 107#endif /* DEBUG */ 108 109/** 110 * flags used to enable tlv signalling from firmware. 111 */ 112#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001 113#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002 114#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 115#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 116#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 117#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 118#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040 119 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 126#define BRCMF_FWS_STATE_CLOSE 2 127 128#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32 129#define BRCMF_FWS_MAX_IFNUM 16 130#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff 131 132#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0 133#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1 134 135#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2) 136#define BRCMF_FWS_PSQ_LEN 256 137 138/** 139 * enum brcmf_fws_skb_state - indicates processing state of skb. 140 */ 141enum brcmf_fws_skb_state { 142 WLFC_PKTTYPE_NEW, 143 WLFC_PKTTYPE_DELAYED, 144 WLFC_PKTTYPE_SUPPRESSED, 145 WLFC_PKTTYPE_MAX 146}; 147 148/** 149 * struct brcmf_skbuff_cb - control buffer associated with skbuff. 150 * 151 * @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). 154 * @needs_hdr: the packet does not yet have a BDC header. 155 * @state: transmit state of the packet. 156 * @mac: descriptor related to destination for this packet. 157 * 158 * This information is stored in control buffer struct sk_buff::cb, which 159 * provides 48 bytes of storage so this structure should not exceed that. 160 */ 161struct brcmf_skbuff_cb { 162 u16 if_flags; 163 u8 da[ETH_ALEN]; 164 u32 htod; 165 u8 needs_hdr; 166 enum brcmf_fws_skb_state state; 167 struct brcmf_fws_mac_descriptor *mac; 168}; 169 170/** 171 * macro casting skbuff control buffer to struct brcmf_skbuff_cb. 172 */ 173#define brcmf_skbcb(skb) ((struct brcmf_skbuff_cb *)((skb)->cb)) 174 175/** 176 * sk_buff control if flags 177 * 178 * b[11] - packet sent upon firmware request. 179 * b[10] - packet only contains signalling data. 180 * b[9] - packet is a tx packet. 181 * b[8] - packet uses FIFO credit (non-pspoll). 182 * b[7] - interface in AP mode. 183 * b[6:4] - AC FIFO number. 184 * b[3:0] - interface index. 185 */ 186#define BRCMF_SKB_IF_FLAGS_REQUESTED_MASK 0x0800 187#define BRCMF_SKB_IF_FLAGS_REQUESTED_SHIFT 11 188#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_MASK 0x0400 189#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_SHIFT 10 190#define BRCMF_SKB_IF_FLAGS_TRANSMIT_MASK 0x0200 191#define BRCMF_SKB_IF_FLAGS_TRANSMIT_SHIFT 9 192#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK 0x0100 193#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_SHIFT 8 194#define BRCMF_SKB_IF_FLAGS_IF_AP_MASK 0x0080 195#define BRCMF_SKB_IF_FLAGS_IF_AP_SHIFT 7 196#define BRCMF_SKB_IF_FLAGS_FIFO_MASK 0x0070 197#define BRCMF_SKB_IF_FLAGS_FIFO_SHIFT 4 198#define BRCMF_SKB_IF_FLAGS_INDEX_MASK 0x000f 199#define BRCMF_SKB_IF_FLAGS_INDEX_SHIFT 0 200 201#define brcmf_skb_if_flags_set_field(skb, field, value) \ 202 brcmu_maskset16(&(brcmf_skbcb(skb)->if_flags), \ 203 BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \ 204 BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT, (value)) 205#define brcmf_skb_if_flags_get_field(skb, field) \ 206 brcmu_maskget16(brcmf_skbcb(skb)->if_flags, \ 207 BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \ 208 BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT) 209 210/** 211 * sk_buff control packet identifier 212 * 213 * 32-bit packet identifier used in PKTTAG tlv from host to dongle. 214 * 215 * - Generated at the host (e.g. dhd) 216 * - Seen as a generic sequence number by firmware except for the flags field. 217 * 218 * Generation : b[31] => generation number for this packet [host->fw] 219 * OR, current generation number [fw->host] 220 * Flags : b[30:27] => command, status flags 221 * FIFO-AC : b[26:24] => AC-FIFO id 222 * h-slot : b[23:8] => hanger-slot 223 * freerun : b[7:0] => A free running counter 224 */ 225#define BRCMF_SKB_HTOD_TAG_GENERATION_MASK 0x80000000 226#define BRCMF_SKB_HTOD_TAG_GENERATION_SHIFT 31 227#define BRCMF_SKB_HTOD_TAG_FLAGS_MASK 0x78000000 228#define BRCMF_SKB_HTOD_TAG_FLAGS_SHIFT 27 229#define BRCMF_SKB_HTOD_TAG_FIFO_MASK 0x07000000 230#define BRCMF_SKB_HTOD_TAG_FIFO_SHIFT 24 231#define BRCMF_SKB_HTOD_TAG_HSLOT_MASK 0x00ffff00 232#define BRCMF_SKB_HTOD_TAG_HSLOT_SHIFT 8 233#define BRCMF_SKB_HTOD_TAG_FREERUN_MASK 0x000000ff 234#define BRCMF_SKB_HTOD_TAG_FREERUN_SHIFT 0 235 236#define brcmf_skb_htod_tag_set_field(skb, field, value) \ 237 brcmu_maskset32(&(brcmf_skbcb(skb)->htod), \ 238 BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \ 239 BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT, (value)) 240#define brcmf_skb_htod_tag_get_field(skb, field) \ 241 brcmu_maskget32(brcmf_skbcb(skb)->htod, \ 242 BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \ 243 BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT) 244 245enum brcmf_fws_fcmode { 246 BRCMF_FWS_FCMODE_NONE, 247 BRCMF_FWS_FCMODE_IMPLIED_CREDIT, 248 BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 249}; 250 251/** 252 * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface 253 * 254 * @occupied: slot is in use. 255 * @mac_handle: handle for mac entry determined by firmware. 256 * @interface_id: interface index. 257 * @state: current state. 258 * @ac_bitmap: ac queue bitmap. 259 * @requested_credit: credits requested by firmware. 260 * @ea: ethernet address. 261 * @psq: power-save queue. 262 */ 263struct brcmf_fws_mac_descriptor { 264 u8 occupied; 265 u8 mac_handle; 266 u8 interface_id; 267 u8 state; 268 u8 ac_bitmap; 269 u8 requested_credit; 270 u8 ea[ETH_ALEN]; 271 struct pktq psq; 272}; 273 274#define BRCMF_FWS_HANGER_MAXITEMS 1024 275 276/** 277 * enum brcmf_fws_hanger_item_state - state of hanger item. 278 * 279 * @WLFC_HANGER_ITEM_STATE_FREE: item is free for use. 280 * @WLFC_HANGER_ITEM_STATE_INUSE: item is in use. 281 * @WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed. 282 */ 283enum brcmf_fws_hanger_item_state { 284 WLFC_HANGER_ITEM_STATE_FREE = 1, 285 WLFC_HANGER_ITEM_STATE_INUSE, 286 WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 287}; 288 289 290/** 291 * struct brcmf_fws_hanger_item - single entry for tx pending packet. 292 * 293 * @state: entry is either free or occupied. 294 * @gen: generation. 295 * @identifier: packet identifier. 296 * @pkt: packet itself. 297 */ 298struct brcmf_fws_hanger_item { 299 enum brcmf_fws_hanger_item_state state; 300 u8 gen; 301 u8 pad[2]; 302 u32 identifier; 303 struct sk_buff *pkt; 304}; 305 306/** 307 * struct brcmf_fws_hanger - holds packets awaiting firmware txstatus. 308 * 309 * @max_items: number of packets it can hold. 310 * @pushed: packets pushed to await txstatus. 311 * @popped: packets popped upon handling txstatus. 312 * @failed_to_push: packets that could not be pushed. 313 * @failed_to_pop: packets that could not be popped. 314 * @failed_slotfind: packets for which failed to find an entry. 315 * @slot_pos: last returned item index for a free entry. 316 * @items: array of hanger items. 317 */ 318struct brcmf_fws_hanger { 319 u32 pushed; 320 u32 popped; 321 u32 failed_to_push; 322 u32 failed_to_pop; 323 u32 failed_slotfind; 324 u32 slot_pos; 325 struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS]; 326}; 327 328struct brcmf_fws_info { 329 struct brcmf_pub *drvr; 330 struct brcmf_fws_stats stats; 331 struct brcmf_fws_hanger hanger; 332 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE]; 333 struct brcmf_fws_mac_descriptor other; 334 enum brcmf_fws_fcmode fcmode; 335 int fifo_credit[NL80211_NUM_ACS+1+1]; 336}; 337 338static int fcmode; 339module_param(fcmode, int, S_IRUSR); 340MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control"); 341 342/** 343 * brcmf_fws_get_tlv_len() - returns defined length for given tlv id. 344 */ 345#define BRCMF_FWS_TLV_DEF(name, id, len) \ 346 case BRCMF_FWS_TYPE_ ## name: \ 347 return len; 348 349static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws, 350 enum brcmf_fws_tlv_type id) 351{ 352 switch (id) { 353 BRCMF_FWS_TLV_DEFLIST 354 default: 355 brcmf_err("invalid tlv id: %d\n", id); 356 fws->stats.tlv_invalid_type++; 357 break; 358 } 359 return -EINVAL; 360} 361#undef BRCMF_FWS_TLV_DEF 362 363static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger) 364{ 365 int i; 366 367 brcmf_dbg(TRACE, "enter\n"); 368 memset(hanger, 0, sizeof(*hanger)); 369 for (i = 0; i < ARRAY_SIZE(hanger->items); i++) 370 hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; 371} 372 373static __used u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h) 374{ 375 u32 i; 376 377 brcmf_dbg(TRACE, "enter\n"); 378 i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS; 379 380 while (i != h->slot_pos) { 381 if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { 382 h->slot_pos = i; 383 return i; 384 } 385 i++; 386 if (i == BRCMF_FWS_HANGER_MAXITEMS) 387 i = 0; 388 } 389 brcmf_err("all slots occupied\n"); 390 h->failed_slotfind++; 391 return BRCMF_FWS_HANGER_MAXITEMS; 392} 393 394static __used int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h, 395 struct sk_buff *pkt, u32 slot_id) 396{ 397 brcmf_dbg(TRACE, "enter\n"); 398 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS) 399 return -ENOENT; 400 401 if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) { 402 brcmf_err("slot is not free\n"); 403 h->failed_to_push++; 404 return -EINVAL; 405 } 406 407 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE; 408 h->items[slot_id].pkt = pkt; 409 h->items[slot_id].identifier = slot_id; 410 h->pushed++; 411 return 0; 412} 413 414static __used int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h, 415 u32 slot_id, struct sk_buff **pktout, 416 bool remove_item) 417{ 418 brcmf_dbg(TRACE, "enter\n"); 419 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS) 420 return -ENOENT; 421 422 if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) { 423 brcmf_err("entry not in use\n"); 424 h->failed_to_pop++; 425 return -EINVAL; 426 } 427 428 *pktout = h->items[slot_id].pkt; 429 if (remove_item) { 430 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE; 431 h->items[slot_id].pkt = NULL; 432 h->items[slot_id].identifier = 0; 433 h->items[slot_id].gen = 0xff; 434 h->popped++; 435 } 436 return 0; 437} 438 439static __used int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h, 440 u32 slot_id, u8 gen) 441{ 442 brcmf_dbg(TRACE, "enter\n"); 443 444 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS) 445 return -ENOENT; 446 447 h->items[slot_id].gen = gen; 448 449 if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_INUSE) { 450 brcmf_err("entry not in use\n"); 451 return -EINVAL; 452 } 453 454 h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; 455 return 0; 456} 457 458static __used int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger, 459 struct sk_buff *pkt, u32 slot_id, 460 int *gen) 461{ 462 brcmf_dbg(TRACE, "enter\n"); 463 *gen = 0xff; 464 465 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS) 466 return -ENOENT; 467 468 if (hanger->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) { 469 brcmf_err("slot not in use\n"); 470 return -EINVAL; 471 } 472 473 *gen = hanger->items[slot_id].gen; 474 return 0; 475} 476 477static void brcmf_fws_hanger_cleanup(struct brcmf_fws_hanger *h, 478 bool (*fn)(struct sk_buff *, void *), 479 int ifidx) 480{ 481 struct sk_buff *skb; 482 int i; 483 enum brcmf_fws_hanger_item_state s; 484 485 brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx); 486 for (i = 0; i < ARRAY_SIZE(h->items); i++) { 487 s = h->items[i].state; 488 if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE || 489 s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { 490 skb = h->items[i].pkt; 491 if (fn == NULL || fn(skb, &ifidx)) { 492 /* suppress packets freed from psq */ 493 if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE) 494 brcmu_pkt_buf_free_skb(skb); 495 h->items[i].state = 496 BRCMF_FWS_HANGER_ITEM_STATE_FREE; 497 } 498 } 499 } 500} 501 502static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc, 503 u8 *addr, u8 ifidx) 504{ 505 brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u\n", addr, ifidx); 506 desc->occupied = 1; 507 desc->state = BRCMF_FWS_STATE_OPEN; 508 desc->requested_credit = 0; 509 /* depending on use may need ifp->bssidx instead */ 510 desc->interface_id = ifidx; 511 desc->ac_bitmap = 0xff; /* update this when handling APSD */ 512 memcpy(&desc->ea[0], addr, ETH_ALEN); 513} 514 515static 516void brcmf_fws_clear_mac_descriptor(struct brcmf_fws_mac_descriptor *desc) 517{ 518 brcmf_dbg(TRACE, 519 "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id); 520 desc->occupied = 0; 521 desc->state = BRCMF_FWS_STATE_CLOSE; 522 desc->requested_credit = 0; 523} 524 525static struct brcmf_fws_mac_descriptor * 526brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea) 527{ 528 struct brcmf_fws_mac_descriptor *entry; 529 int i; 530 531 brcmf_dbg(TRACE, "enter: ea=%pM\n", ea); 532 if (ea == NULL) 533 return ERR_PTR(-EINVAL); 534 535 entry = &fws->nodes[0]; 536 for (i = 0; i < ARRAY_SIZE(fws->nodes); i++) { 537 if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN)) 538 return entry; 539 entry++; 540 } 541 542 return ERR_PTR(-ENOENT); 543} 544 545static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_mac_descriptor *entry, 546 bool (*fn)(struct sk_buff *, void *), 547 int ifidx) 548{ 549 brcmf_dbg(TRACE, "enter: entry=(ea=%pM,ifid=%d), ifidx=%d\n", 550 entry->ea, entry->interface_id, ifidx); 551 if (entry->occupied && (fn == NULL || (ifidx == entry->interface_id))) { 552 brcmf_dbg(TRACE, "flush delayQ: ifidx=%d, qlen=%d\n", 553 ifidx, entry->psq.len); 554 /* release packets held in DELAYQ */ 555 brcmu_pktq_flush(&entry->psq, true, fn, &ifidx); 556 entry->occupied = !!(entry->psq.len); 557 } 558} 559 560static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws, 561 bool (*fn)(struct sk_buff *, void *), 562 int ifidx) 563{ 564 struct brcmf_fws_hanger_item *hi; 565 struct pktq *txq; 566 struct sk_buff *skb; 567 int prec; 568 u32 hslot; 569 570 brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx); 571 txq = brcmf_bus_gettxq(fws->drvr->bus_if); 572 if (IS_ERR(txq)) { 573 brcmf_dbg(TRACE, "no txq to clean up\n"); 574 return; 575 } 576 577 for (prec = 0; prec < txq->num_prec; prec++) { 578 skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx); 579 while (skb) { 580 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); 581 hi = &fws->hanger.items[hslot]; 582 WARN_ON(skb != hi->pkt); 583 hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE; 584 brcmu_pkt_buf_free_skb(skb); 585 skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx); 586 } 587 } 588} 589 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) 597{ 598 int i; 599 struct brcmf_fws_mac_descriptor *table; 600 bool (*matchfn)(struct sk_buff *, void *) = NULL; 601 602 brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx); 603 if (fws == NULL) 604 return; 605 606 if (ifidx != -1) 607 matchfn = brcmf_fws_ifidx_match; 608 609 /* cleanup individual nodes */ 610 table = &fws->nodes[0]; 611 for (i = 0; i < ARRAY_SIZE(fws->nodes); i++) 612 brcmf_fws_mac_desc_cleanup(&table[i], matchfn, ifidx); 613 614 brcmf_fws_mac_desc_cleanup(&fws->other, matchfn, ifidx); 615 brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx); 616 brcmf_fws_hanger_cleanup(&fws->hanger, matchfn, ifidx); 617} 618 619static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) 620{ 621 brcmf_dbg(CTL, "rssi %d\n", rssi); 622 return 0; 623} 624 625static 626int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) 627{ 628 struct brcmf_fws_mac_descriptor *entry, *existing; 629 u8 mac_handle; 630 u8 ifidx; 631 u8 *addr; 632 633 mac_handle = *data++; 634 ifidx = *data++; 635 addr = data; 636 637 entry = &fws->nodes[mac_handle & 0x1F]; 638 if (type == BRCMF_FWS_TYPE_MACDESC_DEL) { 639 brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx); 640 if (entry->occupied) { 641 entry->occupied = 0; 642 entry->state = BRCMF_FWS_STATE_CLOSE; 643 entry->requested_credit = 0; 644 } else { 645 fws->stats.mac_update_failed++; 646 } 647 return 0; 648 } 649 650 brcmf_dbg(TRACE, "add mac %pM idx %d\n", addr, ifidx); 651 existing = brcmf_fws_mac_descriptor_lookup(fws, addr); 652 if (IS_ERR(existing)) { 653 if (!entry->occupied) { 654 entry->mac_handle = mac_handle; 655 brcmf_fws_init_mac_descriptor(entry, addr, ifidx); 656 brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, 657 BRCMF_FWS_PSQ_LEN); 658 } else { 659 fws->stats.mac_update_failed++; 660 } 661 } else { 662 if (entry != existing) { 663 brcmf_dbg(TRACE, "relocate mac\n"); 664 memcpy(entry, existing, 665 offsetof(struct brcmf_fws_mac_descriptor, psq)); 666 entry->mac_handle = mac_handle; 667 brcmf_fws_clear_mac_descriptor(existing); 668 } else { 669 brcmf_dbg(TRACE, "use existing\n"); 670 WARN_ON(entry->mac_handle != mac_handle); 671 /* TODO: what should we do here: continue, reinit, .. */ 672 } 673 } 674 return 0; 675} 676 677static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) 678{ 679 __le32 timestamp; 680 681 memcpy(×tamp, &data[2], sizeof(timestamp)); 682 brcmf_dbg(INFO, "received: seq %d, timestamp %d\n", data[1], 683 le32_to_cpu(timestamp)); 684 return 0; 685} 686 687/* using macro so sparse checking does not complain 688 * about locking imbalance. 689 */ 690#define brcmf_fws_lock(drvr, flags) \ 691do { \ 692 flags = 0; \ 693 spin_lock_irqsave(&((drvr)->fws_spinlock), (flags)); \ 694} while (0) 695 696/* using macro so sparse checking does not complain 697 * about locking imbalance. 698 */ 699#define brcmf_fws_unlock(drvr, flags) \ 700 spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags)) 701 702static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, 703 const struct brcmf_event_msg *e, 704 void *data) 705{ 706 struct brcmf_fws_info *fws = ifp->drvr->fws; 707 int i; 708 ulong flags; 709 u8 *credits = data; 710 711 brcmf_fws_lock(ifp->drvr, flags); 712 for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) 713 fws->fifo_credit[i] = *credits++; 714 brcmf_fws_unlock(ifp->drvr, flags); 715 return 0; 716} 717 718int brcmf_fws_init(struct brcmf_pub *drvr) 719{ 720 u32 tlv = 0; 721 int rc; 722 723 /* enable rssi signals */ 724 if (drvr->fw_signals) 725 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS | 726 BRCMF_FWS_FLAGS_XONXOFF_SIGNALS; 727 728 spin_lock_init(&drvr->fws_spinlock); 729 730 drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL); 731 if (!drvr->fws) { 732 rc = -ENOMEM; 733 goto fail; 734 } 735 736 /* enable proptxtstatus signaling by default */ 737 rc = brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv); 738 if (rc < 0) { 739 brcmf_err("failed to set bdcv2 tlv signaling\n"); 740 goto fail; 741 } 742 743 if (brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP, 744 brcmf_fws_notify_credit_map)) { 745 brcmf_err("register credit map handler failed\n"); 746 goto fail; 747 } 748 749 brcmf_fws_hanger_init(&drvr->fws->hanger); 750 751 /* create debugfs file for statistics */ 752 brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats); 753 754 /* set linkage back */ 755 drvr->fws->drvr = drvr; 756 drvr->fws->fcmode = fcmode; 757 758 /* TODO: remove upon feature delivery */ 759 brcmf_err("%s bdcv2 tlv signaling [%x]\n", 760 drvr->fw_signals ? "enabled" : "disabled", tlv); 761 return 0; 762 763fail: 764 /* disable flow control entirely */ 765 drvr->fw_signals = false; 766 brcmf_fws_deinit(drvr); 767 return rc; 768} 769 770void brcmf_fws_deinit(struct brcmf_pub *drvr) 771{ 772 struct brcmf_fws_info *fws = drvr->fws; 773 ulong flags; 774 775 /* cleanup */ 776 brcmf_fws_lock(drvr, flags); 777 brcmf_fws_cleanup(fws, -1); 778 drvr->fws = NULL; 779 brcmf_fws_unlock(drvr, flags); 780 781 /* free top structure */ 782 kfree(fws); 783} 784 785int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, 786 struct sk_buff *skb) 787{ 788 struct brcmf_fws_info *fws = drvr->fws; 789 ulong flags; 790 u8 *signal_data; 791 s16 data_len; 792 u8 type; 793 u8 len; 794 u8 *data; 795 796 brcmf_dbg(TRACE, "enter: ifidx %d, skblen %u, sig %d\n", 797 ifidx, skb->len, signal_len); 798 799 WARN_ON(signal_len > skb->len); 800 801 /* if flow control disabled, skip to packet data and leave */ 802 if (!signal_len || !drvr->fw_signals) { 803 skb_pull(skb, signal_len); 804 return 0; 805 } 806 807 /* lock during tlv parsing */ 808 brcmf_fws_lock(drvr, flags); 809 810 fws->stats.header_pulls++; 811 data_len = signal_len; 812 signal_data = skb->data; 813 814 while (data_len > 0) { 815 /* extract tlv info */ 816 type = signal_data[0]; 817 818 /* FILLER type is actually not a TLV, but 819 * a single byte that can be skipped. 820 */ 821 if (type == BRCMF_FWS_TYPE_FILLER) { 822 signal_data += 1; 823 data_len -= 1; 824 continue; 825 } 826 len = signal_data[1]; 827 data = signal_data + 2; 828 829 /* abort parsing when length invalid */ 830 if (data_len < len + 2) 831 break; 832 833 if (len != brcmf_fws_get_tlv_len(fws, type)) 834 break; 835 836 brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type, 837 brcmf_fws_get_tlv_name(type), len); 838 switch (type) { 839 case BRCMF_FWS_TYPE_MAC_OPEN: 840 case BRCMF_FWS_TYPE_MAC_CLOSE: 841 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT: 842 case BRCMF_FWS_TYPE_TXSTATUS: 843 case BRCMF_FWS_TYPE_PKTTAG: 844 case BRCMF_FWS_TYPE_INTERFACE_OPEN: 845 case BRCMF_FWS_TYPE_INTERFACE_CLOSE: 846 case BRCMF_FWS_TYPE_FIFO_CREDITBACK: 847 case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP: 848 case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET: 849 case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: 850 case BRCMF_FWS_TYPE_COMP_TXSTATUS: 851 break; 852 case BRCMF_FWS_TYPE_MACDESC_ADD: 853 case BRCMF_FWS_TYPE_MACDESC_DEL: 854 brcmf_fws_macdesc_indicate(fws, type, data); 855 break; 856 case BRCMF_FWS_TYPE_RSSI: 857 brcmf_fws_rssi_indicate(fws, *data); 858 break; 859 case BRCMF_FWS_TYPE_TRANS_ID: 860 brcmf_fws_dbg_seqnum_check(fws, data); 861 break; 862 default: 863 fws->stats.tlv_invalid_type++; 864 break; 865 } 866 867 signal_data += len + 2; 868 data_len -= len + 2; 869 } 870 871 if (data_len != 0) 872 fws->stats.tlv_parse_failed++; 873 874 /* signalling processing result does 875 * not affect the actual ethernet packet. 876 */ 877 skb_pull(skb, signal_len); 878 879 /* this may be a signal-only packet 880 */ 881 if (skb->len == 0) 882 fws->stats.header_only_pkt++; 883 884 brcmf_fws_unlock(drvr, flags); 885 return 0; 886} 887 888void brcmf_fws_reset_interface(struct brcmf_if *ifp) 889{ 890 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc; 891 892 brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx); 893 if (!entry) 894 return; 895 896 brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx); 897} 898 899void brcmf_fws_add_interface(struct brcmf_if *ifp) 900{ 901 struct brcmf_fws_mac_descriptor *entry; 902 903 brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n", 904 ifp->bssidx, ifp->mac_addr); 905 if (!ifp->drvr->fw_signals) 906 return; 907 908 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 909 if (entry) { 910 ifp->fws_desc = entry; 911 brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx); 912 brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, 913 BRCMF_FWS_PSQ_LEN); 914 } else { 915 brcmf_err("no firmware signalling\n"); 916 } 917} 918 919void brcmf_fws_del_interface(struct brcmf_if *ifp) 920{ 921 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc; 922 923 brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx); 924 if (!entry) 925 return; 926 927 ifp->fws_desc = NULL; 928 brcmf_fws_clear_mac_descriptor(entry); 929 brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx); 930 kfree(entry); 931} 932 933bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) 934{ 935 if (!fws) 936 return false; 937 938 brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode); 939 return fws->fcmode != BRCMF_FWS_FCMODE_NONE; 940} 941