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