blob: 0b8d6959c4a97ce65ac7b83973a9a13f8d376eff [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
Stephen Rothwellc6efe572011-09-28 18:32:34 +100018#include <linux/moduleparam.h>
Sam Leffler92ecbff2011-09-07 10:55:16 +030019#include <linux/of.h>
Kalle Valobdcd8172011-07-18 00:22:30 +030020#include <linux/mmc/sdio_func.h>
21#include "core.h"
22#include "cfg80211.h"
23#include "target.h"
24#include "debug.h"
25#include "hif-ops.h"
26
27unsigned int debug_mask;
Kalle Valo003353b2011-09-01 10:14:21 +030028static unsigned int testmode;
Kalle Valobdcd8172011-07-18 00:22:30 +030029
30module_param(debug_mask, uint, 0644);
Kalle Valo003353b2011-09-01 10:14:21 +030031module_param(testmode, uint, 0644);
Kalle Valobdcd8172011-07-18 00:22:30 +030032
33/*
34 * Include definitions here that can be used to tune the WLAN module
35 * behavior. Different customers can tune the behavior as per their needs,
36 * here.
37 */
38
39/*
40 * This configuration item enable/disable keepalive support.
41 * Keepalive support: In the absence of any data traffic to AP, null
42 * frames will be sent to the AP at periodic interval, to keep the association
43 * active. This configuration item defines the periodic interval.
44 * Use value of zero to disable keepalive support
45 * Default: 60 seconds
46 */
47#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60
48
49/*
50 * This configuration item sets the value of disconnect timeout
51 * Firmware delays sending the disconnec event to the host for this
52 * timeout after is gets disconnected from the current AP.
53 * If the firmware successly roams within the disconnect timeout
54 * it sends a new connect event
55 */
56#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
57
58#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
59
Kalle Valobdcd8172011-07-18 00:22:30 +030060#define ATH6KL_DATA_OFFSET 64
61struct sk_buff *ath6kl_buf_alloc(int size)
62{
63 struct sk_buff *skb;
64 u16 reserved;
65
66 /* Add chacheline space at front and back of buffer */
67 reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +
Vasanthakumar Thiagarajan1df94a82011-08-17 18:45:10 +053068 sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES;
Kalle Valobdcd8172011-07-18 00:22:30 +030069 skb = dev_alloc_skb(size + reserved);
70
71 if (skb)
72 skb_reserve(skb, reserved - L1_CACHE_BYTES);
73 return skb;
74}
75
76void ath6kl_init_profile_info(struct ath6kl *ar)
77{
78 ar->ssid_len = 0;
79 memset(ar->ssid, 0, sizeof(ar->ssid));
80
81 ar->dot11_auth_mode = OPEN_AUTH;
82 ar->auth_mode = NONE_AUTH;
83 ar->prwise_crypto = NONE_CRYPT;
84 ar->prwise_crypto_len = 0;
85 ar->grp_crypto = NONE_CRYPT;
Edward Lu38acde32011-08-30 21:58:06 +030086 ar->grp_crypto_len = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +030087 memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
88 memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
89 memset(ar->bssid, 0, sizeof(ar->bssid));
90 ar->bss_ch = 0;
91 ar->nw_type = ar->next_mode = INFRA_NETWORK;
92}
93
94static u8 ath6kl_get_fw_iftype(struct ath6kl *ar)
95{
96 switch (ar->nw_type) {
97 case INFRA_NETWORK:
98 return HI_OPTION_FW_MODE_BSS_STA;
99 case ADHOC_NETWORK:
100 return HI_OPTION_FW_MODE_IBSS;
101 case AP_NETWORK:
102 return HI_OPTION_FW_MODE_AP;
103 default:
104 ath6kl_err("Unsupported interface type :%d\n", ar->nw_type);
105 return 0xff;
106 }
107}
108
Kalle Valobdcd8172011-07-18 00:22:30 +0300109static int ath6kl_set_host_app_area(struct ath6kl *ar)
110{
111 u32 address, data;
112 struct host_app_area host_app_area;
113
114 /* Fetch the address of the host_app_area_s
115 * instance in the host interest area */
116 address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest));
Kevin Fang31024d92011-07-11 17:14:13 +0800117 address = TARG_VTOP(ar->target_type, address);
Kalle Valobdcd8172011-07-18 00:22:30 +0300118
Kalle Valoaddb44b2011-09-02 10:32:05 +0300119 if (ath6kl_diag_read32(ar, address, &data))
Kalle Valobdcd8172011-07-18 00:22:30 +0300120 return -EIO;
121
Kevin Fang31024d92011-07-11 17:14:13 +0800122 address = TARG_VTOP(ar->target_type, data);
Kalle Valocbf49a62011-10-05 12:23:17 +0300123 host_app_area.wmi_protocol_ver = cpu_to_le32(WMI_PROTOCOL_VERSION);
Kalle Valoaddb44b2011-09-02 10:32:05 +0300124 if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area,
125 sizeof(struct host_app_area)))
Kalle Valobdcd8172011-07-18 00:22:30 +0300126 return -EIO;
127
128 return 0;
129}
130
131static inline void set_ac2_ep_map(struct ath6kl *ar,
132 u8 ac,
133 enum htc_endpoint_id ep)
134{
135 ar->ac2ep_map[ac] = ep;
136 ar->ep2ac_map[ep] = ac;
137}
138
139/* connect to a service */
140static int ath6kl_connectservice(struct ath6kl *ar,
141 struct htc_service_connect_req *con_req,
142 char *desc)
143{
144 int status;
145 struct htc_service_connect_resp response;
146
147 memset(&response, 0, sizeof(response));
148
Kalle Vaload226ec2011-08-10 09:49:12 +0300149 status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response);
Kalle Valobdcd8172011-07-18 00:22:30 +0300150 if (status) {
151 ath6kl_err("failed to connect to %s service status:%d\n",
152 desc, status);
153 return status;
154 }
155
156 switch (con_req->svc_id) {
157 case WMI_CONTROL_SVC:
158 if (test_bit(WMI_ENABLED, &ar->flag))
159 ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint);
160 ar->ctrl_ep = response.endpoint;
161 break;
162 case WMI_DATA_BE_SVC:
163 set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint);
164 break;
165 case WMI_DATA_BK_SVC:
166 set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint);
167 break;
168 case WMI_DATA_VI_SVC:
169 set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint);
170 break;
171 case WMI_DATA_VO_SVC:
172 set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint);
173 break;
174 default:
175 ath6kl_err("service id is not mapped %d\n", con_req->svc_id);
176 return -EINVAL;
177 }
178
179 return 0;
180}
181
182static int ath6kl_init_service_ep(struct ath6kl *ar)
183{
184 struct htc_service_connect_req connect;
185
186 memset(&connect, 0, sizeof(connect));
187
188 /* these fields are the same for all service endpoints */
189 connect.ep_cb.rx = ath6kl_rx;
190 connect.ep_cb.rx_refill = ath6kl_rx_refill;
191 connect.ep_cb.tx_full = ath6kl_tx_queue_full;
192
193 /*
194 * Set the max queue depth so that our ath6kl_tx_queue_full handler
195 * gets called.
196 */
197 connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH;
198 connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4;
199 if (!connect.ep_cb.rx_refill_thresh)
200 connect.ep_cb.rx_refill_thresh++;
201
202 /* connect to control service */
203 connect.svc_id = WMI_CONTROL_SVC;
204 if (ath6kl_connectservice(ar, &connect, "WMI CONTROL"))
205 return -EIO;
206
207 connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN;
208
209 /*
210 * Limit the HTC message size on the send path, although e can
211 * receive A-MSDU frames of 4K, we will only send ethernet-sized
212 * (802.3) frames on the send path.
213 */
214 connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH;
215
216 /*
217 * To reduce the amount of committed memory for larger A_MSDU
218 * frames, use the recv-alloc threshold mechanism for larger
219 * packets.
220 */
221 connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE;
222 connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf;
223
224 /*
225 * For the remaining data services set the connection flag to
226 * reduce dribbling, if configured to do so.
227 */
228 connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB;
229 connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK;
230 connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF;
231
232 connect.svc_id = WMI_DATA_BE_SVC;
233
234 if (ath6kl_connectservice(ar, &connect, "WMI DATA BE"))
235 return -EIO;
236
237 /* connect to back-ground map this to WMI LOW_PRI */
238 connect.svc_id = WMI_DATA_BK_SVC;
239 if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
240 return -EIO;
241
242 /* connect to Video service, map this to to HI PRI */
243 connect.svc_id = WMI_DATA_VI_SVC;
244 if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
245 return -EIO;
246
247 /*
248 * Connect to VO service, this is currently not mapped to a WMI
249 * priority stream due to historical reasons. WMI originally
250 * defined 3 priorities over 3 mailboxes We can change this when
251 * WMI is reworked so that priorities are not dependent on
252 * mailboxes.
253 */
254 connect.svc_id = WMI_DATA_VO_SVC;
255 if (ath6kl_connectservice(ar, &connect, "WMI DATA VO"))
256 return -EIO;
257
258 return 0;
259}
260
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +0530261void ath6kl_init_control_info(struct ath6kl *ar)
Kalle Valobdcd8172011-07-18 00:22:30 +0300262{
Kalle Valobdcd8172011-07-18 00:22:30 +0300263 ath6kl_init_profile_info(ar);
264 ar->def_txkey_index = 0;
265 memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
266 ar->ch_hint = 0;
Kalle Valobdcd8172011-07-18 00:22:30 +0300267}
268
269/*
270 * Set HTC/Mbox operational parameters, this can only be called when the
271 * target is in the BMI phase.
272 */
273static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
274 u8 htc_ctrl_buf)
275{
276 int status;
277 u32 blk_size;
278
279 blk_size = ar->mbox_info.block_size;
280
281 if (htc_ctrl_buf)
282 blk_size |= ((u32)htc_ctrl_buf) << 16;
283
284 /* set the host interest area for the block size */
285 status = ath6kl_bmi_write(ar,
286 ath6kl_get_hi_item_addr(ar,
287 HI_ITEM(hi_mbox_io_block_sz)),
288 (u8 *)&blk_size,
289 4);
290 if (status) {
291 ath6kl_err("bmi_write_memory for IO block size failed\n");
292 goto out;
293 }
294
295 ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n",
296 blk_size,
297 ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz)));
298
299 if (mbox_isr_yield_val) {
300 /* set the host interest area for the mbox ISR yield limit */
301 status = ath6kl_bmi_write(ar,
302 ath6kl_get_hi_item_addr(ar,
303 HI_ITEM(hi_mbox_isr_yield_limit)),
304 (u8 *)&mbox_isr_yield_val,
305 4);
306 if (status) {
307 ath6kl_err("bmi_write_memory for yield limit failed\n");
308 goto out;
309 }
310 }
311
312out:
313 return status;
314}
315
316#define REG_DUMP_COUNT_AR6003 60
317#define REGISTER_DUMP_LEN_MAX 60
318
319static void ath6kl_dump_target_assert_info(struct ath6kl *ar)
320{
321 u32 address;
322 u32 regdump_loc = 0;
323 int status;
324 u32 regdump_val[REGISTER_DUMP_LEN_MAX];
325 u32 i;
326
327 if (ar->target_type != TARGET_TYPE_AR6003)
328 return;
329
330 /* the reg dump pointer is copied to the host interest area */
331 address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
Kevin Fang31024d92011-07-11 17:14:13 +0800332 address = TARG_VTOP(ar->target_type, address);
Kalle Valobdcd8172011-07-18 00:22:30 +0300333
334 /* read RAM location through diagnostic window */
Kalle Valoaddb44b2011-09-02 10:32:05 +0300335 status = ath6kl_diag_read32(ar, address, &regdump_loc);
Kalle Valobdcd8172011-07-18 00:22:30 +0300336
337 if (status || !regdump_loc) {
338 ath6kl_err("failed to get ptr to register dump area\n");
339 return;
340 }
341
342 ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n",
343 regdump_loc);
Kevin Fang31024d92011-07-11 17:14:13 +0800344 regdump_loc = TARG_VTOP(ar->target_type, regdump_loc);
Kalle Valobdcd8172011-07-18 00:22:30 +0300345
346 /* fetch register dump data */
Kalle Valoaddb44b2011-09-02 10:32:05 +0300347 status = ath6kl_diag_read(ar, regdump_loc, (u8 *)&regdump_val[0],
348 REG_DUMP_COUNT_AR6003 * (sizeof(u32)));
Kalle Valobdcd8172011-07-18 00:22:30 +0300349
350 if (status) {
351 ath6kl_err("failed to get register dump\n");
352 return;
353 }
354 ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n");
355
356 for (i = 0; i < REG_DUMP_COUNT_AR6003; i++)
357 ath6kl_dbg(ATH6KL_DBG_TRC, " %d : 0x%8.8X\n",
358 i, regdump_val[i]);
359
360}
361
362void ath6kl_target_failure(struct ath6kl *ar)
363{
364 ath6kl_err("target asserted\n");
365
366 /* try dumping target assertion information (if any) */
367 ath6kl_dump_target_assert_info(ar);
368
369}
370
371static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
372{
373 int status = 0;
Jouni Malinen4dea08e2011-08-30 21:57:57 +0300374 int ret;
Kalle Valobdcd8172011-07-18 00:22:30 +0300375
376 /*
377 * Configure the device for rx dot11 header rules. "0,0" are the
378 * default values. Required if checksum offload is needed. Set
379 * RxMetaVersion to 2.
380 */
381 if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
382 ar->rx_meta_ver, 0, 0)) {
383 ath6kl_err("unable to set the rx frame format\n");
384 status = -EIO;
385 }
386
387 if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN)
388 if ((ath6kl_wmi_pmparams_cmd(ar->wmi, 0, 1, 0, 0, 1,
389 IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) {
390 ath6kl_err("unable to set power save fail event policy\n");
391 status = -EIO;
392 }
393
394 if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER))
395 if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, 0,
396 WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) {
397 ath6kl_err("unable to set barker preamble policy\n");
398 status = -EIO;
399 }
400
401 if (ath6kl_wmi_set_keepalive_cmd(ar->wmi,
402 WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) {
403 ath6kl_err("unable to set keep alive interval\n");
404 status = -EIO;
405 }
406
407 if (ath6kl_wmi_disctimeout_cmd(ar->wmi,
408 WLAN_CONFIG_DISCONNECT_TIMEOUT)) {
409 ath6kl_err("unable to set disconnect timeout\n");
410 status = -EIO;
411 }
412
413 if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST))
414 if (ath6kl_wmi_set_wmm_txop(ar->wmi, WMI_TXOP_DISABLED)) {
415 ath6kl_err("unable to set txop bursting\n");
416 status = -EIO;
417 }
418
Jouni Malinen6bbc7c32011-09-05 17:38:47 +0300419 if (ar->p2p) {
420 ret = ath6kl_wmi_info_req_cmd(ar->wmi,
421 P2P_FLAG_CAPABILITIES_REQ |
422 P2P_FLAG_MACADDR_REQ |
423 P2P_FLAG_HMODEL_REQ);
424 if (ret) {
425 ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
426 "capabilities (%d) - assuming P2P not "
427 "supported\n", ret);
428 ar->p2p = 0;
429 }
430 }
431
432 if (ar->p2p) {
433 /* Enable Probe Request reporting for P2P */
434 ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true);
435 if (ret) {
436 ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe "
437 "Request reporting (%d)\n", ret);
438 }
Jouni Malinen4dea08e2011-08-30 21:57:57 +0300439 }
440
Kalle Valobdcd8172011-07-18 00:22:30 +0300441 return status;
442}
443
444int ath6kl_configure_target(struct ath6kl *ar)
445{
446 u32 param, ram_reserved_size;
447 u8 fw_iftype;
448
449 fw_iftype = ath6kl_get_fw_iftype(ar);
450 if (fw_iftype == 0xff)
451 return -EINVAL;
452
453 /* Tell target which HTC version it is used*/
454 param = HTC_PROTOCOL_VERSION;
455 if (ath6kl_bmi_write(ar,
456 ath6kl_get_hi_item_addr(ar,
457 HI_ITEM(hi_app_host_interest)),
458 (u8 *)&param, 4) != 0) {
459 ath6kl_err("bmi_write_memory for htc version failed\n");
460 return -EIO;
461 }
462
463 /* set the firmware mode to STA/IBSS/AP */
464 param = 0;
465
466 if (ath6kl_bmi_read(ar,
467 ath6kl_get_hi_item_addr(ar,
468 HI_ITEM(hi_option_flag)),
469 (u8 *)&param, 4) != 0) {
470 ath6kl_err("bmi_read_memory for setting fwmode failed\n");
471 return -EIO;
472 }
473
474 param |= (1 << HI_OPTION_NUM_DEV_SHIFT);
475 param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT);
Jouni Malinen6bbc7c32011-09-05 17:38:47 +0300476 if (ar->p2p && fw_iftype == HI_OPTION_FW_MODE_BSS_STA) {
477 param |= HI_OPTION_FW_SUBMODE_P2PDEV <<
478 HI_OPTION_FW_SUBMODE_SHIFT;
479 }
Kalle Valobdcd8172011-07-18 00:22:30 +0300480 param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
481 param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);
482
483 if (ath6kl_bmi_write(ar,
484 ath6kl_get_hi_item_addr(ar,
485 HI_ITEM(hi_option_flag)),
486 (u8 *)&param,
487 4) != 0) {
488 ath6kl_err("bmi_write_memory for setting fwmode failed\n");
489 return -EIO;
490 }
491
492 ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n");
493
494 /*
495 * Hardcode the address use for the extended board data
496 * Ideally this should be pre-allocate by the OS at boot time
497 * But since it is a new feature and board data is loaded
498 * at init time, we have to workaround this from host.
499 * It is difficult to patch the firmware boot code,
500 * but possible in theory.
501 */
502
Kalle Valo991b27e2011-09-07 10:55:17 +0300503 param = ar->hw.board_ext_data_addr;
504 ram_reserved_size = ar->hw.reserved_ram_size;
Kalle Valobdcd8172011-07-18 00:22:30 +0300505
Kalle Valo991b27e2011-09-07 10:55:17 +0300506 if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
507 HI_ITEM(hi_board_ext_data)),
508 (u8 *)&param, 4) != 0) {
509 ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
510 return -EIO;
511 }
512
513 if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
514 HI_ITEM(hi_end_ram_reserve_sz)),
515 (u8 *)&ram_reserved_size, 4) != 0) {
516 ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
517 return -EIO;
Kalle Valobdcd8172011-07-18 00:22:30 +0300518 }
519
520 /* set the block size for the target */
521 if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0))
522 /* use default number of control buffers */
523 return -EIO;
524
525 return 0;
526}
527
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +0530528void ath6kl_core_free(struct ath6kl *ar)
Kalle Valobdcd8172011-07-18 00:22:30 +0300529{
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +0530530 wiphy_free(ar->wiphy);
Kalle Valobdcd8172011-07-18 00:22:30 +0300531}
532
533int ath6kl_unavail_ev(struct ath6kl *ar)
534{
535 ath6kl_destroy(ar->net_dev, 1);
536
537 return 0;
538}
539
540/* firmware upload */
Kalle Valobdcd8172011-07-18 00:22:30 +0300541static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
542 u8 **fw, size_t *fw_len)
543{
544 const struct firmware *fw_entry;
545 int ret;
546
547 ret = request_firmware(&fw_entry, filename, ar->dev);
548 if (ret)
549 return ret;
550
551 *fw_len = fw_entry->size;
552 *fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
553
554 if (*fw == NULL)
555 ret = -ENOMEM;
556
557 release_firmware(fw_entry);
558
559 return ret;
560}
561
Sam Leffler92ecbff2011-09-07 10:55:16 +0300562#ifdef CONFIG_OF
563static const char *get_target_ver_dir(const struct ath6kl *ar)
564{
565 switch (ar->version.target_ver) {
566 case AR6003_REV1_VERSION:
567 return "ath6k/AR6003/hw1.0";
568 case AR6003_REV2_VERSION:
569 return "ath6k/AR6003/hw2.0";
570 case AR6003_REV3_VERSION:
571 return "ath6k/AR6003/hw2.1.1";
572 }
573 ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
574 ar->version.target_ver);
575 return NULL;
576}
577
578/*
579 * Check the device tree for a board-id and use it to construct
580 * the pathname to the firmware file. Used (for now) to find a
581 * fallback to the "bdata.bin" file--typically a symlink to the
582 * appropriate board-specific file.
583 */
584static bool check_device_tree(struct ath6kl *ar)
585{
586 static const char *board_id_prop = "atheros,board-id";
587 struct device_node *node;
588 char board_filename[64];
589 const char *board_id;
590 int ret;
591
592 for_each_compatible_node(node, NULL, "atheros,ath6kl") {
593 board_id = of_get_property(node, board_id_prop, NULL);
594 if (board_id == NULL) {
595 ath6kl_warn("No \"%s\" property on %s node.\n",
596 board_id_prop, node->name);
597 continue;
598 }
599 snprintf(board_filename, sizeof(board_filename),
600 "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id);
601
602 ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board,
603 &ar->fw_board_len);
604 if (ret) {
605 ath6kl_err("Failed to get DT board file %s: %d\n",
606 board_filename, ret);
607 continue;
608 }
609 return true;
610 }
611 return false;
612}
613#else
614static bool check_device_tree(struct ath6kl *ar)
615{
616 return false;
617}
618#endif /* CONFIG_OF */
619
Kalle Valobdcd8172011-07-18 00:22:30 +0300620static int ath6kl_fetch_board_file(struct ath6kl *ar)
621{
622 const char *filename;
623 int ret;
624
Kalle Valo772c31e2011-09-07 10:55:16 +0300625 if (ar->fw_board != NULL)
626 return 0;
627
Kalle Valobdcd8172011-07-18 00:22:30 +0300628 switch (ar->version.target_ver) {
629 case AR6003_REV2_VERSION:
630 filename = AR6003_REV2_BOARD_DATA_FILE;
631 break;
Kevin Fang31024d92011-07-11 17:14:13 +0800632 case AR6004_REV1_VERSION:
633 filename = AR6004_REV1_BOARD_DATA_FILE;
634 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300635 default:
636 filename = AR6003_REV3_BOARD_DATA_FILE;
637 break;
638 }
639
640 ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
641 &ar->fw_board_len);
642 if (ret == 0) {
643 /* managed to get proper board file */
644 return 0;
645 }
646
Sam Leffler92ecbff2011-09-07 10:55:16 +0300647 if (check_device_tree(ar)) {
648 /* got board file from device tree */
649 return 0;
650 }
651
Kalle Valobdcd8172011-07-18 00:22:30 +0300652 /* there was no proper board file, try to use default instead */
653 ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
654 filename, ret);
655
656 switch (ar->version.target_ver) {
657 case AR6003_REV2_VERSION:
658 filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
659 break;
Kevin Fang31024d92011-07-11 17:14:13 +0800660 case AR6004_REV1_VERSION:
661 filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE;
662 break;
Kalle Valobdcd8172011-07-18 00:22:30 +0300663 default:
664 filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
665 break;
666 }
667
668 ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
669 &ar->fw_board_len);
670 if (ret) {
671 ath6kl_err("Failed to get default board file %s: %d\n",
672 filename, ret);
673 return ret;
674 }
675
676 ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n");
677 ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n");
678
679 return 0;
680}
681
Kalle Valo772c31e2011-09-07 10:55:16 +0300682static int ath6kl_fetch_otp_file(struct ath6kl *ar)
683{
684 const char *filename;
685 int ret;
686
687 if (ar->fw_otp != NULL)
688 return 0;
689
690 switch (ar->version.target_ver) {
691 case AR6003_REV2_VERSION:
692 filename = AR6003_REV2_OTP_FILE;
693 break;
694 case AR6004_REV1_VERSION:
695 ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n");
696 return 0;
697 break;
698 default:
699 filename = AR6003_REV3_OTP_FILE;
700 break;
701 }
702
703 ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
704 &ar->fw_otp_len);
705 if (ret) {
706 ath6kl_err("Failed to get OTP file %s: %d\n",
707 filename, ret);
708 return ret;
709 }
710
711 return 0;
712}
713
714static int ath6kl_fetch_fw_file(struct ath6kl *ar)
715{
716 const char *filename;
717 int ret;
718
719 if (ar->fw != NULL)
720 return 0;
721
722 if (testmode) {
723 switch (ar->version.target_ver) {
724 case AR6003_REV2_VERSION:
725 filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
726 break;
727 case AR6003_REV3_VERSION:
728 filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
729 break;
730 case AR6004_REV1_VERSION:
731 ath6kl_warn("testmode not supported with ar6004\n");
732 return -EOPNOTSUPP;
733 default:
734 ath6kl_warn("unknown target version: 0x%x\n",
735 ar->version.target_ver);
736 return -EINVAL;
737 }
738
739 set_bit(TESTMODE, &ar->flag);
740
741 goto get_fw;
742 }
743
744 switch (ar->version.target_ver) {
745 case AR6003_REV2_VERSION:
746 filename = AR6003_REV2_FIRMWARE_FILE;
747 break;
748 case AR6004_REV1_VERSION:
749 filename = AR6004_REV1_FIRMWARE_FILE;
750 break;
751 default:
752 filename = AR6003_REV3_FIRMWARE_FILE;
753 break;
754 }
755
756get_fw:
757 ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
758 if (ret) {
759 ath6kl_err("Failed to get firmware file %s: %d\n",
760 filename, ret);
761 return ret;
762 }
763
764 return 0;
765}
766
767static int ath6kl_fetch_patch_file(struct ath6kl *ar)
768{
769 const char *filename;
770 int ret;
771
772 switch (ar->version.target_ver) {
773 case AR6003_REV2_VERSION:
774 filename = AR6003_REV2_PATCH_FILE;
775 break;
776 case AR6004_REV1_VERSION:
777 /* FIXME: implement for AR6004 */
778 return 0;
779 break;
780 default:
781 filename = AR6003_REV3_PATCH_FILE;
782 break;
783 }
784
785 if (ar->fw_patch == NULL) {
786 ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
787 &ar->fw_patch_len);
788 if (ret) {
789 ath6kl_err("Failed to get patch file %s: %d\n",
790 filename, ret);
791 return ret;
792 }
793 }
794
795 return 0;
796}
797
Kalle Valo50d41232011-09-07 10:55:17 +0300798static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
Kalle Valo772c31e2011-09-07 10:55:16 +0300799{
800 int ret;
801
Kalle Valo772c31e2011-09-07 10:55:16 +0300802 ret = ath6kl_fetch_otp_file(ar);
803 if (ret)
804 return ret;
805
806 ret = ath6kl_fetch_fw_file(ar);
807 if (ret)
808 return ret;
809
810 ret = ath6kl_fetch_patch_file(ar);
811 if (ret)
812 return ret;
813
814 return 0;
815}
Kalle Valobdcd8172011-07-18 00:22:30 +0300816
Kalle Valo50d41232011-09-07 10:55:17 +0300817static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
818{
819 size_t magic_len, len, ie_len;
820 const struct firmware *fw;
821 struct ath6kl_fw_ie *hdr;
822 const char *filename;
823 const u8 *data;
Kalle Valo97e04962011-09-12 13:47:34 +0300824 int ret, ie_id, i, index, bit;
Kalle Valo8a137482011-09-07 10:55:17 +0300825 __le32 *val;
Kalle Valo50d41232011-09-07 10:55:17 +0300826
827 switch (ar->version.target_ver) {
828 case AR6003_REV2_VERSION:
829 filename = AR6003_REV2_FIRMWARE_2_FILE;
830 break;
831 case AR6003_REV3_VERSION:
832 filename = AR6003_REV3_FIRMWARE_2_FILE;
833 break;
834 case AR6004_REV1_VERSION:
835 filename = AR6004_REV1_FIRMWARE_2_FILE;
836 break;
837 default:
838 return -EOPNOTSUPP;
839 }
840
841 ret = request_firmware(&fw, filename, ar->dev);
842 if (ret)
843 return ret;
844
845 data = fw->data;
846 len = fw->size;
847
848 /* magic also includes the null byte, check that as well */
849 magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;
850
851 if (len < magic_len) {
852 ret = -EINVAL;
853 goto out;
854 }
855
856 if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {
857 ret = -EINVAL;
858 goto out;
859 }
860
861 len -= magic_len;
862 data += magic_len;
863
864 /* loop elements */
865 while (len > sizeof(struct ath6kl_fw_ie)) {
866 /* hdr is unaligned! */
867 hdr = (struct ath6kl_fw_ie *) data;
868
869 ie_id = le32_to_cpup(&hdr->id);
870 ie_len = le32_to_cpup(&hdr->len);
871
872 len -= sizeof(*hdr);
873 data += sizeof(*hdr);
874
875 if (len < ie_len) {
876 ret = -EINVAL;
877 goto out;
878 }
879
880 switch (ie_id) {
881 case ATH6KL_FW_IE_OTP_IMAGE:
Kalle Valoef548622011-10-01 09:43:09 +0300882 ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
Kalle Valo6bc36432011-09-27 14:31:11 +0300883 ie_len);
884
Kalle Valo50d41232011-09-07 10:55:17 +0300885 ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
886
887 if (ar->fw_otp == NULL) {
888 ret = -ENOMEM;
889 goto out;
890 }
891
892 ar->fw_otp_len = ie_len;
893 break;
894 case ATH6KL_FW_IE_FW_IMAGE:
Kalle Valoef548622011-10-01 09:43:09 +0300895 ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n",
Kalle Valo6bc36432011-09-27 14:31:11 +0300896 ie_len);
897
Kalle Valo50d41232011-09-07 10:55:17 +0300898 ar->fw = kmemdup(data, ie_len, GFP_KERNEL);
899
900 if (ar->fw == NULL) {
901 ret = -ENOMEM;
902 goto out;
903 }
904
905 ar->fw_len = ie_len;
906 break;
907 case ATH6KL_FW_IE_PATCH_IMAGE:
Kalle Valoef548622011-10-01 09:43:09 +0300908 ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n",
Kalle Valo6bc36432011-09-27 14:31:11 +0300909 ie_len);
910
Kalle Valo50d41232011-09-07 10:55:17 +0300911 ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
912
913 if (ar->fw_patch == NULL) {
914 ret = -ENOMEM;
915 goto out;
916 }
917
918 ar->fw_patch_len = ie_len;
919 break;
Kalle Valo8a137482011-09-07 10:55:17 +0300920 case ATH6KL_FW_IE_RESERVED_RAM_SIZE:
921 val = (__le32 *) data;
922 ar->hw.reserved_ram_size = le32_to_cpup(val);
Kalle Valo6bc36432011-09-27 14:31:11 +0300923
924 ath6kl_dbg(ATH6KL_DBG_BOOT,
925 "found reserved ram size ie 0x%d\n",
926 ar->hw.reserved_ram_size);
Kalle Valo8a137482011-09-07 10:55:17 +0300927 break;
Kalle Valo97e04962011-09-12 13:47:34 +0300928 case ATH6KL_FW_IE_CAPABILITIES:
Kalle Valo6bc36432011-09-27 14:31:11 +0300929 ath6kl_dbg(ATH6KL_DBG_BOOT,
Kalle Valoef548622011-10-01 09:43:09 +0300930 "found firmware capabilities ie (%zd B)\n",
Kalle Valo6bc36432011-09-27 14:31:11 +0300931 ie_len);
932
Kalle Valo97e04962011-09-12 13:47:34 +0300933 for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
934 index = ALIGN(i, 8) / 8;
935 bit = i % 8;
936
937 if (data[index] & (1 << bit))
938 __set_bit(i, ar->fw_capabilities);
939 }
Kalle Valo6bc36432011-09-27 14:31:11 +0300940
941 ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "",
942 ar->fw_capabilities,
943 sizeof(ar->fw_capabilities));
Kalle Valo97e04962011-09-12 13:47:34 +0300944 break;
Kalle Valo1b4304d2011-09-27 11:05:26 +0300945 case ATH6KL_FW_IE_PATCH_ADDR:
946 if (ie_len != sizeof(*val))
947 break;
948
949 val = (__le32 *) data;
950 ar->hw.dataset_patch_addr = le32_to_cpup(val);
Kalle Valo6bc36432011-09-27 14:31:11 +0300951
952 ath6kl_dbg(ATH6KL_DBG_BOOT,
953 "found patch address ie 0x%d\n",
954 ar->hw.dataset_patch_addr);
Kalle Valo1b4304d2011-09-27 11:05:26 +0300955 break;
Kalle Valo50d41232011-09-07 10:55:17 +0300956 default:
Kalle Valo6bc36432011-09-27 14:31:11 +0300957 ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
Kalle Valo50d41232011-09-07 10:55:17 +0300958 le32_to_cpup(&hdr->id));
959 break;
960 }
961
962 len -= ie_len;
963 data += ie_len;
964 };
965
966 ret = 0;
967out:
968 release_firmware(fw);
969
970 return ret;
971}
972
973static int ath6kl_fetch_firmwares(struct ath6kl *ar)
974{
975 int ret;
976
977 ret = ath6kl_fetch_board_file(ar);
978 if (ret)
979 return ret;
980
981 ret = ath6kl_fetch_fw_api2(ar);
Kalle Valo6bc36432011-09-27 14:31:11 +0300982 if (ret == 0) {
983 ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n");
Kalle Valo50d41232011-09-07 10:55:17 +0300984 return 0;
Kalle Valo6bc36432011-09-27 14:31:11 +0300985 }
Kalle Valo50d41232011-09-07 10:55:17 +0300986
987 ret = ath6kl_fetch_fw_api1(ar);
988 if (ret)
989 return ret;
990
Kalle Valo6bc36432011-09-27 14:31:11 +0300991 ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n");
992
Kalle Valo50d41232011-09-07 10:55:17 +0300993 return 0;
994}
995
Kalle Valobdcd8172011-07-18 00:22:30 +0300996static int ath6kl_upload_board_file(struct ath6kl *ar)
997{
998 u32 board_address, board_ext_address, param;
Kevin Fang31024d92011-07-11 17:14:13 +0800999 u32 board_data_size, board_ext_data_size;
Kalle Valobdcd8172011-07-18 00:22:30 +03001000 int ret;
1001
Kalle Valo772c31e2011-09-07 10:55:16 +03001002 if (WARN_ON(ar->fw_board == NULL))
1003 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001004
Kevin Fang31024d92011-07-11 17:14:13 +08001005 /*
1006 * Determine where in Target RAM to write Board Data.
1007 * For AR6004, host determine Target RAM address for
1008 * writing board data.
1009 */
1010 if (ar->target_type == TARGET_TYPE_AR6004) {
1011 board_address = AR6004_REV1_BOARD_DATA_ADDRESS;
1012 ath6kl_bmi_write(ar,
1013 ath6kl_get_hi_item_addr(ar,
1014 HI_ITEM(hi_board_data)),
1015 (u8 *) &board_address, 4);
1016 } else {
1017 ath6kl_bmi_read(ar,
1018 ath6kl_get_hi_item_addr(ar,
1019 HI_ITEM(hi_board_data)),
1020 (u8 *) &board_address, 4);
1021 }
1022
Kalle Valobdcd8172011-07-18 00:22:30 +03001023 /* determine where in target ram to write extended board data */
1024 ath6kl_bmi_read(ar,
1025 ath6kl_get_hi_item_addr(ar,
1026 HI_ITEM(hi_board_ext_data)),
1027 (u8 *) &board_ext_address, 4);
1028
Kalle Valobdcd8172011-07-18 00:22:30 +03001029 if (board_ext_address == 0) {
1030 ath6kl_err("Failed to get board file target address.\n");
1031 return -EINVAL;
1032 }
1033
Kevin Fang31024d92011-07-11 17:14:13 +08001034 switch (ar->target_type) {
1035 case TARGET_TYPE_AR6003:
1036 board_data_size = AR6003_BOARD_DATA_SZ;
1037 board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ;
1038 break;
1039 case TARGET_TYPE_AR6004:
1040 board_data_size = AR6004_BOARD_DATA_SZ;
1041 board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ;
1042 break;
1043 default:
1044 WARN_ON(1);
1045 return -EINVAL;
1046 break;
1047 }
1048
1049 if (ar->fw_board_len == (board_data_size +
1050 board_ext_data_size)) {
1051
Kalle Valobdcd8172011-07-18 00:22:30 +03001052 /* write extended board data */
Kalle Valo6bc36432011-09-27 14:31:11 +03001053 ath6kl_dbg(ATH6KL_DBG_BOOT,
1054 "writing extended board data to 0x%x (%d B)\n",
1055 board_ext_address, board_ext_data_size);
1056
Kalle Valobdcd8172011-07-18 00:22:30 +03001057 ret = ath6kl_bmi_write(ar, board_ext_address,
Kevin Fang31024d92011-07-11 17:14:13 +08001058 ar->fw_board + board_data_size,
1059 board_ext_data_size);
Kalle Valobdcd8172011-07-18 00:22:30 +03001060 if (ret) {
1061 ath6kl_err("Failed to write extended board data: %d\n",
1062 ret);
1063 return ret;
1064 }
1065
1066 /* record that extended board data is initialized */
Kevin Fang31024d92011-07-11 17:14:13 +08001067 param = (board_ext_data_size << 16) | 1;
1068
Kalle Valobdcd8172011-07-18 00:22:30 +03001069 ath6kl_bmi_write(ar,
1070 ath6kl_get_hi_item_addr(ar,
1071 HI_ITEM(hi_board_ext_data_config)),
1072 (unsigned char *) &param, 4);
1073 }
1074
Kevin Fang31024d92011-07-11 17:14:13 +08001075 if (ar->fw_board_len < board_data_size) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001076 ath6kl_err("Too small board file: %zu\n", ar->fw_board_len);
1077 ret = -EINVAL;
1078 return ret;
1079 }
1080
Kalle Valo6bc36432011-09-27 14:31:11 +03001081 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n",
1082 board_address, board_data_size);
1083
Kalle Valobdcd8172011-07-18 00:22:30 +03001084 ret = ath6kl_bmi_write(ar, board_address, ar->fw_board,
Kevin Fang31024d92011-07-11 17:14:13 +08001085 board_data_size);
Kalle Valobdcd8172011-07-18 00:22:30 +03001086
1087 if (ret) {
1088 ath6kl_err("Board file bmi write failed: %d\n", ret);
1089 return ret;
1090 }
1091
1092 /* record the fact that Board Data IS initialized */
1093 param = 1;
1094 ath6kl_bmi_write(ar,
1095 ath6kl_get_hi_item_addr(ar,
1096 HI_ITEM(hi_board_data_initialized)),
1097 (u8 *)&param, 4);
1098
1099 return ret;
1100}
1101
1102static int ath6kl_upload_otp(struct ath6kl *ar)
1103{
Kalle Valobdcd8172011-07-18 00:22:30 +03001104 u32 address, param;
Kalle Valobef26a72011-10-12 09:58:28 +03001105 bool from_hw = false;
Kalle Valobdcd8172011-07-18 00:22:30 +03001106 int ret;
1107
Kalle Valo772c31e2011-09-07 10:55:16 +03001108 if (WARN_ON(ar->fw_otp == NULL))
1109 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001110
Kalle Valoa01ac412011-09-07 10:55:17 +03001111 address = ar->hw.app_load_addr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001112
Kalle Valoef548622011-10-01 09:43:09 +03001113 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%zd B)\n", address,
Kalle Valo6bc36432011-09-27 14:31:11 +03001114 ar->fw_otp_len);
1115
Kalle Valobdcd8172011-07-18 00:22:30 +03001116 ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp,
1117 ar->fw_otp_len);
1118 if (ret) {
1119 ath6kl_err("Failed to upload OTP file: %d\n", ret);
1120 return ret;
1121 }
1122
Kalle Valo639d0b82011-09-12 12:48:09 +03001123 /* read firmware start address */
1124 ret = ath6kl_bmi_read(ar,
1125 ath6kl_get_hi_item_addr(ar,
1126 HI_ITEM(hi_app_start)),
1127 (u8 *) &address, sizeof(address));
1128
1129 if (ret) {
1130 ath6kl_err("Failed to read hi_app_start: %d\n", ret);
1131 return ret;
1132 }
1133
Kalle Valobef26a72011-10-12 09:58:28 +03001134 if (ar->hw.app_start_override_addr == 0) {
1135 ar->hw.app_start_override_addr = address;
1136 from_hw = true;
1137 }
Kalle Valo639d0b82011-09-12 12:48:09 +03001138
Kalle Valobef26a72011-10-12 09:58:28 +03001139 ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr%s 0x%x\n",
1140 from_hw ? " (from hw)" : "",
Kalle Valo6bc36432011-09-27 14:31:11 +03001141 ar->hw.app_start_override_addr);
1142
Kalle Valobdcd8172011-07-18 00:22:30 +03001143 /* execute the OTP code */
Kalle Valobef26a72011-10-12 09:58:28 +03001144 ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n",
1145 ar->hw.app_start_override_addr);
Kalle Valobdcd8172011-07-18 00:22:30 +03001146 param = 0;
Kalle Valobef26a72011-10-12 09:58:28 +03001147 ath6kl_bmi_execute(ar, ar->hw.app_start_override_addr, &param);
Kalle Valobdcd8172011-07-18 00:22:30 +03001148
1149 return ret;
1150}
1151
1152static int ath6kl_upload_firmware(struct ath6kl *ar)
1153{
Kalle Valobdcd8172011-07-18 00:22:30 +03001154 u32 address;
1155 int ret;
1156
Kalle Valo772c31e2011-09-07 10:55:16 +03001157 if (WARN_ON(ar->fw == NULL))
1158 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001159
Kalle Valoa01ac412011-09-07 10:55:17 +03001160 address = ar->hw.app_load_addr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001161
Kalle Valoef548622011-10-01 09:43:09 +03001162 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%zd B)\n",
Kalle Valo6bc36432011-09-27 14:31:11 +03001163 address, ar->fw_len);
1164
Kalle Valobdcd8172011-07-18 00:22:30 +03001165 ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len);
1166
1167 if (ret) {
1168 ath6kl_err("Failed to write firmware: %d\n", ret);
1169 return ret;
1170 }
1171
Kevin Fang31024d92011-07-11 17:14:13 +08001172 /*
1173 * Set starting address for firmware
1174 * Don't need to setup app_start override addr on AR6004
1175 */
1176 if (ar->target_type != TARGET_TYPE_AR6004) {
Kalle Valoa01ac412011-09-07 10:55:17 +03001177 address = ar->hw.app_start_override_addr;
Kevin Fang31024d92011-07-11 17:14:13 +08001178 ath6kl_bmi_set_app_start(ar, address);
1179 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001180 return ret;
1181}
1182
1183static int ath6kl_upload_patch(struct ath6kl *ar)
1184{
Kalle Valobdcd8172011-07-18 00:22:30 +03001185 u32 address, param;
1186 int ret;
1187
Kalle Valo772c31e2011-09-07 10:55:16 +03001188 if (WARN_ON(ar->fw_patch == NULL))
1189 return -ENOENT;
Kalle Valobdcd8172011-07-18 00:22:30 +03001190
Kalle Valoa01ac412011-09-07 10:55:17 +03001191 address = ar->hw.dataset_patch_addr;
Kalle Valobdcd8172011-07-18 00:22:30 +03001192
Kalle Valoef548622011-10-01 09:43:09 +03001193 ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%zd B)\n",
Kalle Valo6bc36432011-09-27 14:31:11 +03001194 address, ar->fw_patch_len);
1195
Kalle Valobdcd8172011-07-18 00:22:30 +03001196 ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len);
1197 if (ret) {
1198 ath6kl_err("Failed to write patch file: %d\n", ret);
1199 return ret;
1200 }
1201
1202 param = address;
1203 ath6kl_bmi_write(ar,
1204 ath6kl_get_hi_item_addr(ar,
1205 HI_ITEM(hi_dset_list_head)),
1206 (unsigned char *) &param, 4);
1207
1208 return 0;
1209}
1210
1211static int ath6kl_init_upload(struct ath6kl *ar)
1212{
1213 u32 param, options, sleep, address;
1214 int status = 0;
1215
Kevin Fang31024d92011-07-11 17:14:13 +08001216 if (ar->target_type != TARGET_TYPE_AR6003 &&
1217 ar->target_type != TARGET_TYPE_AR6004)
Kalle Valobdcd8172011-07-18 00:22:30 +03001218 return -EINVAL;
1219
1220 /* temporarily disable system sleep */
1221 address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
1222 status = ath6kl_bmi_reg_read(ar, address, &param);
1223 if (status)
1224 return status;
1225
1226 options = param;
1227
1228 param |= ATH6KL_OPTION_SLEEP_DISABLE;
1229 status = ath6kl_bmi_reg_write(ar, address, param);
1230 if (status)
1231 return status;
1232
1233 address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
1234 status = ath6kl_bmi_reg_read(ar, address, &param);
1235 if (status)
1236 return status;
1237
1238 sleep = param;
1239
1240 param |= SM(SYSTEM_SLEEP_DISABLE, 1);
1241 status = ath6kl_bmi_reg_write(ar, address, param);
1242 if (status)
1243 return status;
1244
1245 ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n",
1246 options, sleep);
1247
1248 /* program analog PLL register */
Kevin Fang31024d92011-07-11 17:14:13 +08001249 /* no need to control 40/44MHz clock on AR6004 */
1250 if (ar->target_type != TARGET_TYPE_AR6004) {
1251 status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER,
1252 0xF9104001);
Kalle Valobdcd8172011-07-18 00:22:30 +03001253
Kevin Fang31024d92011-07-11 17:14:13 +08001254 if (status)
1255 return status;
Kalle Valobdcd8172011-07-18 00:22:30 +03001256
Kevin Fang31024d92011-07-11 17:14:13 +08001257 /* Run at 80/88MHz by default */
1258 param = SM(CPU_CLOCK_STANDARD, 1);
1259
1260 address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;
1261 status = ath6kl_bmi_reg_write(ar, address, param);
1262 if (status)
1263 return status;
1264 }
Kalle Valobdcd8172011-07-18 00:22:30 +03001265
1266 param = 0;
1267 address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;
1268 param = SM(LPO_CAL_ENABLE, 1);
1269 status = ath6kl_bmi_reg_write(ar, address, param);
1270 if (status)
1271 return status;
1272
1273 /* WAR to avoid SDIO CRC err */
1274 if (ar->version.target_ver == AR6003_REV2_VERSION) {
1275 ath6kl_err("temporary war to avoid sdio crc error\n");
1276
1277 param = 0x20;
1278
1279 address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
1280 status = ath6kl_bmi_reg_write(ar, address, param);
1281 if (status)
1282 return status;
1283
1284 address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;
1285 status = ath6kl_bmi_reg_write(ar, address, param);
1286 if (status)
1287 return status;
1288
1289 address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;
1290 status = ath6kl_bmi_reg_write(ar, address, param);
1291 if (status)
1292 return status;
1293
1294 address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;
1295 status = ath6kl_bmi_reg_write(ar, address, param);
1296 if (status)
1297 return status;
1298 }
1299
1300 /* write EEPROM data to Target RAM */
1301 status = ath6kl_upload_board_file(ar);
1302 if (status)
1303 return status;
1304
1305 /* transfer One time Programmable data */
1306 status = ath6kl_upload_otp(ar);
1307 if (status)
1308 return status;
1309
1310 /* Download Target firmware */
1311 status = ath6kl_upload_firmware(ar);
1312 if (status)
1313 return status;
1314
1315 status = ath6kl_upload_patch(ar);
1316 if (status)
1317 return status;
1318
1319 /* Restore system sleep */
1320 address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
1321 status = ath6kl_bmi_reg_write(ar, address, sleep);
1322 if (status)
1323 return status;
1324
1325 address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
1326 param = options | 0x20;
1327 status = ath6kl_bmi_reg_write(ar, address, param);
1328 if (status)
1329 return status;
1330
1331 /* Configure GPIO AR6003 UART */
1332 param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
1333 status = ath6kl_bmi_write(ar,
1334 ath6kl_get_hi_item_addr(ar,
1335 HI_ITEM(hi_dbg_uart_txpin)),
1336 (u8 *)&param, 4);
1337
1338 return status;
1339}
1340
Kalle Valoa01ac412011-09-07 10:55:17 +03001341static int ath6kl_init_hw_params(struct ath6kl *ar)
1342{
1343 switch (ar->version.target_ver) {
1344 case AR6003_REV2_VERSION:
1345 ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
1346 ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS;
Kalle Valo991b27e2011-09-07 10:55:17 +03001347 ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
1348 ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE;
Kalle Valobef26a72011-10-12 09:58:28 +03001349
1350 /* hw2.0 needs override address hardcoded */
1351 ar->hw.app_start_override_addr = 0x944C00;
1352
Kalle Valoa01ac412011-09-07 10:55:17 +03001353 break;
1354 case AR6003_REV3_VERSION:
1355 ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS;
1356 ar->hw.app_load_addr = 0x1234;
Kalle Valo991b27e2011-09-07 10:55:17 +03001357 ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
1358 ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE;
Kalle Valoa01ac412011-09-07 10:55:17 +03001359 break;
1360 case AR6004_REV1_VERSION:
1361 ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
1362 ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS;
Kalle Valo991b27e2011-09-07 10:55:17 +03001363 ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS;
1364 ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE;
Kalle Valoa01ac412011-09-07 10:55:17 +03001365 break;
1366 default:
1367 ath6kl_err("Unsupported hardware version: 0x%x\n",
1368 ar->version.target_ver);
1369 return -EINVAL;
1370 }
1371
Kalle Valo6bc36432011-09-27 14:31:11 +03001372 ath6kl_dbg(ATH6KL_DBG_BOOT,
1373 "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
1374 ar->version.target_ver, ar->target_type,
1375 ar->hw.dataset_patch_addr, ar->hw.app_load_addr);
1376 ath6kl_dbg(ATH6KL_DBG_BOOT,
1377 "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
1378 ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
1379 ar->hw.reserved_ram_size);
1380
Kalle Valoa01ac412011-09-07 10:55:17 +03001381 return 0;
1382}
1383
Vasanthakumar Thiagarajan521dffc2011-10-25 19:33:56 +05301384static int ath6kl_init(struct ath6kl *ar)
Kalle Valobdcd8172011-07-18 00:22:30 +03001385{
Kalle Valobdcd8172011-07-18 00:22:30 +03001386 int status = 0;
1387 s32 timeleft;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301388 struct net_device *ndev;
Kalle Valobdcd8172011-07-18 00:22:30 +03001389
1390 if (!ar)
1391 return -EIO;
1392
1393 /* Do we need to finish the BMI phase */
1394 if (ath6kl_bmi_done(ar)) {
1395 status = -EIO;
1396 goto ath6kl_init_done;
1397 }
1398
1399 /* Indicate that WMI is enabled (although not ready yet) */
1400 set_bit(WMI_ENABLED, &ar->flag);
Vasanthakumar Thiagarajan28657852011-07-21 12:00:49 +05301401 ar->wmi = ath6kl_wmi_init(ar);
Kalle Valobdcd8172011-07-18 00:22:30 +03001402 if (!ar->wmi) {
1403 ath6kl_err("failed to initialize wmi\n");
1404 status = -EIO;
1405 goto ath6kl_init_done;
1406 }
1407
1408 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
1409
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301410 status = ath6kl_register_ieee80211_hw(ar);
1411 if (status)
1412 goto err_node_cleanup;
1413
1414 status = ath6kl_debug_init(ar);
1415 if (status) {
1416 wiphy_unregister(ar->wiphy);
1417 goto err_node_cleanup;
1418 }
1419
1420 /* Add an initial station interface */
1421 ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION);
1422 if (!ndev) {
1423 ath6kl_err("Failed to instantiate a network device\n");
1424 status = -ENOMEM;
1425 wiphy_unregister(ar->wiphy);
1426 goto err_debug_init;
1427 }
1428
1429
1430 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
1431 __func__, ar->net_dev->name, ar->net_dev, ar);
1432
Kalle Valobdcd8172011-07-18 00:22:30 +03001433 /*
1434 * The reason we have to wait for the target here is that the
1435 * driver layer has to init BMI in order to set the host block
1436 * size.
1437 */
Kalle Vaload226ec2011-08-10 09:49:12 +03001438 if (ath6kl_htc_wait_target(ar->htc_target)) {
Kalle Valobdcd8172011-07-18 00:22:30 +03001439 status = -EIO;
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301440 goto err_if_deinit;
Kalle Valobdcd8172011-07-18 00:22:30 +03001441 }
1442
1443 if (ath6kl_init_service_ep(ar)) {
1444 status = -EIO;
1445 goto err_cleanup_scatter;
1446 }
1447
1448 /* setup access class priority mappings */
1449 ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */
1450 ar->ac_stream_pri_map[WMM_AC_BE] = 1;
1451 ar->ac_stream_pri_map[WMM_AC_VI] = 2;
1452 ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
1453
1454 /* give our connected endpoints some buffers */
1455 ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
1456 ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
1457
1458 /* allocate some buffers that handle larger AMSDU frames */
1459 ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
1460
1461 /* setup credit distribution */
1462 ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info);
1463
1464 ath6kl_cookie_init(ar);
1465
1466 /* start HTC */
Kalle Vaload226ec2011-08-10 09:49:12 +03001467 status = ath6kl_htc_start(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001468
1469 if (status) {
1470 ath6kl_cookie_cleanup(ar);
1471 goto err_rxbuf_cleanup;
1472 }
1473
1474 /* Wait for Wmi event to be ready */
1475 timeleft = wait_event_interruptible_timeout(ar->event_wq,
1476 test_bit(WMI_READY,
1477 &ar->flag),
1478 WMI_TIMEOUT);
1479
Kalle Valo6bc36432011-09-27 14:31:11 +03001480 ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");
1481
Kalle Valobdcd8172011-07-18 00:22:30 +03001482 if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
1483 ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
1484 ATH6KL_ABI_VERSION, ar->version.abi_ver);
1485 status = -EIO;
1486 goto err_htc_stop;
1487 }
1488
1489 if (!timeleft || signal_pending(current)) {
1490 ath6kl_err("wmi is not ready or wait was interrupted\n");
1491 status = -EIO;
1492 goto err_htc_stop;
1493 }
1494
1495 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__);
1496
1497 /* communicate the wmi protocol verision to the target */
1498 if ((ath6kl_set_host_app_area(ar)) != 0)
1499 ath6kl_err("unable to set the host app area\n");
1500
1501 ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
1502 ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
1503
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301504 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
1505 WIPHY_FLAG_HAVE_AP_SME;
Vivek Natarajan011a36e2011-09-19 13:29:16 +05301506
Kalle Valobdcd8172011-07-18 00:22:30 +03001507 status = ath6kl_target_config_wlan_params(ar);
1508 if (!status)
1509 goto ath6kl_init_done;
1510
1511err_htc_stop:
Kalle Vaload226ec2011-08-10 09:49:12 +03001512 ath6kl_htc_stop(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001513err_rxbuf_cleanup:
Kalle Vaload226ec2011-08-10 09:49:12 +03001514 ath6kl_htc_flush_rx_buf(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001515 ath6kl_cleanup_amsdu_rxbufs(ar);
1516err_cleanup_scatter:
1517 ath6kl_hif_cleanup_scatter(ar);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301518err_if_deinit:
1519 ath6kl_deinit_if_data(ar, ndev);
1520 wiphy_unregister(ar->wiphy);
1521err_debug_init:
1522 ath6kl_debug_cleanup(ar);
Vasanthakumar Thiagarajan852bd9d2011-07-21 14:24:54 +05301523err_node_cleanup:
Kalle Valobdcd8172011-07-18 00:22:30 +03001524 ath6kl_wmi_shutdown(ar->wmi);
1525 clear_bit(WMI_ENABLED, &ar->flag);
1526 ar->wmi = NULL;
1527
1528ath6kl_init_done:
1529 return status;
1530}
1531
1532int ath6kl_core_init(struct ath6kl *ar)
1533{
1534 int ret = 0;
1535 struct ath6kl_bmi_target_info targ_info;
1536
1537 ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
1538 if (!ar->ath6kl_wq)
1539 return -ENOMEM;
1540
1541 ret = ath6kl_bmi_init(ar);
1542 if (ret)
1543 goto err_wq;
1544
1545 ret = ath6kl_bmi_get_target_info(ar, &targ_info);
1546 if (ret)
1547 goto err_bmi_cleanup;
1548
1549 ar->version.target_ver = le32_to_cpu(targ_info.version);
1550 ar->target_type = le32_to_cpu(targ_info.type);
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301551 ar->wiphy->hw_version = le32_to_cpu(targ_info.version);
Kalle Valobdcd8172011-07-18 00:22:30 +03001552
Kalle Valoa01ac412011-09-07 10:55:17 +03001553 ret = ath6kl_init_hw_params(ar);
1554 if (ret)
1555 goto err_bmi_cleanup;
1556
Kalle Valobdcd8172011-07-18 00:22:30 +03001557 ret = ath6kl_configure_target(ar);
1558 if (ret)
1559 goto err_bmi_cleanup;
1560
Kalle Vaload226ec2011-08-10 09:49:12 +03001561 ar->htc_target = ath6kl_htc_create(ar);
Kalle Valobdcd8172011-07-18 00:22:30 +03001562
1563 if (!ar->htc_target) {
1564 ret = -ENOMEM;
1565 goto err_bmi_cleanup;
1566 }
1567
Kalle Valo772c31e2011-09-07 10:55:16 +03001568 ret = ath6kl_fetch_firmwares(ar);
1569 if (ret)
1570 goto err_htc_cleanup;
1571
Kalle Valobdcd8172011-07-18 00:22:30 +03001572 ret = ath6kl_init_upload(ar);
1573 if (ret)
1574 goto err_htc_cleanup;
1575
Vasanthakumar Thiagarajan521dffc2011-10-25 19:33:56 +05301576 ret = ath6kl_init(ar);
Kalle Valobdcd8172011-07-18 00:22:30 +03001577 if (ret)
1578 goto err_htc_cleanup;
1579
Kalle Valobdcd8172011-07-18 00:22:30 +03001580 return ret;
1581
1582err_htc_cleanup:
Kalle Vaload226ec2011-08-10 09:49:12 +03001583 ath6kl_htc_cleanup(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001584err_bmi_cleanup:
1585 ath6kl_bmi_cleanup(ar);
1586err_wq:
1587 destroy_workqueue(ar->ath6kl_wq);
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301588
Kalle Valobdcd8172011-07-18 00:22:30 +03001589 return ret;
1590}
1591
1592void ath6kl_stop_txrx(struct ath6kl *ar)
1593{
1594 struct net_device *ndev = ar->net_dev;
1595
1596 if (!ndev)
1597 return;
1598
1599 set_bit(DESTROY_IN_PROGRESS, &ar->flag);
1600
1601 if (down_interruptible(&ar->sem)) {
1602 ath6kl_err("down_interruptible failed\n");
1603 return;
1604 }
1605
1606 if (ar->wlan_pwr_state != WLAN_POWER_STATE_CUT_PWR)
1607 ath6kl_stop_endpoint(ndev, false, true);
1608
Raja Mani575b5f32011-07-19 19:27:33 +05301609 clear_bit(WLAN_ENABLED, &ar->flag);
Kalle Valobdcd8172011-07-18 00:22:30 +03001610}
1611
1612/*
1613 * We need to differentiate between the surprise and planned removal of the
1614 * device because of the following consideration:
1615 *
1616 * - In case of surprise removal, the hcd already frees up the pending
1617 * for the device and hence there is no need to unregister the function
1618 * driver inorder to get these requests. For planned removal, the function
1619 * driver has to explicitly unregister itself to have the hcd return all the
1620 * pending requests before the data structures for the devices are freed up.
1621 * Note that as per the current implementation, the function driver will
1622 * end up releasing all the devices since there is no API to selectively
1623 * release a particular device.
1624 *
1625 * - Certain commands issued to the target can be skipped for surprise
1626 * removal since they will anyway not go through.
1627 */
1628void ath6kl_destroy(struct net_device *dev, unsigned int unregister)
1629{
1630 struct ath6kl *ar;
1631
1632 if (!dev || !ath6kl_priv(dev)) {
1633 ath6kl_err("failed to get device structure\n");
1634 return;
1635 }
1636
1637 ar = ath6kl_priv(dev);
1638
1639 destroy_workqueue(ar->ath6kl_wq);
1640
1641 if (ar->htc_target)
Kalle Vaload226ec2011-08-10 09:49:12 +03001642 ath6kl_htc_cleanup(ar->htc_target);
Kalle Valobdcd8172011-07-18 00:22:30 +03001643
Kalle Valobdcd8172011-07-18 00:22:30 +03001644 ath6kl_cookie_cleanup(ar);
1645
1646 ath6kl_cleanup_amsdu_rxbufs(ar);
1647
1648 ath6kl_bmi_cleanup(ar);
1649
Kalle Valobdf53962011-09-02 10:32:04 +03001650 ath6kl_debug_cleanup(ar);
1651
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301652 ath6kl_deinit_if_data(ar, dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001653
Raja Mani19703572011-08-04 19:26:30 +05301654 kfree(ar->fw_board);
1655 kfree(ar->fw_otp);
1656 kfree(ar->fw);
1657 kfree(ar->fw_patch);
1658
Vasanthakumar Thiagarajan8dafb702011-10-25 19:33:58 +05301659 ath6kl_deinit_ieee80211_hw(ar);
Kalle Valobdcd8172011-07-18 00:22:30 +03001660}