Commit bb8c8063 authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville

brcmfmac: hookup firmware signalling to firmware interface events

Firmware signalling needs to handle resources upon interface
events. This patch add calls in the interface event handling
routine.
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPiotr Haber <phaber@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d48200ba
...@@ -550,8 +550,9 @@ struct brcmf_if_event { ...@@ -550,8 +550,9 @@ struct brcmf_if_event {
u8 bssidx; u8 bssidx;
}; };
/* forward declaration */ /* forward declarations */
struct brcmf_cfg80211_vif; struct brcmf_cfg80211_vif;
struct brcmf_fws_mac_descriptor;
/** /**
* struct brcmf_if - interface control information. * struct brcmf_if - interface control information.
...@@ -560,6 +561,9 @@ struct brcmf_cfg80211_vif; ...@@ -560,6 +561,9 @@ struct brcmf_cfg80211_vif;
* @vif: points to cfg80211 specific interface information. * @vif: points to cfg80211 specific interface information.
* @ndev: associated network device. * @ndev: associated network device.
* @stats: interface specific network statistics. * @stats: interface specific network statistics.
* @setmacaddr_work: worker object for setting mac address.
* @multicast_work: worker object for multicast provisioning.
* @fws_desc: interface specific firmware-signalling descriptor.
* @ifidx: interface index in device firmware. * @ifidx: interface index in device firmware.
* @bssidx: index of bss associated with this interface. * @bssidx: index of bss associated with this interface.
* @mac_addr: assigned mac address. * @mac_addr: assigned mac address.
...@@ -573,6 +577,7 @@ struct brcmf_if { ...@@ -573,6 +577,7 @@ struct brcmf_if {
struct net_device_stats stats; struct net_device_stats stats;
struct work_struct setmacaddr_work; struct work_struct setmacaddr_work;
struct work_struct multicast_work; struct work_struct multicast_work;
struct brcmf_fws_mac_descriptor *fws_desc;
int ifidx; int ifidx;
s32 bssidx; s32 bssidx;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
......
...@@ -755,7 +755,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, ...@@ -755,7 +755,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
ifp->ifidx = ifidx; ifp->ifidx = ifidx;
ifp->bssidx = bssidx; ifp->bssidx = bssidx;
init_waitqueue_head(&ifp->pend_8021x_wait); init_waitqueue_head(&ifp->pend_8021x_wait);
if (mac_addr != NULL) if (mac_addr != NULL)
...@@ -882,6 +881,7 @@ int brcmf_bus_start(struct device *dev) ...@@ -882,6 +881,7 @@ int brcmf_bus_start(struct device *dev)
drvr->fw_signals = true; drvr->fw_signals = true;
(void)brcmf_fws_init(drvr); (void)brcmf_fws_init(drvr);
brcmf_fws_add_interface(ifp);
drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev); drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
if (drvr->config == NULL) { if (drvr->config == NULL) {
...@@ -899,8 +899,10 @@ int brcmf_bus_start(struct device *dev) ...@@ -899,8 +899,10 @@ int brcmf_bus_start(struct device *dev)
brcmf_err("failed: %d\n", ret); brcmf_err("failed: %d\n", ret);
if (drvr->config) if (drvr->config)
brcmf_cfg80211_detach(drvr->config); brcmf_cfg80211_detach(drvr->config);
if (drvr->fws) if (drvr->fws) {
brcmf_fws_del_interface(ifp);
brcmf_fws_deinit(drvr); brcmf_fws_deinit(drvr);
}
free_netdev(ifp->ndev); free_netdev(ifp->ndev);
drvr->iflist[0] = NULL; drvr->iflist[0] = NULL;
if (p2p_ifp) { if (p2p_ifp) {
...@@ -956,8 +958,10 @@ void brcmf_detach(struct device *dev) ...@@ -956,8 +958,10 @@ void brcmf_detach(struct device *dev)
/* make sure primary interface removed last */ /* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--) for (i = BRCMF_MAX_IFS-1; i > -1; i--)
if (drvr->iflist[i]) if (drvr->iflist[i]) {
brcmf_fws_del_interface(drvr->iflist[i]);
brcmf_del_if(drvr, i); brcmf_del_if(drvr, i);
}
brcmf_bus_detach(drvr); brcmf_bus_detach(drvr);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "dhd.h" #include "dhd.h"
#include "dhd_dbg.h" #include "dhd_dbg.h"
#include "fwsignal.h"
#include "fweh.h" #include "fweh.h"
#include "fwil.h" #include "fwil.h"
...@@ -198,15 +199,20 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, ...@@ -198,15 +199,20 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
emsg->ifname, emsg->addr); emsg->ifname, emsg->addr);
if (IS_ERR(ifp)) if (IS_ERR(ifp))
return; return;
brcmf_fws_add_interface(ifp);
if (!drvr->fweh.evt_handler[BRCMF_E_IF]) if (!drvr->fweh.evt_handler[BRCMF_E_IF])
err = brcmf_net_attach(ifp, false); err = brcmf_net_attach(ifp, false);
} }
if (ifevent->action == BRCMF_E_IF_CHANGE)
brcmf_fws_reset_interface(ifp);
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
if (ifevent->action == BRCMF_E_IF_DEL) if (ifevent->action == BRCMF_E_IF_DEL) {
brcmf_fws_del_interface(ifp);
brcmf_del_if(drvr, ifevent->bssidx); brcmf_del_if(drvr, ifevent->bssidx);
}
} }
/** /**
......
...@@ -73,16 +73,6 @@ enum brcmf_fws_tlv_type { ...@@ -73,16 +73,6 @@ enum brcmf_fws_tlv_type {
}; };
#undef BRCMF_FWS_TLV_DEF #undef BRCMF_FWS_TLV_DEF
/**
* enum brcmf_fws_tlv_len - length values for tlvs.
*/
#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 #ifdef DEBUG
/** /**
* brcmf_fws_tlv_names - array of tlv names. * brcmf_fws_tlv_names - array of tlv names.
...@@ -117,33 +107,57 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) ...@@ -117,33 +107,57 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
/** /**
* flags used to enable tlv signalling from firmware. * flags used to enable tlv signalling from firmware.
*/ */
#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001 #define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002 #define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002
#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 #define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 #define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 #define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 #define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040 #define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
#define BRCMF_FWS_HANGER_MAXITEMS 1024 #define BRCMF_FWS_HANGER_MAXITEMS 1024
#define BRCMF_FWS_HANGER_ITEM_STATE_FREE 1 #define BRCMF_FWS_HANGER_ITEM_STATE_FREE 1
#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE 2 #define BRCMF_FWS_HANGER_ITEM_STATE_INUSE 2
#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 #define BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3
#define BRCMF_FWS_STATE_OPEN 1 #define BRCMF_FWS_STATE_OPEN 1
#define BRCMF_FWS_STATE_CLOSE 2 #define BRCMF_FWS_STATE_CLOSE 2
#define BRCMF_FWS_FCMODE_NONE 0 #define BRCMF_FWS_FCMODE_NONE 0
#define BRCMF_FWS_FCMODE_IMPLIED_CREDIT 1 #define BRCMF_FWS_FCMODE_IMPLIED_CREDIT 1
#define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 2 #define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 2
#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32 #define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
#define BRCMF_FWS_MAX_IFNUM 16 #define BRCMF_FWS_MAX_IFNUM 16
#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff #define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0 #define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0
#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1 #define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1
#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2)
#define BRCMF_FWS_PSQ_LEN 256
/**
* struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
*
* @occupied: slot is in use.
* @interface_id: interface index.
* @state: current state.
* @ac_bitmap: ac queue bitmap.
* @requested_credit: credits requested by firmware.
* @ea: ethernet address.
* @psq: power-save queue.
*/
struct brcmf_fws_mac_descriptor {
u8 occupied;
u8 interface_id;
u8 state;
u8 ac_bitmap;
u8 requested_credit;
u8 ea[ETH_ALEN];
struct pktq psq;
};
/** /**
* FWFC packet identifier * FWFC packet identifier
* *
...@@ -182,6 +196,27 @@ struct brcmf_fws_info { ...@@ -182,6 +196,27 @@ struct brcmf_fws_info {
struct brcmf_fws_stats stats; struct brcmf_fws_stats stats;
}; };
/**
* brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
*/
#define BRCMF_FWS_TLV_DEF(name, id, len) \
case BRCMF_FWS_TYPE_ ## name: \
return len;
static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
enum brcmf_fws_tlv_type id)
{
switch (id) {
BRCMF_FWS_TLV_DEFLIST
default:
brcmf_err("invalid tlv id: %d\n", id);
fws->stats.tlv_invalid_type++;
break;
}
return -EINVAL;
}
#undef BRCMF_FWS_TLV_DEF
static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
{ {
brcmf_dbg(CTL, "rssi %d\n", rssi); brcmf_dbg(CTL, "rssi %d\n", rssi);
...@@ -308,53 +343,33 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, ...@@ -308,53 +343,33 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
if (data_len < len + 2) if (data_len < len + 2)
break; break;
if (len != brcmf_fws_get_tlv_len(fws, type))
break;
brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type, brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type,
brcmf_fws_get_tlv_name(type), len); brcmf_fws_get_tlv_name(type), len);
switch (type) { switch (type) {
case BRCMF_FWS_TYPE_MAC_OPEN: case BRCMF_FWS_TYPE_MAC_OPEN:
case BRCMF_FWS_TYPE_MAC_CLOSE: case BRCMF_FWS_TYPE_MAC_CLOSE:
WARN_ON(len != BRCMF_FWS_TYPE_MAC_OPEN_LEN);
break;
case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT: case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT_LEN);
break;
case BRCMF_FWS_TYPE_TXSTATUS: case BRCMF_FWS_TYPE_TXSTATUS:
WARN_ON(len != BRCMF_FWS_TYPE_TXSTATUS_LEN);
break;
case BRCMF_FWS_TYPE_PKTTAG: case BRCMF_FWS_TYPE_PKTTAG:
WARN_ON(len != BRCMF_FWS_TYPE_PKTTAG_LEN);
break;
case BRCMF_FWS_TYPE_MACDESC_ADD:
case BRCMF_FWS_TYPE_MACDESC_DEL:
WARN_ON(len != BRCMF_FWS_TYPE_MACDESC_ADD_LEN);
break;
case BRCMF_FWS_TYPE_RSSI:
WARN_ON(len != BRCMF_FWS_TYPE_RSSI_LEN);
brcmf_fws_rssi_indicate(fws, *(s8 *)data);
break;
case BRCMF_FWS_TYPE_INTERFACE_OPEN: case BRCMF_FWS_TYPE_INTERFACE_OPEN:
case BRCMF_FWS_TYPE_INTERFACE_CLOSE: case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
WARN_ON(len != BRCMF_FWS_TYPE_INTERFACE_OPEN_LEN);
break;
case BRCMF_FWS_TYPE_FIFO_CREDITBACK: case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
WARN_ON(len != BRCMF_FWS_TYPE_FIFO_CREDITBACK_LEN);
break;
case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP: case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
WARN_ON(len != BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN);
break;
case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET: case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_PACKET_LEN);
break;
case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
WARN_ON(len != BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS_LEN); case BRCMF_FWS_TYPE_COMP_TXSTATUS:
case BRCMF_FWS_TYPE_MACDESC_ADD:
case BRCMF_FWS_TYPE_MACDESC_DEL:
break;
case BRCMF_FWS_TYPE_RSSI:
brcmf_fws_rssi_indicate(fws, *data);
break; break;
case BRCMF_FWS_TYPE_TRANS_ID: case BRCMF_FWS_TYPE_TRANS_ID:
WARN_ON(len != BRCMF_FWS_TYPE_TRANS_ID_LEN);
brcmf_fws_dbg_seqnum_check(fws, data); brcmf_fws_dbg_seqnum_check(fws, data);
break; break;
case BRCMF_FWS_TYPE_COMP_TXSTATUS:
WARN_ON(len != BRCMF_FWS_TYPE_COMP_TXSTATUS_LEN);
break;
default: default:
fws->stats.tlv_invalid_type++; fws->stats.tlv_invalid_type++;
break; break;
...@@ -380,3 +395,55 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, ...@@ -380,3 +395,55 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
brcmf_fws_unlock(drvr, flags); brcmf_fws_unlock(drvr, flags);
return 0; return 0;
} }
void brcmf_fws_reset_interface(struct brcmf_if *ifp)
{
struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
if (!entry)
return;
entry->occupied = 1;
entry->state = BRCMF_FWS_STATE_OPEN;
entry->requested_credit = 0;
/* depending on use may need ifp->bssidx instead */
entry->interface_id = ifp->ifidx;
entry->ac_bitmap = 0xff; /* update this when handling APSD */
memcpy(&entry->ea[0], ifp->mac_addr, ETH_ALEN);
}
void brcmf_fws_add_interface(struct brcmf_if *ifp)
{
struct brcmf_fws_mac_descriptor *entry;
brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n",
ifp->bssidx, ifp->mac_addr);
if (!ifp->drvr->fw_signals)
return;
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (entry) {
ifp->fws_desc = entry;
brcmf_fws_reset_interface(ifp);
brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
BRCMF_FWS_PSQ_LEN);
} else {
brcmf_err("no firmware signalling\n");
}
}
void brcmf_fws_del_interface(struct brcmf_if *ifp)
{
struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
if (!entry)
return;
ifp->fws_desc = NULL;
entry->occupied = 0;
entry->state = BRCMF_FWS_STATE_CLOSE;
entry->requested_credit = 0;
kfree(entry);
}
...@@ -22,4 +22,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr); ...@@ -22,4 +22,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr);
void brcmf_fws_deinit(struct brcmf_pub *drvr); void brcmf_fws_deinit(struct brcmf_pub *drvr);
int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
struct sk_buff *skb); struct sk_buff *skb);
void brcmf_fws_reset_interface(struct brcmf_if *ifp);
void brcmf_fws_add_interface(struct brcmf_if *ifp);
void brcmf_fws_del_interface(struct brcmf_if *ifp);
#endif /* FWSIGNAL_H_ */ #endif /* FWSIGNAL_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment