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

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

brcmfmac: handle firmware signal for updating mac descriptor info



Firmware can signal the driver to allocate descriptor info for a given
mac address, which will be used for flow control and host queueing.

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 bb8c8063
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -141,11 +141,13 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
			"header_pulls:     %u\n"
			"header_only_pkt:  %u\n"
			"tlv_parse_failed: %u\n"
			"tlv_invalid_type: %u\n",
			"tlv_invalid_type: %u\n"
			"mac_update_fails: %u\n",
			fwstats->header_pulls,
			fwstats->header_only_pkt,
			fwstats->tlv_parse_failed,
			fwstats->tlv_invalid_type);
			fwstats->tlv_invalid_type,
			fwstats->mac_update_failed);

	return simple_read_from_buffer(data, count, ppos, buf, res);
}
+1 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct brcmf_fws_stats {
	u32 tlv_invalid_type;
	u32 header_only_pkt;
	u32 header_pulls;
	u32 mac_update_failed;
};

struct brcmf_pub;
+107 −13
Original line number Diff line number Diff line
@@ -141,6 +141,7 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
 * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
 *
 * @occupied: slot is in use.
 * @mac_handle: handle for mac entry determined by firmware.
 * @interface_id: interface index.
 * @state: current state.
 * @ac_bitmap: ac queue bitmap.
@@ -150,6 +151,7 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
 */
struct brcmf_fws_mac_descriptor {
	u8 occupied;
	u8 mac_handle;
	u8 interface_id;
	u8 state;
	u8 ac_bitmap;
@@ -194,6 +196,7 @@ struct brcmf_fws_mac_descriptor {
struct brcmf_fws_info {
	struct brcmf_pub *drvr;
	struct brcmf_fws_stats stats;
	struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
};

/**
@@ -217,12 +220,107 @@ static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
}
#undef BRCMF_FWS_TLV_DEF

static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
					  u8 *addr, u8 ifidx)
{
	brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u\n", addr, ifidx);
	desc->occupied = 1;
	desc->state = BRCMF_FWS_STATE_OPEN;
	desc->requested_credit = 0;
	/* depending on use may need ifp->bssidx instead */
	desc->interface_id = ifidx;
	desc->ac_bitmap = 0xff; /* update this when handling APSD */
	memcpy(&desc->ea[0], addr, ETH_ALEN);
}

static
void brcmf_fws_clear_mac_descriptor(struct brcmf_fws_mac_descriptor *desc)
{
	brcmf_dbg(TRACE,
		  "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id);
	desc->occupied = 0;
	desc->state = BRCMF_FWS_STATE_CLOSE;
	desc->requested_credit = 0;
}

static struct brcmf_fws_mac_descriptor *
brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea)
{
	struct brcmf_fws_mac_descriptor *entry;
	int i;

	brcmf_dbg(TRACE, "enter: ea=%pM\n", ea);
	if (ea == NULL)
		return ERR_PTR(-EINVAL);

	entry = &fws->nodes[0];
	for (i = 0; i < ARRAY_SIZE(fws->nodes); i++) {
		if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
			return entry;
		entry++;
	}

	return ERR_PTR(-ENOENT);
}

static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
{
	brcmf_dbg(CTL, "rssi %d\n", rssi);
	return 0;
}

static
int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
{
	struct brcmf_fws_mac_descriptor *entry, *existing;
	u8 mac_handle;
	u8 ifidx;
	u8 *addr;

	mac_handle = *data++;
	ifidx = *data++;
	addr = data;

	entry = &fws->nodes[mac_handle & 0x1F];
	if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
		brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx);
		if (entry->occupied) {
			entry->occupied = 0;
			entry->state = BRCMF_FWS_STATE_CLOSE;
			entry->requested_credit = 0;
		} else {
			fws->stats.mac_update_failed++;
		}
		return 0;
	}

	brcmf_dbg(TRACE, "add mac %pM idx %d\n", addr, ifidx);
	existing = brcmf_fws_mac_descriptor_lookup(fws, addr);
	if (IS_ERR(existing)) {
		if (!entry->occupied) {
			entry->mac_handle = mac_handle;
			brcmf_fws_init_mac_descriptor(entry, addr, ifidx);
			brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
					BRCMF_FWS_PSQ_LEN);
		} else {
			fws->stats.mac_update_failed++;
		}
	} else {
		if (entry != existing) {
			brcmf_dbg(TRACE, "relocate mac\n");
			memcpy(entry, existing,
			       offsetof(struct brcmf_fws_mac_descriptor, psq));
			entry->mac_handle = mac_handle;
			brcmf_fws_clear_mac_descriptor(existing);
		} else {
			brcmf_dbg(TRACE, "use existing\n");
			WARN_ON(entry->mac_handle != mac_handle);
			/* TODO: what should we do here: continue, reinit, .. */
		}
	}
	return 0;
}

static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
{
	__le32 timestamp;
@@ -250,11 +348,13 @@ do { \

int brcmf_fws_init(struct brcmf_pub *drvr)
{
	u32 tlv;
	u32 tlv = 0;
	int rc;

	/* enable rssi signals */
	tlv = drvr->fw_signals ? BRCMF_FWS_FLAGS_RSSI_SIGNALS : 0;
	if (drvr->fw_signals)
		tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS |
		      BRCMF_FWS_FLAGS_XONXOFF_SIGNALS;

	spin_lock_init(&drvr->fws_spinlock);

@@ -361,8 +461,10 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
		case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
		case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
		case BRCMF_FWS_TYPE_COMP_TXSTATUS:
			break;
		case BRCMF_FWS_TYPE_MACDESC_ADD:
		case BRCMF_FWS_TYPE_MACDESC_DEL:
			brcmf_fws_macdesc_indicate(fws, type, data);
			break;
		case BRCMF_FWS_TYPE_RSSI:
			brcmf_fws_rssi_indicate(fws, *data);
@@ -404,13 +506,7 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp)
	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);
	brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
}

void brcmf_fws_add_interface(struct brcmf_if *ifp)
@@ -425,7 +521,7 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp)
	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
	if (entry) {
		ifp->fws_desc = entry;
		brcmf_fws_reset_interface(ifp);
		brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
		brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
				BRCMF_FWS_PSQ_LEN);
	} else {
@@ -442,8 +538,6 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp)
		return;

	ifp->fws_desc = NULL;
	entry->occupied = 0;
	entry->state = BRCMF_FWS_STATE_CLOSE;
	entry->requested_credit = 0;
	brcmf_fws_clear_mac_descriptor(entry);
	kfree(entry);
}