Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -550,8 +550,9 @@ struct brcmf_if_event {
	u8 bssidx;
};

/* forward declaration */
/* forward declarations */
struct brcmf_cfg80211_vif;
struct brcmf_fws_mac_descriptor;

/**
 * struct brcmf_if - interface control information.
@@ -560,6 +561,9 @@ struct brcmf_cfg80211_vif;
 * @vif: points to cfg80211 specific interface information.
 * @ndev: associated network device.
 * @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.
 * @bssidx: index of bss associated with this interface.
 * @mac_addr: assigned mac address.
@@ -573,6 +577,7 @@ struct brcmf_if {
	struct net_device_stats stats;
	struct work_struct setmacaddr_work;
	struct work_struct multicast_work;
	struct brcmf_fws_mac_descriptor *fws_desc;
	int ifidx;
	s32 bssidx;
	u8 mac_addr[ETH_ALEN];
+7 −3
Original line number Diff line number Diff line
@@ -755,7 +755,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
	ifp->ifidx = ifidx;
	ifp->bssidx = bssidx;


	init_waitqueue_head(&ifp->pend_8021x_wait);

	if (mac_addr != NULL)
@@ -882,6 +881,7 @@ int brcmf_bus_start(struct device *dev)

	drvr->fw_signals = true;
	(void)brcmf_fws_init(drvr);
	brcmf_fws_add_interface(ifp);

	drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
	if (drvr->config == NULL) {
@@ -899,8 +899,10 @@ int brcmf_bus_start(struct device *dev)
		brcmf_err("failed: %d\n", ret);
		if (drvr->config)
			brcmf_cfg80211_detach(drvr->config);
		if (drvr->fws)
		if (drvr->fws) {
			brcmf_fws_del_interface(ifp);
			brcmf_fws_deinit(drvr);
		}
		free_netdev(ifp->ndev);
		drvr->iflist[0] = NULL;
		if (p2p_ifp) {
@@ -956,8 +958,10 @@ void brcmf_detach(struct device *dev)

	/* make sure primary interface removed last */
	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_bus_detach(drvr);

+8 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include "dhd.h"
#include "dhd_dbg.h"
#include "fwsignal.h"
#include "fweh.h"
#include "fwil.h"

@@ -198,16 +199,21 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
				   emsg->ifname, emsg->addr);
		if (IS_ERR(ifp))
			return;

		brcmf_fws_add_interface(ifp);
		if (!drvr->fweh.evt_handler[BRCMF_E_IF])
			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);

	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_fweh_dequeue_event() - get event from the queue.
+122 −55
Original line number Diff line number Diff line
@@ -73,16 +73,6 @@ enum brcmf_fws_tlv_type {
};
#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
/**
 * brcmf_fws_tlv_names - array of tlv names.
@@ -144,6 +134,30 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF			0
#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
 *
@@ -182,6 +196,27 @@ struct brcmf_fws_info {
	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)
{
	brcmf_dbg(CTL, "rssi %d\n", rssi);
@@ -308,53 +343,33 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
		if (data_len < len + 2)
			break;

		if (len != brcmf_fws_get_tlv_len(fws, type))
			break;

		brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type,
			  brcmf_fws_get_tlv_name(type), len);
		switch (type) {
		case BRCMF_FWS_TYPE_MAC_OPEN:
		case BRCMF_FWS_TYPE_MAC_CLOSE:
			WARN_ON(len != BRCMF_FWS_TYPE_MAC_OPEN_LEN);
			break;
		case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
			WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT_LEN);
			break;
		case BRCMF_FWS_TYPE_TXSTATUS:
			WARN_ON(len != BRCMF_FWS_TYPE_TXSTATUS_LEN);
			break;
		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_CLOSE:
			WARN_ON(len != BRCMF_FWS_TYPE_INTERFACE_OPEN_LEN);
			break;
		case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
			WARN_ON(len != BRCMF_FWS_TYPE_FIFO_CREDITBACK_LEN);
			break;
		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:
			WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_PACKET_LEN);
			break;
		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;
		case BRCMF_FWS_TYPE_TRANS_ID:
			WARN_ON(len != BRCMF_FWS_TYPE_TRANS_ID_LEN);
			brcmf_fws_dbg_seqnum_check(fws, data);
			break;
		case BRCMF_FWS_TYPE_COMP_TXSTATUS:
			WARN_ON(len != BRCMF_FWS_TYPE_COMP_TXSTATUS_LEN);
			break;
		default:
			fws->stats.tlv_invalid_type++;
			break;
@@ -380,3 +395,55 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
	brcmf_fws_unlock(drvr, flags);
	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);
}
+5 −0
Original line number Diff line number Diff line
@@ -22,4 +22,9 @@ int brcmf_fws_init(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,
		      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_ */