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