diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/init.c')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/init.c | 794 |
1 files changed, 609 insertions, 185 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 9d10322eac41..c1d2366704b5 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -15,6 +15,8 @@ | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/of.h> | ||
18 | #include <linux/mmc/sdio_func.h> | 20 | #include <linux/mmc/sdio_func.h> |
19 | #include "core.h" | 21 | #include "core.h" |
20 | #include "cfg80211.h" | 22 | #include "cfg80211.h" |
@@ -23,8 +25,10 @@ | |||
23 | #include "hif-ops.h" | 25 | #include "hif-ops.h" |
24 | 26 | ||
25 | unsigned int debug_mask; | 27 | unsigned int debug_mask; |
28 | static unsigned int testmode; | ||
26 | 29 | ||
27 | module_param(debug_mask, uint, 0644); | 30 | module_param(debug_mask, uint, 0644); |
31 | module_param(testmode, uint, 0644); | ||
28 | 32 | ||
29 | /* | 33 | /* |
30 | * Include definitions here that can be used to tune the WLAN module | 34 | * Include definitions here that can be used to tune the WLAN module |
@@ -53,12 +57,6 @@ module_param(debug_mask, uint, 0644); | |||
53 | 57 | ||
54 | #define CONFIG_AR600x_DEBUG_UART_TX_PIN 8 | 58 | #define CONFIG_AR600x_DEBUG_UART_TX_PIN 8 |
55 | 59 | ||
56 | enum addr_type { | ||
57 | DATASET_PATCH_ADDR, | ||
58 | APP_LOAD_ADDR, | ||
59 | APP_START_OVERRIDE_ADDR, | ||
60 | }; | ||
61 | |||
62 | #define ATH6KL_DATA_OFFSET 64 | 60 | #define ATH6KL_DATA_OFFSET 64 |
63 | struct sk_buff *ath6kl_buf_alloc(int size) | 61 | struct sk_buff *ath6kl_buf_alloc(int size) |
64 | { | 62 | { |
@@ -67,7 +65,7 @@ struct sk_buff *ath6kl_buf_alloc(int size) | |||
67 | 65 | ||
68 | /* Add chacheline space at front and back of buffer */ | 66 | /* Add chacheline space at front and back of buffer */ |
69 | reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + | 67 | reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + |
70 | sizeof(struct htc_packet); | 68 | sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES; |
71 | skb = dev_alloc_skb(size + reserved); | 69 | skb = dev_alloc_skb(size + reserved); |
72 | 70 | ||
73 | if (skb) | 71 | if (skb) |
@@ -85,7 +83,7 @@ void ath6kl_init_profile_info(struct ath6kl *ar) | |||
85 | ar->prwise_crypto = NONE_CRYPT; | 83 | ar->prwise_crypto = NONE_CRYPT; |
86 | ar->prwise_crypto_len = 0; | 84 | ar->prwise_crypto_len = 0; |
87 | ar->grp_crypto = NONE_CRYPT; | 85 | ar->grp_crypto = NONE_CRYPT; |
88 | ar->grp_crpto_len = 0; | 86 | ar->grp_crypto_len = 0; |
89 | memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); | 87 | memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); |
90 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); | 88 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); |
91 | memset(ar->bssid, 0, sizeof(ar->bssid)); | 89 | memset(ar->bssid, 0, sizeof(ar->bssid)); |
@@ -108,17 +106,6 @@ static u8 ath6kl_get_fw_iftype(struct ath6kl *ar) | |||
108 | } | 106 | } |
109 | } | 107 | } |
110 | 108 | ||
111 | static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar, | ||
112 | u32 item_offset) | ||
113 | { | ||
114 | u32 addr = 0; | ||
115 | |||
116 | if (ar->target_type == TARGET_TYPE_AR6003) | ||
117 | addr = ATH6KL_HI_START_ADDR + item_offset; | ||
118 | |||
119 | return addr; | ||
120 | } | ||
121 | |||
122 | static int ath6kl_set_host_app_area(struct ath6kl *ar) | 109 | static int ath6kl_set_host_app_area(struct ath6kl *ar) |
123 | { | 110 | { |
124 | u32 address, data; | 111 | u32 address, data; |
@@ -127,16 +114,15 @@ static int ath6kl_set_host_app_area(struct ath6kl *ar) | |||
127 | /* Fetch the address of the host_app_area_s | 114 | /* Fetch the address of the host_app_area_s |
128 | * instance in the host interest area */ | 115 | * instance in the host interest area */ |
129 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest)); | 116 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest)); |
130 | address = TARG_VTOP(address); | 117 | address = TARG_VTOP(ar->target_type, address); |
131 | 118 | ||
132 | if (ath6kl_read_reg_diag(ar, &address, &data)) | 119 | if (ath6kl_diag_read32(ar, address, &data)) |
133 | return -EIO; | 120 | return -EIO; |
134 | 121 | ||
135 | address = TARG_VTOP(data); | 122 | address = TARG_VTOP(ar->target_type, data); |
136 | host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION; | 123 | host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION; |
137 | if (ath6kl_access_datadiag(ar, address, | 124 | if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area, |
138 | (u8 *)&host_app_area, | 125 | sizeof(struct host_app_area))) |
139 | sizeof(struct host_app_area), false)) | ||
140 | return -EIO; | 126 | return -EIO; |
141 | 127 | ||
142 | return 0; | 128 | return 0; |
@@ -290,6 +276,7 @@ static void ath6kl_init_control_info(struct ath6kl *ar) | |||
290 | memset(&ar->sc_params, 0, sizeof(ar->sc_params)); | 276 | memset(&ar->sc_params, 0, sizeof(ar->sc_params)); |
291 | ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; | 277 | ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; |
292 | ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; | 278 | ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; |
279 | ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; | ||
293 | 280 | ||
294 | memset((u8 *)ar->sta_list, 0, | 281 | memset((u8 *)ar->sta_list, 0, |
295 | AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); | 282 | AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); |
@@ -370,10 +357,10 @@ static void ath6kl_dump_target_assert_info(struct ath6kl *ar) | |||
370 | 357 | ||
371 | /* the reg dump pointer is copied to the host interest area */ | 358 | /* the reg dump pointer is copied to the host interest area */ |
372 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); | 359 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); |
373 | address = TARG_VTOP(address); | 360 | address = TARG_VTOP(ar->target_type, address); |
374 | 361 | ||
375 | /* read RAM location through diagnostic window */ | 362 | /* read RAM location through diagnostic window */ |
376 | status = ath6kl_read_reg_diag(ar, &address, ®dump_loc); | 363 | status = ath6kl_diag_read32(ar, address, ®dump_loc); |
377 | 364 | ||
378 | if (status || !regdump_loc) { | 365 | if (status || !regdump_loc) { |
379 | ath6kl_err("failed to get ptr to register dump area\n"); | 366 | ath6kl_err("failed to get ptr to register dump area\n"); |
@@ -382,15 +369,11 @@ static void ath6kl_dump_target_assert_info(struct ath6kl *ar) | |||
382 | 369 | ||
383 | ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", | 370 | ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", |
384 | regdump_loc); | 371 | regdump_loc); |
385 | 372 | regdump_loc = TARG_VTOP(ar->target_type, regdump_loc); | |
386 | regdump_loc = TARG_VTOP(regdump_loc); | ||
387 | 373 | ||
388 | /* fetch register dump data */ | 374 | /* fetch register dump data */ |
389 | status = ath6kl_access_datadiag(ar, | 375 | status = ath6kl_diag_read(ar, regdump_loc, (u8 *)®dump_val[0], |
390 | regdump_loc, | 376 | REG_DUMP_COUNT_AR6003 * (sizeof(u32))); |
391 | (u8 *)®dump_val[0], | ||
392 | REG_DUMP_COUNT_AR6003 * (sizeof(u32)), | ||
393 | true); | ||
394 | 377 | ||
395 | if (status) { | 378 | if (status) { |
396 | ath6kl_err("failed to get register dump\n"); | 379 | ath6kl_err("failed to get register dump\n"); |
@@ -416,6 +399,7 @@ void ath6kl_target_failure(struct ath6kl *ar) | |||
416 | static int ath6kl_target_config_wlan_params(struct ath6kl *ar) | 399 | static int ath6kl_target_config_wlan_params(struct ath6kl *ar) |
417 | { | 400 | { |
418 | int status = 0; | 401 | int status = 0; |
402 | int ret; | ||
419 | 403 | ||
420 | /* | 404 | /* |
421 | * Configure the device for rx dot11 header rules. "0,0" are the | 405 | * Configure the device for rx dot11 header rules. "0,0" are the |
@@ -460,6 +444,28 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar) | |||
460 | status = -EIO; | 444 | status = -EIO; |
461 | } | 445 | } |
462 | 446 | ||
447 | if (ar->p2p) { | ||
448 | ret = ath6kl_wmi_info_req_cmd(ar->wmi, | ||
449 | P2P_FLAG_CAPABILITIES_REQ | | ||
450 | P2P_FLAG_MACADDR_REQ | | ||
451 | P2P_FLAG_HMODEL_REQ); | ||
452 | if (ret) { | ||
453 | ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P " | ||
454 | "capabilities (%d) - assuming P2P not " | ||
455 | "supported\n", ret); | ||
456 | ar->p2p = 0; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | if (ar->p2p) { | ||
461 | /* Enable Probe Request reporting for P2P */ | ||
462 | ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true); | ||
463 | if (ret) { | ||
464 | ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe " | ||
465 | "Request reporting (%d)\n", ret); | ||
466 | } | ||
467 | } | ||
468 | |||
463 | return status; | 469 | return status; |
464 | } | 470 | } |
465 | 471 | ||
@@ -495,6 +501,10 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
495 | 501 | ||
496 | param |= (1 << HI_OPTION_NUM_DEV_SHIFT); | 502 | param |= (1 << HI_OPTION_NUM_DEV_SHIFT); |
497 | param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT); | 503 | param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT); |
504 | if (ar->p2p && fw_iftype == HI_OPTION_FW_MODE_BSS_STA) { | ||
505 | param |= HI_OPTION_FW_SUBMODE_P2PDEV << | ||
506 | HI_OPTION_FW_SUBMODE_SHIFT; | ||
507 | } | ||
498 | param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); | 508 | param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); |
499 | param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); | 509 | param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); |
500 | 510 | ||
@@ -518,29 +528,21 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
518 | * but possible in theory. | 528 | * but possible in theory. |
519 | */ | 529 | */ |
520 | 530 | ||
521 | if (ar->target_type == TARGET_TYPE_AR6003) { | 531 | param = ar->hw.board_ext_data_addr; |
522 | if (ar->version.target_ver == AR6003_REV2_VERSION) { | 532 | ram_reserved_size = ar->hw.reserved_ram_size; |
523 | param = AR6003_REV2_BOARD_EXT_DATA_ADDRESS; | ||
524 | ram_reserved_size = AR6003_REV2_RAM_RESERVE_SIZE; | ||
525 | } else { | ||
526 | param = AR6003_REV3_BOARD_EXT_DATA_ADDRESS; | ||
527 | ram_reserved_size = AR6003_REV3_RAM_RESERVE_SIZE; | ||
528 | } | ||
529 | 533 | ||
530 | if (ath6kl_bmi_write(ar, | 534 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, |
531 | ath6kl_get_hi_item_addr(ar, | 535 | HI_ITEM(hi_board_ext_data)), |
532 | HI_ITEM(hi_board_ext_data)), | 536 | (u8 *)¶m, 4) != 0) { |
533 | (u8 *)¶m, 4) != 0) { | 537 | ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); |
534 | ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); | 538 | return -EIO; |
535 | return -EIO; | 539 | } |
536 | } | 540 | |
537 | if (ath6kl_bmi_write(ar, | 541 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, |
538 | ath6kl_get_hi_item_addr(ar, | 542 | HI_ITEM(hi_end_ram_reserve_sz)), |
539 | HI_ITEM(hi_end_ram_reserve_sz)), | 543 | (u8 *)&ram_reserved_size, 4) != 0) { |
540 | (u8 *)&ram_reserved_size, 4) != 0) { | 544 | ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); |
541 | ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); | 545 | return -EIO; |
542 | return -EIO; | ||
543 | } | ||
544 | } | 546 | } |
545 | 547 | ||
546 | /* set the block size for the target */ | 548 | /* set the block size for the target */ |
@@ -568,6 +570,12 @@ struct ath6kl *ath6kl_core_alloc(struct device *sdev) | |||
568 | ar->wdev = wdev; | 570 | ar->wdev = wdev; |
569 | wdev->iftype = NL80211_IFTYPE_STATION; | 571 | wdev->iftype = NL80211_IFTYPE_STATION; |
570 | 572 | ||
573 | if (ath6kl_debug_init(ar)) { | ||
574 | ath6kl_err("Failed to initialize debugfs\n"); | ||
575 | ath6kl_cfg80211_deinit(ar); | ||
576 | return NULL; | ||
577 | } | ||
578 | |||
571 | dev = alloc_netdev(0, "wlan%d", ether_setup); | 579 | dev = alloc_netdev(0, "wlan%d", ether_setup); |
572 | if (!dev) { | 580 | if (!dev) { |
573 | ath6kl_err("no memory for network device instance\n"); | 581 | ath6kl_err("no memory for network device instance\n"); |
@@ -579,7 +587,6 @@ struct ath6kl *ath6kl_core_alloc(struct device *sdev) | |||
579 | SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); | 587 | SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); |
580 | wdev->netdev = dev; | 588 | wdev->netdev = dev; |
581 | ar->sme_state = SME_DISCONNECTED; | 589 | ar->sme_state = SME_DISCONNECTED; |
582 | ar->auto_auth_stage = AUTH_IDLE; | ||
583 | 590 | ||
584 | init_netdev(dev); | 591 | init_netdev(dev); |
585 | 592 | ||
@@ -611,29 +618,6 @@ int ath6kl_unavail_ev(struct ath6kl *ar) | |||
611 | } | 618 | } |
612 | 619 | ||
613 | /* firmware upload */ | 620 | /* firmware upload */ |
614 | static u32 ath6kl_get_load_address(u32 target_ver, enum addr_type type) | ||
615 | { | ||
616 | WARN_ON(target_ver != AR6003_REV2_VERSION && | ||
617 | target_ver != AR6003_REV3_VERSION); | ||
618 | |||
619 | switch (type) { | ||
620 | case DATASET_PATCH_ADDR: | ||
621 | return (target_ver == AR6003_REV2_VERSION) ? | ||
622 | AR6003_REV2_DATASET_PATCH_ADDRESS : | ||
623 | AR6003_REV3_DATASET_PATCH_ADDRESS; | ||
624 | case APP_LOAD_ADDR: | ||
625 | return (target_ver == AR6003_REV2_VERSION) ? | ||
626 | AR6003_REV2_APP_LOAD_ADDRESS : | ||
627 | 0x1234; | ||
628 | case APP_START_OVERRIDE_ADDR: | ||
629 | return (target_ver == AR6003_REV2_VERSION) ? | ||
630 | AR6003_REV2_APP_START_OVERRIDE : | ||
631 | AR6003_REV3_APP_START_OVERRIDE; | ||
632 | default: | ||
633 | return 0; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, | 621 | static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, |
638 | u8 **fw, size_t *fw_len) | 622 | u8 **fw, size_t *fw_len) |
639 | { | 623 | { |
@@ -655,15 +639,79 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, | |||
655 | return ret; | 639 | return ret; |
656 | } | 640 | } |
657 | 641 | ||
642 | #ifdef CONFIG_OF | ||
643 | static const char *get_target_ver_dir(const struct ath6kl *ar) | ||
644 | { | ||
645 | switch (ar->version.target_ver) { | ||
646 | case AR6003_REV1_VERSION: | ||
647 | return "ath6k/AR6003/hw1.0"; | ||
648 | case AR6003_REV2_VERSION: | ||
649 | return "ath6k/AR6003/hw2.0"; | ||
650 | case AR6003_REV3_VERSION: | ||
651 | return "ath6k/AR6003/hw2.1.1"; | ||
652 | } | ||
653 | ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__, | ||
654 | ar->version.target_ver); | ||
655 | return NULL; | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * Check the device tree for a board-id and use it to construct | ||
660 | * the pathname to the firmware file. Used (for now) to find a | ||
661 | * fallback to the "bdata.bin" file--typically a symlink to the | ||
662 | * appropriate board-specific file. | ||
663 | */ | ||
664 | static bool check_device_tree(struct ath6kl *ar) | ||
665 | { | ||
666 | static const char *board_id_prop = "atheros,board-id"; | ||
667 | struct device_node *node; | ||
668 | char board_filename[64]; | ||
669 | const char *board_id; | ||
670 | int ret; | ||
671 | |||
672 | for_each_compatible_node(node, NULL, "atheros,ath6kl") { | ||
673 | board_id = of_get_property(node, board_id_prop, NULL); | ||
674 | if (board_id == NULL) { | ||
675 | ath6kl_warn("No \"%s\" property on %s node.\n", | ||
676 | board_id_prop, node->name); | ||
677 | continue; | ||
678 | } | ||
679 | snprintf(board_filename, sizeof(board_filename), | ||
680 | "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id); | ||
681 | |||
682 | ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board, | ||
683 | &ar->fw_board_len); | ||
684 | if (ret) { | ||
685 | ath6kl_err("Failed to get DT board file %s: %d\n", | ||
686 | board_filename, ret); | ||
687 | continue; | ||
688 | } | ||
689 | return true; | ||
690 | } | ||
691 | return false; | ||
692 | } | ||
693 | #else | ||
694 | static bool check_device_tree(struct ath6kl *ar) | ||
695 | { | ||
696 | return false; | ||
697 | } | ||
698 | #endif /* CONFIG_OF */ | ||
699 | |||
658 | static int ath6kl_fetch_board_file(struct ath6kl *ar) | 700 | static int ath6kl_fetch_board_file(struct ath6kl *ar) |
659 | { | 701 | { |
660 | const char *filename; | 702 | const char *filename; |
661 | int ret; | 703 | int ret; |
662 | 704 | ||
705 | if (ar->fw_board != NULL) | ||
706 | return 0; | ||
707 | |||
663 | switch (ar->version.target_ver) { | 708 | switch (ar->version.target_ver) { |
664 | case AR6003_REV2_VERSION: | 709 | case AR6003_REV2_VERSION: |
665 | filename = AR6003_REV2_BOARD_DATA_FILE; | 710 | filename = AR6003_REV2_BOARD_DATA_FILE; |
666 | break; | 711 | break; |
712 | case AR6004_REV1_VERSION: | ||
713 | filename = AR6004_REV1_BOARD_DATA_FILE; | ||
714 | break; | ||
667 | default: | 715 | default: |
668 | filename = AR6003_REV3_BOARD_DATA_FILE; | 716 | filename = AR6003_REV3_BOARD_DATA_FILE; |
669 | break; | 717 | break; |
@@ -676,6 +724,11 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) | |||
676 | return 0; | 724 | return 0; |
677 | } | 725 | } |
678 | 726 | ||
727 | if (check_device_tree(ar)) { | ||
728 | /* got board file from device tree */ | ||
729 | return 0; | ||
730 | } | ||
731 | |||
679 | /* there was no proper board file, try to use default instead */ | 732 | /* there was no proper board file, try to use default instead */ |
680 | ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", | 733 | ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", |
681 | filename, ret); | 734 | filename, ret); |
@@ -684,6 +737,9 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) | |||
684 | case AR6003_REV2_VERSION: | 737 | case AR6003_REV2_VERSION: |
685 | filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE; | 738 | filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE; |
686 | break; | 739 | break; |
740 | case AR6004_REV1_VERSION: | ||
741 | filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE; | ||
742 | break; | ||
687 | default: | 743 | default: |
688 | filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE; | 744 | filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE; |
689 | break; | 745 | break; |
@@ -703,25 +759,346 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) | |||
703 | return 0; | 759 | return 0; |
704 | } | 760 | } |
705 | 761 | ||
762 | static int ath6kl_fetch_otp_file(struct ath6kl *ar) | ||
763 | { | ||
764 | const char *filename; | ||
765 | int ret; | ||
706 | 766 | ||
707 | static int ath6kl_upload_board_file(struct ath6kl *ar) | 767 | if (ar->fw_otp != NULL) |
768 | return 0; | ||
769 | |||
770 | switch (ar->version.target_ver) { | ||
771 | case AR6003_REV2_VERSION: | ||
772 | filename = AR6003_REV2_OTP_FILE; | ||
773 | break; | ||
774 | case AR6004_REV1_VERSION: | ||
775 | ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n"); | ||
776 | return 0; | ||
777 | break; | ||
778 | default: | ||
779 | filename = AR6003_REV3_OTP_FILE; | ||
780 | break; | ||
781 | } | ||
782 | |||
783 | ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, | ||
784 | &ar->fw_otp_len); | ||
785 | if (ret) { | ||
786 | ath6kl_err("Failed to get OTP file %s: %d\n", | ||
787 | filename, ret); | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int ath6kl_fetch_fw_file(struct ath6kl *ar) | ||
708 | { | 795 | { |
709 | u32 board_address, board_ext_address, param; | 796 | const char *filename; |
797 | int ret; | ||
798 | |||
799 | if (ar->fw != NULL) | ||
800 | return 0; | ||
801 | |||
802 | if (testmode) { | ||
803 | switch (ar->version.target_ver) { | ||
804 | case AR6003_REV2_VERSION: | ||
805 | filename = AR6003_REV2_TCMD_FIRMWARE_FILE; | ||
806 | break; | ||
807 | case AR6003_REV3_VERSION: | ||
808 | filename = AR6003_REV3_TCMD_FIRMWARE_FILE; | ||
809 | break; | ||
810 | case AR6004_REV1_VERSION: | ||
811 | ath6kl_warn("testmode not supported with ar6004\n"); | ||
812 | return -EOPNOTSUPP; | ||
813 | default: | ||
814 | ath6kl_warn("unknown target version: 0x%x\n", | ||
815 | ar->version.target_ver); | ||
816 | return -EINVAL; | ||
817 | } | ||
818 | |||
819 | set_bit(TESTMODE, &ar->flag); | ||
820 | |||
821 | goto get_fw; | ||
822 | } | ||
823 | |||
824 | switch (ar->version.target_ver) { | ||
825 | case AR6003_REV2_VERSION: | ||
826 | filename = AR6003_REV2_FIRMWARE_FILE; | ||
827 | break; | ||
828 | case AR6004_REV1_VERSION: | ||
829 | filename = AR6004_REV1_FIRMWARE_FILE; | ||
830 | break; | ||
831 | default: | ||
832 | filename = AR6003_REV3_FIRMWARE_FILE; | ||
833 | break; | ||
834 | } | ||
835 | |||
836 | get_fw: | ||
837 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); | ||
838 | if (ret) { | ||
839 | ath6kl_err("Failed to get firmware file %s: %d\n", | ||
840 | filename, ret); | ||
841 | return ret; | ||
842 | } | ||
843 | |||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int ath6kl_fetch_patch_file(struct ath6kl *ar) | ||
848 | { | ||
849 | const char *filename; | ||
710 | int ret; | 850 | int ret; |
711 | 851 | ||
712 | if (ar->fw_board == NULL) { | 852 | switch (ar->version.target_ver) { |
713 | ret = ath6kl_fetch_board_file(ar); | 853 | case AR6003_REV2_VERSION: |
714 | if (ret) | 854 | filename = AR6003_REV2_PATCH_FILE; |
855 | break; | ||
856 | case AR6004_REV1_VERSION: | ||
857 | /* FIXME: implement for AR6004 */ | ||
858 | return 0; | ||
859 | break; | ||
860 | default: | ||
861 | filename = AR6003_REV3_PATCH_FILE; | ||
862 | break; | ||
863 | } | ||
864 | |||
865 | if (ar->fw_patch == NULL) { | ||
866 | ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, | ||
867 | &ar->fw_patch_len); | ||
868 | if (ret) { | ||
869 | ath6kl_err("Failed to get patch file %s: %d\n", | ||
870 | filename, ret); | ||
715 | return ret; | 871 | return ret; |
872 | } | ||
716 | } | 873 | } |
717 | 874 | ||
718 | /* Determine where in Target RAM to write Board Data */ | 875 | return 0; |
719 | ath6kl_bmi_read(ar, | 876 | } |
720 | ath6kl_get_hi_item_addr(ar, | 877 | |
721 | HI_ITEM(hi_board_data)), | 878 | static int ath6kl_fetch_fw_api1(struct ath6kl *ar) |
722 | (u8 *) &board_address, 4); | 879 | { |
723 | ath6kl_dbg(ATH6KL_DBG_TRC, "board data download addr: 0x%x\n", | 880 | int ret; |
724 | board_address); | 881 | |
882 | ret = ath6kl_fetch_otp_file(ar); | ||
883 | if (ret) | ||
884 | return ret; | ||
885 | |||
886 | ret = ath6kl_fetch_fw_file(ar); | ||
887 | if (ret) | ||
888 | return ret; | ||
889 | |||
890 | ret = ath6kl_fetch_patch_file(ar); | ||
891 | if (ret) | ||
892 | return ret; | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static int ath6kl_fetch_fw_api2(struct ath6kl *ar) | ||
898 | { | ||
899 | size_t magic_len, len, ie_len; | ||
900 | const struct firmware *fw; | ||
901 | struct ath6kl_fw_ie *hdr; | ||
902 | const char *filename; | ||
903 | const u8 *data; | ||
904 | int ret, ie_id, i, index, bit; | ||
905 | __le32 *val; | ||
906 | |||
907 | switch (ar->version.target_ver) { | ||
908 | case AR6003_REV2_VERSION: | ||
909 | filename = AR6003_REV2_FIRMWARE_2_FILE; | ||
910 | break; | ||
911 | case AR6003_REV3_VERSION: | ||
912 | filename = AR6003_REV3_FIRMWARE_2_FILE; | ||
913 | break; | ||
914 | case AR6004_REV1_VERSION: | ||
915 | filename = AR6004_REV1_FIRMWARE_2_FILE; | ||
916 | break; | ||
917 | default: | ||
918 | return -EOPNOTSUPP; | ||
919 | } | ||
920 | |||
921 | ret = request_firmware(&fw, filename, ar->dev); | ||
922 | if (ret) | ||
923 | return ret; | ||
924 | |||
925 | data = fw->data; | ||
926 | len = fw->size; | ||
927 | |||
928 | /* magic also includes the null byte, check that as well */ | ||
929 | magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1; | ||
930 | |||
931 | if (len < magic_len) { | ||
932 | ret = -EINVAL; | ||
933 | goto out; | ||
934 | } | ||
935 | |||
936 | if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) { | ||
937 | ret = -EINVAL; | ||
938 | goto out; | ||
939 | } | ||
940 | |||
941 | len -= magic_len; | ||
942 | data += magic_len; | ||
943 | |||
944 | /* loop elements */ | ||
945 | while (len > sizeof(struct ath6kl_fw_ie)) { | ||
946 | /* hdr is unaligned! */ | ||
947 | hdr = (struct ath6kl_fw_ie *) data; | ||
948 | |||
949 | ie_id = le32_to_cpup(&hdr->id); | ||
950 | ie_len = le32_to_cpup(&hdr->len); | ||
951 | |||
952 | len -= sizeof(*hdr); | ||
953 | data += sizeof(*hdr); | ||
954 | |||
955 | if (len < ie_len) { | ||
956 | ret = -EINVAL; | ||
957 | goto out; | ||
958 | } | ||
959 | |||
960 | switch (ie_id) { | ||
961 | case ATH6KL_FW_IE_OTP_IMAGE: | ||
962 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", | ||
963 | ie_len); | ||
964 | |||
965 | ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); | ||
966 | |||
967 | if (ar->fw_otp == NULL) { | ||
968 | ret = -ENOMEM; | ||
969 | goto out; | ||
970 | } | ||
971 | |||
972 | ar->fw_otp_len = ie_len; | ||
973 | break; | ||
974 | case ATH6KL_FW_IE_FW_IMAGE: | ||
975 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", | ||
976 | ie_len); | ||
977 | |||
978 | ar->fw = kmemdup(data, ie_len, GFP_KERNEL); | ||
979 | |||
980 | if (ar->fw == NULL) { | ||
981 | ret = -ENOMEM; | ||
982 | goto out; | ||
983 | } | ||
984 | |||
985 | ar->fw_len = ie_len; | ||
986 | break; | ||
987 | case ATH6KL_FW_IE_PATCH_IMAGE: | ||
988 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", | ||
989 | ie_len); | ||
990 | |||
991 | ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); | ||
992 | |||
993 | if (ar->fw_patch == NULL) { | ||
994 | ret = -ENOMEM; | ||
995 | goto out; | ||
996 | } | ||
997 | |||
998 | ar->fw_patch_len = ie_len; | ||
999 | break; | ||
1000 | case ATH6KL_FW_IE_RESERVED_RAM_SIZE: | ||
1001 | val = (__le32 *) data; | ||
1002 | ar->hw.reserved_ram_size = le32_to_cpup(val); | ||
1003 | |||
1004 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1005 | "found reserved ram size ie 0x%d\n", | ||
1006 | ar->hw.reserved_ram_size); | ||
1007 | break; | ||
1008 | case ATH6KL_FW_IE_CAPABILITIES: | ||
1009 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1010 | "found firmware capabilities ie (%zd B)\n", | ||
1011 | ie_len); | ||
1012 | |||
1013 | for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) { | ||
1014 | index = ALIGN(i, 8) / 8; | ||
1015 | bit = i % 8; | ||
1016 | |||
1017 | if (data[index] & (1 << bit)) | ||
1018 | __set_bit(i, ar->fw_capabilities); | ||
1019 | } | ||
1020 | |||
1021 | ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "", | ||
1022 | ar->fw_capabilities, | ||
1023 | sizeof(ar->fw_capabilities)); | ||
1024 | break; | ||
1025 | case ATH6KL_FW_IE_PATCH_ADDR: | ||
1026 | if (ie_len != sizeof(*val)) | ||
1027 | break; | ||
1028 | |||
1029 | val = (__le32 *) data; | ||
1030 | ar->hw.dataset_patch_addr = le32_to_cpup(val); | ||
1031 | |||
1032 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1033 | "found patch address ie 0x%d\n", | ||
1034 | ar->hw.dataset_patch_addr); | ||
1035 | break; | ||
1036 | default: | ||
1037 | ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n", | ||
1038 | le32_to_cpup(&hdr->id)); | ||
1039 | break; | ||
1040 | } | ||
1041 | |||
1042 | len -= ie_len; | ||
1043 | data += ie_len; | ||
1044 | }; | ||
1045 | |||
1046 | ret = 0; | ||
1047 | out: | ||
1048 | release_firmware(fw); | ||
1049 | |||
1050 | return ret; | ||
1051 | } | ||
1052 | |||
1053 | static int ath6kl_fetch_firmwares(struct ath6kl *ar) | ||
1054 | { | ||
1055 | int ret; | ||
1056 | |||
1057 | ret = ath6kl_fetch_board_file(ar); | ||
1058 | if (ret) | ||
1059 | return ret; | ||
1060 | |||
1061 | ret = ath6kl_fetch_fw_api2(ar); | ||
1062 | if (ret == 0) { | ||
1063 | ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n"); | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | ret = ath6kl_fetch_fw_api1(ar); | ||
1068 | if (ret) | ||
1069 | return ret; | ||
1070 | |||
1071 | ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n"); | ||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | static int ath6kl_upload_board_file(struct ath6kl *ar) | ||
1077 | { | ||
1078 | u32 board_address, board_ext_address, param; | ||
1079 | u32 board_data_size, board_ext_data_size; | ||
1080 | int ret; | ||
1081 | |||
1082 | if (WARN_ON(ar->fw_board == NULL)) | ||
1083 | return -ENOENT; | ||
1084 | |||
1085 | /* | ||
1086 | * Determine where in Target RAM to write Board Data. | ||
1087 | * For AR6004, host determine Target RAM address for | ||
1088 | * writing board data. | ||
1089 | */ | ||
1090 | if (ar->target_type == TARGET_TYPE_AR6004) { | ||
1091 | board_address = AR6004_REV1_BOARD_DATA_ADDRESS; | ||
1092 | ath6kl_bmi_write(ar, | ||
1093 | ath6kl_get_hi_item_addr(ar, | ||
1094 | HI_ITEM(hi_board_data)), | ||
1095 | (u8 *) &board_address, 4); | ||
1096 | } else { | ||
1097 | ath6kl_bmi_read(ar, | ||
1098 | ath6kl_get_hi_item_addr(ar, | ||
1099 | HI_ITEM(hi_board_data)), | ||
1100 | (u8 *) &board_address, 4); | ||
1101 | } | ||
725 | 1102 | ||
726 | /* determine where in target ram to write extended board data */ | 1103 | /* determine where in target ram to write extended board data */ |
727 | ath6kl_bmi_read(ar, | 1104 | ath6kl_bmi_read(ar, |
@@ -729,21 +1106,37 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
729 | HI_ITEM(hi_board_ext_data)), | 1106 | HI_ITEM(hi_board_ext_data)), |
730 | (u8 *) &board_ext_address, 4); | 1107 | (u8 *) &board_ext_address, 4); |
731 | 1108 | ||
732 | ath6kl_dbg(ATH6KL_DBG_TRC, "board file download addr: 0x%x\n", | ||
733 | board_ext_address); | ||
734 | |||
735 | if (board_ext_address == 0) { | 1109 | if (board_ext_address == 0) { |
736 | ath6kl_err("Failed to get board file target address.\n"); | 1110 | ath6kl_err("Failed to get board file target address.\n"); |
737 | return -EINVAL; | 1111 | return -EINVAL; |
738 | } | 1112 | } |
739 | 1113 | ||
740 | if (ar->fw_board_len == (AR6003_BOARD_DATA_SZ + | 1114 | switch (ar->target_type) { |
741 | AR6003_BOARD_EXT_DATA_SZ)) { | 1115 | case TARGET_TYPE_AR6003: |
1116 | board_data_size = AR6003_BOARD_DATA_SZ; | ||
1117 | board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; | ||
1118 | break; | ||
1119 | case TARGET_TYPE_AR6004: | ||
1120 | board_data_size = AR6004_BOARD_DATA_SZ; | ||
1121 | board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ; | ||
1122 | break; | ||
1123 | default: | ||
1124 | WARN_ON(1); | ||
1125 | return -EINVAL; | ||
1126 | break; | ||
1127 | } | ||
1128 | |||
1129 | if (ar->fw_board_len == (board_data_size + | ||
1130 | board_ext_data_size)) { | ||
1131 | |||
742 | /* write extended board data */ | 1132 | /* write extended board data */ |
743 | ret = ath6kl_bmi_write(ar, board_ext_address, | 1133 | ath6kl_dbg(ATH6KL_DBG_BOOT, |
744 | ar->fw_board + AR6003_BOARD_DATA_SZ, | 1134 | "writing extended board data to 0x%x (%d B)\n", |
745 | AR6003_BOARD_EXT_DATA_SZ); | 1135 | board_ext_address, board_ext_data_size); |
746 | 1136 | ||
1137 | ret = ath6kl_bmi_write(ar, board_ext_address, | ||
1138 | ar->fw_board + board_data_size, | ||
1139 | board_ext_data_size); | ||
747 | if (ret) { | 1140 | if (ret) { |
748 | ath6kl_err("Failed to write extended board data: %d\n", | 1141 | ath6kl_err("Failed to write extended board data: %d\n", |
749 | ret); | 1142 | ret); |
@@ -751,21 +1144,25 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
751 | } | 1144 | } |
752 | 1145 | ||
753 | /* record that extended board data is initialized */ | 1146 | /* record that extended board data is initialized */ |
754 | param = (AR6003_BOARD_EXT_DATA_SZ << 16) | 1; | 1147 | param = (board_ext_data_size << 16) | 1; |
1148 | |||
755 | ath6kl_bmi_write(ar, | 1149 | ath6kl_bmi_write(ar, |
756 | ath6kl_get_hi_item_addr(ar, | 1150 | ath6kl_get_hi_item_addr(ar, |
757 | HI_ITEM(hi_board_ext_data_config)), | 1151 | HI_ITEM(hi_board_ext_data_config)), |
758 | (unsigned char *) ¶m, 4); | 1152 | (unsigned char *) ¶m, 4); |
759 | } | 1153 | } |
760 | 1154 | ||
761 | if (ar->fw_board_len < AR6003_BOARD_DATA_SZ) { | 1155 | if (ar->fw_board_len < board_data_size) { |
762 | ath6kl_err("Too small board file: %zu\n", ar->fw_board_len); | 1156 | ath6kl_err("Too small board file: %zu\n", ar->fw_board_len); |
763 | ret = -EINVAL; | 1157 | ret = -EINVAL; |
764 | return ret; | 1158 | return ret; |
765 | } | 1159 | } |
766 | 1160 | ||
1161 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n", | ||
1162 | board_address, board_data_size); | ||
1163 | |||
767 | ret = ath6kl_bmi_write(ar, board_address, ar->fw_board, | 1164 | ret = ath6kl_bmi_write(ar, board_address, ar->fw_board, |
768 | AR6003_BOARD_DATA_SZ); | 1165 | board_data_size); |
769 | 1166 | ||
770 | if (ret) { | 1167 | if (ret) { |
771 | ath6kl_err("Board file bmi write failed: %d\n", ret); | 1168 | ath6kl_err("Board file bmi write failed: %d\n", ret); |
@@ -784,31 +1181,16 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
784 | 1181 | ||
785 | static int ath6kl_upload_otp(struct ath6kl *ar) | 1182 | static int ath6kl_upload_otp(struct ath6kl *ar) |
786 | { | 1183 | { |
787 | const char *filename; | ||
788 | u32 address, param; | 1184 | u32 address, param; |
789 | int ret; | 1185 | int ret; |
790 | 1186 | ||
791 | switch (ar->version.target_ver) { | 1187 | if (WARN_ON(ar->fw_otp == NULL)) |
792 | case AR6003_REV2_VERSION: | 1188 | return -ENOENT; |
793 | filename = AR6003_REV2_OTP_FILE; | ||
794 | break; | ||
795 | default: | ||
796 | filename = AR6003_REV3_OTP_FILE; | ||
797 | break; | ||
798 | } | ||
799 | 1189 | ||
800 | if (ar->fw_otp == NULL) { | 1190 | address = ar->hw.app_load_addr; |
801 | ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, | ||
802 | &ar->fw_otp_len); | ||
803 | if (ret) { | ||
804 | ath6kl_err("Failed to get OTP file %s: %d\n", | ||
805 | filename, ret); | ||
806 | return ret; | ||
807 | } | ||
808 | } | ||
809 | 1191 | ||
810 | address = ath6kl_get_load_address(ar->version.target_ver, | 1192 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%zd B)\n", address, |
811 | APP_LOAD_ADDR); | 1193 | ar->fw_otp_len); |
812 | 1194 | ||
813 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, | 1195 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, |
814 | ar->fw_otp_len); | 1196 | ar->fw_otp_len); |
@@ -817,10 +1199,25 @@ static int ath6kl_upload_otp(struct ath6kl *ar) | |||
817 | return ret; | 1199 | return ret; |
818 | } | 1200 | } |
819 | 1201 | ||
1202 | /* read firmware start address */ | ||
1203 | ret = ath6kl_bmi_read(ar, | ||
1204 | ath6kl_get_hi_item_addr(ar, | ||
1205 | HI_ITEM(hi_app_start)), | ||
1206 | (u8 *) &address, sizeof(address)); | ||
1207 | |||
1208 | if (ret) { | ||
1209 | ath6kl_err("Failed to read hi_app_start: %d\n", ret); | ||
1210 | return ret; | ||
1211 | } | ||
1212 | |||
1213 | ar->hw.app_start_override_addr = address; | ||
1214 | |||
1215 | ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr 0x%x\n", | ||
1216 | ar->hw.app_start_override_addr); | ||
1217 | |||
820 | /* execute the OTP code */ | 1218 | /* execute the OTP code */ |
1219 | ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n", address); | ||
821 | param = 0; | 1220 | param = 0; |
822 | address = ath6kl_get_load_address(ar->version.target_ver, | ||
823 | APP_START_OVERRIDE_ADDR); | ||
824 | ath6kl_bmi_execute(ar, address, ¶m); | 1221 | ath6kl_bmi_execute(ar, address, ¶m); |
825 | 1222 | ||
826 | return ret; | 1223 | return ret; |
@@ -828,30 +1225,16 @@ static int ath6kl_upload_otp(struct ath6kl *ar) | |||
828 | 1225 | ||
829 | static int ath6kl_upload_firmware(struct ath6kl *ar) | 1226 | static int ath6kl_upload_firmware(struct ath6kl *ar) |
830 | { | 1227 | { |
831 | const char *filename; | ||
832 | u32 address; | 1228 | u32 address; |
833 | int ret; | 1229 | int ret; |
834 | 1230 | ||
835 | switch (ar->version.target_ver) { | 1231 | if (WARN_ON(ar->fw == NULL)) |
836 | case AR6003_REV2_VERSION: | 1232 | return -ENOENT; |
837 | filename = AR6003_REV2_FIRMWARE_FILE; | ||
838 | break; | ||
839 | default: | ||
840 | filename = AR6003_REV3_FIRMWARE_FILE; | ||
841 | break; | ||
842 | } | ||
843 | 1233 | ||
844 | if (ar->fw == NULL) { | 1234 | address = ar->hw.app_load_addr; |
845 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); | ||
846 | if (ret) { | ||
847 | ath6kl_err("Failed to get firmware file %s: %d\n", | ||
848 | filename, ret); | ||
849 | return ret; | ||
850 | } | ||
851 | } | ||
852 | 1235 | ||
853 | address = ath6kl_get_load_address(ar->version.target_ver, | 1236 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%zd B)\n", |
854 | APP_LOAD_ADDR); | 1237 | address, ar->fw_len); |
855 | 1238 | ||
856 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len); | 1239 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len); |
857 | 1240 | ||
@@ -860,41 +1243,29 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) | |||
860 | return ret; | 1243 | return ret; |
861 | } | 1244 | } |
862 | 1245 | ||
863 | /* Set starting address for firmware */ | 1246 | /* |
864 | address = ath6kl_get_load_address(ar->version.target_ver, | 1247 | * Set starting address for firmware |
865 | APP_START_OVERRIDE_ADDR); | 1248 | * Don't need to setup app_start override addr on AR6004 |
866 | ath6kl_bmi_set_app_start(ar, address); | 1249 | */ |
867 | 1250 | if (ar->target_type != TARGET_TYPE_AR6004) { | |
1251 | address = ar->hw.app_start_override_addr; | ||
1252 | ath6kl_bmi_set_app_start(ar, address); | ||
1253 | } | ||
868 | return ret; | 1254 | return ret; |
869 | } | 1255 | } |
870 | 1256 | ||
871 | static int ath6kl_upload_patch(struct ath6kl *ar) | 1257 | static int ath6kl_upload_patch(struct ath6kl *ar) |
872 | { | 1258 | { |
873 | const char *filename; | ||
874 | u32 address, param; | 1259 | u32 address, param; |
875 | int ret; | 1260 | int ret; |
876 | 1261 | ||
877 | switch (ar->version.target_ver) { | 1262 | if (WARN_ON(ar->fw_patch == NULL)) |
878 | case AR6003_REV2_VERSION: | 1263 | return -ENOENT; |
879 | filename = AR6003_REV2_PATCH_FILE; | ||
880 | break; | ||
881 | default: | ||
882 | filename = AR6003_REV3_PATCH_FILE; | ||
883 | break; | ||
884 | } | ||
885 | 1264 | ||
886 | if (ar->fw_patch == NULL) { | 1265 | address = ar->hw.dataset_patch_addr; |
887 | ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, | ||
888 | &ar->fw_patch_len); | ||
889 | if (ret) { | ||
890 | ath6kl_err("Failed to get patch file %s: %d\n", | ||
891 | filename, ret); | ||
892 | return ret; | ||
893 | } | ||
894 | } | ||
895 | 1266 | ||
896 | address = ath6kl_get_load_address(ar->version.target_ver, | 1267 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%zd B)\n", |
897 | DATASET_PATCH_ADDR); | 1268 | address, ar->fw_patch_len); |
898 | 1269 | ||
899 | ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); | 1270 | ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); |
900 | if (ret) { | 1271 | if (ret) { |
@@ -916,7 +1287,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
916 | u32 param, options, sleep, address; | 1287 | u32 param, options, sleep, address; |
917 | int status = 0; | 1288 | int status = 0; |
918 | 1289 | ||
919 | if (ar->target_type != TARGET_TYPE_AR6003) | 1290 | if (ar->target_type != TARGET_TYPE_AR6003 && |
1291 | ar->target_type != TARGET_TYPE_AR6004) | ||
920 | return -EINVAL; | 1292 | return -EINVAL; |
921 | 1293 | ||
922 | /* temporarily disable system sleep */ | 1294 | /* temporarily disable system sleep */ |
@@ -948,18 +1320,22 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
948 | options, sleep); | 1320 | options, sleep); |
949 | 1321 | ||
950 | /* program analog PLL register */ | 1322 | /* program analog PLL register */ |
951 | status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER, | 1323 | /* no need to control 40/44MHz clock on AR6004 */ |
952 | 0xF9104001); | 1324 | if (ar->target_type != TARGET_TYPE_AR6004) { |
953 | if (status) | 1325 | status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER, |
954 | return status; | 1326 | 0xF9104001); |
955 | 1327 | ||
956 | /* Run at 80/88MHz by default */ | 1328 | if (status) |
957 | param = SM(CPU_CLOCK_STANDARD, 1); | 1329 | return status; |
958 | 1330 | ||
959 | address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS; | 1331 | /* Run at 80/88MHz by default */ |
960 | status = ath6kl_bmi_reg_write(ar, address, param); | 1332 | param = SM(CPU_CLOCK_STANDARD, 1); |
961 | if (status) | 1333 | |
962 | return status; | 1334 | address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS; |
1335 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
1336 | if (status) | ||
1337 | return status; | ||
1338 | } | ||
963 | 1339 | ||
964 | param = 0; | 1340 | param = 0; |
965 | address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS; | 1341 | address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS; |
@@ -1036,6 +1412,45 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
1036 | return status; | 1412 | return status; |
1037 | } | 1413 | } |
1038 | 1414 | ||
1415 | static int ath6kl_init_hw_params(struct ath6kl *ar) | ||
1416 | { | ||
1417 | switch (ar->version.target_ver) { | ||
1418 | case AR6003_REV2_VERSION: | ||
1419 | ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS; | ||
1420 | ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS; | ||
1421 | ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS; | ||
1422 | ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE; | ||
1423 | break; | ||
1424 | case AR6003_REV3_VERSION: | ||
1425 | ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS; | ||
1426 | ar->hw.app_load_addr = 0x1234; | ||
1427 | ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS; | ||
1428 | ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE; | ||
1429 | break; | ||
1430 | case AR6004_REV1_VERSION: | ||
1431 | ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS; | ||
1432 | ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS; | ||
1433 | ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS; | ||
1434 | ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE; | ||
1435 | break; | ||
1436 | default: | ||
1437 | ath6kl_err("Unsupported hardware version: 0x%x\n", | ||
1438 | ar->version.target_ver); | ||
1439 | return -EINVAL; | ||
1440 | } | ||
1441 | |||
1442 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1443 | "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n", | ||
1444 | ar->version.target_ver, ar->target_type, | ||
1445 | ar->hw.dataset_patch_addr, ar->hw.app_load_addr); | ||
1446 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1447 | "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x", | ||
1448 | ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr, | ||
1449 | ar->hw.reserved_ram_size); | ||
1450 | |||
1451 | return 0; | ||
1452 | } | ||
1453 | |||
1039 | static int ath6kl_init(struct net_device *dev) | 1454 | static int ath6kl_init(struct net_device *dev) |
1040 | { | 1455 | { |
1041 | struct ath6kl *ar = ath6kl_priv(dev); | 1456 | struct ath6kl *ar = ath6kl_priv(dev); |
@@ -1062,8 +1477,6 @@ static int ath6kl_init(struct net_device *dev) | |||
1062 | 1477 | ||
1063 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); | 1478 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); |
1064 | 1479 | ||
1065 | wlan_node_table_init(&ar->scan_table); | ||
1066 | |||
1067 | /* | 1480 | /* |
1068 | * The reason we have to wait for the target here is that the | 1481 | * The reason we have to wait for the target here is that the |
1069 | * driver layer has to init BMI in order to set the host block | 1482 | * driver layer has to init BMI in order to set the host block |
@@ -1111,6 +1524,8 @@ static int ath6kl_init(struct net_device *dev) | |||
1111 | &ar->flag), | 1524 | &ar->flag), |
1112 | WMI_TIMEOUT); | 1525 | WMI_TIMEOUT); |
1113 | 1526 | ||
1527 | ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n"); | ||
1528 | |||
1114 | if (ar->version.abi_ver != ATH6KL_ABI_VERSION) { | 1529 | if (ar->version.abi_ver != ATH6KL_ABI_VERSION) { |
1115 | ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n", | 1530 | ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n", |
1116 | ATH6KL_ABI_VERSION, ar->version.abi_ver); | 1531 | ATH6KL_ABI_VERSION, ar->version.abi_ver); |
@@ -1133,6 +1548,8 @@ static int ath6kl_init(struct net_device *dev) | |||
1133 | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | | 1548 | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | |
1134 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; | 1549 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; |
1135 | 1550 | ||
1551 | ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; | ||
1552 | |||
1136 | status = ath6kl_target_config_wlan_params(ar); | 1553 | status = ath6kl_target_config_wlan_params(ar); |
1137 | if (!status) | 1554 | if (!status) |
1138 | goto ath6kl_init_done; | 1555 | goto ath6kl_init_done; |
@@ -1145,7 +1562,6 @@ err_rxbuf_cleanup: | |||
1145 | err_cleanup_scatter: | 1562 | err_cleanup_scatter: |
1146 | ath6kl_hif_cleanup_scatter(ar); | 1563 | ath6kl_hif_cleanup_scatter(ar); |
1147 | err_node_cleanup: | 1564 | err_node_cleanup: |
1148 | wlan_node_table_cleanup(&ar->scan_table); | ||
1149 | ath6kl_wmi_shutdown(ar->wmi); | 1565 | ath6kl_wmi_shutdown(ar->wmi); |
1150 | clear_bit(WMI_ENABLED, &ar->flag); | 1566 | clear_bit(WMI_ENABLED, &ar->flag); |
1151 | ar->wmi = NULL; | 1567 | ar->wmi = NULL; |
@@ -1175,6 +1591,10 @@ int ath6kl_core_init(struct ath6kl *ar) | |||
1175 | ar->target_type = le32_to_cpu(targ_info.type); | 1591 | ar->target_type = le32_to_cpu(targ_info.type); |
1176 | ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); | 1592 | ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); |
1177 | 1593 | ||
1594 | ret = ath6kl_init_hw_params(ar); | ||
1595 | if (ret) | ||
1596 | goto err_bmi_cleanup; | ||
1597 | |||
1178 | ret = ath6kl_configure_target(ar); | 1598 | ret = ath6kl_configure_target(ar); |
1179 | if (ret) | 1599 | if (ret) |
1180 | goto err_bmi_cleanup; | 1600 | goto err_bmi_cleanup; |
@@ -1193,6 +1613,10 @@ int ath6kl_core_init(struct ath6kl *ar) | |||
1193 | goto err_htc_cleanup; | 1613 | goto err_htc_cleanup; |
1194 | } | 1614 | } |
1195 | 1615 | ||
1616 | ret = ath6kl_fetch_firmwares(ar); | ||
1617 | if (ret) | ||
1618 | goto err_htc_cleanup; | ||
1619 | |||
1196 | ret = ath6kl_init_upload(ar); | 1620 | ret = ath6kl_init_upload(ar); |
1197 | if (ret) | 1621 | if (ret) |
1198 | goto err_htc_cleanup; | 1622 | goto err_htc_cleanup; |
@@ -1285,6 +1709,8 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) | |||
1285 | 1709 | ||
1286 | ath6kl_bmi_cleanup(ar); | 1710 | ath6kl_bmi_cleanup(ar); |
1287 | 1711 | ||
1712 | ath6kl_debug_cleanup(ar); | ||
1713 | |||
1288 | if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { | 1714 | if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { |
1289 | unregister_netdev(dev); | 1715 | unregister_netdev(dev); |
1290 | clear_bit(NETDEV_REGISTERED, &ar->flag); | 1716 | clear_bit(NETDEV_REGISTERED, &ar->flag); |
@@ -1292,8 +1718,6 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) | |||
1292 | 1718 | ||
1293 | free_netdev(dev); | 1719 | free_netdev(dev); |
1294 | 1720 | ||
1295 | wlan_node_table_cleanup(&ar->scan_table); | ||
1296 | |||
1297 | kfree(ar->fw_board); | 1721 | kfree(ar->fw_board); |
1298 | kfree(ar->fw_otp); | 1722 | kfree(ar->fw_otp); |
1299 | kfree(ar->fw); | 1723 | kfree(ar->fw); |