aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2012-11-14 21:46:05 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-11-16 14:28:45 -0500
commit5c36b99add5c3212b6cdb97cc206e1e3e0fa1e3c (patch)
treeef6ce3d633639ae8f09bede38f31258291f18dc1 /drivers/net/wireless
parent957708f1a2d3fd41021ea0282e1cd856d23df9ca (diff)
brcmfmac: rework firmware event handling code
Handling of firmware event has been reworked into a seperate code file. The change is needed as firmware event can be received in interrupt context. Decoupling of the event handling has been lowered to allow event processing to sleep. Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: Franky Lin <frankyl@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h110
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c399
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c39
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.c498
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.h207
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c246
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h31
9 files changed, 763 insertions, 770 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index fe80b637c519..1a6661a9f008 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
25brcmfmac-objs += \ 25brcmfmac-objs += \
26 wl_cfg80211.o \ 26 wl_cfg80211.o \
27 fwil.o \ 27 fwil.o \
28 fweh.o \
28 dhd_cdc.o \ 29 dhd_cdc.o \
29 dhd_common.o \ 30 dhd_common.o \
30 dhd_linux.o 31 dhd_linux.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 9807092c49cb..10d92b51ee46 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -23,6 +23,8 @@
23 23
24#define BRCMF_VERSION_STR "4.218.248.5" 24#define BRCMF_VERSION_STR "4.218.248.5"
25 25
26#include "fweh.h"
27
26/******************************************************************************* 28/*******************************************************************************
27 * IO codes that are interpreted by dongle firmware 29 * IO codes that are interpreted by dongle firmware
28 ******************************************************************************/ 30 ******************************************************************************/
@@ -117,10 +119,6 @@
117#define DOT11_BSSTYPE_ANY 2 119#define DOT11_BSSTYPE_ANY 2
118#define DOT11_MAX_DEFAULT_KEYS 4 120#define DOT11_MAX_DEFAULT_KEYS 4
119 121
120#define BRCMF_EVENT_MSG_LINK 0x01
121#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
122#define BRCMF_EVENT_MSG_GROUP 0x04
123
124#define BRCMF_ESCAN_REQ_VERSION 1 122#define BRCMF_ESCAN_REQ_VERSION 1
125 123
126#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 124#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
@@ -128,108 +126,6 @@
128#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ 126#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
129#define BRCMF_STA_ASSOC 0x10 /* Associated */ 127#define BRCMF_STA_ASSOC 0x10 /* Associated */
130 128
131struct brcmf_event_msg {
132 __be16 version;
133 __be16 flags;
134 __be32 event_type;
135 __be32 status;
136 __be32 reason;
137 __be32 auth_type;
138 __be32 datalen;
139 u8 addr[ETH_ALEN];
140 char ifname[IFNAMSIZ];
141 u8 ifidx;
142 u8 bsscfgidx;
143} __packed;
144
145struct brcm_ethhdr {
146 u16 subtype;
147 u16 length;
148 u8 version;
149 u8 oui[3];
150 u16 usr_subtype;
151} __packed;
152
153struct brcmf_event {
154 struct ethhdr eth;
155 struct brcm_ethhdr hdr;
156 struct brcmf_event_msg msg;
157} __packed;
158
159/* event codes sent by the dongle to this driver */
160#define BRCMF_E_SET_SSID 0
161#define BRCMF_E_JOIN 1
162#define BRCMF_E_START 2
163#define BRCMF_E_AUTH 3
164#define BRCMF_E_AUTH_IND 4
165#define BRCMF_E_DEAUTH 5
166#define BRCMF_E_DEAUTH_IND 6
167#define BRCMF_E_ASSOC 7
168#define BRCMF_E_ASSOC_IND 8
169#define BRCMF_E_REASSOC 9
170#define BRCMF_E_REASSOC_IND 10
171#define BRCMF_E_DISASSOC 11
172#define BRCMF_E_DISASSOC_IND 12
173#define BRCMF_E_QUIET_START 13
174#define BRCMF_E_QUIET_END 14
175#define BRCMF_E_BEACON_RX 15
176#define BRCMF_E_LINK 16
177#define BRCMF_E_MIC_ERROR 17
178#define BRCMF_E_NDIS_LINK 18
179#define BRCMF_E_ROAM 19
180#define BRCMF_E_TXFAIL 20
181#define BRCMF_E_PMKID_CACHE 21
182#define BRCMF_E_RETROGRADE_TSF 22
183#define BRCMF_E_PRUNE 23
184#define BRCMF_E_AUTOAUTH 24
185#define BRCMF_E_EAPOL_MSG 25
186#define BRCMF_E_SCAN_COMPLETE 26
187#define BRCMF_E_ADDTS_IND 27
188#define BRCMF_E_DELTS_IND 28
189#define BRCMF_E_BCNSENT_IND 29
190#define BRCMF_E_BCNRX_MSG 30
191#define BRCMF_E_BCNLOST_MSG 31
192#define BRCMF_E_ROAM_PREP 32
193#define BRCMF_E_PFN_NET_FOUND 33
194#define BRCMF_E_PFN_NET_LOST 34
195#define BRCMF_E_RESET_COMPLETE 35
196#define BRCMF_E_JOIN_START 36
197#define BRCMF_E_ROAM_START 37
198#define BRCMF_E_ASSOC_START 38
199#define BRCMF_E_IBSS_ASSOC 39
200#define BRCMF_E_RADIO 40
201#define BRCMF_E_PSM_WATCHDOG 41
202#define BRCMF_E_PROBREQ_MSG 44
203#define BRCMF_E_SCAN_CONFIRM_IND 45
204#define BRCMF_E_PSK_SUP 46
205#define BRCMF_E_COUNTRY_CODE_CHANGED 47
206#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48
207#define BRCMF_E_ICV_ERROR 49
208#define BRCMF_E_UNICAST_DECODE_ERROR 50
209#define BRCMF_E_MULTICAST_DECODE_ERROR 51
210#define BRCMF_E_TRACE 52
211#define BRCMF_E_IF 54
212#define BRCMF_E_RSSI 56
213#define BRCMF_E_PFN_SCAN_COMPLETE 57
214#define BRCMF_E_EXTLOG_MSG 58
215#define BRCMF_E_ACTION_FRAME 59
216#define BRCMF_E_ACTION_FRAME_COMPLETE 60
217#define BRCMF_E_PRE_ASSOC_IND 61
218#define BRCMF_E_PRE_REASSOC_IND 62
219#define BRCMF_E_CHANNEL_ADOPTED 63
220#define BRCMF_E_AP_STARTED 64
221#define BRCMF_E_DFS_AP_STOP 65
222#define BRCMF_E_DFS_AP_RESUME 66
223#define BRCMF_E_RESERVED1 67
224#define BRCMF_E_RESERVED2 68
225#define BRCMF_E_ESCAN_RESULT 69
226#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70
227#define BRCMF_E_DCS_REQUEST 73
228
229#define BRCMF_E_FIFO_CREDIT_MAP 74
230
231#define BRCMF_E_LAST 75
232
233#define BRCMF_E_STATUS_SUCCESS 0 129#define BRCMF_E_STATUS_SUCCESS 0
234#define BRCMF_E_STATUS_FAIL 1 130#define BRCMF_E_STATUS_FAIL 1
235#define BRCMF_E_STATUS_TIMEOUT 2 131#define BRCMF_E_STATUS_TIMEOUT 2
@@ -622,6 +518,8 @@ struct brcmf_pub {
622 u8 macvalue[ETH_ALEN]; 518 u8 macvalue[ETH_ALEN];
623 atomic_t pend_8021x_cnt; 519 atomic_t pend_8021x_cnt;
624 wait_queue_head_t pend_8021x_wait; 520 wait_queue_head_t pend_8021x_wait;
521
522 struct brcmf_fweh_info fweh;
625#ifdef DEBUG 523#ifdef DEBUG
626 struct dentry *dbgfs_dir; 524 struct dentry *dbgfs_dir;
627#endif 525#endif
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index 265580f5b270..a8bb5d2cc2d0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -85,7 +85,7 @@ extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
85 struct sk_buff *pkt, int prec); 85 struct sk_buff *pkt, int prec);
86 86
87/* Receive frame for delivery to OS. Callee disposes of rxp. */ 87/* Receive frame for delivery to OS. Callee disposes of rxp. */
88extern void brcmf_rx_frame(struct device *dev, int ifidx, 88extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
89 struct sk_buff_head *rxlist); 89 struct sk_buff_head *rxlist);
90static inline void brcmf_rx_packet(struct device *dev, int ifidx, 90static inline void brcmf_rx_packet(struct device *dev, int ifidx,
91 struct sk_buff *pkt) 91 struct sk_buff *pkt)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
index 3b311393f04a..3d59332238a2 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
@@ -118,405 +118,6 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
118 return p != NULL; 118 return p != NULL;
119} 119}
120 120
121#ifdef DEBUG
122static void
123brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
124{
125 uint i, status, reason;
126 bool group = false, flush_txq = false, link = false;
127 char *auth_str, *event_name;
128 unsigned char *buf;
129 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
130 static struct {
131 uint event;
132 char *event_name;
133 } event_names[] = {
134 {
135 BRCMF_E_SET_SSID, "SET_SSID"}, {
136 BRCMF_E_JOIN, "JOIN"}, {
137 BRCMF_E_START, "START"}, {
138 BRCMF_E_AUTH, "AUTH"}, {
139 BRCMF_E_AUTH_IND, "AUTH_IND"}, {
140 BRCMF_E_DEAUTH, "DEAUTH"}, {
141 BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, {
142 BRCMF_E_ASSOC, "ASSOC"}, {
143 BRCMF_E_ASSOC_IND, "ASSOC_IND"}, {
144 BRCMF_E_REASSOC, "REASSOC"}, {
145 BRCMF_E_REASSOC_IND, "REASSOC_IND"}, {
146 BRCMF_E_DISASSOC, "DISASSOC"}, {
147 BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, {
148 BRCMF_E_QUIET_START, "START_QUIET"}, {
149 BRCMF_E_QUIET_END, "END_QUIET"}, {
150 BRCMF_E_BEACON_RX, "BEACON_RX"}, {
151 BRCMF_E_LINK, "LINK"}, {
152 BRCMF_E_MIC_ERROR, "MIC_ERROR"}, {
153 BRCMF_E_NDIS_LINK, "NDIS_LINK"}, {
154 BRCMF_E_ROAM, "ROAM"}, {
155 BRCMF_E_TXFAIL, "TXFAIL"}, {
156 BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, {
157 BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
158 BRCMF_E_PRUNE, "PRUNE"}, {
159 BRCMF_E_AUTOAUTH, "AUTOAUTH"}, {
160 BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, {
161 BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
162 BRCMF_E_ADDTS_IND, "ADDTS_IND"}, {
163 BRCMF_E_DELTS_IND, "DELTS_IND"}, {
164 BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, {
165 BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, {
166 BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
167 BRCMF_E_ROAM_PREP, "ROAM_PREP"}, {
168 BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
169 BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
170 BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
171 BRCMF_E_JOIN_START, "JOIN_START"}, {
172 BRCMF_E_ROAM_START, "ROAM_START"}, {
173 BRCMF_E_ASSOC_START, "ASSOC_START"}, {
174 BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
175 BRCMF_E_RADIO, "RADIO"}, {
176 BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
177 BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
178 BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
179 BRCMF_E_PSK_SUP, "PSK_SUP"}, {
180 BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
181 BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
182 BRCMF_E_ICV_ERROR, "ICV_ERROR"}, {
183 BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
184 BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
185 BRCMF_E_TRACE, "TRACE"}, {
186 BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, {
187 BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
188 BRCMF_E_IF, "IF"}, {
189 BRCMF_E_RSSI, "RSSI"}, {
190 BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
191 BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT"}
192 };
193 uint event_type, flags, auth_type, datalen;
194 static u32 seqnum_prev;
195 struct msgtrace_hdr hdr;
196 u32 nblost;
197 char *s, *p;
198
199 event_type = be32_to_cpu(event->event_type);
200 flags = be16_to_cpu(event->flags);
201 status = be32_to_cpu(event->status);
202 reason = be32_to_cpu(event->reason);
203 auth_type = be32_to_cpu(event->auth_type);
204 datalen = be32_to_cpu(event->datalen);
205 /* debug dump of event messages */
206 sprintf(eabuf, "%pM", event->addr);
207
208 event_name = "UNKNOWN";
209 for (i = 0; i < ARRAY_SIZE(event_names); i++) {
210 if (event_names[i].event == event_type)
211 event_name = event_names[i].event_name;
212 }
213
214 brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type);
215 brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
216 flags, status, reason, auth_type, eabuf);
217
218 if (flags & BRCMF_EVENT_MSG_LINK)
219 link = true;
220 if (flags & BRCMF_EVENT_MSG_GROUP)
221 group = true;
222 if (flags & BRCMF_EVENT_MSG_FLUSHTXQ)
223 flush_txq = true;
224
225 switch (event_type) {
226 case BRCMF_E_START:
227 case BRCMF_E_DEAUTH:
228 case BRCMF_E_DISASSOC:
229 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
230 break;
231
232 case BRCMF_E_ASSOC_IND:
233 case BRCMF_E_REASSOC_IND:
234 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
235 break;
236
237 case BRCMF_E_ASSOC:
238 case BRCMF_E_REASSOC:
239 if (status == BRCMF_E_STATUS_SUCCESS)
240 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n",
241 event_name, eabuf);
242 else if (status == BRCMF_E_STATUS_TIMEOUT)
243 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n",
244 event_name, eabuf);
245 else if (status == BRCMF_E_STATUS_FAIL)
246 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
247 event_name, eabuf, (int)reason);
248 else
249 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n",
250 event_name, eabuf, (int)status);
251 break;
252
253 case BRCMF_E_DEAUTH_IND:
254 case BRCMF_E_DISASSOC_IND:
255 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n",
256 event_name, eabuf, (int)reason);
257 break;
258
259 case BRCMF_E_AUTH:
260 case BRCMF_E_AUTH_IND:
261 if (auth_type == WLAN_AUTH_OPEN)
262 auth_str = "Open System";
263 else if (auth_type == WLAN_AUTH_SHARED_KEY)
264 auth_str = "Shared Key";
265 else {
266 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
267 auth_str = err_msg;
268 }
269 if (event_type == BRCMF_E_AUTH_IND)
270 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n",
271 event_name, eabuf, auth_str);
272 else if (status == BRCMF_E_STATUS_SUCCESS)
273 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n",
274 event_name, eabuf, auth_str);
275 else if (status == BRCMF_E_STATUS_TIMEOUT)
276 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
277 event_name, eabuf, auth_str);
278 else if (status == BRCMF_E_STATUS_FAIL) {
279 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
280 event_name, eabuf, auth_str, (int)reason);
281 }
282
283 break;
284
285 case BRCMF_E_JOIN:
286 case BRCMF_E_ROAM:
287 case BRCMF_E_SET_SSID:
288 if (status == BRCMF_E_STATUS_SUCCESS)
289 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n",
290 event_name, eabuf);
291 else if (status == BRCMF_E_STATUS_FAIL)
292 brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name);
293 else if (status == BRCMF_E_STATUS_NO_NETWORKS)
294 brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n",
295 event_name);
296 else
297 brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n",
298 event_name, (int)status);
299 break;
300
301 case BRCMF_E_BEACON_RX:
302 if (status == BRCMF_E_STATUS_SUCCESS)
303 brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name);
304 else if (status == BRCMF_E_STATUS_FAIL)
305 brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name);
306 else
307 brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n",
308 event_name, status);
309 break;
310
311 case BRCMF_E_LINK:
312 brcmf_dbg(EVENT, "MACEVENT: %s %s\n",
313 event_name, link ? "UP" : "DOWN");
314 break;
315
316 case BRCMF_E_MIC_ERROR:
317 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
318 event_name, eabuf, group, flush_txq);
319 break;
320
321 case BRCMF_E_ICV_ERROR:
322 case BRCMF_E_UNICAST_DECODE_ERROR:
323 case BRCMF_E_MULTICAST_DECODE_ERROR:
324 brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
325 break;
326
327 case BRCMF_E_TXFAIL:
328 brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf);
329 break;
330
331 case BRCMF_E_SCAN_COMPLETE:
332 case BRCMF_E_PMKID_CACHE:
333 brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
334 break;
335
336 case BRCMF_E_ESCAN_RESULT:
337 brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
338 datalen = 0;
339 break;
340
341 case BRCMF_E_PFN_NET_FOUND:
342 case BRCMF_E_PFN_NET_LOST:
343 case BRCMF_E_PFN_SCAN_COMPLETE:
344 brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name);
345 break;
346
347 case BRCMF_E_PSK_SUP:
348 case BRCMF_E_PRUNE:
349 brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n",
350 event_name, (int)status, (int)reason);
351 break;
352
353 case BRCMF_E_TRACE:
354 buf = (unsigned char *) event_data;
355 memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
356
357 if (hdr.version != MSGTRACE_VERSION) {
358 brcmf_dbg(ERROR,
359 "MACEVENT: %s [unsupported version --> brcmf"
360 " version:%d dongle version:%d]\n",
361 event_name, MSGTRACE_VERSION, hdr.version);
362 /* Reset datalen to avoid display below */
363 datalen = 0;
364 break;
365 }
366
367 /* There are 2 bytes available at the end of data */
368 *(buf + sizeof(struct msgtrace_hdr)
369 + be16_to_cpu(hdr.len)) = '\0';
370
371 if (be32_to_cpu(hdr.discarded_bytes)
372 || be32_to_cpu(hdr.discarded_printf))
373 brcmf_dbg(ERROR,
374 "WLC_E_TRACE: [Discarded traces in dongle -->"
375 " discarded_bytes %d discarded_printf %d]\n",
376 be32_to_cpu(hdr.discarded_bytes),
377 be32_to_cpu(hdr.discarded_printf));
378
379 nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
380 if (nblost > 0)
381 brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum "
382 " %d nblost %d\n", be32_to_cpu(hdr.seqnum),
383 nblost);
384 seqnum_prev = be32_to_cpu(hdr.seqnum);
385
386 /* Display the trace buffer. Advance from \n to \n to
387 * avoid display big
388 * printf (issue with Linux printk )
389 */
390 p = (char *)&buf[sizeof(struct msgtrace_hdr)];
391 while ((s = strstr(p, "\n")) != NULL) {
392 *s = '\0';
393 pr_debug("%s\n", p);
394 p = s + 1;
395 }
396 pr_debug("%s\n", p);
397
398 /* Reset datalen to avoid display below */
399 datalen = 0;
400 break;
401
402 case BRCMF_E_RSSI:
403 brcmf_dbg(EVENT, "MACEVENT: %s %d\n",
404 event_name, be32_to_cpu(*((__be32 *)event_data)));
405 break;
406
407 default:
408 brcmf_dbg(EVENT,
409 "MACEVENT: %s %d, MAC %s, status %d, reason %d, "
410 "auth %d\n", event_name, event_type, eabuf,
411 (int)status, (int)reason, (int)auth_type);
412 break;
413 }
414
415 /* show any appended data */
416 brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data");
417}
418#endif /* DEBUG */
419
420int
421brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
422 struct brcmf_event_msg *event, void **data_ptr)
423{
424 /* check whether packet is a BRCM event pkt */
425 struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
426 struct brcmf_if_event *ifevent;
427 struct brcmf_if *ifp;
428 char *event_data;
429 u32 type, status;
430 u16 flags;
431 int evlen;
432
433 if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) {
434 brcmf_dbg(ERROR, "mismatched OUI, bailing\n");
435 return -EBADE;
436 }
437
438 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
439 if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) !=
440 BCMILCP_BCM_SUBTYPE_EVENT) {
441 brcmf_dbg(ERROR, "mismatched subtype, bailing\n");
442 return -EBADE;
443 }
444
445 *data_ptr = &pvt_data[1];
446 event_data = *data_ptr;
447
448 /* memcpy since BRCM event pkt may be unaligned. */
449 memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg));
450
451 type = get_unaligned_be32(&event->event_type);
452 flags = get_unaligned_be16(&event->flags);
453 status = get_unaligned_be32(&event->status);
454 evlen = get_unaligned_be32(&event->datalen) +
455 sizeof(struct brcmf_event);
456
457 switch (type) {
458 case BRCMF_E_IF:
459 ifevent = (struct brcmf_if_event *) event_data;
460 brcmf_dbg(TRACE, "if event\n");
461
462 if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
463 if (ifevent->action == BRCMF_E_IF_ADD) {
464 ifp = brcmf_add_if(drvr->dev, ifevent->ifidx,
465 ifevent->bssidx,
466 event->ifname,
467 pvt_data->eth.h_dest);
468 if (IS_ERR(ifp))
469 return PTR_ERR(ifp);
470 brcmf_net_attach(ifp);
471 } else {
472 brcmf_del_if(drvr, ifevent->ifidx);
473 }
474 } else {
475 brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",
476 ifevent->ifidx, event->ifname);
477 }
478
479 /* send up the if event: btamp user needs it */
480 *ifidx = brcmf_ifname2idx(drvr, event->ifname);
481 break;
482
483 /* These are what external supplicant/authenticator wants */
484 case BRCMF_E_LINK:
485 case BRCMF_E_ASSOC_IND:
486 case BRCMF_E_REASSOC_IND:
487 case BRCMF_E_DISASSOC_IND:
488 case BRCMF_E_MIC_ERROR:
489 default:
490 /* Fall through: this should get _everything_ */
491
492 *ifidx = brcmf_ifname2idx(drvr, event->ifname);
493 brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n",
494 type, flags, status);
495
496 /* put it back to BRCMF_E_NDIS_LINK */
497 if (type == BRCMF_E_NDIS_LINK) {
498 u32 temp1;
499 __be32 temp2;
500
501 temp1 = get_unaligned_be32(&event->event_type);
502 brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n",
503 temp1);
504
505 temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK);
506 memcpy((void *)(&pvt_data->msg.event_type), &temp2,
507 sizeof(pvt_data->msg.event_type));
508 }
509 break;
510 }
511
512#ifdef DEBUG
513 if (BRCMF_EVENT_ON())
514 brcmf_c_show_host_event(event, event_data);
515#endif /* DEBUG */
516
517 return 0;
518}
519
520/* Convert user's input in hex pattern to byte-size mask */ 121/* Convert user's input in hex pattern to byte-size mask */
521static int brcmf_c_pattern_atoh(char *src, char *dst) 122static int brcmf_c_pattern_atoh(char *src, char *dst)
522{ 123{
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index c2cd28e20d53..60907decca9d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -294,33 +294,13 @@ void brcmf_txflowblock(struct device *dev, bool state)
294 } 294 }
295} 295}
296 296
297static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx, 297void brcmf_rx_frame(struct device *dev, u8 ifidx,
298 void *pktdata, struct brcmf_event_msg *event,
299 void **data)
300{
301 int bcmerror = 0;
302
303 bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data);
304 if (bcmerror != 0)
305 return bcmerror;
306
307 /* only forward if interface has netdev */
308 if (drvr->iflist[*ifidx]->ndev)
309 brcmf_cfg80211_event(drvr->iflist[*ifidx],
310 event, *data);
311
312 return bcmerror;
313}
314
315void brcmf_rx_frame(struct device *dev, int ifidx,
316 struct sk_buff_head *skb_list) 298 struct sk_buff_head *skb_list)
317{ 299{
318 unsigned char *eth; 300 unsigned char *eth;
319 uint len; 301 uint len;
320 void *data;
321 struct sk_buff *skb, *pnext; 302 struct sk_buff *skb, *pnext;
322 struct brcmf_if *ifp; 303 struct brcmf_if *ifp;
323 struct brcmf_event_msg event;
324 struct brcmf_bus *bus_if = dev_get_drvdata(dev); 304 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
325 struct brcmf_pub *drvr = bus_if->drvr; 305 struct brcmf_pub *drvr = bus_if->drvr;
326 306
@@ -367,10 +347,7 @@ void brcmf_rx_frame(struct device *dev, int ifidx,
367 skb_pull(skb, ETH_HLEN); 347 skb_pull(skb, ETH_HLEN);
368 348
369 /* Process special event packets and then discard them */ 349 /* Process special event packets and then discard them */
370 if (ntohs(skb->protocol) == ETH_P_LINK_CTL) 350 brcmf_fweh_process_skb(drvr, skb, &ifidx);
371 brcmf_host_event(drvr, &ifidx,
372 skb_mac_header(skb),
373 &event, &data);
374 351
375 if (drvr->iflist[ifidx]) { 352 if (drvr->iflist[ifidx]) {
376 ifp = drvr->iflist[ifidx]; 353 ifp = drvr->iflist[ifidx];
@@ -823,6 +800,9 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
823 goto fail; 800 goto fail;
824 } 801 }
825 802
803 /* attach firmware event handler */
804 brcmf_fweh_attach(drvr);
805
826 INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address); 806 INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
827 INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list); 807 INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
828 808
@@ -873,10 +853,14 @@ int brcmf_bus_start(struct device *dev)
873 goto fail; 853 goto fail;
874 } 854 }
875 855
856 ret = brcmf_fweh_activate_events(ifp);
857 if (ret < 0)
858 goto fail;
859
876 ret = brcmf_net_attach(ifp); 860 ret = brcmf_net_attach(ifp);
877fail: 861fail:
878 if (ret < 0) { 862 if (ret < 0) {
879 brcmf_dbg(ERROR, "brcmf_net_attach failed"); 863 brcmf_dbg(ERROR, "failed: %d\n", ret);
880 if (drvr->config) 864 if (drvr->config)
881 brcmf_cfg80211_detach(drvr->config); 865 brcmf_cfg80211_detach(drvr->config);
882 free_netdev(drvr->iflist[0]->ndev); 866 free_netdev(drvr->iflist[0]->ndev);
@@ -911,6 +895,9 @@ void brcmf_detach(struct device *dev)
911 if (drvr == NULL) 895 if (drvr == NULL)
912 return; 896 return;
913 897
898 /* stop firmware event handling */
899 brcmf_fweh_detach(drvr);
900
914 /* make sure primary interface removed last */ 901 /* make sure primary interface removed last */
915 for (i = BRCMF_MAX_IFS-1; i > -1; i--) 902 for (i = BRCMF_MAX_IFS-1; i > -1; i--)
916 if (drvr->iflist[i]) 903 if (drvr->iflist[i])
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
new file mode 100644
index 000000000000..c091c125dd56
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -0,0 +1,498 @@
1/*
2 * Copyright (c) 2012 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#include <linux/netdevice.h>
17
18#include "defs.h"
19#include "brcmu_wifi.h"
20#include "brcmu_utils.h"
21
22#include "dhd.h"
23#include "dhd_dbg.h"
24#include "fweh.h"
25#include "fwil.h"
26
27/**
28 * struct brcm_ethhdr - broadcom specific ether header.
29 *
30 * @subtype: subtype for this packet.
31 * @length: TODO: length of appended data.
32 * @version: version indication.
33 * @oui: OUI of this packet.
34 * @usr_subtype: subtype for this OUI.
35 */
36struct brcm_ethhdr {
37 __be16 subtype;
38 __be16 length;
39 u8 version;
40 u8 oui[3];
41 __be16 usr_subtype;
42} __packed;
43
44struct brcmf_event_msg_be {
45 __be16 version;
46 __be16 flags;
47 __be32 event_type;
48 __be32 status;
49 __be32 reason;
50 __be32 auth_type;
51 __be32 datalen;
52 u8 addr[ETH_ALEN];
53 char ifname[IFNAMSIZ];
54 u8 ifidx;
55 u8 bsscfgidx;
56} __packed;
57
58/**
59 * struct brcmf_event - contents of broadcom event packet.
60 *
61 * @eth: standard ether header.
62 * @hdr: broadcom specific ether header.
63 * @msg: common part of the actual event message.
64 */
65struct brcmf_event {
66 struct ethhdr eth;
67 struct brcm_ethhdr hdr;
68 struct brcmf_event_msg_be msg;
69} __packed;
70
71/**
72 * struct brcmf_fweh_queue_item - event item on event queue.
73 *
74 * @q: list element for queuing.
75 * @code: event code.
76 * @ifidx: interface index related to this event.
77 * @ifaddr: ethernet address for interface.
78 * @emsg: common parameters of the firmware event message.
79 * @data: event specific data part of the firmware event.
80 */
81struct brcmf_fweh_queue_item {
82 struct list_head q;
83 enum brcmf_fweh_event_code code;
84 u8 ifidx;
85 u8 ifaddr[ETH_ALEN];
86 struct brcmf_event_msg_be emsg;
87 u8 data[0];
88};
89
90/**
91 * struct brcmf_fweh_event_name - code, name mapping entry.
92 */
93struct brcmf_fweh_event_name {
94 enum brcmf_fweh_event_code code;
95 const char *name;
96};
97
98#ifdef DEBUG
99/* array for mapping code to event name */
100static struct brcmf_fweh_event_name fweh_event_names[] = {
101 { BRCMF_E_SET_SSID, "SET_SSID" },
102 { BRCMF_E_JOIN, "JOIN" },
103 { BRCMF_E_START, "START" },
104 { BRCMF_E_AUTH, "AUTH" },
105 { BRCMF_E_AUTH_IND, "AUTH_IND" },
106 { BRCMF_E_DEAUTH, "DEAUTH" },
107 { BRCMF_E_DEAUTH_IND, "DEAUTH_IND" },
108 { BRCMF_E_ASSOC, "ASSOC" },
109 { BRCMF_E_ASSOC_IND, "ASSOC_IND" },
110 { BRCMF_E_REASSOC, "REASSOC" },
111 { BRCMF_E_REASSOC_IND, "REASSOC_IND" },
112 { BRCMF_E_DISASSOC, "DISASSOC" },
113 { BRCMF_E_DISASSOC_IND, "DISASSOC_IND" },
114 { BRCMF_E_QUIET_START, "START_QUIET" },
115 { BRCMF_E_QUIET_END, "END_QUIET" },
116 { BRCMF_E_BEACON_RX, "BEACON_RX" },
117 { BRCMF_E_LINK, "LINK" },
118 { BRCMF_E_MIC_ERROR, "MIC_ERROR" },
119 { BRCMF_E_NDIS_LINK, "NDIS_LINK" },
120 { BRCMF_E_ROAM, "ROAM" },
121 { BRCMF_E_TXFAIL, "TXFAIL" },
122 { BRCMF_E_PMKID_CACHE, "PMKID_CACHE" },
123 { BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF" },
124 { BRCMF_E_PRUNE, "PRUNE" },
125 { BRCMF_E_AUTOAUTH, "AUTOAUTH" },
126 { BRCMF_E_EAPOL_MSG, "EAPOL_MSG" },
127 { BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE" },
128 { BRCMF_E_ADDTS_IND, "ADDTS_IND" },
129 { BRCMF_E_DELTS_IND, "DELTS_IND" },
130 { BRCMF_E_BCNSENT_IND, "BCNSENT_IND" },
131 { BRCMF_E_BCNRX_MSG, "BCNRX_MSG" },
132 { BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG" },
133 { BRCMF_E_ROAM_PREP, "ROAM_PREP" },
134 { BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND" },
135 { BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST" },
136 { BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE" },
137 { BRCMF_E_JOIN_START, "JOIN_START" },
138 { BRCMF_E_ROAM_START, "ROAM_START" },
139 { BRCMF_E_ASSOC_START, "ASSOC_START" },
140 { BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC" },
141 { BRCMF_E_RADIO, "RADIO" },
142 { BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG" },
143 { BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG" },
144 { BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" },
145 { BRCMF_E_PSK_SUP, "PSK_SUP" },
146 { BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED" },
147 { BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" },
148 { BRCMF_E_ICV_ERROR, "ICV_ERROR" },
149 { BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" },
150 { BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" },
151 { BRCMF_E_TRACE, "TRACE" },
152 { BRCMF_E_IF, "IF" },
153 { BRCMF_E_RSSI, "RSSI" },
154 { BRCMF_E_PFN_SCAN_COMPLETE, "PFN_SCAN_COMPLETE" },
155 { BRCMF_E_EXTLOG_MSG, "EXTLOG_MSG" },
156 { BRCMF_E_ACTION_FRAME, "ACTION_FRAME" },
157 { BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" },
158 { BRCMF_E_PRE_ASSOC_IND, "PRE_ASSOC_IND" },
159 { BRCMF_E_PRE_REASSOC_IND, "PRE_REASSOC_IND" },
160 { BRCMF_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" },
161 { BRCMF_E_AP_STARTED, "AP_STARTED" },
162 { BRCMF_E_DFS_AP_STOP, "DFS_AP_STOP" },
163 { BRCMF_E_DFS_AP_RESUME, "DFS_AP_RESUME" },
164 { BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT" },
165 { BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "ACTION_FRM_OFF_CHAN_CMPLT" },
166 { BRCMF_E_DCS_REQUEST, "DCS_REQUEST" },
167 { BRCMF_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP"}
168};
169
170/**
171 * brcmf_fweh_event_name() - returns name for given event code.
172 *
173 * @code: code to lookup.
174 */
175static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
176{
177 int i;
178 for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) {
179 if (fweh_event_names[i].code == code)
180 return fweh_event_names[i].name;
181 }
182 return "unknown";
183}
184#else
185static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
186{
187 return "nodebug";
188}
189#endif
190
191/**
192 * brcmf_fweh_queue_event() - create and queue event.
193 *
194 * @ifp: firmware interface object.
195 * @code: event code.
196 * @pkt: event ether packet.
197 */
198static void brcmf_fweh_queue_event(struct brcmf_if *ifp,
199 enum brcmf_fweh_event_code code,
200 struct brcmf_event *pkt)
201{
202 struct brcmf_fweh_info *fweh = &ifp->drvr->fweh;
203 struct brcmf_fweh_queue_item *event;
204 gfp_t alloc_flag = GFP_KERNEL;
205 ulong flags;
206 void *data;
207 u32 datalen;
208
209 /* determine event data */
210 datalen = get_unaligned_be32(&pkt->msg.datalen);
211 data = &pkt[1];
212
213 if (!ifp->ndev || (code != BRCMF_E_IF && !fweh->evt_handler[code])) {
214 brcmf_dbg(EVENT, "event ignored: code=%d\n", code);
215 brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), data, datalen, "event:");
216 return;
217 }
218
219 if (in_interrupt())
220 alloc_flag = GFP_ATOMIC;
221
222 event = kzalloc(sizeof(*event) + datalen, alloc_flag);
223 event->code = code;
224 event->ifidx = ifp->idx;
225
226 /* use memcpy to get aligned event message */
227 memcpy(&event->emsg, &pkt->msg, sizeof(event->emsg));
228 memcpy(event->data, data, datalen);
229 memcpy(event->ifaddr, pkt->eth.h_dest, ETH_ALEN);
230
231 spin_lock_irqsave(&fweh->evt_q_lock, flags);
232 list_add_tail(&event->q, &fweh->event_q);
233 spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
234 schedule_work(&fweh->event_work);
235}
236
237/**
238 * brcmf_fweh_process_if_event() - handle IF event.
239 *
240 * @drvr: driver information object.
241 * @item: queue entry.
242 * @ifpp: interface object (may change upon ADD action).
243 */
244static int brcmf_fweh_process_if_event(struct brcmf_pub *drvr,
245 struct brcmf_fweh_queue_item *item,
246 struct brcmf_if **ifpp)
247{
248 struct brcmf_event_msg_be *event = &item->emsg;
249 struct brcmf_if_event *ifevent = (struct brcmf_if_event *)item->data;
250 struct brcmf_if *ifp;
251 int err = 0;
252
253 brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n",
254 ifevent->action, ifevent->ifidx,
255 ifevent->bssidx, ifevent->flags);
256
257 if (ifevent->ifidx >= BRCMF_MAX_IFS) {
258 brcmf_dbg(ERROR, "invalid interface index: %u\n",
259 ifevent->ifidx);
260 return -EINVAL;
261 }
262
263 switch (ifevent->action) {
264 case BRCMF_E_IF_ADD:
265 brcmf_dbg(EVENT, "adding %s (%pM, %pM)\n", event->ifname,
266 event->addr, item->ifaddr);
267 ifp = brcmf_add_if(drvr->dev, ifevent->ifidx, ifevent->bssidx,
268 event->ifname, item->ifaddr);
269 if (!IS_ERR(ifp)) {
270 *ifpp = ifp;
271 err = brcmf_net_attach(ifp);
272 } else {
273 err = PTR_ERR(ifp);
274 }
275 break;
276 case BRCMF_E_IF_DEL:
277 brcmf_del_if(drvr, ifevent->ifidx);
278 break;
279 case BRCMF_E_IF_CHANGE:
280 /* nothing to do here */
281 break;
282 default:
283 brcmf_dbg(ERROR, "unknown event action: %u\n", ifevent->action);
284 err = -EBADE;
285 break;
286 }
287 return err;
288}
289
290/**
291 * brcmf_fweh_dequeue_event() - get event from the queue.
292 *
293 * @fweh: firmware event handling info.
294 */
295static struct brcmf_fweh_queue_item *
296brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh)
297{
298 struct brcmf_fweh_queue_item *event = NULL;
299 ulong flags;
300
301 spin_lock_irqsave(&fweh->evt_q_lock, flags);
302 if (!list_empty(&fweh->event_q)) {
303 event = list_first_entry(&fweh->event_q,
304 struct brcmf_fweh_queue_item, q);
305 list_del(&event->q);
306 }
307 spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
308
309 return event;
310}
311
312/**
313 * brcmf_fweh_event_worker() - firmware event worker.
314 *
315 * @work: worker object.
316 */
317static void brcmf_fweh_event_worker(struct work_struct *work)
318{
319 struct brcmf_pub *drvr;
320 struct brcmf_if *ifp;
321 struct brcmf_fweh_info *fweh;
322 struct brcmf_fweh_queue_item *event;
323 int err = 0;
324 struct brcmf_event_msg_be *emsg_be;
325 struct brcmf_event_msg emsg;
326
327 fweh = container_of(work, struct brcmf_fweh_info, event_work);
328 drvr = container_of(fweh, struct brcmf_pub, fweh);
329
330 while ((event = brcmf_fweh_dequeue_event(fweh))) {
331 ifp = drvr->iflist[event->ifidx];
332
333 brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM:\n",
334 brcmf_fweh_event_name(event->code), event->code,
335 event->emsg.ifidx, event->emsg.bsscfgidx,
336 event->emsg.addr);
337
338 /* handle interface event */
339 if (event->code == BRCMF_E_IF) {
340 err = brcmf_fweh_process_if_event(drvr, event, &ifp);
341 if (err)
342 goto event_free;
343 }
344
345 /* convert event message */
346 emsg_be = &event->emsg;
347 emsg.version = be16_to_cpu(emsg_be->version);
348 emsg.flags = be16_to_cpu(emsg_be->flags);
349 emsg.event_code = event->code;
350 emsg.status = be32_to_cpu(emsg_be->status);
351 emsg.reason = be32_to_cpu(emsg_be->reason);
352 emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
353 emsg.datalen = be32_to_cpu(emsg_be->datalen);
354 memcpy(emsg.addr, emsg_be->addr, ETH_ALEN);
355 memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname));
356 emsg.ifidx = emsg_be->ifidx;
357 emsg.bsscfgidx = emsg_be->bsscfgidx;
358
359 brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n",
360 emsg.version, emsg.flags, emsg.status, emsg.reason);
361 brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
362 min_t(u32, emsg.datalen, 64),
363 "appended:");
364
365 /* handle the event if valid interface and handler */
366 if (ifp->ndev && fweh->evt_handler[event->code])
367 err = fweh->evt_handler[event->code](ifp, &emsg,
368 event->data);
369 else
370 brcmf_dbg(ERROR, "unhandled event %d ignored\n",
371 event->code);
372 if (err) {
373 brcmf_dbg(ERROR, "event handler failed (%d)\n",
374 event->code);
375 err = 0;
376 }
377event_free:
378 kfree(event);
379 }
380}
381
382/**
383 * brcmf_fweh_attach() - initialize firmware event handling.
384 *
385 * @drvr: driver information object.
386 */
387void brcmf_fweh_attach(struct brcmf_pub *drvr)
388{
389 struct brcmf_fweh_info *fweh = &drvr->fweh;
390 INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
391 spin_lock_init(&fweh->evt_q_lock);
392 INIT_LIST_HEAD(&fweh->event_q);
393}
394
395/**
396 * brcmf_fweh_detach() - cleanup firmware event handling.
397 *
398 * @drvr: driver information object.
399 */
400void brcmf_fweh_detach(struct brcmf_pub *drvr)
401{
402 struct brcmf_fweh_info *fweh = &drvr->fweh;
403 struct brcmf_if *ifp = drvr->iflist[0];
404 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
405
406 /* clear all events */
407 memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN);
408 (void)brcmf_fil_iovar_data_set(ifp, "event_msgs",
409 eventmask, BRCMF_EVENTING_MASK_LEN);
410
411 /* cancel the worker */
412 cancel_work_sync(&fweh->event_work);
413 WARN_ON(!list_empty(&fweh->event_q));
414 memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
415}
416
417/**
418 * brcmf_fweh_register() - register handler for given event code.
419 *
420 * @drvr: driver information object.
421 * @code: event code.
422 * @handler: handler for the given event code.
423 */
424int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
425 brcmf_fweh_handler_t handler)
426{
427 if (drvr->fweh.evt_handler[code]) {
428 brcmf_dbg(ERROR, "event code %d already registered\n", code);
429 return -ENOSPC;
430 }
431 drvr->fweh.evt_handler[code] = handler;
432 brcmf_dbg(TRACE, "event handler registered for code %d\n", code);
433 return 0;
434}
435
436/**
437 * brcmf_fweh_unregister() - remove handler for given code.
438 *
439 * @drvr: driver information object.
440 * @code: event code.
441 */
442void brcmf_fweh_unregister(struct brcmf_pub *drvr,
443 enum brcmf_fweh_event_code code)
444{
445 brcmf_dbg(TRACE, "event handler cleared for code %d\n", code);
446 drvr->fweh.evt_handler[code] = NULL;
447}
448
449/**
450 * brcmf_fweh_activate_events() - enables firmware events registered.
451 *
452 * @ifp: primary interface object.
453 */
454int brcmf_fweh_activate_events(struct brcmf_if *ifp)
455{
456 int i, err;
457 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
458
459 for (i = 0; i < BRCMF_E_LAST; i++) {
460 if (ifp->drvr->fweh.evt_handler[i]) {
461 brcmf_dbg(EVENT, "enable event %s\n",
462 brcmf_fweh_event_name(i));
463 setbit(eventmask, i);
464 }
465 }
466
467 /* want to handle IF event as well */
468 setbit(eventmask, BRCMF_E_IF);
469
470 err = brcmf_fil_iovar_data_set(ifp, "event_msgs",
471 eventmask, BRCMF_EVENTING_MASK_LEN);
472 if (err)
473 brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err);
474
475 return err;
476}
477
478/**
479 * brcmf_fweh_process_event() - process skb as firmware event.
480 *
481 * @drvr: driver information object.
482 * @event_packet: event packet to process.
483 * @ifidx: index of the firmware interface (may change).
484 *
485 * If the packet buffer contains a firmware event message it will
486 * dispatch the event to a registered handler (using worker).
487 */
488void brcmf_fweh_process_event(struct brcmf_pub *drvr,
489 struct brcmf_event *event_packet, u8 *ifidx)
490{
491 enum brcmf_fweh_event_code code;
492
493 /* determine event code and interface index */
494 code = get_unaligned_be32(&event_packet->msg.event_type);
495 *ifidx = event_packet->msg.ifidx;
496
497 brcmf_fweh_queue_event(drvr->iflist[*ifidx], code, event_packet);
498}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
new file mode 100644
index 000000000000..13bd33355951
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
@@ -0,0 +1,207 @@
1/*
2 * Copyright (c) 2012 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17
18#ifndef FWEH_H_
19#define FWEH_H_
20
21#include <linux/unaligned/access_ok.h>
22#include <linux/skbuff.h>
23#include <linux/if_ether.h>
24#include <linux/if.h>
25
26/* formward declarations */
27struct brcmf_pub;
28struct brcmf_if;
29struct brcmf_cfg80211_info;
30struct brcmf_event;
31
32/* firmware event codes sent by the dongle */
33enum brcmf_fweh_event_code {
34 BRCMF_E_SET_SSID = 0,
35 BRCMF_E_JOIN = 1,
36 BRCMF_E_START = 2,
37 BRCMF_E_AUTH = 3,
38 BRCMF_E_AUTH_IND = 4,
39 BRCMF_E_DEAUTH = 5,
40 BRCMF_E_DEAUTH_IND = 6,
41 BRCMF_E_ASSOC = 7,
42 BRCMF_E_ASSOC_IND = 8,
43 BRCMF_E_REASSOC = 9,
44 BRCMF_E_REASSOC_IND = 10,
45 BRCMF_E_DISASSOC = 11,
46 BRCMF_E_DISASSOC_IND = 12,
47 BRCMF_E_QUIET_START = 13,
48 BRCMF_E_QUIET_END = 14,
49 BRCMF_E_BEACON_RX = 15,
50 BRCMF_E_LINK = 16,
51 BRCMF_E_MIC_ERROR = 17,
52 BRCMF_E_NDIS_LINK = 18,
53 BRCMF_E_ROAM = 19,
54 BRCMF_E_TXFAIL = 20,
55 BRCMF_E_PMKID_CACHE = 21,
56 BRCMF_E_RETROGRADE_TSF = 22,
57 BRCMF_E_PRUNE = 23,
58 BRCMF_E_AUTOAUTH = 24,
59 BRCMF_E_EAPOL_MSG = 25,
60 BRCMF_E_SCAN_COMPLETE = 26,
61 BRCMF_E_ADDTS_IND = 27,
62 BRCMF_E_DELTS_IND = 28,
63 BRCMF_E_BCNSENT_IND = 29,
64 BRCMF_E_BCNRX_MSG = 30,
65 BRCMF_E_BCNLOST_MSG = 31,
66 BRCMF_E_ROAM_PREP = 32,
67 BRCMF_E_PFN_NET_FOUND = 33,
68 BRCMF_E_PFN_NET_LOST = 34,
69 BRCMF_E_RESET_COMPLETE = 35,
70 BRCMF_E_JOIN_START = 36,
71 BRCMF_E_ROAM_START = 37,
72 BRCMF_E_ASSOC_START = 38,
73 BRCMF_E_IBSS_ASSOC = 39,
74 BRCMF_E_RADIO = 40,
75 BRCMF_E_PSM_WATCHDOG = 41,
76 BRCMF_E_PROBREQ_MSG = 44,
77 BRCMF_E_SCAN_CONFIRM_IND = 45,
78 BRCMF_E_PSK_SUP = 46,
79 BRCMF_E_COUNTRY_CODE_CHANGED = 47,
80 BRCMF_E_EXCEEDED_MEDIUM_TIME = 48,
81 BRCMF_E_ICV_ERROR = 49,
82 BRCMF_E_UNICAST_DECODE_ERROR = 50,
83 BRCMF_E_MULTICAST_DECODE_ERROR = 51,
84 BRCMF_E_TRACE = 52,
85 BRCMF_E_IF = 54,
86 BRCMF_E_RSSI = 56,
87 BRCMF_E_PFN_SCAN_COMPLETE = 57,
88 BRCMF_E_EXTLOG_MSG = 58,
89 BRCMF_E_ACTION_FRAME = 59,
90 BRCMF_E_ACTION_FRAME_COMPLETE = 60,
91 BRCMF_E_PRE_ASSOC_IND = 61,
92 BRCMF_E_PRE_REASSOC_IND = 62,
93 BRCMF_E_CHANNEL_ADOPTED = 63,
94 BRCMF_E_AP_STARTED = 64,
95 BRCMF_E_DFS_AP_STOP = 65,
96 BRCMF_E_DFS_AP_RESUME = 66,
97 BRCMF_E_ESCAN_RESULT = 69,
98 BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE = 70,
99 BRCMF_E_DCS_REQUEST = 73,
100 BRCMF_E_FIFO_CREDIT_MAP = 74,
101 BRCMF_E_LAST
102};
103
104/* flags field values in struct brcmf_event_msg */
105#define BRCMF_EVENT_MSG_LINK 0x01
106#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
107#define BRCMF_EVENT_MSG_GROUP 0x04
108
109/**
110 * definitions for event packet validation.
111 */
112#define BRCMF_EVENT_OUI_OFFSET 19
113#define BRCM_OUI "\x00\x10\x18"
114#define DOT11_OUI_LEN 3
115#define BCMILCP_BCM_SUBTYPE_EVENT 1
116
117
118/**
119 * struct brcmf_event_msg - firmware event message.
120 *
121 * @version: version information.
122 * @flags: event flags.
123 * @event_code: firmware event code.
124 * @status: status information.
125 * @reason: reason code.
126 * @auth_type: authentication type.
127 * @datalen: lenght of event data buffer.
128 * @addr: ether address.
129 * @ifname: interface name.
130 * @ifidx: interface index.
131 * @bsscfgidx: bsscfg index.
132 */
133struct brcmf_event_msg {
134 u16 version;
135 u16 flags;
136 u32 event_code;
137 u32 status;
138 u32 reason;
139 s32 auth_type;
140 u32 datalen;
141 u8 addr[ETH_ALEN];
142 char ifname[IFNAMSIZ];
143 u8 ifidx;
144 u8 bsscfgidx;
145};
146
147typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
148 const struct brcmf_event_msg *evtmsg,
149 void *data);
150
151/**
152 * struct brcmf_fweh_info - firmware event handling information.
153 *
154 * @event_work: event worker.
155 * @evt_q_lock: lock for event queue protection.
156 * @event_q: event queue.
157 * @evt_handler: registered event handlers.
158 */
159struct brcmf_fweh_info {
160 struct work_struct event_work;
161 struct spinlock evt_q_lock;
162 struct list_head event_q;
163 int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp,
164 const struct brcmf_event_msg *evtmsg,
165 void *data);
166};
167
168void brcmf_fweh_attach(struct brcmf_pub *drvr);
169void brcmf_fweh_detach(struct brcmf_pub *drvr);
170int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
171 int (*handler)(struct brcmf_if *ifp,
172 const struct brcmf_event_msg *evtmsg,
173 void *data));
174void brcmf_fweh_unregister(struct brcmf_pub *drvr,
175 enum brcmf_fweh_event_code code);
176int brcmf_fweh_activate_events(struct brcmf_if *ifp);
177void brcmf_fweh_process_event(struct brcmf_pub *drvr,
178 struct brcmf_event *event_packet, u8 *ifidx);
179
180static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
181 struct sk_buff *skb, u8 *ifidx)
182{
183 struct brcmf_event *event_packet;
184 u8 *data;
185 u16 usr_stype;
186
187 /* only process events when protocol matches */
188 if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
189 return;
190
191 /* check for BRCM oui match */
192 event_packet = (struct brcmf_event *)skb_mac_header(skb);
193 data = (u8 *)event_packet;
194 data += BRCMF_EVENT_OUI_OFFSET;
195 if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
196 return;
197
198 /* final match on usr_subtype */
199 data += DOT11_OUI_LEN;
200 usr_stype = get_unaligned_be16(data);
201 if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
202 return;
203
204 brcmf_fweh_process_event(drvr, event_packet, ifidx);
205}
206
207#endif /* FWEH_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index dab6e405a2e1..e6d2d40ad8d5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -2470,7 +2470,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
2470 u32 i; 2470 u32 i;
2471 bool aborted; 2471 bool aborted;
2472 2472
2473 status = be32_to_cpu(e->status); 2473 status = e->status;
2474 2474
2475 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { 2475 if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2476 WL_ERR("scan not ready ndev %p drv_status %x\n", ndev, 2476 WL_ERR("scan not ready ndev %p drv_status %x\n", ndev,
@@ -2551,9 +2551,8 @@ exit:
2551 2551
2552static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) 2552static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
2553{ 2553{
2554 2554 brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
2555 cfg->el.handler[BRCMF_E_ESCAN_RESULT] = 2555 brcmf_cfg80211_escan_handler);
2556 brcmf_cfg80211_escan_handler;
2557 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; 2556 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2558 /* Init scan_timeout timer */ 2557 /* Init scan_timeout timer */
2559 init_timer(&cfg->escan_timeout); 2558 init_timer(&cfg->escan_timeout);
@@ -2794,7 +2793,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
2794 2793
2795 WL_SCAN("Enter\n"); 2794 WL_SCAN("Enter\n");
2796 2795
2797 if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) { 2796 if (e->event_code == BRCMF_E_PFN_NET_LOST) {
2798 WL_SCAN("PFN NET LOST event. Do Nothing\n"); 2797 WL_SCAN("PFN NET LOST event. Do Nothing\n");
2799 return 0; 2798 return 0;
2800 } 2799 }
@@ -3859,8 +3858,8 @@ static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
3859static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, 3858static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
3860 const struct brcmf_event_msg *e) 3859 const struct brcmf_event_msg *e)
3861{ 3860{
3862 u32 event = be32_to_cpu(e->event_type); 3861 u32 event = e->event_code;
3863 u32 status = be32_to_cpu(e->status); 3862 u32 status = e->status;
3864 3863
3865 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { 3864 if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
3866 WL_CONN("Processing set ssid\n"); 3865 WL_CONN("Processing set ssid\n");
@@ -3874,8 +3873,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
3874static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, 3873static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
3875 const struct brcmf_event_msg *e) 3874 const struct brcmf_event_msg *e)
3876{ 3875{
3877 u32 event = be32_to_cpu(e->event_type); 3876 u32 event = e->event_code;
3878 u16 flags = be16_to_cpu(e->flags); 3877 u16 flags = e->flags;
3879 3878
3880 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { 3879 if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
3881 WL_CONN("Processing link down\n"); 3880 WL_CONN("Processing link down\n");
@@ -3887,13 +3886,12 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
3887static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg, 3886static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
3888 const struct brcmf_event_msg *e) 3887 const struct brcmf_event_msg *e)
3889{ 3888{
3890 u32 event = be32_to_cpu(e->event_type); 3889 u32 event = e->event_code;
3891 u32 status = be32_to_cpu(e->status); 3890 u32 status = e->status;
3892 3891
3893 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) { 3892 if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
3894 WL_CONN("Processing Link %s & no network found\n", 3893 WL_CONN("Processing Link %s & no network found\n",
3895 be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ? 3894 e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
3896 "up" : "down");
3897 return true; 3895 return true;
3898 } 3896 }
3899 3897
@@ -4081,9 +4079,9 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
4081 const struct brcmf_event_msg *e, void *data) 4079 const struct brcmf_event_msg *e, void *data)
4082{ 4080{
4083 s32 err = 0; 4081 s32 err = 0;
4084 u32 event = be32_to_cpu(e->event_type); 4082 u32 event = e->event_code;
4085 u32 reason = be32_to_cpu(e->reason); 4083 u32 reason = e->reason;
4086 u32 len = be32_to_cpu(e->datalen); 4084 u32 len = e->datalen;
4087 static int generation; 4085 static int generation;
4088 4086
4089 struct station_info sinfo; 4087 struct station_info sinfo;
@@ -4172,8 +4170,8 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp,
4172{ 4170{
4173 struct brcmf_cfg80211_info *cfg = ifp->drvr->config; 4171 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4174 s32 err = 0; 4172 s32 err = 0;
4175 u32 event = be32_to_cpu(e->event_type); 4173 u32 event = e->event_code;
4176 u32 status = be32_to_cpu(e->status); 4174 u32 status = e->status;
4177 4175
4178 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { 4176 if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
4179 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) 4177 if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
@@ -4189,7 +4187,7 @@ static s32
4189brcmf_notify_mic_status(struct brcmf_if *ifp, 4187brcmf_notify_mic_status(struct brcmf_if *ifp,
4190 const struct brcmf_event_msg *e, void *data) 4188 const struct brcmf_event_msg *e, void *data)
4191{ 4189{
4192 u16 flags = be16_to_cpu(e->flags); 4190 u16 flags = e->flags;
4193 enum nl80211_key_type key_type; 4191 enum nl80211_key_type key_type;
4194 4192
4195 if (flags & BRCMF_EVENT_MSG_GROUP) 4193 if (flags & BRCMF_EVENT_MSG_GROUP)
@@ -4213,19 +4211,28 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
4213 conf->tx_power = -1; 4211 conf->tx_power = -1;
4214} 4212}
4215 4213
4216static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) 4214static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
4217{ 4215{
4218 memset(el, 0, sizeof(*el)); 4216 brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
4219 el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; 4217 brcmf_notify_connect_status);
4220 el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status; 4218 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
4221 el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status; 4219 brcmf_notify_connect_status);
4222 el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status; 4220 brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
4223 el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status; 4221 brcmf_notify_connect_status);
4224 el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status; 4222 brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
4225 el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; 4223 brcmf_notify_connect_status);
4226 el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; 4224 brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
4227 el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; 4225 brcmf_notify_connect_status);
4228 el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results; 4226 brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
4227 brcmf_notify_connect_status);
4228 brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
4229 brcmf_notify_roaming_status);
4230 brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
4231 brcmf_notify_mic_status);
4232 brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
4233 brcmf_notify_connect_status);
4234 brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
4235 brcmf_notify_sched_scan_results);
4229} 4236}
4230 4237
4231static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) 4238static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -4263,115 +4270,6 @@ init_priv_mem_out:
4263 return -ENOMEM; 4270 return -ENOMEM;
4264} 4271}
4265 4272
4266/*
4267* retrieve first queued event from head
4268*/
4269
4270static struct brcmf_cfg80211_event_q *brcmf_deq_event(
4271 struct brcmf_cfg80211_info *cfg)
4272{
4273 struct brcmf_cfg80211_event_q *e = NULL;
4274
4275 spin_lock_irq(&cfg->evt_q_lock);
4276 if (!list_empty(&cfg->evt_q_list)) {
4277 e = list_first_entry(&cfg->evt_q_list,
4278 struct brcmf_cfg80211_event_q, evt_q_list);
4279 list_del(&e->evt_q_list);
4280 }
4281 spin_unlock_irq(&cfg->evt_q_lock);
4282
4283 return e;
4284}
4285
4286/*
4287* push event to tail of the queue
4288*
4289* remark: this function may not sleep as it is called in atomic context.
4290*/
4291
4292static s32
4293brcmf_enq_event(struct brcmf_if *ifp, u32 event,
4294 const struct brcmf_event_msg *msg, void *data)
4295{
4296 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4297 struct brcmf_cfg80211_event_q *e;
4298 s32 err = 0;
4299 ulong flags;
4300 u32 data_len;
4301 u32 total_len;
4302
4303 total_len = sizeof(struct brcmf_cfg80211_event_q);
4304 if (data)
4305 data_len = be32_to_cpu(msg->datalen);
4306 else
4307 data_len = 0;
4308 total_len += data_len;
4309 e = kzalloc(total_len, GFP_ATOMIC);
4310 if (!e)
4311 return -ENOMEM;
4312
4313 e->etype = event;
4314 e->ifp = ifp;
4315 memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
4316 if (data)
4317 memcpy(&e->edata, data, data_len);
4318
4319 spin_lock_irqsave(&cfg->evt_q_lock, flags);
4320 list_add_tail(&e->evt_q_list, &cfg->evt_q_list);
4321 spin_unlock_irqrestore(&cfg->evt_q_lock, flags);
4322
4323 return err;
4324}
4325
4326static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
4327{
4328 kfree(e);
4329}
4330
4331static void brcmf_cfg80211_event_handler(struct work_struct *work)
4332{
4333 struct brcmf_cfg80211_info *cfg =
4334 container_of(work, struct brcmf_cfg80211_info,
4335 event_work);
4336 struct brcmf_cfg80211_event_q *e;
4337
4338 e = brcmf_deq_event(cfg);
4339 if (unlikely(!e)) {
4340 WL_ERR("event queue empty...\n");
4341 return;
4342 }
4343
4344 do {
4345 WL_INFO("event type (%d)\n", e->etype);
4346 if (cfg->el.handler[e->etype])
4347 cfg->el.handler[e->etype](e->ifp, &e->emsg, e->edata);
4348 else
4349 WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
4350 brcmf_put_event(e);
4351 } while ((e = brcmf_deq_event(cfg)));
4352
4353}
4354
4355static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg)
4356{
4357 spin_lock_init(&cfg->evt_q_lock);
4358 INIT_LIST_HEAD(&cfg->evt_q_list);
4359}
4360
4361static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg)
4362{
4363 struct brcmf_cfg80211_event_q *e;
4364
4365 spin_lock_irq(&cfg->evt_q_lock);
4366 while (!list_empty(&cfg->evt_q_list)) {
4367 e = list_first_entry(&cfg->evt_q_list,
4368 struct brcmf_cfg80211_event_q, evt_q_list);
4369 list_del(&e->evt_q_list);
4370 kfree(e);
4371 }
4372 spin_unlock_irq(&cfg->evt_q_lock);
4373}
4374
4375static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) 4273static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
4376{ 4274{
4377 s32 err = 0; 4275 s32 err = 0;
@@ -4383,12 +4281,10 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
4383 cfg->active_scan = true; /* we do active scan for 4281 cfg->active_scan = true; /* we do active scan for
4384 specific scan per default */ 4282 specific scan per default */
4385 cfg->dongle_up = false; /* dongle is not up yet */ 4283 cfg->dongle_up = false; /* dongle is not up yet */
4386 brcmf_init_eq(cfg);
4387 err = brcmf_init_priv_mem(cfg); 4284 err = brcmf_init_priv_mem(cfg);
4388 if (err) 4285 if (err)
4389 return err; 4286 return err;
4390 INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler); 4287 brcmf_register_event_handlers(cfg);
4391 brcmf_init_eloop_handler(&cfg->el);
4392 mutex_init(&cfg->usr_sync); 4288 mutex_init(&cfg->usr_sync);
4393 brcmf_init_escan(cfg); 4289 brcmf_init_escan(cfg);
4394 brcmf_init_conf(cfg->conf); 4290 brcmf_init_conf(cfg->conf);
@@ -4399,9 +4295,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
4399 4295
4400static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) 4296static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
4401{ 4297{
4402 cancel_work_sync(&cfg->event_work);
4403 cfg->dongle_up = false; /* dongle down */ 4298 cfg->dongle_up = false; /* dongle down */
4404 brcmf_flush_eq(cfg);
4405 brcmf_link_down(cfg); 4299 brcmf_link_down(cfg);
4406 brcmf_abort_scanning(cfg); 4300 brcmf_abort_scanning(cfg);
4407 brcmf_deinit_priv_mem(cfg); 4301 brcmf_deinit_priv_mem(cfg);
@@ -4463,64 +4357,6 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
4463 } 4357 }
4464} 4358}
4465 4359
4466void brcmf_cfg80211_event(struct brcmf_if *ifp,
4467 const struct brcmf_event_msg *e, void *data)
4468{
4469 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4470 u32 event_type = be32_to_cpu(e->event_type);
4471
4472 if (!brcmf_enq_event(ifp, event_type, e, data))
4473 schedule_work(&cfg->event_work);
4474}
4475
4476static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
4477{
4478 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
4479 s32 err = 0;
4480
4481 WL_TRACE("Enter\n");
4482
4483 /* Setup event_msgs */
4484 err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
4485 eventmask, BRCMF_EVENTING_MASK_LEN);
4486 if (err) {
4487 WL_ERR("Get event_msgs error (%d)\n", err);
4488 goto dongle_eventmsg_out;
4489 }
4490
4491 setbit(eventmask, BRCMF_E_SET_SSID);
4492 setbit(eventmask, BRCMF_E_ROAM);
4493 setbit(eventmask, BRCMF_E_PRUNE);
4494 setbit(eventmask, BRCMF_E_AUTH);
4495 setbit(eventmask, BRCMF_E_REASSOC);
4496 setbit(eventmask, BRCMF_E_REASSOC_IND);
4497 setbit(eventmask, BRCMF_E_DEAUTH_IND);
4498 setbit(eventmask, BRCMF_E_DISASSOC_IND);
4499 setbit(eventmask, BRCMF_E_DISASSOC);
4500 setbit(eventmask, BRCMF_E_JOIN);
4501 setbit(eventmask, BRCMF_E_ASSOC_IND);
4502 setbit(eventmask, BRCMF_E_PSK_SUP);
4503 setbit(eventmask, BRCMF_E_LINK);
4504 setbit(eventmask, BRCMF_E_NDIS_LINK);
4505 setbit(eventmask, BRCMF_E_MIC_ERROR);
4506 setbit(eventmask, BRCMF_E_PMKID_CACHE);
4507 setbit(eventmask, BRCMF_E_TXFAIL);
4508 setbit(eventmask, BRCMF_E_JOIN_START);
4509 setbit(eventmask, BRCMF_E_ESCAN_RESULT);
4510 setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
4511
4512 err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
4513 eventmask, BRCMF_EVENTING_MASK_LEN);
4514 if (err) {
4515 WL_ERR("Set event_msgs error (%d)\n", err);
4516 goto dongle_eventmsg_out;
4517 }
4518
4519dongle_eventmsg_out:
4520 WL_TRACE("Exit\n");
4521 return err;
4522}
4523
4524static s32 4360static s32
4525brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) 4361brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
4526{ 4362{
@@ -4660,10 +4496,6 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
4660 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, 4496 brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
4661 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); 4497 WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
4662 4498
4663 err = brcmf_dongle_eventmsg(ndev);
4664 if (err)
4665 goto default_conf_out;
4666
4667 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; 4499 power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
4668 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM, 4500 err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
4669 power_mode); 4501 power_mode);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index 399925d32e47..80ba2ea378e4 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -226,25 +226,6 @@ struct brcmf_cfg80211_vif {
226 struct list_head list; 226 struct list_head list;
227}; 227};
228 228
229/* forward declaration */
230struct brcmf_cfg80211_info;
231
232/* cfg80211 main event loop */
233struct brcmf_cfg80211_event_loop {
234 s32(*handler[BRCMF_E_LAST]) (struct brcmf_if *ifp,
235 const struct brcmf_event_msg *e,
236 void *data);
237};
238
239/* event queue for cfg80211 main event */
240struct brcmf_cfg80211_event_q {
241 struct list_head evt_q_list;
242 u32 etype;
243 struct brcmf_if *ifp;
244 struct brcmf_event_msg emsg;
245 s8 edata[1];
246};
247
248/* association inform */ 229/* association inform */
249struct brcmf_cfg80211_connect_info { 230struct brcmf_cfg80211_connect_info {
250 u8 *req_ie; 231 u8 *req_ie;
@@ -365,9 +346,6 @@ struct brcmf_pno_scanresults_le {
365 * @wiphy: wiphy object for cfg80211 interface. 346 * @wiphy: wiphy object for cfg80211 interface.
366 * @conf: dongle configuration. 347 * @conf: dongle configuration.
367 * @scan_request: cfg80211 scan request object. 348 * @scan_request: cfg80211 scan request object.
368 * @el: main event loop.
369 * @evt_q_list: used for event queue.
370 * @evt_q_lock: for event queue synchronization.
371 * @usr_sync: mainly for dongle up/down synchronization. 349 * @usr_sync: mainly for dongle up/down synchronization.
372 * @bss_list: bss_list holding scanned ap information. 350 * @bss_list: bss_list holding scanned ap information.
373 * @scan_req_int: internal scan request object. 351 * @scan_req_int: internal scan request object.
@@ -375,7 +353,6 @@ struct brcmf_pno_scanresults_le {
375 * @ie: information element object for internal purpose. 353 * @ie: information element object for internal purpose.
376 * @conn_info: association info. 354 * @conn_info: association info.
377 * @pmk_list: wpa2 pmk list. 355 * @pmk_list: wpa2 pmk list.
378 * @event_work: event handler work struct.
379 * @scan_status: scan activity on the dongle. 356 * @scan_status: scan activity on the dongle.
380 * @pub: common driver information. 357 * @pub: common driver information.
381 * @channel: current channel. 358 * @channel: current channel.
@@ -401,9 +378,6 @@ struct brcmf_cfg80211_info {
401 struct wiphy *wiphy; 378 struct wiphy *wiphy;
402 struct brcmf_cfg80211_conf *conf; 379 struct brcmf_cfg80211_conf *conf;
403 struct cfg80211_scan_request *scan_request; 380 struct cfg80211_scan_request *scan_request;
404 struct brcmf_cfg80211_event_loop el;
405 struct list_head evt_q_list;
406 spinlock_t evt_q_lock;
407 struct mutex usr_sync; 381 struct mutex usr_sync;
408 struct brcmf_scan_results *bss_list; 382 struct brcmf_scan_results *bss_list;
409 struct brcmf_cfg80211_scan_req scan_req_int; 383 struct brcmf_cfg80211_scan_req scan_req_int;
@@ -411,7 +385,6 @@ struct brcmf_cfg80211_info {
411 struct brcmf_cfg80211_ie ie; 385 struct brcmf_cfg80211_ie ie;
412 struct brcmf_cfg80211_connect_info conn_info; 386 struct brcmf_cfg80211_connect_info conn_info;
413 struct brcmf_cfg80211_pmk_list *pmk_list; 387 struct brcmf_cfg80211_pmk_list *pmk_list;
414 struct work_struct event_work;
415 unsigned long scan_status; 388 unsigned long scan_status;
416 struct brcmf_pub *pub; 389 struct brcmf_pub *pub;
417 u32 channel; 390 u32 channel;
@@ -482,10 +455,6 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
482 455
483struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr); 456struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);
484void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); 457void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
485
486/* event handler from dongle */
487void brcmf_cfg80211_event(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
488 void *data);
489s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg); 458s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg);
490s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg); 459s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg);
491 460