2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
17 #define __UNDEF_NO_VERSION__
22 #include <linux/module.h>
23 #include <linux/types.h>
24 #include <linux/errno.h>
25 #include <linux/pci.h>
26 #include <linux/init.h>
27 #include <linux/kernel.h>
28 #include <linux/netdevice.h>
29 #include <linux/etherdevice.h>
30 #include <linux/skbuff.h>
31 #include <linux/delay.h>
32 #include <linux/string.h>
33 #include <linux/ethtool.h>
34 #include <linux/completion.h>
35 #include <linux/pci_ids.h>
36 #define WLC_MAXBSSCFG 1 /* single BSS configs */
38 #include <asm/system.h>
41 #include <asm/pgtable.h>
42 #include <asm/uaccess.h>
43 #include <asm/unaligned.h>
45 #include <net/mac80211.h>
48 #include <phy_version.h>
50 #include <bcmendian.h>
55 #include <proto/802.1d.h> /* NUMPRIO & BE */
56 #include <linux/proc_fs.h>
57 #include <linux/vmalloc.h>
58 #include <wlc_channel.h>
65 #include <wl_export.h>
68 #include "bcm_rpc_tp.h"
74 #include <wl_mac80211.h>
75 #include <linux/firmware.h>
78 #include <d11ucode_ext.h>
82 extern struct device
*sdiommc_dev
;
85 extern void wlc_wme_setparams(wlc_info_t
*wlc
, u16 aci
, void *arg
,
87 bool wlc_sendpkt_mac80211(wlc_info_t
*wlc
, void *sdu
, struct ieee80211_hw
*hw
);
88 void wlc_mac_bcn_promisc_change(wlc_info_t
*wlc
, bool promisc
);
89 void wlc_set_addrmatch(wlc_info_t
*wlc
, int match_reg_offset
,
90 const struct ether_addr
*addr
);
92 static void wl_timer(ulong data
);
93 static void _wl_timer(wl_timer_t
*t
);
96 #define RPCQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->rpcq_lock, (_flags))
97 #define RPCQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->rpcq_lock, (_flags))
98 #define TXQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->txq_lock, (_flags))
99 #define TXQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->txq_lock, (_flags))
100 static void wl_rpc_down(void *wlh
);
101 static void wl_rpcq_free(wl_info_t
*wl
);
102 static void wl_rpcq_dispatch(struct wl_task
*task
);
103 static void wl_rpc_dispatch_schedule(void *ctx
, struct rpc_buf
*buf
);
104 static void wl_start_txqwork(struct wl_task
*task
);
105 static void wl_txq_free(wl_info_t
*wl
);
106 static void wl_timer_task(wl_task_t
*task
);
107 static int wl_schedule_task(wl_info_t
*wl
, void (*fn
) (struct wl_task
*),
109 #endif /* WLC_HIGH_ONLY */
111 static int ieee_hw_init(struct ieee80211_hw
*hw
);
112 static int ieee_hw_rate_init(struct ieee80211_hw
*hw
);
114 static int wl_linux_watchdog(void *ctx
);
116 /* Flags we support */
117 #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
123 FIF_BCN_PRBRESP_PROMISC)
127 struct ieee80211_tkip_data
{
128 #define TKIP_KEY_LEN 32
129 u8 key
[TKIP_KEY_LEN
];
144 u32 dot11RSNAStatsTKIPReplays
;
145 u32 dot11RSNAStatsTKIPICVErrors
;
146 u32 dot11RSNAStatsTKIPLocalMICFailures
;
150 struct crypto_tfm
*tfm_arc4
;
151 struct crypto_tfm
*tfm_michael
;
153 /* scratch buffers for virt_to_page() (crypto API) */
154 u8 rx_hdr
[16], tx_hdr
[16];
157 #ifndef WLC_HIGH_ONLY
158 #define WL_INFO(dev) ((wl_info_t *)(WL_DEV_IF(dev)->wl)) /* points to wl */
159 static int wl_request_fw(wl_info_t
*wl
, struct pci_dev
*pdev
);
160 static void wl_release_fw(wl_info_t
*wl
);
163 /* local prototypes */
164 static int wl_start(struct sk_buff
*skb
, wl_info_t
*wl
);
165 static int wl_start_int(wl_info_t
*wl
, struct ieee80211_hw
*hw
,
166 struct sk_buff
*skb
);
167 static void wl_dpc(ulong data
);
169 MODULE_AUTHOR("Broadcom Corporation");
170 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
171 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
172 MODULE_LICENSE("Dual BSD/GPL");
175 /* recognized PCI IDs */
176 static struct pci_device_id wl_id_table
[] = {
177 {PCI_VENDOR_ID_BROADCOM
, 0x4357, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, /* 43225 2G */
178 {PCI_VENDOR_ID_BROADCOM
, 0x4353, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, /* 43224 DUAL */
179 {PCI_VENDOR_ID_BROADCOM
, 0x4727, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, /* 4313 DUAL */
183 MODULE_DEVICE_TABLE(pci
, wl_id_table
);
184 static void wl_remove(struct pci_dev
*pdev
);
185 #endif /* !BCMSDIO */
188 static uint sd_drivestrength
= 6;
189 module_param(sd_drivestrength
, uint
, 0);
193 static int msglevel
= 0xdeadbeef;
194 module_param(msglevel
, int, 0);
195 #ifndef WLC_HIGH_ONLY
196 static int phymsglevel
= 0xdeadbeef;
197 module_param(phymsglevel
, int, 0);
198 #endif /* WLC_HIGH_ONLY */
202 module_param(oneonly
, int, 0);
205 module_param(piomode
, int, 0);
207 static int instance_base
; /* Starting instance number */
208 module_param(instance_base
, int, 0);
211 static char *macaddr
;
212 module_param(macaddr
, charp
, S_IRUGO
);
215 static int nompc
= 1;
216 module_param(nompc
, int, 0);
218 static char name
[IFNAMSIZ
] = "eth%d";
219 module_param_string(name
, name
, IFNAMSIZ
, 0);
225 #define WL_MAGIC 0xdeadbeef
227 #define HW_TO_WL(hw) (hw->priv)
228 #define WL_TO_HW(wl) (wl->pub->ieee_hw)
230 static int wl_ops_tx_nl(struct ieee80211_hw
*hw
, struct sk_buff
*skb
);
232 static int wl_ops_tx(struct ieee80211_hw
*hw
, struct sk_buff
*skb
);
234 static int wl_ops_start(struct ieee80211_hw
*hw
);
235 static void wl_ops_stop(struct ieee80211_hw
*hw
);
236 static int wl_ops_add_interface(struct ieee80211_hw
*hw
,
237 struct ieee80211_vif
*vif
);
238 static void wl_ops_remove_interface(struct ieee80211_hw
*hw
,
239 struct ieee80211_vif
*vif
);
240 static int wl_ops_config(struct ieee80211_hw
*hw
, u32 changed
);
241 static void wl_ops_bss_info_changed(struct ieee80211_hw
*hw
,
242 struct ieee80211_vif
*vif
,
243 struct ieee80211_bss_conf
*info
,
245 static void wl_ops_configure_filter(struct ieee80211_hw
*hw
,
246 unsigned int changed_flags
,
247 unsigned int *total_flags
, u64 multicast
);
248 static int wl_ops_set_tim(struct ieee80211_hw
*hw
, struct ieee80211_sta
*sta
,
250 static void wl_ops_sw_scan_start(struct ieee80211_hw
*hw
);
251 static void wl_ops_sw_scan_complete(struct ieee80211_hw
*hw
);
252 static void wl_ops_set_tsf(struct ieee80211_hw
*hw
, u64 tsf
);
253 static int wl_ops_get_stats(struct ieee80211_hw
*hw
,
254 struct ieee80211_low_level_stats
*stats
);
255 static int wl_ops_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
);
256 static void wl_ops_sta_notify(struct ieee80211_hw
*hw
,
257 struct ieee80211_vif
*vif
,
258 enum sta_notify_cmd cmd
,
259 struct ieee80211_sta
*sta
);
260 static int wl_ops_conf_tx(struct ieee80211_hw
*hw
, u16 queue
,
261 const struct ieee80211_tx_queue_params
*params
);
262 static u64
wl_ops_get_tsf(struct ieee80211_hw
*hw
);
263 static int wl_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
264 struct ieee80211_sta
*sta
);
265 static int wl_sta_remove(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
266 struct ieee80211_sta
*sta
);
267 static int wl_ampdu_action(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
268 enum ieee80211_ampdu_mlme_action action
,
269 struct ieee80211_sta
*sta
, u16 tid
, u16
*ssn
);
272 static int wl_ops_tx_nl(struct ieee80211_hw
*hw
, struct sk_buff
*skb
)
275 wl_info_t
*wl
= hw
->priv
;
277 WL_ERROR(("ops->tx called while down\n"));
281 status
= wl_start(skb
, wl
);
286 static int wl_ops_tx(struct ieee80211_hw
*hw
, struct sk_buff
*skb
)
289 wl_info_t
*wl
= hw
->priv
;
292 WL_ERROR(("ops->tx called while down\n"));
296 status
= wl_start(skb
, wl
);
301 #endif /* WLC_HIGH_ONLY */
303 static int wl_ops_start(struct ieee80211_hw
*hw
)
305 wl_info_t
*wl
= hw
->priv
;
306 /* struct ieee80211_channel *curchan = hw->conf.channel; */
307 WL_NONE(("%s : Initial channel: %d\n", __func__
, curchan
->hw_value
));
310 ieee80211_wake_queues(hw
);
316 static void wl_ops_stop(struct ieee80211_hw
*hw
)
318 wl_info_t
*wl
= hw
->priv
;
322 ieee80211_stop_queues(hw
);
329 wl_ops_add_interface(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
334 /* Just STA for now */
335 if (vif
->type
!= NL80211_IFTYPE_AP
&&
336 vif
->type
!= NL80211_IFTYPE_MESH_POINT
&&
337 vif
->type
!= NL80211_IFTYPE_STATION
&&
338 vif
->type
!= NL80211_IFTYPE_WDS
&&
339 vif
->type
!= NL80211_IFTYPE_ADHOC
) {
340 WL_ERROR(("%s: Attempt to add type %d, only STA for now\n",
341 __func__
, vif
->type
));
351 WL_ERROR(("%s: wl_up() returned %d\n", __func__
, err
));
356 wl_ops_remove_interface(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
362 ieee_set_channel(struct ieee80211_hw
*hw
, struct ieee80211_channel
*chan
,
363 enum nl80211_channel_type type
)
365 wl_info_t
*wl
= HW_TO_WL(hw
);
369 case NL80211_CHAN_HT20
:
370 case NL80211_CHAN_NO_HT
:
372 err
= wlc_set(wl
->wlc
, WLC_SET_CHANNEL
, chan
->hw_value
);
375 case NL80211_CHAN_HT40MINUS
:
376 case NL80211_CHAN_HT40PLUS
:
377 WL_ERROR(("%s: Need to implement 40 Mhz Channels!\n",
387 static int wl_ops_config(struct ieee80211_hw
*hw
, u32 changed
)
389 struct ieee80211_conf
*conf
= &hw
->conf
;
390 wl_info_t
*wl
= HW_TO_WL(hw
);
394 if (changed
& IEEE80211_CONF_CHANGE_LISTEN_INTERVAL
) {
395 WL_NONE(("%s: Setting listen interval to %d\n",
396 __func__
, conf
->listen_interval
));
398 (wl
->wlc
, "bcn_li_bcn", conf
->listen_interval
)) {
399 WL_ERROR(("%s: Error setting listen_interval\n",
404 wlc_iovar_getint(wl
->wlc
, "bcn_li_bcn", &new_int
);
405 ASSERT(new_int
== conf
->listen_interval
);
407 if (changed
& IEEE80211_CONF_CHANGE_MONITOR
)
408 WL_NONE(("Need to set monitor mode\n"));
409 if (changed
& IEEE80211_CONF_CHANGE_PS
)
410 WL_NONE(("Need to set Power-save mode\n"));
412 if (changed
& IEEE80211_CONF_CHANGE_POWER
) {
413 WL_NONE(("%s: Setting tx power to %d dbm\n", __func__
,
416 (wl
->wlc
, "qtxpower", conf
->power_level
* 4)) {
417 WL_ERROR(("%s: Error setting power_level\n", __func__
));
421 wlc_iovar_getint(wl
->wlc
, "qtxpower", &new_int
);
422 if (new_int
!= (conf
->power_level
* 4))
423 WL_ERROR(("%s: Power level req != actual, %d %d\n",
424 __func__
, conf
->power_level
* 4, new_int
));
426 if (changed
& IEEE80211_CONF_CHANGE_CHANNEL
) {
427 err
= ieee_set_channel(hw
, conf
->channel
, conf
->channel_type
);
429 if (changed
& IEEE80211_CONF_CHANGE_RETRY_LIMITS
) {
430 WL_NONE(("%s: srl %d, lrl %d\n", __func__
,
431 conf
->short_frame_max_tx_count
,
432 conf
->long_frame_max_tx_count
));
434 (wl
->wlc
, WLC_SET_SRL
,
435 conf
->short_frame_max_tx_count
) < 0) {
436 WL_ERROR(("%s: Error setting srl\n", __func__
));
440 if (wlc_set(wl
->wlc
, WLC_SET_LRL
, conf
->long_frame_max_tx_count
)
442 WL_ERROR(("%s: Error setting lrl\n", __func__
));
453 wl_ops_bss_info_changed(struct ieee80211_hw
*hw
,
454 struct ieee80211_vif
*vif
,
455 struct ieee80211_bss_conf
*info
, u32 changed
)
457 wl_info_t
*wl
= HW_TO_WL(hw
);
464 if (changed
& BSS_CHANGED_ASSOC
) {
465 WL_ERROR(("Associated:\t%s\n", info
->assoc
? "True" : "False"));
466 /* association status changed (associated/disassociated)
467 * also implies a change in the AID.
470 if (changed
& BSS_CHANGED_ERP_CTS_PROT
) {
471 WL_NONE(("Use_cts_prot:\t%s Implement me\n",
472 info
->use_cts_prot
? "True" : "False"));
473 /* CTS protection changed */
475 if (changed
& BSS_CHANGED_ERP_PREAMBLE
) {
476 WL_NONE(("Short preamble:\t%s Implement me\n",
477 info
->use_short_preamble
? "True" : "False"));
478 /* preamble changed */
480 if (changed
& BSS_CHANGED_ERP_SLOT
) {
481 WL_NONE(("Changing short slot:\t%s\n",
482 info
->use_short_slot
? "True" : "False"));
483 if (info
->use_short_slot
)
487 wlc_set(wl
->wlc
, WLC_SET_SHORTSLOT_OVERRIDE
, val
);
488 /* slot timing changed */
491 if (changed
& BSS_CHANGED_HT
) {
492 WL_NONE(("%s: HT mode - Implement me\n", __func__
));
493 /* 802.11n parameters changed */
495 if (changed
& BSS_CHANGED_BASIC_RATES
) {
496 WL_NONE(("Need to change Basic Rates:\t0x%x! Implement me\n",
497 (uint32
) info
->basic_rates
));
498 /* Basic rateset changed */
500 if (changed
& BSS_CHANGED_BEACON_INT
) {
501 WL_NONE(("Beacon Interval:\t%d Implement me\n",
503 /* Beacon interval changed */
505 if (changed
& BSS_CHANGED_BSSID
) {
506 /* char eabuf[ETHER_ADDR_STR_LEN]; */
507 WL_NONE(("new BSSID:\taid %d bss:%s\n",
509 bcm_ether_ntoa((struct ether_addr
*)info
->bssid
,
511 /* BSSID changed, for whatever reason (IBSS and managed mode) */
512 /* FIXME: need to store bssid in bsscfg */
513 wlc_set_addrmatch(wl
->wlc
, RCM_BSSID_OFFSET
,
514 (struct ether_addr
*)info
->bssid
);
516 if (changed
& BSS_CHANGED_BEACON
) {
517 WL_ERROR(("BSS_CHANGED_BEACON\n"));
518 /* Beacon data changed, retrieve new beacon (beaconing modes) */
520 if (changed
& BSS_CHANGED_BEACON_ENABLED
) {
521 WL_ERROR(("Beacon enabled:\t%s\n",
522 info
->enable_beacon
? "True" : "False"));
523 /* Beaconing should be enabled/disabled (beaconing modes) */
532 wl_ops_configure_filter(struct ieee80211_hw
*hw
,
533 unsigned int changed_flags
,
534 unsigned int *total_flags
, u64 multicast
)
536 #ifndef WLC_HIGH_ONLY
537 wl_info_t
*wl
= hw
->priv
;
540 changed_flags
&= MAC_FILTERS
;
541 *total_flags
&= MAC_FILTERS
;
542 if (changed_flags
& FIF_PROMISC_IN_BSS
)
543 WL_ERROR(("FIF_PROMISC_IN_BSS\n"));
544 if (changed_flags
& FIF_ALLMULTI
)
545 WL_ERROR(("FIF_ALLMULTI\n"));
546 if (changed_flags
& FIF_FCSFAIL
)
547 WL_ERROR(("FIF_FCSFAIL\n"));
548 if (changed_flags
& FIF_PLCPFAIL
)
549 WL_ERROR(("FIF_PLCPFAIL\n"));
550 if (changed_flags
& FIF_CONTROL
)
551 WL_ERROR(("FIF_CONTROL\n"));
552 if (changed_flags
& FIF_OTHER_BSS
)
553 WL_ERROR(("FIF_OTHER_BSS\n"));
554 if (changed_flags
& FIF_BCN_PRBRESP_PROMISC
) {
555 WL_NONE(("FIF_BCN_PRBRESP_PROMISC\n"));
556 #ifndef WLC_HIGH_ONLY
558 if (*total_flags
& FIF_BCN_PRBRESP_PROMISC
) {
559 wl
->pub
->mac80211_state
|= MAC80211_PROMISC_BCNS
;
560 wlc_mac_bcn_promisc_change(wl
->wlc
, 1);
562 wlc_mac_bcn_promisc_change(wl
->wlc
, 0);
563 wl
->pub
->mac80211_state
&= ~MAC80211_PROMISC_BCNS
;
572 wl_ops_set_tim(struct ieee80211_hw
*hw
, struct ieee80211_sta
*sta
, bool set
)
574 WL_ERROR(("%s: Enter\n", __func__
));
578 static void wl_ops_sw_scan_start(struct ieee80211_hw
*hw
)
580 WL_NONE(("Scan Start\n"));
584 static void wl_ops_sw_scan_complete(struct ieee80211_hw
*hw
)
586 WL_NONE(("Scan Complete\n"));
590 static void wl_ops_set_tsf(struct ieee80211_hw
*hw
, u64 tsf
)
592 WL_ERROR(("%s: Enter\n", __func__
));
597 wl_ops_get_stats(struct ieee80211_hw
*hw
,
598 struct ieee80211_low_level_stats
*stats
)
600 WL_ERROR(("%s: Enter\n", __func__
));
604 static int wl_ops_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
)
606 WL_ERROR(("%s: Enter\n", __func__
));
611 wl_ops_sta_notify(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
612 enum sta_notify_cmd cmd
, struct ieee80211_sta
*sta
)
614 WL_NONE(("%s: Enter\n", __func__
));
617 WL_ERROR(("%s: Uknown cmd = %d\n", __func__
, cmd
));
624 wl_ops_conf_tx(struct ieee80211_hw
*hw
, u16 queue
,
625 const struct ieee80211_tx_queue_params
*params
)
627 wl_info_t
*wl
= hw
->priv
;
629 WL_NONE(("%s: Enter (WME config)\n", __func__
));
630 WL_NONE(("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue
,
631 params
->txop
, params
->cw_min
, params
->cw_max
, params
->aifs
));
634 wlc_wme_setparams(wl
->wlc
, queue
, (void *)params
, TRUE
);
640 static u64
wl_ops_get_tsf(struct ieee80211_hw
*hw
)
642 WL_ERROR(("%s: Enter\n", __func__
));
647 wl_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
648 struct ieee80211_sta
*sta
)
653 wl_info_t
*wl
= hw
->priv
;
656 scb
= (struct scb
*)sta
->drv_priv
;
657 bzero(scb
, sizeof(struct scb
));
658 for (i
= 0; i
< NUMPRIO
; i
++)
659 scb
->seqctl
[i
] = 0xFFFF;
660 scb
->seqctl_nonqos
= 0xFFFF;
661 scb
->magic
= SCB_MAGIC
;
663 wl
->pub
->global_scb
= scb
;
664 wl
->pub
->global_ampdu
= &(scb
->scb_ampdu
);
665 wl
->pub
->global_ampdu
->scb
= scb
;
667 wl
->pub
->global_ampdu
->max_pdu
= AMPDU_NUM_MPDU
;
669 wl
->pub
->global_ampdu
->max_pdu
= 16;
671 pktq_init(&scb
->scb_ampdu
.txq
, AMPDU_MAX_SCB_TID
,
672 AMPDU_MAX_SCB_TID
* PKTQ_LEN_DEFAULT
);
674 sta
->ht_cap
.ht_supported
= TRUE
;
676 sta
->ht_cap
.ampdu_factor
= AMPDU_RX_FACTOR_16K
;
678 sta
->ht_cap
.ampdu_factor
= AMPDU_RX_FACTOR_64K
;
680 sta
->ht_cap
.ampdu_density
= AMPDU_DEF_MPDU_DENSITY
;
681 sta
->ht_cap
.cap
= IEEE80211_HT_CAP_GRN_FLD
|
682 IEEE80211_HT_CAP_SGI_20
|
683 IEEE80211_HT_CAP_SGI_40
| IEEE80211_HT_CAP_40MHZ_INTOLERANT
;
685 /* minstrel_ht initiates addBA on our behalf by calling ieee80211_start_tx_ba_session() */
690 wl_sta_remove(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
691 struct ieee80211_sta
*sta
)
693 WL_NONE(("%s: Enter\n", __func__
));
698 wl_ampdu_action(struct ieee80211_hw
*hw
,
699 struct ieee80211_vif
*vif
,
700 enum ieee80211_ampdu_mlme_action action
,
701 struct ieee80211_sta
*sta
, u16 tid
, u16
*ssn
)
704 struct scb
*scb
= (struct scb
*)sta
->drv_priv
;
706 wl_info_t
*wl
= hw
->priv
;
708 ASSERT(scb
->magic
== SCB_MAGIC
);
710 case IEEE80211_AMPDU_RX_START
:
711 WL_NONE(("%s: action = IEEE80211_AMPDU_RX_START\n", __func__
));
713 case IEEE80211_AMPDU_RX_STOP
:
714 WL_NONE(("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__
));
716 case IEEE80211_AMPDU_TX_START
:
717 if (!wlc_aggregatable(wl
->wlc
, tid
)) {
718 /* WL_ERROR(("START: tid %d is not agg' able, return FAILURE to stack\n", tid)); */
721 /* XXX: Use the starting sequence number provided ... */
723 ieee80211_start_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
726 case IEEE80211_AMPDU_TX_STOP
:
727 ieee80211_stop_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
729 case IEEE80211_AMPDU_TX_OPERATIONAL
:
730 /* Not sure what to do here */
731 /* Power save wakeup */
732 WL_NONE(("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n",
736 WL_ERROR(("%s: Invalid command, ignoring\n", __func__
));
742 static const struct ieee80211_ops wl_ops
= {
748 .start
= wl_ops_start
,
750 .add_interface
= wl_ops_add_interface
,
751 .remove_interface
= wl_ops_remove_interface
,
752 .config
= wl_ops_config
,
753 .bss_info_changed
= wl_ops_bss_info_changed
,
754 .configure_filter
= wl_ops_configure_filter
,
755 .set_tim
= wl_ops_set_tim
,
756 .sw_scan_start
= wl_ops_sw_scan_start
,
757 .sw_scan_complete
= wl_ops_sw_scan_complete
,
758 .set_tsf
= wl_ops_set_tsf
,
759 .get_stats
= wl_ops_get_stats
,
760 .set_rts_threshold
= wl_ops_set_rts_threshold
,
761 .sta_notify
= wl_ops_sta_notify
,
762 .conf_tx
= wl_ops_conf_tx
,
763 .get_tsf
= wl_ops_get_tsf
,
764 .sta_add
= wl_sta_add
,
765 .sta_remove
= wl_sta_remove
,
766 .ampdu_action
= wl_ampdu_action
,
769 static int wl_set_hint(wl_info_t
*wl
, char *abbrev
)
771 WL_ERROR(("%s: Sending country code %c%c to MAC80211\n", __func__
,
772 abbrev
[0], abbrev
[1]));
773 return regulatory_hint(wl
->pub
->ieee_hw
->wiphy
, abbrev
);
777 * attach to the WL device.
779 * Attach to the WL device identified by vendor and device parameters.
780 * regs is a host accessible memory address pointing to WL device registers.
782 * wl_attach is not defined as static because in the case where no bus
783 * is defined, wl_attach will never be called, and thus, gcc will issue
784 * a warning that this function is defined but not used if we declare
787 static wl_info_t
*wl_attach(uint16 vendor
, uint16 device
, ulong regs
,
788 uint bustype
, void *btparam
, uint irq
)
795 struct ieee80211_hw
*hw
;
796 uint8 perm
[ETH_ALEN
];
798 unit
= wl_found
+ instance_base
;
802 WL_ERROR(("wl%d: unit number overflow, exiting\n", unit
));
806 if (oneonly
&& (unit
!= instance_base
)) {
807 WL_ERROR(("wl%d: wl_attach: oneonly is set, exiting\n", unit
));
811 /* Requires pkttag feature */
812 osh
= osl_attach(btparam
, bustype
, TRUE
);
816 hw
= ieee80211_alloc_hw(sizeof(wl_info_t
), &wl_ops
);
818 WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__
));
822 bzero(hw
->priv
, sizeof(*wl
));
825 /* allocate private info */
826 hw
= pci_get_drvdata(btparam
); /* btparam == pdev */
831 wl
->magic
= WL_MAGIC
;
833 atomic_set(&wl
->callbacks
, 0);
835 /* setup the bottom half handler */
836 tasklet_init(&wl
->tasklet
, wl_dpc
, (ulong
) wl
);
839 wl
->rpc_th
= bcm_rpc_tp_attach(osh
, NULL
);
840 if (wl
->rpc_th
== NULL
) {
841 WL_ERROR(("wl%d: %s: bcm_rpc_tp_attach failed!\n", unit
,
846 wl
->rpc
= bcm_rpc_attach(NULL
, osh
, wl
->rpc_th
);
847 if (wl
->rpc
== NULL
) {
848 WL_ERROR(("wl%d: %s: bcm_rpc_attach failed!\n", unit
,
853 /* init tx work queue for wl_start/send pkt; no need to destroy workitem */
854 MY_INIT_WORK(&wl
->txq_task
.work
, (work_func_t
) wl_start_txqwork
);
855 wl
->txq_task
.context
= wl
;
856 #endif /* WLC_HIGH_ONLY */
859 SET_IEEE80211_DEV(hw
, sdiommc_dev
);
864 if (bustype
== PCI_BUS
) {
865 /* piomode can be overwritten by command argument */
866 wl
->piomode
= piomode
;
867 WL_TRACE(("PCI/%s\n", wl
->piomode
? "PIO" : "DMA"));
868 } else if (bustype
== RPC_BUS
) {
872 WL_TRACE(("force to PCI\n"));
874 wl
->bcm_bustype
= bustype
;
877 if (wl
->bcm_bustype
== RPC_BUS
) {
878 wl
->regsva
= (void *)0;
882 wl
->regsva
= ioremap_nocache(base_addr
, PCI_BAR0_WINSZ
);
883 if (wl
->regsva
== NULL
) {
884 WL_ERROR(("wl%d: ioremap() failed\n", unit
));
888 spin_lock_init(&wl
->rpcq_lock
);
889 spin_lock_init(&wl
->txq_lock
);
891 init_MUTEX(&wl
->sem
);
893 spin_lock_init(&wl
->lock
);
894 spin_lock_init(&wl
->isr_lock
);
897 #ifndef WLC_HIGH_ONLY
899 if (wl_request_fw(wl
, (struct pci_dev
*)btparam
)) {
900 printf("%s: Failed to find firmware usually in %s\n",
901 KBUILD_MODNAME
, "/lib/firmware/brcm");
903 wl_remove((struct pci_dev
*)btparam
);
908 /* common load-time initialization */
909 wl
->wlc
= wlc_attach((void *)wl
, vendor
, device
, unit
, wl
->piomode
, osh
,
910 wl
->regsva
, wl
->bcm_bustype
, btparam
, &err
);
911 #ifndef WLC_HIGH_ONLY
915 printf("%s: %s wlc_attach() failed with code %d\n",
916 KBUILD_MODNAME
, EPI_VERSION_STR
, err
);
919 wl
->pub
= wlc_pub(wl
->wlc
);
921 wl
->pub
->ieee_hw
= hw
;
922 ASSERT(wl
->pub
->ieee_hw
);
923 ASSERT(wl
->pub
->ieee_hw
->priv
== wl
);
926 REGOPSSET(osh
, (osl_rreg_fn_t
) wlc_reg_read
,
927 (osl_wreg_fn_t
) wlc_reg_write
, wl
->wlc
);
928 wl
->rpc_dispatch_ctx
.rpc
= wl
->rpc
;
929 wl
->rpc_dispatch_ctx
.wlc
= wl
->wlc
;
930 bcm_rpc_rxcb_init(wl
->rpc
, wl
, wl_rpc_dispatch_schedule
, wl
,
931 wl_rpc_down
, NULL
, NULL
);
932 #endif /* WLC_HIGH_ONLY */
935 if (wlc_iovar_setint(wl
->wlc
, "mpc", 0)) {
936 WL_ERROR(("wl%d: Error setting MPC variable to 0\n",
941 /* Set SDIO drive strength */
942 wlc_iovar_setint(wl
->wlc
, "sd_drivestrength", sd_drivestrength
);
946 /* register our interrupt handler */
947 if (request_irq(irq
, wl_isr
, IRQF_SHARED
, KBUILD_MODNAME
, wl
)) {
948 WL_ERROR(("wl%d: request_irq() failed\n", unit
));
954 /* register module */
955 wlc_module_register(wl
->pub
, NULL
, "linux", wl
, NULL
, wl_linux_watchdog
,
958 if (ieee_hw_init(hw
)) {
959 WL_ERROR(("wl%d: %s: ieee_hw_init failed!\n", unit
, __func__
));
963 bcopy(&wl
->pub
->cur_etheraddr
, perm
, ETHER_ADDR_LEN
);
964 ASSERT(is_valid_ether_addr(perm
));
965 SET_IEEE80211_PERM_ADDR(hw
, perm
);
967 err
= ieee80211_register_hw(hw
);
969 WL_ERROR(("%s: ieee80211_register_hw failed, status %d\n",
973 if (wl
->pub
->srom_ccode
[0])
974 err
= wl_set_hint(wl
, wl
->pub
->srom_ccode
);
976 err
= wl_set_hint(wl
, "US");
978 WL_ERROR(("%s: regulatory_hint failed, status %d\n", __func__
,
981 #ifndef WLC_HIGH_ONLY
982 WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
983 EPI_VERSION_STR
" (" PHY_VERSION_STR
")", unit
));
985 WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
986 EPI_VERSION_STR
, unit
));
990 printf(" (Compiled in " SRCBASE
" at " __TIME__
" on " __DATE__
")");
1003 #ifdef WLC_HIGH_ONLY
1004 static void *wl_dbus_probe_cb(void *arg
, const char *desc
, uint32 bustype
,
1008 WL_ERROR(("%s:\n", __func__
));
1010 wl
= wl_attach(BCM_DNGL_VID
, BCM_DNGL_BDC_PID
, (ulong
) NULL
, RPC_BUS
,
1013 WL_ERROR(("%s: wl_attach failed\n", __func__
));
1016 /* This is later passed to wl_dbus_disconnect_cb */
1020 static void wl_dbus_disconnect_cb(void *arg
)
1022 wl_info_t
*wl
= arg
;
1024 WL_ERROR(("%s:\n", __func__
));
1027 #ifdef WLC_HIGH_ONLY
1028 if (wl
->pub
->ieee_hw
) {
1029 ieee80211_unregister_hw(wl
->pub
->ieee_hw
);
1030 WL_ERROR(("%s: Back from down\n", __func__
));
1032 wlc_device_removed(wl
->wlc
);
1033 wlc_bmac_dngl_reboot(wl
->rpc
);
1034 bcm_rpc_down(wl
->rpc
);
1039 #ifdef WLC_HIGH_ONLY
1040 if (wl
->pub
->ieee_hw
) {
1041 ieee80211_free_hw(wl
->pub
->ieee_hw
);
1042 WL_ERROR(("%s: Back from ieee80211_free_hw\n",
1044 wl
->pub
->ieee_hw
= NULL
;
1050 #endif /* WLC_HIGH_ONLY */
1053 #define CHAN2GHZ(channel, freqency, chflags) { \
1054 .band = IEEE80211_BAND_2GHZ, \
1055 .center_freq = (freqency), \
1056 .hw_value = (channel), \
1058 .max_antenna_gain = 0, \
1062 static struct ieee80211_channel wl_2ghz_chantable
[] = {
1063 CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS
),
1064 CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS
),
1065 CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS
),
1066 CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS
),
1067 CHAN2GHZ(5, 2432, 0),
1068 CHAN2GHZ(6, 2437, 0),
1069 CHAN2GHZ(7, 2442, 0),
1070 CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS
),
1071 CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS
),
1072 CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS
),
1073 CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS
),
1075 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_IBSS
|
1076 IEEE80211_CHAN_NO_HT40PLUS
),
1078 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_IBSS
|
1079 IEEE80211_CHAN_NO_HT40PLUS
),
1081 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_IBSS
|
1082 IEEE80211_CHAN_NO_HT40PLUS
| IEEE80211_CHAN_NO_HT40MINUS
)
1085 #define CHAN5GHZ(channel, chflags) { \
1086 .band = IEEE80211_BAND_5GHZ, \
1087 .center_freq = 5000 + 5*(channel), \
1088 .hw_value = (channel), \
1090 .max_antenna_gain = 0, \
1094 static struct ieee80211_channel wl_5ghz_nphy_chantable
[] = {
1096 CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS
),
1097 CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS
),
1098 CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS
),
1099 CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS
),
1102 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1103 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1105 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1106 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1108 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1109 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1111 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1112 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1115 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1116 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1118 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1119 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1121 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1122 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1124 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1125 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1127 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1128 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1130 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1131 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1133 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1134 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1136 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1137 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1139 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1140 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1142 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1143 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1145 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1146 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
|
1147 IEEE80211_CHAN_NO_HT40MINUS
),
1149 CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS
),
1150 CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS
),
1151 CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS
),
1152 CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS
),
1153 CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS
| IEEE80211_CHAN_NO_HT40MINUS
)
1156 #define RATE(rate100m, _flags) { \
1157 .bitrate = (rate100m), \
1158 .flags = (_flags), \
1159 .hw_value = (rate100m / 5), \
1162 static struct ieee80211_rate wl_legacy_ratetable
[] = {
1164 RATE(20, IEEE80211_RATE_SHORT_PREAMBLE
),
1165 RATE(55, IEEE80211_RATE_SHORT_PREAMBLE
),
1166 RATE(110, IEEE80211_RATE_SHORT_PREAMBLE
),
1177 static struct ieee80211_supported_band wl_band_2GHz_nphy
= {
1178 .band
= IEEE80211_BAND_2GHZ
,
1179 .channels
= wl_2ghz_chantable
,
1180 .n_channels
= ARRAY_SIZE(wl_2ghz_chantable
),
1181 .bitrates
= wl_legacy_ratetable
,
1182 .n_bitrates
= ARRAY_SIZE(wl_legacy_ratetable
),
1184 /* from include/linux/ieee80211.h */
1185 .cap
= IEEE80211_HT_CAP_GRN_FLD
|
1186 IEEE80211_HT_CAP_SGI_20
|
1187 IEEE80211_HT_CAP_SGI_40
| IEEE80211_HT_CAP_40MHZ_INTOLERANT
,
1188 #ifdef WLC_HIGH_ONLY
1189 .ht_supported
= true,
1190 .ampdu_factor
= AMPDU_RX_FACTOR_16K
,
1192 .ht_supported
= true,
1193 .ampdu_factor
= AMPDU_RX_FACTOR_64K
,
1195 .ampdu_density
= AMPDU_DEF_MPDU_DENSITY
,
1197 /* placeholders for now */
1198 #ifdef WLC_HIGH_ONLY
1200 * rx_mask[0] = 0xff by default
1201 * rx_mask[1] = 0xff if number of rx chain >=2
1202 * rx_mask[2] = 0xff if number of rx chain >=3
1203 * rx_mask[4] = 1 if 40Mhz is supported
1205 .rx_mask
= {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1206 .rx_highest
= 72, /* max rate of single stream */
1208 .rx_mask
= {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
1211 .tx_params
= IEEE80211_HT_MCS_TX_DEFINED
}
1215 static struct ieee80211_supported_band wl_band_5GHz_nphy
= {
1216 .band
= IEEE80211_BAND_5GHZ
,
1217 .channels
= wl_5ghz_nphy_chantable
,
1218 .n_channels
= ARRAY_SIZE(wl_5ghz_nphy_chantable
),
1219 .bitrates
= wl_legacy_ratetable
+ 4,
1220 .n_bitrates
= ARRAY_SIZE(wl_legacy_ratetable
) - 4,
1222 /* use IEEE80211_HT_CAP_* from include/linux/ieee80211.h */
1223 .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 */
1224 .ht_supported
= true,
1225 .ampdu_factor
= AMPDU_RX_FACTOR_64K
,
1226 .ampdu_density
= AMPDU_DEF_MPDU_DENSITY
,
1228 /* placeholders for now */
1229 .rx_mask
= {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
1231 .tx_params
= IEEE80211_HT_MCS_TX_DEFINED
}
1235 static int ieee_hw_rate_init(struct ieee80211_hw
*hw
)
1237 wl_info_t
*wl
= HW_TO_WL(hw
);
1243 hw
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = NULL
;
1244 hw
->wiphy
->bands
[IEEE80211_BAND_5GHZ
] = NULL
;
1246 if (wlc_get(wl
->wlc
, WLC_GET_PHYLIST
, (int *)&phy_list
) < 0) {
1247 WL_ERROR(("Phy list failed\n"));
1249 WL_NONE(("%s: phylist = %c\n", __func__
, phy_list
[0]));
1251 #ifndef WLC_HIGH_ONLY
1252 if (phy_list
[0] == 'n' || phy_list
[0] == 'c') {
1253 if (phy_list
[0] == 'c') {
1255 wl_band_2GHz_nphy
.ht_cap
.mcs
.rx_mask
[1] = 0;
1256 wl_band_2GHz_nphy
.ht_cap
.mcs
.rx_highest
= 72;
1259 if (phy_list
[0] == 's') {
1261 hw
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &wl_band_2GHz_nphy
;
1267 /* Assume all bands use the same phy. True for 11n devices. */
1268 if (NBANDS_PUB(wl
->pub
) > 1) {
1270 #ifndef WLC_HIGH_ONLY
1271 if (phy_list
[0] == 'n' || phy_list
[0] == 'c') {
1273 if (phy_list
[0] == 's') {
1275 hw
->wiphy
->bands
[IEEE80211_BAND_5GHZ
] =
1282 WL_NONE(("%s: 2ghz = %d, 5ghz = %d\n", __func__
, 1, has_5g
));
1287 static int ieee_hw_init(struct ieee80211_hw
*hw
)
1289 hw
->flags
= IEEE80211_HW_SIGNAL_DBM
1290 /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
1291 | IEEE80211_HW_REPORTS_TX_ACK_STATUS
1292 | IEEE80211_HW_AMPDU_AGGREGATION
;
1294 hw
->extra_tx_headroom
= wlc_get_header_len();
1295 /* FIXME: should get this from wlc->machwcap */
1297 /* FIXME: this doesn't seem to be used properly in minstrel_ht.
1298 * mac80211/status.c:ieee80211_tx_status() checks this value,
1299 * but mac80211/rc80211_minstrel_ht.c:minstrel_ht_get_rate()
1300 * appears to always set 3 rates
1302 hw
->max_rates
= 2; /* Primary rate and 1 fallback rate */
1304 hw
->channel_change_time
= 7 * 1000; /* channel change time is dependant on chip and band */
1305 hw
->wiphy
->interface_modes
= BIT(NL80211_IFTYPE_STATION
);
1307 hw
->rate_control_algorithm
= "minstrel_ht";
1309 hw
->sta_data_size
= sizeof(struct scb
);
1310 return ieee_hw_rate_init(hw
);
1315 * determines if a device is a WL device, and if so, attaches it.
1317 * This function determines if a device pointed to by pdev is a WL device,
1318 * and if so, performs a wl_attach() on it.
1322 wl_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*ent
)
1326 struct ieee80211_hw
*hw
;
1331 WL_TRACE(("%s: bus %d slot %d func %d irq %d\n", __func__
,
1332 pdev
->bus
->number
, PCI_SLOT(pdev
->devfn
),
1333 PCI_FUNC(pdev
->devfn
), pdev
->irq
));
1335 if ((pdev
->vendor
!= PCI_VENDOR_ID_BROADCOM
) ||
1336 (((pdev
->device
& 0xff00) != 0x4300) &&
1337 ((pdev
->device
& 0xff00) != 0x4700) &&
1338 ((pdev
->device
< 43000) || (pdev
->device
> 43999))))
1341 rc
= pci_enable_device(pdev
);
1343 WL_ERROR(("%s: Cannot enable device %d-%d_%d\n", __func__
,
1344 pdev
->bus
->number
, PCI_SLOT(pdev
->devfn
),
1345 PCI_FUNC(pdev
->devfn
)));
1348 pci_set_master(pdev
);
1350 pci_read_config_dword(pdev
, 0x40, &val
);
1351 if ((val
& 0x0000ff00) != 0)
1352 pci_write_config_dword(pdev
, 0x40, val
& 0xffff00ff);
1354 hw
= ieee80211_alloc_hw(sizeof(wl_info_t
), &wl_ops
);
1356 WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__
));
1361 SET_IEEE80211_DEV(hw
, &pdev
->dev
);
1363 pci_set_drvdata(pdev
, hw
);
1365 bzero(hw
->priv
, sizeof(*wl
));
1367 wl
= wl_attach(pdev
->vendor
, pdev
->device
, pci_resource_start(pdev
, 0),
1368 PCI_BUS
, pdev
, pdev
->irq
);
1371 WL_ERROR(("%s: %s: wl_attach failed!\n",
1372 KBUILD_MODNAME
, __func__
));
1377 WL_ERROR(("%s: err_1: Major hoarkage\n", __func__
));
1382 static int wl_suspend(struct pci_dev
*pdev
, DRV_SUSPEND_STATE_TYPE state
)
1385 struct ieee80211_hw
*hw
;
1387 WL_TRACE(("wl: wl_suspend\n"));
1389 hw
= pci_get_drvdata(pdev
);
1392 WL_ERROR(("wl: wl_suspend: pci_get_drvdata failed\n"));
1398 wl
->pub
->hw_up
= FALSE
;
1400 PCI_SAVE_STATE(pdev
, wl
->pci_psstate
);
1401 pci_disable_device(pdev
);
1402 return pci_set_power_state(pdev
, PCI_D3hot
);
1405 static int wl_resume(struct pci_dev
*pdev
)
1408 struct ieee80211_hw
*hw
;
1412 WL_TRACE(("wl: wl_resume\n"));
1413 hw
= pci_get_drvdata(pdev
);
1416 WL_ERROR(("wl: wl_resume: pci_get_drvdata failed\n"));
1420 err
= pci_set_power_state(pdev
, PCI_D0
);
1424 PCI_RESTORE_STATE(pdev
, wl
->pci_psstate
);
1426 err
= pci_enable_device(pdev
);
1430 pci_set_master(pdev
);
1432 pci_read_config_dword(pdev
, 0x40, &val
);
1433 if ((val
& 0x0000ff00) != 0)
1434 pci_write_config_dword(pdev
, 0x40, val
& 0xffff00ff);
1442 #endif /* LINUXSTA_PS */
1444 static void wl_remove(struct pci_dev
*pdev
)
1447 struct ieee80211_hw
*hw
;
1449 hw
= pci_get_drvdata(pdev
);
1452 WL_ERROR(("wl: wl_remove: pci_get_drvdata failed\n"));
1455 if (!wlc_chipmatch(pdev
->vendor
, pdev
->device
)) {
1456 WL_ERROR(("wl: wl_remove: wlc_chipmatch failed\n"));
1460 ieee80211_unregister_hw(hw
);
1464 WL_NONE(("%s: Down\n", __func__
));
1466 pci_disable_device(pdev
);
1470 pci_set_drvdata(pdev
, NULL
);
1471 ieee80211_free_hw(hw
);
1474 static struct pci_driver wl_pci_driver
= {
1475 .name
= "brcm80211",
1476 .probe
= wl_pci_probe
,
1478 .suspend
= wl_suspend
,
1479 .resume
= wl_resume
,
1480 #endif /* LINUXSTA_PS */
1481 .remove
= __devexit_p(wl_remove
),
1482 .id_table
= wl_id_table
,
1484 #endif /* !BCMSDIO */
1487 * This is the main entry point for the WL driver.
1489 * This function determines if a device pointed to by pdev is a WL device,
1490 * and if so, performs a wl_attach() on it.
1493 static int __init
wl_module_init(void)
1495 int error
= -ENODEV
;
1498 if (msglevel
!= 0xdeadbeef)
1499 wl_msg_level
= msglevel
;
1501 char *var
= getvar(NULL
, "wl_msglevel");
1503 wl_msg_level
= simple_strtoul(var
, NULL
, 0);
1505 #ifndef WLC_HIGH_ONLY
1507 extern uint32 phyhal_msg_level
;
1509 if (phymsglevel
!= 0xdeadbeef)
1510 phyhal_msg_level
= phymsglevel
;
1512 char *var
= getvar(NULL
, "phy_msglevel");
1514 phyhal_msg_level
= simple_strtoul(var
, NULL
, 0);
1517 #endif /* WLC_HIGH_ONLY */
1521 error
= pci_module_init(&wl_pci_driver
);
1525 #endif /* !BCMSDIO */
1527 #ifdef WLC_HIGH_ONLY
1528 /* BMAC_NOTE: define hardcode number, why NODEVICE is ok ? */
1530 dbus_register(BCM_DNGL_VID
, 0, wl_dbus_probe_cb
,
1531 wl_dbus_disconnect_cb
, NULL
, NULL
, NULL
);
1532 if (error
== DBUS_ERR_NODEVICE
) {
1535 #endif /* WLC_HIGH_ONLY */
1541 * This function unloads the WL driver from the system.
1543 * This function unconditionally unloads the WL driver module from the
1547 static void __exit
wl_module_exit(void)
1550 pci_unregister_driver(&wl_pci_driver
);
1551 #endif /* !BCMSDIO */
1553 #ifdef WLC_HIGH_ONLY
1555 #endif /* WLC_HIGH_ONLY */
1558 module_init(wl_module_init
);
1559 module_exit(wl_module_exit
);
1562 * This function frees the WL per-device resources.
1564 * This function frees resources owned by the WL device pointed to
1565 * by the wl parameter.
1568 void wl_free(wl_info_t
*wl
)
1570 wl_timer_t
*t
, *next
;
1574 #ifndef WLC_HIGH_ONLY
1575 /* free ucode data */
1577 wl_ucode_data_free();
1579 free_irq(wl
->irq
, wl
);
1583 tasklet_kill(&wl
->tasklet
);
1586 wlc_module_unregister(wl
->pub
, "linux", wl
);
1589 /* free common resources */
1591 wlc_detach(wl
->wlc
);
1596 /* virtual interface deletion is deferred so we cannot spinwait */
1598 /* wait for all pending callbacks to complete */
1599 while (atomic_read(&wl
->callbacks
) > 0)
1603 for (t
= wl
->timers
; t
; t
= next
) {
1607 MFREE(wl
->osh
, t
->name
, strlen(t
->name
) + 1);
1609 MFREE(wl
->osh
, t
, sizeof(wl_timer_t
));
1615 * unregister_netdev() calls get_stats() which may read chip registers
1616 * so we cannot unmap the chip registers until after calling unregister_netdev() .
1618 if (wl
->regsva
&& BUSTYPE(wl
->bcm_bustype
) != SDIO_BUS
&&
1619 BUSTYPE(wl
->bcm_bustype
) != JTAG_BUS
) {
1620 iounmap((void *)wl
->regsva
);
1624 #ifdef WLC_HIGH_ONLY
1630 bcm_rpc_detach(wl
->rpc
);
1635 bcm_rpc_tp_detach(wl
->rpc_th
);
1638 #endif /* WLC_HIGH_ONLY */
1640 if (osl_malloced(osh
)) {
1641 printf("**** Memory leak of bytes %d\n", osl_malloced(osh
));
1642 ASSERT(0 && "Memory Leak");
1649 /* transmit a packet */
1650 static int BCMFASTPATH
wl_start(struct sk_buff
*skb
, wl_info_t
*wl
)
1655 return wl_start_int(wl
, WL_TO_HW(wl
), skb
);
1657 #endif /* WLC_LOW */
1659 static int BCMFASTPATH
1660 wl_start_int(wl_info_t
*wl
, struct ieee80211_hw
*hw
, struct sk_buff
*skb
)
1662 #ifdef WLC_HIGH_ONLY
1665 wlc_sendpkt_mac80211(wl
->wlc
, skb
, hw
);
1666 #ifdef WLC_HIGH_ONLY
1669 return NETDEV_TX_OK
;
1672 void wl_txflowcontrol(wl_info_t
*wl
, struct wl_if
*wlif
, bool state
, int prio
)
1674 WL_ERROR(("Shouldn't be here %s\n", __func__
));
1677 #if defined(WLC_HIGH_ONLY)
1678 /* Schedule a completion handler to run at safe time */
1680 wl_schedule_task(wl_info_t
*wl
, void (*fn
) (struct wl_task
*task
),
1685 WL_TRACE(("wl%d: wl_schedule_task\n", wl
->pub
->unit
));
1687 task
= osl_malloc(wl
->osh
, sizeof(wl_task_t
));
1689 WL_ERROR(("wl%d: wl_schedule_task: out of memory, malloced %d bytes\n", wl
->pub
->unit
, osl_malloced(wl
->osh
)));
1693 MY_INIT_WORK(&task
->work
, (work_func_t
) fn
);
1694 task
->context
= context
;
1696 if (!schedule_work(&task
->work
)) {
1697 WL_ERROR(("wl%d: schedule_work() failed\n", wl
->pub
->unit
));
1698 MFREE(wl
->osh
, task
, sizeof(wl_task_t
));
1702 atomic_inc(&wl
->callbacks
);
1706 #endif /* defined(WLC_HIGH_ONLY) */
1708 void wl_init(wl_info_t
*wl
)
1710 WL_TRACE(("wl%d: wl_init\n", wl
->pub
->unit
));
1717 uint
wl_reset(wl_info_t
*wl
)
1719 WL_TRACE(("wl%d: wl_reset\n", wl
->pub
->unit
));
1723 /* dpc will not be rescheduled */
1730 * These are interrupt on/off entry points. Disable interrupts
1731 * during interrupt state transition.
1733 void BCMFASTPATH
wl_intrson(wl_info_t
*wl
)
1735 #if defined(WLC_LOW)
1736 unsigned long flags
;
1738 INT_LOCK(wl
, flags
);
1739 wlc_intrson(wl
->wlc
);
1740 INT_UNLOCK(wl
, flags
);
1741 #endif /* WLC_LOW */
1744 bool wl_alloc_dma_resources(wl_info_t
*wl
, uint addrwidth
)
1749 uint32 BCMFASTPATH
wl_intrsoff(wl_info_t
*wl
)
1751 #if defined(WLC_LOW)
1752 unsigned long flags
;
1755 INT_LOCK(wl
, flags
);
1756 status
= wlc_intrsoff(wl
->wlc
);
1757 INT_UNLOCK(wl
, flags
);
1761 #endif /* WLC_LOW */
1764 void wl_intrsrestore(wl_info_t
*wl
, uint32 macintmask
)
1766 #if defined(WLC_LOW)
1767 unsigned long flags
;
1769 INT_LOCK(wl
, flags
);
1770 wlc_intrsrestore(wl
->wlc
, macintmask
);
1771 INT_UNLOCK(wl
, flags
);
1772 #endif /* WLC_LOW */
1775 int wl_up(wl_info_t
*wl
)
1782 error
= wlc_up(wl
->wlc
);
1787 void wl_down(wl_info_t
*wl
)
1789 uint callbacks
, ret_val
= 0;
1791 /* call common down function */
1792 ret_val
= wlc_down(wl
->wlc
);
1793 callbacks
= atomic_read(&wl
->callbacks
) - ret_val
;
1795 /* wait for down callbacks to complete */
1798 #ifndef WLC_HIGH_ONLY
1799 /* For HIGH_only driver, it's important to actually schedule other work,
1800 * not just spin wait since everything runs at schedule level
1802 SPINWAIT((atomic_read(&wl
->callbacks
) > callbacks
), 100 * 1000);
1803 #endif /* WLC_HIGH_ONLY */
1808 irqreturn_t BCMFASTPATH
wl_isr(int irq
, void *dev_id
)
1810 #if defined(WLC_LOW)
1813 unsigned long flags
;
1815 wl
= (wl_info_t
*) dev_id
;
1817 WL_ISRLOCK(wl
, flags
);
1819 /* call common first level interrupt handler */
1820 ours
= wlc_isr(wl
->wlc
, &wantdpc
);
1822 /* if more to do... */
1825 /* ...and call the second level interrupt handler */
1827 ASSERT(wl
->resched
== FALSE
);
1828 tasklet_schedule(&wl
->tasklet
);
1832 WL_ISRUNLOCK(wl
, flags
);
1834 return IRQ_RETVAL(ours
);
1836 return IRQ_RETVAL(0);
1837 #endif /* WLC_LOW */
1840 static void BCMFASTPATH
wl_dpc(ulong data
)
1845 wl
= (wl_info_t
*) data
;
1849 /* call the common second level interrupt handler */
1852 unsigned long flags
;
1854 INT_LOCK(wl
, flags
);
1855 wlc_intrsupd(wl
->wlc
);
1856 INT_UNLOCK(wl
, flags
);
1859 wl
->resched
= wlc_dpc(wl
->wlc
, TRUE
);
1862 /* wlc_dpc() may bring the driver down */
1866 /* re-schedule dpc */
1868 tasklet_schedule(&wl
->tasklet
);
1870 /* re-enable interrupts */
1876 #endif /* WLC_LOW */
1879 static void wl_link_up(wl_info_t
*wl
, char *ifname
)
1881 WL_ERROR(("wl%d: link up (%s)\n", wl
->pub
->unit
, ifname
));
1884 static void wl_link_down(wl_info_t
*wl
, char *ifname
)
1886 WL_ERROR(("wl%d: link down (%s)\n", wl
->pub
->unit
, ifname
));
1889 void wl_event(wl_info_t
*wl
, char *ifname
, wlc_event_t
*e
)
1892 switch (e
->event
.event_type
) {
1894 case WLC_E_NDIS_LINK
:
1895 if (e
->event
.flags
& WLC_EVENT_MSG_LINK
)
1896 wl_link_up(wl
, ifname
);
1898 wl_link_down(wl
, ifname
);
1905 static void wl_timer(ulong data
)
1907 #ifndef WLC_HIGH_ONLY
1908 _wl_timer((wl_timer_t
*) data
);
1910 wl_timer_t
*t
= (wl_timer_t
*) data
;
1911 wl_schedule_task(t
->wl
, wl_timer_task
, t
);
1912 #endif /* WLC_HIGH_ONLY */
1915 static void _wl_timer(wl_timer_t
*t
)
1921 t
->timer
.expires
= jiffies
+ t
->ms
* HZ
/ 1000;
1922 atomic_inc(&t
->wl
->callbacks
);
1923 add_timer(&t
->timer
);
1931 atomic_dec(&t
->wl
->callbacks
);
1936 wl_timer_t
*wl_init_timer(wl_info_t
*wl
, void (*fn
) (void *arg
), void *arg
,
1941 t
= osl_malloc(wl
->osh
, sizeof(wl_timer_t
));
1943 WL_ERROR(("wl%d: wl_init_timer: out of memory, malloced %d bytes\n", wl
->pub
->unit
, osl_malloced(wl
->osh
)));
1947 bzero(t
, sizeof(wl_timer_t
));
1949 init_timer(&t
->timer
);
1950 t
->timer
.data
= (ulong
) t
;
1951 t
->timer
.function
= wl_timer
;
1955 t
->next
= wl
->timers
;
1959 t
->name
= osl_malloc(wl
->osh
, strlen(name
) + 1);
1961 strcpy(t
->name
, name
);
1967 /* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate
1968 * as well as it's easier to make it periodic
1970 void wl_add_timer(wl_info_t
*wl
, wl_timer_t
*t
, uint ms
, int periodic
)
1974 WL_ERROR(("%s: Already set. Name: %s, per %d\n",
1975 __func__
, t
->name
, periodic
));
1981 t
->periodic
= (bool) periodic
;
1983 t
->timer
.expires
= jiffies
+ ms
* HZ
/ 1000;
1985 atomic_inc(&wl
->callbacks
);
1986 add_timer(&t
->timer
);
1989 /* return TRUE if timer successfully deleted, FALSE if still pending */
1990 bool wl_del_timer(wl_info_t
*wl
, wl_timer_t
*t
)
1994 if (!del_timer(&t
->timer
)) {
1997 atomic_dec(&wl
->callbacks
);
2003 void wl_free_timer(wl_info_t
*wl
, wl_timer_t
*t
)
2007 /* delete the timer in case it is active */
2008 wl_del_timer(wl
, t
);
2010 if (wl
->timers
== t
) {
2011 wl
->timers
= wl
->timers
->next
;
2014 MFREE(wl
->osh
, t
->name
, strlen(t
->name
) + 1);
2016 MFREE(wl
->osh
, t
, sizeof(wl_timer_t
));
2023 if (tmp
->next
== t
) {
2024 tmp
->next
= t
->next
;
2027 MFREE(wl
->osh
, t
->name
, strlen(t
->name
) + 1);
2029 MFREE(wl
->osh
, t
, sizeof(wl_timer_t
));
2037 static int wl_linux_watchdog(void *ctx
)
2039 wl_info_t
*wl
= (wl_info_t
*) ctx
;
2040 struct net_device_stats
*stats
= NULL
;
2044 ASSERT(wl
->stats_id
< 2);
2046 id
= 1 - wl
->stats_id
;
2048 stats
= &wl
->stats_watchdog
[id
];
2049 stats
->rx_packets
= WLCNTVAL(wl
->pub
->_cnt
->rxframe
);
2050 stats
->tx_packets
= WLCNTVAL(wl
->pub
->_cnt
->txframe
);
2051 stats
->rx_bytes
= WLCNTVAL(wl
->pub
->_cnt
->rxbyte
);
2052 stats
->tx_bytes
= WLCNTVAL(wl
->pub
->_cnt
->txbyte
);
2053 stats
->rx_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxerror
);
2054 stats
->tx_errors
= WLCNTVAL(wl
->pub
->_cnt
->txerror
);
2055 stats
->collisions
= 0;
2057 stats
->rx_length_errors
= 0;
2058 stats
->rx_over_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxoflo
);
2059 stats
->rx_crc_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxcrc
);
2060 stats
->rx_frame_errors
= 0;
2061 stats
->rx_fifo_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxoflo
);
2062 stats
->rx_missed_errors
= 0;
2064 stats
->tx_fifo_errors
= WLCNTVAL(wl
->pub
->_cnt
->txuflo
);
2079 #ifdef WLC_HIGH_ONLY
2080 static void wl_rpc_down(void *wlh
)
2082 wl_info_t
*wl
= (wl_info_t
*) (wlh
);
2084 wlc_device_removed(wl
->wlc
);
2089 static int BCMFASTPATH
wl_start(struct sk_buff
*skb
, wl_info_t
*wl
)
2096 /* Lock the queue as tasklet could be running at this time */
2097 TXQ_LOCK(wl
, flags
);
2098 if (wl
->txq_head
== NULL
)
2101 wl
->txq_tail
->prev
= skb
;
2105 if (wl
->txq_dispatched
== FALSE
) {
2106 wl
->txq_dispatched
= TRUE
;
2108 if (schedule_work(&wl
->txq_task
.work
)) {
2109 atomic_inc(&wl
->callbacks
);
2111 WL_ERROR(("wl%d: wl_start/schedule_work failed\n",
2116 TXQ_UNLOCK(wl
, flags
);
2122 static void wl_start_txqwork(struct wl_task
*task
)
2124 wl_info_t
*wl
= (wl_info_t
*) task
->context
;
2125 struct sk_buff
*skb
;
2129 WL_TRACE(("wl%d: wl_start_txqwork\n", wl
->pub
->unit
));
2131 /* First remove an entry then go for execution */
2132 TXQ_LOCK(wl
, flags
);
2133 while (wl
->txq_head
) {
2135 wl
->txq_head
= skb
->prev
;
2137 if (wl
->txq_head
== NULL
)
2138 wl
->txq_tail
= NULL
;
2139 TXQ_UNLOCK(wl
, flags
);
2141 /* it has WL_LOCK/WL_UNLOCK inside */
2142 wl_start_int(wl
, WL_TO_HW(wl
), skb
);
2144 /* bounded our execution, reshedule ourself next */
2148 TXQ_LOCK(wl
, flags
);
2152 if (!schedule_work(&wl
->txq_task
.work
)) {
2153 WL_ERROR(("wl%d: wl_start/schedule_work failed\n",
2155 atomic_dec(&wl
->callbacks
);
2158 wl
->txq_dispatched
= FALSE
;
2159 TXQ_UNLOCK(wl
, flags
);
2160 atomic_dec(&wl
->callbacks
);
2166 static void wl_txq_free(wl_info_t
*wl
)
2168 struct sk_buff
*skb
;
2170 if (wl
->txq_head
== NULL
) {
2171 ASSERT(wl
->txq_tail
== NULL
);
2175 while (wl
->txq_head
) {
2177 wl
->txq_head
= skb
->prev
;
2178 PKTFREE(wl
->osh
, skb
, TRUE
);
2181 wl
->txq_tail
= NULL
;
2184 static void wl_rpcq_free(wl_info_t
*wl
)
2188 if (wl
->rpcq_head
== NULL
) {
2189 ASSERT(wl
->rpcq_tail
== NULL
);
2193 while (wl
->rpcq_head
) {
2194 buf
= wl
->rpcq_head
;
2195 wl
->rpcq_head
= bcm_rpc_buf_next_get(wl
->rpc_th
, buf
);
2196 bcm_rpc_buf_free(wl
->rpc_dispatch_ctx
.rpc
, buf
);
2199 wl
->rpcq_tail
= NULL
;
2202 static void wl_rpcq_dispatch(struct wl_task
*task
)
2204 wl_info_t
*wl
= (wl_info_t
*) task
->context
;
2208 /* First remove an entry then go for execution */
2209 RPCQ_LOCK(wl
, flags
);
2210 while (wl
->rpcq_head
) {
2211 buf
= wl
->rpcq_head
;
2212 wl
->rpcq_head
= bcm_rpc_buf_next_get(wl
->rpc_th
, buf
);
2214 if (wl
->rpcq_head
== NULL
)
2215 wl
->rpcq_tail
= NULL
;
2216 RPCQ_UNLOCK(wl
, flags
);
2219 wlc_rpc_high_dispatch(&wl
->rpc_dispatch_ctx
, buf
);
2222 RPCQ_LOCK(wl
, flags
);
2225 wl
->rpcq_dispatched
= FALSE
;
2227 RPCQ_UNLOCK(wl
, flags
);
2229 MFREE(wl
->osh
, task
, sizeof(wl_task_t
));
2230 atomic_dec(&wl
->callbacks
);
2233 static void wl_rpcq_add(wl_info_t
*wl
, rpc_buf_t
*buf
)
2237 bcm_rpc_buf_next_set(wl
->rpc_th
, buf
, NULL
);
2239 /* Lock the queue as tasklet could be running at this time */
2240 RPCQ_LOCK(wl
, flags
);
2241 if (wl
->rpcq_head
== NULL
)
2242 wl
->rpcq_head
= buf
;
2244 bcm_rpc_buf_next_set(wl
->rpc_th
, wl
->rpcq_tail
, buf
);
2246 wl
->rpcq_tail
= buf
;
2248 if (wl
->rpcq_dispatched
== FALSE
) {
2249 wl
->rpcq_dispatched
= TRUE
;
2250 wl_schedule_task(wl
, wl_rpcq_dispatch
, wl
);
2253 RPCQ_UNLOCK(wl
, flags
);
2257 static const struct name_entry rpc_name_tbl
[] = RPC_ID_TABLE
;
2260 /* dongle-side rpc dispatch routine */
2261 static void wl_rpc_dispatch_schedule(void *ctx
, struct rpc_buf
*buf
)
2264 wl_info_t
*wl
= (wl_info_t
*) ctx
;
2265 wlc_rpc_id_t rpc_id
;
2268 bcm_xdr_buf_init(&b
, bcm_rpc_buf_data(wl
->rpc_th
, buf
),
2269 bcm_rpc_buf_len_get(wl
->rpc_th
, buf
));
2271 err
= bcm_xdr_unpack_uint32(&b
, &rpc_id
);
2273 WL_TRACE(("%s: Dispatch id %s\n", __func__
,
2274 WLC_RPC_ID_LOOKUP(rpc_name_tbl
, rpc_id
)));
2276 /* Handle few emergency ones */
2279 wl_rpcq_add(wl
, buf
);
2284 static void wl_timer_task(wl_task_t
*task
)
2286 wl_timer_t
*t
= (wl_timer_t
*) task
->context
;
2289 MFREE(t
->wl
->osh
, task
, sizeof(wl_task_t
));
2291 /* This dec is for the task_schedule. The timer related
2292 * callback is decremented in _wl_timer
2294 atomic_dec(&t
->wl
->callbacks
);
2296 #endif /* WLC_HIGH_ONLY */
2298 #ifndef WLC_HIGH_ONLY
2299 char *wl_firmwares
[WL_MAX_FW
] = {
2305 int wl_ucode_init_buf(wl_info_t
*wl
, void **pbuf
, uint32 idx
)
2309 struct wl_fw_hdr
*hdr
;
2310 for (i
= 0; i
< wl
->fw
.fw_cnt
; i
++) {
2311 hdr
= (struct wl_fw_hdr
*)wl
->fw
.fw_hdr
[i
]->data
;
2312 for (entry
= 0; entry
< wl
->fw
.hdr_num_entries
[i
];
2314 if (hdr
->idx
== idx
) {
2315 pdata
= wl
->fw
.fw_bin
[i
]->data
+ hdr
->offset
;
2316 *pbuf
= kmalloc(hdr
->len
, GFP_ATOMIC
);
2317 if (*pbuf
== NULL
) {
2318 printf("fail to alloc %d bytes\n",
2321 bcopy(pdata
, *pbuf
, hdr
->len
);
2326 printf("ERROR: ucode buf tag:%d can not be found!\n", idx
);
2331 int wl_ucode_init_uint(wl_info_t
*wl
, uint32
*data
, uint32 idx
)
2335 struct wl_fw_hdr
*hdr
;
2336 for (i
= 0; i
< wl
->fw
.fw_cnt
; i
++) {
2337 hdr
= (struct wl_fw_hdr
*)wl
->fw
.fw_hdr
[i
]->data
;
2338 for (entry
= 0; entry
< wl
->fw
.hdr_num_entries
[i
];
2340 if (hdr
->idx
== idx
) {
2341 pdata
= wl
->fw
.fw_bin
[i
]->data
+ hdr
->offset
;
2342 ASSERT(hdr
->len
== 4);
2343 *data
= *((uint32
*) pdata
);
2348 printf("ERROR: ucode tag:%d can not be found!\n", idx
);
2351 #endif /* WLC_LOW */
2353 static int wl_request_fw(wl_info_t
*wl
, struct pci_dev
*pdev
)
2356 struct device
*device
= &pdev
->dev
;
2360 bzero((void *)&wl
->fw
, sizeof(struct wl_firmware
));
2361 for (i
= 0; i
< WL_MAX_FW
; i
++) {
2362 if (wl_firmwares
[i
] == NULL
)
2364 sprintf(fw_name
, "%s-%d.fw", wl_firmwares
[i
],
2365 UCODE_LOADER_API_VER
);
2366 WL_NONE(("request fw %s\n", fw_name
));
2367 status
= request_firmware(&wl
->fw
.fw_bin
[i
], fw_name
, device
);
2369 printf("%s: fail to load firmware %s\n",
2370 KBUILD_MODNAME
, fw_name
);
2374 WL_NONE(("request fw %s\n", fw_name
));
2375 sprintf(fw_name
, "%s_hdr-%d.fw", wl_firmwares
[i
],
2376 UCODE_LOADER_API_VER
);
2377 status
= request_firmware(&wl
->fw
.fw_hdr
[i
], fw_name
, device
);
2379 printf("%s: fail to load firmware %s\n",
2380 KBUILD_MODNAME
, fw_name
);
2384 wl
->fw
.hdr_num_entries
[i
] =
2385 wl
->fw
.fw_hdr
[i
]->size
/ (sizeof(struct wl_fw_hdr
));
2386 WL_NONE(("request fw %s find: %d entries\n", fw_name
,
2387 wl
->fw
.hdr_num_entries
[i
]));
2390 wl_ucode_data_init(wl
);
2395 void wl_ucode_free_buf(void *p
)
2399 #endif /* WLC_LOW */
2401 static void wl_release_fw(wl_info_t
*wl
)
2404 for (i
= 0; i
< WL_MAX_FW
; i
++) {
2405 release_firmware(wl
->fw
.fw_bin
[i
]);
2406 release_firmware(wl
->fw
.fw_hdr
[i
]);
2409 #endif /* WLC_HIGH_ONLY */