brintos

brintos / linux-shallow public Read only

0
0
Text · 47.2 KiB · 15f455a Raw
1946 lines · c
1 2/*3 * Copyright (c) 2011 Atheros Communications Inc.4 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.5 *6 * Permission to use, copy, modify, and/or distribute this software for any7 * purpose with or without fee is hereby granted, provided that the above8 * copyright notice and this permission notice appear in all copies.9 *10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17 */18 19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt20 21#include <linux/moduleparam.h>22#include <linux/errno.h>23#include <linux/export.h>24#include <linux/of.h>25#include <linux/mmc/sdio_func.h>26#include <linux/vmalloc.h>27 28#include "core.h"29#include "cfg80211.h"30#include "target.h"31#include "debug.h"32#include "hif-ops.h"33#include "htc-ops.h"34 35static const struct ath6kl_hw hw_list[] = {36	{37		.id				= AR6003_HW_2_0_VERSION,38		.name				= "ar6003 hw 2.0",39		.dataset_patch_addr		= 0x57e884,40		.app_load_addr			= 0x543180,41		.board_ext_data_addr		= 0x57e500,42		.reserved_ram_size		= 6912,43		.refclk_hz			= 26000000,44		.uarttx_pin			= 8,45		.flags				= ATH6KL_HW_SDIO_CRC_ERROR_WAR,46 47		/* hw2.0 needs override address hardcoded */48		.app_start_override_addr	= 0x944C00,49 50		.fw = {51			.dir		= AR6003_HW_2_0_FW_DIR,52			.otp		= AR6003_HW_2_0_OTP_FILE,53			.fw		= AR6003_HW_2_0_FIRMWARE_FILE,54			.tcmd		= AR6003_HW_2_0_TCMD_FIRMWARE_FILE,55			.patch		= AR6003_HW_2_0_PATCH_FILE,56		},57 58		.fw_board		= AR6003_HW_2_0_BOARD_DATA_FILE,59		.fw_default_board	= AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,60	},61	{62		.id				= AR6003_HW_2_1_1_VERSION,63		.name				= "ar6003 hw 2.1.1",64		.dataset_patch_addr		= 0x57ff74,65		.app_load_addr			= 0x1234,66		.board_ext_data_addr		= 0x542330,67		.reserved_ram_size		= 512,68		.refclk_hz			= 26000000,69		.uarttx_pin			= 8,70		.testscript_addr		= 0x57ef74,71		.flags				= ATH6KL_HW_SDIO_CRC_ERROR_WAR,72 73		.fw = {74			.dir		= AR6003_HW_2_1_1_FW_DIR,75			.otp		= AR6003_HW_2_1_1_OTP_FILE,76			.fw		= AR6003_HW_2_1_1_FIRMWARE_FILE,77			.tcmd		= AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,78			.patch		= AR6003_HW_2_1_1_PATCH_FILE,79			.utf		= AR6003_HW_2_1_1_UTF_FIRMWARE_FILE,80			.testscript	= AR6003_HW_2_1_1_TESTSCRIPT_FILE,81		},82 83		.fw_board		= AR6003_HW_2_1_1_BOARD_DATA_FILE,84		.fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,85	},86	{87		.id				= AR6004_HW_1_0_VERSION,88		.name				= "ar6004 hw 1.0",89		.dataset_patch_addr		= 0x57e884,90		.app_load_addr			= 0x1234,91		.board_ext_data_addr		= 0x437000,92		.reserved_ram_size		= 19456,93		.board_addr			= 0x433900,94		.refclk_hz			= 26000000,95		.uarttx_pin			= 11,96		.flags				= 0,97 98		.fw = {99			.dir		= AR6004_HW_1_0_FW_DIR,100			.fw		= AR6004_HW_1_0_FIRMWARE_FILE,101		},102 103		.fw_board		= AR6004_HW_1_0_BOARD_DATA_FILE,104		.fw_default_board	= AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,105	},106	{107		.id				= AR6004_HW_1_1_VERSION,108		.name				= "ar6004 hw 1.1",109		.dataset_patch_addr		= 0x57e884,110		.app_load_addr			= 0x1234,111		.board_ext_data_addr		= 0x437000,112		.reserved_ram_size		= 11264,113		.board_addr			= 0x43d400,114		.refclk_hz			= 40000000,115		.uarttx_pin			= 11,116		.flags				= 0,117		.fw = {118			.dir		= AR6004_HW_1_1_FW_DIR,119			.fw		= AR6004_HW_1_1_FIRMWARE_FILE,120		},121 122		.fw_board		= AR6004_HW_1_1_BOARD_DATA_FILE,123		.fw_default_board	= AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,124	},125	{126		.id				= AR6004_HW_1_2_VERSION,127		.name				= "ar6004 hw 1.2",128		.dataset_patch_addr		= 0x436ecc,129		.app_load_addr			= 0x1234,130		.board_ext_data_addr		= 0x437000,131		.reserved_ram_size		= 9216,132		.board_addr			= 0x435c00,133		.refclk_hz			= 40000000,134		.uarttx_pin			= 11,135		.flags				= 0,136 137		.fw = {138			.dir		= AR6004_HW_1_2_FW_DIR,139			.fw		= AR6004_HW_1_2_FIRMWARE_FILE,140		},141		.fw_board		= AR6004_HW_1_2_BOARD_DATA_FILE,142		.fw_default_board	= AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,143	},144	{145		.id				= AR6004_HW_1_3_VERSION,146		.name				= "ar6004 hw 1.3",147		.dataset_patch_addr		= 0x437860,148		.app_load_addr			= 0x1234,149		.board_ext_data_addr		= 0x437000,150		.reserved_ram_size		= 7168,151		.board_addr			= 0x436400,152		.refclk_hz                      = 0,153		.uarttx_pin                     = 11,154		.flags				= 0,155 156		.fw = {157			.dir            = AR6004_HW_1_3_FW_DIR,158			.fw             = AR6004_HW_1_3_FIRMWARE_FILE,159			.tcmd	        = AR6004_HW_1_3_TCMD_FIRMWARE_FILE,160			.utf		= AR6004_HW_1_3_UTF_FIRMWARE_FILE,161			.testscript	= AR6004_HW_1_3_TESTSCRIPT_FILE,162		},163 164		.fw_board               = AR6004_HW_1_3_BOARD_DATA_FILE,165		.fw_default_board       = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE,166	},167	{168		.id				= AR6004_HW_3_0_VERSION,169		.name				= "ar6004 hw 3.0",170		.dataset_patch_addr		= 0,171		.app_load_addr			= 0x1234,172		.board_ext_data_addr		= 0,173		.reserved_ram_size		= 7168,174		.board_addr			= 0x436400,175		.testscript_addr		= 0,176		.uarttx_pin			= 11,177		.flags				= 0,178 179		.fw = {180			.dir		= AR6004_HW_3_0_FW_DIR,181			.fw		= AR6004_HW_3_0_FIRMWARE_FILE,182			.tcmd	        = AR6004_HW_3_0_TCMD_FIRMWARE_FILE,183			.utf		= AR6004_HW_3_0_UTF_FIRMWARE_FILE,184			.testscript	= AR6004_HW_3_0_TESTSCRIPT_FILE,185		},186 187		.fw_board		= AR6004_HW_3_0_BOARD_DATA_FILE,188		.fw_default_board	= AR6004_HW_3_0_DEFAULT_BOARD_DATA_FILE,189	},190};191 192/*193 * Include definitions here that can be used to tune the WLAN module194 * behavior. Different customers can tune the behavior as per their needs,195 * here.196 */197 198/*199 * This configuration item enable/disable keepalive support.200 * Keepalive support: In the absence of any data traffic to AP, null201 * frames will be sent to the AP at periodic interval, to keep the association202 * active. This configuration item defines the periodic interval.203 * Use value of zero to disable keepalive support204 * Default: 60 seconds205 */206#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60207 208/*209 * This configuration item sets the value of disconnect timeout210 * Firmware delays sending the disconnec event to the host for this211 * timeout after is gets disconnected from the current AP.212 * If the firmware successly roams within the disconnect timeout213 * it sends a new connect event214 */215#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10216 217 218#define ATH6KL_DATA_OFFSET    64219struct sk_buff *ath6kl_buf_alloc(int size)220{221	struct sk_buff *skb;222	u16 reserved;223 224	/* Add chacheline space at front and back of buffer */225	reserved = roundup((2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +226		   sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES, 4);227	skb = dev_alloc_skb(size + reserved);228 229	if (skb)230		skb_reserve(skb, reserved - L1_CACHE_BYTES);231	return skb;232}233 234void ath6kl_init_profile_info(struct ath6kl_vif *vif)235{236	vif->ssid_len = 0;237	memset(vif->ssid, 0, sizeof(vif->ssid));238 239	vif->dot11_auth_mode = OPEN_AUTH;240	vif->auth_mode = NONE_AUTH;241	vif->prwise_crypto = NONE_CRYPT;242	vif->prwise_crypto_len = 0;243	vif->grp_crypto = NONE_CRYPT;244	vif->grp_crypto_len = 0;245	memset(vif->wep_key_list, 0, sizeof(vif->wep_key_list));246	memset(vif->req_bssid, 0, sizeof(vif->req_bssid));247	memset(vif->bssid, 0, sizeof(vif->bssid));248	vif->bss_ch = 0;249}250 251static int ath6kl_set_host_app_area(struct ath6kl *ar)252{253	u32 address, data;254	struct host_app_area host_app_area;255 256	/* Fetch the address of the host_app_area_s257	 * instance in the host interest area */258	address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest));259	address = TARG_VTOP(ar->target_type, address);260 261	if (ath6kl_diag_read32(ar, address, &data))262		return -EIO;263 264	address = TARG_VTOP(ar->target_type, data);265	host_app_area.wmi_protocol_ver = cpu_to_le32(WMI_PROTOCOL_VERSION);266	if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area,267			      sizeof(struct host_app_area)))268		return -EIO;269 270	return 0;271}272 273static inline void set_ac2_ep_map(struct ath6kl *ar,274				  u8 ac,275				  enum htc_endpoint_id ep)276{277	ar->ac2ep_map[ac] = ep;278	ar->ep2ac_map[ep] = ac;279}280 281/* connect to a service */282static int ath6kl_connectservice(struct ath6kl *ar,283				 struct htc_service_connect_req  *con_req,284				 char *desc)285{286	int status;287	struct htc_service_connect_resp response;288 289	memset(&response, 0, sizeof(response));290 291	status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response);292	if (status) {293		ath6kl_err("failed to connect to %s service status:%d\n",294			   desc, status);295		return status;296	}297 298	switch (con_req->svc_id) {299	case WMI_CONTROL_SVC:300		if (test_bit(WMI_ENABLED, &ar->flag))301			ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint);302		ar->ctrl_ep = response.endpoint;303		break;304	case WMI_DATA_BE_SVC:305		set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint);306		break;307	case WMI_DATA_BK_SVC:308		set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint);309		break;310	case WMI_DATA_VI_SVC:311		set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint);312		break;313	case WMI_DATA_VO_SVC:314		set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint);315		break;316	default:317		ath6kl_err("service id is not mapped %d\n", con_req->svc_id);318		return -EINVAL;319	}320 321	return 0;322}323 324static int ath6kl_init_service_ep(struct ath6kl *ar)325{326	struct htc_service_connect_req connect;327 328	memset(&connect, 0, sizeof(connect));329 330	/* these fields are the same for all service endpoints */331	connect.ep_cb.tx_comp_multi = ath6kl_tx_complete;332	connect.ep_cb.rx = ath6kl_rx;333	connect.ep_cb.rx_refill = ath6kl_rx_refill;334	connect.ep_cb.tx_full = ath6kl_tx_queue_full;335 336	/*337	 * Set the max queue depth so that our ath6kl_tx_queue_full handler338	 * gets called.339	*/340	connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH;341	connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4;342	if (!connect.ep_cb.rx_refill_thresh)343		connect.ep_cb.rx_refill_thresh++;344 345	/* connect to control service */346	connect.svc_id = WMI_CONTROL_SVC;347	if (ath6kl_connectservice(ar, &connect, "WMI CONTROL"))348		return -EIO;349 350	connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN;351 352	/*353	 * Limit the HTC message size on the send path, although e can354	 * receive A-MSDU frames of 4K, we will only send ethernet-sized355	 * (802.3) frames on the send path.356	 */357	connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH;358 359	/*360	 * To reduce the amount of committed memory for larger A_MSDU361	 * frames, use the recv-alloc threshold mechanism for larger362	 * packets.363	 */364	connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE;365	connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf;366 367	/*368	 * For the remaining data services set the connection flag to369	 * reduce dribbling, if configured to do so.370	 */371	connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB;372	connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK;373	connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF;374 375	connect.svc_id = WMI_DATA_BE_SVC;376 377	if (ath6kl_connectservice(ar, &connect, "WMI DATA BE"))378		return -EIO;379 380	/* connect to back-ground map this to WMI LOW_PRI */381	connect.svc_id = WMI_DATA_BK_SVC;382	if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))383		return -EIO;384 385	/* connect to Video service, map this to HI PRI */386	connect.svc_id = WMI_DATA_VI_SVC;387	if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))388		return -EIO;389 390	/*391	 * Connect to VO service, this is currently not mapped to a WMI392	 * priority stream due to historical reasons. WMI originally393	 * defined 3 priorities over 3 mailboxes We can change this when394	 * WMI is reworked so that priorities are not dependent on395	 * mailboxes.396	 */397	connect.svc_id = WMI_DATA_VO_SVC;398	if (ath6kl_connectservice(ar, &connect, "WMI DATA VO"))399		return -EIO;400 401	return 0;402}403 404void ath6kl_init_control_info(struct ath6kl_vif *vif)405{406	ath6kl_init_profile_info(vif);407	vif->def_txkey_index = 0;408	memset(vif->wep_key_list, 0, sizeof(vif->wep_key_list));409	vif->ch_hint = 0;410}411 412/*413 * Set HTC/Mbox operational parameters, this can only be called when the414 * target is in the BMI phase.415 */416static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,417				 u8 htc_ctrl_buf)418{419	int status;420	u32 blk_size;421 422	blk_size = ar->mbox_info.block_size;423 424	if (htc_ctrl_buf)425		blk_size |=  ((u32)htc_ctrl_buf) << 16;426 427	/* set the host interest area for the block size */428	status = ath6kl_bmi_write_hi32(ar, hi_mbox_io_block_sz, blk_size);429	if (status) {430		ath6kl_err("bmi_write_memory for IO block size failed\n");431		goto out;432	}433 434	ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n",435		   blk_size,436		   ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz)));437 438	if (mbox_isr_yield_val) {439		/* set the host interest area for the mbox ISR yield limit */440		status = ath6kl_bmi_write_hi32(ar, hi_mbox_isr_yield_limit,441					       mbox_isr_yield_val);442		if (status) {443			ath6kl_err("bmi_write_memory for yield limit failed\n");444			goto out;445		}446	}447 448out:449	return status;450}451 452static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)453{454	int ret;455 456	/*457	 * Configure the device for rx dot11 header rules. "0,0" are the458	 * default values. Required if checksum offload is needed. Set459	 * RxMetaVersion to 2.460	 */461	ret = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx,462						 ar->rx_meta_ver, 0, 0);463	if (ret) {464		ath6kl_err("unable to set the rx frame format: %d\n", ret);465		return ret;466	}467 468	if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) {469		ret = ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1,470					      IGNORE_PS_FAIL_DURING_SCAN);471		if (ret) {472			ath6kl_err("unable to set power save fail event policy: %d\n",473				   ret);474			return ret;475		}476	}477 478	if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) {479		ret = ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0,480						   WMI_FOLLOW_BARKER_IN_ERP);481		if (ret) {482			ath6kl_err("unable to set barker preamble policy: %d\n",483				   ret);484			return ret;485		}486	}487 488	ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx,489					   WLAN_CONFIG_KEEP_ALIVE_INTERVAL);490	if (ret) {491		ath6kl_err("unable to set keep alive interval: %d\n", ret);492		return ret;493	}494 495	ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, idx,496					 WLAN_CONFIG_DISCONNECT_TIMEOUT);497	if (ret) {498		ath6kl_err("unable to set disconnect timeout: %d\n", ret);499		return ret;500	}501 502	if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) {503		ret = ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED);504		if (ret) {505			ath6kl_err("unable to set txop bursting: %d\n", ret);506			return ret;507		}508	}509 510	if (ar->p2p && (ar->vif_max == 1 || idx)) {511		ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,512					      P2P_FLAG_CAPABILITIES_REQ |513					      P2P_FLAG_MACADDR_REQ |514					      P2P_FLAG_HMODEL_REQ);515		if (ret) {516			ath6kl_dbg(ATH6KL_DBG_TRC,517				   "failed to request P2P capabilities (%d) - assuming P2P not supported\n",518				   ret);519			ar->p2p = false;520		}521	}522 523	if (ar->p2p && (ar->vif_max == 1 || idx)) {524		/* Enable Probe Request reporting for P2P */525		ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);526		if (ret) {527			ath6kl_dbg(ATH6KL_DBG_TRC,528				   "failed to enable Probe Request reporting (%d)\n",529				   ret);530		}531	}532 533	return ret;534}535 536int ath6kl_configure_target(struct ath6kl *ar)537{538	u32 param, ram_reserved_size;539	u8 fw_iftype, fw_mode = 0, fw_submode = 0;540	int i, status;541 542	param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG);543	if (ath6kl_bmi_write_hi32(ar, hi_serial_enable, param)) {544		ath6kl_err("bmi_write_memory for uart debug failed\n");545		return -EIO;546	}547 548	/*549	 * Note: Even though the firmware interface type is550	 * chosen as BSS_STA for all three interfaces, can551	 * be configured to IBSS/AP as long as the fw submode552	 * remains normal mode (0 - AP, STA and IBSS). But553	 * due to an target assert in firmware only one interface is554	 * configured for now.555	 */556	fw_iftype = HI_OPTION_FW_MODE_BSS_STA;557 558	for (i = 0; i < ar->vif_max; i++)559		fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);560 561	/*562	 * Submodes when fw does not support dynamic interface563	 * switching:564	 *		vif[0] - AP/STA/IBSS565	 *		vif[1] - "P2P dev"/"P2P GO"/"P2P Client"566	 *		vif[2] - "P2P dev"/"P2P GO"/"P2P Client"567	 * Otherwise, All the interface are initialized to p2p dev.568	 */569 570	if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,571		     ar->fw_capabilities)) {572		for (i = 0; i < ar->vif_max; i++)573			fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<574				(i * HI_OPTION_FW_SUBMODE_BITS);575	} else {576		for (i = 0; i < ar->max_norm_iface; i++)577			fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<578				(i * HI_OPTION_FW_SUBMODE_BITS);579 580		for (i = ar->max_norm_iface; i < ar->vif_max; i++)581			fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<582				(i * HI_OPTION_FW_SUBMODE_BITS);583 584		if (ar->p2p && ar->vif_max == 1)585			fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;586	}587 588	if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest,589				  HTC_PROTOCOL_VERSION) != 0) {590		ath6kl_err("bmi_write_memory for htc version failed\n");591		return -EIO;592	}593 594	/* set the firmware mode to STA/IBSS/AP */595	param = 0;596 597	if (ath6kl_bmi_read_hi32(ar, hi_option_flag, &param) != 0) {598		ath6kl_err("bmi_read_memory for setting fwmode failed\n");599		return -EIO;600	}601 602	param |= (ar->vif_max << HI_OPTION_NUM_DEV_SHIFT);603	param |= fw_mode << HI_OPTION_FW_MODE_SHIFT;604	param |= fw_submode << HI_OPTION_FW_SUBMODE_SHIFT;605 606	param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);607	param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);608 609	if (ath6kl_bmi_write_hi32(ar, hi_option_flag, param) != 0) {610		ath6kl_err("bmi_write_memory for setting fwmode failed\n");611		return -EIO;612	}613 614	ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n");615 616	/*617	 * Hardcode the address use for the extended board data618	 * Ideally this should be pre-allocate by the OS at boot time619	 * But since it is a new feature and board data is loaded620	 * at init time, we have to workaround this from host.621	 * It is difficult to patch the firmware boot code,622	 * but possible in theory.623	 */624 625	if ((ar->target_type == TARGET_TYPE_AR6003) ||626	    (ar->version.target_ver == AR6004_HW_1_3_VERSION) ||627	    (ar->version.target_ver == AR6004_HW_3_0_VERSION)) {628		param = ar->hw.board_ext_data_addr;629		ram_reserved_size = ar->hw.reserved_ram_size;630 631		if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {632			ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");633			return -EIO;634		}635 636		if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,637					  ram_reserved_size) != 0) {638			ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");639			return -EIO;640		}641	}642 643	/* set the block size for the target */644	if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0))645		/* use default number of control buffers */646		return -EIO;647 648	/* Configure GPIO AR600x UART */649	status = ath6kl_bmi_write_hi32(ar, hi_dbg_uart_txpin,650				       ar->hw.uarttx_pin);651	if (status)652		return status;653 654	/* Only set the baud rate if we're actually doing debug */655	if (ar->conf_flags & ATH6KL_CONF_UART_DEBUG) {656		status = ath6kl_bmi_write_hi32(ar, hi_desired_baud_rate,657					       ar->hw.uarttx_rate);658		if (status)659			return status;660	}661 662	/* Configure target refclk_hz */663	if (ar->hw.refclk_hz != 0) {664		status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz,665					       ar->hw.refclk_hz);666		if (status)667			return status;668	}669 670	return 0;671}672 673/* firmware upload */674static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,675			 u8 **fw, size_t *fw_len)676{677	const struct firmware *fw_entry;678	int ret;679 680	ret = request_firmware(&fw_entry, filename, ar->dev);681	if (ret)682		return ret;683 684	*fw_len = fw_entry->size;685	*fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);686 687	if (*fw == NULL)688		ret = -ENOMEM;689 690	release_firmware(fw_entry);691 692	return ret;693}694 695#ifdef CONFIG_OF696/*697 * Check the device tree for a board-id and use it to construct698 * the pathname to the firmware file.  Used (for now) to find a699 * fallback to the "bdata.bin" file--typically a symlink to the700 * appropriate board-specific file.701 */702static bool check_device_tree(struct ath6kl *ar)703{704	static const char *board_id_prop = "atheros,board-id";705	struct device_node *node;706	char board_filename[64];707	const char *board_id;708	int ret;709 710	for_each_compatible_node(node, NULL, "atheros,ath6kl") {711		board_id = of_get_property(node, board_id_prop, NULL);712		if (board_id == NULL) {713			ath6kl_warn("No \"%s\" property on %pOFn node.\n",714				    board_id_prop, node);715			continue;716		}717		snprintf(board_filename, sizeof(board_filename),718			 "%s/bdata.%s.bin", ar->hw.fw.dir, board_id);719 720		ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board,721				    &ar->fw_board_len);722		if (ret) {723			ath6kl_err("Failed to get DT board file %s: %d\n",724				   board_filename, ret);725			continue;726		}727		of_node_put(node);728		return true;729	}730	return false;731}732#else733static bool check_device_tree(struct ath6kl *ar)734{735	return false;736}737#endif /* CONFIG_OF */738 739static int ath6kl_fetch_board_file(struct ath6kl *ar)740{741	const char *filename;742	int ret;743 744	if (ar->fw_board != NULL)745		return 0;746 747	if (WARN_ON(ar->hw.fw_board == NULL))748		return -EINVAL;749 750	filename = ar->hw.fw_board;751 752	ret = ath6kl_get_fw(ar, filename, &ar->fw_board,753			    &ar->fw_board_len);754	if (ret == 0) {755		/* managed to get proper board file */756		return 0;757	}758 759	if (check_device_tree(ar)) {760		/* got board file from device tree */761		return 0;762	}763 764	/* there was no proper board file, try to use default instead */765	ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",766		    filename, ret);767 768	filename = ar->hw.fw_default_board;769 770	ret = ath6kl_get_fw(ar, filename, &ar->fw_board,771			    &ar->fw_board_len);772	if (ret) {773		ath6kl_err("Failed to get default board file %s: %d\n",774			   filename, ret);775		return ret;776	}777 778	ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n");779	ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n");780 781	return 0;782}783 784static int ath6kl_fetch_otp_file(struct ath6kl *ar)785{786	char filename[100];787	int ret;788 789	if (ar->fw_otp != NULL)790		return 0;791 792	if (ar->hw.fw.otp == NULL) {793		ath6kl_dbg(ATH6KL_DBG_BOOT,794			   "no OTP file configured for this hw\n");795		return 0;796	}797 798	snprintf(filename, sizeof(filename), "%s/%s",799		 ar->hw.fw.dir, ar->hw.fw.otp);800 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	return 0;810}811 812static int ath6kl_fetch_testmode_file(struct ath6kl *ar)813{814	char filename[100];815	int ret;816 817	if (ar->testmode == 0)818		return 0;819 820	ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", ar->testmode);821 822	if (ar->testmode == 2) {823		if (ar->hw.fw.utf == NULL) {824			ath6kl_warn("testmode 2 not supported\n");825			return -EOPNOTSUPP;826		}827 828		snprintf(filename, sizeof(filename), "%s/%s",829			 ar->hw.fw.dir, ar->hw.fw.utf);830	} else {831		if (ar->hw.fw.tcmd == NULL) {832			ath6kl_warn("testmode 1 not supported\n");833			return -EOPNOTSUPP;834		}835 836		snprintf(filename, sizeof(filename), "%s/%s",837			 ar->hw.fw.dir, ar->hw.fw.tcmd);838	}839 840	set_bit(TESTMODE, &ar->flag);841 842	ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);843	if (ret) {844		ath6kl_err("Failed to get testmode %d firmware file %s: %d\n",845			   ar->testmode, filename, ret);846		return ret;847	}848 849	return 0;850}851 852static int ath6kl_fetch_fw_file(struct ath6kl *ar)853{854	char filename[100];855	int ret;856 857	if (ar->fw != NULL)858		return 0;859 860	/* FIXME: remove WARN_ON() as we won't support FW API 1 for long */861	if (WARN_ON(ar->hw.fw.fw == NULL))862		return -EINVAL;863 864	snprintf(filename, sizeof(filename), "%s/%s",865		 ar->hw.fw.dir, ar->hw.fw.fw);866 867	ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);868	if (ret) {869		ath6kl_err("Failed to get firmware file %s: %d\n",870			   filename, ret);871		return ret;872	}873 874	return 0;875}876 877static int ath6kl_fetch_patch_file(struct ath6kl *ar)878{879	char filename[100];880	int ret;881 882	if (ar->fw_patch != NULL)883		return 0;884 885	if (ar->hw.fw.patch == NULL)886		return 0;887 888	snprintf(filename, sizeof(filename), "%s/%s",889		 ar->hw.fw.dir, ar->hw.fw.patch);890 891	ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,892			    &ar->fw_patch_len);893	if (ret) {894		ath6kl_err("Failed to get patch file %s: %d\n",895			   filename, ret);896		return ret;897	}898 899	return 0;900}901 902static int ath6kl_fetch_testscript_file(struct ath6kl *ar)903{904	char filename[100];905	int ret;906 907	if (ar->testmode != 2)908		return 0;909 910	if (ar->fw_testscript != NULL)911		return 0;912 913	if (ar->hw.fw.testscript == NULL)914		return 0;915 916	snprintf(filename, sizeof(filename), "%s/%s",917		 ar->hw.fw.dir, ar->hw.fw.testscript);918 919	ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript,920				&ar->fw_testscript_len);921	if (ret) {922		ath6kl_err("Failed to get testscript file %s: %d\n",923			   filename, ret);924		return ret;925	}926 927	return 0;928}929 930static int ath6kl_fetch_fw_api1(struct ath6kl *ar)931{932	int ret;933 934	ret = ath6kl_fetch_otp_file(ar);935	if (ret)936		return ret;937 938	ret = ath6kl_fetch_fw_file(ar);939	if (ret)940		return ret;941 942	ret = ath6kl_fetch_patch_file(ar);943	if (ret)944		return ret;945 946	ret = ath6kl_fetch_testscript_file(ar);947	if (ret)948		return ret;949 950	return 0;951}952 953static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)954{955	size_t magic_len, len, ie_len;956	const struct firmware *fw;957	struct ath6kl_fw_ie *hdr;958	char filename[100];959	const u8 *data;960	int ret, ie_id, i, index, bit;961	__le32 *val;962 963	snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name);964 965	ret = request_firmware(&fw, filename, ar->dev);966	if (ret) {967		ath6kl_err("Failed request firmware, rv: %d\n", ret);968		return ret;969	}970 971	data = fw->data;972	len = fw->size;973 974	/* magic also includes the null byte, check that as well */975	magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;976 977	if (len < magic_len) {978		ath6kl_err("Magic length is invalid, len: %zd  magic_len: %zd\n",979			   len, magic_len);980		ret = -EINVAL;981		goto out;982	}983 984	if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {985		ath6kl_err("Magic is invalid, magic_len: %zd\n",986			   magic_len);987		ret = -EINVAL;988		goto out;989	}990 991	len -= magic_len;992	data += magic_len;993 994	/* loop elements */995	while (len > sizeof(struct ath6kl_fw_ie)) {996		/* hdr is unaligned! */997		hdr = (struct ath6kl_fw_ie *) data;998 999		ie_id = le32_to_cpup(&hdr->id);1000		ie_len = le32_to_cpup(&hdr->len);1001 1002		len -= sizeof(*hdr);1003		data += sizeof(*hdr);1004 1005		ath6kl_dbg(ATH6KL_DBG_BOOT, "ie-id: %d  len: %zd (0x%zx)\n",1006			   ie_id, ie_len, ie_len);1007 1008		if (len < ie_len) {1009			ath6kl_err("IE len is invalid, len: %zd  ie_len: %zd  ie-id: %d\n",1010				   len, ie_len, ie_id);1011			ret = -EINVAL;1012			goto out;1013		}1014 1015		switch (ie_id) {1016		case ATH6KL_FW_IE_FW_VERSION:1017			strscpy(ar->wiphy->fw_version, data,1018				min(sizeof(ar->wiphy->fw_version), ie_len+1));1019 1020			ath6kl_dbg(ATH6KL_DBG_BOOT,1021				   "found fw version %s\n",1022				    ar->wiphy->fw_version);1023			break;1024		case ATH6KL_FW_IE_OTP_IMAGE:1025			ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",1026				   ie_len);1027 1028			ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);1029 1030			if (ar->fw_otp == NULL) {1031				ath6kl_err("fw_otp cannot be allocated\n");1032				ret = -ENOMEM;1033				goto out;1034			}1035 1036			ar->fw_otp_len = ie_len;1037			break;1038		case ATH6KL_FW_IE_FW_IMAGE:1039			ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n",1040				   ie_len);1041 1042			/* in testmode we already might have a fw file */1043			if (ar->fw != NULL)1044				break;1045 1046			ar->fw = vmalloc(ie_len);1047 1048			if (ar->fw == NULL) {1049				ath6kl_err("fw storage cannot be allocated, len: %zd\n", ie_len);1050				ret = -ENOMEM;1051				goto out;1052			}1053 1054			memcpy(ar->fw, data, ie_len);1055			ar->fw_len = ie_len;1056			break;1057		case ATH6KL_FW_IE_PATCH_IMAGE:1058			ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n",1059				   ie_len);1060 1061			ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);1062 1063			if (ar->fw_patch == NULL) {1064				ath6kl_err("fw_patch storage cannot be allocated, len: %zd\n", ie_len);1065				ret = -ENOMEM;1066				goto out;1067			}1068 1069			ar->fw_patch_len = ie_len;1070			break;1071		case ATH6KL_FW_IE_RESERVED_RAM_SIZE:1072			val = (__le32 *) data;1073			ar->hw.reserved_ram_size = le32_to_cpup(val);1074 1075			ath6kl_dbg(ATH6KL_DBG_BOOT,1076				   "found reserved ram size ie %d\n",1077				   ar->hw.reserved_ram_size);1078			break;1079		case ATH6KL_FW_IE_CAPABILITIES:1080			ath6kl_dbg(ATH6KL_DBG_BOOT,1081				   "found firmware capabilities ie (%zd B)\n",1082				   ie_len);1083 1084			for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {1085				index = i / 8;1086				bit = i % 8;1087 1088				if (index == ie_len)1089					break;1090 1091				if (data[index] & (1 << bit))1092					__set_bit(i, ar->fw_capabilities);1093			}1094 1095			ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "",1096					ar->fw_capabilities,1097					sizeof(ar->fw_capabilities));1098			break;1099		case ATH6KL_FW_IE_PATCH_ADDR:1100			if (ie_len != sizeof(*val))1101				break;1102 1103			val = (__le32 *) data;1104			ar->hw.dataset_patch_addr = le32_to_cpup(val);1105 1106			ath6kl_dbg(ATH6KL_DBG_BOOT,1107				   "found patch address ie 0x%x\n",1108				   ar->hw.dataset_patch_addr);1109			break;1110		case ATH6KL_FW_IE_BOARD_ADDR:1111			if (ie_len != sizeof(*val))1112				break;1113 1114			val = (__le32 *) data;1115			ar->hw.board_addr = le32_to_cpup(val);1116 1117			ath6kl_dbg(ATH6KL_DBG_BOOT,1118				   "found board address ie 0x%x\n",1119				   ar->hw.board_addr);1120			break;1121		case ATH6KL_FW_IE_VIF_MAX:1122			if (ie_len != sizeof(*val))1123				break;1124 1125			val = (__le32 *) data;1126			ar->vif_max = min_t(unsigned int, le32_to_cpup(val),1127					    ATH6KL_VIF_MAX);1128 1129			if (ar->vif_max > 1 && !ar->p2p)1130				ar->max_norm_iface = 2;1131 1132			ath6kl_dbg(ATH6KL_DBG_BOOT,1133				   "found vif max ie %d\n", ar->vif_max);1134			break;1135		default:1136			ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",1137				   le32_to_cpup(&hdr->id));1138			break;1139		}1140 1141		len -= ie_len;1142		data += ie_len;1143	}1144 1145	ret = 0;1146out:1147	release_firmware(fw);1148 1149	return ret;1150}1151 1152int ath6kl_init_fetch_firmwares(struct ath6kl *ar)1153{1154	int ret;1155 1156	ret = ath6kl_fetch_board_file(ar);1157	if (ret)1158		return ret;1159 1160	ret = ath6kl_fetch_testmode_file(ar);1161	if (ret)1162		return ret;1163 1164	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API5_FILE);1165	if (ret == 0) {1166		ar->fw_api = 5;1167		goto out;1168	}1169 1170	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE);1171	if (ret == 0) {1172		ar->fw_api = 4;1173		goto out;1174	}1175 1176	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);1177	if (ret == 0) {1178		ar->fw_api = 3;1179		goto out;1180	}1181 1182	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API2_FILE);1183	if (ret == 0) {1184		ar->fw_api = 2;1185		goto out;1186	}1187 1188	ret = ath6kl_fetch_fw_api1(ar);1189	if (ret)1190		return ret;1191 1192	ar->fw_api = 1;1193 1194out:1195	ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api %d\n", ar->fw_api);1196 1197	return 0;1198}1199 1200static int ath6kl_upload_board_file(struct ath6kl *ar)1201{1202	u32 board_address, board_ext_address, param;1203	u32 board_data_size, board_ext_data_size;1204	int ret;1205 1206	if (WARN_ON(ar->fw_board == NULL))1207		return -ENOENT;1208 1209	/*1210	 * Determine where in Target RAM to write Board Data.1211	 * For AR6004, host determine Target RAM address for1212	 * writing board data.1213	 */1214	if (ar->hw.board_addr != 0) {1215		board_address = ar->hw.board_addr;1216		ath6kl_bmi_write_hi32(ar, hi_board_data,1217				      board_address);1218	} else {1219		ret = ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address);1220		if (ret) {1221			ath6kl_err("Failed to get board file target address.\n");1222			return ret;1223		}1224	}1225 1226	/* determine where in target ram to write extended board data */1227	ret = ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address);1228	if (ret) {1229		ath6kl_err("Failed to get extended board file target address.\n");1230		return ret;1231	}1232 1233	if (ar->target_type == TARGET_TYPE_AR6003 &&1234	    board_ext_address == 0) {1235		ath6kl_err("Failed to get board file target address.\n");1236		return -EINVAL;1237	}1238 1239	switch (ar->target_type) {1240	case TARGET_TYPE_AR6003:1241		board_data_size = AR6003_BOARD_DATA_SZ;1242		board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ;1243		if (ar->fw_board_len > (board_data_size + board_ext_data_size))1244			board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ_V2;1245		break;1246	case TARGET_TYPE_AR6004:1247		board_data_size = AR6004_BOARD_DATA_SZ;1248		board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ;1249		break;1250	default:1251		WARN_ON(1);1252		return -EINVAL;1253	}1254 1255	if (board_ext_address &&1256	    ar->fw_board_len == (board_data_size + board_ext_data_size)) {1257		/* write extended board data */1258		ath6kl_dbg(ATH6KL_DBG_BOOT,1259			   "writing extended board data to 0x%x (%d B)\n",1260			   board_ext_address, board_ext_data_size);1261 1262		ret = ath6kl_bmi_write(ar, board_ext_address,1263				       ar->fw_board + board_data_size,1264				       board_ext_data_size);1265		if (ret) {1266			ath6kl_err("Failed to write extended board data: %d\n",1267				   ret);1268			return ret;1269		}1270 1271		/* record that extended board data is initialized */1272		param = (board_ext_data_size << 16) | 1;1273 1274		ath6kl_bmi_write_hi32(ar, hi_board_ext_data_config, param);1275	}1276 1277	if (ar->fw_board_len < board_data_size) {1278		ath6kl_err("Too small board file: %zu\n", ar->fw_board_len);1279		ret = -EINVAL;1280		return ret;1281	}1282 1283	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n",1284		   board_address, board_data_size);1285 1286	ret = ath6kl_bmi_write(ar, board_address, ar->fw_board,1287			       board_data_size);1288 1289	if (ret) {1290		ath6kl_err("Board file bmi write failed: %d\n", ret);1291		return ret;1292	}1293 1294	/* record the fact that Board Data IS initialized */1295	if ((ar->version.target_ver == AR6004_HW_1_3_VERSION) ||1296	    (ar->version.target_ver == AR6004_HW_3_0_VERSION))1297		param = board_data_size;1298	else1299		param = 1;1300 1301	ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, param);1302 1303	return ret;1304}1305 1306static int ath6kl_upload_otp(struct ath6kl *ar)1307{1308	u32 address, param;1309	bool from_hw = false;1310	int ret;1311 1312	if (ar->fw_otp == NULL)1313		return 0;1314 1315	address = ar->hw.app_load_addr;1316 1317	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%zd B)\n", address,1318		   ar->fw_otp_len);1319 1320	ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp,1321				       ar->fw_otp_len);1322	if (ret) {1323		ath6kl_err("Failed to upload OTP file: %d\n", ret);1324		return ret;1325	}1326 1327	/* read firmware start address */1328	ret = ath6kl_bmi_read_hi32(ar, hi_app_start, &address);1329 1330	if (ret) {1331		ath6kl_err("Failed to read hi_app_start: %d\n", ret);1332		return ret;1333	}1334 1335	if (ar->hw.app_start_override_addr == 0) {1336		ar->hw.app_start_override_addr = address;1337		from_hw = true;1338	}1339 1340	ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr%s 0x%x\n",1341		   from_hw ? " (from hw)" : "",1342		   ar->hw.app_start_override_addr);1343 1344	/* execute the OTP code */1345	ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n",1346		   ar->hw.app_start_override_addr);1347	param = 0;1348	ath6kl_bmi_execute(ar, ar->hw.app_start_override_addr, &param);1349 1350	return ret;1351}1352 1353static int ath6kl_upload_firmware(struct ath6kl *ar)1354{1355	u32 address;1356	int ret;1357 1358	if (WARN_ON(ar->fw == NULL))1359		return 0;1360 1361	address = ar->hw.app_load_addr;1362 1363	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%zd B)\n",1364		   address, ar->fw_len);1365 1366	ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len);1367 1368	if (ret) {1369		ath6kl_err("Failed to write firmware: %d\n", ret);1370		return ret;1371	}1372 1373	/*1374	 * Set starting address for firmware1375	 * Don't need to setup app_start override addr on AR60041376	 */1377	if (ar->target_type != TARGET_TYPE_AR6004) {1378		address = ar->hw.app_start_override_addr;1379		ath6kl_bmi_set_app_start(ar, address);1380	}1381	return ret;1382}1383 1384static int ath6kl_upload_patch(struct ath6kl *ar)1385{1386	u32 address;1387	int ret;1388 1389	if (ar->fw_patch == NULL)1390		return 0;1391 1392	address = ar->hw.dataset_patch_addr;1393 1394	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%zd B)\n",1395		   address, ar->fw_patch_len);1396 1397	ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len);1398	if (ret) {1399		ath6kl_err("Failed to write patch file: %d\n", ret);1400		return ret;1401	}1402 1403	ath6kl_bmi_write_hi32(ar, hi_dset_list_head, address);1404 1405	return 0;1406}1407 1408static int ath6kl_upload_testscript(struct ath6kl *ar)1409{1410	u32 address;1411	int ret;1412 1413	if (ar->testmode != 2)1414		return 0;1415 1416	if (ar->fw_testscript == NULL)1417		return 0;1418 1419	address = ar->hw.testscript_addr;1420 1421	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n",1422		   address, ar->fw_testscript_len);1423 1424	ret = ath6kl_bmi_write(ar, address, ar->fw_testscript,1425		ar->fw_testscript_len);1426	if (ret) {1427		ath6kl_err("Failed to write testscript file: %d\n", ret);1428		return ret;1429	}1430 1431	ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address);1432 1433	if ((ar->version.target_ver != AR6004_HW_1_3_VERSION) &&1434	    (ar->version.target_ver != AR6004_HW_3_0_VERSION))1435		ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096);1436 1437	ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1);1438 1439	return 0;1440}1441 1442static int ath6kl_init_upload(struct ath6kl *ar)1443{1444	u32 param, options, sleep, address;1445	int status = 0;1446 1447	if (ar->target_type != TARGET_TYPE_AR6003 &&1448	    ar->target_type != TARGET_TYPE_AR6004)1449		return -EINVAL;1450 1451	/* temporarily disable system sleep */1452	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;1453	status = ath6kl_bmi_reg_read(ar, address, &param);1454	if (status)1455		return status;1456 1457	options = param;1458 1459	param |= ATH6KL_OPTION_SLEEP_DISABLE;1460	status = ath6kl_bmi_reg_write(ar, address, param);1461	if (status)1462		return status;1463 1464	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;1465	status = ath6kl_bmi_reg_read(ar, address, &param);1466	if (status)1467		return status;1468 1469	sleep = param;1470 1471	param |= SM(SYSTEM_SLEEP_DISABLE, 1);1472	status = ath6kl_bmi_reg_write(ar, address, param);1473	if (status)1474		return status;1475 1476	ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n",1477		   options, sleep);1478 1479	/* program analog PLL register */1480	/* no need to control 40/44MHz clock on AR6004 */1481	if (ar->target_type != TARGET_TYPE_AR6004) {1482		status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER,1483					      0xF9104001);1484 1485		if (status)1486			return status;1487 1488		/* Run at 80/88MHz by default */1489		param = SM(CPU_CLOCK_STANDARD, 1);1490 1491		address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;1492		status = ath6kl_bmi_reg_write(ar, address, param);1493		if (status)1494			return status;1495	}1496 1497	param = 0;1498	address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;1499	param = SM(LPO_CAL_ENABLE, 1);1500	status = ath6kl_bmi_reg_write(ar, address, param);1501	if (status)1502		return status;1503 1504	/* WAR to avoid SDIO CRC err */1505	if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) {1506		ath6kl_err("temporary war to avoid sdio crc error\n");1507 1508		param = 0x28;1509		address = GPIO_BASE_ADDRESS + GPIO_PIN9_ADDRESS;1510		status = ath6kl_bmi_reg_write(ar, address, param);1511		if (status)1512			return status;1513 1514		param = 0x20;1515 1516		address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;1517		status = ath6kl_bmi_reg_write(ar, address, param);1518		if (status)1519			return status;1520 1521		address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;1522		status = ath6kl_bmi_reg_write(ar, address, param);1523		if (status)1524			return status;1525 1526		address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;1527		status = ath6kl_bmi_reg_write(ar, address, param);1528		if (status)1529			return status;1530 1531		address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;1532		status = ath6kl_bmi_reg_write(ar, address, param);1533		if (status)1534			return status;1535	}1536 1537	/* write EEPROM data to Target RAM */1538	status = ath6kl_upload_board_file(ar);1539	if (status)1540		return status;1541 1542	/* transfer One time Programmable data */1543	status = ath6kl_upload_otp(ar);1544	if (status)1545		return status;1546 1547	/* Download Target firmware */1548	status = ath6kl_upload_firmware(ar);1549	if (status)1550		return status;1551 1552	status = ath6kl_upload_patch(ar);1553	if (status)1554		return status;1555 1556	/* Download the test script */1557	status = ath6kl_upload_testscript(ar);1558	if (status)1559		return status;1560 1561	/* Restore system sleep */1562	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;1563	status = ath6kl_bmi_reg_write(ar, address, sleep);1564	if (status)1565		return status;1566 1567	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;1568	param = options | 0x20;1569	status = ath6kl_bmi_reg_write(ar, address, param);1570	if (status)1571		return status;1572 1573	return status;1574}1575 1576int ath6kl_init_hw_params(struct ath6kl *ar)1577{1578	const struct ath6kl_hw *hw;1579	int i;1580 1581	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {1582		hw = &hw_list[i];1583 1584		if (hw->id == ar->version.target_ver)1585			break;1586	}1587 1588	if (i == ARRAY_SIZE(hw_list)) {1589		ath6kl_err("Unsupported hardware version: 0x%x\n",1590			   ar->version.target_ver);1591		return -EINVAL;1592	}1593 1594	ar->hw = *hw;1595 1596	ath6kl_dbg(ATH6KL_DBG_BOOT,1597		   "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",1598		   ar->version.target_ver, ar->target_type,1599		   ar->hw.dataset_patch_addr, ar->hw.app_load_addr);1600	ath6kl_dbg(ATH6KL_DBG_BOOT,1601		   "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",1602		   ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,1603		   ar->hw.reserved_ram_size);1604	ath6kl_dbg(ATH6KL_DBG_BOOT,1605		   "refclk_hz %d uarttx_pin %d",1606		   ar->hw.refclk_hz, ar->hw.uarttx_pin);1607 1608	return 0;1609}1610 1611static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)1612{1613	switch (type) {1614	case ATH6KL_HIF_TYPE_SDIO:1615		return "sdio";1616	case ATH6KL_HIF_TYPE_USB:1617		return "usb";1618	}1619 1620	return NULL;1621}1622 1623 1624static const struct fw_capa_str_map {1625	int id;1626	const char *name;1627} fw_capa_map[] = {1628	{ ATH6KL_FW_CAPABILITY_HOST_P2P, "host-p2p" },1629	{ ATH6KL_FW_CAPABILITY_SCHED_SCAN, "sched-scan" },1630	{ ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, "sta-p2pdev-duplex" },1631	{ ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, "inactivity-timeout" },1632	{ ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, "rsn-cap-override" },1633	{ ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, "wow-mc-filter" },1634	{ ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, "bmiss-enhance" },1635	{ ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, "sscan-match-list" },1636	{ ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, "rssi-scan-thold" },1637	{ ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, "custom-mac-addr" },1638	{ ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, "tx-err-notify" },1639	{ ATH6KL_FW_CAPABILITY_REGDOMAIN, "regdomain" },1640	{ ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, "sched-scan-v2" },1641	{ ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, "hb-poll" },1642	{ ATH6KL_FW_CAPABILITY_64BIT_RATES, "64bit-rates" },1643	{ ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, "ap-inactivity-mins" },1644	{ ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, "map-lp-endpoint" },1645	{ ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, "ratetable-mcs15" },1646	{ ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, "no-ip-checksum" },1647};1648 1649static const char *ath6kl_init_get_fw_capa_name(unsigned int id)1650{1651	int i;1652 1653	for (i = 0; i < ARRAY_SIZE(fw_capa_map); i++) {1654		if (fw_capa_map[i].id == id)1655			return fw_capa_map[i].name;1656	}1657 1658	return "<unknown>";1659}1660 1661static void ath6kl_init_get_fwcaps(struct ath6kl *ar, char *buf, size_t buf_len)1662{1663	u8 *data = (u8 *) ar->fw_capabilities;1664	size_t trunc_len, len = 0;1665	int i, index, bit;1666	char *trunc = "...";1667 1668	for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {1669		index = i / 8;1670		bit = i % 8;1671 1672		if (index >= sizeof(ar->fw_capabilities) * 4)1673			break;1674 1675		if (buf_len - len < 4) {1676			ath6kl_warn("firmware capability buffer too small!\n");1677 1678			/* add "..." to the end of string */1679			trunc_len = strlen(trunc) + 1;1680			memcpy(buf + buf_len - trunc_len, trunc, trunc_len);1681 1682			return;1683		}1684 1685		if (data[index] & (1 << bit)) {1686			len += scnprintf(buf + len, buf_len - len, "%s,",1687					    ath6kl_init_get_fw_capa_name(i));1688		}1689	}1690 1691	/* overwrite the last comma */1692	if (len > 0)1693		len--;1694 1695	buf[len] = '\0';1696}1697 1698static int ath6kl_init_hw_reset(struct ath6kl *ar)1699{1700	ath6kl_dbg(ATH6KL_DBG_BOOT, "cold resetting the device");1701 1702	return ath6kl_diag_write32(ar, RESET_CONTROL_ADDRESS,1703				   cpu_to_le32(RESET_CONTROL_COLD_RST));1704}1705 1706static int __ath6kl_init_hw_start(struct ath6kl *ar)1707{1708	long timeleft;1709	int ret, i;1710	char buf[200];1711 1712	ath6kl_dbg(ATH6KL_DBG_BOOT, "hw start\n");1713 1714	ret = ath6kl_hif_power_on(ar);1715	if (ret)1716		return ret;1717 1718	ret = ath6kl_configure_target(ar);1719	if (ret)1720		goto err_power_off;1721 1722	ret = ath6kl_init_upload(ar);1723	if (ret)1724		goto err_power_off;1725 1726	/* Do we need to finish the BMI phase */1727	ret = ath6kl_bmi_done(ar);1728	if (ret)1729		goto err_power_off;1730 1731	/*1732	 * The reason we have to wait for the target here is that the1733	 * driver layer has to init BMI in order to set the host block1734	 * size.1735	 */1736	ret = ath6kl_htc_wait_target(ar->htc_target);1737 1738	if (ret == -ETIMEDOUT) {1739		/*1740		 * Most likely USB target is in odd state after reboot and1741		 * needs a reset. A cold reset makes the whole device1742		 * disappear from USB bus and initialisation starts from1743		 * beginning.1744		 */1745		ath6kl_warn("htc wait target timed out, resetting device\n");1746		ath6kl_init_hw_reset(ar);1747		goto err_power_off;1748	} else if (ret) {1749		ath6kl_err("htc wait target failed: %d\n", ret);1750		goto err_power_off;1751	}1752 1753	ret = ath6kl_init_service_ep(ar);1754	if (ret) {1755		ath6kl_err("Endpoint service initialization failed: %d\n", ret);1756		goto err_cleanup_scatter;1757	}1758 1759	/* setup credit distribution */1760	ath6kl_htc_credit_setup(ar->htc_target, &ar->credit_state_info);1761 1762	/* start HTC */1763	ret = ath6kl_htc_start(ar->htc_target);1764	if (ret) {1765		/* FIXME: call this */1766		ath6kl_cookie_cleanup(ar);1767		goto err_cleanup_scatter;1768	}1769 1770	/* Wait for Wmi event to be ready */1771	timeleft = wait_event_interruptible_timeout(ar->event_wq,1772						    test_bit(WMI_READY,1773							     &ar->flag),1774						    WMI_TIMEOUT);1775	if (timeleft <= 0) {1776		clear_bit(WMI_READY, &ar->flag);1777		ath6kl_err("wmi is not ready or wait was interrupted: %ld\n",1778			   timeleft);1779		ret = -EIO;1780		goto err_htc_stop;1781	}1782 1783	ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");1784 1785	if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {1786		ath6kl_info("%s %s fw %s api %d%s\n",1787			    ar->hw.name,1788			    ath6kl_init_get_hif_name(ar->hif_type),1789			    ar->wiphy->fw_version,1790			    ar->fw_api,1791			    test_bit(TESTMODE, &ar->flag) ? " testmode" : "");1792		ath6kl_init_get_fwcaps(ar, buf, sizeof(buf));1793		ath6kl_info("firmware supports: %s\n", buf);1794	}1795 1796	if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {1797		ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",1798			   ATH6KL_ABI_VERSION, ar->version.abi_ver);1799		ret = -EIO;1800		goto err_htc_stop;1801	}1802 1803	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__);1804 1805	/* communicate the wmi protocol verision to the target */1806	/* FIXME: return error */1807	if ((ath6kl_set_host_app_area(ar)) != 0)1808		ath6kl_err("unable to set the host app area\n");1809 1810	for (i = 0; i < ar->vif_max; i++) {1811		ret = ath6kl_target_config_wlan_params(ar, i);1812		if (ret)1813			goto err_htc_stop;1814	}1815 1816	return 0;1817 1818err_htc_stop:1819	ath6kl_htc_stop(ar->htc_target);1820err_cleanup_scatter:1821	ath6kl_hif_cleanup_scatter(ar);1822err_power_off:1823	ath6kl_hif_power_off(ar);1824 1825	return ret;1826}1827 1828int ath6kl_init_hw_start(struct ath6kl *ar)1829{1830	int err;1831 1832	err = __ath6kl_init_hw_start(ar);1833	if (err)1834		return err;1835	ar->state = ATH6KL_STATE_ON;1836	return 0;1837}1838 1839static int __ath6kl_init_hw_stop(struct ath6kl *ar)1840{1841	int ret;1842 1843	ath6kl_dbg(ATH6KL_DBG_BOOT, "hw stop\n");1844 1845	ath6kl_htc_stop(ar->htc_target);1846 1847	ath6kl_hif_stop(ar);1848 1849	ath6kl_bmi_reset(ar);1850 1851	ret = ath6kl_hif_power_off(ar);1852	if (ret)1853		ath6kl_warn("failed to power off hif: %d\n", ret);1854 1855	return 0;1856}1857 1858int ath6kl_init_hw_stop(struct ath6kl *ar)1859{1860	int err;1861 1862	err = __ath6kl_init_hw_stop(ar);1863	if (err)1864		return err;1865	ar->state = ATH6KL_STATE_OFF;1866	return 0;1867}1868 1869void ath6kl_init_hw_restart(struct ath6kl *ar)1870{1871	clear_bit(WMI_READY, &ar->flag);1872 1873	ath6kl_cfg80211_stop_all(ar);1874 1875	if (__ath6kl_init_hw_stop(ar)) {1876		ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n");1877		return;1878	}1879 1880	if (__ath6kl_init_hw_start(ar)) {1881		ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n");1882		return;1883	}1884}1885 1886void ath6kl_stop_txrx(struct ath6kl *ar)1887{1888	struct ath6kl_vif *vif, *tmp_vif;1889	int i;1890 1891	set_bit(DESTROY_IN_PROGRESS, &ar->flag);1892 1893	if (down_interruptible(&ar->sem)) {1894		ath6kl_err("down_interruptible failed\n");1895		return;1896	}1897 1898	for (i = 0; i < AP_MAX_NUM_STA; i++)1899		aggr_reset_state(ar->sta_list[i].aggr_conn);1900 1901	spin_lock_bh(&ar->list_lock);1902	list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) {1903		list_del(&vif->list);1904		spin_unlock_bh(&ar->list_lock);1905		ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));1906		rtnl_lock();1907		wiphy_lock(ar->wiphy);1908		ath6kl_cfg80211_vif_cleanup(vif);1909		wiphy_unlock(ar->wiphy);1910		rtnl_unlock();1911		spin_lock_bh(&ar->list_lock);1912	}1913	spin_unlock_bh(&ar->list_lock);1914 1915	clear_bit(WMI_READY, &ar->flag);1916 1917	if (ar->fw_recovery.enable)1918		del_timer_sync(&ar->fw_recovery.hb_timer);1919 1920	/*1921	 * After wmi_shudown all WMI events will be dropped. We1922	 * need to cleanup the buffers allocated in AP mode and1923	 * give disconnect notification to stack, which usually1924	 * happens in the disconnect_event. Simulate the disconnect1925	 * event by calling the function directly. Sometimes1926	 * disconnect_event will be received when the debug logs1927	 * are collected.1928	 */1929	ath6kl_wmi_shutdown(ar->wmi);1930 1931	clear_bit(WMI_ENABLED, &ar->flag);1932	if (ar->htc_target) {1933		ath6kl_dbg(ATH6KL_DBG_TRC, "%s: shut down htc\n", __func__);1934		ath6kl_htc_stop(ar->htc_target);1935	}1936 1937	/*1938	 * Try to reset the device if we can. The driver may have been1939	 * configure NOT to reset the target during a debug session.1940	 */1941	ath6kl_init_hw_reset(ar);1942 1943	up(&ar->sem);1944}1945EXPORT_SYMBOL(ath6kl_stop_txrx);1946