|
@@ -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);
|
|
|
}
|