/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/if_ether.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/err.h>
#include <uapi/linux/nl80211.h>
#include <net/cfg80211.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "dhd_bus.h"
#include "fwil.h"
#include "fweh.h"
#include "fwsignal.h"
/**
* DOC: Firmware Signalling
*
* Firmware can send signals to host and vice versa, which are passed in the
* data packets using TLV based header. This signalling layer is on top of the
* BDC bus protocol layer.
*/
/*
* single definition for firmware-driver flow control tlv's.
*
* each tlv is specified by BRCMF_FWS_TLV_DEF(name, ID, length).
* A length value 0 indicates variable length tlv.
*/
#define BRCMF_FWS_TLV_DEFLIST \
BRCMF_FWS_TLV_DEF(MAC_OPEN, 1, 1) \
BRCMF_FWS_TLV_DEF(MAC_CLOSE, 2, 1) \
BRCMF_FWS_TLV_DEF(MAC_REQUEST_CREDIT, 3, 2) \
BRCMF_FWS_TLV_DEF(TXSTATUS, 4, 4) \
BRCMF_FWS_TLV_DEF(PKTTAG, 5, 4) \
BRCMF_FWS_TLV_DEF(MACDESC_ADD, 6, 8) \
BRCMF_FWS_TLV_DEF(MACDESC_DEL, 7, 8) \
BRCMF_FWS_TLV_DEF(RSSI, 8, 1) \
BRCMF_FWS_TLV_DEF(INTERFACE_OPEN, 9, 1) \
BRCMF_FWS_TLV_DEF(INTERFACE_CLOSE, 10, 1) \
BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 8) \
BRCMF_FWS_TLV_DEF(PENDING_TRAFFIC_BMP, 12, 2) \
BRCMF_FWS_TLV_DEF(MAC_REQUEST_PACKET, 13, 3) \
BRCMF_FWS_TLV_DEF(HOST_REORDER_RXPKTS, 14, 10) \
BRCMF_FWS_TLV_DEF(TRANS_ID, 18, 6) \
BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \
BRCMF_FWS_TLV_DEF(FILLER, 255, 0)
/*
* enum brcmf_fws_tlv_type - definition of tlv identifiers.
*/
#define BRCMF_FWS_TLV_DEF(name, id, len) \
BRCMF_FWS_TYPE_ ## name = id,
enum brcmf_fws_tlv_type {
BRCMF_FWS_TLV_DEFLIST
BRCMF_FWS_TYPE_INVALID
};
#undef BRCMF_FWS_TLV_DEF
/*
* enum brcmf_fws_tlv_len - definition of tlv lengths.
*/
#define BRCMF_FWS_TLV_DEF(name, id, len) \
BRCMF_FWS_TYPE_ ## name ## _LEN = (len),
enum brcmf_fws_tlv_len {
BRCMF_FWS_TLV_DEFLIST
};
#undef BRCMF_FWS_TLV_DEF
#ifdef DEBUG
/*
* brcmf_fws_tlv_names - array of tlv names.
*/
#define BRCMF_FWS_TLV_DEF(name, id, len) \
{ id, #name },
static struct {
enum brcmf_fws_tlv_type id;
const char *name;
} brcmf_fws_tlv_names[] = {
BRCMF_FWS_TLV_DEFLIST
};
#undef BRCMF_FWS_TLV_DEF
static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
{
int i;
for (i = 0; i < ARRAY_SIZE(brcmf_fws_tlv_names); i++)
if (brcmf_fws_tlv_names[i].id == id)
return brcmf_fws_tlv_names[i].name;
return "INVALID";
}
#else
static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
{
return "NODEBUG";
}
#endif /* DEBUG */
/*
* flags used to enable tlv signalling from firmware.
*/
#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002
#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
#define BRCMF_FWS_STATE_OPEN 1
#define BRCMF_FWS_STATE_CLOSE 2
#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
#define BRCMF_FWS_MAX_IFNUM 16
#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0
#define BRCMF_FWS_HOSTIF_F