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_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
 584                                int ifidx)
 585{
 586        bool (*matchfn)(struct sk_buff *, void *) = NULL;
 587        struct sk_buff *skb;
 588        int prec;
 589
 590        if (ifidx != -1)
 591                matchfn = brcmf_fws_ifidx_match;
 592        for (prec = 0; prec < q->num_prec; prec++) {
 593                skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
 594                while (skb) {
 595                        brcmu_pkt_buf_free_skb(skb);
 596                        skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
 597                }
 598        }
 599}
 600
 601static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
 602{
 603        int i;
 604
 605        memset(hanger, 0, sizeof(*hanger));
 606        for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
 607                hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
 608}
 609
 610static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
 611{
 612        u32 i;
 613
 614        i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
 615
 616        while (i != h->slot_pos) {
 617                if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
 618                        h->slot_pos = i;
 619                        goto done;
 620                }
 621                i++;
 622                if (i == BRCMF_FWS_HANGER_MAXITEMS)
 623                        i = 0;
 624        }
 625        brcmf_err("all slots occupied\n");
 626        h->failed_slotfind++;
 627        i = BRCMF_FWS_HANGER_MAXITEMS;
 628done:
 629        return i;
 630}
 631
 632static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
 633                                    struct sk_buff *pkt, u32 slot_id)
 634{
 635        if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
 636                return -ENOENT;
 637
 638        if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
 639                brcmf_err("slot is not free\n");
 640                h->failed_to_push++;
 641                return -EINVAL;
 642        }
 643
 644        h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
 645        h->items[slot_id].pkt = pkt;
 646        h->pushed++;
 647        return 0;
 648}
 649
 650static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
 651                                          u32 slot_id, struct sk_buff **pktout,
 652                                          bool remove_item)
 653{
 654        if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
 655                return -ENOENT;
 656
 657        if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
 658                brcmf_err("entry not in use\n");
 659                h->failed_to_pop++;
 660                return -EINVAL;
 661        }
 662
 663        *pktout = h->items[slot_id].pkt;
 664        if (remove_item) {
 665                h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
 666                h->items[slot_id].pkt = NULL;
 667                h->popped++;
 668        }
 669        return 0;
 670}
 671
 672static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
 673                                            u32 slot_id)
 674{
 675        if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
 676                return -ENOENT;
 677
 678        if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
 679                brcmf_err("entry not in use\n");
 680                return -EINVAL;
 681        }
 682
 683        h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
 684        return 0;
 685}
 686
 687static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
 688                                     bool (*fn)(struct sk_buff *, void *),
 689                                     int ifidx)
 690{
 691        struct brcmf_fws_hanger *h = &fws->hanger;
 692        struct sk_buff *skb;
 693        int i;
 694        enum brcmf_fws_hanger_item_state s;
 695
 696        for (i = 0; i < ARRAY_SIZE(h->items); i++) {
 697                s = h->items[i].state;
 698                if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
 699                    s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
 700                        skb = h->items[i].pkt;
 701                        if (fn == NULL || fn(skb, &ifidx)) {
 702                                /* suppress packets freed from psq */
 703                                if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
 704                                        brcmu_pkt_buf_free_skb(skb);
 705                                h->items[i].state =
 706                                        BRCMF_FWS_HANGER_ITEM_STATE_FREE;
 707                        }
 708                }
 709        }
 710}
 711
 712static void brcmf_fws_macdesc_set_name(struct brcmf_fws_info *fws,
 713                                       struct brcmf_fws_mac_descriptor *desc)
 714{
 715        if (desc == &fws->desc.other)
 716                strlcpy(desc->name, "MAC-OTHER", sizeof(desc->name));
 717        else if (desc->mac_handle)
 718                scnprintf(desc->name, sizeof(desc->name), "MAC-%d:%d",
 719                          desc->mac_handle, desc->interface_id);
 720        else
 721                scnprintf(desc->name, sizeof(desc->name), "MACIF:%d",
 722                          desc->interface_id);
 723}
 724
 725static void brcmf_fws_macdesc_init(struct brcmf_fws_mac_descriptor *desc,
 726                                   u8 *addr, u8 ifidx)
 727{
 728        brcmf_dbg(TRACE,
 729                  "enter: desc %p ea=%pM, ifidx=%u\n", desc, addr, ifidx);
 730        desc->occupied = 1;
 731        desc->state = BRCMF_FWS_STATE_OPEN;
 732        desc->requested_credit = 0;
 733        desc->requested_packet = 0;
 734        /* depending on use may need ifp->bsscfgidx instead */
 735        desc->interface_id = ifidx;
 736        desc->ac_bitmap = 0xff; /* update this when handling APSD */
 737        if (addr)
 738                memcpy(&desc->ea[0], addr, ETH_ALEN);
 739}
 740
 741static
 742void brcmf_fws_macdesc_deinit(struct brcmf_fws_mac_descriptor *desc)
 743{
 744        brcmf_dbg(TRACE,
 745                  "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id);
 746        desc->occupied = 0;
 747        desc->state = BRCMF_FWS_STATE_CLOSE;
 748        desc->requested_credit = 0;
 749        desc->requested_packet = 0;
 750}
 751
 752static struct brcmf_fws_mac_descriptor *
 753brcmf_fws_macdesc_lookup(struct brcmf_fws_info *fws, u8 *ea)
 754{
 755        struct brcmf_fws_mac_descriptor *entry;
 756        int i;
 757
 758        if (ea == NULL)
 759                return ERR_PTR(-EINVAL);
 760
 761        entry = &fws->desc.nodes[0];
 762        for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++) {
 763                if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
 764                        return entry;
 765                entry++;
 766        }
 767
 768        return ERR_PTR(-ENOENT);
 769}
 770
 771static struct brcmf_fws_mac_descriptor*
 772brcmf_fws_macdesc_find(struct brcmf_fws_info *fws, struct brcmf_if *ifp, u8 *da)
 773{
 774        struct brcmf_fws_mac_descriptor *entry = &fws->desc.other;
 775        bool multicast;
 776
 777        multicast = is_multicast_ether_addr(da);
 778
 779        /* Multicast destination, STA and P2P clients get the interface entry.
 780         * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations
 781         * have their own entry.
 782         */
 783        if (multicast && ifp->fws_desc) {
 784                entry = ifp->fws_desc;
 785                goto done;
 786        }
 787
 788        entry = brcmf_fws_macdesc_lookup(fws, da);
 789        if (IS_ERR(entry))
 790                entry = ifp->fws_desc;
 791
 792done:
 793        return entry;
 794}
 795
 796static bool brcmf_fws_macdesc_closed(struct brcmf_fws_info *fws,
 797                                     struct brcmf_fws_mac_descriptor *entry,
 798                                     int fifo)
 799{
 800        struct brcmf_fws_mac_descriptor *if_entry;
 801        bool closed;
 802
 803        /* for unique destination entries the related interface
 804         * may be closed.
 805         */
 806        if (entry->mac_handle) {
 807                if_entry = &fws->desc.iface[entry->interface_id];
 808                if (if_entry->state == BRCMF_FWS_STATE_CLOSE)
 809                        return true;
 810        }
 811        /* an entry is closed when the state is closed and
 812         * the firmware did not request anything.
 813         */
 814        closed = entry->state == BRCMF_FWS_STATE_CLOSE &&
 815                 !entry->requested_credit && !entry->requested_packet;
 816
 817        /* Or firmware does not allow traffic for given fifo */
 818        return closed || !(entry->ac_bitmap & BIT(fifo));
 819}
 820
 821static void brcmf_fws_macdesc_cleanup(struct brcmf_fws_info *fws,
 822                                      struct brcmf_fws_mac_descriptor *entry,
 823                                      int ifidx)
 824{
 825        if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
 826                brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
 827                entry->occupied = !!(entry->psq.len);
 828        }
 829}
 830
 831static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
 832                                      bool (*fn)(struct sk_buff *, void *),
 833                                      int ifidx)
 834{
 835        struct brcmf_fws_hanger_item *hi;
 836        struct pktq *txq;
 837        struct sk_buff *skb;
 838        int prec;
 839        u32 hslot;
 840
 841        txq = brcmf_bus_gettxq(fws->drvr->bus_if);
 842        if (IS_ERR(txq)) {
 843                brcmf_dbg(TRACE, "no txq to clean up\n");
 844                return;
 845        }
 846
 847        for (prec = 0; prec < txq->num_prec; prec++) {
 848                skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
 849                while (skb) {
 850                        hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
 851                        hi = &fws->hanger.items[hslot];
 852                        WARN_ON(skb != hi->pkt);
 853                        hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
 854                        brcmu_pkt_buf_free_skb(skb);
 855                        skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
 856                }
 857        }
 858}
 859
 860static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
 861{
 862        int i;
 863        struct brcmf_fws_mac_descriptor *table;
 864        bool (*matchfn)(struct sk_buff *, void *) = NULL;
 865
 866        if (fws == NULL)
 867                return;
 868
 869        if (ifidx != -1)
 870                matchfn = brcmf_fws_ifidx_match;
 871
 872        /* cleanup individual nodes */
 873        table = &fws->desc.nodes[0];
 874        for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++)
 875                brcmf_fws_macdesc_cleanup(fws, &table[i], ifidx);
 876
 877        brcmf_fws_macdesc_cleanup(fws, &fws->desc.other, ifidx);
 878        brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
 879        brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
 880}
 881
 882static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
 883{
 884        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
 885        u8 *wlh;
 886        u16 data_offset = 0;
 887        u8 fillers;
 888        __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
 889        __le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq);
 890
 891        brcmf_dbg(TRACE, "enter: %s, idx=%d hslot=%d htod %X seq %X\n",
 892                  entry->name, brcmf_skb_if_flags_get_field(skb, INDEX),
 893                  (le32_to_cpu(pkttag) >> 8) & 0xffff,
 894                  brcmf_skbcb(skb)->htod, brcmf_skbcb(skb)->htod_seq);
 895        if (entry->send_tim_signal)
 896                data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
 897        if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
 898                data_offset += BRCMF_FWS_TYPE_SEQ_LEN;
 899        /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
 900        data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
 901        fillers = round_up(data_offset, 4) - data_offset;
 902        data_offset += fillers;
 903
 904        skb_push(skb, data_offset);
 905        wlh = skb->data;
 906
 907        wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
 908        wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
 909        memcpy(&wlh[2], &pkttag, sizeof(pkttag));
 910        if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
 911                wlh[1] += BRCMF_FWS_TYPE_SEQ_LEN;
 912                memcpy(&wlh[2 + BRCMF_FWS_TYPE_PKTTAG_LEN], &pktseq,
 913                       sizeof(pktseq));
 914        }
 915        wlh += wlh[1] + 2;
 916
 917        if (entry->send_tim_signal) {
 918                entry->send_tim_signal = 0;
 919                wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
 920                wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
 921                wlh[2] = entry->mac_handle;
 922                wlh[3] = entry->traffic_pending_bmp;
 923                brcmf_dbg(TRACE, "adding TIM info: handle %d bmp 0x%X\n",
 924                          entry->mac_handle, entry->traffic_pending_bmp);
 925                wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
 926                entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
 927        }
 928        if (fillers)
 929                memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
 930
 931        return (u8)(data_offset >> 2);
 932}
 933
 934static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
 935                                 struct brcmf_fws_mac_descriptor *entry,
 936                                 int fifo, bool send_immediately)
 937{
 938        struct sk_buff *skb;
 939        struct brcmf_skbuff_cb *skcb;
 940        s32 err;
 941        u32 len;
 942        u8 data_offset;
 943        int ifidx;
 944
 945        /* check delayedQ and suppressQ in one call using bitmap */
 946        if (brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0)
 947                entry->traffic_pending_bmp &= ~NBITVAL(fifo);
 948        else
 949                entry->traffic_pending_bmp |= NBITVAL(fifo);
 950
 951        entry->send_tim_signal = false;
 952        if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
 953                entry->send_tim_signal = true;
 954        if (send_immediately && entry->send_tim_signal &&
 955            entry->state == BRCMF_FWS_STATE_CLOSE) {
 956                /* create a dummy packet and sent that. The traffic          */
 957                /* bitmap info will automatically be attached to that packet */
 958                len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 +
 959                      BRCMF_FWS_TYPE_SEQ_LEN +
 960                      BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +
 961                      4 + fws->drvr->hdrlen;
 962                skb = brcmu_pkt_buf_get_skb(len);
 963                if (skb == NULL)
 964                        return false;
 965                skb_pull(skb, len);
 966                skcb = brcmf_skbcb(skb);
 967                skcb->mac = entry;
 968                skcb->state = BRCMF_FWS_SKBSTATE_TIM;
 969                skcb->htod = 0;
 970                skcb->htod_seq = 0;
 971                data_offset = brcmf_fws_hdrpush(fws, skb);
 972                ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
 973                brcmf_fws_unlock(fws);
 974                err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
 975                brcmf_fws_lock(fws);
 976                if (err)
 977                        brcmu_pkt_buf_free_skb(skb);
 978                return true;
 979        }
 980        return false;
 981}
 982
 983static void
 984brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
 985                             u8 if_id)
 986{
 987        struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id);
 988
 989        if (WARN_ON(!ifp))
 990                return;
 991
 992        if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
 993            pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
 994                brcmf_txflowblock_if(ifp,
 995                                     BRCMF_NETIF_STOP_REASON_FWS_FC, false);
 996        if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
 997            pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER) {
 998                fws->stats.fws_flow_block++;
 999                brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
1000        }
1001        return;
1002}
1003
1004static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
1005{
1006        brcmf_dbg(CTL, "rssi %d\n", rssi);
1007        return 0;
1008}
1009
1010static
1011int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
1012{
1013        struct brcmf_fws_mac_descriptor *entry, *existing;
1014        u8 mac_handle;
1015        u8 ifidx;
1016        u8 *addr;
1017
1018        mac_handle = *data++;
1019        ifidx = *data++;
1020        addr = data;
1021
1022        entry = &fws->desc.nodes[mac_handle & 0x1F];
1023        if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
1024                if (entry->occupied) {
1025                        brcmf_dbg(TRACE, "deleting %s mac %pM\n",
1026                                  entry->name, addr);
1027                        brcmf_fws_lock(fws);
1028                        brcmf_fws_macdesc_cleanup(fws, entry, -1);
1029                        brcmf_fws_macdesc_deinit(entry);
1030                        brcmf_fws_unlock(fws);
1031                } else
1032                        fws->stats.mac_update_failed++;
1033                return 0;
1034        }
1035
1036        existing = brcmf_fws_macdesc_lookup(fws, addr);
1037        if (IS_ERR(existing)) {
1038                if (!entry->occupied) {
1039                        brcmf_fws_lock(fws);
1040                        entry->mac_handle = mac_handle;
1041                        brcmf_fws_macdesc_init(entry, addr, ifidx);
1042                        brcmf_fws_macdesc_set_name(fws, entry);
1043                        brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
1044                                        BRCMF_FWS_PSQ_LEN);
1045                        brcmf_fws_unlock(fws);
1046                        brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
1047                } else {
1048                        fws->stats.mac_update_failed++;
1049                }
1050        } else {
1051                if (entry != existing) {
1052                        brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
1053                        brcmf_fws_lock(fws);
1054                        memcpy(entry, existing,
1055                               offsetof(struct brcmf_fws_mac_descriptor, psq));
1056                        entry->mac_handle = mac_handle;
1057                        brcmf_fws_macdesc_deinit(existing);
1058                        brcmf_fws_macdesc_set_name(fws, entry);
1059                        brcmf_fws_unlock(fws);
1060                        brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
1061                                  addr);
1062                } else {
1063                        brcmf_dbg(TRACE, "use existing\n");
1064                        WARN_ON(entry->mac_handle != mac_handle);
1065                        /* TODO: what should we do here: continue, reinit, .. */
1066                }
1067        }
1068        return 0;
1069}
1070
1071static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
1072                                            u8 type, u8 *data)
1073{
1074        struct brcmf_fws_mac_descriptor *entry;
1075        u8 mac_handle;
1076        int ret;
1077
1078        mac_handle = data[0];
1079        entry = &fws->desc.nodes[mac_handle & 0x1F];
1080        if (!entry->occupied) {
1081                fws->stats.mac_ps_update_failed++;
1082                return -ESRCH;
1083        }
1084        brcmf_fws_lock(fws);
1085        /* a state update should wipe old credits */
1086        entry->requested_credit = 0;
1087        entry->requested_packet = 0;
1088        if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
1089                entry->state = BRCMF_FWS_STATE_OPEN;
1090                ret = BRCMF_FWS_RET_OK_SCHEDULE;
1091        } else {
1092                entry->state = BRCMF_FWS_STATE_CLOSE;
1093                brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false);
1094                brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false);
1095                brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false);
1096                brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
1097                ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1098        }
1099        brcmf_fws_unlock(fws);
1100        return ret;
1101}
1102
1103static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
1104                                              u8 type, u8 *data)
1105{
1106        struct brcmf_fws_mac_descriptor *entry;
1107        u8 ifidx;
1108        int ret;
1109
1110        ifidx = data[0];
1111
1112        if (ifidx >= BRCMF_MAX_IFS) {
1113                ret = -ERANGE;
1114                goto fail;
1115        }
1116
1117        entry = &fws->desc.iface[ifidx];
1118        if (!entry->occupied) {
1119                ret = -ESRCH;
1120                goto fail;
1121        }
1122
1123        brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
1124                  entry->name);
1125        brcmf_fws_lock(fws);
1126        switch (type) {
1127        case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1128                entry->state = BRCMF_FWS_STATE_OPEN;
1129                ret = BRCMF_FWS_RET_OK_SCHEDULE;
1130                break;
1131        case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1132                entry->state = BRCMF_FWS_STATE_CLOSE;
1133                ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1134                break;
1135        default:
1136                ret = -EINVAL;
1137                brcmf_fws_unlock(fws);
1138                goto fail;
1139        }
1140        brcmf_fws_unlock(fws);
1141        return ret;
1142
1143fail:
1144        fws->stats.if_update_failed++;
1145        return ret;
1146}
1147
1148static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
1149                                      u8 *data)
1150{
1151        struct brcmf_fws_mac_descriptor *entry;
1152
1153        entry = &fws->desc.nodes[data[1] & 0x1F];
1154        if (!entry->occupied) {
1155                if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1156                        fws->stats.credit_request_failed++;
1157                else
1158                        fws->stats.packet_request_failed++;
1159                return -ESRCH;
1160        }
1161
1162        brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
1163                  brcmf_fws_get_tlv_name(type), type, entry->name,
1164                  data[0], data[2]);
1165        brcmf_fws_lock(fws);
1166        if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1167                entry->requested_credit = data[0];
1168        else
1169                entry->requested_packet = data[0];
1170
1171        entry->ac_bitmap = data[2];
1172        brcmf_fws_unlock(fws);
1173        return BRCMF_FWS_RET_OK_SCHEDULE;
1174}
1175
1176static void
1177brcmf_fws_macdesc_use_req_credit(struct brcmf_fws_mac_descriptor *entry,
1178                                 struct sk_buff *skb)
1179{
1180        if (entry->requested_credit > 0) {
1181                entry->requested_credit--;
1182                brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1183                brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 1);
1184                if (entry->state != BRCMF_FWS_STATE_CLOSE)
1185                        brcmf_err("requested credit set while mac not closed!\n");
1186        } else if (entry->requested_packet > 0) {
1187                entry->requested_packet--;
1188                brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1189                brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1190                if (entry->state != BRCMF_FWS_STATE_CLOSE)
1191                        brcmf_err("requested packet set while mac not closed!\n");
1192        } else {
1193                brcmf_skb_if_flags_set_field(skb, REQUESTED, 0);
1194                brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1195        }
1196}
1197
1198static void brcmf_fws_macdesc_return_req_credit(struct sk_buff *skb)
1199{
1200        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1201
1202        if ((brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) &&
1203            (entry->state == BRCMF_FWS_STATE_CLOSE))
1204                entry->requested_credit++;
1205}
1206
1207static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
1208                                     u8 fifo, u8 credits)
1209{
1210        int lender_ac;
1211        int *borrowed;
1212        int *fifo_credit;
1213
1214        if (!credits)
1215                return;
1216
1217        fws->fifo_credit_map |= 1 << fifo;
1218
1219        if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
1220            (fws->credits_borrowed[0])) {
1221                for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
1222                     lender_ac--) {
1223                        borrowed = &fws->credits_borrowed[lender_ac];
1224                        if (*borrowed) {
1225                                fws->fifo_credit_map |= (1 << lender_ac);
1226                                fifo_credit = &fws->fifo_credit[lender_ac];
1227                                if (*borrowed >= credits) {
1228                                        *borrowed -= credits;
1229                                        *fifo_credit += credits;
1230                                        return;
1231                                } else {
1232                                        credits -= *borrowed;
1233                                        *fifo_credit += *borrowed;
1234                                        *borrowed = 0;
1235                                }
1236                        }
1237                }
1238        }
1239
1240        fws->fifo_credit[fifo] += credits;
1241        if (fws->fifo_credit[fifo] > fws->init_fifo_credit[fifo])
1242                fws->fifo_credit[fifo] = fws->init_fifo_credit[fifo];
1243
1244}
1245
1246static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
1247{
1248        /* only schedule dequeue when there are credits for delayed traffic */
1249        if ((fws->fifo_credit_map & fws->fifo_delay_map) ||
1250            (!brcmf_fws_fc_active(fws) && fws->fifo_delay_map))
1251                queue_work(fws->fws_wq, &fws->fws_dequeue_work);
1252}
1253
1254static int brcmf_fws_enq(struct brcmf_fws_info *fws,
1255                         enum brcmf_fws_skb_state state, int fifo,
1256                         struct sk_buff *p)
1257{
1258        struct brcmf_pub *drvr = fws->drvr;
1259        int prec = 2 * fifo;
1260        u32 *qfull_stat = &fws->stats.delayq_full_error;
1261        struct brcmf_fws_mac_descriptor *entry;
1262        struct pktq *pq;
1263        struct sk_buff_head *queue;
1264        struct sk_buff *p_head;
1265        struct sk_buff *p_tail;
1266        u32 fr_new;
1267        u32 fr_compare;
1268
1269        entry = brcmf_skbcb(p)->mac;
1270        if (entry == NULL) {
1271                bphy_err(drvr, "no mac descriptor found for skb %p\n", p);
1272                return -ENOENT;
1273        }
1274
1275        brcmf_dbg(DATA, "enter: fifo %d skb %p\n", fifo, p);
1276        if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
1277                prec += 1;
1278                qfull_stat = &fws->stats.supprq_full_error;
1279
1280                /* Fix out of order delivery of frames. Dont assume frame    */
1281                /* can be inserted at the end, but look for correct position */
1282                pq = &entry->psq;
1283                if (pktq_full(pq) || pktq_pfull(pq, prec)) {
1284                        *qfull_stat += 1;
1285                        return -ENFILE;
1286                }
1287                queue = &pq->q[prec].skblist;
1288
1289                p_head = skb_peek(queue);
1290                p_tail = skb_peek_tail(queue);
1291                fr_new = brcmf_skb_htod_tag_get_field(p, FREERUN);
1292
1293                while (p_head != p_tail) {
1294                        fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
1295                                                                  FREERUN);
1296                        /* be sure to handle wrap of 256 */
1297                        if (((fr_new > fr_compare) &&
1298                             ((fr_new - fr_compare) < 128)) ||
1299                            ((fr_new < fr_compare) &&
1300                             ((fr_compare - fr_new) > 128)))
1301                                break;
1302                        p_tail = skb_queue_prev(queue, p_tail);
1303                }
1304                /* Position found. Determine what to do */
1305                if (p_tail == NULL) {
1306                        /* empty list */
1307                        __skb_queue_tail(queue, p);
1308                } else {
1309                        fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
1310                                                                  FREERUN);
1311                        if (((fr_new > fr_compare) &&
1312                             ((fr_new - fr_compare) < 128)) ||
1313                            ((fr_new < fr_compare) &&
1314                             ((fr_compare - fr_new) > 128))) {
1315                                /* After tail */
1316                                __skb_queue_after(queue, p_tail, p);
1317                        } else {
1318                                /* Before tail */
1319                                __skb_insert(p, p_tail->prev, p_tail, queue);
1320                        }
1321                }
1322
1323                /* Complete the counters and statistics */
1324                pq->len++;
1325                if (pq->hi_prec < prec)
1326                        pq->hi_prec = (u8) prec;
1327        } else if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
1328                *qfull_stat += 1;
1329                return -ENFILE;
1330        }
1331
1332        /* increment total enqueued packet count */
1333        fws->fifo_delay_map |= 1 << fifo;
1334        fws->fifo_enqpkt[fifo]++;
1335
1336        /* update the sk_buff state */
1337        brcmf_skbcb(p)->state = state;
1338
1339        /*
1340         * A packet has been pushed so update traffic
1341         * availability bitmap, if applicable
1342         */
1343        brcmf_fws_tim_update(fws, entry, fifo, true);
1344        brcmf_fws_flow_control_check(fws, &entry->psq,
1345                                     brcmf_skb_if_flags_get_field(p, INDEX));
1346        return 0;
1347}
1348
1349static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
1350{
1351        struct brcmf_fws_mac_descriptor *table;
1352        struct brcmf_fws_mac_descriptor *entry;
1353        struct sk_buff *p;
1354        int num_nodes;
1355        int node_pos;
1356        int prec_out;
1357        int pmsk;
1358        int i;
1359
1360        table = (struct brcmf_fws_mac_descriptor *)&fws->desc;
1361        num_nodes = sizeof(fws->desc) / sizeof(struct brcmf_fws_mac_descriptor);
1362        node_pos = fws->deq_node_pos[fifo];
1363
1364        for (i = 0; i < num_nodes; i++) {
1365                entry = &table[(node_pos + i) % num_nodes];
1366                if (!entry->occupied ||
1367                    brcmf_fws_macdesc_closed(fws, entry, fifo))
1368                        continue;
1369
1370                if (entry->suppressed)
1371                        pmsk = 2;
1372                else
1373                        pmsk = 3;
1374                p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
1375                if (p == NULL) {
1376                        if (entry->suppressed) {
1377                                if (entry->suppr_transit_count)
1378                                        continue;
1379                                entry->suppressed = false;
1380                                p = brcmu_pktq_mdeq(&entry->psq,
1381                                                    1 << (fifo * 2), &prec_out);
1382                        }
1383                }
1384                if  (p == NULL)
1385                        continue;
1386
1387                brcmf_fws_macdesc_use_req_credit(entry, p);
1388
1389                /* move dequeue position to ensure fair round-robin */
1390                fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
1391                brcmf_fws_flow_control_check(fws, &entry->psq,
1392                                             brcmf_skb_if_flags_get_field(p,
1393                                                                          INDEX)
1394                                             );
1395                /*
1396                 * A packet has been picked up, update traffic
1397                 * availability bitmap, if applicable
1398                 */
1399                brcmf_fws_tim_update(fws, entry, fifo, false);
1400
1401                /*
1402                 * decrement total enqueued fifo packets and
1403                 * clear delay bitmap if done.
1404                 */
1405                fws->fifo_enqpkt[fifo]--;
1406                if (fws->fifo_enqpkt[fifo] == 0)
1407                        fws->fifo_delay_map &= ~(1 << fifo);
1408                goto done;
1409        }
1410        p = NULL;
1411done:
1412        brcmf_dbg(DATA, "exit: fifo %d skb %p\n", fifo, p);
1413        return p;
1414}
1415
1416static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
1417                                         struct sk_buff *skb,
1418                                         u32 genbit, u16 seq)
1419{
1420        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1421        u32 hslot;
1422        int ret;
1423
1424        hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1425
1426        /* this packet was suppressed */
1427        if (!entry->suppressed) {
1428                entry->suppressed = true;
1429                entry->suppr_transit_count = entry->transit_count;
1430                brcmf_dbg(DATA, "suppress %s: transit %d\n",
1431                          entry->name, entry->transit_count);
1432        }
1433
1434        entry->generation = genbit;
1435
1436        brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
1437        brcmf_skbcb(skb)->htod_seq = seq;
1438        if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
1439                brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1);
1440                brcmf_skb_htod_seq_set_field(skb, FROMFW, 0);
1441        } else {
1442                brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0);
1443        }
1444        ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
1445
1446        if (ret != 0) {
1447                /* suppress q is full drop this packet */
1448                brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, true);
1449        } else {
1450                /* Mark suppressed to avoid a double free during wlfc cleanup */
1451                brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);
1452        }
1453
1454        return ret;
1455}
1456
1457static int
1458brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
1459                      u32 genbit, u16 seq, u8 compcnt)
1460{
1461        struct brcmf_pub *drvr = fws->drvr;
1462        u32 fifo;
1463        u8 cnt = 0;
1464        int ret;
1465        bool remove_from_hanger = true;
1466        struct sk_buff *skb;
1467        struct brcmf_skbuff_cb *skcb;
1468        struct brcmf_fws_mac_descriptor *entry = NULL;
1469        struct brcmf_if *ifp;
1470
1471        brcmf_dbg(DATA, "flags %d\n", flags);
1472
1473        if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
1474                fws->stats.txs_discard += compcnt;
1475        else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
1476                fws->stats.txs_supp_core += compcnt;
1477                remove_from_hanger = false;
1478        } else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
1479                fws->stats.txs_supp_ps += compcnt;
1480                remove_from_hanger = false;
1481        } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
1482                fws->stats.txs_tossed += compcnt;
1483        else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)
1484                fws->stats.txs_host_tossed += compcnt;
1485        else
1486                bphy_err(drvr, "unexpected txstatus\n");
1487
1488        while (cnt < compcnt) {
1489                ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
1490                                              remove_from_hanger);
1491                if (ret != 0) {
1492                        bphy_err(drvr, "no packet in hanger slot: hslot=%d\n",
1493                                 hslot);
1494                        goto cont;
1495                }
1496
1497                skcb = brcmf_skbcb(skb);
1498                entry = skcb->mac;
1499                if (WARN_ON(!entry)) {
1500                        brcmu_pkt_buf_free_skb(skb);
1501                        goto cont;
1502                }
1503                entry->transit_count--;
1504                if (entry->suppressed && entry->suppr_transit_count)
1505                        entry->suppr_transit_count--;
1506
1507                brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name,
1508                          flags, skcb->htod, seq);
1509
1510                /* pick up the implicit credit from this packet */
1511                fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
1512                if (fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT ||
1513                    (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
1514                    flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED) {
1515                        brcmf_fws_return_credits(fws, fifo, 1);
1516                        brcmf_fws_schedule_deq(fws);
1517                }
1518                brcmf_fws_macdesc_return_req_credit(skb);
1519
1520                ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
1521                if (ret) {
1522                        brcmu_pkt_buf_free_skb(skb);
1523                        goto cont;
1524                }
1525                if (!remove_from_hanger)
1526                        ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
1527                                                            genbit, seq);
1528                if (remove_from_hanger || ret)
1529                        brcmf_txfinalize(ifp, skb, true);
1530
1531cont:
1532                hslot = (hslot + 1) & (BRCMF_FWS_TXSTAT_HSLOT_MASK >>
1533                                       BRCMF_FWS_TXSTAT_HSLOT_SHIFT);
1534                if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
1535                        seq = (seq + 1) & BRCMF_SKB_HTOD_SEQ_NR_MASK;
1536
1537                cnt++;
1538        }
1539
1540        return 0;
1541}
1542
1543static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
1544                                             u8 *data)
1545{
1546        int i;
1547
1548        if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
1549                brcmf_dbg(INFO, "ignored\n");
1550                return BRCMF_FWS_RET_OK_NOSCHEDULE;
1551        }
1552
1553        brcmf_dbg(DATA, "enter: data %pM\n", data);
1554        brcmf_fws_lock(fws);
1555        for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
1556                brcmf_fws_return_credits(fws, i, data[i]);
1557
1558        brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
1559                  fws->fifo_delay_map);
1560        brcmf_fws_unlock(fws);
1561        return BRCMF_FWS_RET_OK_SCHEDULE;
1562}
1563
1564static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 type,
1565                                       u8 *data)
1566{
1567        __le32 status_le;
1568        __le16 seq_le;
1569        u32 status;
1570        u32 hslot;
1571        u32 genbit;
1572        u8 flags;
1573        u16 seq;
1574        u8 compcnt;
1575        u8 compcnt_offset = BRCMF_FWS_TYPE_TXSTATUS_LEN;
1576
1577        memcpy(&status_le, data, sizeof(status_le));
1578        status = le32_to_cpu(status_le);
1579        flags = brcmf_txstatus_get_field(status, FLAGS);
1580        hslot = brcmf_txstatus_get_field(status, HSLOT);
1581        genbit = brcmf_txstatus_get_field(status, GENERATION);
1582        if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
1583                memcpy(&seq_le, &data[BRCMF_FWS_TYPE_TXSTATUS_LEN],
1584                       sizeof(seq_le));
1585                seq = le16_to_cpu(seq_le);
1586                compcnt_offset += BRCMF_FWS_TYPE_SEQ_LEN;
1587        } else {
1588                seq = 0;
1589        }
1590
1591        if (type == BRCMF_FWS_TYPE_COMP_TXSTATUS)
1592                compcnt = data[compcnt_offset];
1593        else
1594                compcnt = 1;
1595        fws->stats.txs_indicate += compcnt;
1596
1597        brcmf_fws_lock(fws);
1598        brcmf_fws_txs_process(fws, flags, hslot, genbit, seq, compcnt);
1599        brcmf_fws_unlock(fws);
1600        return BRCMF_FWS_RET_OK_NOSCHEDULE;
1601}
1602
1603static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
1604{
1605        __le32 timestamp;
1606
1607        memcpy(&timestamp, &data[2], sizeof(timestamp));
1608        brcmf_dbg(CTL, "received: seq %d, timestamp %d\n", data[1],
1609                  le32_to_cpu(timestamp));
1610        return 0;
1611}
1612
1613static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
1614                                       const struct brcmf_event_msg *e,
1615                                       void *data)
1616{
1617        struct brcmf_pub *drvr = ifp->drvr;
1618        struct brcmf_fws_info *fws = drvr_to_fws(drvr);
1619        int i;
1620        u8 *credits = data;
1621
1622        if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
1623                bphy_err(drvr, "event payload too small (%d)\n", e->datalen);
1624                return -EINVAL;
1625        }
1626
1627        fws->creditmap_received = true;
1628
1629        brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
1630        brcmf_fws_lock(fws);
1631        for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
1632                fws->fifo_credit[i] += credits[i] - fws->init_fifo_credit[i];
1633                fws->init_fifo_credit[i] = credits[i];
1634                if (fws->fifo_credit[i] > 0)
1635                        fws->fifo_credit_map |= 1 << i;
1636                else
1637                        fws->fifo_credit_map &= ~(1 << i);
1638                WARN_ONCE(fws->fifo_credit[i] < 0,
1639                          "fifo_credit[%d] is negative(%d)\n", i,
1640                          fws->fifo_credit[i]);
1641        }
1642        brcmf_fws_schedule_deq(fws);
1643        brcmf_fws_unlock(fws);
1644        return 0;
1645}
1646
1647static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
1648                                                const struct brcmf_event_msg *e,
1649                                                void *data)
1650{
1651        struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
1652
1653        if (fws) {
1654                brcmf_fws_lock(fws);
1655                fws->bcmc_credit_check = true;
1656                brcmf_fws_unlock(fws);
1657        }
1658        return 0;
1659}
1660
1661static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
1662                                         u8 start, u8 end,
1663                                         struct sk_buff_head *skb_list)
1664{
1665        /* initialize return list */
1666        __skb_queue_head_init(skb_list);
1667
1668        if (rfi->pend_pkts == 0) {
1669                brcmf_dbg(INFO, "no packets in reorder queue\n");
1670                return;
1671        }
1672
1673        do {
1674                if (rfi->pktslots[start]) {
1675                        __skb_queue_tail(skb_list, rfi->pktslots[start]);
1676                        rfi->pktslots[start] = NULL;
1677                }
1678                start++;
1679                if (start > rfi->max_idx)
1680                        start = 0;
1681        } while (start != end);
1682        rfi->pend_pkts -= skb_queue_len(skb_list);
1683}
1684
1685void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
1686{
1687        struct brcmf_pub *drvr = ifp->drvr;
1688        u8 *reorder_data;
1689        u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
1690        struct brcmf_ampdu_rx_reorder *rfi;
1691        struct sk_buff_head reorder_list;
1692        struct sk_buff *pnext;
1693        u8 flags;
1694        u32 buf_size;
1695
1696        reorder_data = ((struct brcmf_skb_reorder_data *)pkt->cb)->reorder;
1697        flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
1698        flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
1699
1700        /* validate flags and flow id */
1701        if (flags == 0xFF) {
1702                bphy_err(drvr, "invalid flags...so ignore this packet\n");
1703                brcmf_netif_rx(ifp, pkt);
1704                return;
1705        }
1706
1707        rfi = ifp->drvr->reorder_flows[flow_id];
1708        if (flags & BRCMF_RXREORDER_DEL_FLOW) {
1709                brcmf_dbg(INFO, "flow-%d: delete\n",
1710                          flow_id);
1711
1712                if (rfi == NULL) {
1713                        brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
1714                                  flow_id);
1715                        brcmf_netif_rx(ifp, pkt);
1716                        return;
1717                }
1718
1719                brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
1720                                             &reorder_list);
1721                /* add the last packet */
1722                __skb_queue_tail(&reorder_list, pkt);
1723                kfree(rfi);
1724                ifp->drvr->reorder_flows[flow_id] = NULL;
1725                goto netif_rx;
1726        }
1727        /* from here on we need a flow reorder instance */
1728        if (rfi == NULL) {
1729                buf_size = sizeof(*rfi);
1730                max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
1731
1732                buf_size += (max_idx + 1) * sizeof(pkt);
1733
1734                /* allocate space for flow reorder info */
1735                brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
1736                          flow_id, max_idx);
1737                rfi = kzalloc(buf_size, GFP_ATOMIC);
1738                if (rfi == NULL) {
1739                        bphy_err(drvr, "failed to alloc buffer\n");
1740                        brcmf_netif_rx(ifp, pkt);
1741                        return;
1742                }
1743
1744                ifp->drvr->reorder_flows[flow_id] = rfi;
1745                rfi->pktslots = (struct sk_buff **)(rfi + 1);
1746                rfi->max_idx = max_idx;
1747        }
1748        if (flags & BRCMF_RXREORDER_NEW_HOLE)  {
1749                if (rfi->pend_pkts) {
1750                        brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
1751                                                     rfi->exp_idx,
1752                                                     &reorder_list);
1753                        WARN_ON(rfi->pend_pkts);
1754                } else {
1755                        __skb_queue_head_init(&reorder_list);
1756                }
1757                rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
1758                rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1759                rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
1760                rfi->pktslots[rfi->cur_idx] = pkt;
1761                rfi->pend_pkts++;
1762                brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
1763                          flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
1764        } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
1765                cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
1766                exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1767
1768                if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
1769                        /* still in the current hole */
1770                        /* enqueue the current on the buffer chain */
1771                        if (rfi->pktslots[cur_idx] != NULL) {
1772                                brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
1773                                brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
1774                                rfi->pktslots[cur_idx] = NULL;
1775                        }
1776                        rfi->pktslots[cur_idx] = pkt;
1777                        rfi->pend_pkts++;
1778                        rfi->cur_idx = cur_idx;
1779                        brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
1780                                  flow_id, cur_idx, exp_idx, rfi->pend_pkts);
1781
1782                        /* can return now as there is no reorder
1783                         * list to process.
1784                         */
1785                        return;
1786                }
1787                if (rfi->exp_idx == cur_idx) {
1788                        if (rfi->pktslots[cur_idx] != NULL) {
1789                                brcmf_dbg(INFO, "error buffer pending..free it\n");
1790                                brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
1791                                rfi->pktslots[cur_idx] = NULL;
1792                        }
1793                        rfi->pktslots[cur_idx] = pkt;
1794                        rfi->pend_pkts++;
1795
1796                        /* got the expected one. flush from current to expected
1797                         * and update expected
1798                         */
1799                        brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
1800                                  flow_id, cur_idx, exp_idx, rfi->pend_pkts);
1801
1802                        rfi->cur_idx = cur_idx;
1803                        rfi->exp_idx = exp_idx;
1804
1805                        brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
1806                                                     &reorder_list);
1807                        brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
1808                                  flow_id, skb_queue_len(&reorder_list),
1809                                  rfi->pend_pkts);
1810                } else {
1811                        u8 end_idx;
1812
1813                        brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
1814                                  flow_id, flags, rfi->cur_idx, rfi->exp_idx,
1815                                  cur_idx, exp_idx);
1816                        if (flags & BRCMF_RXREORDER_FLUSH_ALL)
1817                                end_idx = rfi->exp_idx;
1818                        else
1819                                end_idx = exp_idx;
1820
1821                        /* flush pkts first */
1822                        brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
1823                                                     &reorder_list);
1824
1825                        if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
1826                                __skb_queue_tail(&reorder_list, pkt);
1827                        } else {
1828                                rfi->pktslots[cur_idx] = pkt;
1829                                rfi->pend_pkts++;
1830                        }
1831                        rfi->exp_idx = exp_idx;
1832                        rfi->cur_idx = cur_idx;
1833                }
1834        } else {
1835                /* explicity window move updating the expected index */
1836                exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1837
1838                brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
1839                          flow_id, flags, rfi->exp_idx, exp_idx);
1840                if (flags & BRCMF_RXREORDER_FLUSH_ALL)
1841                        end_idx =  rfi->exp_idx;
1842                else
1843                        end_idx =  exp_idx;
1844
1845                brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
1846                                             &reorder_list);
1847                __skb_queue_tail(&reorder_list, pkt);
1848                /* set the new expected idx */
1849                rfi->exp_idx = exp_idx;
1850        }
1851netif_rx:
1852        skb_queue_walk_safe(&reorder_list, pkt, pnext) {
1853                __skb_unlink(pkt, &reorder_list);
1854                brcmf_netif_rx(ifp, pkt);
1855        }
1856}
1857
1858void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
1859{
1860        struct brcmf_skb_reorder_data *rd;
1861        struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
1862        u8 *signal_data;
1863        s16 data_len;
1864        u8 type;
1865        u8 len;
1866        u8 *data;
1867        s32 status;
1868        s32 err;
1869
1870        brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
1871                  ifp->ifidx, skb->len, siglen);
1872
1873        WARN_ON(siglen > skb->len);
1874
1875        if (!siglen)
1876                return;
1877        /* if flow control disabled, skip to packet data and leave */
1878        if ((!fws) || (!fws->fw_signals)) {
1879                skb_pull(skb, siglen);
1880                return;
1881        }
1882
1883        fws->stats.header_pulls++;
1884        data_len = siglen;
1885        signal_data = skb->data;
1886
1887        status = BRCMF_FWS_RET_OK_NOSCHEDULE;
1888        while (data_len > 0) {
1889                /* extract tlv info */
1890                type = signal_data[0];
1891
1892                /* FILLER type is actually not a TLV, but
1893                 * a single byte that can be skipped.
1894                 */
1895                if (type == BRCMF_FWS_TYPE_FILLER) {
1896                        signal_data += 1;
1897                        data_len -= 1;
1898                        continue;
1899                }
1900                len = signal_data[1];
1901                data = signal_data + 2;
1902
1903                brcmf_dbg(HDRS, "tlv type=%s (%d), len=%d (%d)\n",
1904                          brcmf_fws_get_tlv_name(type), type, len,
1905                          brcmf_fws_get_tlv_len(fws, type));
1906
1907                /* abort parsing when length invalid */
1908                if (data_len < len + 2)
1909                        break;
1910
1911                if (len < brcmf_fws_get_tlv_len(fws, type))
1912                        break;
1913
1914                err = BRCMF_FWS_RET_OK_NOSCHEDULE;
1915                switch (type) {
1916                case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
1917                        rd = (struct brcmf_skb_reorder_data *)skb->cb;
1918                        rd->reorder = data;
1919                        break;
1920                case BRCMF_FWS_TYPE_MACDESC_ADD:
1921                case BRCMF_FWS_TYPE_MACDESC_DEL:
1922                        brcmf_fws_macdesc_indicate(fws, type, data);
1923                        break;
1924                case BRCMF_FWS_TYPE_MAC_OPEN:
1925                case BRCMF_FWS_TYPE_MAC_CLOSE:
1926                        err = brcmf_fws_macdesc_state_indicate(fws, type, data);
1927                        break;
1928                case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1929                case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1930                        err = brcmf_fws_interface_state_indicate(fws, type,
1931                                                                 data);
1932                        break;
1933                case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
1934                case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
1935                        err = brcmf_fws_request_indicate(fws, type, data);
1936                        break;
1937                case BRCMF_FWS_TYPE_TXSTATUS:
1938                case BRCMF_FWS_TYPE_COMP_TXSTATUS:
1939                        brcmf_fws_txstatus_indicate(fws, type, data);
1940                        break;
1941                case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
1942                        err = brcmf_fws_fifocreditback_indicate(fws, data);
1943                        break;
1944                case BRCMF_FWS_TYPE_RSSI:
1945                        brcmf_fws_rssi_indicate(fws, *data);
1946                        break;
1947                case BRCMF_FWS_TYPE_TRANS_ID:
1948                        brcmf_fws_dbg_seqnum_check(fws, data);
1949                        break;
1950                case BRCMF_FWS_TYPE_PKTTAG:
1951                case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
1952                default:
1953                        fws->stats.tlv_invalid_type++;
1954                        break;
1955                }
1956                if (err == BRCMF_FWS_RET_OK_SCHEDULE)
1957                        status = BRCMF_FWS_RET_OK_SCHEDULE;
1958                signal_data += len + 2;
1959                data_len -= len + 2;
1960        }
1961
1962        if (data_len != 0)
1963                fws->stats.tlv_parse_failed++;
1964
1965        if (status == BRCMF_FWS_RET_OK_SCHEDULE)
1966                brcmf_fws_schedule_deq(fws);
1967
1968        /* signalling processing result does
1969         * not affect the actual ethernet packet.
1970         */
1971        skb_pull(skb, siglen);
1972
1973        /* this may be a signal-only packet
1974         */
1975        if (skb->len == 0)
1976                fws->stats.header_only_pkt++;
1977}
1978
1979static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
1980                                   struct sk_buff *p)
1981{
1982        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
1983        struct brcmf_fws_mac_descriptor *entry = skcb->mac;
1984        u8 flags;
1985
1986        if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED)
1987                brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
1988        flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
1989        if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
1990                /*
1991                 * Indicate that this packet is being sent in response to an
1992                 * explicit request from the firmware side.
1993                 */
1994                flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
1995        }
1996        brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
1997        return brcmf_fws_hdrpush(fws, p);
1998}
1999
2000static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
2001                                   struct sk_buff *skb, int fifo)
2002{
2003        struct brcmf_pub *drvr = fws->drvr;
2004        struct brcmf_fws_mac_descriptor *entry;
2005        struct sk_buff *pktout;
2006        int qidx, hslot;
2007        int rc = 0;
2008
2009        entry = brcmf_skbcb(skb)->mac;
2010        if (entry->occupied) {
2011                qidx = 2 * fifo;
2012                if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
2013                        qidx++;
2014
2015                pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb);
2016                if (pktout == NULL) {
2017                        bphy_err(drvr, "%s queue %d full\n", entry->name, qidx);
2018                        rc = -ENOSPC;
2019                }
2020        } else {
2021                bphy_err(drvr, "%s entry removed\n", entry->name);
2022                rc = -ENOENT;
2023        }
2024
2025        if (rc) {
2026                fws->stats.rollback_failed++;
2027                hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
2028                brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
2029                                      hslot, 0, 0, 1);
2030        } else {
2031                fws->stats.rollback_success++;
2032                brcmf_fws_return_credits(fws, fifo, 1);
2033                brcmf_fws_macdesc_return_req_credit(skb);
2034        }
2035}
2036
2037static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
2038{
2039        int lender_ac;
2040
2041        if (time_after(fws->borrow_defer_timestamp, jiffies)) {
2042                fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
2043                return -ENAVAIL;
2044        }
2045
2046        for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
2047                if (fws->fifo_credit[lender_ac] > 0) {
2048                        fws->credits_borrowed[lender_ac]++;
2049                        fws->fifo_credit[lender_ac]--;
2050                        if (fws->fifo_credit[lender_ac] == 0)
2051                                fws->fifo_credit_map &= ~(1 << lender_ac);
2052                        fws->fifo_credit_map |= (1 << BRCMF_FWS_FIFO_AC_BE);
2053                        brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac);
2054                        return 0;
2055                }
2056        }
2057        fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
2058        return -ENAVAIL;
2059}
2060
2061static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
2062                                struct sk_buff *skb)
2063{
2064        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
2065        struct brcmf_fws_mac_descriptor *entry;
2066        int rc;
2067        u8 ifidx;
2068        u8 data_offset;
2069
2070        entry = skcb->mac;
2071        if (IS_ERR(entry))
2072                return PTR_ERR(entry);
2073
2074        data_offset = brcmf_fws_precommit_skb(fws, fifo, skb);
2075        entry->transit_count++;
2076        if (entry->suppressed)
2077                entry->suppr_transit_count++;
2078        ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
2079        brcmf_fws_unlock(fws);
2080        rc = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
2081        brcmf_fws_lock(fws);
2082        brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
2083                  skcb->if_flags, skcb->htod, rc);
2084        if (rc < 0) {
2085                entry->transit_count--;
2086                if (entry->suppressed)
2087                        entry->suppr_transit_count--;
2088                (void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL);
2089                goto rollback;
2090        }
2091
2092        fws->stats.pkt2bus++;
2093        fws->stats.send_pkts[fifo]++;
2094        if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
2095                fws->stats.requested_sent[fifo]++;
2096
2097        return rc;
2098
2099rollback:
2100        brcmf_fws_rollback_toq(fws, skb, fifo);
2101        return rc;
2102}
2103
2104static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
2105                                  int fifo)
2106{
2107        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
2108        int rc, hslot;
2109
2110        skcb->htod = 0;
2111        skcb->htod_seq = 0;
2112        hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
2113        brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
2114        brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]);
2115        brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
2116        rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
2117        if (!rc)
2118                skcb->mac->seq[fifo]++;
2119        else
2120                fws->stats.generic_error++;
2121        return rc;
2122}
2123
2124int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
2125{
2126        struct brcmf_pub *drvr = ifp->drvr;
2127        struct brcmf_fws_info *fws = drvr_to_fws(drvr);
2128        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
2129        struct ethhdr *eh = (struct ethhdr *)(skb->data);
2130        int fifo = BRCMF_FWS_FIFO_BCMC;
2131        bool multicast = is_multicast_ether_addr(eh->h_dest);
2132        int rc = 0;
2133
2134        brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
2135
2136        /* set control buffer information */
2137        skcb->if_flags = 0;
2138        skcb->state = BRCMF_FWS_SKBSTATE_NEW;
2139        brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
2140        if (!multicast)
2141                fifo = brcmf_fws_prio2fifo[skb->priority];
2142
2143        brcmf_fws_lock(fws);
2144        if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
2145                fws->borrow_defer_timestamp = jiffies +
2146                                              BRCMF_FWS_BORROW_DEFER_PERIOD;
2147
2148        skcb->mac = brcmf_fws_macdesc_find(fws, ifp, eh->h_dest);
2149        brcmf_dbg(DATA, "%s mac %pM multi %d fifo %d\n", skcb->mac->name,
2150                  eh->h_dest, multicast, fifo);
2151        if (!brcmf_fws_assign_htod(fws, skb, fifo)) {
2152                brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
2153                brcmf_fws_schedule_deq(fws);
2154        } else {
2155                bphy_err(drvr, "drop skb: no hanger slot\n");
2156                brcmf_txfinalize(ifp, skb, false);
2157                rc = -ENOMEM;
2158        }
2159        brcmf_fws_unlock(fws);
2160
2161        return rc;
2162}
2163
2164void brcmf_fws_reset_interface(struct brcmf_if *ifp)
2165{
2166        struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
2167
2168        brcmf_dbg(TRACE, "enter: bsscfgidx=%d\n", ifp->bsscfgidx);
2169        if (!entry)
2170                return;
2171
2172        brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
2173}
2174
2175void brcmf_fws_add_interface(struct brcmf_if *ifp)
2176{
2177        struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
2178        struct brcmf_fws_mac_descriptor *entry;
2179
2180        if (!ifp->ndev || !brcmf_fws_queue_skbs(fws))
2181                return;
2182
2183        entry = &fws->desc.iface[ifp->ifidx];
2184        ifp->fws_desc = entry;
2185        brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
2186        brcmf_fws_macdesc_set_name(fws, entry);
2187        brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
2188                        BRCMF_FWS_PSQ_LEN);
2189        brcmf_dbg(TRACE, "added %s\n", entry->name);
2190}
2191
2192void brcmf_fws_del_interface(struct brcmf_if *ifp)
2193{
2194        struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
2195        struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
2196
2197        if (!entry)
2198                return;
2199
2200        brcmf_fws_lock(fws);
2201        ifp->fws_desc = NULL;
2202        brcmf_dbg(TRACE, "deleting %s\n", entry->name);
2203        brcmf_fws_macdesc_deinit(entry);
2204        brcmf_fws_cleanup(fws, ifp->ifidx);
2205        brcmf_fws_unlock(fws);
2206}
2207
2208static void brcmf_fws_dequeue_worker(struct work_struct *worker)
2209{
2210        struct brcmf_fws_info *fws;
2211        struct brcmf_pub *drvr;
2212        struct sk_buff *skb;
2213        int fifo;
2214        u32 hslot;
2215        u32 ifidx;
2216        int ret;
2217
2218        fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
2219        drvr = fws->drvr;
2220
2221        brcmf_fws_lock(fws);
2222        for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked;
2223             fifo--) {
2224                if (!brcmf_fws_fc_active(fws)) {
2225                        while ((skb = brcmf_fws_deq(fws, fifo)) != NULL) {
2226                                hslot = brcmf_skb_htod_tag_get_field(skb,
2227                                                                     HSLOT);
2228                                brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
2229                                                        &skb, true);
2230                                ifidx = brcmf_skb_if_flags_get_field(skb,
2231                                                                     INDEX);
2232                                /* Use proto layer to send data frame */
2233                                brcmf_fws_unlock(fws);
2234                                ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
2235                                brcmf_fws_lock(fws);
2236                                if (ret < 0)
2237                                        brcmf_txfinalize(brcmf_get_ifp(drvr,
2238                                                                       ifidx),
2239                                                         skb, false);
2240                                if (fws->bus_flow_blocked)
2241                                        break;
2242                        }
2243                        continue;
2244                }
2245                while ((fws->fifo_credit[fifo] > 0) ||
2246                       ((!fws->bcmc_credit_check) &&
2247                        (fifo == BRCMF_FWS_FIFO_BCMC))) {
2248                        skb = brcmf_fws_deq(fws, fifo);
2249                        if (!skb)
2250                                break;
2251                        fws->fifo_credit[fifo]--;
2252                        if (brcmf_fws_commit_skb(fws, fifo, skb))
2253                                break;
2254                        if (fws->bus_flow_blocked)
2255                                break;
2256                }
2257                if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
2258                    (fws->fifo_credit[fifo] <= 0) &&
2259                    (!fws->bus_flow_blocked)) {
2260                        while (brcmf_fws_borrow_credit(fws) == 0) {
2261                                skb = brcmf_fws_deq(fws, fifo);
2262                                if (!skb) {
2263                                        brcmf_fws_return_credits(fws, fifo, 1);
2264                                        break;
2265                                }
2266                                if (brcmf_fws_commit_skb(fws, fifo, skb))
2267                                        break;
2268                                if (fws->bus_flow_blocked)
2269                                        break;
2270                        }
2271                }
2272        }
2273        brcmf_fws_unlock(fws);
2274}
2275
2276#ifdef DEBUG
2277static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
2278{
2279        struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
2280        struct brcmf_fws_stats *fwstats = &(drvr_to_fws(bus_if->drvr)->stats);
2281
2282        seq_printf(seq,
2283                   "header_pulls:      %u\n"
2284                   "header_only_pkt:   %u\n"
2285                   "tlv_parse_failed:  %u\n"
2286                   "tlv_invalid_type:  %u\n"
2287                   "mac_update_fails:  %u\n"
2288                   "ps_update_fails:   %u\n"
2289                   "if_update_fails:   %u\n"
2290                   "pkt2bus:           %u\n"
2291                   "generic_error:     %u\n"
2292                   "rollback_success:  %u\n"
2293                   "rollback_failed:   %u\n"
2294                   "delayq_full:       %u\n"
2295                   "supprq_full:       %u\n"
2296                   "txs_indicate:      %u\n"
2297                   "txs_discard:       %u\n"
2298                   "txs_suppr_core:    %u\n"
2299                   "txs_suppr_ps:      %u\n"
2300                   "txs_tossed:        %u\n"
2301                   "txs_host_tossed:   %u\n"
2302                   "bus_flow_block:    %u\n"
2303                   "fws_flow_block:    %u\n"
2304                   "send_pkts:         BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
2305                   "requested_sent:    BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
2306                   fwstats->header_pulls,
2307                   fwstats->header_only_pkt,
2308                   fwstats->tlv_parse_failed,
2309                   fwstats->tlv_invalid_type,
2310                   fwstats->mac_update_failed,
2311                   fwstats->mac_ps_update_failed,
2312                   fwstats->if_update_failed,
2313                   fwstats->pkt2bus,
2314                   fwstats->generic_error,
2315                   fwstats->rollback_success,
2316                   fwstats->rollback_failed,
2317                   fwstats->delayq_full_error,
2318                   fwstats->supprq_full_error,
2319                   fwstats->txs_indicate,
2320                   fwstats->txs_discard,
2321                   fwstats->txs_supp_core,
2322                   fwstats->txs_supp_ps,
2323                   fwstats->txs_tossed,
2324                   fwstats->txs_host_tossed,
2325                   fwstats->bus_flow_block,
2326                   fwstats->fws_flow_block,
2327                   fwstats->send_pkts[0], fwstats->send_pkts[1],
2328                   fwstats->send_pkts[2], fwstats->send_pkts[3],
2329                   fwstats->send_pkts[4],
2330                   fwstats->requested_sent[0],
2331                   fwstats->requested_sent[1],
2332                   fwstats->requested_sent[2],
2333                   fwstats->requested_sent[3],
2334                   fwstats->requested_sent[4]);
2335
2336        return 0;
2337}
2338#else
2339static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
2340{
2341        return 0;
2342}
2343#endif
2344
2345struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
2346{
2347        struct brcmf_fws_info *fws;
2348        struct brcmf_if *ifp;
2349        u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
2350        int rc;
2351        u32 mode;
2352
2353        fws = kzalloc(sizeof(*fws), GFP_KERNEL);
2354        if (!fws) {
2355                rc = -ENOMEM;
2356                goto fail;
2357        }
2358
2359        spin_lock_init(&fws->spinlock);
2360
2361        /* store drvr reference */
2362        fws->drvr = drvr;
2363        fws->fcmode = drvr->settings->fcmode;
2364
2365        if ((drvr->bus_if->always_use_fws_queue == false) &&
2366            (fws->fcmode == BRCMF_FWS_FCMODE_NONE)) {
2367                fws->avoid_queueing = true;
2368                brcmf_dbg(INFO, "FWS queueing will be avoided\n");
2369                return fws;
2370        }
2371
2372        fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
2373        if (fws->fws_wq == NULL) {
2374                bphy_err(drvr, "workqueue creation failed\n");
2375                rc = -EBADF;
2376                goto fail;
2377        }
2378        INIT_WORK(&fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
2379
2380        /* enable firmware signalling if fcmode active */
2381        if (fws->fcmode != BRCMF_FWS_FCMODE_NONE)
2382                tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
2383                       BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
2384                       BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE |
2385                       BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE;
2386
2387        rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
2388                                 brcmf_fws_notify_credit_map);
2389        if (rc < 0) {
2390                bphy_err(drvr, "register credit map handler failed\n");
2391                goto fail;
2392        }
2393        rc = brcmf_fweh_register(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT,
2394                                 brcmf_fws_notify_bcmc_credit_support);
2395        if (rc < 0) {
2396                bphy_err(drvr, "register bcmc credit handler failed\n");
2397                brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
2398                goto fail;
2399        }
2400
2401        /* Setting the iovar may fail if feature is unsupported
2402         * so leave the rc as is so driver initialization can
2403         * continue. Set mode back to none indicating not enabled.
2404         */
2405        fws->fw_signals = true;
2406        ifp = brcmf_get_ifp(drvr, 0);
2407        if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) {
2408                bphy_err(drvr, "failed to set bdcv2 tlv signaling\n");
2409                fws->fcmode = BRCMF_FWS_FCMODE_NONE;
2410                fws->fw_signals = false;
2411        }
2412
2413        if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1))
2414                brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
2415
2416        /* Enable seq number reuse, if supported */
2417        if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) {
2418                if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
2419                        mode = 0;
2420                        BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
2421                        if (brcmf_fil_iovar_int_set(ifp,
2422                                                    "wlfc_mode", mode) == 0) {
2423                                BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
2424                        }
2425                }
2426        }
2427
2428        brcmf_fws_hanger_init(&fws->hanger);
2429        brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
2430        brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
2431        brcmf_dbg(INFO, "added %s\n", fws->desc.other.name);
2432        brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
2433                        BRCMF_FWS_PSQ_LEN);
2434
2435        brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
2436                  fws->fw_signals ? "enabled" : "disabled", tlv);
2437        return fws;
2438
2439fail:
2440        brcmf_fws_detach(fws);
2441        return ERR_PTR(rc);
2442}
2443
2444void brcmf_fws_detach(struct brcmf_fws_info *fws)
2445{
2446        if (!fws)
2447                return;
2448
2449        if (fws->fws_wq)
2450                destroy_workqueue(fws->fws_wq);
2451
2452        /* cleanup */
2453        brcmf_fws_lock(fws);
2454        brcmf_fws_cleanup(fws, -1);
2455        brcmf_fws_unlock(fws);
2456
2457        /* free top structure */
2458        kfree(fws);
2459}
2460
2461void brcmf_fws_debugfs_create(struct brcmf_pub *drvr)
2462{
2463        /* create debugfs file for statistics */
2464        brcmf_debugfs_add_entry(drvr, "fws_stats",
2465                                brcmf_debugfs_fws_stats_read);
2466}
2467
2468bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws)
2469{
2470        return !fws->avoid_queueing;
2471}
2472
2473bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
2474{
2475        if (!fws->creditmap_received)
2476                return false;
2477
2478        return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
2479}
2480
2481void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
2482{
2483        u32 hslot;
2484
2485        if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
2486                brcmu_pkt_buf_free_skb(skb);
2487                return;
2488        }
2489        brcmf_fws_lock(fws);
2490        hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
2491        brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0,
2492                              1);
2493        brcmf_fws_unlock(fws);
2494}
2495
2496void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
2497{
2498        struct brcmf_fws_info *fws = drvr_to_fws(drvr);
2499        struct brcmf_if *ifp;
2500        int i;
2501
2502        if (fws->avoid_queueing) {
2503                for (i = 0; i < BRCMF_MAX_IFS; i++) {
2504                        ifp = drvr->iflist[i];
2505                        if (!ifp || !ifp->ndev)
2506                                continue;
2507                        brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW,
2508                                             flow_blocked);
2509                }
2510        } else {
2511                fws->bus_flow_blocked = flow_blocked;
2512                if (!flow_blocked)
2513                        brcmf_fws_schedule_deq(fws);
2514                else
2515                        fws->stats.bus_flow_block++;
2516        }
2517}
2518