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 static int wl_proc_read(char *buffer
, char **start
, off_t offset
, int length
,
97 int *eof
, void *data
);
98 static int wl_proc_write(struct file
*filp
, const char __user
*buff
,
99 unsigned long len
, void *data
);
102 #define RPCQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->rpcq_lock, (_flags))
103 #define RPCQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->rpcq_lock, (_flags))
104 #define TXQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->txq_lock, (_flags))
105 #define TXQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->txq_lock, (_flags))
106 static void wl_rpc_down(void *wlh
);
107 static void wl_rpcq_free(wl_info_t
*wl
);
108 static void wl_rpcq_dispatch(struct wl_task
*task
);
109 static void wl_rpc_dispatch_schedule(void *ctx
, struct rpc_buf
*buf
);
110 static void wl_start_txqwork(struct wl_task
*task
);
111 static void wl_txq_free(wl_info_t
*wl
);
112 static void wl_timer_task(wl_task_t
*task
);
113 static int wl_schedule_task(wl_info_t
*wl
, void (*fn
) (struct wl_task
*),
115 #endif /* WLC_HIGH_ONLY */
117 static int ieee_hw_init(struct ieee80211_hw
*hw
);
118 static int ieee_hw_rate_init(struct ieee80211_hw
*hw
);
120 static int wl_linux_watchdog(void *ctx
);
122 /* Flags we support */
123 #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
129 FIF_BCN_PRBRESP_PROMISC)
131 static int wl_found
= 0;
133 struct ieee80211_tkip_data
{
134 #define TKIP_KEY_LEN 32
135 u8 key
[TKIP_KEY_LEN
];
150 u32 dot11RSNAStatsTKIPReplays
;
151 u32 dot11RSNAStatsTKIPICVErrors
;
152 u32 dot11RSNAStatsTKIPLocalMICFailures
;
156 struct crypto_tfm
*tfm_arc4
;
157 struct crypto_tfm
*tfm_michael
;
159 /* scratch buffers for virt_to_page() (crypto API) */
160 u8 rx_hdr
[16], tx_hdr
[16];
163 #ifndef WLC_HIGH_ONLY
164 #define WL_INFO(dev) ((wl_info_t*)(WL_DEV_IF(dev)->wl)) /* points to wl */
165 static int wl_request_fw(wl_info_t
*wl
, struct pci_dev
*pdev
);
166 static void wl_release_fw(wl_info_t
*wl
);
169 /* local prototypes */
170 static int wl_start(struct sk_buff
*skb
, wl_info_t
*wl
);
171 static int wl_start_int(wl_info_t
*wl
, struct ieee80211_hw
*hw
,
172 struct sk_buff
*skb
);
173 static void wl_dpc(ulong data
);
175 MODULE_AUTHOR("Broadcom Corporation");
176 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
177 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
178 MODULE_LICENSE("Dual BSD/GPL");
181 /* recognized PCI IDs */
182 static struct pci_device_id wl_id_table
[] = {
183 {PCI_VENDOR_ID_BROADCOM
, 0x4357, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, /* 43225 2G */
184 {PCI_VENDOR_ID_BROADCOM
, 0x4353, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, /* 43224 DUAL */
185 {PCI_VENDOR_ID_BROADCOM
, 0x4727, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, /* 4313 DUAL */
189 MODULE_DEVICE_TABLE(pci
, wl_id_table
);
190 #endif /* !BCMSDIO */
193 static uint sd_drivestrength
= 6;
194 module_param(sd_drivestrength
, uint
, 0);
198 static int msglevel
= 0xdeadbeef;
199 module_param(msglevel
, int, 0);
200 #ifndef WLC_HIGH_ONLY
201 static int phymsglevel
= 0xdeadbeef;
202 module_param(phymsglevel
, int, 0);
203 #endif /* WLC_HIGH_ONLY */
206 static int oneonly
= 0;
207 module_param(oneonly
, int, 0);
209 static int piomode
= 0;
210 module_param(piomode
, int, 0);
212 static int instance_base
= 0; /* Starting instance number */
213 module_param(instance_base
, int, 0);
216 static char *macaddr
= NULL
;
217 module_param(macaddr
, charp
, S_IRUGO
);
220 static int nompc
= 1;
221 module_param(nompc
, int, 0);
223 static char name
[IFNAMSIZ
] = "eth%d";
224 module_param_string(name
, name
, IFNAMSIZ
, 0);
230 #define WL_MAGIC 0xdeadbeef
232 #define HW_TO_WL(hw) hw->priv
233 #define WL_TO_HW(wl) wl->pub->ieee_hw
235 static int wl_ops_tx_nl(struct ieee80211_hw
*hw
, struct sk_buff
*skb
);
237 static int wl_ops_tx(struct ieee80211_hw
*hw
, struct sk_buff
*skb
);
239 static int wl_ops_start(struct ieee80211_hw
*hw
);
240 static void wl_ops_stop(struct ieee80211_hw
*hw
);
241 static int wl_ops_add_interface(struct ieee80211_hw
*hw
,
242 struct ieee80211_vif
*vif
);
243 static void wl_ops_remove_interface(struct ieee80211_hw
*hw
,
244 struct ieee80211_vif
*vif
);
245 static int wl_ops_config(struct ieee80211_hw
*hw
, u32 changed
);
246 static void wl_ops_bss_info_changed(struct ieee80211_hw
*hw
,
247 struct ieee80211_vif
*vif
,
248 struct ieee80211_bss_conf
*info
,
250 static void wl_ops_configure_filter(struct ieee80211_hw
*hw
,
251 unsigned int changed_flags
,
252 unsigned int *total_flags
, u64 multicast
);
253 static int wl_ops_set_tim(struct ieee80211_hw
*hw
, struct ieee80211_sta
*sta
,
255 static void wl_ops_sw_scan_start(struct ieee80211_hw
*hw
);
256 static void wl_ops_sw_scan_complete(struct ieee80211_hw
*hw
);
257 static void wl_ops_set_tsf(struct ieee80211_hw
*hw
, u64 tsf
);
258 static int wl_ops_get_stats(struct ieee80211_hw
*hw
,
259 struct ieee80211_low_level_stats
*stats
);
260 static int wl_ops_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
);
261 static void wl_ops_sta_notify(struct ieee80211_hw
*hw
,
262 struct ieee80211_vif
*vif
,
263 enum sta_notify_cmd cmd
,
264 struct ieee80211_sta
*sta
);
265 static int wl_ops_conf_tx(struct ieee80211_hw
*hw
, u16 queue
,
266 const struct ieee80211_tx_queue_params
*params
);
267 static u64
wl_ops_get_tsf(struct ieee80211_hw
*hw
);
268 static int wl_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
269 struct ieee80211_sta
*sta
);
270 static int wl_sta_remove(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
271 struct ieee80211_sta
*sta
);
272 static int wl_ampdu_action(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
273 enum ieee80211_ampdu_mlme_action action
,
274 struct ieee80211_sta
*sta
, u16 tid
, u16
*ssn
);
277 static int wl_ops_tx_nl(struct ieee80211_hw
*hw
, struct sk_buff
*skb
)
280 wl_info_t
*wl
= hw
->priv
;
282 WL_ERROR(("ops->tx called while down\n"));
286 status
= wl_start(skb
, wl
);
291 static int wl_ops_tx(struct ieee80211_hw
*hw
, struct sk_buff
*skb
)
294 wl_info_t
*wl
= hw
->priv
;
297 WL_ERROR(("ops->tx called while down\n"));
301 status
= wl_start(skb
, wl
);
306 #endif /* WLC_HIGH_ONLY */
308 static int wl_ops_start(struct ieee80211_hw
*hw
)
310 wl_info_t
*wl
= hw
->priv
;
311 /* struct ieee80211_channel *curchan = hw->conf.channel; */
312 WL_NONE(("%s : Initial channel: %d\n", __func__
, curchan
->hw_value
));
315 ieee80211_wake_queues(hw
);
321 static void wl_ops_stop(struct ieee80211_hw
*hw
)
323 wl_info_t
*wl
= hw
->priv
;
327 ieee80211_stop_queues(hw
);
334 wl_ops_add_interface(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
339 /* Just STA for now */
340 if (vif
->type
!= NL80211_IFTYPE_AP
&&
341 vif
->type
!= NL80211_IFTYPE_MESH_POINT
&&
342 vif
->type
!= NL80211_IFTYPE_STATION
&&
343 vif
->type
!= NL80211_IFTYPE_WDS
&&
344 vif
->type
!= NL80211_IFTYPE_ADHOC
) {
345 WL_ERROR(("%s: Attempt to add type %d, only STA for now\n",
346 __func__
, vif
->type
));
356 WL_ERROR(("%s: wl_up() returned %d\n", __func__
, err
));
361 wl_ops_remove_interface(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
367 ieee_set_channel(struct ieee80211_hw
*hw
, struct ieee80211_channel
*chan
,
368 enum nl80211_channel_type type
)
370 wl_info_t
*wl
= HW_TO_WL(hw
);
374 case NL80211_CHAN_HT20
:
375 case NL80211_CHAN_NO_HT
:
377 err
= wlc_set(wl
->wlc
, WLC_SET_CHANNEL
, chan
->hw_value
);
380 case NL80211_CHAN_HT40MINUS
:
381 case NL80211_CHAN_HT40PLUS
:
382 WL_ERROR(("%s: Need to implement 40 Mhz Channels!\n",
392 static int wl_ops_config(struct ieee80211_hw
*hw
, u32 changed
)
394 struct ieee80211_conf
*conf
= &hw
->conf
;
395 wl_info_t
*wl
= HW_TO_WL(hw
);
399 if (changed
& IEEE80211_CONF_CHANGE_LISTEN_INTERVAL
) {
400 WL_NONE(("%s: Setting listen interval to %d\n",
401 __func__
, conf
->listen_interval
));
403 (wl
->wlc
, "bcn_li_bcn", conf
->listen_interval
)) {
404 WL_ERROR(("%s: Error setting listen_interval\n",
409 wlc_iovar_getint(wl
->wlc
, "bcn_li_bcn", &new_int
);
410 ASSERT(new_int
== conf
->listen_interval
);
412 if (changed
& IEEE80211_CONF_CHANGE_MONITOR
)
413 WL_NONE(("Need to set monitor mode\n"));
414 if (changed
& IEEE80211_CONF_CHANGE_PS
)
415 WL_NONE(("Need to set Power-save mode\n"));
417 if (changed
& IEEE80211_CONF_CHANGE_POWER
) {
418 WL_NONE(("%s: Setting tx power to %d dbm\n", __func__
,
421 (wl
->wlc
, "qtxpower", conf
->power_level
* 4)) {
422 WL_ERROR(("%s: Error setting power_level\n", __func__
));
426 wlc_iovar_getint(wl
->wlc
, "qtxpower", &new_int
);
427 if (new_int
!= (conf
->power_level
* 4))
428 WL_ERROR(("%s: Power level req != actual, %d %d\n",
429 __func__
, conf
->power_level
* 4, new_int
));
431 if (changed
& IEEE80211_CONF_CHANGE_CHANNEL
) {
432 err
= ieee_set_channel(hw
, conf
->channel
, conf
->channel_type
);
434 if (changed
& IEEE80211_CONF_CHANGE_RETRY_LIMITS
) {
435 WL_NONE(("%s: srl %d, lrl %d\n", __func__
,
436 conf
->short_frame_max_tx_count
,
437 conf
->long_frame_max_tx_count
));
439 (wl
->wlc
, WLC_SET_SRL
,
440 conf
->short_frame_max_tx_count
) < 0) {
441 WL_ERROR(("%s: Error setting srl\n", __func__
));
445 if (wlc_set(wl
->wlc
, WLC_SET_LRL
, conf
->long_frame_max_tx_count
)
447 WL_ERROR(("%s: Error setting lrl\n", __func__
));
458 wl_ops_bss_info_changed(struct ieee80211_hw
*hw
,
459 struct ieee80211_vif
*vif
,
460 struct ieee80211_bss_conf
*info
, u32 changed
)
462 wl_info_t
*wl
= HW_TO_WL(hw
);
469 if (changed
& BSS_CHANGED_ASSOC
) {
470 WL_ERROR(("Associated:\t%s\n", info
->assoc
? "True" : "False"));
471 /* association status changed (associated/disassociated)
472 * also implies a change in the AID.
475 if (changed
& BSS_CHANGED_ERP_CTS_PROT
) {
476 WL_NONE(("Use_cts_prot:\t%s Implement me\n",
477 info
->use_cts_prot
? "True" : "False"));
478 /* CTS protection changed */
480 if (changed
& BSS_CHANGED_ERP_PREAMBLE
) {
481 WL_NONE(("Short preamble:\t%s Implement me\n",
482 info
->use_short_preamble
? "True" : "False"));
483 /* preamble changed */
485 if (changed
& BSS_CHANGED_ERP_SLOT
) {
486 WL_NONE(("Changing short slot:\t%s\n",
487 info
->use_short_slot
? "True" : "False"));
488 if (info
->use_short_slot
)
492 wlc_set(wl
->wlc
, WLC_SET_SHORTSLOT_OVERRIDE
, val
);
493 /* slot timing changed */
496 if (changed
& BSS_CHANGED_HT
) {
497 WL_NONE(("%s: HT mode - Implement me\n", __func__
));
498 /* 802.11n parameters changed */
500 if (changed
& BSS_CHANGED_BASIC_RATES
) {
501 WL_NONE(("Need to change Basic Rates:\t0x%x! Implement me\n",
502 (uint32
) info
->basic_rates
));
503 /* Basic rateset changed */
505 if (changed
& BSS_CHANGED_BEACON_INT
) {
506 WL_NONE(("Beacon Interval:\t%d Implement me\n",
508 /* Beacon interval changed */
510 if (changed
& BSS_CHANGED_BSSID
) {
511 /* char eabuf[ETHER_ADDR_STR_LEN]; */
512 WL_NONE(("new BSSID:\taid %d bss:%s\n",
514 bcm_ether_ntoa((struct ether_addr
*)info
->bssid
,
516 /* BSSID changed, for whatever reason (IBSS and managed mode) */
517 /* FIXME: need to store bssid in bsscfg */
518 wlc_set_addrmatch(wl
->wlc
, RCM_BSSID_OFFSET
,
519 (struct ether_addr
*)info
->bssid
);
521 if (changed
& BSS_CHANGED_BEACON
) {
522 WL_ERROR(("BSS_CHANGED_BEACON\n"));
523 /* Beacon data changed, retrieve new beacon (beaconing modes) */
525 if (changed
& BSS_CHANGED_BEACON_ENABLED
) {
526 WL_ERROR(("Beacon enabled:\t%s\n",
527 info
->enable_beacon
? "True" : "False"));
528 /* Beaconing should be enabled/disabled (beaconing modes) */
537 wl_ops_configure_filter(struct ieee80211_hw
*hw
,
538 unsigned int changed_flags
,
539 unsigned int *total_flags
, u64 multicast
)
541 #ifndef WLC_HIGH_ONLY
542 wl_info_t
*wl
= hw
->priv
;
545 changed_flags
&= MAC_FILTERS
;
546 *total_flags
&= MAC_FILTERS
;
547 if (changed_flags
& FIF_PROMISC_IN_BSS
)
548 WL_ERROR(("FIF_PROMISC_IN_BSS\n"));
549 if (changed_flags
& FIF_ALLMULTI
)
550 WL_ERROR(("FIF_ALLMULTI\n"));
551 if (changed_flags
& FIF_FCSFAIL
)
552 WL_ERROR(("FIF_FCSFAIL\n"));
553 if (changed_flags
& FIF_PLCPFAIL
)
554 WL_ERROR(("FIF_PLCPFAIL\n"));
555 if (changed_flags
& FIF_CONTROL
)
556 WL_ERROR(("FIF_CONTROL\n"));
557 if (changed_flags
& FIF_OTHER_BSS
)
558 WL_ERROR(("FIF_OTHER_BSS\n"));
559 if (changed_flags
& FIF_BCN_PRBRESP_PROMISC
) {
560 WL_NONE(("FIF_BCN_PRBRESP_PROMISC\n"));
561 #ifndef WLC_HIGH_ONLY
563 if (*total_flags
& FIF_BCN_PRBRESP_PROMISC
) {
564 wl
->pub
->mac80211_state
|= MAC80211_PROMISC_BCNS
;
565 wlc_mac_bcn_promisc_change(wl
->wlc
, 1);
567 wlc_mac_bcn_promisc_change(wl
->wlc
, 0);
568 wl
->pub
->mac80211_state
&= ~MAC80211_PROMISC_BCNS
;
577 wl_ops_set_tim(struct ieee80211_hw
*hw
, struct ieee80211_sta
*sta
, bool set
)
579 WL_ERROR(("%s: Enter\n", __func__
));
583 static void wl_ops_sw_scan_start(struct ieee80211_hw
*hw
)
585 WL_NONE(("Scan Start\n"));
589 static void wl_ops_sw_scan_complete(struct ieee80211_hw
*hw
)
591 WL_NONE(("Scan Complete\n"));
595 static void wl_ops_set_tsf(struct ieee80211_hw
*hw
, u64 tsf
)
597 WL_ERROR(("%s: Enter\n", __func__
));
602 wl_ops_get_stats(struct ieee80211_hw
*hw
,
603 struct ieee80211_low_level_stats
*stats
)
605 WL_ERROR(("%s: Enter\n", __func__
));
609 static int wl_ops_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
)
611 WL_ERROR(("%s: Enter\n", __func__
));
616 wl_ops_sta_notify(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
617 enum sta_notify_cmd cmd
, struct ieee80211_sta
*sta
)
619 WL_NONE(("%s: Enter\n", __func__
));
622 WL_ERROR(("%s: Uknown cmd = %d\n", __func__
, cmd
));
629 wl_ops_conf_tx(struct ieee80211_hw
*hw
, u16 queue
,
630 const struct ieee80211_tx_queue_params
*params
)
632 wl_info_t
*wl
= hw
->priv
;
634 WL_NONE(("%s: Enter (WME config)\n", __func__
));
635 WL_NONE(("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue
,
636 params
->txop
, params
->cw_min
, params
->cw_max
, params
->aifs
));
639 wlc_wme_setparams(wl
->wlc
, queue
, (void *)params
, TRUE
);
645 static u64
wl_ops_get_tsf(struct ieee80211_hw
*hw
)
647 WL_ERROR(("%s: Enter\n", __func__
));
652 wl_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
653 struct ieee80211_sta
*sta
)
658 wl_info_t
*wl
= hw
->priv
;
661 scb
= (struct scb
*)sta
->drv_priv
;
662 bzero(scb
, sizeof(struct scb
));
663 for (i
= 0; i
< NUMPRIO
; i
++)
664 scb
->seqctl
[i
] = 0xFFFF;
665 scb
->seqctl_nonqos
= 0xFFFF;
666 scb
->magic
= SCB_MAGIC
;
668 wl
->pub
->global_scb
= scb
;
669 wl
->pub
->global_ampdu
= &(scb
->scb_ampdu
);
670 wl
->pub
->global_ampdu
->scb
= scb
;
672 wl
->pub
->global_ampdu
->max_pdu
= AMPDU_NUM_MPDU
;
674 wl
->pub
->global_ampdu
->max_pdu
= 16;
676 pktq_init(&scb
->scb_ampdu
.txq
, AMPDU_MAX_SCB_TID
,
677 AMPDU_MAX_SCB_TID
* PKTQ_LEN_DEFAULT
);
679 sta
->ht_cap
.ht_supported
= TRUE
;
681 sta
->ht_cap
.ampdu_factor
= AMPDU_RX_FACTOR_16K
;
683 sta
->ht_cap
.ampdu_factor
= AMPDU_RX_FACTOR_64K
;
685 sta
->ht_cap
.ampdu_density
= AMPDU_DEF_MPDU_DENSITY
;
686 sta
->ht_cap
.cap
= IEEE80211_HT_CAP_GRN_FLD
|
687 IEEE80211_HT_CAP_SGI_20
|
688 IEEE80211_HT_CAP_SGI_40
| IEEE80211_HT_CAP_40MHZ_INTOLERANT
;
690 /* minstrel_ht initiates addBA on our behalf by calling ieee80211_start_tx_ba_session() */
695 wl_sta_remove(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
696 struct ieee80211_sta
*sta
)
698 WL_NONE(("%s: Enter\n", __func__
));
703 wl_ampdu_action(struct ieee80211_hw
*hw
,
704 struct ieee80211_vif
*vif
,
705 enum ieee80211_ampdu_mlme_action action
,
706 struct ieee80211_sta
*sta
, u16 tid
, u16
*ssn
)
709 struct scb
*scb
= (struct scb
*)sta
->drv_priv
;
711 wl_info_t
*wl
= hw
->priv
;
713 ASSERT(scb
->magic
== SCB_MAGIC
);
715 case IEEE80211_AMPDU_RX_START
:
716 WL_NONE(("%s: action = IEEE80211_AMPDU_RX_START\n", __func__
));
718 case IEEE80211_AMPDU_RX_STOP
:
719 WL_NONE(("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__
));
721 case IEEE80211_AMPDU_TX_START
:
722 if (!wlc_aggregatable(wl
->wlc
, tid
)) {
723 /* WL_ERROR(("START: tid %d is not agg' able, return FAILURE to stack\n", tid)); */
726 /* XXX: Use the starting sequence number provided ... */
728 ieee80211_start_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
731 case IEEE80211_AMPDU_TX_STOP
:
732 ieee80211_stop_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
734 case IEEE80211_AMPDU_TX_OPERATIONAL
:
735 /* Not sure what to do here */
736 /* Power save wakeup */
737 WL_NONE(("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n",
741 WL_ERROR(("%s: Invalid command, ignoring\n", __func__
));
747 static const struct ieee80211_ops wl_ops
= {
753 .start
= wl_ops_start
,
755 .add_interface
= wl_ops_add_interface
,
756 .remove_interface
= wl_ops_remove_interface
,
757 .config
= wl_ops_config
,
758 .bss_info_changed
= wl_ops_bss_info_changed
,
759 .configure_filter
= wl_ops_configure_filter
,
760 .set_tim
= wl_ops_set_tim
,
761 .sw_scan_start
= wl_ops_sw_scan_start
,
762 .sw_scan_complete
= wl_ops_sw_scan_complete
,
763 .set_tsf
= wl_ops_set_tsf
,
764 .get_stats
= wl_ops_get_stats
,
765 .set_rts_threshold
= wl_ops_set_rts_threshold
,
766 .sta_notify
= wl_ops_sta_notify
,
767 .conf_tx
= wl_ops_conf_tx
,
768 .get_tsf
= wl_ops_get_tsf
,
769 .sta_add
= wl_sta_add
,
770 .sta_remove
= wl_sta_remove
,
771 .ampdu_action
= wl_ampdu_action
,
774 static int wl_set_hint(wl_info_t
*wl
, char *abbrev
)
776 WL_ERROR(("%s: Sending country code %c%c to MAC80211\n", __func__
,
777 abbrev
[0], abbrev
[1]));
778 return regulatory_hint(wl
->pub
->ieee_hw
->wiphy
, abbrev
);
782 * attach to the WL device.
784 * Attach to the WL device identified by vendor and device parameters.
785 * regs is a host accessible memory address pointing to WL device registers.
787 * wl_attach is not defined as static because in the case where no bus
788 * is defined, wl_attach will never be called, and thus, gcc will issue
789 * a warning that this function is defined but not used if we declare
792 static wl_info_t
*wl_attach(uint16 vendor
, uint16 device
, ulong regs
,
793 uint bustype
, void *btparam
, uint irq
)
800 struct ieee80211_hw
*hw
;
801 uint8 perm
[ETH_ALEN
];
803 unit
= wl_found
+ instance_base
;
807 WL_ERROR(("wl%d: unit number overflow, exiting\n", unit
));
811 if (oneonly
&& (unit
!= instance_base
)) {
812 WL_ERROR(("wl%d: wl_attach: oneonly is set, exiting\n", unit
));
816 /* Requires pkttag feature */
817 osh
= osl_attach(btparam
, bustype
, TRUE
);
821 hw
= ieee80211_alloc_hw(sizeof(wl_info_t
), &wl_ops
);
823 WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__
));
827 bzero(hw
->priv
, sizeof(*wl
));
830 /* allocate private info */
831 hw
= pci_get_drvdata(btparam
); /* btparam == pdev */
836 wl
->magic
= WL_MAGIC
;
838 atomic_set(&wl
->callbacks
, 0);
840 /* setup the bottom half handler */
841 tasklet_init(&wl
->tasklet
, wl_dpc
, (ulong
) wl
);
844 wl
->rpc_th
= bcm_rpc_tp_attach(osh
, NULL
);
845 if (wl
->rpc_th
== NULL
) {
846 WL_ERROR(("wl%d: %s: bcm_rpc_tp_attach failed!\n", unit
,
851 wl
->rpc
= bcm_rpc_attach(NULL
, osh
, wl
->rpc_th
);
852 if (wl
->rpc
== NULL
) {
853 WL_ERROR(("wl%d: %s: bcm_rpc_attach failed!\n", unit
,
858 /* init tx work queue for wl_start/send pkt; no need to destroy workitem */
859 MY_INIT_WORK(&wl
->txq_task
.work
, (work_func_t
) wl_start_txqwork
);
860 wl
->txq_task
.context
= wl
;
861 #endif /* WLC_HIGH_ONLY */
864 SET_IEEE80211_DEV(hw
, sdiommc_dev
);
869 if (bustype
== PCI_BUS
) {
870 /* piomode can be overwritten by command argument */
871 wl
->piomode
= piomode
;
872 WL_TRACE(("PCI/%s\n", wl
->piomode
? "PIO" : "DMA"));
873 } else if (bustype
== RPC_BUS
) {
877 WL_TRACE(("force to PCI\n"));
879 wl
->bcm_bustype
= bustype
;
882 if (wl
->bcm_bustype
== RPC_BUS
) {
883 wl
->regsva
= (void *)0;
887 if ((wl
->regsva
= ioremap_nocache(base_addr
, PCI_BAR0_WINSZ
)) == NULL
) {
888 WL_ERROR(("wl%d: ioremap() failed\n", unit
));
892 spin_lock_init(&wl
->rpcq_lock
);
893 spin_lock_init(&wl
->txq_lock
);
895 init_MUTEX(&wl
->sem
);
897 spin_lock_init(&wl
->lock
);
898 spin_lock_init(&wl
->isr_lock
);
901 #ifndef WLC_HIGH_ONLY
903 if (wl_request_fw(wl
, (struct pci_dev
*)btparam
)) {
904 printf("%s: %s driver failed\n", KBUILD_MODNAME
,
910 /* common load-time initialization */
911 wl
->wlc
= wlc_attach((void *)wl
, vendor
, device
, unit
, wl
->piomode
, osh
,
912 wl
->regsva
, wl
->bcm_bustype
, btparam
, &err
);
913 #ifndef WLC_HIGH_ONLY
917 printf("%s: %s driver failed with code %d\n", KBUILD_MODNAME
,
918 EPI_VERSION_STR
, err
);
921 wl
->pub
= wlc_pub(wl
->wlc
);
923 wl
->pub
->ieee_hw
= hw
;
924 ASSERT(wl
->pub
->ieee_hw
);
925 ASSERT(wl
->pub
->ieee_hw
->priv
== wl
);
928 REGOPSSET(osh
, (osl_rreg_fn_t
) wlc_reg_read
,
929 (osl_wreg_fn_t
) wlc_reg_write
, wl
->wlc
);
930 wl
->rpc_dispatch_ctx
.rpc
= wl
->rpc
;
931 wl
->rpc_dispatch_ctx
.wlc
= wl
->wlc
;
932 bcm_rpc_rxcb_init(wl
->rpc
, wl
, wl_rpc_dispatch_schedule
, wl
,
933 wl_rpc_down
, NULL
, NULL
);
934 #endif /* WLC_HIGH_ONLY */
937 if (wlc_iovar_setint(wl
->wlc
, "mpc", 0)) {
938 WL_ERROR(("wl%d: Error setting MPC variable to 0\n",
943 /* Set SDIO drive strength */
944 wlc_iovar_setint(wl
->wlc
, "sd_drivestrength", sd_drivestrength
);
948 /* register our interrupt handler */
949 if (request_irq(irq
, wl_isr
, IRQF_SHARED
, KBUILD_MODNAME
, wl
)) {
950 WL_ERROR(("wl%d: request_irq() failed\n", unit
));
956 /* register module */
957 wlc_module_register(wl
->pub
, NULL
, "linux", wl
, NULL
, wl_linux_watchdog
,
960 if (ieee_hw_init(hw
)) {
961 WL_ERROR(("wl%d: %s: ieee_hw_init failed!\n", unit
, __func__
));
965 bcopy(&wl
->pub
->cur_etheraddr
, perm
, ETHER_ADDR_LEN
);
966 ASSERT(is_valid_ether_addr(perm
));
967 SET_IEEE80211_PERM_ADDR(hw
, perm
);
969 err
= ieee80211_register_hw(hw
);
971 WL_ERROR(("%s: ieee80211_register_hw failed, status %d\n",
975 if (wl
->pub
->srom_ccode
[0])
976 err
= wl_set_hint(wl
, wl
->pub
->srom_ccode
);
978 err
= wl_set_hint(wl
, "US");
980 WL_ERROR(("%s: regulatory_hint failed, status %d\n", __func__
,
983 #ifndef WLC_HIGH_ONLY
984 WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
985 EPI_VERSION_STR
" (" PHY_VERSION_STR
")", unit
));
987 WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
988 EPI_VERSION_STR
, unit
));
992 printf(" (Compiled in " SRCBASE
" at " __TIME__
" on " __DATE__
")");
996 if ((wl
->proc_entry
=
997 create_proc_entry(PROC_ENTRY_NAME
, 0644, NULL
)) == NULL
) {
998 WL_ERROR(("create_proc_entry failed *******\n"));
1001 wl
->proc_entry
->read_proc
= wl_proc_read
;
1002 wl
->proc_entry
->write_proc
= wl_proc_write
;
1003 wl
->proc_entry
->data
= wl
;
1004 /* wl->proc_entry->owner = THIS_MODULE; */
1006 if ((wl
->ioctlbuf
= (char *)vmalloc(PAGE_SIZE
)) == NULL
) {
1007 WL_ERROR(("%s: Vmalloc failed\n", __func__
));
1009 wl
->ioctlbuf_sz
= PAGE_SIZE
;
1010 memset(wl
->ioctlbuf
, 0, PAGE_SIZE
);
1011 wl
->ioctlbuf
[0] = '!';
1022 #define PROC_MESSAGE "Broadcom driver debugger access only. Requires matching 'wl' app\n"
1024 /* OS Entry point when app attempts to read */
1026 wl_proc_read(char *buffer
, char **start
, off_t offset
, int length
, int *eof
,
1029 wl_info_t
*wl
= (wl_info_t
*) data
;
1031 switch (wl
->proc_state
) {
1036 case WL_PROC_HAVE_IOC
:
1037 /* Give the processed buffer back to userland */
1038 if (!wl
->ioctl_in_progress
) {
1039 WL_ERROR(("%s: No ioctl in progress nothing to read, 2\n", __func__
));
1043 if (wl
->ioc
.len
> wl
->ioctlbuf_sz
) {
1045 bcopy(wl
->ioctlbuf
, buffer
+ offset
, wl
->ioc
.len
);
1047 wl
->ioctl_in_progress
= 0;
1048 return wl
->ioc
.len
+ offset
;
1050 case WL_PROC_HAVE_BUF
:
1051 /* Give the processed IOC back to userland */
1052 if (!wl
->ioctl_in_progress
) {
1053 WL_ERROR(("%s: No ioctl in progress nothing to read, 1\n", __func__
));
1056 if (length
!= sizeof(wl_ioctl_t
)) {
1057 WL_ERROR(("%s: Reading ioc but len != sizeof(wl_ioctl_t)\n", __func__
));
1060 bcopy(&wl
->ioc
, buffer
+ offset
, length
);
1062 return length
+ offset
;
1065 WL_ERROR(("%s: Proc read out of sync. proc_state %d, ioctl_in_progress %d\n", __func__
, wl
->proc_state
, wl
->ioctl_in_progress
));
1068 WL_ERROR(("%s: Invalid ioctl!!!\n", __func__
));
1072 /* OS Entry point when app attempts to write */
1074 wl_proc_write(struct file
*filp
, const char __user
*buff
, unsigned long length
,
1077 wl_info_t
*wl
= (wl_info_t
*) data
;
1080 switch (wl
->proc_state
) {
1083 if (wl
->ioctl_in_progress
) {
1084 WL_ERROR(("%s: ioctl still in progress\n", __func__
));
1087 if (length
!= sizeof(wl_ioctl_t
)) {
1088 WL_ERROR(("%s: Expecting ioctl sized buf\n", __func__
));
1091 if (copy_from_user(&wl
->ioc
, buff
, sizeof(wl_ioctl_t
))) {
1092 WL_ERROR(("%s: copy from user failed\n", __func__
));
1096 wl
->ioctl_in_progress
++;
1097 return sizeof(wl_ioctl_t
);
1099 case WL_PROC_HAVE_IOC
:
1100 if (!wl
->ioctl_in_progress
) {
1101 WL_ERROR(("%s: Ioctl not ready yet 1\n", __func__
));
1104 if (wl
->ioctlbuf_sz
< length
) {
1105 WL_ERROR(("%s: Buf write, ioctl buf %d not big enough too hold buffer %d\n", __func__
, (int)sizeof(wl
->ioctlbuf
), (int)length
));
1106 WL_ERROR(("Shortening input\n"));
1107 length
= wl
->ioctlbuf_sz
;
1109 if (length
!= wl
->ioc
.len
) {
1110 WL_ERROR(("%s: ioc.len %d != length param %d\n",
1111 __func__
, wl
->ioc
.len
, (int)length
));
1114 if (copy_from_user(wl
->ioctlbuf
, buff
, length
)) {
1115 WL_ERROR(("%s: copy from user of %d bytes failed\n",
1116 __func__
, (int)length
));
1123 wlc_ioctl(wl
->wlc
, wl
->ioc
.cmd
, wl
->ioctlbuf
, wl
->ioc
.len
,
1132 case WL_PROC_HAVE_BUF
:
1133 WL_ERROR(("%s: Illegal write. Rejecting.\n", __func__
));
1136 WL_ERROR(("%s: Proc write out of sync. proc_state %d, ioctl_in_progress %d\n", __func__
, wl
->proc_state
, wl
->ioctl_in_progress
));
1141 #ifdef WLC_HIGH_ONLY
1142 static void *wl_dbus_probe_cb(void *arg
, const char *desc
, uint32 bustype
,
1146 WL_ERROR(("%s:\n", __func__
));
1150 wl_attach(BCM_DNGL_VID
, BCM_DNGL_BDC_PID
, (ulong
) NULL
, RPC_BUS
,
1152 WL_ERROR(("%s: wl_attach failed\n", __func__
));
1155 /* This is later passed to wl_dbus_disconnect_cb */
1159 static void wl_dbus_disconnect_cb(void *arg
)
1161 wl_info_t
*wl
= arg
;
1163 WL_ERROR(("%s:\n", __func__
));
1166 #ifdef WLC_HIGH_ONLY
1167 if (wl
->pub
->ieee_hw
) {
1168 ieee80211_unregister_hw(wl
->pub
->ieee_hw
);
1169 WL_ERROR(("%s: Back from down\n", __func__
));
1171 wlc_device_removed(wl
->wlc
);
1172 wlc_bmac_dngl_reboot(wl
->rpc
);
1173 bcm_rpc_down(wl
->rpc
);
1178 #ifdef WLC_HIGH_ONLY
1179 if (wl
->pub
->ieee_hw
) {
1180 ieee80211_free_hw(wl
->pub
->ieee_hw
);
1181 WL_ERROR(("%s: Back from ieee80211_free_hw\n",
1183 wl
->pub
->ieee_hw
= NULL
;
1189 #endif /* WLC_HIGH_ONLY */
1192 static void __devexit
wl_remove(struct pci_dev
*pdev
);
1195 #define CHAN2GHZ(channel, freqency, chflags) { \
1196 .band = IEEE80211_BAND_2GHZ, \
1197 .center_freq = (freqency), \
1198 .hw_value = (channel), \
1200 .max_antenna_gain = 0, \
1204 static struct ieee80211_channel wl_2ghz_chantable
[] = {
1205 CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS
),
1206 CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS
),
1207 CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS
),
1208 CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS
),
1209 CHAN2GHZ(5, 2432, 0),
1210 CHAN2GHZ(6, 2437, 0),
1211 CHAN2GHZ(7, 2442, 0),
1212 CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS
),
1213 CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS
),
1214 CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS
),
1215 CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS
),
1217 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_IBSS
|
1218 IEEE80211_CHAN_NO_HT40PLUS
),
1220 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_IBSS
|
1221 IEEE80211_CHAN_NO_HT40PLUS
),
1223 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_IBSS
|
1224 IEEE80211_CHAN_NO_HT40PLUS
| IEEE80211_CHAN_NO_HT40MINUS
)
1227 #define CHAN5GHZ(channel, chflags) { \
1228 .band = IEEE80211_BAND_5GHZ, \
1229 .center_freq = 5000 + 5*(channel), \
1230 .hw_value = (channel), \
1232 .max_antenna_gain = 0, \
1236 static struct ieee80211_channel wl_5ghz_nphy_chantable
[] = {
1238 CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS
),
1239 CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS
),
1240 CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS
),
1241 CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS
),
1244 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1245 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1247 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1248 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1250 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1251 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1253 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1254 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1257 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1258 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1260 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1261 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1263 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1264 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1266 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1267 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1269 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1270 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1272 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1273 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1275 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1276 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1278 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1279 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1281 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1282 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40MINUS
),
1284 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1285 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
),
1287 IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IBSS
|
1288 IEEE80211_CHAN_PASSIVE_SCAN
| IEEE80211_CHAN_NO_HT40PLUS
|
1289 IEEE80211_CHAN_NO_HT40MINUS
),
1291 CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS
),
1292 CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS
),
1293 CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS
),
1294 CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS
),
1295 CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS
| IEEE80211_CHAN_NO_HT40MINUS
)
1298 #define RATE(rate100m, _flags) { \
1299 .bitrate = (rate100m), \
1300 .flags = (_flags), \
1301 .hw_value = (rate100m / 5), \
1304 static struct ieee80211_rate wl_legacy_ratetable
[] = {
1306 RATE(20, IEEE80211_RATE_SHORT_PREAMBLE
),
1307 RATE(55, IEEE80211_RATE_SHORT_PREAMBLE
),
1308 RATE(110, IEEE80211_RATE_SHORT_PREAMBLE
),
1319 static struct ieee80211_supported_band wl_band_2GHz_nphy
= {
1320 .band
= IEEE80211_BAND_2GHZ
,
1321 .channels
= wl_2ghz_chantable
,
1322 .n_channels
= ARRAY_SIZE(wl_2ghz_chantable
),
1323 .bitrates
= wl_legacy_ratetable
,
1324 .n_bitrates
= ARRAY_SIZE(wl_legacy_ratetable
),
1326 /* from include/linux/ieee80211.h */
1327 .cap
= IEEE80211_HT_CAP_GRN_FLD
|
1328 IEEE80211_HT_CAP_SGI_20
|
1329 IEEE80211_HT_CAP_SGI_40
| IEEE80211_HT_CAP_40MHZ_INTOLERANT
,
1330 #ifdef WLC_HIGH_ONLY
1331 .ht_supported
= true,
1332 .ampdu_factor
= AMPDU_RX_FACTOR_16K
,
1334 .ht_supported
= true,
1335 .ampdu_factor
= AMPDU_RX_FACTOR_64K
,
1337 .ampdu_density
= AMPDU_DEF_MPDU_DENSITY
,
1339 /* placeholders for now */
1340 #ifdef WLC_HIGH_ONLY
1342 * rx_mask[0] = 0xff by default
1343 * rx_mask[1] = 0xff if number of rx chain >=2
1344 * rx_mask[2] = 0xff if number of rx chain >=3
1345 * rx_mask[4] = 1 if 40Mhz is supported
1347 .rx_mask
= {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1348 .rx_highest
= 72, /* max rate of single stream */
1350 .rx_mask
= {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
1353 .tx_params
= IEEE80211_HT_MCS_TX_DEFINED
}
1357 static struct ieee80211_supported_band wl_band_5GHz_nphy
= {
1358 .band
= IEEE80211_BAND_5GHZ
,
1359 .channels
= wl_5ghz_nphy_chantable
,
1360 .n_channels
= ARRAY_SIZE(wl_5ghz_nphy_chantable
),
1361 .bitrates
= wl_legacy_ratetable
+ 4,
1362 .n_bitrates
= ARRAY_SIZE(wl_legacy_ratetable
) - 4,
1364 /* use IEEE80211_HT_CAP_* from include/linux/ieee80211.h */
1365 .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 */
1366 .ht_supported
= true,
1367 .ampdu_factor
= AMPDU_RX_FACTOR_64K
,
1368 .ampdu_density
= AMPDU_DEF_MPDU_DENSITY
,
1370 /* placeholders for now */
1371 .rx_mask
= {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
1373 .tx_params
= IEEE80211_HT_MCS_TX_DEFINED
}
1377 static int ieee_hw_rate_init(struct ieee80211_hw
*hw
)
1379 wl_info_t
*wl
= HW_TO_WL(hw
);
1385 hw
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = NULL
;
1386 hw
->wiphy
->bands
[IEEE80211_BAND_5GHZ
] = NULL
;
1388 if (wlc_get(wl
->wlc
, WLC_GET_PHYLIST
, (int *)&phy_list
) < 0) {
1389 WL_ERROR(("Phy list failed\n"));
1391 WL_NONE(("%s: phylist = %c\n", __func__
, phy_list
[0]));
1393 #ifndef WLC_HIGH_ONLY
1394 if (phy_list
[0] == 'n' || phy_list
[0] == 'c') {
1395 if (phy_list
[0] == 'c') {
1397 wl_band_2GHz_nphy
.ht_cap
.mcs
.rx_mask
[1] = 0;
1398 wl_band_2GHz_nphy
.ht_cap
.mcs
.rx_highest
= 72;
1401 if (phy_list
[0] == 's') {
1403 hw
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &wl_band_2GHz_nphy
;
1409 /* Assume all bands use the same phy. True for 11n devices. */
1410 if (NBANDS_PUB(wl
->pub
) > 1) {
1412 #ifndef WLC_HIGH_ONLY
1413 if (phy_list
[0] == 'n' || phy_list
[0] == 'c') {
1415 if (phy_list
[0] == 's') {
1417 hw
->wiphy
->bands
[IEEE80211_BAND_5GHZ
] =
1424 WL_NONE(("%s: 2ghz = %d, 5ghz = %d\n", __func__
, 1, has_5g
));
1429 static int ieee_hw_init(struct ieee80211_hw
*hw
)
1431 hw
->flags
= IEEE80211_HW_SIGNAL_DBM
1432 /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
1433 | IEEE80211_HW_REPORTS_TX_ACK_STATUS
1434 | IEEE80211_HW_AMPDU_AGGREGATION
;
1436 hw
->extra_tx_headroom
= wlc_get_header_len();
1437 /* FIXME: should get this from wlc->machwcap */
1439 /* FIXME: this doesn't seem to be used properly in minstrel_ht.
1440 * mac80211/status.c:ieee80211_tx_status() checks this value,
1441 * but mac80211/rc80211_minstrel_ht.c:minstrel_ht_get_rate()
1442 * appears to always set 3 rates
1444 hw
->max_rates
= 2; /* Primary rate and 1 fallback rate */
1446 hw
->channel_change_time
= 7 * 1000; /* channel change time is dependant on chip and band */
1447 hw
->wiphy
->interface_modes
= BIT(NL80211_IFTYPE_STATION
);
1449 hw
->rate_control_algorithm
= "minstrel_ht";
1451 hw
->sta_data_size
= sizeof(struct scb
);
1452 return ieee_hw_rate_init(hw
);
1457 * determines if a device is a WL device, and if so, attaches it.
1459 * This function determines if a device pointed to by pdev is a WL device,
1460 * and if so, performs a wl_attach() on it.
1464 wl_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*ent
)
1468 struct ieee80211_hw
*hw
;
1473 WL_TRACE(("%s: bus %d slot %d func %d irq %d\n", __func__
,
1474 pdev
->bus
->number
, PCI_SLOT(pdev
->devfn
),
1475 PCI_FUNC(pdev
->devfn
), pdev
->irq
));
1477 if ((pdev
->vendor
!= PCI_VENDOR_ID_BROADCOM
) ||
1478 (((pdev
->device
& 0xff00) != 0x4300) &&
1479 ((pdev
->device
& 0xff00) != 0x4700) &&
1480 ((pdev
->device
< 43000) || (pdev
->device
> 43999))))
1483 rc
= pci_enable_device(pdev
);
1485 WL_ERROR(("%s: Cannot enable device %d-%d_%d\n", __func__
,
1486 pdev
->bus
->number
, PCI_SLOT(pdev
->devfn
),
1487 PCI_FUNC(pdev
->devfn
)));
1490 pci_set_master(pdev
);
1492 pci_read_config_dword(pdev
, 0x40, &val
);
1493 if ((val
& 0x0000ff00) != 0)
1494 pci_write_config_dword(pdev
, 0x40, val
& 0xffff00ff);
1496 hw
= ieee80211_alloc_hw(sizeof(wl_info_t
), &wl_ops
);
1498 WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__
));
1503 SET_IEEE80211_DEV(hw
, &pdev
->dev
);
1505 pci_set_drvdata(pdev
, hw
);
1507 bzero(hw
->priv
, sizeof(*wl
));
1509 wl
= wl_attach(pdev
->vendor
, pdev
->device
, pci_resource_start(pdev
, 0),
1510 PCI_BUS
, pdev
, pdev
->irq
);
1514 WL_ERROR(("%s: err_1: Major hoarkage\n", __func__
));
1519 static int wl_suspend(struct pci_dev
*pdev
, DRV_SUSPEND_STATE_TYPE state
)
1522 struct ieee80211_hw
*hw
;
1524 WL_TRACE(("wl: wl_suspend\n"));
1526 hw
= pci_get_drvdata(pdev
);
1529 WL_ERROR(("wl: wl_suspend: pci_get_drvdata failed\n"));
1535 wl
->pub
->hw_up
= FALSE
;
1537 PCI_SAVE_STATE(pdev
, wl
->pci_psstate
);
1538 pci_disable_device(pdev
);
1539 return pci_set_power_state(pdev
, PCI_D3hot
);
1542 static int wl_resume(struct pci_dev
*pdev
)
1545 struct ieee80211_hw
*hw
;
1549 WL_TRACE(("wl: wl_resume\n"));
1550 hw
= pci_get_drvdata(pdev
);
1553 WL_ERROR(("wl: wl_resume: pci_get_drvdata failed\n"));
1557 err
= pci_set_power_state(pdev
, PCI_D0
);
1561 PCI_RESTORE_STATE(pdev
, wl
->pci_psstate
);
1563 err
= pci_enable_device(pdev
);
1567 pci_set_master(pdev
);
1569 pci_read_config_dword(pdev
, 0x40, &val
);
1570 if ((val
& 0x0000ff00) != 0)
1571 pci_write_config_dword(pdev
, 0x40, val
& 0xffff00ff);
1579 #endif /* LINUXSTA_PS */
1581 static void __devexit
wl_remove(struct pci_dev
*pdev
)
1584 struct ieee80211_hw
*hw
;
1586 hw
= pci_get_drvdata(pdev
);
1589 WL_ERROR(("wl: wl_remove: pci_get_drvdata failed\n"));
1592 if (!wlc_chipmatch(pdev
->vendor
, pdev
->device
)) {
1593 WL_ERROR(("wl: wl_remove: wlc_chipmatch failed\n"));
1597 ieee80211_unregister_hw(hw
);
1602 WL_NONE(("%s: Down\n", __func__
));
1604 pci_disable_device(pdev
);
1608 pci_set_drvdata(pdev
, NULL
);
1609 ieee80211_free_hw(hw
);
1612 static struct pci_driver wl_pci_driver
= {
1618 #endif /* LINUXSTA_PS */
1619 remove
:__devexit_p(wl_remove
),
1620 id_table
:wl_id_table
,
1622 #endif /* !BCMSDIO */
1625 * This is the main entry point for the WL driver.
1627 * This function determines if a device pointed to by pdev is a WL device,
1628 * and if so, performs a wl_attach() on it.
1631 static int __init
wl_module_init(void)
1633 int error
= -ENODEV
;
1636 if (msglevel
!= 0xdeadbeef)
1637 wl_msg_level
= msglevel
;
1639 char *var
= getvar(NULL
, "wl_msglevel");
1641 wl_msg_level
= bcm_strtoul(var
, NULL
, 0);
1643 #ifndef WLC_HIGH_ONLY
1645 extern uint32 phyhal_msg_level
;
1647 if (phymsglevel
!= 0xdeadbeef)
1648 phyhal_msg_level
= phymsglevel
;
1650 char *var
= getvar(NULL
, "phy_msglevel");
1652 phyhal_msg_level
= bcm_strtoul(var
, NULL
, 0);
1655 #endif /* WLC_HIGH_ONLY */
1659 if (!(error
= pci_module_init(&wl_pci_driver
)))
1662 #endif /* !BCMSDIO */
1664 #ifdef WLC_HIGH_ONLY
1665 /* BMAC_NOTE: define hardcode number, why NODEVICE is ok ? */
1667 dbus_register(BCM_DNGL_VID
, 0, wl_dbus_probe_cb
,
1668 wl_dbus_disconnect_cb
, NULL
, NULL
, NULL
);
1669 if (error
== DBUS_ERR_NODEVICE
) {
1672 #endif /* WLC_HIGH_ONLY */
1678 * This function unloads the WL driver from the system.
1680 * This function unconditionally unloads the WL driver module from the
1684 static void __exit
wl_module_exit(void)
1687 pci_unregister_driver(&wl_pci_driver
);
1688 #endif /* !BCMSDIO */
1690 #ifdef WLC_HIGH_ONLY
1692 #endif /* WLC_HIGH_ONLY */
1695 module_init(wl_module_init
);
1696 module_exit(wl_module_exit
);
1699 * This function frees the WL per-device resources.
1701 * This function frees resources owned by the WL device pointed to
1702 * by the wl parameter.
1705 void wl_free(wl_info_t
*wl
)
1707 wl_timer_t
*t
, *next
;
1711 #ifndef WLC_HIGH_ONLY
1712 /* free ucode data */
1714 wl_ucode_data_free();
1716 free_irq(wl
->irq
, wl
);
1720 tasklet_kill(&wl
->tasklet
);
1723 wlc_module_unregister(wl
->pub
, "linux", wl
);
1726 /* free common resources */
1728 wlc_detach(wl
->wlc
);
1733 /* virtual interface deletion is deferred so we cannot spinwait */
1735 /* wait for all pending callbacks to complete */
1736 while (atomic_read(&wl
->callbacks
) > 0)
1740 for (t
= wl
->timers
; t
; t
= next
) {
1744 MFREE(wl
->osh
, t
->name
, strlen(t
->name
) + 1);
1746 MFREE(wl
->osh
, t
, sizeof(wl_timer_t
));
1749 if (wl
->ioctlbuf_sz
) {
1750 remove_proc_entry(PROC_ENTRY_NAME
, NULL
);
1751 vfree(wl
->ioctlbuf
);
1752 wl
->ioctlbuf_sz
= 0;
1758 * unregister_netdev() calls get_stats() which may read chip registers
1759 * so we cannot unmap the chip registers until after calling unregister_netdev() .
1761 if (wl
->regsva
&& BUSTYPE(wl
->bcm_bustype
) != SDIO_BUS
&&
1762 BUSTYPE(wl
->bcm_bustype
) != JTAG_BUS
) {
1763 iounmap((void *)wl
->regsva
);
1767 #ifdef WLC_HIGH_ONLY
1773 bcm_rpc_detach(wl
->rpc
);
1778 bcm_rpc_tp_detach(wl
->rpc_th
);
1781 #endif /* WLC_HIGH_ONLY */
1783 if (osl_malloced(osh
)) {
1784 printf("**** Memory leak of bytes %d\n", osl_malloced(osh
));
1785 ASSERT(0 && "Memory Leak");
1792 /* transmit a packet */
1793 static int BCMFASTPATH
wl_start(struct sk_buff
*skb
, wl_info_t
*wl
)
1798 return wl_start_int(wl
, WL_TO_HW(wl
), skb
);
1800 #endif /* WLC_LOW */
1802 static int BCMFASTPATH
1803 wl_start_int(wl_info_t
*wl
, struct ieee80211_hw
*hw
, struct sk_buff
*skb
)
1805 #ifdef WLC_HIGH_ONLY
1808 wlc_sendpkt_mac80211(wl
->wlc
, skb
, hw
);
1809 #ifdef WLC_HIGH_ONLY
1812 return NETDEV_TX_OK
;
1815 void wl_txflowcontrol(wl_info_t
*wl
, struct wl_if
*wlif
, bool state
, int prio
)
1817 WL_ERROR(("Shouldn't be here %s\n", __func__
));
1820 #if defined(WLC_HIGH_ONLY)
1821 /* Schedule a completion handler to run at safe time */
1823 wl_schedule_task(wl_info_t
*wl
, void (*fn
) (struct wl_task
*task
),
1828 WL_TRACE(("wl%d: wl_schedule_task\n", wl
->pub
->unit
));
1830 if (!(task
= osl_malloc(wl
->osh
, sizeof(wl_task_t
)))) {
1831 WL_ERROR(("wl%d: wl_schedule_task: out of memory, malloced %d bytes\n", wl
->pub
->unit
, osl_malloced(wl
->osh
)));
1835 MY_INIT_WORK(&task
->work
, (work_func_t
) fn
);
1836 task
->context
= context
;
1838 if (!schedule_work(&task
->work
)) {
1839 WL_ERROR(("wl%d: schedule_work() failed\n", wl
->pub
->unit
));
1840 MFREE(wl
->osh
, task
, sizeof(wl_task_t
));
1844 atomic_inc(&wl
->callbacks
);
1848 #endif /* defined(WLC_HIGH_ONLY) */
1850 void wl_init(wl_info_t
*wl
)
1852 WL_TRACE(("wl%d: wl_init\n", wl
->pub
->unit
));
1859 uint
wl_reset(wl_info_t
*wl
)
1861 WL_TRACE(("wl%d: wl_reset\n", wl
->pub
->unit
));
1865 /* dpc will not be rescheduled */
1872 * These are interrupt on/off entry points. Disable interrupts
1873 * during interrupt state transition.
1875 void BCMFASTPATH
wl_intrson(wl_info_t
*wl
)
1877 #if defined(WLC_LOW)
1878 unsigned long flags
;
1880 INT_LOCK(wl
, flags
);
1881 wlc_intrson(wl
->wlc
);
1882 INT_UNLOCK(wl
, flags
);
1883 #endif /* WLC_LOW */
1886 bool wl_alloc_dma_resources(wl_info_t
*wl
, uint addrwidth
)
1891 uint32 BCMFASTPATH
wl_intrsoff(wl_info_t
*wl
)
1893 #if defined(WLC_LOW)
1894 unsigned long flags
;
1897 INT_LOCK(wl
, flags
);
1898 status
= wlc_intrsoff(wl
->wlc
);
1899 INT_UNLOCK(wl
, flags
);
1903 #endif /* WLC_LOW */
1906 void wl_intrsrestore(wl_info_t
*wl
, uint32 macintmask
)
1908 #if defined(WLC_LOW)
1909 unsigned long flags
;
1911 INT_LOCK(wl
, flags
);
1912 wlc_intrsrestore(wl
->wlc
, macintmask
);
1913 INT_UNLOCK(wl
, flags
);
1914 #endif /* WLC_LOW */
1917 int wl_up(wl_info_t
*wl
)
1924 error
= wlc_up(wl
->wlc
);
1929 void wl_down(wl_info_t
*wl
)
1931 uint callbacks
, ret_val
= 0;
1933 /* call common down function */
1934 ret_val
= wlc_down(wl
->wlc
);
1935 callbacks
= atomic_read(&wl
->callbacks
) - ret_val
;
1937 /* wait for down callbacks to complete */
1940 #ifndef WLC_HIGH_ONLY
1941 /* For HIGH_only driver, it's important to actually schedule other work,
1942 * not just spin wait since everything runs at schedule level
1944 SPINWAIT((atomic_read(&wl
->callbacks
) > callbacks
), 100 * 1000);
1945 #endif /* WLC_HIGH_ONLY */
1950 irqreturn_t BCMFASTPATH
wl_isr(int irq
, void *dev_id
)
1952 #if defined(WLC_LOW)
1955 unsigned long flags
;
1957 wl
= (wl_info_t
*) dev_id
;
1959 WL_ISRLOCK(wl
, flags
);
1961 /* call common first level interrupt handler */
1962 if ((ours
= wlc_isr(wl
->wlc
, &wantdpc
))) {
1963 /* if more to do... */
1966 /* ...and call the second level interrupt handler */
1968 ASSERT(wl
->resched
== FALSE
);
1969 tasklet_schedule(&wl
->tasklet
);
1973 WL_ISRUNLOCK(wl
, flags
);
1975 return IRQ_RETVAL(ours
);
1977 return IRQ_RETVAL(0);
1978 #endif /* WLC_LOW */
1981 static void BCMFASTPATH
wl_dpc(ulong data
)
1986 wl
= (wl_info_t
*) data
;
1990 /* call the common second level interrupt handler */
1993 unsigned long flags
;
1995 INT_LOCK(wl
, flags
);
1996 wlc_intrsupd(wl
->wlc
);
1997 INT_UNLOCK(wl
, flags
);
2000 wl
->resched
= wlc_dpc(wl
->wlc
, TRUE
);
2003 /* wlc_dpc() may bring the driver down */
2007 /* re-schedule dpc */
2009 tasklet_schedule(&wl
->tasklet
);
2011 /* re-enable interrupts */
2017 #endif /* WLC_LOW */
2020 static void wl_link_up(wl_info_t
*wl
, char *ifname
)
2022 WL_ERROR(("wl%d: link up (%s)\n", wl
->pub
->unit
, ifname
));
2025 static void wl_link_down(wl_info_t
*wl
, char *ifname
)
2027 WL_ERROR(("wl%d: link down (%s)\n", wl
->pub
->unit
, ifname
));
2030 void wl_event(wl_info_t
*wl
, char *ifname
, wlc_event_t
*e
)
2033 switch (e
->event
.event_type
) {
2035 case WLC_E_NDIS_LINK
:
2036 if (e
->event
.flags
& WLC_EVENT_MSG_LINK
)
2037 wl_link_up(wl
, ifname
);
2039 wl_link_down(wl
, ifname
);
2046 static void wl_timer(ulong data
)
2048 #ifndef WLC_HIGH_ONLY
2049 _wl_timer((wl_timer_t
*) data
);
2051 wl_timer_t
*t
= (wl_timer_t
*) data
;
2052 wl_schedule_task(t
->wl
, wl_timer_task
, t
);
2053 #endif /* WLC_HIGH_ONLY */
2056 static void _wl_timer(wl_timer_t
*t
)
2062 t
->timer
.expires
= jiffies
+ t
->ms
* HZ
/ 1000;
2063 atomic_inc(&t
->wl
->callbacks
);
2064 add_timer(&t
->timer
);
2072 atomic_dec(&t
->wl
->callbacks
);
2077 wl_timer_t
*wl_init_timer(wl_info_t
*wl
, void (*fn
) (void *arg
), void *arg
,
2082 if (!(t
= osl_malloc(wl
->osh
, sizeof(wl_timer_t
)))) {
2083 WL_ERROR(("wl%d: wl_init_timer: out of memory, malloced %d bytes\n", wl
->pub
->unit
, osl_malloced(wl
->osh
)));
2087 bzero(t
, sizeof(wl_timer_t
));
2089 init_timer(&t
->timer
);
2090 t
->timer
.data
= (ulong
) t
;
2091 t
->timer
.function
= wl_timer
;
2095 t
->next
= wl
->timers
;
2099 if ((t
->name
= osl_malloc(wl
->osh
, strlen(name
) + 1)))
2100 strcpy(t
->name
, name
);
2106 /* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate
2107 * as well as it's easier to make it periodic
2109 void wl_add_timer(wl_info_t
*wl
, wl_timer_t
*t
, uint ms
, int periodic
)
2113 WL_ERROR(("%s: Already set. Name: %s, per %d\n",
2114 __func__
, t
->name
, periodic
));
2120 t
->periodic
= (bool) periodic
;
2122 t
->timer
.expires
= jiffies
+ ms
* HZ
/ 1000;
2124 atomic_inc(&wl
->callbacks
);
2125 add_timer(&t
->timer
);
2128 /* return TRUE if timer successfully deleted, FALSE if still pending */
2129 bool wl_del_timer(wl_info_t
*wl
, wl_timer_t
*t
)
2133 if (!del_timer(&t
->timer
)) {
2136 atomic_dec(&wl
->callbacks
);
2142 void wl_free_timer(wl_info_t
*wl
, wl_timer_t
*t
)
2146 /* delete the timer in case it is active */
2147 wl_del_timer(wl
, t
);
2149 if (wl
->timers
== t
) {
2150 wl
->timers
= wl
->timers
->next
;
2153 MFREE(wl
->osh
, t
->name
, strlen(t
->name
) + 1);
2155 MFREE(wl
->osh
, t
, sizeof(wl_timer_t
));
2162 if (tmp
->next
== t
) {
2163 tmp
->next
= t
->next
;
2166 MFREE(wl
->osh
, t
->name
, strlen(t
->name
) + 1);
2168 MFREE(wl
->osh
, t
, sizeof(wl_timer_t
));
2176 static int wl_linux_watchdog(void *ctx
)
2178 wl_info_t
*wl
= (wl_info_t
*) ctx
;
2179 struct net_device_stats
*stats
= NULL
;
2183 ASSERT(wl
->stats_id
< 2);
2185 id
= 1 - wl
->stats_id
;
2187 stats
= &wl
->stats_watchdog
[id
];
2188 stats
->rx_packets
= WLCNTVAL(wl
->pub
->_cnt
->rxframe
);
2189 stats
->tx_packets
= WLCNTVAL(wl
->pub
->_cnt
->txframe
);
2190 stats
->rx_bytes
= WLCNTVAL(wl
->pub
->_cnt
->rxbyte
);
2191 stats
->tx_bytes
= WLCNTVAL(wl
->pub
->_cnt
->txbyte
);
2192 stats
->rx_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxerror
);
2193 stats
->tx_errors
= WLCNTVAL(wl
->pub
->_cnt
->txerror
);
2194 stats
->collisions
= 0;
2196 stats
->rx_length_errors
= 0;
2197 stats
->rx_over_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxoflo
);
2198 stats
->rx_crc_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxcrc
);
2199 stats
->rx_frame_errors
= 0;
2200 stats
->rx_fifo_errors
= WLCNTVAL(wl
->pub
->_cnt
->rxoflo
);
2201 stats
->rx_missed_errors
= 0;
2203 stats
->tx_fifo_errors
= WLCNTVAL(wl
->pub
->_cnt
->txuflo
);
2218 #ifdef WLC_HIGH_ONLY
2219 static void wl_rpc_down(void *wlh
)
2221 wl_info_t
*wl
= (wl_info_t
*) (wlh
);
2223 wlc_device_removed(wl
->wlc
);
2228 static int BCMFASTPATH
wl_start(struct sk_buff
*skb
, wl_info_t
*wl
)
2235 /* Lock the queue as tasklet could be running at this time */
2236 TXQ_LOCK(wl
, flags
);
2237 if (wl
->txq_head
== NULL
)
2240 wl
->txq_tail
->prev
= skb
;
2244 if (wl
->txq_dispatched
== FALSE
) {
2245 wl
->txq_dispatched
= TRUE
;
2247 if (schedule_work(&wl
->txq_task
.work
)) {
2248 atomic_inc(&wl
->callbacks
);
2250 WL_ERROR(("wl%d: wl_start/schedule_work failed\n",
2255 TXQ_UNLOCK(wl
, flags
);
2261 static void wl_start_txqwork(struct wl_task
*task
)
2263 wl_info_t
*wl
= (wl_info_t
*) task
->context
;
2264 struct sk_buff
*skb
;
2268 WL_TRACE(("wl%d: wl_start_txqwork\n", wl
->pub
->unit
));
2270 /* First remove an entry then go for execution */
2271 TXQ_LOCK(wl
, flags
);
2272 while (wl
->txq_head
) {
2274 wl
->txq_head
= skb
->prev
;
2276 if (wl
->txq_head
== NULL
)
2277 wl
->txq_tail
= NULL
;
2278 TXQ_UNLOCK(wl
, flags
);
2280 /* it has WL_LOCK/WL_UNLOCK inside */
2281 wl_start_int(wl
, WL_TO_HW(wl
), skb
);
2283 /* bounded our execution, reshedule ourself next */
2287 TXQ_LOCK(wl
, flags
);
2291 if (!schedule_work(&wl
->txq_task
.work
)) {
2292 WL_ERROR(("wl%d: wl_start/schedule_work failed\n",
2294 atomic_dec(&wl
->callbacks
);
2297 wl
->txq_dispatched
= FALSE
;
2298 TXQ_UNLOCK(wl
, flags
);
2299 atomic_dec(&wl
->callbacks
);
2305 static void wl_txq_free(wl_info_t
*wl
)
2307 struct sk_buff
*skb
;
2309 if (wl
->txq_head
== NULL
) {
2310 ASSERT(wl
->txq_tail
== NULL
);
2314 while (wl
->txq_head
) {
2316 wl
->txq_head
= skb
->prev
;
2317 PKTFREE(wl
->osh
, skb
, TRUE
);
2320 wl
->txq_tail
= NULL
;
2323 static void wl_rpcq_free(wl_info_t
*wl
)
2327 if (wl
->rpcq_head
== NULL
) {
2328 ASSERT(wl
->rpcq_tail
== NULL
);
2332 while (wl
->rpcq_head
) {
2333 buf
= wl
->rpcq_head
;
2334 wl
->rpcq_head
= bcm_rpc_buf_next_get(wl
->rpc_th
, buf
);
2335 bcm_rpc_buf_free(wl
->rpc_dispatch_ctx
.rpc
, buf
);
2338 wl
->rpcq_tail
= NULL
;
2341 static void wl_rpcq_dispatch(struct wl_task
*task
)
2343 wl_info_t
*wl
= (wl_info_t
*) task
->context
;
2347 /* First remove an entry then go for execution */
2348 RPCQ_LOCK(wl
, flags
);
2349 while (wl
->rpcq_head
) {
2350 buf
= wl
->rpcq_head
;
2351 wl
->rpcq_head
= bcm_rpc_buf_next_get(wl
->rpc_th
, buf
);
2353 if (wl
->rpcq_head
== NULL
)
2354 wl
->rpcq_tail
= NULL
;
2355 RPCQ_UNLOCK(wl
, flags
);
2358 wlc_rpc_high_dispatch(&wl
->rpc_dispatch_ctx
, buf
);
2361 RPCQ_LOCK(wl
, flags
);
2364 wl
->rpcq_dispatched
= FALSE
;
2366 RPCQ_UNLOCK(wl
, flags
);
2368 MFREE(wl
->osh
, task
, sizeof(wl_task_t
));
2369 atomic_dec(&wl
->callbacks
);
2372 static void wl_rpcq_add(wl_info_t
*wl
, rpc_buf_t
*buf
)
2376 bcm_rpc_buf_next_set(wl
->rpc_th
, buf
, NULL
);
2378 /* Lock the queue as tasklet could be running at this time */
2379 RPCQ_LOCK(wl
, flags
);
2380 if (wl
->rpcq_head
== NULL
)
2381 wl
->rpcq_head
= buf
;
2383 bcm_rpc_buf_next_set(wl
->rpc_th
, wl
->rpcq_tail
, buf
);
2385 wl
->rpcq_tail
= buf
;
2387 if (wl
->rpcq_dispatched
== FALSE
) {
2388 wl
->rpcq_dispatched
= TRUE
;
2389 wl_schedule_task(wl
, wl_rpcq_dispatch
, wl
);
2392 RPCQ_UNLOCK(wl
, flags
);
2396 static const struct name_entry rpc_name_tbl
[] = RPC_ID_TABLE
;
2399 /* dongle-side rpc dispatch routine */
2400 static void wl_rpc_dispatch_schedule(void *ctx
, struct rpc_buf
*buf
)
2403 wl_info_t
*wl
= (wl_info_t
*) ctx
;
2404 wlc_rpc_id_t rpc_id
;
2407 bcm_xdr_buf_init(&b
, bcm_rpc_buf_data(wl
->rpc_th
, buf
),
2408 bcm_rpc_buf_len_get(wl
->rpc_th
, buf
));
2410 err
= bcm_xdr_unpack_uint32(&b
, &rpc_id
);
2412 WL_TRACE(("%s: Dispatch id %s\n", __func__
,
2413 WLC_RPC_ID_LOOKUP(rpc_name_tbl
, rpc_id
)));
2415 /* Handle few emergency ones */
2418 wl_rpcq_add(wl
, buf
);
2423 static void wl_timer_task(wl_task_t
*task
)
2425 wl_timer_t
*t
= (wl_timer_t
*) task
->context
;
2428 MFREE(t
->wl
->osh
, task
, sizeof(wl_task_t
));
2430 /* This dec is for the task_schedule. The timer related
2431 * callback is decremented in _wl_timer
2433 atomic_dec(&t
->wl
->callbacks
);
2435 #endif /* WLC_HIGH_ONLY */
2437 #ifndef WLC_HIGH_ONLY
2438 char *wl_firmwares
[WL_MAX_FW
] = {
2444 int wl_ucode_init_buf(wl_info_t
*wl
, void **pbuf
, uint32 idx
)
2448 struct wl_fw_hdr
*hdr
;
2449 for (i
= 0; i
< wl
->fw
.fw_cnt
; i
++) {
2450 hdr
= (struct wl_fw_hdr
*)wl
->fw
.fw_hdr
[i
]->data
;
2451 for (entry
= 0; entry
< wl
->fw
.hdr_num_entries
[i
];
2453 if (hdr
->idx
== idx
) {
2454 pdata
= wl
->fw
.fw_bin
[i
]->data
+ hdr
->offset
;
2455 *pbuf
= kmalloc(hdr
->len
, GFP_ATOMIC
);
2456 if (*pbuf
== NULL
) {
2457 printf("fail to alloc %d bytes\n",
2460 bcopy(pdata
, *pbuf
, hdr
->len
);
2465 printf("ERROR: ucode buf tag:%d can not be found!\n", idx
);
2470 int wl_ucode_init_uint(wl_info_t
*wl
, uint32
*data
, uint32 idx
)
2474 struct wl_fw_hdr
*hdr
;
2475 for (i
= 0; i
< wl
->fw
.fw_cnt
; i
++) {
2476 hdr
= (struct wl_fw_hdr
*)wl
->fw
.fw_hdr
[i
]->data
;
2477 for (entry
= 0; entry
< wl
->fw
.hdr_num_entries
[i
];
2479 if (hdr
->idx
== idx
) {
2480 pdata
= wl
->fw
.fw_bin
[i
]->data
+ hdr
->offset
;
2481 ASSERT(hdr
->len
== 4);
2482 *data
= *((uint32
*) pdata
);
2487 printf("ERROR: ucode tag:%d can not be found!\n", idx
);
2490 #endif /* WLC_LOW */
2492 static int wl_request_fw(wl_info_t
*wl
, struct pci_dev
*pdev
)
2495 struct device
*device
= &pdev
->dev
;
2499 bzero((void *)&wl
->fw
, sizeof(struct wl_firmware
));
2500 for (i
= 0; i
< WL_MAX_FW
; i
++) {
2501 if (wl_firmwares
[i
] == NULL
)
2503 sprintf(fw_name
, "%s-%d.fw", wl_firmwares
[i
],
2504 UCODE_LOADER_API_VER
);
2505 WL_NONE(("request fw %s\n", fw_name
));
2506 status
= request_firmware(&wl
->fw
.fw_bin
[i
], fw_name
, device
);
2508 printf("fail to request firmware %s\n", fw_name
);
2512 WL_NONE(("request fw %s\n", fw_name
));
2513 sprintf(fw_name
, "%s_hdr-%d.fw", wl_firmwares
[i
],
2514 UCODE_LOADER_API_VER
);
2515 status
= request_firmware(&wl
->fw
.fw_hdr
[i
], fw_name
, device
);
2517 printf("fail to request firmware %s\n", fw_name
);
2521 wl
->fw
.hdr_num_entries
[i
] =
2522 wl
->fw
.fw_hdr
[i
]->size
/ (sizeof(struct wl_fw_hdr
));
2523 WL_NONE(("request fw %s find: %d entries\n", fw_name
,
2524 wl
->fw
.hdr_num_entries
[i
]));
2527 wl_ucode_data_init(wl
);
2532 void wl_ucode_free_buf(void *p
)
2536 #endif /* WLC_LOW */
2538 static void wl_release_fw(wl_info_t
*wl
)
2541 for (i
= 0; i
< WL_MAX_FW
; i
++) {
2542 release_firmware(wl
->fw
.fw_bin
[i
]);
2543 release_firmware(wl
->fw
.fw_hdr
[i
]);
2546 #endif /* WLC_HIGH_ONLY */