X-Git-Url: http://git.cascardo.info/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fath%2Fath6kl%2Finit.c;h=03cae142f17827b10694af4d582aeae9d7271507;hb=b0fc7c1a643bb0e689cd2846b0edf7c707a87600;hp=7f55be3092d1c63698bc2f9d83d88d6ce2769868;hpb=dca88ad6915b65f6e037f8c3e632fcd92a70bd88;p=cascardo%2Flinux.git diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 7f55be3092d1..03cae142f178 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,22 +18,16 @@ #include #include +#include #include #include + #include "core.h" #include "cfg80211.h" #include "target.h" #include "debug.h" #include "hif-ops.h" -unsigned int debug_mask; -static unsigned int testmode; -static bool suspend_cutpower; - -module_param(debug_mask, uint, 0644); -module_param(testmode, uint, 0644); -module_param(suspend_cutpower, bool, 0444); - static const struct ath6kl_hw hw_list[] = { { .id = AR6003_HW_2_0_VERSION, @@ -47,11 +42,14 @@ static const struct ath6kl_hw hw_list[] = { /* hw2.0 needs override address hardcoded */ .app_start_override_addr = 0x944C00, - .fw_otp = AR6003_HW_2_0_OTP_FILE, - .fw = AR6003_HW_2_0_FIRMWARE_FILE, - .fw_tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE, - .fw_patch = AR6003_HW_2_0_PATCH_FILE, - .fw_api2 = AR6003_HW_2_0_FIRMWARE_2_FILE, + .fw = { + .dir = AR6003_HW_2_0_FW_DIR, + .otp = AR6003_HW_2_0_OTP_FILE, + .fw = AR6003_HW_2_0_FIRMWARE_FILE, + .tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE, + .patch = AR6003_HW_2_0_PATCH_FILE, + }, + .fw_board = AR6003_HW_2_0_BOARD_DATA_FILE, .fw_default_board = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE, }, @@ -64,14 +62,20 @@ static const struct ath6kl_hw hw_list[] = { .reserved_ram_size = 512, .refclk_hz = 26000000, .uarttx_pin = 8, + .testscript_addr = 0x57ef74, + + .fw = { + .dir = AR6003_HW_2_1_1_FW_DIR, + .otp = AR6003_HW_2_1_1_OTP_FILE, + .fw = AR6003_HW_2_1_1_FIRMWARE_FILE, + .tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE, + .patch = AR6003_HW_2_1_1_PATCH_FILE, + .utf = AR6003_HW_2_1_1_UTF_FIRMWARE_FILE, + .testscript = AR6003_HW_2_1_1_TESTSCRIPT_FILE, + }, - .fw_otp = AR6003_HW_2_1_1_OTP_FILE, - .fw = AR6003_HW_2_1_1_FIRMWARE_FILE, - .fw_tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE, - .fw_patch = AR6003_HW_2_1_1_PATCH_FILE, - .fw_api2 = AR6003_HW_2_1_1_FIRMWARE_2_FILE, .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, - .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, + .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, }, { .id = AR6004_HW_1_0_VERSION, @@ -84,8 +88,11 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 26000000, .uarttx_pin = 11, - .fw = AR6004_HW_1_0_FIRMWARE_FILE, - .fw_api2 = AR6004_HW_1_0_FIRMWARE_2_FILE, + .fw = { + .dir = AR6004_HW_1_0_FW_DIR, + .fw = AR6004_HW_1_0_FIRMWARE_FILE, + }, + .fw_board = AR6004_HW_1_0_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE, }, @@ -100,8 +107,11 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 40000000, .uarttx_pin = 11, - .fw = AR6004_HW_1_1_FIRMWARE_FILE, - .fw_api2 = AR6004_HW_1_1_FIRMWARE_2_FILE, + .fw = { + .dir = AR6004_HW_1_1_FW_DIR, + .fw = AR6004_HW_1_1_FIRMWARE_FILE, + }, + .fw_board = AR6004_HW_1_1_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE, }, @@ -342,11 +352,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, blk_size |= ((u32)htc_ctrl_buf) << 16; /* set the host interest area for the block size */ - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_mbox_io_block_sz)), - (u8 *)&blk_size, - 4); + status = ath6kl_bmi_write_hi32(ar, hi_mbox_io_block_sz, blk_size); if (status) { ath6kl_err("bmi_write_memory for IO block size failed\n"); goto out; @@ -358,11 +364,8 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, if (mbox_isr_yield_val) { /* set the host interest area for the mbox ISR yield limit */ - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_mbox_isr_yield_limit)), - (u8 *)&mbox_isr_yield_val, - 4); + status = ath6kl_bmi_write_hi32(ar, hi_mbox_isr_yield_limit, + mbox_isr_yield_val); if (status) { ath6kl_err("bmi_write_memory for yield limit failed\n"); goto out; @@ -375,7 +378,6 @@ out: static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) { - int status = 0; int ret; /* @@ -383,43 +385,54 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) * default values. Required if checksum offload is needed. Set * RxMetaVersion to 2. */ - if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, - ar->rx_meta_ver, 0, 0)) { - ath6kl_err("unable to set the rx frame format\n"); - status = -EIO; + ret = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, + ar->rx_meta_ver, 0, 0); + if (ret) { + ath6kl_err("unable to set the rx frame format: %d\n", ret); + return ret; } - if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) - if ((ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, - IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { - ath6kl_err("unable to set power save fail event policy\n"); - status = -EIO; + if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) { + ret = ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, + IGNORE_PS_FAIL_DURING_SCAN); + if (ret) { + ath6kl_err("unable to set power save fail event policy: %d\n", + ret); + return ret; } + } - if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) - if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, - WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { - ath6kl_err("unable to set barker preamble policy\n"); - status = -EIO; + if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) { + ret = ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, + WMI_FOLLOW_BARKER_IN_ERP); + if (ret) { + ath6kl_err("unable to set barker preamble policy: %d\n", + ret); + return ret; } + } - if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, - WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { - ath6kl_err("unable to set keep alive interval\n"); - status = -EIO; + ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, + WLAN_CONFIG_KEEP_ALIVE_INTERVAL); + if (ret) { + ath6kl_err("unable to set keep alive interval: %d\n", ret); + return ret; } - if (ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, - WLAN_CONFIG_DISCONNECT_TIMEOUT)) { - ath6kl_err("unable to set disconnect timeout\n"); - status = -EIO; + ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, + WLAN_CONFIG_DISCONNECT_TIMEOUT); + if (ret) { + ath6kl_err("unable to set disconnect timeout: %d\n", ret); + return ret; } - if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) - if (ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED)) { - ath6kl_err("unable to set txop bursting\n"); - status = -EIO; + if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) { + ret = ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED); + if (ret) { + ath6kl_err("unable to set txop bursting: %d\n", ret); + return ret; } + } if (ar->p2p && (ar->vif_max == 1 || idx)) { ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx, @@ -443,7 +456,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) } } - return status; + return ret; } int ath6kl_configure_target(struct ath6kl *ar) @@ -452,6 +465,12 @@ int ath6kl_configure_target(struct ath6kl *ar) u8 fw_iftype, fw_mode = 0, fw_submode = 0; int i, status; + param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG); + if (ath6kl_bmi_write_hi32(ar, hi_serial_enable, param)) { + ath6kl_err("bmi_write_memory for uart debug failed\n"); + return -EIO; + } + /* * Note: Even though the firmware interface type is * chosen as BSS_STA for all three interfaces, can @@ -483,11 +502,8 @@ int ath6kl_configure_target(struct ath6kl *ar) if (ar->p2p && ar->vif_max == 1) fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; - param = HTC_PROTOCOL_VERSION; - if (ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_app_host_interest)), - (u8 *)¶m, 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest, + HTC_PROTOCOL_VERSION) != 0) { ath6kl_err("bmi_write_memory for htc version failed\n"); return -EIO; } @@ -495,10 +511,7 @@ int ath6kl_configure_target(struct ath6kl *ar) /* set the firmware mode to STA/IBSS/AP */ param = 0; - if (ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_option_flag)), - (u8 *)¶m, 4) != 0) { + if (ath6kl_bmi_read_hi32(ar, hi_option_flag, ¶m) != 0) { ath6kl_err("bmi_read_memory for setting fwmode failed\n"); return -EIO; } @@ -510,11 +523,7 @@ int ath6kl_configure_target(struct ath6kl *ar) param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); - if (ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_option_flag)), - (u8 *)¶m, - 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_option_flag, param) != 0) { ath6kl_err("bmi_write_memory for setting fwmode failed\n"); return -EIO; } @@ -533,16 +542,13 @@ int ath6kl_configure_target(struct ath6kl *ar) param = ar->hw.board_ext_data_addr; ram_reserved_size = ar->hw.reserved_ram_size; - if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_ext_data)), - (u8 *)¶m, 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); return -EIO; } - if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_end_ram_reserve_sz)), - (u8 *)&ram_reserved_size, 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, + ram_reserved_size) != 0) { ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); return -EIO; } @@ -553,56 +559,19 @@ int ath6kl_configure_target(struct ath6kl *ar) return -EIO; /* Configure GPIO AR600x UART */ - param = ar->hw.uarttx_pin; - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_dbg_uart_txpin)), - (u8 *)¶m, 4); + status = ath6kl_bmi_write_hi32(ar, hi_dbg_uart_txpin, + ar->hw.uarttx_pin); if (status) return status; /* Configure target refclk_hz */ - param = ar->hw.refclk_hz; - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_refclk_hz)), - (u8 *)¶m, 4); + status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz); if (status) return status; return 0; } -void ath6kl_core_free(struct ath6kl *ar) -{ - wiphy_free(ar->wiphy); -} - -void ath6kl_core_cleanup(struct ath6kl *ar) -{ - ath6kl_hif_power_off(ar); - - destroy_workqueue(ar->ath6kl_wq); - - if (ar->htc_target) - ath6kl_htc_cleanup(ar->htc_target); - - ath6kl_cookie_cleanup(ar); - - ath6kl_cleanup_amsdu_rxbufs(ar); - - ath6kl_bmi_cleanup(ar); - - ath6kl_debug_cleanup(ar); - - kfree(ar->fw_board); - kfree(ar->fw_otp); - kfree(ar->fw); - kfree(ar->fw_patch); - - ath6kl_deinit_ieee80211_hw(ar); -} - /* firmware upload */ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, u8 **fw, size_t *fw_len) @@ -626,21 +595,6 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, } #ifdef CONFIG_OF -static const char *get_target_ver_dir(const struct ath6kl *ar) -{ - switch (ar->version.target_ver) { - case AR6003_HW_1_0_VERSION: - return "ath6k/AR6003/hw1.0"; - case AR6003_HW_2_0_VERSION: - return "ath6k/AR6003/hw2.0"; - case AR6003_HW_2_1_1_VERSION: - return "ath6k/AR6003/hw2.1.1"; - } - ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__, - ar->version.target_ver); - return NULL; -} - /* * Check the device tree for a board-id and use it to construct * the pathname to the firmware file. Used (for now) to find a @@ -663,7 +617,7 @@ static bool check_device_tree(struct ath6kl *ar) continue; } snprintf(board_filename, sizeof(board_filename), - "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id); + "%s/bdata.%s.bin", ar->hw.fw.dir, board_id); ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board, &ar->fw_board_len); @@ -730,19 +684,20 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) static int ath6kl_fetch_otp_file(struct ath6kl *ar) { - const char *filename; + char filename[100]; int ret; if (ar->fw_otp != NULL) return 0; - if (ar->hw.fw_otp == NULL) { + if (ar->hw.fw.otp == NULL) { ath6kl_dbg(ATH6KL_DBG_BOOT, "no OTP file configured for this hw\n"); return 0; } - filename = ar->hw.fw_otp; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.otp); ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, &ar->fw_otp_len); @@ -755,33 +710,61 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar) return 0; } -static int ath6kl_fetch_fw_file(struct ath6kl *ar) +static int ath6kl_fetch_testmode_file(struct ath6kl *ar) { - const char *filename; + char filename[100]; int ret; - if (ar->fw != NULL) + if (ar->testmode == 0) return 0; - if (testmode) { - if (ar->hw.fw_tcmd == NULL) { - ath6kl_warn("testmode not supported\n"); + ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", ar->testmode); + + if (ar->testmode == 2) { + if (ar->hw.fw.utf == NULL) { + ath6kl_warn("testmode 2 not supported\n"); return -EOPNOTSUPP; } - filename = ar->hw.fw_tcmd; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.utf); + } else { + if (ar->hw.fw.tcmd == NULL) { + ath6kl_warn("testmode 1 not supported\n"); + return -EOPNOTSUPP; + } - set_bit(TESTMODE, &ar->flag); + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.tcmd); + } + + set_bit(TESTMODE, &ar->flag); - goto get_fw; + ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); + if (ret) { + ath6kl_err("Failed to get testmode %d firmware file %s: %d\n", + ar->testmode, filename, ret); + return ret; } - if (WARN_ON(ar->hw.fw == NULL)) + return 0; +} + +static int ath6kl_fetch_fw_file(struct ath6kl *ar) +{ + char filename[100]; + int ret; + + if (ar->fw != NULL) + return 0; + + /* FIXME: remove WARN_ON() as we won't support FW API 1 for long */ + if (WARN_ON(ar->hw.fw.fw == NULL)) return -EINVAL; - filename = ar->hw.fw; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.fw); -get_fw: ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); if (ret) { ath6kl_err("Failed to get firmware file %s: %d\n", @@ -794,16 +777,17 @@ get_fw: static int ath6kl_fetch_patch_file(struct ath6kl *ar) { - const char *filename; + char filename[100]; int ret; if (ar->fw_patch != NULL) return 0; - if (ar->hw.fw_patch == NULL) + if (ar->hw.fw.patch == NULL) return 0; - filename = ar->hw.fw_patch; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.patch); ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, &ar->fw_patch_len); @@ -816,6 +800,34 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar) return 0; } +static int ath6kl_fetch_testscript_file(struct ath6kl *ar) +{ + char filename[100]; + int ret; + + if (ar->testmode != 2) + return 0; + + if (ar->fw_testscript != NULL) + return 0; + + if (ar->hw.fw.testscript == NULL) + return 0; + + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.testscript); + + ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript, + &ar->fw_testscript_len); + if (ret) { + ath6kl_err("Failed to get testscript file %s: %d\n", + filename, ret); + return ret; + } + + return 0; +} + static int ath6kl_fetch_fw_api1(struct ath6kl *ar) { int ret; @@ -832,23 +844,24 @@ static int ath6kl_fetch_fw_api1(struct ath6kl *ar) if (ret) return ret; + ret = ath6kl_fetch_testscript_file(ar); + if (ret) + return ret; + return 0; } -static int ath6kl_fetch_fw_api2(struct ath6kl *ar) +static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) { size_t magic_len, len, ie_len; const struct firmware *fw; struct ath6kl_fw_ie *hdr; - const char *filename; + char filename[100]; const u8 *data; int ret, ie_id, i, index, bit; __le32 *val; - if (ar->hw.fw_api2 == NULL) - return -EOPNOTSUPP; - - filename = ar->hw.fw_api2; + snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name); ret = request_firmware(&fw, filename, ar->dev); if (ret) @@ -892,7 +905,7 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar) switch (ie_id) { case ATH6KL_FW_IE_OTP_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", - ie_len); + ie_len); ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); @@ -905,7 +918,11 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar) break; case ATH6KL_FW_IE_FW_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", - ie_len); + ie_len); + + /* in testmode we already might have a fw file */ + if (ar->fw != NULL) + break; ar->fw = kmemdup(data, ie_len, GFP_KERNEL); @@ -918,7 +935,7 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar) break; case ATH6KL_FW_IE_PATCH_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", - ie_len); + ie_len); ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); @@ -1010,7 +1027,7 @@ out: return ret; } -static int ath6kl_fetch_firmwares(struct ath6kl *ar) +int ath6kl_init_fetch_firmwares(struct ath6kl *ar) { int ret; @@ -1018,17 +1035,30 @@ static int ath6kl_fetch_firmwares(struct ath6kl *ar) if (ret) return ret; - ret = ath6kl_fetch_fw_api2(ar); + ret = ath6kl_fetch_testmode_file(ar); + if (ret) + return ret; + + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); if (ret == 0) { - ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n"); - return 0; + ar->fw_api = 3; + goto out; + } + + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API2_FILE); + if (ret == 0) { + ar->fw_api = 2; + goto out; } ret = ath6kl_fetch_fw_api1(ar); if (ret) return ret; - ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n"); + ar->fw_api = 1; + +out: + ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; } @@ -1049,22 +1079,14 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) */ if (ar->hw.board_addr != 0) { board_address = ar->hw.board_addr; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_data)), - (u8 *) &board_address, 4); + ath6kl_bmi_write_hi32(ar, hi_board_data, + board_address); } else { - ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_data)), - (u8 *) &board_address, 4); + ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); } /* determine where in target ram to write extended board data */ - ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_ext_data)), - (u8 *) &board_ext_address, 4); + ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); if (ar->target_type == TARGET_TYPE_AR6003 && board_ext_address == 0) { @@ -1076,6 +1098,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) case TARGET_TYPE_AR6003: board_data_size = AR6003_BOARD_DATA_SZ; board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; + if (ar->fw_board_len > (board_data_size + board_ext_data_size)) + board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ_V2; break; case TARGET_TYPE_AR6004: board_data_size = AR6004_BOARD_DATA_SZ; @@ -1107,10 +1131,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) /* record that extended board data is initialized */ param = (board_ext_data_size << 16) | 1; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_ext_data_config)), - (unsigned char *) ¶m, 4); + ath6kl_bmi_write_hi32(ar, hi_board_ext_data_config, param); } if (ar->fw_board_len < board_data_size) { @@ -1131,11 +1152,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) } /* record the fact that Board Data IS initialized */ - param = 1; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_data_initialized)), - (u8 *)¶m, 4); + ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1); return ret; } @@ -1162,10 +1179,7 @@ static int ath6kl_upload_otp(struct ath6kl *ar) } /* read firmware start address */ - ret = ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_app_start)), - (u8 *) &address, sizeof(address)); + ret = ath6kl_bmi_read_hi32(ar, hi_app_start, &address); if (ret) { ath6kl_err("Failed to read hi_app_start: %d\n", ret); @@ -1223,7 +1237,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) static int ath6kl_upload_patch(struct ath6kl *ar) { - u32 address, param; + u32 address; int ret; if (ar->fw_patch == NULL) @@ -1240,11 +1254,37 @@ static int ath6kl_upload_patch(struct ath6kl *ar) return ret; } - param = address; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_dset_list_head)), - (unsigned char *) ¶m, 4); + ath6kl_bmi_write_hi32(ar, hi_dset_list_head, address); + + return 0; +} + +static int ath6kl_upload_testscript(struct ath6kl *ar) +{ + u32 address; + int ret; + + if (ar->testmode != 2) + return 0; + + if (ar->fw_testscript == NULL) + return 0; + + address = ar->hw.testscript_addr; + + ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n", + address, ar->fw_testscript_len); + + ret = ath6kl_bmi_write(ar, address, ar->fw_testscript, + ar->fw_testscript_len); + if (ret) { + ath6kl_err("Failed to write testscript file: %d\n", ret); + return ret; + } + + ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address); + ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); + ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1); return 0; } @@ -1255,7 +1295,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) int status = 0; if (ar->target_type != TARGET_TYPE_AR6003 && - ar->target_type != TARGET_TYPE_AR6004) + ar->target_type != TARGET_TYPE_AR6004) return -EINVAL; /* temporarily disable system sleep */ @@ -1312,7 +1352,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; /* WAR to avoid SDIO CRC err */ - if (ar->version.target_ver == AR6003_HW_2_0_VERSION) { + if (ar->version.target_ver == AR6003_HW_2_0_VERSION || + ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { ath6kl_err("temporary war to avoid sdio crc error\n"); param = 0x20; @@ -1357,6 +1398,11 @@ static int ath6kl_init_upload(struct ath6kl *ar) if (status) return status; + /* Download the test script */ + status = ath6kl_upload_testscript(ar); + if (status) + return status; + /* Restore system sleep */ address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; status = ath6kl_bmi_reg_write(ar, address, sleep); @@ -1372,9 +1418,9 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; } -static int ath6kl_init_hw_params(struct ath6kl *ar) +int ath6kl_init_hw_params(struct ath6kl *ar) { - const struct ath6kl_hw *hw; + const struct ath6kl_hw *uninitialized_var(hw); int i; for (i = 0; i < ARRAY_SIZE(hw_list); i++) { @@ -1481,10 +1527,11 @@ int ath6kl_init_hw_start(struct ath6kl *ar) if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) { - ath6kl_info("%s %s fw %s%s\n", + ath6kl_info("%s %s fw %s api %d%s\n", ar->hw.name, ath6kl_init_get_hif_name(ar->hif_type), ar->wiphy->fw_version, + ar->fw_api, test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); } @@ -1549,173 +1596,7 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) return 0; } -int ath6kl_core_init(struct ath6kl *ar) -{ - struct ath6kl_bmi_target_info targ_info; - struct net_device *ndev; - int ret = 0, i; - - ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); - if (!ar->ath6kl_wq) - return -ENOMEM; - - ret = ath6kl_bmi_init(ar); - if (ret) - goto err_wq; - - /* - * Turn on power to get hardware (target) version and leave power - * on delibrately as we will boot the hardware anyway within few - * seconds. - */ - ret = ath6kl_hif_power_on(ar); - if (ret) - goto err_bmi_cleanup; - - ret = ath6kl_bmi_get_target_info(ar, &targ_info); - if (ret) - goto err_power_off; - - ar->version.target_ver = le32_to_cpu(targ_info.version); - ar->target_type = le32_to_cpu(targ_info.type); - ar->wiphy->hw_version = le32_to_cpu(targ_info.version); - - ret = ath6kl_init_hw_params(ar); - if (ret) - goto err_power_off; - - ar->htc_target = ath6kl_htc_create(ar); - - if (!ar->htc_target) { - ret = -ENOMEM; - goto err_power_off; - } - - ret = ath6kl_fetch_firmwares(ar); - if (ret) - goto err_htc_cleanup; - - /* FIXME: we should free all firmwares in the error cases below */ - - /* Indicate that WMI is enabled (although not ready yet) */ - set_bit(WMI_ENABLED, &ar->flag); - ar->wmi = ath6kl_wmi_init(ar); - if (!ar->wmi) { - ath6kl_err("failed to initialize wmi\n"); - ret = -EIO; - goto err_htc_cleanup; - } - - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); - - ret = ath6kl_register_ieee80211_hw(ar); - if (ret) - goto err_node_cleanup; - - ret = ath6kl_debug_init(ar); - if (ret) { - wiphy_unregister(ar->wiphy); - goto err_node_cleanup; - } - - for (i = 0; i < ar->vif_max; i++) - ar->avail_idx_map |= BIT(i); - - rtnl_lock(); - - /* Add an initial station interface */ - ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, - INFRA_NETWORK); - - rtnl_unlock(); - - if (!ndev) { - ath6kl_err("Failed to instantiate a network device\n"); - ret = -ENOMEM; - wiphy_unregister(ar->wiphy); - goto err_debug_init; - } - - - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", - __func__, ndev->name, ndev, ar); - - /* setup access class priority mappings */ - ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ - ar->ac_stream_pri_map[WMM_AC_BE] = 1; - ar->ac_stream_pri_map[WMM_AC_VI] = 2; - ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ - - /* give our connected endpoints some buffers */ - ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); - ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); - - /* allocate some buffers that handle larger AMSDU frames */ - ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); - - ath6kl_cookie_init(ar); - - ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | - ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; - - if (suspend_cutpower) - ar->conf_flags |= ATH6KL_CONF_SUSPEND_CUTPOWER; - - ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | - WIPHY_FLAG_HAVE_AP_SME | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - - if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) - ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; - - ar->wiphy->probe_resp_offload = - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; - - set_bit(FIRST_BOOT, &ar->flag); - - ret = ath6kl_init_hw_start(ar); - if (ret) { - ath6kl_err("Failed to start hardware: %d\n", ret); - goto err_rxbuf_cleanup; - } - - /* - * Set mac address which is received in ready event - * FIXME: Move to ath6kl_interface_add() - */ - memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); - - return ret; - -err_rxbuf_cleanup: - ath6kl_htc_flush_rx_buf(ar->htc_target); - ath6kl_cleanup_amsdu_rxbufs(ar); - rtnl_lock(); - ath6kl_deinit_if_data(netdev_priv(ndev)); - rtnl_unlock(); - wiphy_unregister(ar->wiphy); -err_debug_init: - ath6kl_debug_cleanup(ar); -err_node_cleanup: - ath6kl_wmi_shutdown(ar->wmi); - clear_bit(WMI_ENABLED, &ar->flag); - ar->wmi = NULL; -err_htc_cleanup: - ath6kl_htc_cleanup(ar->htc_target); -err_power_off: - ath6kl_hif_power_off(ar); -err_bmi_cleanup: - ath6kl_bmi_cleanup(ar); -err_wq: - destroy_workqueue(ar->ath6kl_wq); - - return ret; -} - +/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) { static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -1747,6 +1628,7 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) void ath6kl_stop_txrx(struct ath6kl *ar) { struct ath6kl_vif *vif, *tmp_vif; + int i; set_bit(DESTROY_IN_PROGRESS, &ar->flag); @@ -1755,13 +1637,16 @@ void ath6kl_stop_txrx(struct ath6kl *ar) return; } + for (i = 0; i < AP_MAX_NUM_STA; i++) + aggr_reset_state(ar->sta_list[i].aggr_conn); + spin_lock_bh(&ar->list_lock); list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { list_del(&vif->list); spin_unlock_bh(&ar->list_lock); ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); rtnl_lock(); - ath6kl_deinit_if_data(vif); + ath6kl_cfg80211_vif_cleanup(vif); rtnl_unlock(); spin_lock_bh(&ar->list_lock); } @@ -1791,8 +1676,11 @@ void ath6kl_stop_txrx(struct ath6kl *ar) * configure NOT to reset the target during a debug session. */ ath6kl_dbg(ATH6KL_DBG_TRC, - "attempting to reset target on instance destroy\n"); + "attempting to reset target on instance destroy\n"); ath6kl_reset_device(ar, ar->target_type, true, true); clear_bit(WLAN_ENABLED, &ar->flag); + + up(&ar->sem); } +EXPORT_SYMBOL(ath6kl_stop_txrx);