blob: 876b6b28dd223ee21245c0b6a38ae45afc064596 [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001
2/*
3 * Copyright (c) 2011 Atheros Communications Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
Sam Leffler92ecbff2011-09-07 10:55:16 +030018#include <linux/of.h>
Kalle Valobdcd8172011-07-18 00:22:30 +030019#include <linux/mmc/sdio_func.h>
20#include "core.h"
21#include "cfg80211.h"
22#include "target.h"
23#include "debug.h"
24#include "hif-ops.h"
25
26unsigned int debug_mask;
Kalle Valo003353b2011-09-01 10:14:21 +030027static unsigned int testmode;
Kalle Valobdcd8172011-07-18 00:22:30 +030028
29module_param(debug_mask, uint, 0644);
Kalle Valo003353b2011-09-01 10:14:21 +030030module_param(testmode, uint, 0644);
Kalle Valobdcd8172011-07-18 00:22:30 +030031
32/*
33 * Include definitions here that can be used to tune the WLAN module
34 * behavior. Different customers can tune the behavior as per their needs,
35 * here.
36 */
37
38/*
39 * This configuration item enable/disable keepalive support.
40 * Keepalive support: In the absence of any data traffic to AP, null
41 * frames will be sent to the AP at periodic interval, to keep the association
42 * active. This configuration item defines the periodic interval.
43 * Use value of zero to disable keepalive support
44 * Default: 60 seconds
45 */
46#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60
47
48/*
49 * This configuration item sets the value of disconnect timeout
50 * Firmware delays sending the disconnec event to the host for this
51 * timeout after is gets disconnected from the current AP.
52 * If the firmware successly roams within the disconnect timeout
53 * it sends a new connect event
54 */
55#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
56
57#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
58
Kalle Valobdcd8172011-07-18 00:22:30 +030059#define ATH6KL_DATA_OFFSET 64
60struct sk_buff *ath6kl_buf_alloc(int size)
61{
62 struct sk_buff *skb;
63 u16 reserved;
64
65 /* Add chacheline space at front and back of buffer */
66 reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +
Vasanthakumar Thiagarajan1df94a82011-08-17 18:45:10 +053067 sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES;
Kalle Valobdcd8172011-07-18 00:22:30 +030068 skb = dev_alloc_skb(size + reserved);
69
70 if (skb)
71 skb_reserve(skb, reserved - L1_CACHE_BYTES);
72 return skb;
73}
74
75void ath6kl_init_profile_info(struct ath6kl *ar)
76{
77 ar->ssid_len = 0;
78 memset(ar->ssid, 0, sizeof(ar->ssid));
79
80 ar->dot11_auth_mode = OPEN_AUTH;
81 ar->auth_mode = NONE_AUTH;
82 ar->prwise_crypto = NONE_CRYPT;
83 ar->prwise_crypto_len = 0;
84 ar->grp_crypto = NONE_CRYPT;
Edward Lu38acde32011-08-30 21:58:06 +030085 ar->grp_crypto_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +030086 memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
87 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
88 memset(ar->bssid, 0, sizeof(ar->bssid));
89 ar->bss_ch = 0;
90 ar->nw_type = ar->next_mode = INFRA_NETWORK;
91}
92
93static u8 ath6kl_get_fw_iftype(struct ath6kl *ar)
94{
95 switch (ar->nw_type) {
96 case INFRA_NETWORK:
97 return HI_OPTION_FW_MODE_BSS_STA;
98 case ADHOC_NETWORK:
99 return HI_OPTION_FW_MODE_IBSS;
100 case AP_NETWORK:
101 return HI_OPTION_FW_MODE_AP;
102 default:
103 ath6kl_err("Unsupported interface type :%d\n", ar->nw_type);
104 return 0xff;
105 }
106}
107
Kalle Valobdcd8172011-07-18 00:22:30 +0300108static int ath6kl_set_host_app_area(struct ath6kl *ar)
109{
110 u32 address, data;
111 struct host_app_area host_app_area;
112
113 /* Fetch the address of the host_app_area_s
114 * instance in the host interest area */
115 address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest));
Kevin Fang31024d92011-07-11 17:14:13 +0800116 address = TARG_VTOP(ar->target_type, address);
Kalle Valobdcd8172011-07-18 00:22:30 +0300117
Kalle Valoaddb44b2011-09-02 10:32:05 +0300118 if (ath6kl_diag_read32(ar, address, &data))
Kalle Valobdcd8172011-07-18 00:22:30 +0300119 return -EIO;
120
Kevin Fang31024d92011-07-11 17:14:13 +0800121 address = TARG_VTOP(ar->target_type, data);
Kalle Valobdcd8172011-07-18 00:22:30 +0300122 host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION;
Kalle Valoaddb44b2011-09-02 10:32:05 +0300123 if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area,
124 sizeof(struct host_app_area)))
Kalle Valobdcd8172011-07-18 00:22:30 +0300125 return -EIO;
126
127 return 0;
128}
129
130static inline void set_ac2_ep_map(struct ath6kl *ar,
131 u8 ac,
132 enum htc_endpoint_id ep)
133{
134 ar->ac2ep_map[ac] = ep;
135 ar->ep2ac_map[ep] = ac;
136}
137
138/* connect to a service */
139static int ath6kl_connectservice(struct ath6kl *ar,
140 struct htc_service_connect_req *con_req,
141 char *desc)
142{
143 int status;
144 struct htc_service_connect_resp response;
145
146 memset(&response, 0, sizeof(response));
147
Kalle Vaload226ec2011-08-10 09:49:12 +0300148 status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response);
Kalle Valobdcd8172011-07-18 00:22:30 +0300149 if (status) {
150 ath6kl_err("failed to connect to %s service status:%d\n",
151 desc, status);
152 return status;
153 }
154
155 switch (con_req->svc_id) {
156 case WMI_CONTROL_SVC:
157 if (test_bit(WMI_ENABLED, &ar->flag))
158 ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint);
159 ar->ctrl_ep = response.endpoint;
160 break;
161 case WMI_DATA_BE_SVC:
162 set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint);
163 break;
164 case WMI_DATA_BK_SVC:
165 set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint);
166 break;
167 case WMI_DATA_VI_SVC:
168 set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint);
169 break;
170 case WMI_DATA_VO_SVC:
171 set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint);
172 break;
173 default:
174 ath6kl_err("service id is not mapped %d\n", con_req->svc_id);
175 return -EINVAL;
176 }
177
178 return 0;
179}
180
181static int ath6kl_init_service_ep(struct ath6kl *ar)
182{
183 struct htc_service_connect_req connect;
184
185 memset(&connect, 0, sizeof(connect));
186
187 /* these fields are the same for all service endpoints */
188 connect.ep_cb.rx = ath6kl_rx;
189 connect.ep_cb.rx_refill = ath6kl_rx_refill;
190 connect.ep_cb.tx_full = ath6kl_tx_queue_full;
191
192 /*
193 * Set the max queue depth so that our ath6kl_tx_queue_full handler
194 * gets called.
195 */
196 connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH;
197 connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4;
198 if (!connect.ep_cb.rx_refill_thresh)
199 connect.ep_cb.rx_refill_thresh++;
200
201 /* connect to control service */
202 connect.svc_id = WMI_CONTROL_SVC;
203 if (ath6kl_connectservice(ar, &connect, "WMI CONTROL"))
204 return -EIO;
205
206 connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN;
207
208 /*
209 * Limit the HTC message size on the send path, although e can
210 * receive A-MSDU frames of 4K, we will only send ethernet-sized
211 * (802.3) frames on the send path.
212 */
213 connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH;
214
215 /*
216 * To reduce the amount of committed memory for larger A_MSDU
217 * frames, use the recv-alloc threshold mechanism for larger
218 * packets.
219 */
220 connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE;
221 connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf;
222
223 /*
224 * For the remaining data services set the connection flag to
225 * reduce dribbling, if configured to do so.
226 */
227 connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB;
228 connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK;
229 connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF;
230
231 connect.svc_id = WMI_DATA_BE_SVC;
232
233 if (ath6kl_connectservice(ar, &connect, "WMI DATA BE"))
234 return -EIO;
235
236 /* connect to back-ground map this to WMI LOW_PRI */
237 connect.svc_id = WMI_DATA_BK_SVC;
238 if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
239 return -EIO;
240
241 /* connect to Video service, map this to to HI PRI */
242 connect.svc_id = WMI_DATA_VI_SVC;
243 if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
244 return -EIO;
245
246 /*
247 * Connect to VO service, this is currently not mapped to a WMI
248 * priority stream due to historical reasons. WMI originally
249 * defined 3 priorities over 3 mailboxes We can change this when
250 * WMI is reworked so that priorities are not dependent on
251 * mailboxes.
252 */
253 connect.svc_id = WMI_DATA_VO_SVC;
254 if (ath6kl_connectservice(ar, &connect, "WMI DATA VO"))
255 return -EIO;
256
257 return 0;
258}
259
260static void ath6kl_init_control_info(struct ath6kl *ar)
261{
262 u8 ctr;
263
264 clear_bit(WMI_ENABLED, &ar->flag);
265 ath6kl_init_profile_info(ar);
266 ar->def_txkey_index = 0;
267 memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
268 ar->ch_hint = 0;
269 ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
270 ar->listen_intvl_b = 0;
271 ar->tx_pwr = 0;
272 clear_bit(SKIP_SCAN, &ar->flag);
273 set_bit(WMM_ENABLED, &ar->flag);
274 ar->intra_bss = 1;
275 memset(&ar->sc_params, 0, sizeof(ar->sc_params));
276 ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
277 ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
Vivek Natarajane5090442011-08-31 15:02:19 +0530278 ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
Kalle Valobdcd8172011-07-18 00:22:30 +0300279
280 memset((u8 *)ar->sta_list, 0,
281 AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
282
283 spin_lock_init(&ar->mcastpsq_lock);
284
285 /* Init the PS queues */
286 for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
287 spin_lock_init(&ar->sta_list[ctr].psq_lock);
288 skb_queue_head_init(&ar->sta_list[ctr].psq);
289 }
290
291 skb_queue_head_init(&ar->mcastpsq);
292
293 memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
294}
295
296/*
297 * Set HTC/Mbox operational parameters, this can only be called when the
298 * target is in the BMI phase.
299 */
300static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
301 u8 htc_ctrl_buf)
302{
303 int status;
304 u32 blk_size;
305
306 blk_size = ar->mbox_info.block_size;
307
308 if (htc_ctrl_buf)
309 blk_size |= ((u32)htc_ctrl_buf) << 16;
310
311 /* set the host interest area for the block size */
312 status = ath6kl_bmi_write(ar,
313 ath6kl_get_hi_item_addr(ar,
314 HI_ITEM(hi_mbox_io_block_sz)),
315 (u8 *)&blk_size,
316 4);
317 if (status) {
318 ath6kl_err("bmi_write_memory for IO block size failed\n");
319 goto out;
320 }
321
322 ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n",
323 blk_size,
324 ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz)));
325
326 if (mbox_isr_yield_val) {
327 /* set the host interest area for the mbox ISR yield limit */
328 status = ath6kl_bmi_write(ar,
329 ath6kl_get_hi_item_addr(ar,
330 HI_ITEM(hi_mbox_isr_yield_limit)),
331 (u8 *)&mbox_isr_yield_val,
332 4);
333 if (status) {
334 ath6kl_err("bmi_write_memory for yield limit failed\n");
335 goto out;
336 }
337 }
338
339out:
340 return status;
341}
342
343#define REG_DUMP_COUNT_AR6003 60
344#define REGISTER_DUMP_LEN_MAX 60
345
346static void ath6kl_dump_target_assert_info(struct ath6kl *ar)
347{
348 u32 address;
349 u32 regdump_loc = 0;
350 int status;
351 u32 regdump_val[REGISTER_DUMP_LEN_MAX];
352 u32 i;
353
354 if (ar->target_type != TARGET_TYPE_AR6003)
355 return;
356
357 /* the reg dump pointer is copied to the host interest area */
358 address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
Kevin Fang31024d92011-07-11 17:14:13 +0800359 address = TARG_VTOP(ar->target_type, address);
Kalle Valobdcd8172011-07-18 00:22:30 +0300360
361 /* read RAM location through diagnostic window */
Kalle Valoaddb44b2011-09-02 10:32:05 +0300362 status = ath6kl_diag_read32(ar, address, &regdump_loc);
Kalle Valobdcd8172011-07-18 00:22:30 +0300363
364 if (status || !regdump_loc) {
365 ath6kl_err("failed to get ptr to register dump area\n");
366 return;
367 }
368
369 ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n",
370 regdump_loc);
Kevin Fang31024d92011-07-11 17:14:13 +0800371 regdump_loc = TARG_VTOP(ar->target_type, regdump_loc);
Kalle Valobdcd8172011-07-18 00:22:30 +0300372
373 /* fetch register dump data */
Kalle Valoaddb44b2011-09-02 10:32:05 +0300374 status = ath6kl_diag_read(ar, regdump_loc, (u8 *)&regdump_val[0],
375 REG_DUMP_COUNT_AR6003 * (sizeof(u32)));
Kalle Valobdcd8172011-07-18 00:22:30 +0300376
377 if (status) {
378 ath6kl_err("failed to get register dump\n");
379 return;
380 }
381 ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n");
382
383 for (i = 0; i < REG_DUMP_COUNT_AR6003; i++)
384 ath6kl_dbg(ATH6KL_DBG_TRC, " %d : 0x%8.8X\n",
385 i, regdump_val[i]);
386
387}
388
389void ath6kl_target_failure(struct ath6kl *ar)
390{
391 ath6kl_err("target asserted\n");
392
393 /* try dumping target assertion information (if any) */
394 ath6kl_dump_target_assert_info(ar);
395
396}
397
398static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
399{
400 int status = 0;
Jouni Malinen4dea08e2011-08-30 21:57:57 +0300401 int ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300402
403 /*
404 * Configure the device for rx dot11 header rules. "0,0" are the
405 * default values. Required if checksum offload is needed. Set
406 * RxMetaVersion to 2.
407 */
408 if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
409 ar->rx_meta_ver, 0, 0)) {
410 ath6kl_err("unable to set the rx frame format\n");
411 status = -EIO;
412 }
413
414 if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN)
415 if ((ath6kl_wmi_pmparams_cmd(ar->wmi, 0, 1, 0, 0, 1,
416 IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) {
417 ath6kl_err("unable to set power save fail event policy\n");
418 status = -EIO;
419 }
420
421 if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER))
422 if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, 0,
423 WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) {
424 ath6kl_err("unable to set barker preamble policy\n");
425 status = -EIO;
426 }
427
428 if (ath6kl_wmi_set_keepalive_cmd(ar->wmi,
429 WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) {
430 ath6kl_err("unable to set keep alive interval\n");
431 status = -EIO;
432 }
433
434 if (ath6kl_wmi_disctimeout_cmd(ar->wmi,
435 WLAN_CONFIG_DISCONNECT_TIMEOUT)) {
436 ath6kl_err("unable to set disconnect timeout\n");
437 status = -EIO;
438 }
439
440 if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST))
441 if (ath6kl_wmi_set_wmm_txop(ar->wmi, WMI_TXOP_DISABLED)) {
442 ath6kl_err("unable to set txop bursting\n");
443 status = -EIO;
444 }
445
Jouni Malinen6bbc7c32011-09-05 17:38:47 +0300446 if (ar->p2p) {
447 ret = ath6kl_wmi_info_req_cmd(ar->wmi,
448 P2P_FLAG_CAPABILITIES_REQ |
449 P2P_FLAG_MACADDR_REQ |
450 P2P_FLAG_HMODEL_REQ);
451 if (ret) {
452 ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
453 "capabilities (%d) - assuming P2P not "
454 "supported\n", ret);
455 ar->p2p = 0;
456 }
457 }
458
459 if (ar->p2p) {
460 /* Enable Probe Request reporting for P2P */
461 ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true);
462 if (ret) {
463 ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe "
464 "Request reporting (%d)\n", ret);
465 }
Jouni Malinen4dea08e2011-08-30 21:57:57 +0300466 }
467
Kalle Valobdcd8172011-07-18 00:22:30 +0300468 return status;
469}
470
471int ath6kl_configure_target(struct ath6kl *ar)
472{
473 u32 param, ram_reserved_size;
474 u8 fw_iftype;
475
476 fw_iftype = ath6kl_get_fw_iftype(ar);
477 if (fw_iftype == 0xff)
478 return -EINVAL;
479
480 /* Tell target which HTC version it is used*/
481 param = HTC_PROTOCOL_VERSION;
482 if (ath6kl_bmi_write(ar,
483 ath6kl_get_hi_item_addr(ar,
484 HI_ITEM(hi_app_host_interest)),
485 (u8 *)&param, 4) != 0) {
486 ath6kl_err("bmi_write_memory for htc version failed\n");
487 return -EIO;
488 }
489
490 /* set the firmware mode to STA/IBSS/AP */
491 param = 0;
492
493 if (ath6kl_bmi_read(ar,
494 ath6kl_get_hi_item_addr(ar,
495 HI_ITEM(hi_option_flag)),
496 (u8 *)&param, 4) != 0) {
497 ath6kl_err("bmi_read_memory for setting fwmode failed\n");
498 return -EIO;
499 }
500
501 param |= (1 << HI_OPTION_NUM_DEV_SHIFT);
502 param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +0300503 if (ar->p2p && fw_iftype == HI_OPTION_FW_MODE_BSS_STA) {
504 param |= HI_OPTION_FW_SUBMODE_P2PDEV <<
505 HI_OPTION_FW_SUBMODE_SHIFT;
506 }
Kalle Valobdcd8172011-07-18 00:22:30 +0300507 param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
508 param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);
509
510 if (ath6kl_bmi_write(ar,
511 ath6kl_get_hi_item_addr(ar,
512 HI_ITEM(hi_option_flag)),
513 (u8 *)&param,
514 4) != 0) {
515 ath6kl_err("bmi_write_memory for setting fwmode failed\n");
516 return -EIO;
517 }
518
519 ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n");
520
521 /*
522 * Hardcode the address use for the extended board data
523 * Ideally this should be pre-allocate by the OS at boot time
524 * But since it is a new feature and board data is loaded
525 * at init time, we have to workaround this from host.
526 * It is difficult to patch the firmware boot code,
527 * but possible in theory.
528 */
529
Kalle Valo991b27e2011-09-07 10:55:17 +0300530 param = ar->hw.board_ext_data_addr;
531 ram_reserved_size = ar->hw.reserved_ram_size;
Kalle Valobdcd8172011-07-18 00:22:30 +0300532
Kalle Valo991b27e2011-09-07 10:55:17 +0300533 if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
534 HI_ITEM(hi_board_ext_data)),
535 (u8 *)&param, 4) != 0) {
536 ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
537 return -EIO;
538 }
539
540 if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
541 HI_ITEM(hi_end_ram_reserve_sz)),
542 (u8 *)&ram_reserved_size, 4) != 0) {
543 ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
544 return -EIO;
Kalle Valobdcd8172011-07-18 00:22:30 +0300545 }
546
547 /* set the block size for the target */
548 if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0))
549 /* use default number of control buffers */
550 return -EIO;
551
552 return 0;
553}
554
555struct ath6kl *ath6kl_core_alloc(struct device *sdev)
556{
557 struct net_device *dev;
558 struct ath6kl *ar;
559 struct wireless_dev *wdev;
560
561 wdev = ath6kl_cfg80211_init(sdev);
562 if (!wdev) {
563 ath6kl_err("ath6kl_cfg80211_init failed\n");
564 return NULL;
565 }
566
567 ar = wdev_priv(wdev);
568 ar->dev = sdev;
569 ar->wdev = wdev;
570 wdev->iftype = NL80211_IFTYPE_STATION;
571
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +0530572 if (ath6kl_debug_init(ar)) {
573 ath6kl_err("Failed to initialize debugfs\n");
574 ath6kl_cfg80211_deinit(ar);
575 return NULL;
576 }
577
Kalle Valobdcd8172011-07-18 00:22:30 +0300578 dev = alloc_netdev(0, "wlan%d", ether_setup);
579 if (!dev) {
580 ath6kl_err("no memory for network device instance\n");
581 ath6kl_cfg80211_deinit(ar);
582 return NULL;
583 }
584
585 dev->ieee80211_ptr = wdev;
586 SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
587 wdev->netdev = dev;
588 ar->sme_state = SME_DISCONNECTED;
Kalle Valobdcd8172011-07-18 00:22:30 +0300589
590 init_netdev(dev);
591
592 ar->net_dev = dev;
Raja Mani575b5f32011-07-19 19:27:33 +0530593 set_bit(WLAN_ENABLED, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +0300594
595 ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
596
597 spin_lock_init(&ar->lock);
598
599 ath6kl_init_control_info(ar);
600 init_waitqueue_head(&ar->event_wq);
601 sema_init(&ar->sem, 1);
602 clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
603
604 INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
605
606 setup_timer(&ar->disconnect_timer, disconnect_timer_handler,
607 (unsigned long) dev);
608
609 return ar;
610}
611
612int ath6kl_unavail_ev(struct ath6kl *ar)
613{
614 ath6kl_destroy(ar->net_dev, 1);
615
616 return 0;
617}
618
619/* firmware upload */
Kalle Valobdcd8172011-07-18 00:22:30 +0300620static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
621 u8 **fw, size_t *fw_len)
622{
623 const struct firmware *fw_entry;
624 int ret;
625
626 ret = request_firmware(&fw_entry, filename, ar->dev);
627 if (ret)
628 return ret;
629
630 *fw_len = fw_entry->size;
631 *fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
632
633 if (*fw == NULL)
634 ret = -ENOMEM;
635
636 release_firmware(fw_entry);
637
638 return ret;
639}
640
Sam Leffler92ecbff2011-09-07 10:55:16 +0300641#ifdef CONFIG_OF
642static const char *get_target_ver_dir(const struct ath6kl *ar)
643{
644 switch (ar->version.target_ver) {
645 case AR6003_REV1_VERSION:
646 return "ath6k/AR6003/hw1.0";
647 case AR6003_REV2_VERSION:
648 return "ath6k/AR6003/hw2.0";
649 case AR6003_REV3_VERSION:
650 return "ath6k/AR6003/hw2.1.1";
651 }
652 ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
653 ar->version.target_ver);
654 return NULL;
655}
656
657/*
658 * Check the device tree for a board-id and use it to construct
659 * the pathname to the firmware file. Used (for now) to find a
660 * fallback to the "bdata.bin" file--typically a symlink to the
661 * appropriate board-specific file.
662 */
663static bool check_device_tree(struct ath6kl *ar)
664{
665 static const char *board_id_prop = "atheros,board-id";
666 struct device_node *node;
667 char board_filename[64];
668 const char *board_id;
669 int ret;
670
671 for_each_compatible_node(node, NULL, "atheros,ath6kl") {
672 board_id = of_get_property(node, board_id_prop, NULL);
673 if (board_id == NULL) {
674 ath6kl_warn("No \"%s\" property on %s node.\n",
675 board_id_prop, node->name);
676 continue;
677 }
678 snprintf(board_filename, sizeof(board_filename),
679 "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id);
680
681 ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board,
682 &ar->fw_board_len);
683 if (ret) {
684 ath6kl_err("Failed to get DT board file %s: %d\n",
685 board_filename, ret);
686 continue;
687 }
688 return true;
689 }
690 return false;
691}
692#else
693static bool check_device_tree(struct ath6kl *ar)
694{
695 return false;
696}
697#endif /* CONFIG_OF */
698
Kalle Valobdcd8172011-07-18 00:22:30 +0300699static int ath6kl_fetch_board_file(struct ath6kl *ar)
700{
701 const char *filename;
702 int ret;
703
Kalle Valo772c31e2011-09-07 10:55:16 +0300704 if (ar->fw_board != NULL)
705 return 0;
706
Kalle Valobdcd8172011-07-18 00:22:30 +0300707 switch (ar->version.target_ver) {
708 case AR6003_REV2_VERSION:
709 filename = AR6003_REV2_BOARD_DATA_FILE;
710 break;
Kevin Fang31024d92011-07-11 17:14:13 +0800711 case AR6004_REV1_VERSION:
712 filename = AR6004_REV1_BOARD_DATA_FILE;
713 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300714 default:
715 filename = AR6003_REV3_BOARD_DATA_FILE;
716 break;
717 }
718
719 ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
720 &ar->fw_board_len);
721 if (ret == 0) {
722 /* managed to get proper board file */
723 return 0;
724 }
725
Sam Leffler92ecbff2011-09-07 10:55:16 +0300726 if (check_device_tree(ar)) {
727 /* got board file from device tree */
728 return 0;
729 }
730
Kalle Valobdcd8172011-07-18 00:22:30 +0300731 /* there was no proper board file, try to use default instead */
732 ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
733 filename, ret);
734
735 switch (ar->version.target_ver) {
736 case AR6003_REV2_VERSION:
737 filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
738 break;
Kevin Fang31024d92011-07-11 17:14:13 +0800739 case AR6004_REV1_VERSION:
740 filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE;
741 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300742 default:
743 filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
744 break;
745 }
746
747 ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
748 &ar->fw_board_len);
749 if (ret) {
750 ath6kl_err("Failed to get default board file %s: %d\n",
751 filename, ret);
752 return ret;
753 }
754
755 ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n");
756 ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n");
757
758 return 0;
759}
760
Kalle Valo772c31e2011-09-07 10:55:16 +0300761static int ath6kl_fetch_otp_file(struct ath6kl *ar)
762{
763 const char *filename;
764 int ret;
765
766 if (ar->fw_otp != NULL)
767 return 0;
768
769 switch (ar->version.target_ver) {
770 case AR6003_REV2_VERSION:
771 filename = AR6003_REV2_OTP_FILE;
772 break;
773 case AR6004_REV1_VERSION:
774 ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n");
775 return 0;
776 break;
777 default:
778 filename = AR6003_REV3_OTP_FILE;
779 break;
780 }
781
782 ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
783 &ar->fw_otp_len);
784 if (ret) {
785 ath6kl_err("Failed to get OTP file %s: %d\n",
786 filename, ret);
787 return ret;
788 }
789
790 return 0;
791}
792
793static int ath6kl_fetch_fw_file(struct ath6kl *ar)
794{
795 const char *filename;
796 int ret;
797
798 if (ar->fw != NULL)
799 return 0;
800
801 if (testmode) {
802 switch (ar->version.target_ver) {
803 case AR6003_REV2_VERSION:
804 filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
805 break;
806 case AR6003_REV3_VERSION:
807 filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
808 break;
809 case AR6004_REV1_VERSION:
810 ath6kl_warn("testmode not supported with ar6004\n");
811 return -EOPNOTSUPP;
812 default:
813 ath6kl_warn("unknown target version: 0x%x\n",
814 ar->version.target_ver);
815 return -EINVAL;
816 }
817
818 set_bit(TESTMODE, &ar->flag);
819
820 goto get_fw;
821 }
822
823 switch (ar->version.target_ver) {
824 case AR6003_REV2_VERSION:
825 filename = AR6003_REV2_FIRMWARE_FILE;
826 break;
827 case AR6004_REV1_VERSION:
828 filename = AR6004_REV1_FIRMWARE_FILE;
829 break;
830 default:
831 filename = AR6003_REV3_FIRMWARE_FILE;
832 break;
833 }
834
835get_fw:
836 ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
837 if (ret) {
838 ath6kl_err("Failed to get firmware file %s: %d\n",
839 filename, ret);
840 return ret;
841 }
842
843 return 0;
844}
845
846static int ath6kl_fetch_patch_file(struct ath6kl *ar)
847{
848 const char *filename;
849 int ret;
850
851 switch (ar->version.target_ver) {
852 case AR6003_REV2_VERSION:
853 filename = AR6003_REV2_PATCH_FILE;
854 break;
855 case AR6004_REV1_VERSION:
856 /* FIXME: implement for AR6004 */
857 return 0;
858 break;
859 default:
860 filename = AR6003_REV3_PATCH_FILE;
861 break;
862 }
863
864 if (ar->fw_patch == NULL) {
865 ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
866 &ar->fw_patch_len);
867 if (ret) {
868 ath6kl_err("Failed to get patch file %s: %d\n",
869 filename, ret);
870 return ret;
871 }
872 }
873
874 return 0;
875}
876
Kalle Valo50d41232011-09-07 10:55:17 +0300877static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
Kalle Valo772c31e2011-09-07 10:55:16 +0300878{
879 int ret;
880
Kalle Valo772c31e2011-09-07 10:55:16 +0300881 ret = ath6kl_fetch_otp_file(ar);
882 if (ret)
883 return ret;
884
885 ret = ath6kl_fetch_fw_file(ar);
886 if (ret)
887 return ret;
888
889 ret = ath6kl_fetch_patch_file(ar);
890 if (ret)
891 return ret;
892
893 return 0;
894}
Kalle Valobdcd8172011-07-18 00:22:30 +0300895
Kalle Valo50d41232011-09-07 10:55:17 +0300896static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
897{
898 size_t magic_len, len, ie_len;
899 const struct firmware *fw;
900 struct ath6kl_fw_ie *hdr;
901 const char *filename;
902 const u8 *data;
Kalle Valo97e04962011-09-12 13:47:34 +0300903 int ret, ie_id, i, index, bit;
Kalle Valo8a137482011-09-07 10:55:17 +0300904 __le32 *val;
Kalle Valo50d41232011-09-07 10:55:17 +0300905
906 switch (ar->version.target_ver) {
907 case AR6003_REV2_VERSION:
908 filename = AR6003_REV2_FIRMWARE_2_FILE;
909 break;
910 case AR6003_REV3_VERSION:
911 filename = AR6003_REV3_FIRMWARE_2_FILE;
912 break;
913 case AR6004_REV1_VERSION:
914 filename = AR6004_REV1_FIRMWARE_2_FILE;
915 break;
916 default:
917 return -EOPNOTSUPP;
918 }
919
920 ret = request_firmware(&fw, filename, ar->dev);
921 if (ret)
922 return ret;
923
924 data = fw->data;
925 len = fw->size;
926
927 /* magic also includes the null byte, check that as well */
928 magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;
929
930 if (len < magic_len) {
931 ret = -EINVAL;
932 goto out;
933 }
934
935 if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {
936 ret = -EINVAL;
937 goto out;
938 }
939
940 len -= magic_len;
941 data += magic_len;
942
943 /* loop elements */
944 while (len > sizeof(struct ath6kl_fw_ie)) {
945 /* hdr is unaligned! */
946 hdr = (struct ath6kl_fw_ie *) data;
947
948 ie_id = le32_to_cpup(&hdr->id);
949 ie_len = le32_to_cpup(&hdr->len);
950
951 len -= sizeof(*hdr);
952 data += sizeof(*hdr);
953
954 if (len < ie_len) {
955 ret = -EINVAL;
956 goto out;
957 }
958
959 switch (ie_id) {
960 case ATH6KL_FW_IE_OTP_IMAGE:
Kalle Valo6bc36432011-09-27 14:31:11 +0300961 ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%d B)\n",
962 ie_len);
963
Kalle Valo50d41232011-09-07 10:55:17 +0300964 ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
965
966 if (ar->fw_otp == NULL) {
967 ret = -ENOMEM;
968 goto out;
969 }
970
971 ar->fw_otp_len = ie_len;
972 break;
973 case ATH6KL_FW_IE_FW_IMAGE:
Kalle Valo6bc36432011-09-27 14:31:11 +0300974 ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%d B)\n",
975 ie_len);
976
Kalle Valo50d41232011-09-07 10:55:17 +0300977 ar->fw = kmemdup(data, ie_len, GFP_KERNEL);
978
979 if (ar->fw == NULL) {
980 ret = -ENOMEM;
981 goto out;
982 }
983
984 ar->fw_len = ie_len;
985 break;
986 case ATH6KL_FW_IE_PATCH_IMAGE:
Kalle Valo6bc36432011-09-27 14:31:11 +0300987 ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%d B)\n",
988 ie_len);
989
Kalle Valo50d41232011-09-07 10:55:17 +0300990 ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
991
992 if (ar->fw_patch == NULL) {
993 ret = -ENOMEM;
994 goto out;
995 }
996
997 ar->fw_patch_len = ie_len;
998 break;
Kalle Valo8a137482011-09-07 10:55:17 +0300999 case ATH6KL_FW_IE_RESERVED_RAM_SIZE:
1000 val = (__le32 *) data;
1001 ar->hw.reserved_ram_size = le32_to_cpup(val);
Kalle Valo6bc36432011-09-27 14:31:11 +03001002
1003 ath6kl_dbg(ATH6KL_DBG_BOOT,
1004 "found reserved ram size ie 0x%d\n",
1005 ar->hw.reserved_ram_size);
Kalle Valo8a137482011-09-07 10:55:17 +03001006 break;
Kalle Valo97e04962011-09-12 13:47:34 +03001007 case ATH6KL_FW_IE_CAPABILITIES:
Kalle Valo6bc36432011-09-27 14:31:11 +03001008 ath6kl_dbg(ATH6KL_DBG_BOOT,
1009 "found firmware capabilities ie (%d B)\n",
1010 ie_len);
1011
Kalle Valo97e04962011-09-12 13:47:34 +03001012 for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
1013 index = ALIGN(i, 8) / 8;
1014 bit = i % 8;
1015
1016 if (data[index] & (1 << bit))
1017 __set_bit(i, ar->fw_capabilities);
1018 }
Kalle Valo6bc36432011-09-27 14:31:11 +03001019
1020 ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "",
1021 ar->fw_capabilities,
1022 sizeof(ar->fw_capabilities));
Kalle Valo97e04962011-09-12 13:47:34 +03001023 break;
Kalle Valo1b4304d2011-09-27 11:05:26 +03001024 case ATH6KL_FW_IE_PATCH_ADDR:
1025 if (ie_len != sizeof(*val))
1026 break;
1027
1028 val = (__le32 *) data;
1029 ar->hw.dataset_patch_addr = le32_to_cpup(val);
Kalle Valo6bc36432011-09-27 14:31:11 +03001030
1031 ath6kl_dbg(ATH6KL_DBG_BOOT,
1032 "found patch address ie 0x%d\n",
1033 ar->hw.dataset_patch_addr);
Kalle Valo1b4304d2011-09-27 11:05:26 +03001034 break;
Kalle Valo50d41232011-09-07 10:55:17 +03001035 default:
Kalle Valo6bc36432011-09-27 14:31:11 +03001036 ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
Kalle Valo50d41232011-09-07 10:55:17 +03001037 le32_to_cpup(&hdr->id));
1038 break;
1039 }
1040
1041 len -= ie_len;
1042 data += ie_len;
1043 };
1044
1045 ret = 0;
1046out:
1047 release_firmware(fw);
1048
1049 return ret;
1050}
1051
1052static int ath6kl_fetch_firmwares(struct ath6kl *ar)
1053{
1054 int ret;
1055
1056 ret = ath6kl_fetch_board_file(ar);
1057 if (ret)
1058 return ret;
1059
1060 ret = ath6kl_fetch_fw_api2(ar);
Kalle Valo6bc36432011-09-27 14:31:11 +03001061 if (ret == 0) {
1062 ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n");
Kalle Valo50d41232011-09-07 10:55:17 +03001063 return 0;
Kalle Valo6bc36432011-09-27 14:31:11 +03001064 }
Kalle Valo50d41232011-09-07 10:55:17 +03001065
1066 ret = ath6kl_fetch_fw_api1(ar);
1067 if (ret)
1068 return ret;
1069
Kalle Valo6bc36432011-09-27 14:31:11 +03001070 ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n");
1071
Kalle Valo50d41232011-09-07 10:55:17 +03001072 return 0;
1073}
1074
Kalle Valobdcd8172011-07-18 00:22:30 +03001075static int ath6kl_upload_board_file(struct ath6kl *ar)
1076{
1077 u32 board_address, board_ext_address, param;
Kevin Fang31024d92011-07-11 17:14:13 +08001078 u32 board_data_size, board_ext_data_size;
Kalle Valobdcd8172011-07-18 00:22:30 +03001079 int ret;
1080
Kalle Valo772c31e2011-09-07 10:55:16 +03001081 if (WARN_ON(ar->fw_board == NULL))
1082 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001083
Kevin Fang31024d92011-07-11 17:14:13 +08001084 /*
1085 * Determine where in Target RAM to write Board Data.
1086 * For AR6004, host determine Target RAM address for
1087 * writing board data.
1088 */
1089 if (ar->target_type == TARGET_TYPE_AR6004) {
1090 board_address = AR6004_REV1_BOARD_DATA_ADDRESS;
1091 ath6kl_bmi_write(ar,
1092 ath6kl_get_hi_item_addr(ar,
1093 HI_ITEM(hi_board_data)),
1094 (u8 *) &board_address, 4);
1095 } else {
1096 ath6kl_bmi_read(ar,
1097 ath6kl_get_hi_item_addr(ar,
1098 HI_ITEM(hi_board_data)),
1099 (u8 *) &board_address, 4);
1100 }
1101
Kalle Valobdcd8172011-07-18 00:22:30 +03001102 /* determine where in target ram to write extended board data */
1103 ath6kl_bmi_read(ar,
1104 ath6kl_get_hi_item_addr(ar,
1105 HI_ITEM(hi_board_ext_data)),
1106 (u8 *) &board_ext_address, 4);
1107
Kalle Valobdcd8172011-07-18 00:22:30 +03001108 if (board_ext_address == 0) {
1109 ath6kl_err("Failed to get board file target address.\n");
1110 return -EINVAL;
1111 }
1112
Kevin Fang31024d92011-07-11 17:14:13 +08001113 switch (ar->target_type) {
1114 case TARGET_TYPE_AR6003:
1115 board_data_size = AR6003_BOARD_DATA_SZ;
1116 board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ;
1117 break;
1118 case TARGET_TYPE_AR6004:
1119 board_data_size = AR6004_BOARD_DATA_SZ;
1120 board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ;
1121 break;
1122 default:
1123 WARN_ON(1);
1124 return -EINVAL;
1125 break;
1126 }
1127
1128 if (ar->fw_board_len == (board_data_size +
1129 board_ext_data_size)) {
1130
Kalle Valobdcd8172011-07-18 00:22:30 +03001131 /* write extended board data */
Kalle Valo6bc36432011-09-27 14:31:11 +03001132 ath6kl_dbg(ATH6KL_DBG_BOOT,
1133 "writing extended board data to 0x%x (%d B)\n",
1134 board_ext_address, board_ext_data_size);
1135
Kalle Valobdcd8172011-07-18 00:22:30 +03001136 ret = ath6kl_bmi_write(ar, board_ext_address,
Kevin Fang31024d92011-07-11 17:14:13 +08001137 ar->fw_board + board_data_size,
1138 board_ext_data_size);
Kalle Valobdcd8172011-07-18 00:22:30 +03001139 if (ret) {
1140 ath6kl_err("Failed to write extended board data: %d\n",
1141 ret);
1142 return ret;
1143 }
1144
1145 /* record that extended board data is initialized */
Kevin Fang31024d92011-07-11 17:14:13 +08001146 param = (board_ext_data_size << 16) | 1;
1147
Kalle Valobdcd8172011-07-18 00:22:30 +03001148 ath6kl_bmi_write(ar,
1149 ath6kl_get_hi_item_addr(ar,
1150 HI_ITEM(hi_board_ext_data_config)),
1151 (unsigned char *) &param, 4);
1152 }
1153
Kevin Fang31024d92011-07-11 17:14:13 +08001154 if (ar->fw_board_len < board_data_size) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001155 ath6kl_err("Too small board file: %zu\n", ar->fw_board_len);
1156 ret = -EINVAL;
1157 return ret;
1158 }
1159
Kalle Valo6bc36432011-09-27 14:31:11 +03001160 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n",
1161 board_address, board_data_size);
1162
Kalle Valobdcd8172011-07-18 00:22:30 +03001163 ret = ath6kl_bmi_write(ar, board_address, ar->fw_board,
Kevin Fang31024d92011-07-11 17:14:13 +08001164 board_data_size);
Kalle Valobdcd8172011-07-18 00:22:30 +03001165
1166 if (ret) {
1167 ath6kl_err("Board file bmi write failed: %d\n", ret);
1168 return ret;
1169 }
1170
1171 /* record the fact that Board Data IS initialized */
1172 param = 1;
1173 ath6kl_bmi_write(ar,
1174 ath6kl_get_hi_item_addr(ar,
1175 HI_ITEM(hi_board_data_initialized)),
1176 (u8 *)&param, 4);
1177
1178 return ret;
1179}
1180
1181static int ath6kl_upload_otp(struct ath6kl *ar)
1182{
Kalle Valobdcd8172011-07-18 00:22:30 +03001183 u32 address, param;
1184 int ret;
1185
Kalle Valo772c31e2011-09-07 10:55:16 +03001186 if (WARN_ON(ar->fw_otp == NULL))
1187 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001188
Kalle Valoa01ac412011-09-07 10:55:17 +03001189 address = ar->hw.app_load_addr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001190
Kalle Valo6bc36432011-09-27 14:31:11 +03001191 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%d B)\n", address,
1192 ar->fw_otp_len);
1193
Kalle Valobdcd8172011-07-18 00:22:30 +03001194 ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp,
1195 ar->fw_otp_len);
1196 if (ret) {
1197 ath6kl_err("Failed to upload OTP file: %d\n", ret);
1198 return ret;
1199 }
1200
Kalle Valo639d0b82011-09-12 12:48:09 +03001201 /* read firmware start address */
1202 ret = ath6kl_bmi_read(ar,
1203 ath6kl_get_hi_item_addr(ar,
1204 HI_ITEM(hi_app_start)),
1205 (u8 *) &address, sizeof(address));
1206
1207 if (ret) {
1208 ath6kl_err("Failed to read hi_app_start: %d\n", ret);
1209 return ret;
1210 }
1211
1212 ar->hw.app_start_override_addr = address;
1213
Kalle Valo6bc36432011-09-27 14:31:11 +03001214 ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr 0x%x\n",
1215 ar->hw.app_start_override_addr);
1216
Kalle Valobdcd8172011-07-18 00:22:30 +03001217 /* execute the OTP code */
Kalle Valo6bc36432011-09-27 14:31:11 +03001218 ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n", address);
Kalle Valobdcd8172011-07-18 00:22:30 +03001219 param = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +03001220 ath6kl_bmi_execute(ar, address, &param);
1221
1222 return ret;
1223}
1224
1225static int ath6kl_upload_firmware(struct ath6kl *ar)
1226{
Kalle Valobdcd8172011-07-18 00:22:30 +03001227 u32 address;
1228 int ret;
1229
Kalle Valo772c31e2011-09-07 10:55:16 +03001230 if (WARN_ON(ar->fw == NULL))
1231 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001232
Kalle Valoa01ac412011-09-07 10:55:17 +03001233 address = ar->hw.app_load_addr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001234
Kalle Valo6bc36432011-09-27 14:31:11 +03001235 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%d B)\n",
1236 address, ar->fw_len);
1237
Kalle Valobdcd8172011-07-18 00:22:30 +03001238 ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len);
1239
1240 if (ret) {
1241 ath6kl_err("Failed to write firmware: %d\n", ret);
1242 return ret;
1243 }
1244
Kevin Fang31024d92011-07-11 17:14:13 +08001245 /*
1246 * Set starting address for firmware
1247 * Don't need to setup app_start override addr on AR6004
1248 */
1249 if (ar->target_type != TARGET_TYPE_AR6004) {
Kalle Valoa01ac412011-09-07 10:55:17 +03001250 address = ar->hw.app_start_override_addr;
Kevin Fang31024d92011-07-11 17:14:13 +08001251 ath6kl_bmi_set_app_start(ar, address);
1252 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001253 return ret;
1254}
1255
1256static int ath6kl_upload_patch(struct ath6kl *ar)
1257{
Kalle Valobdcd8172011-07-18 00:22:30 +03001258 u32 address, param;
1259 int ret;
1260
Kalle Valo772c31e2011-09-07 10:55:16 +03001261 if (WARN_ON(ar->fw_patch == NULL))
1262 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001263
Kalle Valoa01ac412011-09-07 10:55:17 +03001264 address = ar->hw.dataset_patch_addr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001265
Kalle Valo6bc36432011-09-27 14:31:11 +03001266 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%d B)\n",
1267 address, ar->fw_patch_len);
1268
Kalle Valobdcd8172011-07-18 00:22:30 +03001269 ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len);
1270 if (ret) {
1271 ath6kl_err("Failed to write patch file: %d\n", ret);
1272 return ret;
1273 }
1274
1275 param = address;
1276 ath6kl_bmi_write(ar,
1277 ath6kl_get_hi_item_addr(ar,
1278 HI_ITEM(hi_dset_list_head)),
1279 (unsigned char *) &param, 4);
1280
1281 return 0;
1282}
1283
1284static int ath6kl_init_upload(struct ath6kl *ar)
1285{
1286 u32 param, options, sleep, address;
1287 int status = 0;
1288
Kevin Fang31024d92011-07-11 17:14:13 +08001289 if (ar->target_type != TARGET_TYPE_AR6003 &&
1290 ar->target_type != TARGET_TYPE_AR6004)
Kalle Valobdcd8172011-07-18 00:22:30 +03001291 return -EINVAL;
1292
1293 /* temporarily disable system sleep */
1294 address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
1295 status = ath6kl_bmi_reg_read(ar, address, &param);
1296 if (status)
1297 return status;
1298
1299 options = param;
1300
1301 param |= ATH6KL_OPTION_SLEEP_DISABLE;
1302 status = ath6kl_bmi_reg_write(ar, address, param);
1303 if (status)
1304 return status;
1305
1306 address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
1307 status = ath6kl_bmi_reg_read(ar, address, &param);
1308 if (status)
1309 return status;
1310
1311 sleep = param;
1312
1313 param |= SM(SYSTEM_SLEEP_DISABLE, 1);
1314 status = ath6kl_bmi_reg_write(ar, address, param);
1315 if (status)
1316 return status;
1317
1318 ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n",
1319 options, sleep);
1320
1321 /* program analog PLL register */
Kevin Fang31024d92011-07-11 17:14:13 +08001322 /* no need to control 40/44MHz clock on AR6004 */
1323 if (ar->target_type != TARGET_TYPE_AR6004) {
1324 status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER,
1325 0xF9104001);
Kalle Valobdcd8172011-07-18 00:22:30 +03001326
Kevin Fang31024d92011-07-11 17:14:13 +08001327 if (status)
1328 return status;
Kalle Valobdcd8172011-07-18 00:22:30 +03001329
Kevin Fang31024d92011-07-11 17:14:13 +08001330 /* Run at 80/88MHz by default */
1331 param = SM(CPU_CLOCK_STANDARD, 1);
1332
1333 address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;
1334 status = ath6kl_bmi_reg_write(ar, address, param);
1335 if (status)
1336 return status;
1337 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001338
1339 param = 0;
1340 address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;
1341 param = SM(LPO_CAL_ENABLE, 1);
1342 status = ath6kl_bmi_reg_write(ar, address, param);
1343 if (status)
1344 return status;
1345
1346 /* WAR to avoid SDIO CRC err */
1347 if (ar->version.target_ver == AR6003_REV2_VERSION) {
1348 ath6kl_err("temporary war to avoid sdio crc error\n");
1349
1350 param = 0x20;
1351
1352 address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
1353 status = ath6kl_bmi_reg_write(ar, address, param);
1354 if (status)
1355 return status;
1356
1357 address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;
1358 status = ath6kl_bmi_reg_write(ar, address, param);
1359 if (status)
1360 return status;
1361
1362 address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;
1363 status = ath6kl_bmi_reg_write(ar, address, param);
1364 if (status)
1365 return status;
1366
1367 address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;
1368 status = ath6kl_bmi_reg_write(ar, address, param);
1369 if (status)
1370 return status;
1371 }
1372
1373 /* write EEPROM data to Target RAM */
1374 status = ath6kl_upload_board_file(ar);
1375 if (status)
1376 return status;
1377
1378 /* transfer One time Programmable data */
1379 status = ath6kl_upload_otp(ar);
1380 if (status)
1381 return status;
1382
1383 /* Download Target firmware */
1384 status = ath6kl_upload_firmware(ar);
1385 if (status)
1386 return status;
1387
1388 status = ath6kl_upload_patch(ar);
1389 if (status)
1390 return status;
1391
1392 /* Restore system sleep */
1393 address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
1394 status = ath6kl_bmi_reg_write(ar, address, sleep);
1395 if (status)
1396 return status;
1397
1398 address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
1399 param = options | 0x20;
1400 status = ath6kl_bmi_reg_write(ar, address, param);
1401 if (status)
1402 return status;
1403
1404 /* Configure GPIO AR6003 UART */
1405 param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
1406 status = ath6kl_bmi_write(ar,
1407 ath6kl_get_hi_item_addr(ar,
1408 HI_ITEM(hi_dbg_uart_txpin)),
1409 (u8 *)&param, 4);
1410
1411 return status;
1412}
1413
Kalle Valoa01ac412011-09-07 10:55:17 +03001414static int ath6kl_init_hw_params(struct ath6kl *ar)
1415{
1416 switch (ar->version.target_ver) {
1417 case AR6003_REV2_VERSION:
1418 ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
1419 ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS;
Kalle Valo991b27e2011-09-07 10:55:17 +03001420 ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
1421 ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE;
Kalle Valoa01ac412011-09-07 10:55:17 +03001422 break;
1423 case AR6003_REV3_VERSION:
1424 ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS;
1425 ar->hw.app_load_addr = 0x1234;
Kalle Valo991b27e2011-09-07 10:55:17 +03001426 ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
1427 ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE;
Kalle Valoa01ac412011-09-07 10:55:17 +03001428 break;
1429 case AR6004_REV1_VERSION:
1430 ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
1431 ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS;
Kalle Valo991b27e2011-09-07 10:55:17 +03001432 ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS;
1433 ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE;
Kalle Valoa01ac412011-09-07 10:55:17 +03001434 break;
1435 default:
1436 ath6kl_err("Unsupported hardware version: 0x%x\n",
1437 ar->version.target_ver);
1438 return -EINVAL;
1439 }
1440
Kalle Valo6bc36432011-09-27 14:31:11 +03001441 ath6kl_dbg(ATH6KL_DBG_BOOT,
1442 "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
1443 ar->version.target_ver, ar->target_type,
1444 ar->hw.dataset_patch_addr, ar->hw.app_load_addr);
1445 ath6kl_dbg(ATH6KL_DBG_BOOT,
1446 "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
1447 ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
1448 ar->hw.reserved_ram_size);
1449
Kalle Valoa01ac412011-09-07 10:55:17 +03001450 return 0;
1451}
1452
Kalle Valobdcd8172011-07-18 00:22:30 +03001453static int ath6kl_init(struct net_device *dev)
1454{
1455 struct ath6kl *ar = ath6kl_priv(dev);
1456 int status = 0;
1457 s32 timeleft;
1458
1459 if (!ar)
1460 return -EIO;
1461
1462 /* Do we need to finish the BMI phase */
1463 if (ath6kl_bmi_done(ar)) {
1464 status = -EIO;
1465 goto ath6kl_init_done;
1466 }
1467
1468 /* Indicate that WMI is enabled (although not ready yet) */
1469 set_bit(WMI_ENABLED, &ar->flag);
Vasanthakumar Thiagarajan28657852011-07-21 12:00:49 +05301470 ar->wmi = ath6kl_wmi_init(ar);
Kalle Valobdcd8172011-07-18 00:22:30 +03001471 if (!ar->wmi) {
1472 ath6kl_err("failed to initialize wmi\n");
1473 status = -EIO;
1474 goto ath6kl_init_done;
1475 }
1476
1477 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
1478
1479 /*
1480 * The reason we have to wait for the target here is that the
1481 * driver layer has to init BMI in order to set the host block
1482 * size.
1483 */
Kalle Vaload226ec2011-08-10 09:49:12 +03001484 if (ath6kl_htc_wait_target(ar->htc_target)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001485 status = -EIO;
Vasanthakumar Thiagarajan852bd9d2011-07-21 14:24:54 +05301486 goto err_node_cleanup;
Kalle Valobdcd8172011-07-18 00:22:30 +03001487 }
1488
1489 if (ath6kl_init_service_ep(ar)) {
1490 status = -EIO;
1491 goto err_cleanup_scatter;
1492 }
1493
1494 /* setup access class priority mappings */
1495 ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */
1496 ar->ac_stream_pri_map[WMM_AC_BE] = 1;
1497 ar->ac_stream_pri_map[WMM_AC_VI] = 2;
1498 ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
1499
1500 /* give our connected endpoints some buffers */
1501 ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
1502 ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
1503
1504 /* allocate some buffers that handle larger AMSDU frames */
1505 ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
1506
1507 /* setup credit distribution */
1508 ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info);
1509
1510 ath6kl_cookie_init(ar);
1511
1512 /* start HTC */
Kalle Vaload226ec2011-08-10 09:49:12 +03001513 status = ath6kl_htc_start(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001514
1515 if (status) {
1516 ath6kl_cookie_cleanup(ar);
1517 goto err_rxbuf_cleanup;
1518 }
1519
1520 /* Wait for Wmi event to be ready */
1521 timeleft = wait_event_interruptible_timeout(ar->event_wq,
1522 test_bit(WMI_READY,
1523 &ar->flag),
1524 WMI_TIMEOUT);
1525
Kalle Valo6bc36432011-09-27 14:31:11 +03001526 ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");
1527
Kalle Valobdcd8172011-07-18 00:22:30 +03001528 if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
1529 ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
1530 ATH6KL_ABI_VERSION, ar->version.abi_ver);
1531 status = -EIO;
1532 goto err_htc_stop;
1533 }
1534
1535 if (!timeleft || signal_pending(current)) {
1536 ath6kl_err("wmi is not ready or wait was interrupted\n");
1537 status = -EIO;
1538 goto err_htc_stop;
1539 }
1540
1541 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__);
1542
1543 /* communicate the wmi protocol verision to the target */
1544 if ((ath6kl_set_host_app_area(ar)) != 0)
1545 ath6kl_err("unable to set the host app area\n");
1546
1547 ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
1548 ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
1549
Vivek Natarajan011a36e2011-09-19 13:29:16 +05301550 ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
1551
Kalle Valobdcd8172011-07-18 00:22:30 +03001552 status = ath6kl_target_config_wlan_params(ar);
1553 if (!status)
1554 goto ath6kl_init_done;
1555
1556err_htc_stop:
Kalle Vaload226ec2011-08-10 09:49:12 +03001557 ath6kl_htc_stop(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001558err_rxbuf_cleanup:
Kalle Vaload226ec2011-08-10 09:49:12 +03001559 ath6kl_htc_flush_rx_buf(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001560 ath6kl_cleanup_amsdu_rxbufs(ar);
1561err_cleanup_scatter:
1562 ath6kl_hif_cleanup_scatter(ar);
Vasanthakumar Thiagarajan852bd9d2011-07-21 14:24:54 +05301563err_node_cleanup:
Kalle Valobdcd8172011-07-18 00:22:30 +03001564 ath6kl_wmi_shutdown(ar->wmi);
1565 clear_bit(WMI_ENABLED, &ar->flag);
1566 ar->wmi = NULL;
1567
1568ath6kl_init_done:
1569 return status;
1570}
1571
1572int ath6kl_core_init(struct ath6kl *ar)
1573{
1574 int ret = 0;
1575 struct ath6kl_bmi_target_info targ_info;
1576
1577 ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
1578 if (!ar->ath6kl_wq)
1579 return -ENOMEM;
1580
1581 ret = ath6kl_bmi_init(ar);
1582 if (ret)
1583 goto err_wq;
1584
1585 ret = ath6kl_bmi_get_target_info(ar, &targ_info);
1586 if (ret)
1587 goto err_bmi_cleanup;
1588
1589 ar->version.target_ver = le32_to_cpu(targ_info.version);
1590 ar->target_type = le32_to_cpu(targ_info.type);
1591 ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version);
1592
Kalle Valoa01ac412011-09-07 10:55:17 +03001593 ret = ath6kl_init_hw_params(ar);
1594 if (ret)
1595 goto err_bmi_cleanup;
1596
Kalle Valobdcd8172011-07-18 00:22:30 +03001597 ret = ath6kl_configure_target(ar);
1598 if (ret)
1599 goto err_bmi_cleanup;
1600
Kalle Vaload226ec2011-08-10 09:49:12 +03001601 ar->htc_target = ath6kl_htc_create(ar);
Kalle Valobdcd8172011-07-18 00:22:30 +03001602
1603 if (!ar->htc_target) {
1604 ret = -ENOMEM;
1605 goto err_bmi_cleanup;
1606 }
1607
1608 ar->aggr_cntxt = aggr_init(ar->net_dev);
1609 if (!ar->aggr_cntxt) {
1610 ath6kl_err("failed to initialize aggr\n");
1611 ret = -ENOMEM;
1612 goto err_htc_cleanup;
1613 }
1614
Kalle Valo772c31e2011-09-07 10:55:16 +03001615 ret = ath6kl_fetch_firmwares(ar);
1616 if (ret)
1617 goto err_htc_cleanup;
1618
Kalle Valobdcd8172011-07-18 00:22:30 +03001619 ret = ath6kl_init_upload(ar);
1620 if (ret)
1621 goto err_htc_cleanup;
1622
1623 ret = ath6kl_init(ar->net_dev);
1624 if (ret)
1625 goto err_htc_cleanup;
1626
1627 /* This runs the init function if registered */
1628 ret = register_netdev(ar->net_dev);
1629 if (ret) {
1630 ath6kl_err("register_netdev failed\n");
1631 ath6kl_destroy(ar->net_dev, 0);
1632 return ret;
1633 }
1634
1635 set_bit(NETDEV_REGISTERED, &ar->flag);
1636
1637 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
1638 __func__, ar->net_dev->name, ar->net_dev, ar);
1639
1640 return ret;
1641
1642err_htc_cleanup:
Kalle Vaload226ec2011-08-10 09:49:12 +03001643 ath6kl_htc_cleanup(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001644err_bmi_cleanup:
1645 ath6kl_bmi_cleanup(ar);
1646err_wq:
1647 destroy_workqueue(ar->ath6kl_wq);
1648 return ret;
1649}
1650
1651void ath6kl_stop_txrx(struct ath6kl *ar)
1652{
1653 struct net_device *ndev = ar->net_dev;
1654
1655 if (!ndev)
1656 return;
1657
1658 set_bit(DESTROY_IN_PROGRESS, &ar->flag);
1659
1660 if (down_interruptible(&ar->sem)) {
1661 ath6kl_err("down_interruptible failed\n");
1662 return;
1663 }
1664
1665 if (ar->wlan_pwr_state != WLAN_POWER_STATE_CUT_PWR)
1666 ath6kl_stop_endpoint(ndev, false, true);
1667
Raja Mani575b5f32011-07-19 19:27:33 +05301668 clear_bit(WLAN_ENABLED, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +03001669}
1670
1671/*
1672 * We need to differentiate between the surprise and planned removal of the
1673 * device because of the following consideration:
1674 *
1675 * - In case of surprise removal, the hcd already frees up the pending
1676 * for the device and hence there is no need to unregister the function
1677 * driver inorder to get these requests. For planned removal, the function
1678 * driver has to explicitly unregister itself to have the hcd return all the
1679 * pending requests before the data structures for the devices are freed up.
1680 * Note that as per the current implementation, the function driver will
1681 * end up releasing all the devices since there is no API to selectively
1682 * release a particular device.
1683 *
1684 * - Certain commands issued to the target can be skipped for surprise
1685 * removal since they will anyway not go through.
1686 */
1687void ath6kl_destroy(struct net_device *dev, unsigned int unregister)
1688{
1689 struct ath6kl *ar;
1690
1691 if (!dev || !ath6kl_priv(dev)) {
1692 ath6kl_err("failed to get device structure\n");
1693 return;
1694 }
1695
1696 ar = ath6kl_priv(dev);
1697
1698 destroy_workqueue(ar->ath6kl_wq);
1699
1700 if (ar->htc_target)
Kalle Vaload226ec2011-08-10 09:49:12 +03001701 ath6kl_htc_cleanup(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001702
1703 aggr_module_destroy(ar->aggr_cntxt);
1704
1705 ath6kl_cookie_cleanup(ar);
1706
1707 ath6kl_cleanup_amsdu_rxbufs(ar);
1708
1709 ath6kl_bmi_cleanup(ar);
1710
Kalle Valobdf53962011-09-02 10:32:04 +03001711 ath6kl_debug_cleanup(ar);
1712
Kalle Valobdcd8172011-07-18 00:22:30 +03001713 if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) {
1714 unregister_netdev(dev);
1715 clear_bit(NETDEV_REGISTERED, &ar->flag);
1716 }
1717
1718 free_netdev(dev);
1719
Raja Mani19703572011-08-04 19:26:30 +05301720 kfree(ar->fw_board);
1721 kfree(ar->fw_otp);
1722 kfree(ar->fw);
1723 kfree(ar->fw_patch);
1724
Kalle Valobdcd8172011-07-18 00:22:30 +03001725 ath6kl_cfg80211_deinit(ar);
1726}