aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-03 06:40:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-03 15:07:05 -0400
commit6971280aefe437262f6d52339b0b2d5d64ab4e15 (patch)
treef1a592ec885710291e74520c41d4e4cecee0ed93 /drivers/net/wireless
parenta3e993c78631b918f26db38605678889e3a5e964 (diff)
brcmfmac: add firmware-signalling hanger functions
The hanger for firmware-signalling is used to retain information for outstanding transmit packets that await tx status. 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/net/wireless')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index b123a80b17cf..a6443c667e33 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -267,9 +267,64 @@ struct brcmf_fws_mac_descriptor {
267 struct pktq psq; 267 struct pktq psq;
268}; 268};
269 269
270#define BRCMF_FWS_HANGER_MAXITEMS 1024
271
272/**
273 * enum brcmf_fws_hanger_item_state - state of hanger item.
274 *
275 * @WLFC_HANGER_ITEM_STATE_FREE: item is free for use.
276 * @WLFC_HANGER_ITEM_STATE_INUSE: item is in use.
277 * @WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed.
278 */
279enum brcmf_fws_hanger_item_state {
280 WLFC_HANGER_ITEM_STATE_FREE = 1,
281 WLFC_HANGER_ITEM_STATE_INUSE,
282 WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED
283};
284
285
286/**
287 * struct brcmf_fws_hanger_item - single entry for tx pending packet.
288 *
289 * @state: entry is either free or occupied.
290 * @gen: generation.
291 * @identifier: packet identifier.
292 * @pkt: packet itself.
293 */
294struct brcmf_fws_hanger_item {
295 enum brcmf_fws_hanger_item_state state;
296 u8 gen;
297 u8 pad[2];
298 u32 identifier;
299 struct sk_buff *pkt;
300};
301
302/**
303 * struct brcmf_fws_hanger - holds packets awaiting firmware txstatus.
304 *
305 * @max_items: number of packets it can hold.
306 * @pushed: packets pushed to await txstatus.
307 * @popped: packets popped upon handling txstatus.
308 * @failed_to_push: packets that could not be pushed.
309 * @failed_to_pop: packets that could not be popped.
310 * @failed_slotfind: packets for which failed to find an entry.
311 * @slot_pos: last returned item index for a free entry.
312 * @items: array of hanger items.
313 */
314struct brcmf_fws_hanger {
315 u32 pushed;
316 u32 popped;
317 u32 failed_to_push;
318 u32 failed_to_pop;
319 u32 failed_slotfind;
320 u32 slot_pos;
321 struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS];
322};
323
270struct brcmf_fws_info { 324struct brcmf_fws_info {
271 struct brcmf_pub *drvr; 325 struct brcmf_pub *drvr;
272 struct brcmf_fws_stats stats; 326 struct brcmf_fws_stats stats;
327 struct brcmf_fws_hanger hanger;
273 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE]; 328 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
274 struct brcmf_fws_mac_descriptor other; 329 struct brcmf_fws_mac_descriptor other;
275 int fifo_credit[NL80211_NUM_ACS+1+1]; 330 int fifo_credit[NL80211_NUM_ACS+1+1];
@@ -296,6 +351,145 @@ static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
296} 351}
297#undef BRCMF_FWS_TLV_DEF 352#undef BRCMF_FWS_TLV_DEF
298 353
354static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
355{
356 int i;
357
358 brcmf_dbg(TRACE, "enter\n");
359 memset(hanger, 0, sizeof(*hanger));
360 for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
361 hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE;
362}
363
364static __used u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
365{
366 u32 i;
367
368 brcmf_dbg(TRACE, "enter\n");
369 i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
370
371 while (i != h->slot_pos) {
372 if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) {
373 h->slot_pos = i;
374 return i;
375 }
376 i++;
377 if (i == BRCMF_FWS_HANGER_MAXITEMS)
378 i = 0;
379 }
380 brcmf_err("all slots occupied\n");
381 h->failed_slotfind++;
382 return BRCMF_FWS_HANGER_MAXITEMS;
383}
384
385static __used int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
386 struct sk_buff *pkt, u32 slot_id)
387{
388 brcmf_dbg(TRACE, "enter\n");
389 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
390 return -ENOENT;
391
392 if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
393 brcmf_err("slot is not free\n");
394 h->failed_to_push++;
395 return -EINVAL;
396 }
397
398 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
399 h->items[slot_id].pkt = pkt;
400 h->items[slot_id].identifier = slot_id;
401 h->pushed++;
402 return 0;
403}
404
405static __used int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
406 u32 slot_id, struct sk_buff **pktout,
407 bool remove_item)
408{
409 brcmf_dbg(TRACE, "enter\n");
410 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
411 return -ENOENT;
412
413 if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
414 brcmf_err("entry not in use\n");
415 h->failed_to_pop++;
416 return -EINVAL;
417 }
418
419 *pktout = h->items[slot_id].pkt;
420 if (remove_item) {
421 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
422 h->items[slot_id].pkt = NULL;
423 h->items[slot_id].identifier = 0;
424 h->items[slot_id].gen = 0xff;
425 h->popped++;
426 }
427 return 0;
428}
429
430static __used int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
431 u32 slot_id, u8 gen)
432{
433 brcmf_dbg(TRACE, "enter\n");
434
435 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
436 return -ENOENT;
437
438 h->items[slot_id].gen = gen;
439
440 if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_INUSE) {
441 brcmf_err("entry not in use\n");
442 return -EINVAL;
443 }
444
445 h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
446 return 0;
447}
448
449static __used int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger,
450 struct sk_buff *pkt, u32 slot_id,
451 int *gen)
452{
453 brcmf_dbg(TRACE, "enter\n");
454 *gen = 0xff;
455
456 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
457 return -ENOENT;
458
459 if (hanger->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
460 brcmf_err("slot not in use\n");
461 return -EINVAL;
462 }
463
464 *gen = hanger->items[slot_id].gen;
465 return 0;
466}
467
468static void brcmf_fws_hanger_cleanup(struct brcmf_fws_hanger *h,
469 bool (*fn)(struct sk_buff *, void *),
470 int ifidx)
471{
472 struct sk_buff *skb;
473 int i;
474 enum brcmf_fws_hanger_item_state s;
475
476 brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
477 for (i = 0; i < ARRAY_SIZE(h->items); i++) {
478 s = h->items[i].state;
479 if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
480 s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
481 skb = h->items[i].pkt;
482 if (fn == NULL || fn(skb, &ifidx)) {
483 /* suppress packets freed from psq */
484 if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
485 brcmu_pkt_buf_free_skb(skb);
486 h->items[i].state =
487 BRCMF_FWS_HANGER_ITEM_STATE_FREE;
488 }
489 }
490 }
491}
492
299static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc, 493static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
300 u8 *addr, u8 ifidx) 494 u8 *addr, u8 ifidx)
301{ 495{
@@ -379,6 +573,7 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
379 brcmf_fws_mac_desc_cleanup(&table[i], matchfn, ifidx); 573 brcmf_fws_mac_desc_cleanup(&table[i], matchfn, ifidx);
380 574
381 brcmf_fws_mac_desc_cleanup(&fws->other, matchfn, ifidx); 575 brcmf_fws_mac_desc_cleanup(&fws->other, matchfn, ifidx);
576 brcmf_fws_hanger_cleanup(&fws->hanger, matchfn, ifidx);
382} 577}
383 578
384static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) 579static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
@@ -511,6 +706,8 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
511 goto fail; 706 goto fail;
512 } 707 }
513 708
709 brcmf_fws_hanger_init(&drvr->fws->hanger);
710
514 /* create debugfs file for statistics */ 711 /* create debugfs file for statistics */
515 brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats); 712 brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
516 713