diff options
Diffstat (limited to 'drivers/staging/brcm80211/sys/wl_mac80211.c')
-rw-r--r-- | drivers/staging/brcm80211/sys/wl_mac80211.c | 1026 |
1 files changed, 245 insertions, 781 deletions
diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index d060377629a..bdd629d72a7 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c | |||
@@ -21,72 +21,36 @@ | |||
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/pci_ids.h> | 22 | #include <linux/pci_ids.h> |
23 | #include <bcmdefs.h> | 23 | #include <bcmdefs.h> |
24 | #include <linuxver.h> | 24 | #include <linux/module.h> |
25 | #include <linux/pci.h> | ||
26 | #include <linux/sched.h> | ||
25 | #include <osl.h> | 27 | #include <osl.h> |
26 | #define WLC_MAXBSSCFG 1 /* single BSS configs */ | 28 | #define WLC_MAXBSSCFG 1 /* single BSS configs */ |
27 | 29 | ||
28 | #include <wlc_cfg.h> | 30 | #include <wlc_cfg.h> |
29 | #include <net/mac80211.h> | 31 | #include <net/mac80211.h> |
30 | #include <epivers.h> | ||
31 | #ifndef WLC_HIGH_ONLY | ||
32 | #include <phy_version.h> | 32 | #include <phy_version.h> |
33 | #endif | ||
34 | #include <bcmutils.h> | 33 | #include <bcmutils.h> |
35 | #include <pcicfg.h> | 34 | #include <pcicfg.h> |
36 | #include <wlioctl.h> | 35 | #include <wlioctl.h> |
37 | #include <wlc_key.h> | 36 | #include <wlc_key.h> |
37 | #include <sbhndpio.h> | ||
38 | #include <sbhnddma.h> | ||
38 | #include <wlc_channel.h> | 39 | #include <wlc_channel.h> |
39 | #include <wlc_pub.h> | 40 | #include <wlc_pub.h> |
40 | #include <wlc_scb.h> | 41 | #include <wlc_scb.h> |
41 | #include <wl_dbg.h> | 42 | #include <wl_dbg.h> |
42 | #ifdef BCMSDIO | ||
43 | #include <bcmsdh.h> | ||
44 | #endif | ||
45 | #include <wl_export.h> | 43 | #include <wl_export.h> |
46 | #ifdef WLC_HIGH_ONLY | ||
47 | #include "dbus.h" | ||
48 | #include "bcm_rpc_tp.h" | ||
49 | #include "bcm_rpc.h" | ||
50 | #include "bcm_xdr.h" | ||
51 | #include "wlc_rpc.h" | ||
52 | #endif | ||
53 | 44 | ||
54 | #include <wl_mac80211.h> | 45 | #include <wl_mac80211.h> |
55 | #include <linux/firmware.h> | 46 | #include <linux/firmware.h> |
56 | #ifndef WLC_HIGH_ONLY | ||
57 | #include <wl_ucode.h> | 47 | #include <wl_ucode.h> |
58 | #include <d11ucode_ext.h> | 48 | #include <d11ucode_ext.h> |
59 | #endif | ||
60 | 49 | ||
61 | #ifdef BCMSDIO | ||
62 | extern struct device *sdiommc_dev; | ||
63 | #endif | ||
64 | |||
65 | extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, | ||
66 | bool suspend); | ||
67 | bool wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw); | ||
68 | void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc); | ||
69 | void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, | ||
70 | const struct ether_addr *addr); | ||
71 | 50 | ||
72 | static void wl_timer(unsigned long data); | 51 | static void wl_timer(unsigned long data); |
73 | static void _wl_timer(wl_timer_t *t); | 52 | static void _wl_timer(wl_timer_t *t); |
74 | 53 | ||
75 | #ifdef WLC_HIGH_ONLY | ||
76 | #define RPCQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->rpcq_lock, (_flags)) | ||
77 | #define RPCQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->rpcq_lock, (_flags)) | ||
78 | #define TXQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->txq_lock, (_flags)) | ||
79 | #define TXQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->txq_lock, (_flags)) | ||
80 | static void wl_rpc_down(void *wlh); | ||
81 | static void wl_rpcq_free(wl_info_t *wl); | ||
82 | static void wl_rpcq_dispatch(struct wl_task *task); | ||
83 | static void wl_rpc_dispatch_schedule(void *ctx, struct rpc_buf *buf); | ||
84 | static void wl_start_txqwork(struct wl_task *task); | ||
85 | static void wl_txq_free(wl_info_t *wl); | ||
86 | static void wl_timer_task(wl_task_t *task); | ||
87 | static int wl_schedule_task(wl_info_t *wl, void (*fn) (struct wl_task *), | ||
88 | void *context); | ||
89 | #endif /* WLC_HIGH_ONLY */ | ||
90 | 54 | ||
91 | static int ieee_hw_init(struct ieee80211_hw *hw); | 55 | static int ieee_hw_init(struct ieee80211_hw *hw); |
92 | static int ieee_hw_rate_init(struct ieee80211_hw *hw); | 56 | static int ieee_hw_rate_init(struct ieee80211_hw *hw); |
@@ -134,16 +98,14 @@ struct ieee80211_tkip_data { | |||
134 | u8 rx_hdr[16], tx_hdr[16]; | 98 | u8 rx_hdr[16], tx_hdr[16]; |
135 | }; | 99 | }; |
136 | 100 | ||
137 | #ifndef WLC_HIGH_ONLY | 101 | #define WL_DEV_IF(dev) ((struct wl_if *)netdev_priv(dev)) |
138 | #define WL_DEV_IF(dev) ((wl_if_t *)netdev_priv(dev)) | 102 | #define WL_INFO(dev) ((struct wl_info *)(WL_DEV_IF(dev)->wl)) |
139 | #define WL_INFO(dev) ((wl_info_t *)(WL_DEV_IF(dev)->wl)) /* points to wl */ | 103 | static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev); |
140 | static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev); | 104 | static void wl_release_fw(struct wl_info *wl); |
141 | static void wl_release_fw(wl_info_t *wl); | ||
142 | #endif | ||
143 | 105 | ||
144 | /* local prototypes */ | 106 | /* local prototypes */ |
145 | static int wl_start(struct sk_buff *skb, wl_info_t *wl); | 107 | static int wl_start(struct sk_buff *skb, struct wl_info *wl); |
146 | static int wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw, | 108 | static int wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw, |
147 | struct sk_buff *skb); | 109 | struct sk_buff *skb); |
148 | static void wl_dpc(unsigned long data); | 110 | static void wl_dpc(unsigned long data); |
149 | 111 | ||
@@ -152,7 +114,6 @@ MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); | |||
152 | MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); | 114 | MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); |
153 | MODULE_LICENSE("Dual BSD/GPL"); | 115 | MODULE_LICENSE("Dual BSD/GPL"); |
154 | 116 | ||
155 | #ifndef BCMSDIO | ||
156 | /* recognized PCI IDs */ | 117 | /* recognized PCI IDs */ |
157 | static struct pci_device_id wl_id_table[] = { | 118 | static struct pci_device_id wl_id_table[] = { |
158 | {PCI_VENDOR_ID_BROADCOM, 0x4357, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43225 2G */ | 119 | {PCI_VENDOR_ID_BROADCOM, 0x4357, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43225 2G */ |
@@ -163,55 +124,18 @@ static struct pci_device_id wl_id_table[] = { | |||
163 | 124 | ||
164 | MODULE_DEVICE_TABLE(pci, wl_id_table); | 125 | MODULE_DEVICE_TABLE(pci, wl_id_table); |
165 | static void wl_remove(struct pci_dev *pdev); | 126 | static void wl_remove(struct pci_dev *pdev); |
166 | #endif /* !BCMSDIO */ | ||
167 | 127 | ||
168 | #ifdef BCMSDIO | ||
169 | static uint sd_drivestrength = 6; | ||
170 | module_param(sd_drivestrength, uint, 0); | ||
171 | #endif | ||
172 | 128 | ||
173 | #ifdef BCMDBG | 129 | #ifdef BCMDBG |
174 | static int msglevel = 0xdeadbeef; | 130 | static int msglevel = 0xdeadbeef; |
175 | module_param(msglevel, int, 0); | 131 | module_param(msglevel, int, 0); |
176 | #ifndef WLC_HIGH_ONLY | ||
177 | static int phymsglevel = 0xdeadbeef; | 132 | static int phymsglevel = 0xdeadbeef; |
178 | module_param(phymsglevel, int, 0); | 133 | module_param(phymsglevel, int, 0); |
179 | #endif /* WLC_HIGH_ONLY */ | ||
180 | #endif /* BCMDBG */ | 134 | #endif /* BCMDBG */ |
181 | 135 | ||
182 | static int oneonly; | ||
183 | module_param(oneonly, int, 0); | ||
184 | |||
185 | static int piomode; | ||
186 | module_param(piomode, int, 0); | ||
187 | |||
188 | static int instance_base; /* Starting instance number */ | ||
189 | module_param(instance_base, int, 0); | ||
190 | |||
191 | #if defined(BCMDBG) | ||
192 | static char *macaddr; | ||
193 | module_param(macaddr, charp, S_IRUGO); | ||
194 | #endif | ||
195 | |||
196 | static int nompc = 1; | ||
197 | module_param(nompc, int, 0); | ||
198 | |||
199 | static char name[IFNAMSIZ] = "eth%d"; | ||
200 | module_param_string(name, name, IFNAMSIZ, 0); | ||
201 | |||
202 | #ifndef SRCBASE | ||
203 | #define SRCBASE "." | ||
204 | #endif | ||
205 | |||
206 | #define WL_MAGIC 0xdeadbeef | ||
207 | |||
208 | #define HW_TO_WL(hw) (hw->priv) | 136 | #define HW_TO_WL(hw) (hw->priv) |
209 | #define WL_TO_HW(wl) (wl->pub->ieee_hw) | 137 | #define WL_TO_HW(wl) (wl->pub->ieee_hw) |
210 | #ifdef WLC_HIGH_ONLY | ||
211 | static int wl_ops_tx_nl(struct ieee80211_hw *hw, struct sk_buff *skb); | ||
212 | #else | ||
213 | static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | 138 | static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb); |
214 | #endif | ||
215 | static int wl_ops_start(struct ieee80211_hw *hw); | 139 | static int wl_ops_start(struct ieee80211_hw *hw); |
216 | static void wl_ops_stop(struct ieee80211_hw *hw); | 140 | static void wl_ops_stop(struct ieee80211_hw *hw); |
217 | static int wl_ops_add_interface(struct ieee80211_hw *hw, | 141 | static int wl_ops_add_interface(struct ieee80211_hw *hw, |
@@ -249,28 +173,13 @@ static int wl_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
249 | enum ieee80211_ampdu_mlme_action action, | 173 | enum ieee80211_ampdu_mlme_action action, |
250 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); | 174 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); |
251 | 175 | ||
252 | #ifdef WLC_HIGH_ONLY | ||
253 | static int wl_ops_tx_nl(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
254 | { | ||
255 | int status; | ||
256 | wl_info_t *wl = hw->priv; | ||
257 | if (!wl->pub->up) { | ||
258 | WL_ERROR(("ops->tx called while down\n")); | ||
259 | status = -ENETDOWN; | ||
260 | goto done; | ||
261 | } | ||
262 | status = wl_start(skb, wl); | ||
263 | done: | ||
264 | return status; | ||
265 | } | ||
266 | #else | ||
267 | static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 176 | static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
268 | { | 177 | { |
269 | int status; | 178 | int status; |
270 | wl_info_t *wl = hw->priv; | 179 | struct wl_info *wl = hw->priv; |
271 | WL_LOCK(wl); | 180 | WL_LOCK(wl); |
272 | if (!wl->pub->up) { | 181 | if (!wl->pub->up) { |
273 | WL_ERROR(("ops->tx called while down\n")); | 182 | WL_ERROR("ops->tx called while down\n"); |
274 | status = -ENETDOWN; | 183 | status = -ENETDOWN; |
275 | goto done; | 184 | goto done; |
276 | } | 185 | } |
@@ -279,13 +188,14 @@ static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
279 | WL_UNLOCK(wl); | 188 | WL_UNLOCK(wl); |
280 | return status; | 189 | return status; |
281 | } | 190 | } |
282 | #endif /* WLC_HIGH_ONLY */ | ||
283 | 191 | ||
284 | static int wl_ops_start(struct ieee80211_hw *hw) | 192 | static int wl_ops_start(struct ieee80211_hw *hw) |
285 | { | 193 | { |
286 | wl_info_t *wl = hw->priv; | 194 | struct wl_info *wl = hw->priv; |
287 | /* struct ieee80211_channel *curchan = hw->conf.channel; */ | 195 | /* |
288 | WL_NONE(("%s : Initial channel: %d\n", __func__, curchan->hw_value)); | 196 | struct ieee80211_channel *curchan = hw->conf.channel; |
197 | WL_NONE("%s : Initial channel: %d\n", __func__, curchan->hw_value); | ||
198 | */ | ||
289 | 199 | ||
290 | WL_LOCK(wl); | 200 | WL_LOCK(wl); |
291 | ieee80211_wake_queues(hw); | 201 | ieee80211_wake_queues(hw); |
@@ -296,7 +206,7 @@ static int wl_ops_start(struct ieee80211_hw *hw) | |||
296 | 206 | ||
297 | static void wl_ops_stop(struct ieee80211_hw *hw) | 207 | static void wl_ops_stop(struct ieee80211_hw *hw) |
298 | { | 208 | { |
299 | wl_info_t *wl = hw->priv; | 209 | struct wl_info *wl = hw->priv; |
300 | ASSERT(wl); | 210 | ASSERT(wl); |
301 | WL_LOCK(wl); | 211 | WL_LOCK(wl); |
302 | wl_down(wl); | 212 | wl_down(wl); |
@@ -309,7 +219,7 @@ static void wl_ops_stop(struct ieee80211_hw *hw) | |||
309 | static int | 219 | static int |
310 | wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 220 | wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
311 | { | 221 | { |
312 | wl_info_t *wl; | 222 | struct wl_info *wl; |
313 | int err; | 223 | int err; |
314 | 224 | ||
315 | /* Just STA for now */ | 225 | /* Just STA for now */ |
@@ -318,8 +228,8 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
318 | vif->type != NL80211_IFTYPE_STATION && | 228 | vif->type != NL80211_IFTYPE_STATION && |
319 | vif->type != NL80211_IFTYPE_WDS && | 229 | vif->type != NL80211_IFTYPE_WDS && |
320 | vif->type != NL80211_IFTYPE_ADHOC) { | 230 | vif->type != NL80211_IFTYPE_ADHOC) { |
321 | WL_ERROR(("%s: Attempt to add type %d, only STA for now\n", | 231 | WL_ERROR("%s: Attempt to add type %d, only STA for now\n", |
322 | __func__, vif->type)); | 232 | __func__, vif->type); |
323 | return -EOPNOTSUPP; | 233 | return -EOPNOTSUPP; |
324 | } | 234 | } |
325 | 235 | ||
@@ -329,7 +239,7 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
329 | WL_UNLOCK(wl); | 239 | WL_UNLOCK(wl); |
330 | 240 | ||
331 | if (err != 0) | 241 | if (err != 0) |
332 | WL_ERROR(("%s: wl_up() returned %d\n", __func__, err)); | 242 | WL_ERROR("%s: wl_up() returned %d\n", __func__, err); |
333 | return err; | 243 | return err; |
334 | } | 244 | } |
335 | 245 | ||
@@ -343,7 +253,7 @@ static int | |||
343 | ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, | 253 | ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, |
344 | enum nl80211_channel_type type) | 254 | enum nl80211_channel_type type) |
345 | { | 255 | { |
346 | wl_info_t *wl = HW_TO_WL(hw); | 256 | struct wl_info *wl = HW_TO_WL(hw); |
347 | int err = 0; | 257 | int err = 0; |
348 | 258 | ||
349 | switch (type) { | 259 | switch (type) { |
@@ -355,8 +265,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, | |||
355 | break; | 265 | break; |
356 | case NL80211_CHAN_HT40MINUS: | 266 | case NL80211_CHAN_HT40MINUS: |
357 | case NL80211_CHAN_HT40PLUS: | 267 | case NL80211_CHAN_HT40PLUS: |
358 | WL_ERROR(("%s: Need to implement 40 Mhz Channels!\n", | 268 | WL_ERROR("%s: Need to implement 40 Mhz Channels!\n", __func__); |
359 | __func__)); | ||
360 | break; | 269 | break; |
361 | } | 270 | } |
362 | 271 | ||
@@ -368,17 +277,17 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, | |||
368 | static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) | 277 | static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) |
369 | { | 278 | { |
370 | struct ieee80211_conf *conf = &hw->conf; | 279 | struct ieee80211_conf *conf = &hw->conf; |
371 | wl_info_t *wl = HW_TO_WL(hw); | 280 | struct wl_info *wl = HW_TO_WL(hw); |
372 | int err = 0; | 281 | int err = 0; |
373 | int new_int; | 282 | int new_int; |
374 | 283 | ||
375 | if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { | 284 | if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { |
376 | WL_NONE(("%s: Setting listen interval to %d\n", | 285 | WL_NONE("%s: Setting listen interval to %d\n", |
377 | __func__, conf->listen_interval)); | 286 | __func__, conf->listen_interval); |
378 | if (wlc_iovar_setint | 287 | if (wlc_iovar_setint |
379 | (wl->wlc, "bcn_li_bcn", conf->listen_interval)) { | 288 | (wl->wlc, "bcn_li_bcn", conf->listen_interval)) { |
380 | WL_ERROR(("%s: Error setting listen_interval\n", | 289 | WL_ERROR("%s: Error setting listen_interval\n", |
381 | __func__)); | 290 | __func__); |
382 | err = -EIO; | 291 | err = -EIO; |
383 | goto config_out; | 292 | goto config_out; |
384 | } | 293 | } |
@@ -386,41 +295,42 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) | |||
386 | ASSERT(new_int == conf->listen_interval); | 295 | ASSERT(new_int == conf->listen_interval); |
387 | } | 296 | } |
388 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) | 297 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) |
389 | WL_NONE(("Need to set monitor mode\n")); | 298 | WL_NONE("Need to set monitor mode\n"); |
390 | if (changed & IEEE80211_CONF_CHANGE_PS) | 299 | if (changed & IEEE80211_CONF_CHANGE_PS) |
391 | WL_NONE(("Need to set Power-save mode\n")); | 300 | WL_NONE("Need to set Power-save mode\n"); |
392 | 301 | ||
393 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 302 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
394 | WL_NONE(("%s: Setting tx power to %d dbm\n", __func__, | 303 | WL_NONE("%s: Setting tx power to %d dbm\n", |
395 | conf->power_level)); | 304 | __func__, conf->power_level); |
396 | if (wlc_iovar_setint | 305 | if (wlc_iovar_setint |
397 | (wl->wlc, "qtxpower", conf->power_level * 4)) { | 306 | (wl->wlc, "qtxpower", conf->power_level * 4)) { |
398 | WL_ERROR(("%s: Error setting power_level\n", __func__)); | 307 | WL_ERROR("%s: Error setting power_level\n", __func__); |
399 | err = -EIO; | 308 | err = -EIO; |
400 | goto config_out; | 309 | goto config_out; |
401 | } | 310 | } |
402 | wlc_iovar_getint(wl->wlc, "qtxpower", &new_int); | 311 | wlc_iovar_getint(wl->wlc, "qtxpower", &new_int); |
403 | if (new_int != (conf->power_level * 4)) | 312 | if (new_int != (conf->power_level * 4)) |
404 | WL_ERROR(("%s: Power level req != actual, %d %d\n", | 313 | WL_ERROR("%s: Power level req != actual, %d %d\n", |
405 | __func__, conf->power_level * 4, new_int)); | 314 | __func__, conf->power_level * 4, new_int); |
406 | } | 315 | } |
407 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 316 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
408 | err = ieee_set_channel(hw, conf->channel, conf->channel_type); | 317 | err = ieee_set_channel(hw, conf->channel, conf->channel_type); |
409 | } | 318 | } |
410 | if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { | 319 | if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { |
411 | WL_NONE(("%s: srl %d, lrl %d\n", __func__, | 320 | WL_NONE("%s: srl %d, lrl %d\n", |
412 | conf->short_frame_max_tx_count, | 321 | __func__, |
413 | conf->long_frame_max_tx_count)); | 322 | conf->short_frame_max_tx_count, |
323 | conf->long_frame_max_tx_count); | ||
414 | if (wlc_set | 324 | if (wlc_set |
415 | (wl->wlc, WLC_SET_SRL, | 325 | (wl->wlc, WLC_SET_SRL, |
416 | conf->short_frame_max_tx_count) < 0) { | 326 | conf->short_frame_max_tx_count) < 0) { |
417 | WL_ERROR(("%s: Error setting srl\n", __func__)); | 327 | WL_ERROR("%s: Error setting srl\n", __func__); |
418 | err = -EIO; | 328 | err = -EIO; |
419 | goto config_out; | 329 | goto config_out; |
420 | } | 330 | } |
421 | if (wlc_set(wl->wlc, WLC_SET_LRL, conf->long_frame_max_tx_count) | 331 | if (wlc_set(wl->wlc, WLC_SET_LRL, conf->long_frame_max_tx_count) |
422 | < 0) { | 332 | < 0) { |
423 | WL_ERROR(("%s: Error setting lrl\n", __func__)); | 333 | WL_ERROR("%s: Error setting lrl\n", __func__); |
424 | err = -EIO; | 334 | err = -EIO; |
425 | goto config_out; | 335 | goto config_out; |
426 | } | 336 | } |
@@ -435,32 +345,29 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, | |||
435 | struct ieee80211_vif *vif, | 345 | struct ieee80211_vif *vif, |
436 | struct ieee80211_bss_conf *info, u32 changed) | 346 | struct ieee80211_bss_conf *info, u32 changed) |
437 | { | 347 | { |
438 | wl_info_t *wl = HW_TO_WL(hw); | 348 | struct wl_info *wl = HW_TO_WL(hw); |
439 | int val; | 349 | int val; |
440 | 350 | ||
441 | #ifdef WLC_HIGH_ONLY | ||
442 | WL_LOCK(wl); | ||
443 | #endif | ||
444 | 351 | ||
445 | if (changed & BSS_CHANGED_ASSOC) { | 352 | if (changed & BSS_CHANGED_ASSOC) { |
446 | WL_ERROR(("Associated:\t%s\n", info->assoc ? "True" : "False")); | 353 | WL_ERROR("Associated:\t%s\n", info->assoc ? "True" : "False"); |
447 | /* association status changed (associated/disassociated) | 354 | /* association status changed (associated/disassociated) |
448 | * also implies a change in the AID. | 355 | * also implies a change in the AID. |
449 | */ | 356 | */ |
450 | } | 357 | } |
451 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | 358 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { |
452 | WL_NONE(("Use_cts_prot:\t%s Implement me\n", | 359 | WL_NONE("Use_cts_prot:\t%s Implement me\n", |
453 | info->use_cts_prot ? "True" : "False")); | 360 | info->use_cts_prot ? "True" : "False"); |
454 | /* CTS protection changed */ | 361 | /* CTS protection changed */ |
455 | } | 362 | } |
456 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | 363 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
457 | WL_NONE(("Short preamble:\t%s Implement me\n", | 364 | WL_NONE("Short preamble:\t%s Implement me\n", |
458 | info->use_short_preamble ? "True" : "False")); | 365 | info->use_short_preamble ? "True" : "False"); |
459 | /* preamble changed */ | 366 | /* preamble changed */ |
460 | } | 367 | } |
461 | if (changed & BSS_CHANGED_ERP_SLOT) { | 368 | if (changed & BSS_CHANGED_ERP_SLOT) { |
462 | WL_NONE(("Changing short slot:\t%s\n", | 369 | WL_NONE("Changing short slot:\t%s\n", |
463 | info->use_short_slot ? "True" : "False")); | 370 | info->use_short_slot ? "True" : "False"); |
464 | if (info->use_short_slot) | 371 | if (info->use_short_slot) |
465 | val = 1; | 372 | val = 1; |
466 | else | 373 | else |
@@ -470,39 +377,36 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, | |||
470 | } | 377 | } |
471 | 378 | ||
472 | if (changed & BSS_CHANGED_HT) { | 379 | if (changed & BSS_CHANGED_HT) { |
473 | WL_NONE(("%s: HT mode - Implement me\n", __func__)); | 380 | WL_NONE("%s: HT mode - Implement me\n", __func__); |
474 | /* 802.11n parameters changed */ | 381 | /* 802.11n parameters changed */ |
475 | } | 382 | } |
476 | if (changed & BSS_CHANGED_BASIC_RATES) { | 383 | if (changed & BSS_CHANGED_BASIC_RATES) { |
477 | WL_NONE(("Need to change Basic Rates:\t0x%x! Implement me\n", | 384 | WL_NONE("Need to change Basic Rates:\t0x%x! Implement me\n", |
478 | (u32) info->basic_rates)); | 385 | (u32) info->basic_rates); |
479 | /* Basic rateset changed */ | 386 | /* Basic rateset changed */ |
480 | } | 387 | } |
481 | if (changed & BSS_CHANGED_BEACON_INT) { | 388 | if (changed & BSS_CHANGED_BEACON_INT) { |
482 | WL_NONE(("Beacon Interval:\t%d Implement me\n", | 389 | WL_NONE("Beacon Interval:\t%d Implement me\n", |
483 | info->beacon_int)); | 390 | info->beacon_int); |
484 | /* Beacon interval changed */ | 391 | /* Beacon interval changed */ |
485 | } | 392 | } |
486 | if (changed & BSS_CHANGED_BSSID) { | 393 | if (changed & BSS_CHANGED_BSSID) { |
487 | WL_NONE(("new BSSID:\taid %d bss:%pM\n", info->aid, | 394 | WL_NONE("new BSSID:\taid %d bss:%pM\n", |
488 | info->bssid)); | 395 | info->aid, info->bssid); |
489 | /* BSSID changed, for whatever reason (IBSS and managed mode) */ | 396 | /* BSSID changed, for whatever reason (IBSS and managed mode) */ |
490 | /* FIXME: need to store bssid in bsscfg */ | 397 | /* FIXME: need to store bssid in bsscfg */ |
491 | wlc_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, | 398 | wlc_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, |
492 | (struct ether_addr *)info->bssid); | 399 | (struct ether_addr *)info->bssid); |
493 | } | 400 | } |
494 | if (changed & BSS_CHANGED_BEACON) { | 401 | if (changed & BSS_CHANGED_BEACON) { |
495 | WL_ERROR(("BSS_CHANGED_BEACON\n")); | 402 | WL_ERROR("BSS_CHANGED_BEACON\n"); |
496 | /* Beacon data changed, retrieve new beacon (beaconing modes) */ | 403 | /* Beacon data changed, retrieve new beacon (beaconing modes) */ |
497 | } | 404 | } |
498 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 405 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
499 | WL_ERROR(("Beacon enabled:\t%s\n", | 406 | WL_ERROR("Beacon enabled:\t%s\n", |
500 | info->enable_beacon ? "True" : "False")); | 407 | info->enable_beacon ? "True" : "False"); |
501 | /* Beaconing should be enabled/disabled (beaconing modes) */ | 408 | /* Beaconing should be enabled/disabled (beaconing modes) */ |
502 | } | 409 | } |
503 | #ifdef WLC_HIGH_ONLY | ||
504 | WL_UNLOCK(wl); | ||
505 | #endif | ||
506 | return; | 410 | return; |
507 | } | 411 | } |
508 | 412 | ||
@@ -511,27 +415,24 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, | |||
511 | unsigned int changed_flags, | 415 | unsigned int changed_flags, |
512 | unsigned int *total_flags, u64 multicast) | 416 | unsigned int *total_flags, u64 multicast) |
513 | { | 417 | { |
514 | #ifndef WLC_HIGH_ONLY | 418 | struct wl_info *wl = hw->priv; |
515 | wl_info_t *wl = hw->priv; | ||
516 | #endif | ||
517 | 419 | ||
518 | changed_flags &= MAC_FILTERS; | 420 | changed_flags &= MAC_FILTERS; |
519 | *total_flags &= MAC_FILTERS; | 421 | *total_flags &= MAC_FILTERS; |
520 | if (changed_flags & FIF_PROMISC_IN_BSS) | 422 | if (changed_flags & FIF_PROMISC_IN_BSS) |
521 | WL_ERROR(("FIF_PROMISC_IN_BSS\n")); | 423 | WL_ERROR("FIF_PROMISC_IN_BSS\n"); |
522 | if (changed_flags & FIF_ALLMULTI) | 424 | if (changed_flags & FIF_ALLMULTI) |
523 | WL_ERROR(("FIF_ALLMULTI\n")); | 425 | WL_ERROR("FIF_ALLMULTI\n"); |
524 | if (changed_flags & FIF_FCSFAIL) | 426 | if (changed_flags & FIF_FCSFAIL) |
525 | WL_ERROR(("FIF_FCSFAIL\n")); | 427 | WL_ERROR("FIF_FCSFAIL\n"); |
526 | if (changed_flags & FIF_PLCPFAIL) | 428 | if (changed_flags & FIF_PLCPFAIL) |
527 | WL_ERROR(("FIF_PLCPFAIL\n")); | 429 | WL_ERROR("FIF_PLCPFAIL\n"); |
528 | if (changed_flags & FIF_CONTROL) | 430 | if (changed_flags & FIF_CONTROL) |
529 | WL_ERROR(("FIF_CONTROL\n")); | 431 | WL_ERROR("FIF_CONTROL\n"); |
530 | if (changed_flags & FIF_OTHER_BSS) | 432 | if (changed_flags & FIF_OTHER_BSS) |
531 | WL_ERROR(("FIF_OTHER_BSS\n")); | 433 | WL_ERROR("FIF_OTHER_BSS\n"); |
532 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { | 434 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { |
533 | WL_NONE(("FIF_BCN_PRBRESP_PROMISC\n")); | 435 | WL_NONE("FIF_BCN_PRBRESP_PROMISC\n"); |
534 | #ifndef WLC_HIGH_ONLY | ||
535 | WL_LOCK(wl); | 436 | WL_LOCK(wl); |
536 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { | 437 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { |
537 | wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; | 438 | wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; |
@@ -541,7 +442,6 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, | |||
541 | wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS; | 442 | wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS; |
542 | } | 443 | } |
543 | WL_UNLOCK(wl); | 444 | WL_UNLOCK(wl); |
544 | #endif | ||
545 | } | 445 | } |
546 | return; | 446 | return; |
547 | } | 447 | } |
@@ -549,25 +449,25 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, | |||
549 | static int | 449 | static int |
550 | wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) | 450 | wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) |
551 | { | 451 | { |
552 | WL_ERROR(("%s: Enter\n", __func__)); | 452 | WL_ERROR("%s: Enter\n", __func__); |
553 | return 0; | 453 | return 0; |
554 | } | 454 | } |
555 | 455 | ||
556 | static void wl_ops_sw_scan_start(struct ieee80211_hw *hw) | 456 | static void wl_ops_sw_scan_start(struct ieee80211_hw *hw) |
557 | { | 457 | { |
558 | WL_NONE(("Scan Start\n")); | 458 | WL_NONE("Scan Start\n"); |
559 | return; | 459 | return; |
560 | } | 460 | } |
561 | 461 | ||
562 | static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw) | 462 | static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw) |
563 | { | 463 | { |
564 | WL_NONE(("Scan Complete\n")); | 464 | WL_NONE("Scan Complete\n"); |
565 | return; | 465 | return; |
566 | } | 466 | } |
567 | 467 | ||
568 | static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf) | 468 | static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf) |
569 | { | 469 | { |
570 | WL_ERROR(("%s: Enter\n", __func__)); | 470 | WL_ERROR("%s: Enter\n", __func__); |
571 | return; | 471 | return; |
572 | } | 472 | } |
573 | 473 | ||
@@ -575,13 +475,13 @@ static int | |||
575 | wl_ops_get_stats(struct ieee80211_hw *hw, | 475 | wl_ops_get_stats(struct ieee80211_hw *hw, |
576 | struct ieee80211_low_level_stats *stats) | 476 | struct ieee80211_low_level_stats *stats) |
577 | { | 477 | { |
578 | WL_ERROR(("%s: Enter\n", __func__)); | 478 | WL_ERROR("%s: Enter\n", __func__); |
579 | return 0; | 479 | return 0; |
580 | } | 480 | } |
581 | 481 | ||
582 | static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | 482 | static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) |
583 | { | 483 | { |
584 | WL_ERROR(("%s: Enter\n", __func__)); | 484 | WL_ERROR("%s: Enter\n", __func__); |
585 | return 0; | 485 | return 0; |
586 | } | 486 | } |
587 | 487 | ||
@@ -589,10 +489,10 @@ static void | |||
589 | wl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 489 | wl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
590 | enum sta_notify_cmd cmd, struct ieee80211_sta *sta) | 490 | enum sta_notify_cmd cmd, struct ieee80211_sta *sta) |
591 | { | 491 | { |
592 | WL_NONE(("%s: Enter\n", __func__)); | 492 | WL_NONE("%s: Enter\n", __func__); |
593 | switch (cmd) { | 493 | switch (cmd) { |
594 | default: | 494 | default: |
595 | WL_ERROR(("%s: Uknown cmd = %d\n", __func__, cmd)); | 495 | WL_ERROR("%s: Unknown cmd = %d\n", __func__, cmd); |
596 | break; | 496 | break; |
597 | } | 497 | } |
598 | return; | 498 | return; |
@@ -602,11 +502,11 @@ static int | |||
602 | wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, | 502 | wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, |
603 | const struct ieee80211_tx_queue_params *params) | 503 | const struct ieee80211_tx_queue_params *params) |
604 | { | 504 | { |
605 | wl_info_t *wl = hw->priv; | 505 | struct wl_info *wl = hw->priv; |
606 | 506 | ||
607 | WL_NONE(("%s: Enter (WME config)\n", __func__)); | 507 | WL_NONE("%s: Enter (WME config)\n", __func__); |
608 | WL_NONE(("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue, | 508 | WL_NONE("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue, |
609 | params->txop, params->cw_min, params->cw_max, params->aifs)); | 509 | params->txop, params->cw_min, params->cw_max, params->aifs); |
610 | 510 | ||
611 | WL_LOCK(wl); | 511 | WL_LOCK(wl); |
612 | wlc_wme_setparams(wl->wlc, queue, (void *)params, true); | 512 | wlc_wme_setparams(wl->wlc, queue, (void *)params, true); |
@@ -617,7 +517,7 @@ wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
617 | 517 | ||
618 | static u64 wl_ops_get_tsf(struct ieee80211_hw *hw) | 518 | static u64 wl_ops_get_tsf(struct ieee80211_hw *hw) |
619 | { | 519 | { |
620 | WL_ERROR(("%s: Enter\n", __func__)); | 520 | WL_ERROR("%s: Enter\n", __func__); |
621 | return 0; | 521 | return 0; |
622 | } | 522 | } |
623 | 523 | ||
@@ -628,11 +528,11 @@ wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
628 | struct scb *scb; | 528 | struct scb *scb; |
629 | 529 | ||
630 | int i; | 530 | int i; |
631 | wl_info_t *wl = hw->priv; | 531 | struct wl_info *wl = hw->priv; |
632 | 532 | ||
633 | /* Init the scb */ | 533 | /* Init the scb */ |
634 | scb = (struct scb *)sta->drv_priv; | 534 | scb = (struct scb *)sta->drv_priv; |
635 | bzero(scb, sizeof(struct scb)); | 535 | memset(scb, 0, sizeof(struct scb)); |
636 | for (i = 0; i < NUMPRIO; i++) | 536 | for (i = 0; i < NUMPRIO; i++) |
637 | scb->seqctl[i] = 0xFFFF; | 537 | scb->seqctl[i] = 0xFFFF; |
638 | scb->seqctl_nonqos = 0xFFFF; | 538 | scb->seqctl_nonqos = 0xFFFF; |
@@ -641,20 +541,12 @@ wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
641 | wl->pub->global_scb = scb; | 541 | wl->pub->global_scb = scb; |
642 | wl->pub->global_ampdu = &(scb->scb_ampdu); | 542 | wl->pub->global_ampdu = &(scb->scb_ampdu); |
643 | wl->pub->global_ampdu->scb = scb; | 543 | wl->pub->global_ampdu->scb = scb; |
644 | #ifdef WLC_HIGH_ONLY | ||
645 | wl->pub->global_ampdu->max_pdu = AMPDU_NUM_MPDU; | ||
646 | #else | ||
647 | wl->pub->global_ampdu->max_pdu = 16; | 544 | wl->pub->global_ampdu->max_pdu = 16; |
648 | #endif | ||
649 | pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID, | 545 | pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID, |
650 | AMPDU_MAX_SCB_TID * PKTQ_LEN_DEFAULT); | 546 | AMPDU_MAX_SCB_TID * PKTQ_LEN_DEFAULT); |
651 | 547 | ||
652 | sta->ht_cap.ht_supported = true; | 548 | sta->ht_cap.ht_supported = true; |
653 | #ifdef WLC_HIGH_ONLY | ||
654 | sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_16K; | ||
655 | #else | ||
656 | sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_64K; | 549 | sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_64K; |
657 | #endif | ||
658 | sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY; | 550 | sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY; |
659 | sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD | | 551 | sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD | |
660 | IEEE80211_HT_CAP_SGI_20 | | 552 | IEEE80211_HT_CAP_SGI_20 | |
@@ -668,7 +560,7 @@ static int | |||
668 | wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 560 | wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
669 | struct ieee80211_sta *sta) | 561 | struct ieee80211_sta *sta) |
670 | { | 562 | { |
671 | WL_NONE(("%s: Enter\n", __func__)); | 563 | WL_NONE("%s: Enter\n", __func__); |
672 | return 0; | 564 | return 0; |
673 | } | 565 | } |
674 | 566 | ||
@@ -681,19 +573,19 @@ wl_ampdu_action(struct ieee80211_hw *hw, | |||
681 | #if defined(BCMDBG) | 573 | #if defined(BCMDBG) |
682 | struct scb *scb = (struct scb *)sta->drv_priv; | 574 | struct scb *scb = (struct scb *)sta->drv_priv; |
683 | #endif | 575 | #endif |
684 | wl_info_t *wl = hw->priv; | 576 | struct wl_info *wl = hw->priv; |
685 | 577 | ||
686 | ASSERT(scb->magic == SCB_MAGIC); | 578 | ASSERT(scb->magic == SCB_MAGIC); |
687 | switch (action) { | 579 | switch (action) { |
688 | case IEEE80211_AMPDU_RX_START: | 580 | case IEEE80211_AMPDU_RX_START: |
689 | WL_NONE(("%s: action = IEEE80211_AMPDU_RX_START\n", __func__)); | 581 | WL_NONE("%s: action = IEEE80211_AMPDU_RX_START\n", __func__); |
690 | break; | 582 | break; |
691 | case IEEE80211_AMPDU_RX_STOP: | 583 | case IEEE80211_AMPDU_RX_STOP: |
692 | WL_NONE(("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__)); | 584 | WL_NONE("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__); |
693 | break; | 585 | break; |
694 | case IEEE80211_AMPDU_TX_START: | 586 | case IEEE80211_AMPDU_TX_START: |
695 | if (!wlc_aggregatable(wl->wlc, tid)) { | 587 | if (!wlc_aggregatable(wl->wlc, tid)) { |
696 | /* WL_ERROR(("START: tid %d is not agg' able, return FAILURE to stack\n", tid)); */ | 588 | /* WL_ERROR("START: tid %d is not agg' able, return FAILURE to stack\n", tid); */ |
697 | return -1; | 589 | return -1; |
698 | } | 590 | } |
699 | /* XXX: Use the starting sequence number provided ... */ | 591 | /* XXX: Use the starting sequence number provided ... */ |
@@ -707,22 +599,18 @@ wl_ampdu_action(struct ieee80211_hw *hw, | |||
707 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 599 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
708 | /* Not sure what to do here */ | 600 | /* Not sure what to do here */ |
709 | /* Power save wakeup */ | 601 | /* Power save wakeup */ |
710 | WL_NONE(("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n", | 602 | WL_NONE("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n", |
711 | __func__)); | 603 | __func__); |
712 | break; | 604 | break; |
713 | default: | 605 | default: |
714 | WL_ERROR(("%s: Invalid command, ignoring\n", __func__)); | 606 | WL_ERROR("%s: Invalid command, ignoring\n", __func__); |
715 | } | 607 | } |
716 | 608 | ||
717 | return 0; | 609 | return 0; |
718 | } | 610 | } |
719 | 611 | ||
720 | static const struct ieee80211_ops wl_ops = { | 612 | static const struct ieee80211_ops wl_ops = { |
721 | #ifdef WLC_HIGH_ONLY | ||
722 | .tx = wl_ops_tx_nl, | ||
723 | #else | ||
724 | .tx = wl_ops_tx, | 613 | .tx = wl_ops_tx, |
725 | #endif | ||
726 | .start = wl_ops_start, | 614 | .start = wl_ops_start, |
727 | .stop = wl_ops_stop, | 615 | .stop = wl_ops_stop, |
728 | .add_interface = wl_ops_add_interface, | 616 | .add_interface = wl_ops_add_interface, |
@@ -744,10 +632,10 @@ static const struct ieee80211_ops wl_ops = { | |||
744 | .ampdu_action = wl_ampdu_action, | 632 | .ampdu_action = wl_ampdu_action, |
745 | }; | 633 | }; |
746 | 634 | ||
747 | static int wl_set_hint(wl_info_t *wl, char *abbrev) | 635 | static int wl_set_hint(struct wl_info *wl, char *abbrev) |
748 | { | 636 | { |
749 | WL_ERROR(("%s: Sending country code %c%c to MAC80211\n", __func__, | 637 | WL_ERROR("%s: Sending country code %c%c to MAC80211\n", |
750 | abbrev[0], abbrev[1])); | 638 | __func__, abbrev[0], abbrev[1]); |
751 | return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); | 639 | return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); |
752 | } | 640 | } |
753 | 641 | ||
@@ -762,117 +650,61 @@ static int wl_set_hint(wl_info_t *wl, char *abbrev) | |||
762 | * a warning that this function is defined but not used if we declare | 650 | * a warning that this function is defined but not used if we declare |
763 | * it as static. | 651 | * it as static. |
764 | */ | 652 | */ |
765 | static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, | 653 | static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, |
766 | uint bustype, void *btparam, uint irq) | 654 | uint bustype, void *btparam, uint irq) |
767 | { | 655 | { |
768 | wl_info_t *wl; | 656 | struct wl_info *wl; |
769 | osl_t *osh; | 657 | struct osl_info *osh; |
770 | int unit, err; | 658 | int unit, err; |
771 | 659 | ||
772 | unsigned long base_addr; | 660 | unsigned long base_addr; |
773 | struct ieee80211_hw *hw; | 661 | struct ieee80211_hw *hw; |
774 | u8 perm[ETH_ALEN]; | 662 | u8 perm[ETH_ALEN]; |
775 | 663 | ||
776 | unit = wl_found + instance_base; | 664 | unit = wl_found; |
777 | err = 0; | 665 | err = 0; |
778 | 666 | ||
779 | if (unit < 0) { | 667 | if (unit < 0) { |
780 | WL_ERROR(("wl%d: unit number overflow, exiting\n", unit)); | 668 | WL_ERROR("wl%d: unit number overflow, exiting\n", unit); |
781 | return NULL; | 669 | return NULL; |
782 | } | 670 | } |
783 | 671 | ||
784 | if (oneonly && (unit != instance_base)) { | 672 | osh = osl_attach(btparam, bustype); |
785 | WL_ERROR(("wl%d: wl_attach: oneonly is set, exiting\n", unit)); | ||
786 | return NULL; | ||
787 | } | ||
788 | |||
789 | /* Requires pkttag feature */ | ||
790 | osh = osl_attach(btparam, bustype, true); | ||
791 | ASSERT(osh); | 673 | ASSERT(osh); |
792 | 674 | ||
793 | #ifdef WLC_HIGH_ONLY | ||
794 | hw = ieee80211_alloc_hw(sizeof(wl_info_t), &wl_ops); | ||
795 | if (!hw) { | ||
796 | WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__)); | ||
797 | ASSERT(0); | ||
798 | } | ||
799 | |||
800 | bzero(hw->priv, sizeof(*wl)); | ||
801 | wl = hw->priv; | ||
802 | #else | ||
803 | /* allocate private info */ | 675 | /* allocate private info */ |
804 | hw = pci_get_drvdata(btparam); /* btparam == pdev */ | 676 | hw = pci_get_drvdata(btparam); /* btparam == pdev */ |
805 | wl = hw->priv; | 677 | wl = hw->priv; |
806 | #endif | ||
807 | ASSERT(wl); | 678 | ASSERT(wl); |
808 | 679 | ||
809 | wl->magic = WL_MAGIC; | ||
810 | wl->osh = osh; | 680 | wl->osh = osh; |
811 | atomic_set(&wl->callbacks, 0); | 681 | atomic_set(&wl->callbacks, 0); |
812 | 682 | ||
813 | /* setup the bottom half handler */ | 683 | /* setup the bottom half handler */ |
814 | tasklet_init(&wl->tasklet, wl_dpc, (unsigned long) wl); | 684 | tasklet_init(&wl->tasklet, wl_dpc, (unsigned long) wl); |
815 | 685 | ||
816 | #ifdef WLC_HIGH_ONLY | ||
817 | wl->rpc_th = bcm_rpc_tp_attach(osh, NULL); | ||
818 | if (wl->rpc_th == NULL) { | ||
819 | WL_ERROR(("wl%d: %s: bcm_rpc_tp_attach failed!\n", unit, | ||
820 | __func__)); | ||
821 | goto fail; | ||
822 | } | ||
823 | |||
824 | wl->rpc = bcm_rpc_attach(NULL, osh, wl->rpc_th); | ||
825 | if (wl->rpc == NULL) { | ||
826 | WL_ERROR(("wl%d: %s: bcm_rpc_attach failed!\n", unit, | ||
827 | __func__)); | ||
828 | goto fail; | ||
829 | } | ||
830 | |||
831 | /* init tx work queue for wl_start/send pkt; no need to destroy workitem */ | ||
832 | INIT_WORK(&wl->txq_task.work, (work_func_t) wl_start_txqwork); | ||
833 | wl->txq_task.context = wl; | ||
834 | #endif /* WLC_HIGH_ONLY */ | ||
835 | 686 | ||
836 | #ifdef BCMSDIO | ||
837 | SET_IEEE80211_DEV(hw, sdiommc_dev); | ||
838 | #endif | ||
839 | 687 | ||
840 | base_addr = regs; | 688 | base_addr = regs; |
841 | 689 | ||
842 | if (bustype == PCI_BUS) { | 690 | if (bustype == PCI_BUS) { |
843 | /* piomode can be overwritten by command argument */ | 691 | wl->piomode = false; |
844 | wl->piomode = piomode; | ||
845 | WL_TRACE(("PCI/%s\n", wl->piomode ? "PIO" : "DMA")); | ||
846 | } else if (bustype == RPC_BUS) { | 692 | } else if (bustype == RPC_BUS) { |
847 | /* Do nothing */ | 693 | /* Do nothing */ |
848 | } else { | 694 | } else { |
849 | bustype = PCI_BUS; | 695 | bustype = PCI_BUS; |
850 | WL_TRACE(("force to PCI\n")); | 696 | WL_TRACE("force to PCI\n"); |
851 | } | 697 | } |
852 | wl->bcm_bustype = bustype; | 698 | wl->bcm_bustype = bustype; |
853 | 699 | ||
854 | #ifdef WLC_HIGH_ONLY | ||
855 | if (wl->bcm_bustype == RPC_BUS) { | ||
856 | wl->regsva = (void *)0; | ||
857 | btparam = wl->rpc; | ||
858 | } else | ||
859 | #endif | ||
860 | wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ); | 700 | wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ); |
861 | if (wl->regsva == NULL) { | 701 | if (wl->regsva == NULL) { |
862 | WL_ERROR(("wl%d: ioremap() failed\n", unit)); | 702 | WL_ERROR("wl%d: ioremap() failed\n", unit); |
863 | goto fail; | 703 | goto fail; |
864 | } | 704 | } |
865 | #ifdef WLC_HIGH_ONLY | ||
866 | spin_lock_init(&wl->rpcq_lock); | ||
867 | spin_lock_init(&wl->txq_lock); | ||
868 | |||
869 | sema_init(&wl->sem, 1); | ||
870 | #else | ||
871 | spin_lock_init(&wl->lock); | 705 | spin_lock_init(&wl->lock); |
872 | spin_lock_init(&wl->isr_lock); | 706 | spin_lock_init(&wl->isr_lock); |
873 | #endif | ||
874 | 707 | ||
875 | #ifndef WLC_HIGH_ONLY | ||
876 | /* prepare ucode */ | 708 | /* prepare ucode */ |
877 | if (wl_request_fw(wl, (struct pci_dev *)btparam)) { | 709 | if (wl_request_fw(wl, (struct pci_dev *)btparam)) { |
878 | printf("%s: Failed to find firmware usually in %s\n", | 710 | printf("%s: Failed to find firmware usually in %s\n", |
@@ -881,17 +713,14 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, | |||
881 | wl_remove((struct pci_dev *)btparam); | 713 | wl_remove((struct pci_dev *)btparam); |
882 | goto fail1; | 714 | goto fail1; |
883 | } | 715 | } |
884 | #endif | ||
885 | 716 | ||
886 | /* common load-time initialization */ | 717 | /* common load-time initialization */ |
887 | wl->wlc = wlc_attach((void *)wl, vendor, device, unit, wl->piomode, osh, | 718 | wl->wlc = wlc_attach((void *)wl, vendor, device, unit, wl->piomode, osh, |
888 | wl->regsva, wl->bcm_bustype, btparam, &err); | 719 | wl->regsva, wl->bcm_bustype, btparam, &err); |
889 | #ifndef WLC_HIGH_ONLY | ||
890 | wl_release_fw(wl); | 720 | wl_release_fw(wl); |
891 | #endif | ||
892 | if (!wl->wlc) { | 721 | if (!wl->wlc) { |
893 | printf("%s: %s wlc_attach() failed with code %d\n", | 722 | printf("%s: wlc_attach() failed with code %d\n", |
894 | KBUILD_MODNAME, EPI_VERSION_STR, err); | 723 | KBUILD_MODNAME, err); |
895 | goto fail; | 724 | goto fail; |
896 | } | 725 | } |
897 | wl->pub = wlc_pub(wl->wlc); | 726 | wl->pub = wlc_pub(wl->wlc); |
@@ -900,52 +729,35 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, | |||
900 | ASSERT(wl->pub->ieee_hw); | 729 | ASSERT(wl->pub->ieee_hw); |
901 | ASSERT(wl->pub->ieee_hw->priv == wl); | 730 | ASSERT(wl->pub->ieee_hw->priv == wl); |
902 | 731 | ||
903 | #ifdef WLC_HIGH_ONLY | 732 | |
904 | REGOPSSET(osh, (osl_rreg_fn_t) wlc_reg_read, | 733 | if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { |
905 | (osl_wreg_fn_t) wlc_reg_write, wl->wlc); | 734 | WL_ERROR("wl%d: Error setting MPC variable to 0\n", unit); |
906 | wl->rpc_dispatch_ctx.rpc = wl->rpc; | ||
907 | wl->rpc_dispatch_ctx.wlc = wl->wlc; | ||
908 | bcm_rpc_rxcb_init(wl->rpc, wl, wl_rpc_dispatch_schedule, wl, | ||
909 | wl_rpc_down, NULL, NULL); | ||
910 | #endif /* WLC_HIGH_ONLY */ | ||
911 | |||
912 | if (nompc) { | ||
913 | if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { | ||
914 | WL_ERROR(("wl%d: Error setting MPC variable to 0\n", | ||
915 | unit)); | ||
916 | } | ||
917 | } | 735 | } |
918 | #ifdef BCMSDIO | ||
919 | /* Set SDIO drive strength */ | ||
920 | wlc_iovar_setint(wl->wlc, "sd_drivestrength", sd_drivestrength); | ||
921 | #endif | ||
922 | 736 | ||
923 | #ifdef WLC_LOW | ||
924 | /* register our interrupt handler */ | 737 | /* register our interrupt handler */ |
925 | if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { | 738 | if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { |
926 | WL_ERROR(("wl%d: request_irq() failed\n", unit)); | 739 | WL_ERROR("wl%d: request_irq() failed\n", unit); |
927 | goto fail; | 740 | goto fail; |
928 | } | 741 | } |
929 | wl->irq = irq; | 742 | wl->irq = irq; |
930 | #endif /* WLC_LOW */ | ||
931 | 743 | ||
932 | /* register module */ | 744 | /* register module */ |
933 | wlc_module_register(wl->pub, NULL, "linux", wl, NULL, wl_linux_watchdog, | 745 | wlc_module_register(wl->pub, NULL, "linux", wl, NULL, wl_linux_watchdog, |
934 | NULL); | 746 | NULL); |
935 | 747 | ||
936 | if (ieee_hw_init(hw)) { | 748 | if (ieee_hw_init(hw)) { |
937 | WL_ERROR(("wl%d: %s: ieee_hw_init failed!\n", unit, __func__)); | 749 | WL_ERROR("wl%d: %s: ieee_hw_init failed!\n", unit, __func__); |
938 | goto fail; | 750 | goto fail; |
939 | } | 751 | } |
940 | 752 | ||
941 | bcopy(&wl->pub->cur_etheraddr, perm, ETHER_ADDR_LEN); | 753 | bcopy(&wl->pub->cur_etheraddr, perm, ETH_ALEN); |
942 | ASSERT(is_valid_ether_addr(perm)); | 754 | ASSERT(is_valid_ether_addr(perm)); |
943 | SET_IEEE80211_PERM_ADDR(hw, perm); | 755 | SET_IEEE80211_PERM_ADDR(hw, perm); |
944 | 756 | ||
945 | err = ieee80211_register_hw(hw); | 757 | err = ieee80211_register_hw(hw); |
946 | if (err) { | 758 | if (err) { |
947 | WL_ERROR(("%s: ieee80211_register_hw failed, status %d\n", | 759 | WL_ERROR("%s: ieee80211_register_hw failed, status %d\n", |
948 | __func__, err)); | 760 | __func__, err); |
949 | } | 761 | } |
950 | 762 | ||
951 | if (wl->pub->srom_ccode[0]) | 763 | if (wl->pub->srom_ccode[0]) |
@@ -953,19 +765,14 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, | |||
953 | else | 765 | else |
954 | err = wl_set_hint(wl, "US"); | 766 | err = wl_set_hint(wl, "US"); |
955 | if (err) { | 767 | if (err) { |
956 | WL_ERROR(("%s: regulatory_hint failed, status %d\n", __func__, | 768 | WL_ERROR("%s: regulatory_hint failed, status %d\n", |
957 | err)); | 769 | __func__, err); |
958 | } | 770 | } |
959 | #ifndef WLC_HIGH_ONLY | 771 | WL_ERROR("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver (" PHY_VERSION_STR ")", |
960 | WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver " | 772 | unit); |
961 | EPI_VERSION_STR " (" PHY_VERSION_STR ")", unit)); | ||
962 | #else | ||
963 | WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver " | ||
964 | EPI_VERSION_STR, unit)); | ||
965 | #endif | ||
966 | 773 | ||
967 | #ifdef BCMDBG | 774 | #ifdef BCMDBG |
968 | printf(" (Compiled in " SRCBASE " at " __TIME__ " on " __DATE__ ")"); | 775 | printf(" (Compiled at " __TIME__ " on " __DATE__ ")"); |
969 | #endif /* BCMDBG */ | 776 | #endif /* BCMDBG */ |
970 | printf("\n"); | 777 | printf("\n"); |
971 | 778 | ||
@@ -978,54 +785,6 @@ fail1: | |||
978 | return NULL; | 785 | return NULL; |
979 | } | 786 | } |
980 | 787 | ||
981 | #ifdef WLC_HIGH_ONLY | ||
982 | static void *wl_dbus_probe_cb(void *arg, const char *desc, u32 bustype, | ||
983 | u32 hdrlen) | ||
984 | { | ||
985 | wl_info_t *wl; | ||
986 | WL_ERROR(("%s:\n", __func__)); | ||
987 | |||
988 | wl = wl_attach(BCM_DNGL_VID, BCM_DNGL_BDC_PID, (unsigned long) NULL, RPC_BUS, | ||
989 | NULL, 0); | ||
990 | if (!wl) { | ||
991 | WL_ERROR(("%s: wl_attach failed\n", __func__)); | ||
992 | } | ||
993 | |||
994 | /* This is later passed to wl_dbus_disconnect_cb */ | ||
995 | return wl; | ||
996 | } | ||
997 | |||
998 | static void wl_dbus_disconnect_cb(void *arg) | ||
999 | { | ||
1000 | wl_info_t *wl = arg; | ||
1001 | |||
1002 | WL_ERROR(("%s:\n", __func__)); | ||
1003 | |||
1004 | if (wl) { | ||
1005 | #ifdef WLC_HIGH_ONLY | ||
1006 | if (wl->pub->ieee_hw) { | ||
1007 | ieee80211_unregister_hw(wl->pub->ieee_hw); | ||
1008 | WL_ERROR(("%s: Back from down\n", __func__)); | ||
1009 | } | ||
1010 | wlc_device_removed(wl->wlc); | ||
1011 | wlc_bmac_dngl_reboot(wl->rpc); | ||
1012 | bcm_rpc_down(wl->rpc); | ||
1013 | #endif | ||
1014 | WL_LOCK(wl); | ||
1015 | wl_down(wl); | ||
1016 | WL_UNLOCK(wl); | ||
1017 | #ifdef WLC_HIGH_ONLY | ||
1018 | if (wl->pub->ieee_hw) { | ||
1019 | ieee80211_free_hw(wl->pub->ieee_hw); | ||
1020 | WL_ERROR(("%s: Back from ieee80211_free_hw\n", | ||
1021 | __func__)); | ||
1022 | wl->pub->ieee_hw = NULL; | ||
1023 | } | ||
1024 | #endif | ||
1025 | wl_free(wl); | ||
1026 | } | ||
1027 | } | ||
1028 | #endif /* WLC_HIGH_ONLY */ | ||
1029 | 788 | ||
1030 | 789 | ||
1031 | #define CHAN2GHZ(channel, freqency, chflags) { \ | 790 | #define CHAN2GHZ(channel, freqency, chflags) { \ |
@@ -1163,29 +922,13 @@ static struct ieee80211_supported_band wl_band_2GHz_nphy = { | |||
1163 | .cap = IEEE80211_HT_CAP_GRN_FLD | | 922 | .cap = IEEE80211_HT_CAP_GRN_FLD | |
1164 | IEEE80211_HT_CAP_SGI_20 | | 923 | IEEE80211_HT_CAP_SGI_20 | |
1165 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT, | 924 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT, |
1166 | #ifdef WLC_HIGH_ONLY | ||
1167 | .ht_supported = true, | ||
1168 | .ampdu_factor = AMPDU_RX_FACTOR_16K, | ||
1169 | #else | ||
1170 | .ht_supported = true, | 925 | .ht_supported = true, |
1171 | .ampdu_factor = AMPDU_RX_FACTOR_64K, | 926 | .ampdu_factor = AMPDU_RX_FACTOR_64K, |
1172 | #endif | ||
1173 | .ampdu_density = AMPDU_DEF_MPDU_DENSITY, | 927 | .ampdu_density = AMPDU_DEF_MPDU_DENSITY, |
1174 | .mcs = { | 928 | .mcs = { |
1175 | /* placeholders for now */ | 929 | /* placeholders for now */ |
1176 | #ifdef WLC_HIGH_ONLY | ||
1177 | /* | ||
1178 | * rx_mask[0] = 0xff by default | ||
1179 | * rx_mask[1] = 0xff if number of rx chain >=2 | ||
1180 | * rx_mask[2] = 0xff if number of rx chain >=3 | ||
1181 | * rx_mask[4] = 1 if 40Mhz is supported | ||
1182 | */ | ||
1183 | .rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
1184 | .rx_highest = 72, /* max rate of single stream */ | ||
1185 | #else | ||
1186 | .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, | 930 | .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, |
1187 | .rx_highest = 500, | 931 | .rx_highest = 500, |
1188 | #endif | ||
1189 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED} | 932 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED} |
1190 | } | 933 | } |
1191 | }; | 934 | }; |
@@ -1212,7 +955,7 @@ static struct ieee80211_supported_band wl_band_5GHz_nphy = { | |||
1212 | 955 | ||
1213 | static int ieee_hw_rate_init(struct ieee80211_hw *hw) | 956 | static int ieee_hw_rate_init(struct ieee80211_hw *hw) |
1214 | { | 957 | { |
1215 | wl_info_t *wl = HW_TO_WL(hw); | 958 | struct wl_info *wl = HW_TO_WL(hw); |
1216 | int has_5g; | 959 | int has_5g; |
1217 | char phy_list[4]; | 960 | char phy_list[4]; |
1218 | 961 | ||
@@ -1222,20 +965,16 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) | |||
1222 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; | 965 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; |
1223 | 966 | ||
1224 | if (wlc_get(wl->wlc, WLC_GET_PHYLIST, (int *)&phy_list) < 0) { | 967 | if (wlc_get(wl->wlc, WLC_GET_PHYLIST, (int *)&phy_list) < 0) { |
1225 | WL_ERROR(("Phy list failed\n")); | 968 | WL_ERROR("Phy list failed\n"); |
1226 | } | 969 | } |
1227 | WL_NONE(("%s: phylist = %c\n", __func__, phy_list[0])); | 970 | WL_NONE("%s: phylist = %c\n", __func__, phy_list[0]); |
1228 | 971 | ||
1229 | #ifndef WLC_HIGH_ONLY | ||
1230 | if (phy_list[0] == 'n' || phy_list[0] == 'c') { | 972 | if (phy_list[0] == 'n' || phy_list[0] == 'c') { |
1231 | if (phy_list[0] == 'c') { | 973 | if (phy_list[0] == 'c') { |
1232 | /* Single stream */ | 974 | /* Single stream */ |
1233 | wl_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0; | 975 | wl_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0; |
1234 | wl_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72; | 976 | wl_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72; |
1235 | } | 977 | } |
1236 | #else | ||
1237 | if (phy_list[0] == 's') { | ||
1238 | #endif | ||
1239 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl_band_2GHz_nphy; | 978 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl_band_2GHz_nphy; |
1240 | } else { | 979 | } else { |
1241 | BUG(); | 980 | BUG(); |
@@ -1245,11 +984,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) | |||
1245 | /* Assume all bands use the same phy. True for 11n devices. */ | 984 | /* Assume all bands use the same phy. True for 11n devices. */ |
1246 | if (NBANDS_PUB(wl->pub) > 1) { | 985 | if (NBANDS_PUB(wl->pub) > 1) { |
1247 | has_5g++; | 986 | has_5g++; |
1248 | #ifndef WLC_HIGH_ONLY | ||
1249 | if (phy_list[0] == 'n' || phy_list[0] == 'c') { | 987 | if (phy_list[0] == 'n' || phy_list[0] == 'c') { |
1250 | #else | ||
1251 | if (phy_list[0] == 's') { | ||
1252 | #endif | ||
1253 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 988 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = |
1254 | &wl_band_5GHz_nphy; | 989 | &wl_band_5GHz_nphy; |
1255 | } else { | 990 | } else { |
@@ -1257,7 +992,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) | |||
1257 | } | 992 | } |
1258 | } | 993 | } |
1259 | 994 | ||
1260 | WL_NONE(("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g)); | 995 | WL_NONE("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g); |
1261 | 996 | ||
1262 | return 0; | 997 | return 0; |
1263 | } | 998 | } |
@@ -1288,7 +1023,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw) | |||
1288 | return ieee_hw_rate_init(hw); | 1023 | return ieee_hw_rate_init(hw); |
1289 | } | 1024 | } |
1290 | 1025 | ||
1291 | #ifndef BCMSDIO | ||
1292 | /** | 1026 | /** |
1293 | * determines if a device is a WL device, and if so, attaches it. | 1027 | * determines if a device is a WL device, and if so, attaches it. |
1294 | * | 1028 | * |
@@ -1300,15 +1034,15 @@ int __devinit | |||
1300 | wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 1034 | wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
1301 | { | 1035 | { |
1302 | int rc; | 1036 | int rc; |
1303 | wl_info_t *wl; | 1037 | struct wl_info *wl; |
1304 | struct ieee80211_hw *hw; | 1038 | struct ieee80211_hw *hw; |
1305 | u32 val; | 1039 | u32 val; |
1306 | 1040 | ||
1307 | ASSERT(pdev); | 1041 | ASSERT(pdev); |
1308 | 1042 | ||
1309 | WL_TRACE(("%s: bus %d slot %d func %d irq %d\n", __func__, | 1043 | WL_TRACE("%s: bus %d slot %d func %d irq %d\n", |
1310 | pdev->bus->number, PCI_SLOT(pdev->devfn), | 1044 | __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), |
1311 | PCI_FUNC(pdev->devfn), pdev->irq)); | 1045 | PCI_FUNC(pdev->devfn), pdev->irq); |
1312 | 1046 | ||
1313 | if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || | 1047 | if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || |
1314 | (((pdev->device & 0xff00) != 0x4300) && | 1048 | (((pdev->device & 0xff00) != 0x4300) && |
@@ -1318,9 +1052,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1318 | 1052 | ||
1319 | rc = pci_enable_device(pdev); | 1053 | rc = pci_enable_device(pdev); |
1320 | if (rc) { | 1054 | if (rc) { |
1321 | WL_ERROR(("%s: Cannot enable device %d-%d_%d\n", __func__, | 1055 | WL_ERROR("%s: Cannot enable device %d-%d_%d\n", |
1322 | pdev->bus->number, PCI_SLOT(pdev->devfn), | 1056 | __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), |
1323 | PCI_FUNC(pdev->devfn))); | 1057 | PCI_FUNC(pdev->devfn)); |
1324 | return -ENODEV; | 1058 | return -ENODEV; |
1325 | } | 1059 | } |
1326 | pci_set_master(pdev); | 1060 | pci_set_master(pdev); |
@@ -1329,9 +1063,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1329 | if ((val & 0x0000ff00) != 0) | 1063 | if ((val & 0x0000ff00) != 0) |
1330 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | 1064 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); |
1331 | 1065 | ||
1332 | hw = ieee80211_alloc_hw(sizeof(wl_info_t), &wl_ops); | 1066 | hw = ieee80211_alloc_hw(sizeof(struct wl_info), &wl_ops); |
1333 | if (!hw) { | 1067 | if (!hw) { |
1334 | WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__)); | 1068 | WL_ERROR("%s: ieee80211_alloc_hw failed\n", __func__); |
1335 | rc = -ENOMEM; | 1069 | rc = -ENOMEM; |
1336 | goto err_1; | 1070 | goto err_1; |
1337 | } | 1071 | } |
@@ -1340,34 +1074,34 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1340 | 1074 | ||
1341 | pci_set_drvdata(pdev, hw); | 1075 | pci_set_drvdata(pdev, hw); |
1342 | 1076 | ||
1343 | bzero(hw->priv, sizeof(*wl)); | 1077 | memset(hw->priv, 0, sizeof(*wl)); |
1344 | 1078 | ||
1345 | wl = wl_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0), | 1079 | wl = wl_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0), |
1346 | PCI_BUS, pdev, pdev->irq); | 1080 | PCI_BUS, pdev, pdev->irq); |
1347 | 1081 | ||
1348 | if (!wl) { | 1082 | if (!wl) { |
1349 | WL_ERROR(("%s: %s: wl_attach failed!\n", | 1083 | WL_ERROR("%s: %s: wl_attach failed!\n", |
1350 | KBUILD_MODNAME, __func__)); | 1084 | KBUILD_MODNAME, __func__); |
1351 | return -ENODEV; | 1085 | return -ENODEV; |
1352 | } | 1086 | } |
1353 | return 0; | 1087 | return 0; |
1354 | err_1: | 1088 | err_1: |
1355 | WL_ERROR(("%s: err_1: Major hoarkage\n", __func__)); | 1089 | WL_ERROR("%s: err_1: Major hoarkage\n", __func__); |
1356 | return 0; | 1090 | return 0; |
1357 | } | 1091 | } |
1358 | 1092 | ||
1359 | #ifdef LINUXSTA_PS | 1093 | #ifdef LINUXSTA_PS |
1360 | static int wl_suspend(struct pci_dev *pdev, pm_message_t state) | 1094 | static int wl_suspend(struct pci_dev *pdev, pm_message_t state) |
1361 | { | 1095 | { |
1362 | wl_info_t *wl; | 1096 | struct wl_info *wl; |
1363 | struct ieee80211_hw *hw; | 1097 | struct ieee80211_hw *hw; |
1364 | 1098 | ||
1365 | WL_TRACE(("wl: wl_suspend\n")); | 1099 | WL_TRACE("wl: wl_suspend\n"); |
1366 | 1100 | ||
1367 | hw = pci_get_drvdata(pdev); | 1101 | hw = pci_get_drvdata(pdev); |
1368 | wl = HW_TO_WL(hw); | 1102 | wl = HW_TO_WL(hw); |
1369 | if (!wl) { | 1103 | if (!wl) { |
1370 | WL_ERROR(("wl: wl_suspend: pci_get_drvdata failed\n")); | 1104 | WL_ERROR("wl: wl_suspend: pci_get_drvdata failed\n"); |
1371 | return -ENODEV; | 1105 | return -ENODEV; |
1372 | } | 1106 | } |
1373 | 1107 | ||
@@ -1382,16 +1116,16 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state) | |||
1382 | 1116 | ||
1383 | static int wl_resume(struct pci_dev *pdev) | 1117 | static int wl_resume(struct pci_dev *pdev) |
1384 | { | 1118 | { |
1385 | wl_info_t *wl; | 1119 | struct wl_info *wl; |
1386 | struct ieee80211_hw *hw; | 1120 | struct ieee80211_hw *hw; |
1387 | int err = 0; | 1121 | int err = 0; |
1388 | u32 val; | 1122 | u32 val; |
1389 | 1123 | ||
1390 | WL_TRACE(("wl: wl_resume\n")); | 1124 | WL_TRACE("wl: wl_resume\n"); |
1391 | hw = pci_get_drvdata(pdev); | 1125 | hw = pci_get_drvdata(pdev); |
1392 | wl = HW_TO_WL(hw); | 1126 | wl = HW_TO_WL(hw); |
1393 | if (!wl) { | 1127 | if (!wl) { |
1394 | WL_ERROR(("wl: wl_resume: pci_get_drvdata failed\n")); | 1128 | WL_ERROR("wl: wl_resume: pci_get_drvdata failed\n"); |
1395 | return -ENODEV; | 1129 | return -ENODEV; |
1396 | } | 1130 | } |
1397 | 1131 | ||
@@ -1421,17 +1155,17 @@ static int wl_resume(struct pci_dev *pdev) | |||
1421 | 1155 | ||
1422 | static void wl_remove(struct pci_dev *pdev) | 1156 | static void wl_remove(struct pci_dev *pdev) |
1423 | { | 1157 | { |
1424 | wl_info_t *wl; | 1158 | struct wl_info *wl; |
1425 | struct ieee80211_hw *hw; | 1159 | struct ieee80211_hw *hw; |
1426 | 1160 | ||
1427 | hw = pci_get_drvdata(pdev); | 1161 | hw = pci_get_drvdata(pdev); |
1428 | wl = HW_TO_WL(hw); | 1162 | wl = HW_TO_WL(hw); |
1429 | if (!wl) { | 1163 | if (!wl) { |
1430 | WL_ERROR(("wl: wl_remove: pci_get_drvdata failed\n")); | 1164 | WL_ERROR("wl: wl_remove: pci_get_drvdata failed\n"); |
1431 | return; | 1165 | return; |
1432 | } | 1166 | } |
1433 | if (!wlc_chipmatch(pdev->vendor, pdev->device)) { | 1167 | if (!wlc_chipmatch(pdev->vendor, pdev->device)) { |
1434 | WL_ERROR(("wl: wl_remove: wlc_chipmatch failed\n")); | 1168 | WL_ERROR("wl: wl_remove: wlc_chipmatch failed\n"); |
1435 | return; | 1169 | return; |
1436 | } | 1170 | } |
1437 | if (wl->wlc) { | 1171 | if (wl->wlc) { |
@@ -1439,7 +1173,7 @@ static void wl_remove(struct pci_dev *pdev) | |||
1439 | WL_LOCK(wl); | 1173 | WL_LOCK(wl); |
1440 | wl_down(wl); | 1174 | wl_down(wl); |
1441 | WL_UNLOCK(wl); | 1175 | WL_UNLOCK(wl); |
1442 | WL_NONE(("%s: Down\n", __func__)); | 1176 | WL_NONE("%s: Down\n", __func__); |
1443 | } | 1177 | } |
1444 | pci_disable_device(pdev); | 1178 | pci_disable_device(pdev); |
1445 | 1179 | ||
@@ -1459,7 +1193,6 @@ static struct pci_driver wl_pci_driver = { | |||
1459 | .remove = __devexit_p(wl_remove), | 1193 | .remove = __devexit_p(wl_remove), |
1460 | .id_table = wl_id_table, | 1194 | .id_table = wl_id_table, |
1461 | }; | 1195 | }; |
1462 | #endif /* !BCMSDIO */ | ||
1463 | 1196 | ||
1464 | /** | 1197 | /** |
1465 | * This is the main entry point for the WL driver. | 1198 | * This is the main entry point for the WL driver. |
@@ -1480,7 +1213,6 @@ static int __init wl_module_init(void) | |||
1480 | if (var) | 1213 | if (var) |
1481 | wl_msg_level = simple_strtoul(var, NULL, 0); | 1214 | wl_msg_level = simple_strtoul(var, NULL, 0); |
1482 | } | 1215 | } |
1483 | #ifndef WLC_HIGH_ONLY | ||
1484 | { | 1216 | { |
1485 | extern u32 phyhal_msg_level; | 1217 | extern u32 phyhal_msg_level; |
1486 | 1218 | ||
@@ -1492,25 +1224,13 @@ static int __init wl_module_init(void) | |||
1492 | phyhal_msg_level = simple_strtoul(var, NULL, 0); | 1224 | phyhal_msg_level = simple_strtoul(var, NULL, 0); |
1493 | } | 1225 | } |
1494 | } | 1226 | } |
1495 | #endif /* WLC_HIGH_ONLY */ | ||
1496 | #endif /* BCMDBG */ | 1227 | #endif /* BCMDBG */ |
1497 | 1228 | ||
1498 | #ifndef BCMSDIO | ||
1499 | error = pci_register_driver(&wl_pci_driver); | 1229 | error = pci_register_driver(&wl_pci_driver); |
1500 | if (!error) | 1230 | if (!error) |
1501 | return 0; | 1231 | return 0; |
1502 | 1232 | ||
1503 | #endif /* !BCMSDIO */ | ||
1504 | 1233 | ||
1505 | #ifdef WLC_HIGH_ONLY | ||
1506 | /* BMAC_NOTE: define hardcode number, why NODEVICE is ok ? */ | ||
1507 | error = | ||
1508 | dbus_register(BCM_DNGL_VID, 0, wl_dbus_probe_cb, | ||
1509 | wl_dbus_disconnect_cb, NULL, NULL, NULL); | ||
1510 | if (error == DBUS_ERR_NODEVICE) { | ||
1511 | error = DBUS_OK; | ||
1512 | } | ||
1513 | #endif /* WLC_HIGH_ONLY */ | ||
1514 | 1234 | ||
1515 | return error; | 1235 | return error; |
1516 | } | 1236 | } |
@@ -1524,13 +1244,8 @@ static int __init wl_module_init(void) | |||
1524 | */ | 1244 | */ |
1525 | static void __exit wl_module_exit(void) | 1245 | static void __exit wl_module_exit(void) |
1526 | { | 1246 | { |
1527 | #ifndef BCMSDIO | ||
1528 | pci_unregister_driver(&wl_pci_driver); | 1247 | pci_unregister_driver(&wl_pci_driver); |
1529 | #endif /* !BCMSDIO */ | ||
1530 | 1248 | ||
1531 | #ifdef WLC_HIGH_ONLY | ||
1532 | dbus_deregister(); | ||
1533 | #endif /* WLC_HIGH_ONLY */ | ||
1534 | } | 1249 | } |
1535 | 1250 | ||
1536 | module_init(wl_module_init); | 1251 | module_init(wl_module_init); |
@@ -1543,19 +1258,17 @@ module_exit(wl_module_exit); | |||
1543 | * by the wl parameter. | 1258 | * by the wl parameter. |
1544 | * | 1259 | * |
1545 | */ | 1260 | */ |
1546 | void wl_free(wl_info_t *wl) | 1261 | void wl_free(struct wl_info *wl) |
1547 | { | 1262 | { |
1548 | wl_timer_t *t, *next; | 1263 | wl_timer_t *t, *next; |
1549 | osl_t *osh; | 1264 | struct osl_info *osh; |
1550 | 1265 | ||
1551 | ASSERT(wl); | 1266 | ASSERT(wl); |
1552 | #ifndef WLC_HIGH_ONLY | ||
1553 | /* free ucode data */ | 1267 | /* free ucode data */ |
1554 | if (wl->fw.fw_cnt) | 1268 | if (wl->fw.fw_cnt) |
1555 | wl_ucode_data_free(); | 1269 | wl_ucode_data_free(); |
1556 | if (wl->irq) | 1270 | if (wl->irq) |
1557 | free_irq(wl->irq, wl); | 1271 | free_irq(wl->irq, wl); |
1558 | #endif | ||
1559 | 1272 | ||
1560 | /* kill dpc */ | 1273 | /* kill dpc */ |
1561 | tasklet_kill(&wl->tasklet); | 1274 | tasklet_kill(&wl->tasklet); |
@@ -1593,103 +1306,50 @@ void wl_free(wl_info_t *wl) | |||
1593 | * unregister_netdev() calls get_stats() which may read chip registers | 1306 | * unregister_netdev() calls get_stats() which may read chip registers |
1594 | * so we cannot unmap the chip registers until after calling unregister_netdev() . | 1307 | * so we cannot unmap the chip registers until after calling unregister_netdev() . |
1595 | */ | 1308 | */ |
1596 | if (wl->regsva && BUSTYPE(wl->bcm_bustype) != SDIO_BUS && | 1309 | if (wl->regsva && wl->bcm_bustype != SDIO_BUS && |
1597 | BUSTYPE(wl->bcm_bustype) != JTAG_BUS) { | 1310 | wl->bcm_bustype != JTAG_BUS) { |
1598 | iounmap((void *)wl->regsva); | 1311 | iounmap((void *)wl->regsva); |
1599 | } | 1312 | } |
1600 | wl->regsva = NULL; | 1313 | wl->regsva = NULL; |
1601 | 1314 | ||
1602 | #ifdef WLC_HIGH_ONLY | ||
1603 | wl_rpcq_free(wl); | ||
1604 | |||
1605 | wl_txq_free(wl); | ||
1606 | |||
1607 | if (wl->rpc) { | ||
1608 | bcm_rpc_detach(wl->rpc); | ||
1609 | wl->rpc = NULL; | ||
1610 | } | ||
1611 | |||
1612 | if (wl->rpc_th) { | ||
1613 | bcm_rpc_tp_detach(wl->rpc_th); | ||
1614 | wl->rpc_th = NULL; | ||
1615 | } | ||
1616 | #endif /* WLC_HIGH_ONLY */ | ||
1617 | 1315 | ||
1618 | osl_detach(osh); | 1316 | osl_detach(osh); |
1619 | } | 1317 | } |
1620 | 1318 | ||
1621 | #ifdef WLC_LOW | ||
1622 | /* transmit a packet */ | 1319 | /* transmit a packet */ |
1623 | static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) | 1320 | static int BCMFASTPATH wl_start(struct sk_buff *skb, struct wl_info *wl) |
1624 | { | 1321 | { |
1625 | if (!wl) | 1322 | if (!wl) |
1626 | return -ENETDOWN; | 1323 | return -ENETDOWN; |
1627 | 1324 | ||
1628 | return wl_start_int(wl, WL_TO_HW(wl), skb); | 1325 | return wl_start_int(wl, WL_TO_HW(wl), skb); |
1629 | } | 1326 | } |
1630 | #endif /* WLC_LOW */ | ||
1631 | 1327 | ||
1632 | static int BCMFASTPATH | 1328 | static int BCMFASTPATH |
1633 | wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw, struct sk_buff *skb) | 1329 | wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw, struct sk_buff *skb) |
1634 | { | 1330 | { |
1635 | #ifdef WLC_HIGH_ONLY | ||
1636 | WL_LOCK(wl); | ||
1637 | #endif | ||
1638 | wlc_sendpkt_mac80211(wl->wlc, skb, hw); | 1331 | wlc_sendpkt_mac80211(wl->wlc, skb, hw); |
1639 | #ifdef WLC_HIGH_ONLY | ||
1640 | WL_UNLOCK(wl); | ||
1641 | #endif | ||
1642 | return NETDEV_TX_OK; | 1332 | return NETDEV_TX_OK; |
1643 | } | 1333 | } |
1644 | 1334 | ||
1645 | void wl_txflowcontrol(wl_info_t *wl, struct wl_if *wlif, bool state, int prio) | 1335 | void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, |
1336 | int prio) | ||
1646 | { | 1337 | { |
1647 | WL_ERROR(("Shouldn't be here %s\n", __func__)); | 1338 | WL_ERROR("Shouldn't be here %s\n", __func__); |
1648 | } | 1339 | } |
1649 | 1340 | ||
1650 | #if defined(WLC_HIGH_ONLY) | 1341 | void wl_init(struct wl_info *wl) |
1651 | /* Schedule a completion handler to run at safe time */ | ||
1652 | static int | ||
1653 | wl_schedule_task(wl_info_t *wl, void (*fn) (struct wl_task *task), | ||
1654 | void *context) | ||
1655 | { | 1342 | { |
1656 | wl_task_t *task; | 1343 | WL_TRACE("wl%d: wl_init\n", wl->pub->unit); |
1657 | |||
1658 | WL_TRACE(("wl%d: wl_schedule_task\n", wl->pub->unit)); | ||
1659 | |||
1660 | task = kmalloc(sizeof(wl_task_t), GFP_ATOMIC); | ||
1661 | if (!task) { | ||
1662 | WL_ERROR(("wl%d: wl_schedule_task: out of memory\n", wl->pub->unit)); | ||
1663 | return -ENOMEM; | ||
1664 | } | ||
1665 | |||
1666 | INIT_WORK(&task->work, (work_func_t) fn); | ||
1667 | task->context = context; | ||
1668 | |||
1669 | if (!schedule_work(&task->work)) { | ||
1670 | WL_ERROR(("wl%d: schedule_work() failed\n", wl->pub->unit)); | ||
1671 | kfree(task); | ||
1672 | return -ENOMEM; | ||
1673 | } | ||
1674 | |||
1675 | atomic_inc(&wl->callbacks); | ||
1676 | |||
1677 | return 0; | ||
1678 | } | ||
1679 | #endif /* defined(WLC_HIGH_ONLY) */ | ||
1680 | |||
1681 | void wl_init(wl_info_t *wl) | ||
1682 | { | ||
1683 | WL_TRACE(("wl%d: wl_init\n", wl->pub->unit)); | ||
1684 | 1344 | ||
1685 | wl_reset(wl); | 1345 | wl_reset(wl); |
1686 | 1346 | ||
1687 | wlc_init(wl->wlc); | 1347 | wlc_init(wl->wlc); |
1688 | } | 1348 | } |
1689 | 1349 | ||
1690 | uint wl_reset(wl_info_t *wl) | 1350 | uint wl_reset(struct wl_info *wl) |
1691 | { | 1351 | { |
1692 | WL_TRACE(("wl%d: wl_reset\n", wl->pub->unit)); | 1352 | WL_TRACE("wl%d: wl_reset\n", wl->pub->unit); |
1693 | 1353 | ||
1694 | wlc_reset(wl->wlc); | 1354 | wlc_reset(wl->wlc); |
1695 | 1355 | ||
@@ -1703,25 +1363,22 @@ uint wl_reset(wl_info_t *wl) | |||
1703 | * These are interrupt on/off entry points. Disable interrupts | 1363 | * These are interrupt on/off entry points. Disable interrupts |
1704 | * during interrupt state transition. | 1364 | * during interrupt state transition. |
1705 | */ | 1365 | */ |
1706 | void BCMFASTPATH wl_intrson(wl_info_t *wl) | 1366 | void BCMFASTPATH wl_intrson(struct wl_info *wl) |
1707 | { | 1367 | { |
1708 | #if defined(WLC_LOW) | ||
1709 | unsigned long flags; | 1368 | unsigned long flags; |
1710 | 1369 | ||
1711 | INT_LOCK(wl, flags); | 1370 | INT_LOCK(wl, flags); |
1712 | wlc_intrson(wl->wlc); | 1371 | wlc_intrson(wl->wlc); |
1713 | INT_UNLOCK(wl, flags); | 1372 | INT_UNLOCK(wl, flags); |
1714 | #endif /* WLC_LOW */ | ||
1715 | } | 1373 | } |
1716 | 1374 | ||
1717 | bool wl_alloc_dma_resources(wl_info_t *wl, uint addrwidth) | 1375 | bool wl_alloc_dma_resources(struct wl_info *wl, uint addrwidth) |
1718 | { | 1376 | { |
1719 | return true; | 1377 | return true; |
1720 | } | 1378 | } |
1721 | 1379 | ||
1722 | u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl) | 1380 | u32 BCMFASTPATH wl_intrsoff(struct wl_info *wl) |
1723 | { | 1381 | { |
1724 | #if defined(WLC_LOW) | ||
1725 | unsigned long flags; | 1382 | unsigned long flags; |
1726 | u32 status; | 1383 | u32 status; |
1727 | 1384 | ||
@@ -1729,23 +1386,18 @@ u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl) | |||
1729 | status = wlc_intrsoff(wl->wlc); | 1386 | status = wlc_intrsoff(wl->wlc); |
1730 | INT_UNLOCK(wl, flags); | 1387 | INT_UNLOCK(wl, flags); |
1731 | return status; | 1388 | return status; |
1732 | #else | ||
1733 | return 0; | ||
1734 | #endif /* WLC_LOW */ | ||
1735 | } | 1389 | } |
1736 | 1390 | ||
1737 | void wl_intrsrestore(wl_info_t *wl, u32 macintmask) | 1391 | void wl_intrsrestore(struct wl_info *wl, u32 macintmask) |
1738 | { | 1392 | { |
1739 | #if defined(WLC_LOW) | ||
1740 | unsigned long flags; | 1393 | unsigned long flags; |
1741 | 1394 | ||
1742 | INT_LOCK(wl, flags); | 1395 | INT_LOCK(wl, flags); |
1743 | wlc_intrsrestore(wl->wlc, macintmask); | 1396 | wlc_intrsrestore(wl->wlc, macintmask); |
1744 | INT_UNLOCK(wl, flags); | 1397 | INT_UNLOCK(wl, flags); |
1745 | #endif /* WLC_LOW */ | ||
1746 | } | 1398 | } |
1747 | 1399 | ||
1748 | int wl_up(wl_info_t *wl) | 1400 | int wl_up(struct wl_info *wl) |
1749 | { | 1401 | { |
1750 | int error = 0; | 1402 | int error = 0; |
1751 | 1403 | ||
@@ -1757,7 +1409,7 @@ int wl_up(wl_info_t *wl) | |||
1757 | return error; | 1409 | return error; |
1758 | } | 1410 | } |
1759 | 1411 | ||
1760 | void wl_down(wl_info_t *wl) | 1412 | void wl_down(struct wl_info *wl) |
1761 | { | 1413 | { |
1762 | uint callbacks, ret_val = 0; | 1414 | uint callbacks, ret_val = 0; |
1763 | 1415 | ||
@@ -1768,24 +1420,21 @@ void wl_down(wl_info_t *wl) | |||
1768 | /* wait for down callbacks to complete */ | 1420 | /* wait for down callbacks to complete */ |
1769 | WL_UNLOCK(wl); | 1421 | WL_UNLOCK(wl); |
1770 | 1422 | ||
1771 | #ifndef WLC_HIGH_ONLY | ||
1772 | /* For HIGH_only driver, it's important to actually schedule other work, | 1423 | /* For HIGH_only driver, it's important to actually schedule other work, |
1773 | * not just spin wait since everything runs at schedule level | 1424 | * not just spin wait since everything runs at schedule level |
1774 | */ | 1425 | */ |
1775 | SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); | 1426 | SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); |
1776 | #endif /* WLC_HIGH_ONLY */ | ||
1777 | 1427 | ||
1778 | WL_LOCK(wl); | 1428 | WL_LOCK(wl); |
1779 | } | 1429 | } |
1780 | 1430 | ||
1781 | irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) | 1431 | irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) |
1782 | { | 1432 | { |
1783 | #if defined(WLC_LOW) | 1433 | struct wl_info *wl; |
1784 | wl_info_t *wl; | ||
1785 | bool ours, wantdpc; | 1434 | bool ours, wantdpc; |
1786 | unsigned long flags; | 1435 | unsigned long flags; |
1787 | 1436 | ||
1788 | wl = (wl_info_t *) dev_id; | 1437 | wl = (struct wl_info *) dev_id; |
1789 | 1438 | ||
1790 | WL_ISRLOCK(wl, flags); | 1439 | WL_ISRLOCK(wl, flags); |
1791 | 1440 | ||
@@ -1805,17 +1454,13 @@ irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) | |||
1805 | WL_ISRUNLOCK(wl, flags); | 1454 | WL_ISRUNLOCK(wl, flags); |
1806 | 1455 | ||
1807 | return IRQ_RETVAL(ours); | 1456 | return IRQ_RETVAL(ours); |
1808 | #else | ||
1809 | return IRQ_RETVAL(0); | ||
1810 | #endif /* WLC_LOW */ | ||
1811 | } | 1457 | } |
1812 | 1458 | ||
1813 | static void BCMFASTPATH wl_dpc(unsigned long data) | 1459 | static void BCMFASTPATH wl_dpc(unsigned long data) |
1814 | { | 1460 | { |
1815 | #ifdef WLC_LOW | 1461 | struct wl_info *wl; |
1816 | wl_info_t *wl; | ||
1817 | 1462 | ||
1818 | wl = (wl_info_t *) data; | 1463 | wl = (struct wl_info *) data; |
1819 | 1464 | ||
1820 | WL_LOCK(wl); | 1465 | WL_LOCK(wl); |
1821 | 1466 | ||
@@ -1846,20 +1491,19 @@ static void BCMFASTPATH wl_dpc(unsigned long data) | |||
1846 | 1491 | ||
1847 | done: | 1492 | done: |
1848 | WL_UNLOCK(wl); | 1493 | WL_UNLOCK(wl); |
1849 | #endif /* WLC_LOW */ | ||
1850 | } | 1494 | } |
1851 | 1495 | ||
1852 | static void wl_link_up(wl_info_t *wl, char *ifname) | 1496 | static void wl_link_up(struct wl_info *wl, char *ifname) |
1853 | { | 1497 | { |
1854 | WL_ERROR(("wl%d: link up (%s)\n", wl->pub->unit, ifname)); | 1498 | WL_ERROR("wl%d: link up (%s)\n", wl->pub->unit, ifname); |
1855 | } | 1499 | } |
1856 | 1500 | ||
1857 | static void wl_link_down(wl_info_t *wl, char *ifname) | 1501 | static void wl_link_down(struct wl_info *wl, char *ifname) |
1858 | { | 1502 | { |
1859 | WL_ERROR(("wl%d: link down (%s)\n", wl->pub->unit, ifname)); | 1503 | WL_ERROR("wl%d: link down (%s)\n", wl->pub->unit, ifname); |
1860 | } | 1504 | } |
1861 | 1505 | ||
1862 | void wl_event(wl_info_t *wl, char *ifname, wlc_event_t *e) | 1506 | void wl_event(struct wl_info *wl, char *ifname, wlc_event_t *e) |
1863 | { | 1507 | { |
1864 | 1508 | ||
1865 | switch (e->event.event_type) { | 1509 | switch (e->event.event_type) { |
@@ -1877,12 +1521,7 @@ void wl_event(wl_info_t *wl, char *ifname, wlc_event_t *e) | |||
1877 | 1521 | ||
1878 | static void wl_timer(unsigned long data) | 1522 | static void wl_timer(unsigned long data) |
1879 | { | 1523 | { |
1880 | #ifndef WLC_HIGH_ONLY | ||
1881 | _wl_timer((wl_timer_t *) data); | 1524 | _wl_timer((wl_timer_t *) data); |
1882 | #else | ||
1883 | wl_timer_t *t = (wl_timer_t *) data; | ||
1884 | wl_schedule_task(t->wl, wl_timer_task, t); | ||
1885 | #endif /* WLC_HIGH_ONLY */ | ||
1886 | } | 1525 | } |
1887 | 1526 | ||
1888 | static void _wl_timer(wl_timer_t *t) | 1527 | static void _wl_timer(wl_timer_t *t) |
@@ -1906,18 +1545,18 @@ static void _wl_timer(wl_timer_t *t) | |||
1906 | WL_UNLOCK(t->wl); | 1545 | WL_UNLOCK(t->wl); |
1907 | } | 1546 | } |
1908 | 1547 | ||
1909 | wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn) (void *arg), void *arg, | 1548 | wl_timer_t *wl_init_timer(struct wl_info *wl, void (*fn) (void *arg), void *arg, |
1910 | const char *name) | 1549 | const char *name) |
1911 | { | 1550 | { |
1912 | wl_timer_t *t; | 1551 | wl_timer_t *t; |
1913 | 1552 | ||
1914 | t = kmalloc(sizeof(wl_timer_t), GFP_ATOMIC); | 1553 | t = kmalloc(sizeof(wl_timer_t), GFP_ATOMIC); |
1915 | if (!t) { | 1554 | if (!t) { |
1916 | WL_ERROR(("wl%d: wl_init_timer: out of memory\n", wl->pub->unit)); | 1555 | WL_ERROR("wl%d: wl_init_timer: out of memory\n", wl->pub->unit); |
1917 | return 0; | 1556 | return 0; |
1918 | } | 1557 | } |
1919 | 1558 | ||
1920 | bzero(t, sizeof(wl_timer_t)); | 1559 | memset(t, 0, sizeof(wl_timer_t)); |
1921 | 1560 | ||
1922 | init_timer(&t->timer); | 1561 | init_timer(&t->timer); |
1923 | t->timer.data = (unsigned long) t; | 1562 | t->timer.data = (unsigned long) t; |
@@ -1940,12 +1579,12 @@ wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn) (void *arg), void *arg, | |||
1940 | /* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate | 1579 | /* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate |
1941 | * as well as it's easier to make it periodic | 1580 | * as well as it's easier to make it periodic |
1942 | */ | 1581 | */ |
1943 | void wl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic) | 1582 | void wl_add_timer(struct wl_info *wl, wl_timer_t *t, uint ms, int periodic) |
1944 | { | 1583 | { |
1945 | #ifdef BCMDBG | 1584 | #ifdef BCMDBG |
1946 | if (t->set) { | 1585 | if (t->set) { |
1947 | WL_ERROR(("%s: Already set. Name: %s, per %d\n", | 1586 | WL_ERROR("%s: Already set. Name: %s, per %d\n", |
1948 | __func__, t->name, periodic)); | 1587 | __func__, t->name, periodic); |
1949 | } | 1588 | } |
1950 | #endif | 1589 | #endif |
1951 | ASSERT(!t->set); | 1590 | ASSERT(!t->set); |
@@ -1960,7 +1599,7 @@ void wl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic) | |||
1960 | } | 1599 | } |
1961 | 1600 | ||
1962 | /* return true if timer successfully deleted, false if still pending */ | 1601 | /* return true if timer successfully deleted, false if still pending */ |
1963 | bool wl_del_timer(wl_info_t *wl, wl_timer_t *t) | 1602 | bool wl_del_timer(struct wl_info *wl, wl_timer_t *t) |
1964 | { | 1603 | { |
1965 | if (t->set) { | 1604 | if (t->set) { |
1966 | t->set = false; | 1605 | t->set = false; |
@@ -1973,7 +1612,7 @@ bool wl_del_timer(wl_info_t *wl, wl_timer_t *t) | |||
1973 | return true; | 1612 | return true; |
1974 | } | 1613 | } |
1975 | 1614 | ||
1976 | void wl_free_timer(wl_info_t *wl, wl_timer_t *t) | 1615 | void wl_free_timer(struct wl_info *wl, wl_timer_t *t) |
1977 | { | 1616 | { |
1978 | wl_timer_t *tmp; | 1617 | wl_timer_t *tmp; |
1979 | 1618 | ||
@@ -2009,7 +1648,7 @@ void wl_free_timer(wl_info_t *wl, wl_timer_t *t) | |||
2009 | 1648 | ||
2010 | static int wl_linux_watchdog(void *ctx) | 1649 | static int wl_linux_watchdog(void *ctx) |
2011 | { | 1650 | { |
2012 | wl_info_t *wl = (wl_info_t *) ctx; | 1651 | struct wl_info *wl = (struct wl_info *) ctx; |
2013 | struct net_device_stats *stats = NULL; | 1652 | struct net_device_stats *stats = NULL; |
2014 | uint id; | 1653 | uint id; |
2015 | /* refresh stats */ | 1654 | /* refresh stats */ |
@@ -2049,233 +1688,12 @@ struct wl_fw_hdr { | |||
2049 | u32 idx; | 1688 | u32 idx; |
2050 | }; | 1689 | }; |
2051 | 1690 | ||
2052 | #ifdef WLC_HIGH_ONLY | ||
2053 | static void wl_rpc_down(void *wlh) | ||
2054 | { | ||
2055 | wl_info_t *wl = (wl_info_t *) (wlh); | ||
2056 | |||
2057 | wlc_device_removed(wl->wlc); | ||
2058 | |||
2059 | wl_rpcq_free(wl); | ||
2060 | } | ||
2061 | |||
2062 | static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) | ||
2063 | { | ||
2064 | |||
2065 | unsigned long flags; | ||
2066 | |||
2067 | skb->prev = NULL; | ||
2068 | |||
2069 | /* Lock the queue as tasklet could be running at this time */ | ||
2070 | TXQ_LOCK(wl, flags); | ||
2071 | if (wl->txq_head == NULL) | ||
2072 | wl->txq_head = skb; | ||
2073 | else { | ||
2074 | wl->txq_tail->prev = skb; | ||
2075 | } | ||
2076 | wl->txq_tail = skb; | ||
2077 | |||
2078 | if (wl->txq_dispatched == false) { | ||
2079 | wl->txq_dispatched = true; | ||
2080 | |||
2081 | if (schedule_work(&wl->txq_task.work)) { | ||
2082 | atomic_inc(&wl->callbacks); | ||
2083 | } else { | ||
2084 | WL_ERROR(("wl%d: wl_start/schedule_work failed\n", | ||
2085 | wl->pub->unit)); | ||
2086 | } | ||
2087 | } | ||
2088 | |||
2089 | TXQ_UNLOCK(wl, flags); | ||
2090 | |||
2091 | return 0; | ||
2092 | |||
2093 | } | ||
2094 | |||
2095 | static void wl_start_txqwork(struct wl_task *task) | ||
2096 | { | ||
2097 | wl_info_t *wl = (wl_info_t *) task->context; | ||
2098 | struct sk_buff *skb; | ||
2099 | unsigned long flags; | ||
2100 | uint count = 0; | ||
2101 | |||
2102 | WL_TRACE(("wl%d: wl_start_txqwork\n", wl->pub->unit)); | ||
2103 | |||
2104 | /* First remove an entry then go for execution */ | ||
2105 | TXQ_LOCK(wl, flags); | ||
2106 | while (wl->txq_head) { | ||
2107 | skb = wl->txq_head; | ||
2108 | wl->txq_head = skb->prev; | ||
2109 | skb->prev = NULL; | ||
2110 | if (wl->txq_head == NULL) | ||
2111 | wl->txq_tail = NULL; | ||
2112 | TXQ_UNLOCK(wl, flags); | ||
2113 | |||
2114 | /* it has WL_LOCK/WL_UNLOCK inside */ | ||
2115 | wl_start_int(wl, WL_TO_HW(wl), skb); | ||
2116 | |||
2117 | /* bounded our execution, reshedule ourself next */ | ||
2118 | if (++count >= 10) | ||
2119 | break; | ||
2120 | |||
2121 | TXQ_LOCK(wl, flags); | ||
2122 | } | ||
2123 | |||
2124 | if (count >= 10) { | ||
2125 | if (!schedule_work(&wl->txq_task.work)) { | ||
2126 | WL_ERROR(("wl%d: wl_start/schedule_work failed\n", | ||
2127 | wl->pub->unit)); | ||
2128 | atomic_dec(&wl->callbacks); | ||
2129 | } | ||
2130 | } else { | ||
2131 | wl->txq_dispatched = false; | ||
2132 | TXQ_UNLOCK(wl, flags); | ||
2133 | atomic_dec(&wl->callbacks); | ||
2134 | } | ||
2135 | |||
2136 | return; | ||
2137 | } | ||
2138 | |||
2139 | static void wl_txq_free(wl_info_t *wl) | ||
2140 | { | ||
2141 | struct sk_buff *skb; | ||
2142 | |||
2143 | if (wl->txq_head == NULL) { | ||
2144 | ASSERT(wl->txq_tail == NULL); | ||
2145 | return; | ||
2146 | } | ||
2147 | |||
2148 | while (wl->txq_head) { | ||
2149 | skb = wl->txq_head; | ||
2150 | wl->txq_head = skb->prev; | ||
2151 | PKTFREE(wl->osh, skb, true); | ||
2152 | } | ||
2153 | |||
2154 | wl->txq_tail = NULL; | ||
2155 | } | ||
2156 | |||
2157 | static void wl_rpcq_free(wl_info_t *wl) | ||
2158 | { | ||
2159 | rpc_buf_t *buf; | ||
2160 | |||
2161 | if (wl->rpcq_head == NULL) { | ||
2162 | ASSERT(wl->rpcq_tail == NULL); | ||
2163 | return; | ||
2164 | } | ||
2165 | |||
2166 | while (wl->rpcq_head) { | ||
2167 | buf = wl->rpcq_head; | ||
2168 | wl->rpcq_head = bcm_rpc_buf_next_get(wl->rpc_th, buf); | ||
2169 | bcm_rpc_buf_free(wl->rpc_dispatch_ctx.rpc, buf); | ||
2170 | } | ||
2171 | |||
2172 | wl->rpcq_tail = NULL; | ||
2173 | } | ||
2174 | |||
2175 | static void wl_rpcq_dispatch(struct wl_task *task) | ||
2176 | { | ||
2177 | wl_info_t *wl = (wl_info_t *) task->context; | ||
2178 | rpc_buf_t *buf; | ||
2179 | unsigned long flags; | ||
2180 | |||
2181 | /* First remove an entry then go for execution */ | ||
2182 | RPCQ_LOCK(wl, flags); | ||
2183 | while (wl->rpcq_head) { | ||
2184 | buf = wl->rpcq_head; | ||
2185 | wl->rpcq_head = bcm_rpc_buf_next_get(wl->rpc_th, buf); | ||
2186 | |||
2187 | if (wl->rpcq_head == NULL) | ||
2188 | wl->rpcq_tail = NULL; | ||
2189 | RPCQ_UNLOCK(wl, flags); | ||
2190 | |||
2191 | WL_LOCK(wl); | ||
2192 | wlc_rpc_high_dispatch(&wl->rpc_dispatch_ctx, buf); | ||
2193 | WL_UNLOCK(wl); | ||
2194 | |||
2195 | RPCQ_LOCK(wl, flags); | ||
2196 | } | ||
2197 | |||
2198 | wl->rpcq_dispatched = false; | ||
2199 | |||
2200 | RPCQ_UNLOCK(wl, flags); | ||
2201 | |||
2202 | kfree(task); | ||
2203 | atomic_dec(&wl->callbacks); | ||
2204 | } | ||
2205 | |||
2206 | static void wl_rpcq_add(wl_info_t *wl, rpc_buf_t *buf) | ||
2207 | { | ||
2208 | unsigned long flags; | ||
2209 | |||
2210 | bcm_rpc_buf_next_set(wl->rpc_th, buf, NULL); | ||
2211 | |||
2212 | /* Lock the queue as tasklet could be running at this time */ | ||
2213 | RPCQ_LOCK(wl, flags); | ||
2214 | if (wl->rpcq_head == NULL) | ||
2215 | wl->rpcq_head = buf; | ||
2216 | else | ||
2217 | bcm_rpc_buf_next_set(wl->rpc_th, wl->rpcq_tail, buf); | ||
2218 | |||
2219 | wl->rpcq_tail = buf; | ||
2220 | |||
2221 | if (wl->rpcq_dispatched == false) { | ||
2222 | wl->rpcq_dispatched = true; | ||
2223 | wl_schedule_task(wl, wl_rpcq_dispatch, wl); | ||
2224 | } | ||
2225 | |||
2226 | RPCQ_UNLOCK(wl, flags); | ||
2227 | } | ||
2228 | |||
2229 | #if defined(BCMDBG) | ||
2230 | static const struct name_entry rpc_name_tbl[] = RPC_ID_TABLE; | ||
2231 | #endif /* BCMDBG */ | ||
2232 | |||
2233 | /* dongle-side rpc dispatch routine */ | ||
2234 | static void wl_rpc_dispatch_schedule(void *ctx, struct rpc_buf *buf) | ||
2235 | { | ||
2236 | bcm_xdr_buf_t b; | ||
2237 | wl_info_t *wl = (wl_info_t *) ctx; | ||
2238 | wlc_rpc_id_t rpc_id; | ||
2239 | int err; | ||
2240 | |||
2241 | bcm_xdr_buf_init(&b, bcm_rpc_buf_data(wl->rpc_th, buf), | ||
2242 | bcm_rpc_buf_len_get(wl->rpc_th, buf)); | ||
2243 | |||
2244 | err = bcm_xdr_unpack_u32(&b, &rpc_id); | ||
2245 | ASSERT(!err); | ||
2246 | WL_TRACE(("%s: Dispatch id %s\n", __func__, | ||
2247 | WLC_RPC_ID_LOOKUP(rpc_name_tbl, rpc_id))); | ||
2248 | |||
2249 | /* Handle few emergency ones */ | ||
2250 | switch (rpc_id) { | ||
2251 | default: | ||
2252 | wl_rpcq_add(wl, buf); | ||
2253 | break; | ||
2254 | } | ||
2255 | } | ||
2256 | |||
2257 | static void wl_timer_task(wl_task_t *task) | ||
2258 | { | ||
2259 | wl_timer_t *t = (wl_timer_t *) task->context; | ||
2260 | |||
2261 | _wl_timer(t); | ||
2262 | kfree(task); | ||
2263 | |||
2264 | /* This dec is for the task_schedule. The timer related | ||
2265 | * callback is decremented in _wl_timer | ||
2266 | */ | ||
2267 | atomic_dec(&t->wl->callbacks); | ||
2268 | } | ||
2269 | #endif /* WLC_HIGH_ONLY */ | ||
2270 | |||
2271 | #ifndef WLC_HIGH_ONLY | ||
2272 | char *wl_firmwares[WL_MAX_FW] = { | 1691 | char *wl_firmwares[WL_MAX_FW] = { |
2273 | "brcm/bcm43xx", | 1692 | "brcm/bcm43xx", |
2274 | NULL | 1693 | NULL |
2275 | }; | 1694 | }; |
2276 | 1695 | ||
2277 | #ifdef WLC_LOW | 1696 | int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, u32 idx) |
2278 | int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx) | ||
2279 | { | 1697 | { |
2280 | int i, entry; | 1698 | int i, entry; |
2281 | const u8 *pdata; | 1699 | const u8 *pdata; |
@@ -2301,7 +1719,7 @@ int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx) | |||
2301 | return -1; | 1719 | return -1; |
2302 | } | 1720 | } |
2303 | 1721 | ||
2304 | int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx) | 1722 | int wl_ucode_init_uint(struct wl_info *wl, u32 *data, u32 idx) |
2305 | { | 1723 | { |
2306 | int i, entry; | 1724 | int i, entry; |
2307 | const u8 *pdata; | 1725 | const u8 *pdata; |
@@ -2321,22 +1739,21 @@ int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx) | |||
2321 | printf("ERROR: ucode tag:%d can not be found!\n", idx); | 1739 | printf("ERROR: ucode tag:%d can not be found!\n", idx); |
2322 | return -1; | 1740 | return -1; |
2323 | } | 1741 | } |
2324 | #endif /* WLC_LOW */ | ||
2325 | 1742 | ||
2326 | static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev) | 1743 | static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev) |
2327 | { | 1744 | { |
2328 | int status; | 1745 | int status; |
2329 | struct device *device = &pdev->dev; | 1746 | struct device *device = &pdev->dev; |
2330 | char fw_name[100]; | 1747 | char fw_name[100]; |
2331 | int i; | 1748 | int i; |
2332 | 1749 | ||
2333 | bzero((void *)&wl->fw, sizeof(struct wl_firmware)); | 1750 | memset((void *)&wl->fw, 0, sizeof(struct wl_firmware)); |
2334 | for (i = 0; i < WL_MAX_FW; i++) { | 1751 | for (i = 0; i < WL_MAX_FW; i++) { |
2335 | if (wl_firmwares[i] == NULL) | 1752 | if (wl_firmwares[i] == NULL) |
2336 | break; | 1753 | break; |
2337 | sprintf(fw_name, "%s-%d.fw", wl_firmwares[i], | 1754 | sprintf(fw_name, "%s-%d.fw", wl_firmwares[i], |
2338 | UCODE_LOADER_API_VER); | 1755 | UCODE_LOADER_API_VER); |
2339 | WL_NONE(("request fw %s\n", fw_name)); | 1756 | WL_NONE("request fw %s\n", fw_name); |
2340 | status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); | 1757 | status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); |
2341 | if (status) { | 1758 | if (status) { |
2342 | printf("%s: fail to load firmware %s\n", | 1759 | printf("%s: fail to load firmware %s\n", |
@@ -2344,7 +1761,7 @@ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev) | |||
2344 | wl_release_fw(wl); | 1761 | wl_release_fw(wl); |
2345 | return status; | 1762 | return status; |
2346 | } | 1763 | } |
2347 | WL_NONE(("request fw %s\n", fw_name)); | 1764 | WL_NONE("request fw %s\n", fw_name); |
2348 | sprintf(fw_name, "%s_hdr-%d.fw", wl_firmwares[i], | 1765 | sprintf(fw_name, "%s_hdr-%d.fw", wl_firmwares[i], |
2349 | UCODE_LOADER_API_VER); | 1766 | UCODE_LOADER_API_VER); |
2350 | status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); | 1767 | status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); |
@@ -2356,22 +1773,19 @@ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev) | |||
2356 | } | 1773 | } |
2357 | wl->fw.hdr_num_entries[i] = | 1774 | wl->fw.hdr_num_entries[i] = |
2358 | wl->fw.fw_hdr[i]->size / (sizeof(struct wl_fw_hdr)); | 1775 | wl->fw.fw_hdr[i]->size / (sizeof(struct wl_fw_hdr)); |
2359 | WL_NONE(("request fw %s find: %d entries\n", fw_name, | 1776 | WL_NONE("request fw %s find: %d entries\n", |
2360 | wl->fw.hdr_num_entries[i])); | 1777 | fw_name, wl->fw.hdr_num_entries[i]); |
2361 | } | 1778 | } |
2362 | wl->fw.fw_cnt = i; | 1779 | wl->fw.fw_cnt = i; |
2363 | wl_ucode_data_init(wl); | 1780 | return wl_ucode_data_init(wl); |
2364 | return 0; | ||
2365 | } | 1781 | } |
2366 | 1782 | ||
2367 | #ifdef WLC_LOW | ||
2368 | void wl_ucode_free_buf(void *p) | 1783 | void wl_ucode_free_buf(void *p) |
2369 | { | 1784 | { |
2370 | kfree(p); | 1785 | kfree(p); |
2371 | } | 1786 | } |
2372 | #endif /* WLC_LOW */ | ||
2373 | 1787 | ||
2374 | static void wl_release_fw(wl_info_t *wl) | 1788 | static void wl_release_fw(struct wl_info *wl) |
2375 | { | 1789 | { |
2376 | int i; | 1790 | int i; |
2377 | for (i = 0; i < WL_MAX_FW; i++) { | 1791 | for (i = 0; i < WL_MAX_FW; i++) { |
@@ -2379,4 +1793,54 @@ static void wl_release_fw(wl_info_t *wl) | |||
2379 | release_firmware(wl->fw.fw_hdr[i]); | 1793 | release_firmware(wl->fw.fw_hdr[i]); |
2380 | } | 1794 | } |
2381 | } | 1795 | } |
2382 | #endif /* WLC_HIGH_ONLY */ | 1796 | |
1797 | |||
1798 | /* | ||
1799 | * checks validity of all firmware images loaded from user space | ||
1800 | */ | ||
1801 | int wl_check_firmwares(struct wl_info *wl) | ||
1802 | { | ||
1803 | int i; | ||
1804 | int entry; | ||
1805 | int rc = 0; | ||
1806 | const struct firmware *fw; | ||
1807 | const struct firmware *fw_hdr; | ||
1808 | struct wl_fw_hdr *ucode_hdr; | ||
1809 | for (i = 0; i < WL_MAX_FW && rc == 0; i++) { | ||
1810 | fw = wl->fw.fw_bin[i]; | ||
1811 | fw_hdr = wl->fw.fw_hdr[i]; | ||
1812 | if (fw == NULL && fw_hdr == NULL) { | ||
1813 | break; | ||
1814 | } else if (fw == NULL || fw_hdr == NULL) { | ||
1815 | WL_ERROR("%s: invalid bin/hdr fw\n", __func__); | ||
1816 | rc = -EBADF; | ||
1817 | } else if (fw_hdr->size % sizeof(struct wl_fw_hdr)) { | ||
1818 | WL_ERROR("%s: non integral fw hdr file size %d/%zu\n", | ||
1819 | __func__, fw_hdr->size, | ||
1820 | sizeof(struct wl_fw_hdr)); | ||
1821 | rc = -EBADF; | ||
1822 | } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { | ||
1823 | WL_ERROR("%s: out of bounds fw file size %d\n", | ||
1824 | __func__, fw->size); | ||
1825 | rc = -EBADF; | ||
1826 | } else { | ||
1827 | /* check if ucode section overruns firmware image */ | ||
1828 | ucode_hdr = (struct wl_fw_hdr *)fw_hdr->data; | ||
1829 | for (entry = 0; entry < wl->fw.hdr_num_entries[i] && rc; | ||
1830 | entry++, ucode_hdr++) { | ||
1831 | if (ucode_hdr->offset + ucode_hdr->len > | ||
1832 | fw->size) { | ||
1833 | WL_ERROR("%s: conflicting bin/hdr\n", | ||
1834 | __func__); | ||
1835 | rc = -EBADF; | ||
1836 | } | ||
1837 | } | ||
1838 | } | ||
1839 | } | ||
1840 | if (rc == 0 && wl->fw.fw_cnt != i) { | ||
1841 | WL_ERROR("%s: invalid fw_cnt=%d\n", __func__, wl->fw.fw_cnt); | ||
1842 | rc = -EBADF; | ||
1843 | } | ||
1844 | return rc; | ||
1845 | } | ||
1846 | |||