Staging: IIO: DDS: AD9833 / AD9834 driver
[linux-2.6-block.git] / drivers / staging / brcm80211 / sys / wl_mac80211.c
CommitLineData
a9533e7e
HP
1/*
2 * Copyright (c) 2010 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#define __UNDEF_NO_VERSION__
18
a9533e7e 19#include <linux/kernel.h>
a9533e7e 20#include <linux/etherdevice.h>
a9533e7e 21#include <linux/string.h>
a9533e7e 22#include <linux/pci_ids.h>
a1c16ed2 23#include <bcmdefs.h>
c6ac24e9
BR
24#include <linux/module.h>
25#include <linux/pci.h>
26#include <linux/sched.h>
a1c16ed2 27#include <osl.h>
a9533e7e
HP
28#define WLC_MAXBSSCFG 1 /* single BSS configs */
29
a9533e7e
HP
30#include <wlc_cfg.h>
31#include <net/mac80211.h>
a9533e7e 32#include <phy_version.h>
a9533e7e
HP
33#include <bcmutils.h>
34#include <pcicfg.h>
35#include <wlioctl.h>
36#include <wlc_key.h>
a52ba66c
BR
37#include <sbhndpio.h>
38#include <sbhnddma.h>
a9533e7e
HP
39#include <wlc_channel.h>
40#include <wlc_pub.h>
41#include <wlc_scb.h>
42#include <wl_dbg.h>
a9533e7e 43#include <wl_export.h>
a9533e7e
HP
44
45#include <wl_mac80211.h>
46#include <linux/firmware.h>
a9533e7e
HP
47#include <wl_ucode.h>
48#include <d11ucode_ext.h>
a9533e7e 49
a9533e7e 50
3deea904 51static void wl_timer(unsigned long data);
7cc4a4c0 52static void _wl_timer(wl_timer_t *t);
a9533e7e 53
a9533e7e
HP
54
55static int ieee_hw_init(struct ieee80211_hw *hw);
56static int ieee_hw_rate_init(struct ieee80211_hw *hw);
57
58static int wl_linux_watchdog(void *ctx);
59
60/* Flags we support */
61#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
62 FIF_ALLMULTI | \
63 FIF_FCSFAIL | \
64 FIF_PLCPFAIL | \
65 FIF_CONTROL | \
66 FIF_OTHER_BSS | \
67 FIF_BCN_PRBRESP_PROMISC)
68
7e85c729 69static int wl_found;
a9533e7e
HP
70
71struct ieee80211_tkip_data {
72#define TKIP_KEY_LEN 32
73 u8 key[TKIP_KEY_LEN];
74 int key_set;
75
76 u32 tx_iv32;
77 u16 tx_iv16;
78 u16 tx_ttak[5];
79 int tx_phase1_done;
80
81 u32 rx_iv32;
82 u16 rx_iv16;
83 u16 rx_ttak[5];
84 int rx_phase1_done;
85 u32 rx_iv32_new;
86 u16 rx_iv16_new;
87
88 u32 dot11RSNAStatsTKIPReplays;
89 u32 dot11RSNAStatsTKIPICVErrors;
90 u32 dot11RSNAStatsTKIPLocalMICFailures;
91
92 int key_idx;
93
94 struct crypto_tfm *tfm_arc4;
95 struct crypto_tfm *tfm_michael;
96
97 /* scratch buffers for virt_to_page() (crypto API) */
98 u8 rx_hdr[16], tx_hdr[16];
99};
100
6cdeaef2 101#define WL_DEV_IF(dev) ((struct wl_if *)netdev_priv(dev))
2cb22a7a
RV
102#define WL_INFO(dev) ((struct wl_info *)(WL_DEV_IF(dev)->wl))
103static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev);
104static void wl_release_fw(struct wl_info *wl);
a9533e7e
HP
105
106/* local prototypes */
2cb22a7a
RV
107static int wl_start(struct sk_buff *skb, struct wl_info *wl);
108static int wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw,
a9533e7e 109 struct sk_buff *skb);
3deea904 110static void wl_dpc(unsigned long data);
a9533e7e
HP
111
112MODULE_AUTHOR("Broadcom Corporation");
113MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
114MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
115MODULE_LICENSE("Dual BSD/GPL");
116
a9533e7e
HP
117/* recognized PCI IDs */
118static struct pci_device_id wl_id_table[] = {
119 {PCI_VENDOR_ID_BROADCOM, 0x4357, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43225 2G */
120 {PCI_VENDOR_ID_BROADCOM, 0x4353, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43224 DUAL */
121 {PCI_VENDOR_ID_BROADCOM, 0x4727, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 4313 DUAL */
122 {0}
123};
124
125MODULE_DEVICE_TABLE(pci, wl_id_table);
6f0c5bcd 126static void wl_remove(struct pci_dev *pdev);
a9533e7e 127
a9533e7e
HP
128
129#ifdef BCMDBG
130static int msglevel = 0xdeadbeef;
131module_param(msglevel, int, 0);
a9533e7e
HP
132static int phymsglevel = 0xdeadbeef;
133module_param(phymsglevel, int, 0);
a9533e7e
HP
134#endif /* BCMDBG */
135
0d706ef4
JC
136#define HW_TO_WL(hw) (hw->priv)
137#define WL_TO_HW(wl) (wl->pub->ieee_hw)
a9533e7e 138static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
a9533e7e
HP
139static int wl_ops_start(struct ieee80211_hw *hw);
140static void wl_ops_stop(struct ieee80211_hw *hw);
141static int wl_ops_add_interface(struct ieee80211_hw *hw,
142 struct ieee80211_vif *vif);
143static void wl_ops_remove_interface(struct ieee80211_hw *hw,
144 struct ieee80211_vif *vif);
145static int wl_ops_config(struct ieee80211_hw *hw, u32 changed);
146static void wl_ops_bss_info_changed(struct ieee80211_hw *hw,
147 struct ieee80211_vif *vif,
148 struct ieee80211_bss_conf *info,
149 u32 changed);
150static void wl_ops_configure_filter(struct ieee80211_hw *hw,
151 unsigned int changed_flags,
152 unsigned int *total_flags, u64 multicast);
153static int wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
154 bool set);
155static void wl_ops_sw_scan_start(struct ieee80211_hw *hw);
156static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw);
157static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf);
158static int wl_ops_get_stats(struct ieee80211_hw *hw,
159 struct ieee80211_low_level_stats *stats);
160static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
161static void wl_ops_sta_notify(struct ieee80211_hw *hw,
162 struct ieee80211_vif *vif,
163 enum sta_notify_cmd cmd,
164 struct ieee80211_sta *sta);
165static int wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
166 const struct ieee80211_tx_queue_params *params);
167static u64 wl_ops_get_tsf(struct ieee80211_hw *hw);
168static int wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
169 struct ieee80211_sta *sta);
170static int wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
171 struct ieee80211_sta *sta);
172static int wl_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
173 enum ieee80211_ampdu_mlme_action action,
7cc4a4c0 174 struct ieee80211_sta *sta, u16 tid, u16 *ssn);
a9533e7e 175
a9533e7e
HP
176static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
177{
178 int status;
2cb22a7a 179 struct wl_info *wl = hw->priv;
a9533e7e
HP
180 WL_LOCK(wl);
181 if (!wl->pub->up) {
182 WL_ERROR(("ops->tx called while down\n"));
183 status = -ENETDOWN;
184 goto done;
185 }
186 status = wl_start(skb, wl);
187 done:
188 WL_UNLOCK(wl);
189 return status;
190}
a9533e7e
HP
191
192static int wl_ops_start(struct ieee80211_hw *hw)
193{
2cb22a7a 194 struct wl_info *wl = hw->priv;
a9533e7e
HP
195 /* struct ieee80211_channel *curchan = hw->conf.channel; */
196 WL_NONE(("%s : Initial channel: %d\n", __func__, curchan->hw_value));
197
198 WL_LOCK(wl);
199 ieee80211_wake_queues(hw);
200 WL_UNLOCK(wl);
201
202 return 0;
203}
204
205static void wl_ops_stop(struct ieee80211_hw *hw)
206{
2cb22a7a 207 struct wl_info *wl = hw->priv;
a9533e7e
HP
208 ASSERT(wl);
209 WL_LOCK(wl);
210 wl_down(wl);
211 ieee80211_stop_queues(hw);
212 WL_UNLOCK(wl);
213
214 return;
215}
216
217static int
218wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
219{
2cb22a7a 220 struct wl_info *wl;
a9533e7e
HP
221 int err;
222
223 /* Just STA for now */
224 if (vif->type != NL80211_IFTYPE_AP &&
225 vif->type != NL80211_IFTYPE_MESH_POINT &&
226 vif->type != NL80211_IFTYPE_STATION &&
227 vif->type != NL80211_IFTYPE_WDS &&
228 vif->type != NL80211_IFTYPE_ADHOC) {
229 WL_ERROR(("%s: Attempt to add type %d, only STA for now\n",
230 __func__, vif->type));
231 return -EOPNOTSUPP;
232 }
233
234 wl = HW_TO_WL(hw);
235 WL_LOCK(wl);
236 err = wl_up(wl);
237 WL_UNLOCK(wl);
238
239 if (err != 0)
240 WL_ERROR(("%s: wl_up() returned %d\n", __func__, err));
241 return err;
242}
243
244static void
245wl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
246{
247 return;
248}
249
250static int
251ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
252 enum nl80211_channel_type type)
253{
2cb22a7a 254 struct wl_info *wl = HW_TO_WL(hw);
a9533e7e
HP
255 int err = 0;
256
257 switch (type) {
258 case NL80211_CHAN_HT20:
259 case NL80211_CHAN_NO_HT:
260 WL_LOCK(wl);
261 err = wlc_set(wl->wlc, WLC_SET_CHANNEL, chan->hw_value);
262 WL_UNLOCK(wl);
263 break;
264 case NL80211_CHAN_HT40MINUS:
265 case NL80211_CHAN_HT40PLUS:
266 WL_ERROR(("%s: Need to implement 40 Mhz Channels!\n",
267 __func__));
268 break;
269 }
270
271 if (err)
272 return -EIO;
273 return err;
274}
275
276static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
277{
278 struct ieee80211_conf *conf = &hw->conf;
2cb22a7a 279 struct wl_info *wl = HW_TO_WL(hw);
a9533e7e
HP
280 int err = 0;
281 int new_int;
282
283 if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
284 WL_NONE(("%s: Setting listen interval to %d\n",
285 __func__, conf->listen_interval));
286 if (wlc_iovar_setint
287 (wl->wlc, "bcn_li_bcn", conf->listen_interval)) {
288 WL_ERROR(("%s: Error setting listen_interval\n",
289 __func__));
290 err = -EIO;
291 goto config_out;
292 }
293 wlc_iovar_getint(wl->wlc, "bcn_li_bcn", &new_int);
294 ASSERT(new_int == conf->listen_interval);
295 }
296 if (changed & IEEE80211_CONF_CHANGE_MONITOR)
297 WL_NONE(("Need to set monitor mode\n"));
298 if (changed & IEEE80211_CONF_CHANGE_PS)
299 WL_NONE(("Need to set Power-save mode\n"));
300
301 if (changed & IEEE80211_CONF_CHANGE_POWER) {
302 WL_NONE(("%s: Setting tx power to %d dbm\n", __func__,
303 conf->power_level));
304 if (wlc_iovar_setint
305 (wl->wlc, "qtxpower", conf->power_level * 4)) {
306 WL_ERROR(("%s: Error setting power_level\n", __func__));
307 err = -EIO;
308 goto config_out;
309 }
310 wlc_iovar_getint(wl->wlc, "qtxpower", &new_int);
311 if (new_int != (conf->power_level * 4))
312 WL_ERROR(("%s: Power level req != actual, %d %d\n",
313 __func__, conf->power_level * 4, new_int));
314 }
315 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
316 err = ieee_set_channel(hw, conf->channel, conf->channel_type);
317 }
318 if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
319 WL_NONE(("%s: srl %d, lrl %d\n", __func__,
320 conf->short_frame_max_tx_count,
321 conf->long_frame_max_tx_count));
322 if (wlc_set
323 (wl->wlc, WLC_SET_SRL,
324 conf->short_frame_max_tx_count) < 0) {
325 WL_ERROR(("%s: Error setting srl\n", __func__));
326 err = -EIO;
327 goto config_out;
328 }
329 if (wlc_set(wl->wlc, WLC_SET_LRL, conf->long_frame_max_tx_count)
330 < 0) {
331 WL_ERROR(("%s: Error setting lrl\n", __func__));
332 err = -EIO;
333 goto config_out;
334 }
335 }
336
337 config_out:
338 return err;
339}
340
341static void
342wl_ops_bss_info_changed(struct ieee80211_hw *hw,
343 struct ieee80211_vif *vif,
344 struct ieee80211_bss_conf *info, u32 changed)
345{
2cb22a7a 346 struct wl_info *wl = HW_TO_WL(hw);
a9533e7e
HP
347 int val;
348
a9533e7e
HP
349
350 if (changed & BSS_CHANGED_ASSOC) {
351 WL_ERROR(("Associated:\t%s\n", info->assoc ? "True" : "False"));
352 /* association status changed (associated/disassociated)
353 * also implies a change in the AID.
354 */
355 }
356 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
357 WL_NONE(("Use_cts_prot:\t%s Implement me\n",
358 info->use_cts_prot ? "True" : "False"));
359 /* CTS protection changed */
360 }
361 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
362 WL_NONE(("Short preamble:\t%s Implement me\n",
363 info->use_short_preamble ? "True" : "False"));
364 /* preamble changed */
365 }
366 if (changed & BSS_CHANGED_ERP_SLOT) {
367 WL_NONE(("Changing short slot:\t%s\n",
368 info->use_short_slot ? "True" : "False"));
369 if (info->use_short_slot)
370 val = 1;
371 else
372 val = 0;
373 wlc_set(wl->wlc, WLC_SET_SHORTSLOT_OVERRIDE, val);
374 /* slot timing changed */
375 }
376
377 if (changed & BSS_CHANGED_HT) {
378 WL_NONE(("%s: HT mode - Implement me\n", __func__));
379 /* 802.11n parameters changed */
380 }
381 if (changed & BSS_CHANGED_BASIC_RATES) {
382 WL_NONE(("Need to change Basic Rates:\t0x%x! Implement me\n",
66cbd3ab 383 (u32) info->basic_rates));
a9533e7e
HP
384 /* Basic rateset changed */
385 }
386 if (changed & BSS_CHANGED_BEACON_INT) {
387 WL_NONE(("Beacon Interval:\t%d Implement me\n",
388 info->beacon_int));
389 /* Beacon interval changed */
390 }
391 if (changed & BSS_CHANGED_BSSID) {
ba07d0cb
AS
392 WL_NONE(("new BSSID:\taid %d bss:%pM\n", info->aid,
393 info->bssid));
a9533e7e
HP
394 /* BSSID changed, for whatever reason (IBSS and managed mode) */
395 /* FIXME: need to store bssid in bsscfg */
396 wlc_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET,
397 (struct ether_addr *)info->bssid);
398 }
399 if (changed & BSS_CHANGED_BEACON) {
400 WL_ERROR(("BSS_CHANGED_BEACON\n"));
401 /* Beacon data changed, retrieve new beacon (beaconing modes) */
402 }
403 if (changed & BSS_CHANGED_BEACON_ENABLED) {
404 WL_ERROR(("Beacon enabled:\t%s\n",
405 info->enable_beacon ? "True" : "False"));
406 /* Beaconing should be enabled/disabled (beaconing modes) */
407 }
a9533e7e
HP
408 return;
409}
410
411static void
412wl_ops_configure_filter(struct ieee80211_hw *hw,
413 unsigned int changed_flags,
414 unsigned int *total_flags, u64 multicast)
415{
2cb22a7a 416 struct wl_info *wl = hw->priv;
a9533e7e
HP
417
418 changed_flags &= MAC_FILTERS;
419 *total_flags &= MAC_FILTERS;
420 if (changed_flags & FIF_PROMISC_IN_BSS)
421 WL_ERROR(("FIF_PROMISC_IN_BSS\n"));
422 if (changed_flags & FIF_ALLMULTI)
423 WL_ERROR(("FIF_ALLMULTI\n"));
424 if (changed_flags & FIF_FCSFAIL)
425 WL_ERROR(("FIF_FCSFAIL\n"));
426 if (changed_flags & FIF_PLCPFAIL)
427 WL_ERROR(("FIF_PLCPFAIL\n"));
428 if (changed_flags & FIF_CONTROL)
429 WL_ERROR(("FIF_CONTROL\n"));
430 if (changed_flags & FIF_OTHER_BSS)
431 WL_ERROR(("FIF_OTHER_BSS\n"));
432 if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
433 WL_NONE(("FIF_BCN_PRBRESP_PROMISC\n"));
a9533e7e
HP
434 WL_LOCK(wl);
435 if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
436 wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS;
437 wlc_mac_bcn_promisc_change(wl->wlc, 1);
438 } else {
439 wlc_mac_bcn_promisc_change(wl->wlc, 0);
440 wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS;
441 }
442 WL_UNLOCK(wl);
a9533e7e
HP
443 }
444 return;
445}
446
447static int
448wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
449{
450 WL_ERROR(("%s: Enter\n", __func__));
451 return 0;
452}
453
454static void wl_ops_sw_scan_start(struct ieee80211_hw *hw)
455{
456 WL_NONE(("Scan Start\n"));
457 return;
458}
459
460static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw)
461{
462 WL_NONE(("Scan Complete\n"));
463 return;
464}
465
466static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf)
467{
468 WL_ERROR(("%s: Enter\n", __func__));
469 return;
470}
471
472static int
473wl_ops_get_stats(struct ieee80211_hw *hw,
474 struct ieee80211_low_level_stats *stats)
475{
476 WL_ERROR(("%s: Enter\n", __func__));
477 return 0;
478}
479
480static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
481{
482 WL_ERROR(("%s: Enter\n", __func__));
483 return 0;
484}
485
486static void
487wl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
488 enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
489{
490 WL_NONE(("%s: Enter\n", __func__));
491 switch (cmd) {
492 default:
493 WL_ERROR(("%s: Uknown cmd = %d\n", __func__, cmd));
494 break;
495 }
496 return;
497}
498
499static int
500wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
501 const struct ieee80211_tx_queue_params *params)
502{
2cb22a7a 503 struct wl_info *wl = hw->priv;
a9533e7e
HP
504
505 WL_NONE(("%s: Enter (WME config)\n", __func__));
506 WL_NONE(("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue,
507 params->txop, params->cw_min, params->cw_max, params->aifs));
508
509 WL_LOCK(wl);
0f0881b0 510 wlc_wme_setparams(wl->wlc, queue, (void *)params, true);
a9533e7e
HP
511 WL_UNLOCK(wl);
512
513 return 0;
514}
515
516static u64 wl_ops_get_tsf(struct ieee80211_hw *hw)
517{
518 WL_ERROR(("%s: Enter\n", __func__));
519 return 0;
520}
521
522static int
523wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
524 struct ieee80211_sta *sta)
525{
526 struct scb *scb;
527
528 int i;
2cb22a7a 529 struct wl_info *wl = hw->priv;
a9533e7e
HP
530
531 /* Init the scb */
532 scb = (struct scb *)sta->drv_priv;
9249ede9 533 memset(scb, 0, sizeof(struct scb));
a9533e7e
HP
534 for (i = 0; i < NUMPRIO; i++)
535 scb->seqctl[i] = 0xFFFF;
536 scb->seqctl_nonqos = 0xFFFF;
537 scb->magic = SCB_MAGIC;
538
539 wl->pub->global_scb = scb;
540 wl->pub->global_ampdu = &(scb->scb_ampdu);
541 wl->pub->global_ampdu->scb = scb;
a9533e7e 542 wl->pub->global_ampdu->max_pdu = 16;
a9533e7e
HP
543 pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID,
544 AMPDU_MAX_SCB_TID * PKTQ_LEN_DEFAULT);
545
0f0881b0 546 sta->ht_cap.ht_supported = true;
a9533e7e 547 sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_64K;
a9533e7e
HP
548 sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY;
549 sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD |
550 IEEE80211_HT_CAP_SGI_20 |
551 IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
552
553 /* minstrel_ht initiates addBA on our behalf by calling ieee80211_start_tx_ba_session() */
554 return 0;
555}
556
557static int
558wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
559 struct ieee80211_sta *sta)
560{
561 WL_NONE(("%s: Enter\n", __func__));
562 return 0;
563}
564
565static int
566wl_ampdu_action(struct ieee80211_hw *hw,
567 struct ieee80211_vif *vif,
568 enum ieee80211_ampdu_mlme_action action,
7cc4a4c0 569 struct ieee80211_sta *sta, u16 tid, u16 *ssn)
a9533e7e
HP
570{
571#if defined(BCMDBG)
572 struct scb *scb = (struct scb *)sta->drv_priv;
573#endif
2cb22a7a 574 struct wl_info *wl = hw->priv;
a9533e7e
HP
575
576 ASSERT(scb->magic == SCB_MAGIC);
577 switch (action) {
578 case IEEE80211_AMPDU_RX_START:
579 WL_NONE(("%s: action = IEEE80211_AMPDU_RX_START\n", __func__));
580 break;
581 case IEEE80211_AMPDU_RX_STOP:
582 WL_NONE(("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__));
583 break;
584 case IEEE80211_AMPDU_TX_START:
585 if (!wlc_aggregatable(wl->wlc, tid)) {
586 /* WL_ERROR(("START: tid %d is not agg' able, return FAILURE to stack\n", tid)); */
587 return -1;
588 }
589 /* XXX: Use the starting sequence number provided ... */
590 *ssn = 0;
591 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
592 break;
593
594 case IEEE80211_AMPDU_TX_STOP:
595 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
596 break;
597 case IEEE80211_AMPDU_TX_OPERATIONAL:
598 /* Not sure what to do here */
599 /* Power save wakeup */
600 WL_NONE(("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n",
601 __func__));
602 break;
603 default:
604 WL_ERROR(("%s: Invalid command, ignoring\n", __func__));
605 }
606
607 return 0;
608}
609
610static const struct ieee80211_ops wl_ops = {
a9533e7e 611 .tx = wl_ops_tx,
a9533e7e
HP
612 .start = wl_ops_start,
613 .stop = wl_ops_stop,
614 .add_interface = wl_ops_add_interface,
615 .remove_interface = wl_ops_remove_interface,
616 .config = wl_ops_config,
617 .bss_info_changed = wl_ops_bss_info_changed,
618 .configure_filter = wl_ops_configure_filter,
619 .set_tim = wl_ops_set_tim,
620 .sw_scan_start = wl_ops_sw_scan_start,
621 .sw_scan_complete = wl_ops_sw_scan_complete,
622 .set_tsf = wl_ops_set_tsf,
623 .get_stats = wl_ops_get_stats,
624 .set_rts_threshold = wl_ops_set_rts_threshold,
625 .sta_notify = wl_ops_sta_notify,
626 .conf_tx = wl_ops_conf_tx,
627 .get_tsf = wl_ops_get_tsf,
628 .sta_add = wl_sta_add,
629 .sta_remove = wl_sta_remove,
630 .ampdu_action = wl_ampdu_action,
631};
632
2cb22a7a 633static int wl_set_hint(struct wl_info *wl, char *abbrev)
a9533e7e
HP
634{
635 WL_ERROR(("%s: Sending country code %c%c to MAC80211\n", __func__,
636 abbrev[0], abbrev[1]));
90ea2296 637 return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
a9533e7e
HP
638}
639
640/**
641 * attach to the WL device.
642 *
643 * Attach to the WL device identified by vendor and device parameters.
644 * regs is a host accessible memory address pointing to WL device registers.
645 *
646 * wl_attach is not defined as static because in the case where no bus
647 * is defined, wl_attach will never be called, and thus, gcc will issue
648 * a warning that this function is defined but not used if we declare
649 * it as static.
650 */
2cb22a7a 651static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs,
a9533e7e
HP
652 uint bustype, void *btparam, uint irq)
653{
2cb22a7a 654 struct wl_info *wl;
e69284f2 655 struct osl_info *osh;
a9533e7e
HP
656 int unit, err;
657
3deea904 658 unsigned long base_addr;
a9533e7e 659 struct ieee80211_hw *hw;
41feb5ed 660 u8 perm[ETH_ALEN];
a9533e7e 661
06fc8846 662 unit = wl_found;
a9533e7e
HP
663 err = 0;
664
665 if (unit < 0) {
666 WL_ERROR(("wl%d: unit number overflow, exiting\n", unit));
667 return NULL;
668 }
669
997dd24f 670 osh = osl_attach(btparam, bustype);
a9533e7e
HP
671 ASSERT(osh);
672
a9533e7e
HP
673 /* allocate private info */
674 hw = pci_get_drvdata(btparam); /* btparam == pdev */
675 wl = hw->priv;
a9533e7e
HP
676 ASSERT(wl);
677
a9533e7e
HP
678 wl->osh = osh;
679 atomic_set(&wl->callbacks, 0);
680
eb4764c3 681 /* setup the bottom half handler */
3deea904 682 tasklet_init(&wl->tasklet, wl_dpc, (unsigned long) wl);
eb4764c3 683
a9533e7e 684
a9533e7e
HP
685
686 base_addr = regs;
687
688 if (bustype == PCI_BUS) {
06fc8846 689 wl->piomode = false;
a9533e7e
HP
690 } else if (bustype == RPC_BUS) {
691 /* Do nothing */
692 } else {
693 bustype = PCI_BUS;
694 WL_TRACE(("force to PCI\n"));
695 }
696 wl->bcm_bustype = bustype;
697
ca8c1e59
JC
698 wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ);
699 if (wl->regsva == NULL) {
a9533e7e
HP
700 WL_ERROR(("wl%d: ioremap() failed\n", unit));
701 goto fail;
702 }
a9533e7e
HP
703 spin_lock_init(&wl->lock);
704 spin_lock_init(&wl->isr_lock);
a9533e7e 705
a9533e7e
HP
706 /* prepare ucode */
707 if (wl_request_fw(wl, (struct pci_dev *)btparam)) {
683b505b
BR
708 printf("%s: Failed to find firmware usually in %s\n",
709 KBUILD_MODNAME, "/lib/firmware/brcm");
710 wl_release_fw(wl);
711 wl_remove((struct pci_dev *)btparam);
712 goto fail1;
a9533e7e 713 }
a9533e7e
HP
714
715 /* common load-time initialization */
eb4764c3
BH
716 wl->wlc = wlc_attach((void *)wl, vendor, device, unit, wl->piomode, osh,
717 wl->regsva, wl->bcm_bustype, btparam, &err);
eb4764c3 718 wl_release_fw(wl);
eb4764c3 719 if (!wl->wlc) {
4766ae6c
BR
720 printf("%s: wlc_attach() failed with code %d\n",
721 KBUILD_MODNAME, err);
a9533e7e
HP
722 goto fail;
723 }
a9533e7e
HP
724 wl->pub = wlc_pub(wl->wlc);
725
726 wl->pub->ieee_hw = hw;
727 ASSERT(wl->pub->ieee_hw);
728 ASSERT(wl->pub->ieee_hw->priv == wl);
729
a9533e7e 730
06fc8846
BR
731 if (wlc_iovar_setint(wl->wlc, "mpc", 0)) {
732 WL_ERROR(("wl%d: Error setting MPC variable to 0\n",
733 unit));
a9533e7e 734 }
a9533e7e 735
a9533e7e
HP
736 /* register our interrupt handler */
737 if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
738 WL_ERROR(("wl%d: request_irq() failed\n", unit));
739 goto fail;
740 }
741 wl->irq = irq;
a9533e7e
HP
742
743 /* register module */
744 wlc_module_register(wl->pub, NULL, "linux", wl, NULL, wl_linux_watchdog,
745 NULL);
746
747 if (ieee_hw_init(hw)) {
748 WL_ERROR(("wl%d: %s: ieee_hw_init failed!\n", unit, __func__));
749 goto fail;
750 }
751
b8d63078 752 bcopy(&wl->pub->cur_etheraddr, perm, ETH_ALEN);
a9533e7e
HP
753 ASSERT(is_valid_ether_addr(perm));
754 SET_IEEE80211_PERM_ADDR(hw, perm);
755
756 err = ieee80211_register_hw(hw);
757 if (err) {
758 WL_ERROR(("%s: ieee80211_register_hw failed, status %d\n",
759 __func__, err));
760 }
761
762 if (wl->pub->srom_ccode[0])
763 err = wl_set_hint(wl, wl->pub->srom_ccode);
764 else
765 err = wl_set_hint(wl, "US");
766 if (err) {
767 WL_ERROR(("%s: regulatory_hint failed, status %d\n", __func__,
768 err));
769 }
a9533e7e 770 WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
4766ae6c 771 " (" PHY_VERSION_STR ")", unit));
a9533e7e
HP
772
773#ifdef BCMDBG
06fc8846 774 printf(" (Compiled at " __TIME__ " on " __DATE__ ")");
a9533e7e
HP
775#endif /* BCMDBG */
776 printf("\n");
777
a9533e7e
HP
778 wl_found++;
779 return wl;
780
781 fail:
782 wl_free(wl);
9e56568a 783fail1:
a9533e7e
HP
784 return NULL;
785}
786
a9533e7e 787
a9533e7e
HP
788
789#define CHAN2GHZ(channel, freqency, chflags) { \
790 .band = IEEE80211_BAND_2GHZ, \
791 .center_freq = (freqency), \
792 .hw_value = (channel), \
793 .flags = chflags, \
794 .max_antenna_gain = 0, \
795 .max_power = 19, \
796}
797
798static struct ieee80211_channel wl_2ghz_chantable[] = {
799 CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
800 CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS),
801 CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS),
802 CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS),
803 CHAN2GHZ(5, 2432, 0),
804 CHAN2GHZ(6, 2437, 0),
805 CHAN2GHZ(7, 2442, 0),
806 CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS),
807 CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS),
808 CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
809 CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
810 CHAN2GHZ(12, 2467,
811 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
812 IEEE80211_CHAN_NO_HT40PLUS),
813 CHAN2GHZ(13, 2472,
814 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
815 IEEE80211_CHAN_NO_HT40PLUS),
816 CHAN2GHZ(14, 2484,
817 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
818 IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
819};
820
821#define CHAN5GHZ(channel, chflags) { \
822 .band = IEEE80211_BAND_5GHZ, \
823 .center_freq = 5000 + 5*(channel), \
824 .hw_value = (channel), \
825 .flags = chflags, \
826 .max_antenna_gain = 0, \
827 .max_power = 21, \
828}
829
830static struct ieee80211_channel wl_5ghz_nphy_chantable[] = {
831 /* UNII-1 */
832 CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS),
833 CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS),
834 CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS),
835 CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
836 /* UNII-2 */
837 CHAN5GHZ(52,
838 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
839 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
840 CHAN5GHZ(56,
841 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
842 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
843 CHAN5GHZ(60,
844 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
845 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
846 CHAN5GHZ(64,
847 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
848 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
849 /* MID */
850 CHAN5GHZ(100,
851 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
852 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
853 CHAN5GHZ(104,
854 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
855 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
856 CHAN5GHZ(108,
857 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
858 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
859 CHAN5GHZ(112,
860 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
861 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
862 CHAN5GHZ(116,
863 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
864 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
865 CHAN5GHZ(120,
866 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
867 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
868 CHAN5GHZ(124,
869 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
870 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
871 CHAN5GHZ(128,
872 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
873 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
874 CHAN5GHZ(132,
875 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
876 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
877 CHAN5GHZ(136,
878 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
879 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
880 CHAN5GHZ(140,
881 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
882 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
883 IEEE80211_CHAN_NO_HT40MINUS),
884 /* UNII-3 */
885 CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
886 CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS),
887 CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS),
888 CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS),
889 CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
890};
891
892#define RATE(rate100m, _flags) { \
893 .bitrate = (rate100m), \
894 .flags = (_flags), \
895 .hw_value = (rate100m / 5), \
896}
897
898static struct ieee80211_rate wl_legacy_ratetable[] = {
899 RATE(10, 0),
900 RATE(20, IEEE80211_RATE_SHORT_PREAMBLE),
901 RATE(55, IEEE80211_RATE_SHORT_PREAMBLE),
902 RATE(110, IEEE80211_RATE_SHORT_PREAMBLE),
903 RATE(60, 0),
904 RATE(90, 0),
905 RATE(120, 0),
906 RATE(180, 0),
907 RATE(240, 0),
908 RATE(360, 0),
909 RATE(480, 0),
910 RATE(540, 0),
911};
912
913static struct ieee80211_supported_band wl_band_2GHz_nphy = {
914 .band = IEEE80211_BAND_2GHZ,
915 .channels = wl_2ghz_chantable,
916 .n_channels = ARRAY_SIZE(wl_2ghz_chantable),
917 .bitrates = wl_legacy_ratetable,
918 .n_bitrates = ARRAY_SIZE(wl_legacy_ratetable),
919 .ht_cap = {
920 /* from include/linux/ieee80211.h */
921 .cap = IEEE80211_HT_CAP_GRN_FLD |
922 IEEE80211_HT_CAP_SGI_20 |
923 IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
a9533e7e
HP
924 .ht_supported = true,
925 .ampdu_factor = AMPDU_RX_FACTOR_64K,
a9533e7e
HP
926 .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
927 .mcs = {
928 /* placeholders for now */
a9533e7e
HP
929 .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
930 .rx_highest = 500,
a9533e7e
HP
931 .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
932 }
933};
934
935static struct ieee80211_supported_band wl_band_5GHz_nphy = {
936 .band = IEEE80211_BAND_5GHZ,
937 .channels = wl_5ghz_nphy_chantable,
938 .n_channels = ARRAY_SIZE(wl_5ghz_nphy_chantable),
939 .bitrates = wl_legacy_ratetable + 4,
940 .n_bitrates = ARRAY_SIZE(wl_legacy_ratetable) - 4,
941 .ht_cap = {
942 /* use IEEE80211_HT_CAP_* from include/linux/ieee80211.h */
943 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
944 .ht_supported = true,
945 .ampdu_factor = AMPDU_RX_FACTOR_64K,
946 .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
947 .mcs = {
948 /* placeholders for now */
949 .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
950 .rx_highest = 500,
951 .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
952 }
953};
954
955static int ieee_hw_rate_init(struct ieee80211_hw *hw)
956{
2cb22a7a 957 struct wl_info *wl = HW_TO_WL(hw);
a9533e7e
HP
958 int has_5g;
959 char phy_list[4];
960
961 has_5g = 0;
962
963 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
964 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
965
966 if (wlc_get(wl->wlc, WLC_GET_PHYLIST, (int *)&phy_list) < 0) {
967 WL_ERROR(("Phy list failed\n"));
968 }
969 WL_NONE(("%s: phylist = %c\n", __func__, phy_list[0]));
970
a9533e7e
HP
971 if (phy_list[0] == 'n' || phy_list[0] == 'c') {
972 if (phy_list[0] == 'c') {
973 /* Single stream */
974 wl_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0;
975 wl_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72;
976 }
a9533e7e
HP
977 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl_band_2GHz_nphy;
978 } else {
979 BUG();
90ea2296 980 return -1;
a9533e7e
HP
981 }
982
983 /* Assume all bands use the same phy. True for 11n devices. */
984 if (NBANDS_PUB(wl->pub) > 1) {
985 has_5g++;
a9533e7e 986 if (phy_list[0] == 'n' || phy_list[0] == 'c') {
a9533e7e
HP
987 hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
988 &wl_band_5GHz_nphy;
989 } else {
90ea2296 990 return -1;
a9533e7e
HP
991 }
992 }
993
994 WL_NONE(("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g));
995
90ea2296 996 return 0;
a9533e7e
HP
997}
998
999static int ieee_hw_init(struct ieee80211_hw *hw)
1000{
1001 hw->flags = IEEE80211_HW_SIGNAL_DBM
1002 /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
1003 | IEEE80211_HW_REPORTS_TX_ACK_STATUS
1004 | IEEE80211_HW_AMPDU_AGGREGATION;
1005
1006 hw->extra_tx_headroom = wlc_get_header_len();
1007 /* FIXME: should get this from wlc->machwcap */
1008 hw->queues = 4;
1009 /* FIXME: this doesn't seem to be used properly in minstrel_ht.
1010 * mac80211/status.c:ieee80211_tx_status() checks this value,
1011 * but mac80211/rc80211_minstrel_ht.c:minstrel_ht_get_rate()
1012 * appears to always set 3 rates
1013 */
1014 hw->max_rates = 2; /* Primary rate and 1 fallback rate */
1015
1016 hw->channel_change_time = 7 * 1000; /* channel change time is dependant on chip and band */
1017 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1018
1019 hw->rate_control_algorithm = "minstrel_ht";
1020
1021 hw->sta_data_size = sizeof(struct scb);
90ea2296 1022 return ieee_hw_rate_init(hw);
a9533e7e
HP
1023}
1024
a9533e7e
HP
1025/**
1026 * determines if a device is a WL device, and if so, attaches it.
1027 *
1028 * This function determines if a device pointed to by pdev is a WL device,
1029 * and if so, performs a wl_attach() on it.
1030 *
1031 */
1032int __devinit
1033wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1034{
1035 int rc;
2cb22a7a 1036 struct wl_info *wl;
a9533e7e 1037 struct ieee80211_hw *hw;
66cbd3ab 1038 u32 val;
a9533e7e
HP
1039
1040 ASSERT(pdev);
1041
1042 WL_TRACE(("%s: bus %d slot %d func %d irq %d\n", __func__,
1043 pdev->bus->number, PCI_SLOT(pdev->devfn),
1044 PCI_FUNC(pdev->devfn), pdev->irq));
1045
1046 if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) ||
1047 (((pdev->device & 0xff00) != 0x4300) &&
1048 ((pdev->device & 0xff00) != 0x4700) &&
1049 ((pdev->device < 43000) || (pdev->device > 43999))))
90ea2296 1050 return -ENODEV;
a9533e7e
HP
1051
1052 rc = pci_enable_device(pdev);
1053 if (rc) {
1054 WL_ERROR(("%s: Cannot enable device %d-%d_%d\n", __func__,
1055 pdev->bus->number, PCI_SLOT(pdev->devfn),
1056 PCI_FUNC(pdev->devfn)));
90ea2296 1057 return -ENODEV;
a9533e7e
HP
1058 }
1059 pci_set_master(pdev);
1060
1061 pci_read_config_dword(pdev, 0x40, &val);
1062 if ((val & 0x0000ff00) != 0)
1063 pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
1064
2cb22a7a 1065 hw = ieee80211_alloc_hw(sizeof(struct wl_info), &wl_ops);
a9533e7e
HP
1066 if (!hw) {
1067 WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__));
1068 rc = -ENOMEM;
1069 goto err_1;
1070 }
1071
1072 SET_IEEE80211_DEV(hw, &pdev->dev);
1073
1074 pci_set_drvdata(pdev, hw);
1075
9249ede9 1076 memset(hw->priv, 0, sizeof(*wl));
a9533e7e
HP
1077
1078 wl = wl_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0),
1079 PCI_BUS, pdev, pdev->irq);
1080
683b505b
BR
1081 if (!wl) {
1082 WL_ERROR(("%s: %s: wl_attach failed!\n",
1083 KBUILD_MODNAME, __func__));
1084 return -ENODEV;
1085 }
a9533e7e
HP
1086 return 0;
1087 err_1:
1088 WL_ERROR(("%s: err_1: Major hoarkage\n", __func__));
1089 return 0;
1090}
1091
1092#ifdef LINUXSTA_PS
878a6673 1093static int wl_suspend(struct pci_dev *pdev, pm_message_t state)
a9533e7e 1094{
2cb22a7a 1095 struct wl_info *wl;
a9533e7e
HP
1096 struct ieee80211_hw *hw;
1097
1098 WL_TRACE(("wl: wl_suspend\n"));
1099
1100 hw = pci_get_drvdata(pdev);
1101 wl = HW_TO_WL(hw);
1102 if (!wl) {
1103 WL_ERROR(("wl: wl_suspend: pci_get_drvdata failed\n"));
1104 return -ENODEV;
1105 }
1106
1107 WL_LOCK(wl);
1108 wl_down(wl);
0965ae88 1109 wl->pub->hw_up = false;
a9533e7e 1110 WL_UNLOCK(wl);
8ba9cfdb 1111 pci_save_state(pdev, wl->pci_psstate);
a9533e7e
HP
1112 pci_disable_device(pdev);
1113 return pci_set_power_state(pdev, PCI_D3hot);
1114}
1115
1116static int wl_resume(struct pci_dev *pdev)
1117{
2cb22a7a 1118 struct wl_info *wl;
a9533e7e
HP
1119 struct ieee80211_hw *hw;
1120 int err = 0;
66cbd3ab 1121 u32 val;
a9533e7e
HP
1122
1123 WL_TRACE(("wl: wl_resume\n"));
1124 hw = pci_get_drvdata(pdev);
1125 wl = HW_TO_WL(hw);
1126 if (!wl) {
1127 WL_ERROR(("wl: wl_resume: pci_get_drvdata failed\n"));
1128 return -ENODEV;
1129 }
1130
1131 err = pci_set_power_state(pdev, PCI_D0);
1132 if (err)
1133 return err;
1134
8ba9cfdb 1135 pci_restore_state(pdev, wl->pci_psstate);
a9533e7e
HP
1136
1137 err = pci_enable_device(pdev);
1138 if (err)
1139 return err;
1140
1141 pci_set_master(pdev);
1142
1143 pci_read_config_dword(pdev, 0x40, &val);
1144 if ((val & 0x0000ff00) != 0)
1145 pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
1146
1147 WL_LOCK(wl);
1148 err = wl_up(wl);
1149 WL_UNLOCK(wl);
1150
90ea2296 1151 return err;
a9533e7e
HP
1152}
1153#endif /* LINUXSTA_PS */
1154
6f0c5bcd 1155static void wl_remove(struct pci_dev *pdev)
a9533e7e 1156{
2cb22a7a 1157 struct wl_info *wl;
a9533e7e
HP
1158 struct ieee80211_hw *hw;
1159
1160 hw = pci_get_drvdata(pdev);
1161 wl = HW_TO_WL(hw);
1162 if (!wl) {
1163 WL_ERROR(("wl: wl_remove: pci_get_drvdata failed\n"));
1164 return;
1165 }
1166 if (!wlc_chipmatch(pdev->vendor, pdev->device)) {
1167 WL_ERROR(("wl: wl_remove: wlc_chipmatch failed\n"));
1168 return;
1169 }
683b505b
BR
1170 if (wl->wlc) {
1171 ieee80211_unregister_hw(hw);
1172 WL_LOCK(wl);
1173 wl_down(wl);
1174 WL_UNLOCK(wl);
1175 WL_NONE(("%s: Down\n", __func__));
1176 }
a9533e7e
HP
1177 pci_disable_device(pdev);
1178
1179 wl_free(wl);
1180
1181 pci_set_drvdata(pdev, NULL);
1182 ieee80211_free_hw(hw);
1183}
1184
1185static struct pci_driver wl_pci_driver = {
5fee2540
JC
1186 .name = "brcm80211",
1187 .probe = wl_pci_probe,
a9533e7e 1188#ifdef LINUXSTA_PS
5fee2540
JC
1189 .suspend = wl_suspend,
1190 .resume = wl_resume,
a9533e7e 1191#endif /* LINUXSTA_PS */
5fee2540
JC
1192 .remove = __devexit_p(wl_remove),
1193 .id_table = wl_id_table,
a9533e7e 1194};
a9533e7e
HP
1195
1196/**
1197 * This is the main entry point for the WL driver.
1198 *
1199 * This function determines if a device pointed to by pdev is a WL device,
1200 * and if so, performs a wl_attach() on it.
1201 *
1202 */
1203static int __init wl_module_init(void)
1204{
1205 int error = -ENODEV;
1206
1207#ifdef BCMDBG
1208 if (msglevel != 0xdeadbeef)
1209 wl_msg_level = msglevel;
1210 else {
1211 char *var = getvar(NULL, "wl_msglevel");
1212 if (var)
48c51a8c 1213 wl_msg_level = simple_strtoul(var, NULL, 0);
a9533e7e 1214 }
a9533e7e 1215 {
66cbd3ab 1216 extern u32 phyhal_msg_level;
a9533e7e
HP
1217
1218 if (phymsglevel != 0xdeadbeef)
1219 phyhal_msg_level = phymsglevel;
1220 else {
1221 char *var = getvar(NULL, "phy_msglevel");
1222 if (var)
48c51a8c 1223 phyhal_msg_level = simple_strtoul(var, NULL, 0);
a9533e7e
HP
1224 }
1225 }
a9533e7e
HP
1226#endif /* BCMDBG */
1227
8ba9cfdb 1228 error = pci_register_driver(&wl_pci_driver);
ca8c1e59 1229 if (!error)
90ea2296 1230 return 0;
a9533e7e 1231
a9533e7e 1232
a9533e7e 1233
90ea2296 1234 return error;
a9533e7e
HP
1235}
1236
1237/**
1238 * This function unloads the WL driver from the system.
1239 *
1240 * This function unconditionally unloads the WL driver module from the
1241 * system.
1242 *
1243 */
1244static void __exit wl_module_exit(void)
1245{
a9533e7e 1246 pci_unregister_driver(&wl_pci_driver);
a9533e7e 1247
a9533e7e
HP
1248}
1249
1250module_init(wl_module_init);
1251module_exit(wl_module_exit);
1252
1253/**
1254 * This function frees the WL per-device resources.
1255 *
1256 * This function frees resources owned by the WL device pointed to
1257 * by the wl parameter.
1258 *
1259 */
2cb22a7a 1260void wl_free(struct wl_info *wl)
a9533e7e
HP
1261{
1262 wl_timer_t *t, *next;
e69284f2 1263 struct osl_info *osh;
a9533e7e
HP
1264
1265 ASSERT(wl);
a9533e7e
HP
1266 /* free ucode data */
1267 if (wl->fw.fw_cnt)
1268 wl_ucode_data_free();
a9533e7e
HP
1269 if (wl->irq)
1270 free_irq(wl->irq, wl);
a9533e7e
HP
1271
1272 /* kill dpc */
1273 tasklet_kill(&wl->tasklet);
1274
1275 if (wl->pub) {
1276 wlc_module_unregister(wl->pub, "linux", wl);
1277 }
1278
1279 /* free common resources */
1280 if (wl->wlc) {
1281 wlc_detach(wl->wlc);
1282 wl->wlc = NULL;
1283 wl->pub = NULL;
1284 }
1285
1286 /* virtual interface deletion is deferred so we cannot spinwait */
1287
1288 /* wait for all pending callbacks to complete */
1289 while (atomic_read(&wl->callbacks) > 0)
1290 schedule();
1291
1292 /* free timers */
1293 for (t = wl->timers; t; t = next) {
1294 next = t->next;
1295#ifdef BCMDBG
1296 if (t->name)
182acb3c 1297 kfree(t->name);
a9533e7e 1298#endif
182acb3c 1299 kfree(t);
a9533e7e
HP
1300 }
1301
a9533e7e
HP
1302 osh = wl->osh;
1303
1304 /*
1305 * unregister_netdev() calls get_stats() which may read chip registers
1306 * so we cannot unmap the chip registers until after calling unregister_netdev() .
1307 */
fa7a1db2
BR
1308 if (wl->regsva && wl->bcm_bustype != SDIO_BUS &&
1309 wl->bcm_bustype != JTAG_BUS) {
a9533e7e
HP
1310 iounmap((void *)wl->regsva);
1311 }
1312 wl->regsva = NULL;
1313
a9533e7e 1314
a9533e7e
HP
1315 osl_detach(osh);
1316}
1317
a9533e7e 1318/* transmit a packet */
2cb22a7a 1319static int BCMFASTPATH wl_start(struct sk_buff *skb, struct wl_info *wl)
a9533e7e
HP
1320{
1321 if (!wl)
1322 return -ENETDOWN;
1323
1324 return wl_start_int(wl, WL_TO_HW(wl), skb);
1325}
a9533e7e
HP
1326
1327static int BCMFASTPATH
2cb22a7a 1328wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw, struct sk_buff *skb)
a9533e7e 1329{
a9533e7e 1330 wlc_sendpkt_mac80211(wl->wlc, skb, hw);
90ea2296 1331 return NETDEV_TX_OK;
a9533e7e
HP
1332}
1333
2cb22a7a
RV
1334void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state,
1335 int prio)
a9533e7e
HP
1336{
1337 WL_ERROR(("Shouldn't be here %s\n", __func__));
1338}
1339
2cb22a7a 1340void wl_init(struct wl_info *wl)
a9533e7e
HP
1341{
1342 WL_TRACE(("wl%d: wl_init\n", wl->pub->unit));
1343
1344 wl_reset(wl);
1345
1346 wlc_init(wl->wlc);
1347}
1348
2cb22a7a 1349uint wl_reset(struct wl_info *wl)
a9533e7e
HP
1350{
1351 WL_TRACE(("wl%d: wl_reset\n", wl->pub->unit));
1352
1353 wlc_reset(wl->wlc);
1354
1355 /* dpc will not be rescheduled */
1356 wl->resched = 0;
1357
90ea2296 1358 return 0;
a9533e7e
HP
1359}
1360
1361/*
1362 * These are interrupt on/off entry points. Disable interrupts
1363 * during interrupt state transition.
1364 */
2cb22a7a 1365void BCMFASTPATH wl_intrson(struct wl_info *wl)
a9533e7e 1366{
a9533e7e
HP
1367 unsigned long flags;
1368
1369 INT_LOCK(wl, flags);
1370 wlc_intrson(wl->wlc);
1371 INT_UNLOCK(wl, flags);
a9533e7e
HP
1372}
1373
2cb22a7a 1374bool wl_alloc_dma_resources(struct wl_info *wl, uint addrwidth)
a9533e7e 1375{
0f0881b0 1376 return true;
a9533e7e
HP
1377}
1378
2cb22a7a 1379u32 BCMFASTPATH wl_intrsoff(struct wl_info *wl)
a9533e7e 1380{
a9533e7e 1381 unsigned long flags;
66cbd3ab 1382 u32 status;
a9533e7e
HP
1383
1384 INT_LOCK(wl, flags);
1385 status = wlc_intrsoff(wl->wlc);
1386 INT_UNLOCK(wl, flags);
1387 return status;
a9533e7e
HP
1388}
1389
2cb22a7a 1390void wl_intrsrestore(struct wl_info *wl, u32 macintmask)
a9533e7e 1391{
a9533e7e
HP
1392 unsigned long flags;
1393
1394 INT_LOCK(wl, flags);
1395 wlc_intrsrestore(wl->wlc, macintmask);
1396 INT_UNLOCK(wl, flags);
a9533e7e
HP
1397}
1398
2cb22a7a 1399int wl_up(struct wl_info *wl)
a9533e7e
HP
1400{
1401 int error = 0;
1402
1403 if (wl->pub->up)
90ea2296 1404 return 0;
a9533e7e
HP
1405
1406 error = wlc_up(wl->wlc);
1407
90ea2296 1408 return error;
a9533e7e
HP
1409}
1410
2cb22a7a 1411void wl_down(struct wl_info *wl)
a9533e7e
HP
1412{
1413 uint callbacks, ret_val = 0;
1414
1415 /* call common down function */
1416 ret_val = wlc_down(wl->wlc);
1417 callbacks = atomic_read(&wl->callbacks) - ret_val;
1418
1419 /* wait for down callbacks to complete */
1420 WL_UNLOCK(wl);
1421
a9533e7e
HP
1422 /* For HIGH_only driver, it's important to actually schedule other work,
1423 * not just spin wait since everything runs at schedule level
1424 */
1425 SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000);
a9533e7e
HP
1426
1427 WL_LOCK(wl);
1428}
1429
1430irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id)
1431{
2cb22a7a 1432 struct wl_info *wl;
a9533e7e
HP
1433 bool ours, wantdpc;
1434 unsigned long flags;
1435
2cb22a7a 1436 wl = (struct wl_info *) dev_id;
a9533e7e
HP
1437
1438 WL_ISRLOCK(wl, flags);
1439
1440 /* call common first level interrupt handler */
ca8c1e59
JC
1441 ours = wlc_isr(wl->wlc, &wantdpc);
1442 if (ours) {
a9533e7e
HP
1443 /* if more to do... */
1444 if (wantdpc) {
1445
1446 /* ...and call the second level interrupt handler */
1447 /* schedule dpc */
0965ae88 1448 ASSERT(wl->resched == false);
a9533e7e
HP
1449 tasklet_schedule(&wl->tasklet);
1450 }
1451 }
1452
1453 WL_ISRUNLOCK(wl, flags);
1454
1455 return IRQ_RETVAL(ours);
a9533e7e
HP
1456}
1457
3deea904 1458static void BCMFASTPATH wl_dpc(unsigned long data)
a9533e7e 1459{
2cb22a7a 1460 struct wl_info *wl;
a9533e7e 1461
2cb22a7a 1462 wl = (struct wl_info *) data;
a9533e7e
HP
1463
1464 WL_LOCK(wl);
1465
1466 /* call the common second level interrupt handler */
1467 if (wl->pub->up) {
1468 if (wl->resched) {
1469 unsigned long flags;
1470
1471 INT_LOCK(wl, flags);
1472 wlc_intrsupd(wl->wlc);
1473 INT_UNLOCK(wl, flags);
1474 }
1475
0f0881b0 1476 wl->resched = wlc_dpc(wl->wlc, true);
a9533e7e
HP
1477 }
1478
1479 /* wlc_dpc() may bring the driver down */
1480 if (!wl->pub->up)
1481 goto done;
1482
1483 /* re-schedule dpc */
1484 if (wl->resched)
1485 tasklet_schedule(&wl->tasklet);
1486 else {
1487 /* re-enable interrupts */
1488 wl_intrson(wl);
1489 }
1490
1491 done:
1492 WL_UNLOCK(wl);
a9533e7e
HP
1493}
1494
2cb22a7a 1495static void wl_link_up(struct wl_info *wl, char *ifname)
a9533e7e
HP
1496{
1497 WL_ERROR(("wl%d: link up (%s)\n", wl->pub->unit, ifname));
1498}
1499
2cb22a7a 1500static void wl_link_down(struct wl_info *wl, char *ifname)
a9533e7e
HP
1501{
1502 WL_ERROR(("wl%d: link down (%s)\n", wl->pub->unit, ifname));
1503}
1504
2cb22a7a 1505void wl_event(struct wl_info *wl, char *ifname, wlc_event_t *e)
a9533e7e
HP
1506{
1507
1508 switch (e->event.event_type) {
1509 case WLC_E_LINK:
1510 case WLC_E_NDIS_LINK:
1511 if (e->event.flags & WLC_EVENT_MSG_LINK)
1512 wl_link_up(wl, ifname);
1513 else
1514 wl_link_down(wl, ifname);
1515 break;
1516 case WLC_E_RADIO:
1517 break;
1518 }
1519}
1520
3deea904 1521static void wl_timer(unsigned long data)
a9533e7e 1522{
a9533e7e 1523 _wl_timer((wl_timer_t *) data);
a9533e7e
HP
1524}
1525
7cc4a4c0 1526static void _wl_timer(wl_timer_t *t)
a9533e7e
HP
1527{
1528 WL_LOCK(t->wl);
1529
1530 if (t->set) {
1531 if (t->periodic) {
1532 t->timer.expires = jiffies + t->ms * HZ / 1000;
1533 atomic_inc(&t->wl->callbacks);
1534 add_timer(&t->timer);
0f0881b0 1535 t->set = true;
a9533e7e 1536 } else
0965ae88 1537 t->set = false;
a9533e7e
HP
1538
1539 t->fn(t->arg);
1540 }
1541
1542 atomic_dec(&t->wl->callbacks);
1543
1544 WL_UNLOCK(t->wl);
1545}
1546
2cb22a7a 1547wl_timer_t *wl_init_timer(struct wl_info *wl, void (*fn) (void *arg), void *arg,
a9533e7e
HP
1548 const char *name)
1549{
1550 wl_timer_t *t;
1551
5fcc1fcb 1552 t = kmalloc(sizeof(wl_timer_t), GFP_ATOMIC);
ca8c1e59 1553 if (!t) {
97e17d0e 1554 WL_ERROR(("wl%d: wl_init_timer: out of memory\n", wl->pub->unit));
a9533e7e
HP
1555 return 0;
1556 }
1557
9249ede9 1558 memset(t, 0, sizeof(wl_timer_t));
a9533e7e
HP
1559
1560 init_timer(&t->timer);
3deea904 1561 t->timer.data = (unsigned long) t;
a9533e7e
HP
1562 t->timer.function = wl_timer;
1563 t->wl = wl;
1564 t->fn = fn;
1565 t->arg = arg;
1566 t->next = wl->timers;
1567 wl->timers = t;
1568
1569#ifdef BCMDBG
5fcc1fcb 1570 t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC);
ca8c1e59 1571 if (t->name)
a9533e7e
HP
1572 strcpy(t->name, name);
1573#endif
1574
1575 return t;
1576}
1577
1578/* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate
1579 * as well as it's easier to make it periodic
1580 */
2cb22a7a 1581void wl_add_timer(struct wl_info *wl, wl_timer_t *t, uint ms, int periodic)
a9533e7e
HP
1582{
1583#ifdef BCMDBG
1584 if (t->set) {
1585 WL_ERROR(("%s: Already set. Name: %s, per %d\n",
1586 __func__, t->name, periodic));
1587 }
1588#endif
1589 ASSERT(!t->set);
1590
1591 t->ms = ms;
1592 t->periodic = (bool) periodic;
0f0881b0 1593 t->set = true;
a9533e7e
HP
1594 t->timer.expires = jiffies + ms * HZ / 1000;
1595
1596 atomic_inc(&wl->callbacks);
1597 add_timer(&t->timer);
1598}
1599
0965ae88 1600/* return true if timer successfully deleted, false if still pending */
2cb22a7a 1601bool wl_del_timer(struct wl_info *wl, wl_timer_t *t)
a9533e7e
HP
1602{
1603 if (t->set) {
0965ae88 1604 t->set = false;
a9533e7e 1605 if (!del_timer(&t->timer)) {
0965ae88 1606 return false;
a9533e7e
HP
1607 }
1608 atomic_dec(&wl->callbacks);
1609 }
1610
0f0881b0 1611 return true;
a9533e7e
HP
1612}
1613
2cb22a7a 1614void wl_free_timer(struct wl_info *wl, wl_timer_t *t)
a9533e7e
HP
1615{
1616 wl_timer_t *tmp;
1617
1618 /* delete the timer in case it is active */
1619 wl_del_timer(wl, t);
1620
1621 if (wl->timers == t) {
1622 wl->timers = wl->timers->next;
1623#ifdef BCMDBG
1624 if (t->name)
182acb3c 1625 kfree(t->name);
a9533e7e 1626#endif
182acb3c 1627 kfree(t);
a9533e7e
HP
1628 return;
1629
1630 }
1631
1632 tmp = wl->timers;
1633 while (tmp) {
1634 if (tmp->next == t) {
1635 tmp->next = t->next;
1636#ifdef BCMDBG
1637 if (t->name)
182acb3c 1638 kfree(t->name);
a9533e7e 1639#endif
182acb3c 1640 kfree(t);
a9533e7e
HP
1641 return;
1642 }
1643 tmp = tmp->next;
1644 }
1645
1646}
1647
1648static int wl_linux_watchdog(void *ctx)
1649{
2cb22a7a 1650 struct wl_info *wl = (struct wl_info *) ctx;
a9533e7e
HP
1651 struct net_device_stats *stats = NULL;
1652 uint id;
1653 /* refresh stats */
1654 if (wl->pub->up) {
1655 ASSERT(wl->stats_id < 2);
1656
1657 id = 1 - wl->stats_id;
1658
1659 stats = &wl->stats_watchdog[id];
1660 stats->rx_packets = WLCNTVAL(wl->pub->_cnt->rxframe);
1661 stats->tx_packets = WLCNTVAL(wl->pub->_cnt->txframe);
1662 stats->rx_bytes = WLCNTVAL(wl->pub->_cnt->rxbyte);
1663 stats->tx_bytes = WLCNTVAL(wl->pub->_cnt->txbyte);
1664 stats->rx_errors = WLCNTVAL(wl->pub->_cnt->rxerror);
1665 stats->tx_errors = WLCNTVAL(wl->pub->_cnt->txerror);
1666 stats->collisions = 0;
1667
1668 stats->rx_length_errors = 0;
1669 stats->rx_over_errors = WLCNTVAL(wl->pub->_cnt->rxoflo);
1670 stats->rx_crc_errors = WLCNTVAL(wl->pub->_cnt->rxcrc);
1671 stats->rx_frame_errors = 0;
1672 stats->rx_fifo_errors = WLCNTVAL(wl->pub->_cnt->rxoflo);
1673 stats->rx_missed_errors = 0;
1674
1675 stats->tx_fifo_errors = WLCNTVAL(wl->pub->_cnt->txuflo);
1676
1677 wl->stats_id = id;
1678
1679 }
1680
1681 return 0;
1682}
1683
1684struct wl_fw_hdr {
66cbd3ab
GKH
1685 u32 offset;
1686 u32 len;
1687 u32 idx;
a9533e7e
HP
1688};
1689
a9533e7e
HP
1690char *wl_firmwares[WL_MAX_FW] = {
1691 "brcm/bcm43xx",
1692 NULL
1693};
1694
2cb22a7a 1695int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, u32 idx)
a9533e7e
HP
1696{
1697 int i, entry;
41feb5ed 1698 const u8 *pdata;
a9533e7e
HP
1699 struct wl_fw_hdr *hdr;
1700 for (i = 0; i < wl->fw.fw_cnt; i++) {
1701 hdr = (struct wl_fw_hdr *)wl->fw.fw_hdr[i]->data;
1702 for (entry = 0; entry < wl->fw.hdr_num_entries[i];
1703 entry++, hdr++) {
1704 if (hdr->idx == idx) {
1705 pdata = wl->fw.fw_bin[i]->data + hdr->offset;
1706 *pbuf = kmalloc(hdr->len, GFP_ATOMIC);
1707 if (*pbuf == NULL) {
1708 printf("fail to alloc %d bytes\n",
1709 hdr->len);
1710 }
1711 bcopy(pdata, *pbuf, hdr->len);
1712 return 0;
1713 }
1714 }
1715 }
1716 printf("ERROR: ucode buf tag:%d can not be found!\n", idx);
1717 *pbuf = NULL;
1718 return -1;
1719}
1720
2cb22a7a 1721int wl_ucode_init_uint(struct wl_info *wl, u32 *data, u32 idx)
a9533e7e
HP
1722{
1723 int i, entry;
41feb5ed 1724 const u8 *pdata;
a9533e7e
HP
1725 struct wl_fw_hdr *hdr;
1726 for (i = 0; i < wl->fw.fw_cnt; i++) {
1727 hdr = (struct wl_fw_hdr *)wl->fw.fw_hdr[i]->data;
1728 for (entry = 0; entry < wl->fw.hdr_num_entries[i];
1729 entry++, hdr++) {
1730 if (hdr->idx == idx) {
1731 pdata = wl->fw.fw_bin[i]->data + hdr->offset;
1732 ASSERT(hdr->len == 4);
66cbd3ab 1733 *data = *((u32 *) pdata);
a9533e7e
HP
1734 return 0;
1735 }
1736 }
1737 }
1738 printf("ERROR: ucode tag:%d can not be found!\n", idx);
1739 return -1;
1740}
a9533e7e 1741
2cb22a7a 1742static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev)
a9533e7e
HP
1743{
1744 int status;
1745 struct device *device = &pdev->dev;
1746 char fw_name[100];
1747 int i;
1748
9249ede9 1749 memset((void *)&wl->fw, 0, sizeof(struct wl_firmware));
a9533e7e
HP
1750 for (i = 0; i < WL_MAX_FW; i++) {
1751 if (wl_firmwares[i] == NULL)
1752 break;
1753 sprintf(fw_name, "%s-%d.fw", wl_firmwares[i],
1754 UCODE_LOADER_API_VER);
1755 WL_NONE(("request fw %s\n", fw_name));
1756 status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
1757 if (status) {
683b505b
BR
1758 printf("%s: fail to load firmware %s\n",
1759 KBUILD_MODNAME, fw_name);
eb4764c3 1760 wl_release_fw(wl);
a9533e7e
HP
1761 return status;
1762 }
1763 WL_NONE(("request fw %s\n", fw_name));
1764 sprintf(fw_name, "%s_hdr-%d.fw", wl_firmwares[i],
1765 UCODE_LOADER_API_VER);
1766 status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
1767 if (status) {
683b505b
BR
1768 printf("%s: fail to load firmware %s\n",
1769 KBUILD_MODNAME, fw_name);
eb4764c3 1770 wl_release_fw(wl);
a9533e7e
HP
1771 return status;
1772 }
1773 wl->fw.hdr_num_entries[i] =
1774 wl->fw.fw_hdr[i]->size / (sizeof(struct wl_fw_hdr));
1775 WL_NONE(("request fw %s find: %d entries\n", fw_name,
1776 wl->fw.hdr_num_entries[i]));
1777 }
1778 wl->fw.fw_cnt = i;
3d44661a 1779 return wl_ucode_data_init(wl);
a9533e7e
HP
1780}
1781
a9533e7e
HP
1782void wl_ucode_free_buf(void *p)
1783{
1784 kfree(p);
1785}
a9533e7e 1786
2cb22a7a 1787static void wl_release_fw(struct wl_info *wl)
a9533e7e
HP
1788{
1789 int i;
eb4764c3 1790 for (i = 0; i < WL_MAX_FW; i++) {
a9533e7e
HP
1791 release_firmware(wl->fw.fw_bin[i]);
1792 release_firmware(wl->fw.fw_hdr[i]);
1793 }
1794}
3d44661a
RV
1795
1796
1797/*
1798 * checks validity of all firmware images loaded from user space
1799 */
1800int wl_check_firmwares(struct wl_info *wl)
1801{
1802 int i;
1803 int entry;
1804 int rc = 0;
1805 const struct firmware *fw;
1806 const struct firmware *fw_hdr;
1807 struct wl_fw_hdr *ucode_hdr;
1808 for (i = 0; i < WL_MAX_FW && rc == 0; i++) {
1809 fw = wl->fw.fw_bin[i];
1810 fw_hdr = wl->fw.fw_hdr[i];
1811 if (fw == NULL && fw_hdr == NULL) {
1812 break;
1813 } else if (fw == NULL || fw_hdr == NULL) {
1814 WL_ERROR(("%s: invalid bin/hdr fw\n", __func__));
1815 rc = -EBADF;
1816 } else if (fw_hdr->size % sizeof(struct wl_fw_hdr)) {
1817 WL_ERROR(("%s: non integral fw hdr file size %d/%d\n",
1818 __func__, fw_hdr->size,
1819 sizeof(struct wl_fw_hdr)));
1820 rc = -EBADF;
1821 } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) {
1822 WL_ERROR(("%s: out of bounds fw file size %d\n",
1823 __func__, fw->size));
1824 rc = -EBADF;
1825 } else {
1826 /* check if ucode section overruns firmware image */
1827 ucode_hdr = (struct wl_fw_hdr *)fw_hdr->data;
1828 for (entry = 0; entry < wl->fw.hdr_num_entries[i] && rc;
1829 entry++, ucode_hdr++) {
1830 if (ucode_hdr->offset + ucode_hdr->len >
1831 fw->size) {
1832 WL_ERROR(("%s: conflicting bin/hdr\n",
1833 __func__));
1834 rc = -EBADF;
1835 }
1836 }
1837 }
1838 }
1839 if (rc == 0 && wl->fw.fw_cnt != i) {
1840 WL_ERROR(("%s: invalid fw_cnt=%d\n", __func__, wl->fw.fw_cnt));
1841 rc = -EBADF;
1842 }
1843 return rc;
1844}
1845