aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-03 06:40:30 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-03 15:07:04 -0400
commitbb8c8063f82ce3eb7b44772202ca944f92ac39f5 (patch)
treec62af5503a147b3dde91993a0513a7e2e7777cc4
parentd48200ba45dd2edfe6286abfc783a81a4a492e98 (diff)
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: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Piotr Haber <phaber@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h7
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c10
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.c10
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c177
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h5
5 files changed, 148 insertions, 61 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index b4b970038799..64006edeb430 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -550,8 +550,9 @@ struct brcmf_if_event {
550 u8 bssidx; 550 u8 bssidx;
551}; 551};
552 552
553/* forward declaration */ 553/* forward declarations */
554struct brcmf_cfg80211_vif; 554struct brcmf_cfg80211_vif;
555struct brcmf_fws_mac_descriptor;
555 556
556/** 557/**
557 * struct brcmf_if - interface control information. 558 * struct brcmf_if - interface control information.
@@ -560,6 +561,9 @@ struct brcmf_cfg80211_vif;
560 * @vif: points to cfg80211 specific interface information. 561 * @vif: points to cfg80211 specific interface information.
561 * @ndev: associated network device. 562 * @ndev: associated network device.
562 * @stats: interface specific network statistics. 563 * @stats: interface specific network statistics.
564 * @setmacaddr_work: worker object for setting mac address.
565 * @multicast_work: worker object for multicast provisioning.
566 * @fws_desc: interface specific firmware-signalling descriptor.
563 * @ifidx: interface index in device firmware. 567 * @ifidx: interface index in device firmware.
564 * @bssidx: index of bss associated with this interface. 568 * @bssidx: index of bss associated with this interface.
565 * @mac_addr: assigned mac address. 569 * @mac_addr: assigned mac address.
@@ -573,6 +577,7 @@ struct brcmf_if {
573 struct net_device_stats stats; 577 struct net_device_stats stats;
574 struct work_struct setmacaddr_work; 578 struct work_struct setmacaddr_work;
575 struct work_struct multicast_work; 579 struct work_struct multicast_work;
580 struct brcmf_fws_mac_descriptor *fws_desc;
576 int ifidx; 581 int ifidx;
577 s32 bssidx; 582 s32 bssidx;
578 u8 mac_addr[ETH_ALEN]; 583 u8 mac_addr[ETH_ALEN];
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index fa5a2af04d46..a08db02537fc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -755,7 +755,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
755 ifp->ifidx = ifidx; 755 ifp->ifidx = ifidx;
756 ifp->bssidx = bssidx; 756 ifp->bssidx = bssidx;
757 757
758
759 init_waitqueue_head(&ifp->pend_8021x_wait); 758 init_waitqueue_head(&ifp->pend_8021x_wait);
760 759
761 if (mac_addr != NULL) 760 if (mac_addr != NULL)
@@ -882,6 +881,7 @@ int brcmf_bus_start(struct device *dev)
882 881
883 drvr->fw_signals = true; 882 drvr->fw_signals = true;
884 (void)brcmf_fws_init(drvr); 883 (void)brcmf_fws_init(drvr);
884 brcmf_fws_add_interface(ifp);
885 885
886 drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev); 886 drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
887 if (drvr->config == NULL) { 887 if (drvr->config == NULL) {
@@ -899,8 +899,10 @@ fail:
899 brcmf_err("failed: %d\n", ret); 899 brcmf_err("failed: %d\n", ret);
900 if (drvr->config) 900 if (drvr->config)
901 brcmf_cfg80211_detach(drvr->config); 901 brcmf_cfg80211_detach(drvr->config);
902 if (drvr->fws) 902 if (drvr->fws) {
903 brcmf_fws_del_interface(ifp);
903 brcmf_fws_deinit(drvr); 904 brcmf_fws_deinit(drvr);
905 }
904 free_netdev(ifp->ndev); 906 free_netdev(ifp->ndev);
905 drvr->iflist[0] = NULL; 907 drvr->iflist[0] = NULL;
906 if (p2p_ifp) { 908 if (p2p_ifp) {
@@ -956,8 +958,10 @@ void brcmf_detach(struct device *dev)
956 958
957 /* make sure primary interface removed last */ 959 /* make sure primary interface removed last */
958 for (i = BRCMF_MAX_IFS-1; i > -1; i--) 960 for (i = BRCMF_MAX_IFS-1; i > -1; i--)
959 if (drvr->iflist[i]) 961 if (drvr->iflist[i]) {
962 brcmf_fws_del_interface(drvr->iflist[i]);
960 brcmf_del_if(drvr, i); 963 brcmf_del_if(drvr, i);
964 }
961 965
962 brcmf_bus_detach(drvr); 966 brcmf_bus_detach(drvr);
963 967
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
index e9d6f91a1f2b..dad94147b6b5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -20,6 +20,7 @@
20 20
21#include "dhd.h" 21#include "dhd.h"
22#include "dhd_dbg.h" 22#include "dhd_dbg.h"
23#include "fwsignal.h"
23#include "fweh.h" 24#include "fweh.h"
24#include "fwil.h" 25#include "fwil.h"
25 26
@@ -198,15 +199,20 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
198 emsg->ifname, emsg->addr); 199 emsg->ifname, emsg->addr);
199 if (IS_ERR(ifp)) 200 if (IS_ERR(ifp))
200 return; 201 return;
201 202 brcmf_fws_add_interface(ifp);
202 if (!drvr->fweh.evt_handler[BRCMF_E_IF]) 203 if (!drvr->fweh.evt_handler[BRCMF_E_IF])
203 err = brcmf_net_attach(ifp, false); 204 err = brcmf_net_attach(ifp, false);
204 } 205 }
205 206
207 if (ifevent->action == BRCMF_E_IF_CHANGE)
208 brcmf_fws_reset_interface(ifp);
209
206 err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); 210 err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
207 211
208 if (ifevent->action == BRCMF_E_IF_DEL) 212 if (ifevent->action == BRCMF_E_IF_DEL) {
213 brcmf_fws_del_interface(ifp);
209 brcmf_del_if(drvr, ifevent->bssidx); 214 brcmf_del_if(drvr, ifevent->bssidx);
215 }
210} 216}
211 217
212/** 218/**
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 071d55f9cd4d..7ceaceba1845 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -73,16 +73,6 @@ enum brcmf_fws_tlv_type {
73}; 73};
74#undef BRCMF_FWS_TLV_DEF 74#undef BRCMF_FWS_TLV_DEF
75 75
76/**
77 * enum brcmf_fws_tlv_len - length values for tlvs.
78 */
79#define BRCMF_FWS_TLV_DEF(name, id, len) \
80 BRCMF_FWS_TYPE_ ## name ## _LEN = len,
81enum brcmf_fws_tlv_len {
82 BRCMF_FWS_TLV_DEFLIST
83};
84#undef BRCMF_FWS_TLV_DEF
85
86#ifdef DEBUG 76#ifdef DEBUG
87/** 77/**
88 * brcmf_fws_tlv_names - array of tlv names. 78 * 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/** 107/**
118 * flags used to enable tlv signalling from firmware. 108 * flags used to enable tlv signalling from firmware.
119 */ 109 */
120#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001 110#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
121#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002 111#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002
122#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 112#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
123#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 113#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
124#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 114#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
125#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 115#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
126#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040 116#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
127 117
128#define BRCMF_FWS_HANGER_MAXITEMS 1024 118#define BRCMF_FWS_HANGER_MAXITEMS 1024
129#define BRCMF_FWS_HANGER_ITEM_STATE_FREE 1 119#define BRCMF_FWS_HANGER_ITEM_STATE_FREE 1
130#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE 2 120#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE 2
131#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 121#define BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3
132 122
133#define BRCMF_FWS_STATE_OPEN 1 123#define BRCMF_FWS_STATE_OPEN 1
134#define BRCMF_FWS_STATE_CLOSE 2 124#define BRCMF_FWS_STATE_CLOSE 2
135 125
136#define BRCMF_FWS_FCMODE_NONE 0 126#define BRCMF_FWS_FCMODE_NONE 0
137#define BRCMF_FWS_FCMODE_IMPLIED_CREDIT 1 127#define BRCMF_FWS_FCMODE_IMPLIED_CREDIT 1
138#define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 2 128#define BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 2
139 129
140#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32 130#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
141#define BRCMF_FWS_MAX_IFNUM 16 131#define BRCMF_FWS_MAX_IFNUM 16
142#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff 132#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
143 133
144#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0 134#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0
145#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1 135#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1
146 136
137#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2)
138#define BRCMF_FWS_PSQ_LEN 256
139
140/**
141 * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
142 *
143 * @occupied: slot is in use.
144 * @interface_id: interface index.
145 * @state: current state.
146 * @ac_bitmap: ac queue bitmap.
147 * @requested_credit: credits requested by firmware.
148 * @ea: ethernet address.
149 * @psq: power-save queue.
150 */
151struct brcmf_fws_mac_descriptor {
152 u8 occupied;
153 u8 interface_id;
154 u8 state;
155 u8 ac_bitmap;
156 u8 requested_credit;
157 u8 ea[ETH_ALEN];
158 struct pktq psq;
159};
160
147/** 161/**
148 * FWFC packet identifier 162 * FWFC packet identifier
149 * 163 *
@@ -182,6 +196,27 @@ struct brcmf_fws_info {
182 struct brcmf_fws_stats stats; 196 struct brcmf_fws_stats stats;
183}; 197};
184 198
199/**
200 * brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
201 */
202#define BRCMF_FWS_TLV_DEF(name, id, len) \
203 case BRCMF_FWS_TYPE_ ## name: \
204 return len;
205
206static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
207 enum brcmf_fws_tlv_type id)
208{
209 switch (id) {
210 BRCMF_FWS_TLV_DEFLIST
211 default:
212 brcmf_err("invalid tlv id: %d\n", id);
213 fws->stats.tlv_invalid_type++;
214 break;
215 }
216 return -EINVAL;
217}
218#undef BRCMF_FWS_TLV_DEF
219
185static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) 220static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
186{ 221{
187 brcmf_dbg(CTL, "rssi %d\n", rssi); 222 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 if (data_len < len + 2) 343 if (data_len < len + 2)
309 break; 344 break;
310 345
346 if (len != brcmf_fws_get_tlv_len(fws, type))
347 break;
348
311 brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type, 349 brcmf_dbg(INFO, "tlv type=%d (%s), len=%d\n", type,
312 brcmf_fws_get_tlv_name(type), len); 350 brcmf_fws_get_tlv_name(type), len);
313 switch (type) { 351 switch (type) {
314 case BRCMF_FWS_TYPE_MAC_OPEN: 352 case BRCMF_FWS_TYPE_MAC_OPEN:
315 case BRCMF_FWS_TYPE_MAC_CLOSE: 353 case BRCMF_FWS_TYPE_MAC_CLOSE:
316 WARN_ON(len != BRCMF_FWS_TYPE_MAC_OPEN_LEN);
317 break;
318 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT: 354 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
319 WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT_LEN);
320 break;
321 case BRCMF_FWS_TYPE_TXSTATUS: 355 case BRCMF_FWS_TYPE_TXSTATUS:
322 WARN_ON(len != BRCMF_FWS_TYPE_TXSTATUS_LEN);
323 break;
324 case BRCMF_FWS_TYPE_PKTTAG: 356 case BRCMF_FWS_TYPE_PKTTAG:
325 WARN_ON(len != BRCMF_FWS_TYPE_PKTTAG_LEN);
326 break;
327 case BRCMF_FWS_TYPE_MACDESC_ADD:
328 case BRCMF_FWS_TYPE_MACDESC_DEL:
329 WARN_ON(len != BRCMF_FWS_TYPE_MACDESC_ADD_LEN);
330 break;
331 case BRCMF_FWS_TYPE_RSSI:
332 WARN_ON(len != BRCMF_FWS_TYPE_RSSI_LEN);
333 brcmf_fws_rssi_indicate(fws, *(s8 *)data);
334 break;
335 case BRCMF_FWS_TYPE_INTERFACE_OPEN: 357 case BRCMF_FWS_TYPE_INTERFACE_OPEN:
336 case BRCMF_FWS_TYPE_INTERFACE_CLOSE: 358 case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
337 WARN_ON(len != BRCMF_FWS_TYPE_INTERFACE_OPEN_LEN);
338 break;
339 case BRCMF_FWS_TYPE_FIFO_CREDITBACK: 359 case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
340 WARN_ON(len != BRCMF_FWS_TYPE_FIFO_CREDITBACK_LEN);
341 break;
342 case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP: 360 case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
343 WARN_ON(len != BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN);
344 break;
345 case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET: 361 case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
346 WARN_ON(len != BRCMF_FWS_TYPE_MAC_REQUEST_PACKET_LEN);
347 break;
348 case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: 362 case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
349 WARN_ON(len != BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS_LEN); 363 case BRCMF_FWS_TYPE_COMP_TXSTATUS:
364 case BRCMF_FWS_TYPE_MACDESC_ADD:
365 case BRCMF_FWS_TYPE_MACDESC_DEL:
366 break;
367 case BRCMF_FWS_TYPE_RSSI:
368 brcmf_fws_rssi_indicate(fws, *data);
350 break; 369 break;
351 case BRCMF_FWS_TYPE_TRANS_ID: 370 case BRCMF_FWS_TYPE_TRANS_ID:
352 WARN_ON(len != BRCMF_FWS_TYPE_TRANS_ID_LEN);
353 brcmf_fws_dbg_seqnum_check(fws, data); 371 brcmf_fws_dbg_seqnum_check(fws, data);
354 break; 372 break;
355 case BRCMF_FWS_TYPE_COMP_TXSTATUS:
356 WARN_ON(len != BRCMF_FWS_TYPE_COMP_TXSTATUS_LEN);
357 break;
358 default: 373 default:
359 fws->stats.tlv_invalid_type++; 374 fws->stats.tlv_invalid_type++;
360 break; 375 break;
@@ -380,3 +395,55 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
380 brcmf_fws_unlock(drvr, flags); 395 brcmf_fws_unlock(drvr, flags);
381 return 0; 396 return 0;
382} 397}
398
399void brcmf_fws_reset_interface(struct brcmf_if *ifp)
400{
401 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
402
403 brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
404 if (!entry)
405 return;
406
407 entry->occupied = 1;
408 entry->state = BRCMF_FWS_STATE_OPEN;
409 entry->requested_credit = 0;
410 /* depending on use may need ifp->bssidx instead */
411 entry->interface_id = ifp->ifidx;
412 entry->ac_bitmap = 0xff; /* update this when handling APSD */
413 memcpy(&entry->ea[0], ifp->mac_addr, ETH_ALEN);
414}
415
416void brcmf_fws_add_interface(struct brcmf_if *ifp)
417{
418 struct brcmf_fws_mac_descriptor *entry;
419
420 brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n",
421 ifp->bssidx, ifp->mac_addr);
422 if (!ifp->drvr->fw_signals)
423 return;
424
425 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
426 if (entry) {
427 ifp->fws_desc = entry;
428 brcmf_fws_reset_interface(ifp);
429 brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
430 BRCMF_FWS_PSQ_LEN);
431 } else {
432 brcmf_err("no firmware signalling\n");
433 }
434}
435
436void brcmf_fws_del_interface(struct brcmf_if *ifp)
437{
438 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
439
440 brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
441 if (!entry)
442 return;
443
444 ifp->fws_desc = NULL;
445 entry->occupied = 0;
446 entry->state = BRCMF_FWS_STATE_CLOSE;
447 entry->requested_credit = 0;
448 kfree(entry);
449}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
index e728eea72bb4..38a75e494d7d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
@@ -22,4 +22,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr);
22void brcmf_fws_deinit(struct brcmf_pub *drvr); 22void brcmf_fws_deinit(struct brcmf_pub *drvr);
23int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, 23int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
24 struct sk_buff *skb); 24 struct sk_buff *skb);
25
26void brcmf_fws_reset_interface(struct brcmf_if *ifp);
27void brcmf_fws_add_interface(struct brcmf_if *ifp);
28void brcmf_fws_del_interface(struct brcmf_if *ifp);
29
25#endif /* FWSIGNAL_H_ */ 30#endif /* FWSIGNAL_H_ */