1bdcd8170SKalle Valo 2bdcd8170SKalle Valo /* 3bdcd8170SKalle Valo * Copyright (c) 2011 Atheros Communications Inc. 4bdcd8170SKalle Valo * 5bdcd8170SKalle Valo * Permission to use, copy, modify, and/or distribute this software for any 6bdcd8170SKalle Valo * purpose with or without fee is hereby granted, provided that the above 7bdcd8170SKalle Valo * copyright notice and this permission notice appear in all copies. 8bdcd8170SKalle Valo * 9bdcd8170SKalle Valo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10bdcd8170SKalle Valo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11bdcd8170SKalle Valo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12bdcd8170SKalle Valo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13bdcd8170SKalle Valo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14bdcd8170SKalle Valo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15bdcd8170SKalle Valo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16bdcd8170SKalle Valo */ 17bdcd8170SKalle Valo 18bdcd8170SKalle Valo #include <linux/mmc/sdio_func.h> 19bdcd8170SKalle Valo #include "core.h" 20bdcd8170SKalle Valo #include "cfg80211.h" 21bdcd8170SKalle Valo #include "target.h" 22bdcd8170SKalle Valo #include "debug.h" 23bdcd8170SKalle Valo #include "hif-ops.h" 24bdcd8170SKalle Valo 25bdcd8170SKalle Valo unsigned int debug_mask; 26bdcd8170SKalle Valo 27bdcd8170SKalle Valo module_param(debug_mask, uint, 0644); 28bdcd8170SKalle Valo 29bdcd8170SKalle Valo /* 30bdcd8170SKalle Valo * Include definitions here that can be used to tune the WLAN module 31bdcd8170SKalle Valo * behavior. Different customers can tune the behavior as per their needs, 32bdcd8170SKalle Valo * here. 33bdcd8170SKalle Valo */ 34bdcd8170SKalle Valo 35bdcd8170SKalle Valo /* 36bdcd8170SKalle Valo * This configuration item enable/disable keepalive support. 37bdcd8170SKalle Valo * Keepalive support: In the absence of any data traffic to AP, null 38bdcd8170SKalle Valo * frames will be sent to the AP at periodic interval, to keep the association 39bdcd8170SKalle Valo * active. This configuration item defines the periodic interval. 40bdcd8170SKalle Valo * Use value of zero to disable keepalive support 41bdcd8170SKalle Valo * Default: 60 seconds 42bdcd8170SKalle Valo */ 43bdcd8170SKalle Valo #define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60 44bdcd8170SKalle Valo 45bdcd8170SKalle Valo /* 46bdcd8170SKalle Valo * This configuration item sets the value of disconnect timeout 47bdcd8170SKalle Valo * Firmware delays sending the disconnec event to the host for this 48bdcd8170SKalle Valo * timeout after is gets disconnected from the current AP. 49bdcd8170SKalle Valo * If the firmware successly roams within the disconnect timeout 50bdcd8170SKalle Valo * it sends a new connect event 51bdcd8170SKalle Valo */ 52bdcd8170SKalle Valo #define WLAN_CONFIG_DISCONNECT_TIMEOUT 10 53bdcd8170SKalle Valo 54bdcd8170SKalle Valo #define CONFIG_AR600x_DEBUG_UART_TX_PIN 8 55bdcd8170SKalle Valo 56bdcd8170SKalle Valo enum addr_type { 57bdcd8170SKalle Valo DATASET_PATCH_ADDR, 58bdcd8170SKalle Valo APP_LOAD_ADDR, 59bdcd8170SKalle Valo APP_START_OVERRIDE_ADDR, 60bdcd8170SKalle Valo }; 61bdcd8170SKalle Valo 62bdcd8170SKalle Valo #define ATH6KL_DATA_OFFSET 64 63bdcd8170SKalle Valo struct sk_buff *ath6kl_buf_alloc(int size) 64bdcd8170SKalle Valo { 65bdcd8170SKalle Valo struct sk_buff *skb; 66bdcd8170SKalle Valo u16 reserved; 67bdcd8170SKalle Valo 68bdcd8170SKalle Valo /* Add chacheline space at front and back of buffer */ 69bdcd8170SKalle Valo reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + 70bdcd8170SKalle Valo sizeof(struct htc_packet); 71bdcd8170SKalle Valo skb = dev_alloc_skb(size + reserved); 72bdcd8170SKalle Valo 73bdcd8170SKalle Valo if (skb) 74bdcd8170SKalle Valo skb_reserve(skb, reserved - L1_CACHE_BYTES); 75bdcd8170SKalle Valo return skb; 76bdcd8170SKalle Valo } 77bdcd8170SKalle Valo 78bdcd8170SKalle Valo void ath6kl_init_profile_info(struct ath6kl *ar) 79bdcd8170SKalle Valo { 80bdcd8170SKalle Valo ar->ssid_len = 0; 81bdcd8170SKalle Valo memset(ar->ssid, 0, sizeof(ar->ssid)); 82bdcd8170SKalle Valo 83bdcd8170SKalle Valo ar->dot11_auth_mode = OPEN_AUTH; 84bdcd8170SKalle Valo ar->auth_mode = NONE_AUTH; 85bdcd8170SKalle Valo ar->prwise_crypto = NONE_CRYPT; 86bdcd8170SKalle Valo ar->prwise_crypto_len = 0; 87bdcd8170SKalle Valo ar->grp_crypto = NONE_CRYPT; 88bdcd8170SKalle Valo ar->grp_crpto_len = 0; 89bdcd8170SKalle Valo memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); 90bdcd8170SKalle Valo memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); 91bdcd8170SKalle Valo memset(ar->bssid, 0, sizeof(ar->bssid)); 92bdcd8170SKalle Valo ar->bss_ch = 0; 93bdcd8170SKalle Valo ar->nw_type = ar->next_mode = INFRA_NETWORK; 94bdcd8170SKalle Valo } 95bdcd8170SKalle Valo 96bdcd8170SKalle Valo static u8 ath6kl_get_fw_iftype(struct ath6kl *ar) 97bdcd8170SKalle Valo { 98bdcd8170SKalle Valo switch (ar->nw_type) { 99bdcd8170SKalle Valo case INFRA_NETWORK: 100bdcd8170SKalle Valo return HI_OPTION_FW_MODE_BSS_STA; 101bdcd8170SKalle Valo case ADHOC_NETWORK: 102bdcd8170SKalle Valo return HI_OPTION_FW_MODE_IBSS; 103bdcd8170SKalle Valo case AP_NETWORK: 104bdcd8170SKalle Valo return HI_OPTION_FW_MODE_AP; 105bdcd8170SKalle Valo default: 106bdcd8170SKalle Valo ath6kl_err("Unsupported interface type :%d\n", ar->nw_type); 107bdcd8170SKalle Valo return 0xff; 108bdcd8170SKalle Valo } 109bdcd8170SKalle Valo } 110bdcd8170SKalle Valo 111bdcd8170SKalle Valo static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar, 112bdcd8170SKalle Valo u32 item_offset) 113bdcd8170SKalle Valo { 114bdcd8170SKalle Valo u32 addr = 0; 115bdcd8170SKalle Valo 116bdcd8170SKalle Valo if (ar->target_type == TARGET_TYPE_AR6003) 117bdcd8170SKalle Valo addr = ATH6KL_HI_START_ADDR + item_offset; 118bdcd8170SKalle Valo 119bdcd8170SKalle Valo return addr; 120bdcd8170SKalle Valo } 121bdcd8170SKalle Valo 122bdcd8170SKalle Valo static int ath6kl_set_host_app_area(struct ath6kl *ar) 123bdcd8170SKalle Valo { 124bdcd8170SKalle Valo u32 address, data; 125bdcd8170SKalle Valo struct host_app_area host_app_area; 126bdcd8170SKalle Valo 127bdcd8170SKalle Valo /* Fetch the address of the host_app_area_s 128bdcd8170SKalle Valo * instance in the host interest area */ 129bdcd8170SKalle Valo address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest)); 130bdcd8170SKalle Valo address = TARG_VTOP(address); 131bdcd8170SKalle Valo 132bdcd8170SKalle Valo if (ath6kl_read_reg_diag(ar, &address, &data)) 133bdcd8170SKalle Valo return -EIO; 134bdcd8170SKalle Valo 135bdcd8170SKalle Valo address = TARG_VTOP(data); 136bdcd8170SKalle Valo host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION; 137bdcd8170SKalle Valo if (ath6kl_access_datadiag(ar, address, 138bdcd8170SKalle Valo (u8 *)&host_app_area, 139bdcd8170SKalle Valo sizeof(struct host_app_area), false)) 140bdcd8170SKalle Valo return -EIO; 141bdcd8170SKalle Valo 142bdcd8170SKalle Valo return 0; 143bdcd8170SKalle Valo } 144bdcd8170SKalle Valo 145bdcd8170SKalle Valo static inline void set_ac2_ep_map(struct ath6kl *ar, 146bdcd8170SKalle Valo u8 ac, 147bdcd8170SKalle Valo enum htc_endpoint_id ep) 148bdcd8170SKalle Valo { 149bdcd8170SKalle Valo ar->ac2ep_map[ac] = ep; 150bdcd8170SKalle Valo ar->ep2ac_map[ep] = ac; 151bdcd8170SKalle Valo } 152bdcd8170SKalle Valo 153bdcd8170SKalle Valo /* connect to a service */ 154bdcd8170SKalle Valo static int ath6kl_connectservice(struct ath6kl *ar, 155bdcd8170SKalle Valo struct htc_service_connect_req *con_req, 156bdcd8170SKalle Valo char *desc) 157bdcd8170SKalle Valo { 158bdcd8170SKalle Valo int status; 159bdcd8170SKalle Valo struct htc_service_connect_resp response; 160bdcd8170SKalle Valo 161bdcd8170SKalle Valo memset(&response, 0, sizeof(response)); 162bdcd8170SKalle Valo 163bdcd8170SKalle Valo status = htc_conn_service(ar->htc_target, con_req, &response); 164bdcd8170SKalle Valo if (status) { 165bdcd8170SKalle Valo ath6kl_err("failed to connect to %s service status:%d\n", 166bdcd8170SKalle Valo desc, status); 167bdcd8170SKalle Valo return status; 168bdcd8170SKalle Valo } 169bdcd8170SKalle Valo 170bdcd8170SKalle Valo switch (con_req->svc_id) { 171bdcd8170SKalle Valo case WMI_CONTROL_SVC: 172bdcd8170SKalle Valo if (test_bit(WMI_ENABLED, &ar->flag)) 173bdcd8170SKalle Valo ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint); 174bdcd8170SKalle Valo ar->ctrl_ep = response.endpoint; 175bdcd8170SKalle Valo break; 176bdcd8170SKalle Valo case WMI_DATA_BE_SVC: 177bdcd8170SKalle Valo set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint); 178bdcd8170SKalle Valo break; 179bdcd8170SKalle Valo case WMI_DATA_BK_SVC: 180bdcd8170SKalle Valo set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint); 181bdcd8170SKalle Valo break; 182bdcd8170SKalle Valo case WMI_DATA_VI_SVC: 183bdcd8170SKalle Valo set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint); 184bdcd8170SKalle Valo break; 185bdcd8170SKalle Valo case WMI_DATA_VO_SVC: 186bdcd8170SKalle Valo set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint); 187bdcd8170SKalle Valo break; 188bdcd8170SKalle Valo default: 189bdcd8170SKalle Valo ath6kl_err("service id is not mapped %d\n", con_req->svc_id); 190bdcd8170SKalle Valo return -EINVAL; 191bdcd8170SKalle Valo } 192bdcd8170SKalle Valo 193bdcd8170SKalle Valo return 0; 194bdcd8170SKalle Valo } 195bdcd8170SKalle Valo 196bdcd8170SKalle Valo static int ath6kl_init_service_ep(struct ath6kl *ar) 197bdcd8170SKalle Valo { 198bdcd8170SKalle Valo struct htc_service_connect_req connect; 199bdcd8170SKalle Valo 200bdcd8170SKalle Valo memset(&connect, 0, sizeof(connect)); 201bdcd8170SKalle Valo 202bdcd8170SKalle Valo /* these fields are the same for all service endpoints */ 203bdcd8170SKalle Valo connect.ep_cb.rx = ath6kl_rx; 204bdcd8170SKalle Valo connect.ep_cb.rx_refill = ath6kl_rx_refill; 205bdcd8170SKalle Valo connect.ep_cb.tx_full = ath6kl_tx_queue_full; 206bdcd8170SKalle Valo 207bdcd8170SKalle Valo /* 208bdcd8170SKalle Valo * Set the max queue depth so that our ath6kl_tx_queue_full handler 209bdcd8170SKalle Valo * gets called. 210bdcd8170SKalle Valo */ 211bdcd8170SKalle Valo connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH; 212bdcd8170SKalle Valo connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4; 213bdcd8170SKalle Valo if (!connect.ep_cb.rx_refill_thresh) 214bdcd8170SKalle Valo connect.ep_cb.rx_refill_thresh++; 215bdcd8170SKalle Valo 216bdcd8170SKalle Valo /* connect to control service */ 217bdcd8170SKalle Valo connect.svc_id = WMI_CONTROL_SVC; 218bdcd8170SKalle Valo if (ath6kl_connectservice(ar, &connect, "WMI CONTROL")) 219bdcd8170SKalle Valo return -EIO; 220bdcd8170SKalle Valo 221bdcd8170SKalle Valo connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN; 222bdcd8170SKalle Valo 223bdcd8170SKalle Valo /* 224bdcd8170SKalle Valo * Limit the HTC message size on the send path, although e can 225bdcd8170SKalle Valo * receive A-MSDU frames of 4K, we will only send ethernet-sized 226bdcd8170SKalle Valo * (802.3) frames on the send path. 227bdcd8170SKalle Valo */ 228bdcd8170SKalle Valo connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH; 229bdcd8170SKalle Valo 230bdcd8170SKalle Valo /* 231bdcd8170SKalle Valo * To reduce the amount of committed memory for larger A_MSDU 232bdcd8170SKalle Valo * frames, use the recv-alloc threshold mechanism for larger 233bdcd8170SKalle Valo * packets. 234bdcd8170SKalle Valo */ 235bdcd8170SKalle Valo connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE; 236bdcd8170SKalle Valo connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf; 237bdcd8170SKalle Valo 238bdcd8170SKalle Valo /* 239bdcd8170SKalle Valo * For the remaining data services set the connection flag to 240bdcd8170SKalle Valo * reduce dribbling, if configured to do so. 241bdcd8170SKalle Valo */ 242bdcd8170SKalle Valo connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB; 243bdcd8170SKalle Valo connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK; 244bdcd8170SKalle Valo connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF; 245bdcd8170SKalle Valo 246bdcd8170SKalle Valo connect.svc_id = WMI_DATA_BE_SVC; 247bdcd8170SKalle Valo 248bdcd8170SKalle Valo if (ath6kl_connectservice(ar, &connect, "WMI DATA BE")) 249bdcd8170SKalle Valo return -EIO; 250bdcd8170SKalle Valo 251bdcd8170SKalle Valo /* connect to back-ground map this to WMI LOW_PRI */ 252bdcd8170SKalle Valo connect.svc_id = WMI_DATA_BK_SVC; 253bdcd8170SKalle Valo if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) 254bdcd8170SKalle Valo return -EIO; 255bdcd8170SKalle Valo 256bdcd8170SKalle Valo /* connect to Video service, map this to to HI PRI */ 257bdcd8170SKalle Valo connect.svc_id = WMI_DATA_VI_SVC; 258bdcd8170SKalle Valo if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) 259bdcd8170SKalle Valo return -EIO; 260bdcd8170SKalle Valo 261bdcd8170SKalle Valo /* 262bdcd8170SKalle Valo * Connect to VO service, this is currently not mapped to a WMI 263bdcd8170SKalle Valo * priority stream due to historical reasons. WMI originally 264bdcd8170SKalle Valo * defined 3 priorities over 3 mailboxes We can change this when 265bdcd8170SKalle Valo * WMI is reworked so that priorities are not dependent on 266bdcd8170SKalle Valo * mailboxes. 267bdcd8170SKalle Valo */ 268bdcd8170SKalle Valo connect.svc_id = WMI_DATA_VO_SVC; 269bdcd8170SKalle Valo if (ath6kl_connectservice(ar, &connect, "WMI DATA VO")) 270bdcd8170SKalle Valo return -EIO; 271bdcd8170SKalle Valo 272bdcd8170SKalle Valo return 0; 273bdcd8170SKalle Valo } 274bdcd8170SKalle Valo 275bdcd8170SKalle Valo static void ath6kl_init_control_info(struct ath6kl *ar) 276bdcd8170SKalle Valo { 277bdcd8170SKalle Valo u8 ctr; 278bdcd8170SKalle Valo 279bdcd8170SKalle Valo clear_bit(WMI_ENABLED, &ar->flag); 280bdcd8170SKalle Valo ath6kl_init_profile_info(ar); 281bdcd8170SKalle Valo ar->def_txkey_index = 0; 282bdcd8170SKalle Valo memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); 283bdcd8170SKalle Valo ar->ch_hint = 0; 284bdcd8170SKalle Valo ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL; 285bdcd8170SKalle Valo ar->listen_intvl_b = 0; 286bdcd8170SKalle Valo ar->tx_pwr = 0; 287bdcd8170SKalle Valo clear_bit(SKIP_SCAN, &ar->flag); 288bdcd8170SKalle Valo set_bit(WMM_ENABLED, &ar->flag); 289bdcd8170SKalle Valo ar->intra_bss = 1; 290bdcd8170SKalle Valo memset(&ar->sc_params, 0, sizeof(ar->sc_params)); 291bdcd8170SKalle Valo ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; 292bdcd8170SKalle Valo ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; 293bdcd8170SKalle Valo 294bdcd8170SKalle Valo memset((u8 *)ar->sta_list, 0, 295bdcd8170SKalle Valo AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); 296bdcd8170SKalle Valo 297bdcd8170SKalle Valo spin_lock_init(&ar->mcastpsq_lock); 298bdcd8170SKalle Valo 299bdcd8170SKalle Valo /* Init the PS queues */ 300bdcd8170SKalle Valo for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { 301bdcd8170SKalle Valo spin_lock_init(&ar->sta_list[ctr].psq_lock); 302bdcd8170SKalle Valo skb_queue_head_init(&ar->sta_list[ctr].psq); 303bdcd8170SKalle Valo } 304bdcd8170SKalle Valo 305bdcd8170SKalle Valo skb_queue_head_init(&ar->mcastpsq); 306bdcd8170SKalle Valo 307bdcd8170SKalle Valo memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); 308bdcd8170SKalle Valo } 309bdcd8170SKalle Valo 310bdcd8170SKalle Valo /* 311bdcd8170SKalle Valo * Set HTC/Mbox operational parameters, this can only be called when the 312bdcd8170SKalle Valo * target is in the BMI phase. 313bdcd8170SKalle Valo */ 314bdcd8170SKalle Valo static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, 315bdcd8170SKalle Valo u8 htc_ctrl_buf) 316bdcd8170SKalle Valo { 317bdcd8170SKalle Valo int status; 318bdcd8170SKalle Valo u32 blk_size; 319bdcd8170SKalle Valo 320bdcd8170SKalle Valo blk_size = ar->mbox_info.block_size; 321bdcd8170SKalle Valo 322bdcd8170SKalle Valo if (htc_ctrl_buf) 323bdcd8170SKalle Valo blk_size |= ((u32)htc_ctrl_buf) << 16; 324bdcd8170SKalle Valo 325bdcd8170SKalle Valo /* set the host interest area for the block size */ 326bdcd8170SKalle Valo status = ath6kl_bmi_write(ar, 327bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 328bdcd8170SKalle Valo HI_ITEM(hi_mbox_io_block_sz)), 329bdcd8170SKalle Valo (u8 *)&blk_size, 330bdcd8170SKalle Valo 4); 331bdcd8170SKalle Valo if (status) { 332bdcd8170SKalle Valo ath6kl_err("bmi_write_memory for IO block size failed\n"); 333bdcd8170SKalle Valo goto out; 334bdcd8170SKalle Valo } 335bdcd8170SKalle Valo 336bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n", 337bdcd8170SKalle Valo blk_size, 338bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz))); 339bdcd8170SKalle Valo 340bdcd8170SKalle Valo if (mbox_isr_yield_val) { 341bdcd8170SKalle Valo /* set the host interest area for the mbox ISR yield limit */ 342bdcd8170SKalle Valo status = ath6kl_bmi_write(ar, 343bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 344bdcd8170SKalle Valo HI_ITEM(hi_mbox_isr_yield_limit)), 345bdcd8170SKalle Valo (u8 *)&mbox_isr_yield_val, 346bdcd8170SKalle Valo 4); 347bdcd8170SKalle Valo if (status) { 348bdcd8170SKalle Valo ath6kl_err("bmi_write_memory for yield limit failed\n"); 349bdcd8170SKalle Valo goto out; 350bdcd8170SKalle Valo } 351bdcd8170SKalle Valo } 352bdcd8170SKalle Valo 353bdcd8170SKalle Valo out: 354bdcd8170SKalle Valo return status; 355bdcd8170SKalle Valo } 356bdcd8170SKalle Valo 357bdcd8170SKalle Valo #define REG_DUMP_COUNT_AR6003 60 358bdcd8170SKalle Valo #define REGISTER_DUMP_LEN_MAX 60 359bdcd8170SKalle Valo 360bdcd8170SKalle Valo static void ath6kl_dump_target_assert_info(struct ath6kl *ar) 361bdcd8170SKalle Valo { 362bdcd8170SKalle Valo u32 address; 363bdcd8170SKalle Valo u32 regdump_loc = 0; 364bdcd8170SKalle Valo int status; 365bdcd8170SKalle Valo u32 regdump_val[REGISTER_DUMP_LEN_MAX]; 366bdcd8170SKalle Valo u32 i; 367bdcd8170SKalle Valo 368bdcd8170SKalle Valo if (ar->target_type != TARGET_TYPE_AR6003) 369bdcd8170SKalle Valo return; 370bdcd8170SKalle Valo 371bdcd8170SKalle Valo /* the reg dump pointer is copied to the host interest area */ 372bdcd8170SKalle Valo address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); 373bdcd8170SKalle Valo address = TARG_VTOP(address); 374bdcd8170SKalle Valo 375bdcd8170SKalle Valo /* read RAM location through diagnostic window */ 376bdcd8170SKalle Valo status = ath6kl_read_reg_diag(ar, &address, ®dump_loc); 377bdcd8170SKalle Valo 378bdcd8170SKalle Valo if (status || !regdump_loc) { 379bdcd8170SKalle Valo ath6kl_err("failed to get ptr to register dump area\n"); 380bdcd8170SKalle Valo return; 381bdcd8170SKalle Valo } 382bdcd8170SKalle Valo 383bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", 384bdcd8170SKalle Valo regdump_loc); 385bdcd8170SKalle Valo 386bdcd8170SKalle Valo regdump_loc = TARG_VTOP(regdump_loc); 387bdcd8170SKalle Valo 388bdcd8170SKalle Valo /* fetch register dump data */ 389bdcd8170SKalle Valo status = ath6kl_access_datadiag(ar, 390bdcd8170SKalle Valo regdump_loc, 391bdcd8170SKalle Valo (u8 *)®dump_val[0], 392bdcd8170SKalle Valo REG_DUMP_COUNT_AR6003 * (sizeof(u32)), 393bdcd8170SKalle Valo true); 394bdcd8170SKalle Valo 395bdcd8170SKalle Valo if (status) { 396bdcd8170SKalle Valo ath6kl_err("failed to get register dump\n"); 397bdcd8170SKalle Valo return; 398bdcd8170SKalle Valo } 399bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n"); 400bdcd8170SKalle Valo 401bdcd8170SKalle Valo for (i = 0; i < REG_DUMP_COUNT_AR6003; i++) 402bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, " %d : 0x%8.8X\n", 403bdcd8170SKalle Valo i, regdump_val[i]); 404bdcd8170SKalle Valo 405bdcd8170SKalle Valo } 406bdcd8170SKalle Valo 407bdcd8170SKalle Valo void ath6kl_target_failure(struct ath6kl *ar) 408bdcd8170SKalle Valo { 409bdcd8170SKalle Valo ath6kl_err("target asserted\n"); 410bdcd8170SKalle Valo 411bdcd8170SKalle Valo /* try dumping target assertion information (if any) */ 412bdcd8170SKalle Valo ath6kl_dump_target_assert_info(ar); 413bdcd8170SKalle Valo 414bdcd8170SKalle Valo } 415bdcd8170SKalle Valo 416bdcd8170SKalle Valo static int ath6kl_target_config_wlan_params(struct ath6kl *ar) 417bdcd8170SKalle Valo { 418bdcd8170SKalle Valo int status = 0; 419bdcd8170SKalle Valo 420bdcd8170SKalle Valo /* 421bdcd8170SKalle Valo * Configure the device for rx dot11 header rules. "0,0" are the 422bdcd8170SKalle Valo * default values. Required if checksum offload is needed. Set 423bdcd8170SKalle Valo * RxMetaVersion to 2. 424bdcd8170SKalle Valo */ 425bdcd8170SKalle Valo if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, 426bdcd8170SKalle Valo ar->rx_meta_ver, 0, 0)) { 427bdcd8170SKalle Valo ath6kl_err("unable to set the rx frame format\n"); 428bdcd8170SKalle Valo status = -EIO; 429bdcd8170SKalle Valo } 430bdcd8170SKalle Valo 431bdcd8170SKalle Valo if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) 432bdcd8170SKalle Valo if ((ath6kl_wmi_pmparams_cmd(ar->wmi, 0, 1, 0, 0, 1, 433bdcd8170SKalle Valo IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { 434bdcd8170SKalle Valo ath6kl_err("unable to set power save fail event policy\n"); 435bdcd8170SKalle Valo status = -EIO; 436bdcd8170SKalle Valo } 437bdcd8170SKalle Valo 438bdcd8170SKalle Valo if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) 439bdcd8170SKalle Valo if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, 0, 440bdcd8170SKalle Valo WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { 441bdcd8170SKalle Valo ath6kl_err("unable to set barker preamble policy\n"); 442bdcd8170SKalle Valo status = -EIO; 443bdcd8170SKalle Valo } 444bdcd8170SKalle Valo 445bdcd8170SKalle Valo if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, 446bdcd8170SKalle Valo WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { 447bdcd8170SKalle Valo ath6kl_err("unable to set keep alive interval\n"); 448bdcd8170SKalle Valo status = -EIO; 449bdcd8170SKalle Valo } 450bdcd8170SKalle Valo 451bdcd8170SKalle Valo if (ath6kl_wmi_disctimeout_cmd(ar->wmi, 452bdcd8170SKalle Valo WLAN_CONFIG_DISCONNECT_TIMEOUT)) { 453bdcd8170SKalle Valo ath6kl_err("unable to set disconnect timeout\n"); 454bdcd8170SKalle Valo status = -EIO; 455bdcd8170SKalle Valo } 456bdcd8170SKalle Valo 457bdcd8170SKalle Valo if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) 458bdcd8170SKalle Valo if (ath6kl_wmi_set_wmm_txop(ar->wmi, WMI_TXOP_DISABLED)) { 459bdcd8170SKalle Valo ath6kl_err("unable to set txop bursting\n"); 460bdcd8170SKalle Valo status = -EIO; 461bdcd8170SKalle Valo } 462bdcd8170SKalle Valo 463bdcd8170SKalle Valo return status; 464bdcd8170SKalle Valo } 465bdcd8170SKalle Valo 466bdcd8170SKalle Valo int ath6kl_configure_target(struct ath6kl *ar) 467bdcd8170SKalle Valo { 468bdcd8170SKalle Valo u32 param, ram_reserved_size; 469bdcd8170SKalle Valo u8 fw_iftype; 470bdcd8170SKalle Valo 471bdcd8170SKalle Valo fw_iftype = ath6kl_get_fw_iftype(ar); 472bdcd8170SKalle Valo if (fw_iftype == 0xff) 473bdcd8170SKalle Valo return -EINVAL; 474bdcd8170SKalle Valo 475bdcd8170SKalle Valo /* Tell target which HTC version it is used*/ 476bdcd8170SKalle Valo param = HTC_PROTOCOL_VERSION; 477bdcd8170SKalle Valo if (ath6kl_bmi_write(ar, 478bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 479bdcd8170SKalle Valo HI_ITEM(hi_app_host_interest)), 480bdcd8170SKalle Valo (u8 *)¶m, 4) != 0) { 481bdcd8170SKalle Valo ath6kl_err("bmi_write_memory for htc version failed\n"); 482bdcd8170SKalle Valo return -EIO; 483bdcd8170SKalle Valo } 484bdcd8170SKalle Valo 485bdcd8170SKalle Valo /* set the firmware mode to STA/IBSS/AP */ 486bdcd8170SKalle Valo param = 0; 487bdcd8170SKalle Valo 488bdcd8170SKalle Valo if (ath6kl_bmi_read(ar, 489bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 490bdcd8170SKalle Valo HI_ITEM(hi_option_flag)), 491bdcd8170SKalle Valo (u8 *)¶m, 4) != 0) { 492bdcd8170SKalle Valo ath6kl_err("bmi_read_memory for setting fwmode failed\n"); 493bdcd8170SKalle Valo return -EIO; 494bdcd8170SKalle Valo } 495bdcd8170SKalle Valo 496bdcd8170SKalle Valo param |= (1 << HI_OPTION_NUM_DEV_SHIFT); 497bdcd8170SKalle Valo param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT); 498bdcd8170SKalle Valo param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); 499bdcd8170SKalle Valo param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); 500bdcd8170SKalle Valo 501bdcd8170SKalle Valo if (ath6kl_bmi_write(ar, 502bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 503bdcd8170SKalle Valo HI_ITEM(hi_option_flag)), 504bdcd8170SKalle Valo (u8 *)¶m, 505bdcd8170SKalle Valo 4) != 0) { 506bdcd8170SKalle Valo ath6kl_err("bmi_write_memory for setting fwmode failed\n"); 507bdcd8170SKalle Valo return -EIO; 508bdcd8170SKalle Valo } 509bdcd8170SKalle Valo 510bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n"); 511bdcd8170SKalle Valo 512bdcd8170SKalle Valo /* 513bdcd8170SKalle Valo * Hardcode the address use for the extended board data 514bdcd8170SKalle Valo * Ideally this should be pre-allocate by the OS at boot time 515bdcd8170SKalle Valo * But since it is a new feature and board data is loaded 516bdcd8170SKalle Valo * at init time, we have to workaround this from host. 517bdcd8170SKalle Valo * It is difficult to patch the firmware boot code, 518bdcd8170SKalle Valo * but possible in theory. 519bdcd8170SKalle Valo */ 520bdcd8170SKalle Valo 521bdcd8170SKalle Valo if (ar->target_type == TARGET_TYPE_AR6003) { 522bdcd8170SKalle Valo if (ar->version.target_ver == AR6003_REV2_VERSION) { 523bdcd8170SKalle Valo param = AR6003_REV2_BOARD_EXT_DATA_ADDRESS; 524bdcd8170SKalle Valo ram_reserved_size = AR6003_REV2_RAM_RESERVE_SIZE; 525bdcd8170SKalle Valo } else { 526bdcd8170SKalle Valo param = AR6003_REV3_BOARD_EXT_DATA_ADDRESS; 527bdcd8170SKalle Valo ram_reserved_size = AR6003_REV3_RAM_RESERVE_SIZE; 528bdcd8170SKalle Valo } 529bdcd8170SKalle Valo 530bdcd8170SKalle Valo if (ath6kl_bmi_write(ar, 531bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 532bdcd8170SKalle Valo HI_ITEM(hi_board_ext_data)), 533bdcd8170SKalle Valo (u8 *)¶m, 4) != 0) { 534bdcd8170SKalle Valo ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); 535bdcd8170SKalle Valo return -EIO; 536bdcd8170SKalle Valo } 537bdcd8170SKalle Valo if (ath6kl_bmi_write(ar, 538bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 539bdcd8170SKalle Valo HI_ITEM(hi_end_ram_reserve_sz)), 540bdcd8170SKalle Valo (u8 *)&ram_reserved_size, 4) != 0) { 541bdcd8170SKalle Valo ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); 542bdcd8170SKalle Valo return -EIO; 543bdcd8170SKalle Valo } 544bdcd8170SKalle Valo } 545bdcd8170SKalle Valo 546bdcd8170SKalle Valo /* set the block size for the target */ 547bdcd8170SKalle Valo if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0)) 548bdcd8170SKalle Valo /* use default number of control buffers */ 549bdcd8170SKalle Valo return -EIO; 550bdcd8170SKalle Valo 551bdcd8170SKalle Valo return 0; 552bdcd8170SKalle Valo } 553bdcd8170SKalle Valo 554bdcd8170SKalle Valo struct ath6kl *ath6kl_core_alloc(struct device *sdev) 555bdcd8170SKalle Valo { 556bdcd8170SKalle Valo struct net_device *dev; 557bdcd8170SKalle Valo struct ath6kl *ar; 558bdcd8170SKalle Valo struct wireless_dev *wdev; 559bdcd8170SKalle Valo 560bdcd8170SKalle Valo wdev = ath6kl_cfg80211_init(sdev); 561bdcd8170SKalle Valo if (!wdev) { 562bdcd8170SKalle Valo ath6kl_err("ath6kl_cfg80211_init failed\n"); 563bdcd8170SKalle Valo return NULL; 564bdcd8170SKalle Valo } 565bdcd8170SKalle Valo 566bdcd8170SKalle Valo ar = wdev_priv(wdev); 567bdcd8170SKalle Valo ar->dev = sdev; 568bdcd8170SKalle Valo ar->wdev = wdev; 569bdcd8170SKalle Valo wdev->iftype = NL80211_IFTYPE_STATION; 570bdcd8170SKalle Valo 571bdcd8170SKalle Valo dev = alloc_netdev(0, "wlan%d", ether_setup); 572bdcd8170SKalle Valo if (!dev) { 573bdcd8170SKalle Valo ath6kl_err("no memory for network device instance\n"); 574bdcd8170SKalle Valo ath6kl_cfg80211_deinit(ar); 575bdcd8170SKalle Valo return NULL; 576bdcd8170SKalle Valo } 577bdcd8170SKalle Valo 578bdcd8170SKalle Valo dev->ieee80211_ptr = wdev; 579bdcd8170SKalle Valo SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); 580bdcd8170SKalle Valo wdev->netdev = dev; 581bdcd8170SKalle Valo ar->sme_state = SME_DISCONNECTED; 582bdcd8170SKalle Valo ar->auto_auth_stage = AUTH_IDLE; 583bdcd8170SKalle Valo 584bdcd8170SKalle Valo init_netdev(dev); 585bdcd8170SKalle Valo 586bdcd8170SKalle Valo ar->net_dev = dev; 587bdcd8170SKalle Valo ar->wlan_state = WLAN_ENABLED; 588bdcd8170SKalle Valo 589bdcd8170SKalle Valo ar->wlan_pwr_state = WLAN_POWER_STATE_ON; 590bdcd8170SKalle Valo 591bdcd8170SKalle Valo spin_lock_init(&ar->lock); 592bdcd8170SKalle Valo 593bdcd8170SKalle Valo ath6kl_init_control_info(ar); 594bdcd8170SKalle Valo init_waitqueue_head(&ar->event_wq); 595bdcd8170SKalle Valo sema_init(&ar->sem, 1); 596bdcd8170SKalle Valo clear_bit(DESTROY_IN_PROGRESS, &ar->flag); 597bdcd8170SKalle Valo 598bdcd8170SKalle Valo INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); 599bdcd8170SKalle Valo 600bdcd8170SKalle Valo setup_timer(&ar->disconnect_timer, disconnect_timer_handler, 601bdcd8170SKalle Valo (unsigned long) dev); 602bdcd8170SKalle Valo 603bdcd8170SKalle Valo return ar; 604bdcd8170SKalle Valo } 605bdcd8170SKalle Valo 606bdcd8170SKalle Valo int ath6kl_unavail_ev(struct ath6kl *ar) 607bdcd8170SKalle Valo { 608bdcd8170SKalle Valo ath6kl_destroy(ar->net_dev, 1); 609bdcd8170SKalle Valo 610bdcd8170SKalle Valo return 0; 611bdcd8170SKalle Valo } 612bdcd8170SKalle Valo 613bdcd8170SKalle Valo /* firmware upload */ 614bdcd8170SKalle Valo static u32 ath6kl_get_load_address(u32 target_ver, enum addr_type type) 615bdcd8170SKalle Valo { 616bdcd8170SKalle Valo WARN_ON(target_ver != AR6003_REV2_VERSION && 617bdcd8170SKalle Valo target_ver != AR6003_REV3_VERSION); 618bdcd8170SKalle Valo 619bdcd8170SKalle Valo switch (type) { 620bdcd8170SKalle Valo case DATASET_PATCH_ADDR: 621bdcd8170SKalle Valo return (target_ver == AR6003_REV2_VERSION) ? 622bdcd8170SKalle Valo AR6003_REV2_DATASET_PATCH_ADDRESS : 623bdcd8170SKalle Valo AR6003_REV3_DATASET_PATCH_ADDRESS; 624bdcd8170SKalle Valo case APP_LOAD_ADDR: 625bdcd8170SKalle Valo return (target_ver == AR6003_REV2_VERSION) ? 626bdcd8170SKalle Valo AR6003_REV2_APP_LOAD_ADDRESS : 627bdcd8170SKalle Valo 0x1234; 628bdcd8170SKalle Valo case APP_START_OVERRIDE_ADDR: 629bdcd8170SKalle Valo return (target_ver == AR6003_REV2_VERSION) ? 630bdcd8170SKalle Valo AR6003_REV2_APP_START_OVERRIDE : 631bdcd8170SKalle Valo AR6003_REV3_APP_START_OVERRIDE; 632bdcd8170SKalle Valo default: 633bdcd8170SKalle Valo return 0; 634bdcd8170SKalle Valo } 635bdcd8170SKalle Valo } 636bdcd8170SKalle Valo 637bdcd8170SKalle Valo static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, 638bdcd8170SKalle Valo u8 **fw, size_t *fw_len) 639bdcd8170SKalle Valo { 640bdcd8170SKalle Valo const struct firmware *fw_entry; 641bdcd8170SKalle Valo int ret; 642bdcd8170SKalle Valo 643bdcd8170SKalle Valo ret = request_firmware(&fw_entry, filename, ar->dev); 644bdcd8170SKalle Valo if (ret) 645bdcd8170SKalle Valo return ret; 646bdcd8170SKalle Valo 647bdcd8170SKalle Valo *fw_len = fw_entry->size; 648bdcd8170SKalle Valo *fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); 649bdcd8170SKalle Valo 650bdcd8170SKalle Valo if (*fw == NULL) 651bdcd8170SKalle Valo ret = -ENOMEM; 652bdcd8170SKalle Valo 653bdcd8170SKalle Valo release_firmware(fw_entry); 654bdcd8170SKalle Valo 655bdcd8170SKalle Valo return ret; 656bdcd8170SKalle Valo } 657bdcd8170SKalle Valo 658bdcd8170SKalle Valo static int ath6kl_fetch_board_file(struct ath6kl *ar) 659bdcd8170SKalle Valo { 660bdcd8170SKalle Valo const char *filename; 661bdcd8170SKalle Valo int ret; 662bdcd8170SKalle Valo 663bdcd8170SKalle Valo switch (ar->version.target_ver) { 664bdcd8170SKalle Valo case AR6003_REV2_VERSION: 665bdcd8170SKalle Valo filename = AR6003_REV2_BOARD_DATA_FILE; 666bdcd8170SKalle Valo break; 667bdcd8170SKalle Valo default: 668bdcd8170SKalle Valo filename = AR6003_REV3_BOARD_DATA_FILE; 669bdcd8170SKalle Valo break; 670bdcd8170SKalle Valo } 671bdcd8170SKalle Valo 672bdcd8170SKalle Valo ret = ath6kl_get_fw(ar, filename, &ar->fw_board, 673bdcd8170SKalle Valo &ar->fw_board_len); 674bdcd8170SKalle Valo if (ret == 0) { 675bdcd8170SKalle Valo /* managed to get proper board file */ 676bdcd8170SKalle Valo return 0; 677bdcd8170SKalle Valo } 678bdcd8170SKalle Valo 679bdcd8170SKalle Valo /* there was no proper board file, try to use default instead */ 680bdcd8170SKalle Valo ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", 681bdcd8170SKalle Valo filename, ret); 682bdcd8170SKalle Valo 683bdcd8170SKalle Valo switch (ar->version.target_ver) { 684bdcd8170SKalle Valo case AR6003_REV2_VERSION: 685bdcd8170SKalle Valo filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE; 686bdcd8170SKalle Valo break; 687bdcd8170SKalle Valo default: 688bdcd8170SKalle Valo filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE; 689bdcd8170SKalle Valo break; 690bdcd8170SKalle Valo } 691bdcd8170SKalle Valo 692bdcd8170SKalle Valo ret = ath6kl_get_fw(ar, filename, &ar->fw_board, 693bdcd8170SKalle Valo &ar->fw_board_len); 694bdcd8170SKalle Valo if (ret) { 695bdcd8170SKalle Valo ath6kl_err("Failed to get default board file %s: %d\n", 696bdcd8170SKalle Valo filename, ret); 697bdcd8170SKalle Valo return ret; 698bdcd8170SKalle Valo } 699bdcd8170SKalle Valo 700bdcd8170SKalle Valo ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n"); 701bdcd8170SKalle Valo ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n"); 702bdcd8170SKalle Valo 703bdcd8170SKalle Valo return 0; 704bdcd8170SKalle Valo } 705bdcd8170SKalle Valo 706bdcd8170SKalle Valo 707bdcd8170SKalle Valo static int ath6kl_upload_board_file(struct ath6kl *ar) 708bdcd8170SKalle Valo { 709bdcd8170SKalle Valo u32 board_address, board_ext_address, param; 710bdcd8170SKalle Valo int ret; 711bdcd8170SKalle Valo 712bdcd8170SKalle Valo if (ar->fw_board == NULL) { 713bdcd8170SKalle Valo ret = ath6kl_fetch_board_file(ar); 714bdcd8170SKalle Valo if (ret) 715bdcd8170SKalle Valo return ret; 716bdcd8170SKalle Valo } 717bdcd8170SKalle Valo 718bdcd8170SKalle Valo /* Determine where in Target RAM to write Board Data */ 719bdcd8170SKalle Valo ath6kl_bmi_read(ar, 720bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 721bdcd8170SKalle Valo HI_ITEM(hi_board_data)), 722bdcd8170SKalle Valo (u8 *) &board_address, 4); 723bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "board data download addr: 0x%x\n", 724bdcd8170SKalle Valo board_address); 725bdcd8170SKalle Valo 726bdcd8170SKalle Valo /* determine where in target ram to write extended board data */ 727bdcd8170SKalle Valo ath6kl_bmi_read(ar, 728bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 729bdcd8170SKalle Valo HI_ITEM(hi_board_ext_data)), 730bdcd8170SKalle Valo (u8 *) &board_ext_address, 4); 731bdcd8170SKalle Valo 732bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "board file download addr: 0x%x\n", 733bdcd8170SKalle Valo board_ext_address); 734bdcd8170SKalle Valo 735bdcd8170SKalle Valo if (board_ext_address == 0) { 736bdcd8170SKalle Valo ath6kl_err("Failed to get board file target address.\n"); 737bdcd8170SKalle Valo return -EINVAL; 738bdcd8170SKalle Valo } 739bdcd8170SKalle Valo 740bdcd8170SKalle Valo if (ar->fw_board_len == (AR6003_BOARD_DATA_SZ + 741bdcd8170SKalle Valo AR6003_BOARD_EXT_DATA_SZ)) { 742bdcd8170SKalle Valo /* write extended board data */ 743bdcd8170SKalle Valo ret = ath6kl_bmi_write(ar, board_ext_address, 744bdcd8170SKalle Valo ar->fw_board + AR6003_BOARD_DATA_SZ, 745bdcd8170SKalle Valo AR6003_BOARD_EXT_DATA_SZ); 746bdcd8170SKalle Valo 747bdcd8170SKalle Valo if (ret) { 748bdcd8170SKalle Valo ath6kl_err("Failed to write extended board data: %d\n", 749bdcd8170SKalle Valo ret); 750bdcd8170SKalle Valo return ret; 751bdcd8170SKalle Valo } 752bdcd8170SKalle Valo 753bdcd8170SKalle Valo /* record that extended board data is initialized */ 754bdcd8170SKalle Valo param = (AR6003_BOARD_EXT_DATA_SZ << 16) | 1; 755bdcd8170SKalle Valo ath6kl_bmi_write(ar, 756bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 757bdcd8170SKalle Valo HI_ITEM(hi_board_ext_data_config)), 758bdcd8170SKalle Valo (unsigned char *) ¶m, 4); 759bdcd8170SKalle Valo } 760bdcd8170SKalle Valo 761bdcd8170SKalle Valo if (ar->fw_board_len < AR6003_BOARD_DATA_SZ) { 762bdcd8170SKalle Valo ath6kl_err("Too small board file: %zu\n", ar->fw_board_len); 763bdcd8170SKalle Valo ret = -EINVAL; 764bdcd8170SKalle Valo return ret; 765bdcd8170SKalle Valo } 766bdcd8170SKalle Valo 767bdcd8170SKalle Valo ret = ath6kl_bmi_write(ar, board_address, ar->fw_board, 768bdcd8170SKalle Valo AR6003_BOARD_DATA_SZ); 769bdcd8170SKalle Valo 770bdcd8170SKalle Valo if (ret) { 771bdcd8170SKalle Valo ath6kl_err("Board file bmi write failed: %d\n", ret); 772bdcd8170SKalle Valo return ret; 773bdcd8170SKalle Valo } 774bdcd8170SKalle Valo 775bdcd8170SKalle Valo /* record the fact that Board Data IS initialized */ 776bdcd8170SKalle Valo param = 1; 777bdcd8170SKalle Valo ath6kl_bmi_write(ar, 778bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 779bdcd8170SKalle Valo HI_ITEM(hi_board_data_initialized)), 780bdcd8170SKalle Valo (u8 *)¶m, 4); 781bdcd8170SKalle Valo 782bdcd8170SKalle Valo return ret; 783bdcd8170SKalle Valo } 784bdcd8170SKalle Valo 785bdcd8170SKalle Valo static int ath6kl_upload_otp(struct ath6kl *ar) 786bdcd8170SKalle Valo { 787bdcd8170SKalle Valo const char *filename; 788bdcd8170SKalle Valo u32 address, param; 789bdcd8170SKalle Valo int ret; 790bdcd8170SKalle Valo 791bdcd8170SKalle Valo switch (ar->version.target_ver) { 792bdcd8170SKalle Valo case AR6003_REV2_VERSION: 793bdcd8170SKalle Valo filename = AR6003_REV2_OTP_FILE; 794bdcd8170SKalle Valo break; 795bdcd8170SKalle Valo default: 796bdcd8170SKalle Valo filename = AR6003_REV3_OTP_FILE; 797bdcd8170SKalle Valo break; 798bdcd8170SKalle Valo } 799bdcd8170SKalle Valo 800bdcd8170SKalle Valo if (ar->fw_otp == NULL) { 801bdcd8170SKalle Valo ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, 802bdcd8170SKalle Valo &ar->fw_otp_len); 803bdcd8170SKalle Valo if (ret) { 804bdcd8170SKalle Valo ath6kl_err("Failed to get OTP file %s: %d\n", 805bdcd8170SKalle Valo filename, ret); 806bdcd8170SKalle Valo return ret; 807bdcd8170SKalle Valo } 808bdcd8170SKalle Valo } 809bdcd8170SKalle Valo 810bdcd8170SKalle Valo address = ath6kl_get_load_address(ar->version.target_ver, 811bdcd8170SKalle Valo APP_LOAD_ADDR); 812bdcd8170SKalle Valo 813bdcd8170SKalle Valo ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, 814bdcd8170SKalle Valo ar->fw_otp_len); 815bdcd8170SKalle Valo if (ret) { 816bdcd8170SKalle Valo ath6kl_err("Failed to upload OTP file: %d\n", ret); 817bdcd8170SKalle Valo return ret; 818bdcd8170SKalle Valo } 819bdcd8170SKalle Valo 820bdcd8170SKalle Valo /* execute the OTP code */ 821bdcd8170SKalle Valo param = 0; 822bdcd8170SKalle Valo address = ath6kl_get_load_address(ar->version.target_ver, 823bdcd8170SKalle Valo APP_START_OVERRIDE_ADDR); 824bdcd8170SKalle Valo ath6kl_bmi_execute(ar, address, ¶m); 825bdcd8170SKalle Valo 826bdcd8170SKalle Valo return ret; 827bdcd8170SKalle Valo } 828bdcd8170SKalle Valo 829bdcd8170SKalle Valo static int ath6kl_upload_firmware(struct ath6kl *ar) 830bdcd8170SKalle Valo { 831bdcd8170SKalle Valo const char *filename; 832bdcd8170SKalle Valo u32 address; 833bdcd8170SKalle Valo int ret; 834bdcd8170SKalle Valo 835bdcd8170SKalle Valo switch (ar->version.target_ver) { 836bdcd8170SKalle Valo case AR6003_REV2_VERSION: 837bdcd8170SKalle Valo filename = AR6003_REV2_FIRMWARE_FILE; 838bdcd8170SKalle Valo break; 839bdcd8170SKalle Valo default: 840bdcd8170SKalle Valo filename = AR6003_REV3_FIRMWARE_FILE; 841bdcd8170SKalle Valo break; 842bdcd8170SKalle Valo } 843bdcd8170SKalle Valo 844bdcd8170SKalle Valo if (ar->fw == NULL) { 845bdcd8170SKalle Valo ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); 846bdcd8170SKalle Valo if (ret) { 847bdcd8170SKalle Valo ath6kl_err("Failed to get firmware file %s: %d\n", 848bdcd8170SKalle Valo filename, ret); 849bdcd8170SKalle Valo return ret; 850bdcd8170SKalle Valo } 851bdcd8170SKalle Valo } 852bdcd8170SKalle Valo 853bdcd8170SKalle Valo address = ath6kl_get_load_address(ar->version.target_ver, 854bdcd8170SKalle Valo APP_LOAD_ADDR); 855bdcd8170SKalle Valo 856bdcd8170SKalle Valo ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len); 857bdcd8170SKalle Valo 858bdcd8170SKalle Valo if (ret) { 859bdcd8170SKalle Valo ath6kl_err("Failed to write firmware: %d\n", ret); 860bdcd8170SKalle Valo return ret; 861bdcd8170SKalle Valo } 862bdcd8170SKalle Valo 863bdcd8170SKalle Valo /* Set starting address for firmware */ 864bdcd8170SKalle Valo address = ath6kl_get_load_address(ar->version.target_ver, 865bdcd8170SKalle Valo APP_START_OVERRIDE_ADDR); 866bdcd8170SKalle Valo ath6kl_bmi_set_app_start(ar, address); 867bdcd8170SKalle Valo 868bdcd8170SKalle Valo return ret; 869bdcd8170SKalle Valo } 870bdcd8170SKalle Valo 871bdcd8170SKalle Valo static int ath6kl_upload_patch(struct ath6kl *ar) 872bdcd8170SKalle Valo { 873bdcd8170SKalle Valo const char *filename; 874bdcd8170SKalle Valo u32 address, param; 875bdcd8170SKalle Valo int ret; 876bdcd8170SKalle Valo 877bdcd8170SKalle Valo switch (ar->version.target_ver) { 878bdcd8170SKalle Valo case AR6003_REV2_VERSION: 879bdcd8170SKalle Valo filename = AR6003_REV2_PATCH_FILE; 880bdcd8170SKalle Valo break; 881bdcd8170SKalle Valo default: 882bdcd8170SKalle Valo filename = AR6003_REV3_PATCH_FILE; 883bdcd8170SKalle Valo break; 884bdcd8170SKalle Valo } 885bdcd8170SKalle Valo 886bdcd8170SKalle Valo if (ar->fw_patch == NULL) { 887bdcd8170SKalle Valo ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, 888bdcd8170SKalle Valo &ar->fw_patch_len); 889bdcd8170SKalle Valo if (ret) { 890bdcd8170SKalle Valo ath6kl_err("Failed to get patch file %s: %d\n", 891bdcd8170SKalle Valo filename, ret); 892bdcd8170SKalle Valo return ret; 893bdcd8170SKalle Valo } 894bdcd8170SKalle Valo } 895bdcd8170SKalle Valo 896bdcd8170SKalle Valo address = ath6kl_get_load_address(ar->version.target_ver, 897bdcd8170SKalle Valo DATASET_PATCH_ADDR); 898bdcd8170SKalle Valo 899bdcd8170SKalle Valo ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); 900bdcd8170SKalle Valo if (ret) { 901bdcd8170SKalle Valo ath6kl_err("Failed to write patch file: %d\n", ret); 902bdcd8170SKalle Valo return ret; 903bdcd8170SKalle Valo } 904bdcd8170SKalle Valo 905bdcd8170SKalle Valo param = address; 906bdcd8170SKalle Valo ath6kl_bmi_write(ar, 907bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 908bdcd8170SKalle Valo HI_ITEM(hi_dset_list_head)), 909bdcd8170SKalle Valo (unsigned char *) ¶m, 4); 910bdcd8170SKalle Valo 911bdcd8170SKalle Valo return 0; 912bdcd8170SKalle Valo } 913bdcd8170SKalle Valo 914bdcd8170SKalle Valo static int ath6kl_init_upload(struct ath6kl *ar) 915bdcd8170SKalle Valo { 916bdcd8170SKalle Valo u32 param, options, sleep, address; 917bdcd8170SKalle Valo int status = 0; 918bdcd8170SKalle Valo 919bdcd8170SKalle Valo if (ar->target_type != TARGET_TYPE_AR6003) 920bdcd8170SKalle Valo return -EINVAL; 921bdcd8170SKalle Valo 922bdcd8170SKalle Valo /* temporarily disable system sleep */ 923bdcd8170SKalle Valo address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS; 924bdcd8170SKalle Valo status = ath6kl_bmi_reg_read(ar, address, ¶m); 925bdcd8170SKalle Valo if (status) 926bdcd8170SKalle Valo return status; 927bdcd8170SKalle Valo 928bdcd8170SKalle Valo options = param; 929bdcd8170SKalle Valo 930bdcd8170SKalle Valo param |= ATH6KL_OPTION_SLEEP_DISABLE; 931bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 932bdcd8170SKalle Valo if (status) 933bdcd8170SKalle Valo return status; 934bdcd8170SKalle Valo 935bdcd8170SKalle Valo address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; 936bdcd8170SKalle Valo status = ath6kl_bmi_reg_read(ar, address, ¶m); 937bdcd8170SKalle Valo if (status) 938bdcd8170SKalle Valo return status; 939bdcd8170SKalle Valo 940bdcd8170SKalle Valo sleep = param; 941bdcd8170SKalle Valo 942bdcd8170SKalle Valo param |= SM(SYSTEM_SLEEP_DISABLE, 1); 943bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 944bdcd8170SKalle Valo if (status) 945bdcd8170SKalle Valo return status; 946bdcd8170SKalle Valo 947bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n", 948bdcd8170SKalle Valo options, sleep); 949bdcd8170SKalle Valo 950bdcd8170SKalle Valo /* program analog PLL register */ 951bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER, 952bdcd8170SKalle Valo 0xF9104001); 953bdcd8170SKalle Valo if (status) 954bdcd8170SKalle Valo return status; 955bdcd8170SKalle Valo 956bdcd8170SKalle Valo /* Run at 80/88MHz by default */ 957bdcd8170SKalle Valo param = SM(CPU_CLOCK_STANDARD, 1); 958bdcd8170SKalle Valo 959bdcd8170SKalle Valo address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS; 960bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 961bdcd8170SKalle Valo if (status) 962bdcd8170SKalle Valo return status; 963bdcd8170SKalle Valo 964bdcd8170SKalle Valo param = 0; 965bdcd8170SKalle Valo address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS; 966bdcd8170SKalle Valo param = SM(LPO_CAL_ENABLE, 1); 967bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 968bdcd8170SKalle Valo if (status) 969bdcd8170SKalle Valo return status; 970bdcd8170SKalle Valo 971bdcd8170SKalle Valo /* WAR to avoid SDIO CRC err */ 972bdcd8170SKalle Valo if (ar->version.target_ver == AR6003_REV2_VERSION) { 973bdcd8170SKalle Valo ath6kl_err("temporary war to avoid sdio crc error\n"); 974bdcd8170SKalle Valo 975bdcd8170SKalle Valo param = 0x20; 976bdcd8170SKalle Valo 977bdcd8170SKalle Valo address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS; 978bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 979bdcd8170SKalle Valo if (status) 980bdcd8170SKalle Valo return status; 981bdcd8170SKalle Valo 982bdcd8170SKalle Valo address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS; 983bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 984bdcd8170SKalle Valo if (status) 985bdcd8170SKalle Valo return status; 986bdcd8170SKalle Valo 987bdcd8170SKalle Valo address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS; 988bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 989bdcd8170SKalle Valo if (status) 990bdcd8170SKalle Valo return status; 991bdcd8170SKalle Valo 992bdcd8170SKalle Valo address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS; 993bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 994bdcd8170SKalle Valo if (status) 995bdcd8170SKalle Valo return status; 996bdcd8170SKalle Valo } 997bdcd8170SKalle Valo 998bdcd8170SKalle Valo /* write EEPROM data to Target RAM */ 999bdcd8170SKalle Valo status = ath6kl_upload_board_file(ar); 1000bdcd8170SKalle Valo if (status) 1001bdcd8170SKalle Valo return status; 1002bdcd8170SKalle Valo 1003bdcd8170SKalle Valo /* transfer One time Programmable data */ 1004bdcd8170SKalle Valo status = ath6kl_upload_otp(ar); 1005bdcd8170SKalle Valo if (status) 1006bdcd8170SKalle Valo return status; 1007bdcd8170SKalle Valo 1008bdcd8170SKalle Valo /* Download Target firmware */ 1009bdcd8170SKalle Valo status = ath6kl_upload_firmware(ar); 1010bdcd8170SKalle Valo if (status) 1011bdcd8170SKalle Valo return status; 1012bdcd8170SKalle Valo 1013bdcd8170SKalle Valo status = ath6kl_upload_patch(ar); 1014bdcd8170SKalle Valo if (status) 1015bdcd8170SKalle Valo return status; 1016bdcd8170SKalle Valo 1017bdcd8170SKalle Valo /* Restore system sleep */ 1018bdcd8170SKalle Valo address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; 1019bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, sleep); 1020bdcd8170SKalle Valo if (status) 1021bdcd8170SKalle Valo return status; 1022bdcd8170SKalle Valo 1023bdcd8170SKalle Valo address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS; 1024bdcd8170SKalle Valo param = options | 0x20; 1025bdcd8170SKalle Valo status = ath6kl_bmi_reg_write(ar, address, param); 1026bdcd8170SKalle Valo if (status) 1027bdcd8170SKalle Valo return status; 1028bdcd8170SKalle Valo 1029bdcd8170SKalle Valo /* Configure GPIO AR6003 UART */ 1030bdcd8170SKalle Valo param = CONFIG_AR600x_DEBUG_UART_TX_PIN; 1031bdcd8170SKalle Valo status = ath6kl_bmi_write(ar, 1032bdcd8170SKalle Valo ath6kl_get_hi_item_addr(ar, 1033bdcd8170SKalle Valo HI_ITEM(hi_dbg_uart_txpin)), 1034bdcd8170SKalle Valo (u8 *)¶m, 4); 1035bdcd8170SKalle Valo 1036bdcd8170SKalle Valo return status; 1037bdcd8170SKalle Valo } 1038bdcd8170SKalle Valo 1039bdcd8170SKalle Valo static int ath6kl_init(struct net_device *dev) 1040bdcd8170SKalle Valo { 1041bdcd8170SKalle Valo struct ath6kl *ar = ath6kl_priv(dev); 1042bdcd8170SKalle Valo int status = 0; 1043bdcd8170SKalle Valo s32 timeleft; 1044bdcd8170SKalle Valo 1045bdcd8170SKalle Valo if (!ar) 1046bdcd8170SKalle Valo return -EIO; 1047bdcd8170SKalle Valo 1048bdcd8170SKalle Valo /* Do we need to finish the BMI phase */ 1049bdcd8170SKalle Valo if (ath6kl_bmi_done(ar)) { 1050bdcd8170SKalle Valo status = -EIO; 1051bdcd8170SKalle Valo goto ath6kl_init_done; 1052bdcd8170SKalle Valo } 1053bdcd8170SKalle Valo 1054bdcd8170SKalle Valo /* Indicate that WMI is enabled (although not ready yet) */ 1055bdcd8170SKalle Valo set_bit(WMI_ENABLED, &ar->flag); 1056bdcd8170SKalle Valo ar->wmi = ath6kl_wmi_init((void *) ar); 1057bdcd8170SKalle Valo if (!ar->wmi) { 1058bdcd8170SKalle Valo ath6kl_err("failed to initialize wmi\n"); 1059bdcd8170SKalle Valo status = -EIO; 1060bdcd8170SKalle Valo goto ath6kl_init_done; 1061bdcd8170SKalle Valo } 1062bdcd8170SKalle Valo 1063bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); 1064bdcd8170SKalle Valo 1065bdcd8170SKalle Valo /* 1066bdcd8170SKalle Valo * The reason we have to wait for the target here is that the 1067bdcd8170SKalle Valo * driver layer has to init BMI in order to set the host block 1068bdcd8170SKalle Valo * size. 1069bdcd8170SKalle Valo */ 1070bdcd8170SKalle Valo if (htc_wait_target(ar->htc_target)) { 1071bdcd8170SKalle Valo status = -EIO; 1072bdcd8170SKalle Valo goto err_wmi_cleanup; 1073bdcd8170SKalle Valo } 1074bdcd8170SKalle Valo 1075bdcd8170SKalle Valo if (ath6kl_init_service_ep(ar)) { 1076bdcd8170SKalle Valo status = -EIO; 1077bdcd8170SKalle Valo goto err_cleanup_scatter; 1078bdcd8170SKalle Valo } 1079bdcd8170SKalle Valo 1080bdcd8170SKalle Valo /* setup access class priority mappings */ 1081bdcd8170SKalle Valo ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ 1082bdcd8170SKalle Valo ar->ac_stream_pri_map[WMM_AC_BE] = 1; 1083bdcd8170SKalle Valo ar->ac_stream_pri_map[WMM_AC_VI] = 2; 1084bdcd8170SKalle Valo ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ 1085bdcd8170SKalle Valo 1086bdcd8170SKalle Valo /* give our connected endpoints some buffers */ 1087bdcd8170SKalle Valo ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); 1088bdcd8170SKalle Valo ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); 1089bdcd8170SKalle Valo 1090bdcd8170SKalle Valo /* allocate some buffers that handle larger AMSDU frames */ 1091bdcd8170SKalle Valo ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); 1092bdcd8170SKalle Valo 1093bdcd8170SKalle Valo /* setup credit distribution */ 1094bdcd8170SKalle Valo ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info); 1095bdcd8170SKalle Valo 1096bdcd8170SKalle Valo ath6kl_cookie_init(ar); 1097bdcd8170SKalle Valo 1098bdcd8170SKalle Valo /* start HTC */ 1099bdcd8170SKalle Valo status = htc_start(ar->htc_target); 1100bdcd8170SKalle Valo 1101bdcd8170SKalle Valo if (status) { 1102bdcd8170SKalle Valo ath6kl_cookie_cleanup(ar); 1103bdcd8170SKalle Valo goto err_rxbuf_cleanup; 1104bdcd8170SKalle Valo } 1105bdcd8170SKalle Valo 1106bdcd8170SKalle Valo /* Wait for Wmi event to be ready */ 1107bdcd8170SKalle Valo timeleft = wait_event_interruptible_timeout(ar->event_wq, 1108bdcd8170SKalle Valo test_bit(WMI_READY, 1109bdcd8170SKalle Valo &ar->flag), 1110bdcd8170SKalle Valo WMI_TIMEOUT); 1111bdcd8170SKalle Valo 1112bdcd8170SKalle Valo if (ar->version.abi_ver != ATH6KL_ABI_VERSION) { 1113bdcd8170SKalle Valo ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n", 1114bdcd8170SKalle Valo ATH6KL_ABI_VERSION, ar->version.abi_ver); 1115bdcd8170SKalle Valo status = -EIO; 1116bdcd8170SKalle Valo goto err_htc_stop; 1117bdcd8170SKalle Valo } 1118bdcd8170SKalle Valo 1119bdcd8170SKalle Valo if (!timeleft || signal_pending(current)) { 1120bdcd8170SKalle Valo ath6kl_err("wmi is not ready or wait was interrupted\n"); 1121bdcd8170SKalle Valo status = -EIO; 1122bdcd8170SKalle Valo goto err_htc_stop; 1123bdcd8170SKalle Valo } 1124bdcd8170SKalle Valo 1125bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__); 1126bdcd8170SKalle Valo 1127bdcd8170SKalle Valo /* communicate the wmi protocol verision to the target */ 1128bdcd8170SKalle Valo if ((ath6kl_set_host_app_area(ar)) != 0) 1129bdcd8170SKalle Valo ath6kl_err("unable to set the host app area\n"); 1130bdcd8170SKalle Valo 1131bdcd8170SKalle Valo ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | 1132bdcd8170SKalle Valo ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; 1133bdcd8170SKalle Valo 1134bdcd8170SKalle Valo status = ath6kl_target_config_wlan_params(ar); 1135bdcd8170SKalle Valo if (!status) 1136bdcd8170SKalle Valo goto ath6kl_init_done; 1137bdcd8170SKalle Valo 1138bdcd8170SKalle Valo err_htc_stop: 1139bdcd8170SKalle Valo htc_stop(ar->htc_target); 1140bdcd8170SKalle Valo err_rxbuf_cleanup: 1141bdcd8170SKalle Valo htc_flush_rx_buf(ar->htc_target); 1142bdcd8170SKalle Valo ath6kl_cleanup_amsdu_rxbufs(ar); 1143bdcd8170SKalle Valo err_cleanup_scatter: 1144bdcd8170SKalle Valo ath6kl_hif_cleanup_scatter(ar); 1145bdcd8170SKalle Valo err_wmi_cleanup: 1146bdcd8170SKalle Valo ath6kl_wmi_shutdown(ar->wmi); 1147bdcd8170SKalle Valo clear_bit(WMI_ENABLED, &ar->flag); 1148bdcd8170SKalle Valo ar->wmi = NULL; 1149bdcd8170SKalle Valo 1150bdcd8170SKalle Valo ath6kl_init_done: 1151bdcd8170SKalle Valo return status; 1152bdcd8170SKalle Valo } 1153bdcd8170SKalle Valo 1154bdcd8170SKalle Valo int ath6kl_core_init(struct ath6kl *ar) 1155bdcd8170SKalle Valo { 1156bdcd8170SKalle Valo int ret = 0; 1157bdcd8170SKalle Valo struct ath6kl_bmi_target_info targ_info; 1158bdcd8170SKalle Valo 1159bdcd8170SKalle Valo ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); 1160bdcd8170SKalle Valo if (!ar->ath6kl_wq) 1161bdcd8170SKalle Valo return -ENOMEM; 1162bdcd8170SKalle Valo 1163bdcd8170SKalle Valo ret = ath6kl_bmi_init(ar); 1164bdcd8170SKalle Valo if (ret) 1165bdcd8170SKalle Valo goto err_wq; 1166bdcd8170SKalle Valo 1167bdcd8170SKalle Valo ret = ath6kl_bmi_get_target_info(ar, &targ_info); 1168bdcd8170SKalle Valo if (ret) 1169bdcd8170SKalle Valo goto err_bmi_cleanup; 1170bdcd8170SKalle Valo 1171bdcd8170SKalle Valo ar->version.target_ver = le32_to_cpu(targ_info.version); 1172bdcd8170SKalle Valo ar->target_type = le32_to_cpu(targ_info.type); 1173bdcd8170SKalle Valo ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); 1174bdcd8170SKalle Valo 1175bdcd8170SKalle Valo ret = ath6kl_configure_target(ar); 1176bdcd8170SKalle Valo if (ret) 1177bdcd8170SKalle Valo goto err_bmi_cleanup; 1178bdcd8170SKalle Valo 1179bdcd8170SKalle Valo ar->htc_target = htc_create(ar); 1180bdcd8170SKalle Valo 1181bdcd8170SKalle Valo if (!ar->htc_target) { 1182bdcd8170SKalle Valo ret = -ENOMEM; 1183bdcd8170SKalle Valo goto err_bmi_cleanup; 1184bdcd8170SKalle Valo } 1185bdcd8170SKalle Valo 1186bdcd8170SKalle Valo ar->aggr_cntxt = aggr_init(ar->net_dev); 1187bdcd8170SKalle Valo if (!ar->aggr_cntxt) { 1188bdcd8170SKalle Valo ath6kl_err("failed to initialize aggr\n"); 1189bdcd8170SKalle Valo ret = -ENOMEM; 1190bdcd8170SKalle Valo goto err_htc_cleanup; 1191bdcd8170SKalle Valo } 1192bdcd8170SKalle Valo 1193bdcd8170SKalle Valo ret = ath6kl_init_upload(ar); 1194bdcd8170SKalle Valo if (ret) 1195bdcd8170SKalle Valo goto err_htc_cleanup; 1196bdcd8170SKalle Valo 1197bdcd8170SKalle Valo ret = ath6kl_init(ar->net_dev); 1198bdcd8170SKalle Valo if (ret) 1199bdcd8170SKalle Valo goto err_htc_cleanup; 1200bdcd8170SKalle Valo 1201bdcd8170SKalle Valo /* This runs the init function if registered */ 1202bdcd8170SKalle Valo ret = register_netdev(ar->net_dev); 1203bdcd8170SKalle Valo if (ret) { 1204bdcd8170SKalle Valo ath6kl_err("register_netdev failed\n"); 1205bdcd8170SKalle Valo ath6kl_destroy(ar->net_dev, 0); 1206bdcd8170SKalle Valo return ret; 1207bdcd8170SKalle Valo } 1208bdcd8170SKalle Valo 1209bdcd8170SKalle Valo set_bit(NETDEV_REGISTERED, &ar->flag); 1210bdcd8170SKalle Valo 1211bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", 1212bdcd8170SKalle Valo __func__, ar->net_dev->name, ar->net_dev, ar); 1213bdcd8170SKalle Valo 1214bdcd8170SKalle Valo return ret; 1215bdcd8170SKalle Valo 1216bdcd8170SKalle Valo err_htc_cleanup: 1217bdcd8170SKalle Valo htc_cleanup(ar->htc_target); 1218bdcd8170SKalle Valo err_bmi_cleanup: 1219bdcd8170SKalle Valo ath6kl_bmi_cleanup(ar); 1220bdcd8170SKalle Valo err_wq: 1221bdcd8170SKalle Valo destroy_workqueue(ar->ath6kl_wq); 1222bdcd8170SKalle Valo return ret; 1223bdcd8170SKalle Valo } 1224bdcd8170SKalle Valo 1225bdcd8170SKalle Valo void ath6kl_stop_txrx(struct ath6kl *ar) 1226bdcd8170SKalle Valo { 1227bdcd8170SKalle Valo struct net_device *ndev = ar->net_dev; 1228bdcd8170SKalle Valo 1229bdcd8170SKalle Valo if (!ndev) 1230bdcd8170SKalle Valo return; 1231bdcd8170SKalle Valo 1232bdcd8170SKalle Valo set_bit(DESTROY_IN_PROGRESS, &ar->flag); 1233bdcd8170SKalle Valo 1234bdcd8170SKalle Valo if (down_interruptible(&ar->sem)) { 1235bdcd8170SKalle Valo ath6kl_err("down_interruptible failed\n"); 1236bdcd8170SKalle Valo return; 1237bdcd8170SKalle Valo } 1238bdcd8170SKalle Valo 1239bdcd8170SKalle Valo if (ar->wlan_pwr_state != WLAN_POWER_STATE_CUT_PWR) 1240bdcd8170SKalle Valo ath6kl_stop_endpoint(ndev, false, true); 1241bdcd8170SKalle Valo 1242bdcd8170SKalle Valo ar->wlan_state = WLAN_DISABLED; 1243bdcd8170SKalle Valo } 1244bdcd8170SKalle Valo 1245bdcd8170SKalle Valo /* 1246bdcd8170SKalle Valo * We need to differentiate between the surprise and planned removal of the 1247bdcd8170SKalle Valo * device because of the following consideration: 1248bdcd8170SKalle Valo * 1249bdcd8170SKalle Valo * - In case of surprise removal, the hcd already frees up the pending 1250bdcd8170SKalle Valo * for the device and hence there is no need to unregister the function 1251bdcd8170SKalle Valo * driver inorder to get these requests. For planned removal, the function 1252bdcd8170SKalle Valo * driver has to explicitly unregister itself to have the hcd return all the 1253bdcd8170SKalle Valo * pending requests before the data structures for the devices are freed up. 1254bdcd8170SKalle Valo * Note that as per the current implementation, the function driver will 1255bdcd8170SKalle Valo * end up releasing all the devices since there is no API to selectively 1256bdcd8170SKalle Valo * release a particular device. 1257bdcd8170SKalle Valo * 1258bdcd8170SKalle Valo * - Certain commands issued to the target can be skipped for surprise 1259bdcd8170SKalle Valo * removal since they will anyway not go through. 1260bdcd8170SKalle Valo */ 1261bdcd8170SKalle Valo void ath6kl_destroy(struct net_device *dev, unsigned int unregister) 1262bdcd8170SKalle Valo { 1263bdcd8170SKalle Valo struct ath6kl *ar; 1264bdcd8170SKalle Valo 1265bdcd8170SKalle Valo if (!dev || !ath6kl_priv(dev)) { 1266bdcd8170SKalle Valo ath6kl_err("failed to get device structure\n"); 1267bdcd8170SKalle Valo return; 1268bdcd8170SKalle Valo } 1269bdcd8170SKalle Valo 1270bdcd8170SKalle Valo ar = ath6kl_priv(dev); 1271bdcd8170SKalle Valo 1272bdcd8170SKalle Valo destroy_workqueue(ar->ath6kl_wq); 1273bdcd8170SKalle Valo 1274bdcd8170SKalle Valo if (ar->htc_target) 1275bdcd8170SKalle Valo htc_cleanup(ar->htc_target); 1276bdcd8170SKalle Valo 1277bdcd8170SKalle Valo aggr_module_destroy(ar->aggr_cntxt); 1278bdcd8170SKalle Valo 1279bdcd8170SKalle Valo ath6kl_cookie_cleanup(ar); 1280bdcd8170SKalle Valo 1281bdcd8170SKalle Valo ath6kl_cleanup_amsdu_rxbufs(ar); 1282bdcd8170SKalle Valo 1283bdcd8170SKalle Valo ath6kl_bmi_cleanup(ar); 1284bdcd8170SKalle Valo 1285bdcd8170SKalle Valo if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { 1286bdcd8170SKalle Valo unregister_netdev(dev); 1287bdcd8170SKalle Valo clear_bit(NETDEV_REGISTERED, &ar->flag); 1288bdcd8170SKalle Valo } 1289bdcd8170SKalle Valo 1290bdcd8170SKalle Valo free_netdev(dev); 1291bdcd8170SKalle Valo 1292bdcd8170SKalle Valo ath6kl_cfg80211_deinit(ar); 1293bdcd8170SKalle Valo } 1294