htc_drv_init.c revision 226afe68fdbd1aa3680158aca0a3631cbd019626
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 2fb9987d0f748c983bb795a86f47522313f701a08Sujith * Copyright (c) 2010 Atheros Communications Inc. 3fb9987d0f748c983bb795a86f47522313f701a08Sujith * 4fb9987d0f748c983bb795a86f47522313f701a08Sujith * Permission to use, copy, modify, and/or distribute this software for any 5fb9987d0f748c983bb795a86f47522313f701a08Sujith * purpose with or without fee is hereby granted, provided that the above 6fb9987d0f748c983bb795a86f47522313f701a08Sujith * copyright notice and this permission notice appear in all copies. 7fb9987d0f748c983bb795a86f47522313f701a08Sujith * 8fb9987d0f748c983bb795a86f47522313f701a08Sujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9fb9987d0f748c983bb795a86f47522313f701a08Sujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10fb9987d0f748c983bb795a86f47522313f701a08Sujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11fb9987d0f748c983bb795a86f47522313f701a08Sujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12fb9987d0f748c983bb795a86f47522313f701a08Sujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13fb9987d0f748c983bb795a86f47522313f701a08Sujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14fb9987d0f748c983bb795a86f47522313f701a08Sujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 16fb9987d0f748c983bb795a86f47522313f701a08Sujith 17fb9987d0f748c983bb795a86f47522313f701a08Sujith#include "htc.h" 18fb9987d0f748c983bb795a86f47522313f701a08Sujith 19fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_AUTHOR("Atheros Communications"); 20fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_LICENSE("Dual BSD/GPL"); 21fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices"); 22fb9987d0f748c983bb795a86f47522313f701a08Sujith 23fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic unsigned int ath9k_debug = ATH_DBG_DEFAULT; 24fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_param_named(debug, ath9k_debug, uint, 0); 25fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_PARM_DESC(debug, "Debugging mask"); 26fb9987d0f748c983bb795a86f47522313f701a08Sujith 27e1572c5eeca8ef87a250322364584458b2dadb35Sujithint htc_modparam_nohwcrypt; 28e1572c5eeca8ef87a250322364584458b2dadb35Sujithmodule_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444); 29fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); 30fb9987d0f748c983bb795a86f47522313f701a08Sujith 31fb9987d0f748c983bb795a86f47522313f701a08Sujith#define CHAN2G(_freq, _idx) { \ 32fb9987d0f748c983bb795a86f47522313f701a08Sujith .center_freq = (_freq), \ 33fb9987d0f748c983bb795a86f47522313f701a08Sujith .hw_value = (_idx), \ 34fb9987d0f748c983bb795a86f47522313f701a08Sujith .max_power = 20, \ 35fb9987d0f748c983bb795a86f47522313f701a08Sujith} 36fb9987d0f748c983bb795a86f47522313f701a08Sujith 37ea46e644e80bd4ac778964afd998df4f666486d4Sujith#define CHAN5G(_freq, _idx) { \ 38ea46e644e80bd4ac778964afd998df4f666486d4Sujith .band = IEEE80211_BAND_5GHZ, \ 39ea46e644e80bd4ac778964afd998df4f666486d4Sujith .center_freq = (_freq), \ 40ea46e644e80bd4ac778964afd998df4f666486d4Sujith .hw_value = (_idx), \ 41ea46e644e80bd4ac778964afd998df4f666486d4Sujith .max_power = 20, \ 42ea46e644e80bd4ac778964afd998df4f666486d4Sujith} 43ea46e644e80bd4ac778964afd998df4f666486d4Sujith 4421cb987914cb5334af78378141efed77505ea987Vivek Natarajan#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193" 4521cb987914cb5334af78378141efed77505ea987Vivek Natarajan 46fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_channel ath9k_2ghz_channels[] = { 47fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2412, 0), /* Channel 1 */ 48fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2417, 1), /* Channel 2 */ 49fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2422, 2), /* Channel 3 */ 50fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2427, 3), /* Channel 4 */ 51fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2432, 4), /* Channel 5 */ 52fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2437, 5), /* Channel 6 */ 53fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2442, 6), /* Channel 7 */ 54fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2447, 7), /* Channel 8 */ 55fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2452, 8), /* Channel 9 */ 56fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2457, 9), /* Channel 10 */ 57fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2462, 10), /* Channel 11 */ 58fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2467, 11), /* Channel 12 */ 59fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2472, 12), /* Channel 13 */ 60fb9987d0f748c983bb795a86f47522313f701a08Sujith CHAN2G(2484, 13), /* Channel 14 */ 61fb9987d0f748c983bb795a86f47522313f701a08Sujith}; 62fb9987d0f748c983bb795a86f47522313f701a08Sujith 63ea46e644e80bd4ac778964afd998df4f666486d4Sujithstatic struct ieee80211_channel ath9k_5ghz_channels[] = { 64ea46e644e80bd4ac778964afd998df4f666486d4Sujith /* _We_ call this UNII 1 */ 65ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5180, 14), /* Channel 36 */ 66ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5200, 15), /* Channel 40 */ 67ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5220, 16), /* Channel 44 */ 68ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5240, 17), /* Channel 48 */ 69ea46e644e80bd4ac778964afd998df4f666486d4Sujith /* _We_ call this UNII 2 */ 70ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5260, 18), /* Channel 52 */ 71ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5280, 19), /* Channel 56 */ 72ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5300, 20), /* Channel 60 */ 73ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5320, 21), /* Channel 64 */ 74ea46e644e80bd4ac778964afd998df4f666486d4Sujith /* _We_ call this "Middle band" */ 75ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5500, 22), /* Channel 100 */ 76ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5520, 23), /* Channel 104 */ 77ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5540, 24), /* Channel 108 */ 78ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5560, 25), /* Channel 112 */ 79ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5580, 26), /* Channel 116 */ 80ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5600, 27), /* Channel 120 */ 81ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5620, 28), /* Channel 124 */ 82ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5640, 29), /* Channel 128 */ 83ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5660, 30), /* Channel 132 */ 84ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5680, 31), /* Channel 136 */ 85ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5700, 32), /* Channel 140 */ 86ea46e644e80bd4ac778964afd998df4f666486d4Sujith /* _We_ call this UNII 3 */ 87ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5745, 33), /* Channel 149 */ 88ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5765, 34), /* Channel 153 */ 89ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5785, 35), /* Channel 157 */ 90ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5805, 36), /* Channel 161 */ 91ea46e644e80bd4ac778964afd998df4f666486d4Sujith CHAN5G(5825, 37), /* Channel 165 */ 92ea46e644e80bd4ac778964afd998df4f666486d4Sujith}; 93ea46e644e80bd4ac778964afd998df4f666486d4Sujith 94fb9987d0f748c983bb795a86f47522313f701a08Sujith/* Atheros hardware rate code addition for short premble */ 95fb9987d0f748c983bb795a86f47522313f701a08Sujith#define SHPCHECK(__hw_rate, __flags) \ 96fb9987d0f748c983bb795a86f47522313f701a08Sujith ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) 97fb9987d0f748c983bb795a86f47522313f701a08Sujith 98fb9987d0f748c983bb795a86f47522313f701a08Sujith#define RATE(_bitrate, _hw_rate, _flags) { \ 99fb9987d0f748c983bb795a86f47522313f701a08Sujith .bitrate = (_bitrate), \ 100fb9987d0f748c983bb795a86f47522313f701a08Sujith .flags = (_flags), \ 101fb9987d0f748c983bb795a86f47522313f701a08Sujith .hw_value = (_hw_rate), \ 102fb9987d0f748c983bb795a86f47522313f701a08Sujith .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ 103fb9987d0f748c983bb795a86f47522313f701a08Sujith} 104fb9987d0f748c983bb795a86f47522313f701a08Sujith 105fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_rate ath9k_legacy_rates[] = { 106fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(10, 0x1b, 0), 107fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ 108fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ 109fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ 110fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(60, 0x0b, 0), 111fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(90, 0x0f, 0), 112fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(120, 0x0a, 0), 113fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(180, 0x0e, 0), 114fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(240, 0x09, 0), 115fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(360, 0x0d, 0), 116fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(480, 0x08, 0), 117fb9987d0f748c983bb795a86f47522313f701a08Sujith RATE(540, 0x0c, 0), 118fb9987d0f748c983bb795a86f47522313f701a08Sujith}; 119fb9987d0f748c983bb795a86f47522313f701a08Sujith 120fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) 121fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 122fb9987d0f748c983bb795a86f47522313f701a08Sujith int time_left; 123fb9987d0f748c983bb795a86f47522313f701a08Sujith 124d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com if (atomic_read(&priv->htc->tgt_ready) > 0) { 125d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com atomic_dec(&priv->htc->tgt_ready); 126d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com return 0; 127d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com } 128d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com 129fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Firmware can take up to 50ms to get ready, to be safe use 1 second */ 130fb9987d0f748c983bb795a86f47522313f701a08Sujith time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ); 131fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!time_left) { 132fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n"); 133fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ETIMEDOUT; 134fb9987d0f748c983bb795a86f47522313f701a08Sujith } 135fb9987d0f748c983bb795a86f47522313f701a08Sujith 136d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com atomic_dec(&priv->htc->tgt_ready); 137d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com 138fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 139fb9987d0f748c983bb795a86f47522313f701a08Sujith} 140fb9987d0f748c983bb795a86f47522313f701a08Sujith 141fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_priv(struct ath9k_htc_priv *priv) 142fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 143e1572c5eeca8ef87a250322364584458b2dadb35Sujith ath9k_htc_exit_debug(priv->ah); 144fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_deinit(priv->ah); 145fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_kill(&priv->wmi_tasklet); 146fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_kill(&priv->rx_tasklet); 147fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_kill(&priv->tx_tasklet); 148fb9987d0f748c983bb795a86f47522313f701a08Sujith kfree(priv->ah); 149fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->ah = NULL; 150fb9987d0f748c983bb795a86f47522313f701a08Sujith} 151fb9987d0f748c983bb795a86f47522313f701a08Sujith 152fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_device(struct ath9k_htc_priv *priv) 153fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 154fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = priv->hw; 155fb9987d0f748c983bb795a86f47522313f701a08Sujith 156fb9987d0f748c983bb795a86f47522313f701a08Sujith wiphy_rfkill_stop_polling(hw->wiphy); 157fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_deinit_leds(priv); 158fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_unregister_hw(hw); 159fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_rx_cleanup(priv); 160fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_tx_cleanup(priv); 161fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_deinit_priv(priv); 162fb9987d0f748c983bb795a86f47522313f701a08Sujith} 163fb9987d0f748c983bb795a86f47522313f701a08Sujith 164fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv, 165fb9987d0f748c983bb795a86f47522313f701a08Sujith u16 service_id, 166fb9987d0f748c983bb795a86f47522313f701a08Sujith void (*tx) (void *, 167fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *, 168fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id, 169fb9987d0f748c983bb795a86f47522313f701a08Sujith bool txok), 170fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id *ep_id) 171fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 172fb9987d0f748c983bb795a86f47522313f701a08Sujith struct htc_service_connreq req; 173fb9987d0f748c983bb795a86f47522313f701a08Sujith 174fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&req, 0, sizeof(struct htc_service_connreq)); 175fb9987d0f748c983bb795a86f47522313f701a08Sujith 176fb9987d0f748c983bb795a86f47522313f701a08Sujith req.service_id = service_id; 177fb9987d0f748c983bb795a86f47522313f701a08Sujith req.ep_callbacks.priv = priv; 178fb9987d0f748c983bb795a86f47522313f701a08Sujith req.ep_callbacks.rx = ath9k_htc_rxep; 179fb9987d0f748c983bb795a86f47522313f701a08Sujith req.ep_callbacks.tx = tx; 180fb9987d0f748c983bb795a86f47522313f701a08Sujith 181fb9987d0f748c983bb795a86f47522313f701a08Sujith return htc_connect_service(priv->htc, &req, ep_id); 182fb9987d0f748c983bb795a86f47522313f701a08Sujith} 183fb9987d0f748c983bb795a86f47522313f701a08Sujith 184fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharanstatic int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid, 185fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan u32 drv_info) 186fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 187fb9987d0f748c983bb795a86f47522313f701a08Sujith int ret; 188fb9987d0f748c983bb795a86f47522313f701a08Sujith 189fb9987d0f748c983bb795a86f47522313f701a08Sujith /* WMI CMD*/ 190fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep); 191fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 192fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 193fb9987d0f748c983bb795a86f47522313f701a08Sujith 194fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Beacon */ 1959c6dda4e2dfea970a7105e3805f0195bc3079f2fSujith ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep, 196fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->beacon_ep); 197fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 198fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 199fb9987d0f748c983bb795a86f47522313f701a08Sujith 200fb9987d0f748c983bb795a86f47522313f701a08Sujith /* CAB */ 201fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep, 202fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->cab_ep); 203fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 204fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 205fb9987d0f748c983bb795a86f47522313f701a08Sujith 206fb9987d0f748c983bb795a86f47522313f701a08Sujith 207fb9987d0f748c983bb795a86f47522313f701a08Sujith /* UAPSD */ 208fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep, 209fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->uapsd_ep); 210fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 211fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 212fb9987d0f748c983bb795a86f47522313f701a08Sujith 213fb9987d0f748c983bb795a86f47522313f701a08Sujith /* MGMT */ 214fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep, 215fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->mgmt_ep); 216fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 217fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 218fb9987d0f748c983bb795a86f47522313f701a08Sujith 219fb9987d0f748c983bb795a86f47522313f701a08Sujith /* DATA BE */ 220fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep, 221fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->data_be_ep); 222fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 223fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 224fb9987d0f748c983bb795a86f47522313f701a08Sujith 225fb9987d0f748c983bb795a86f47522313f701a08Sujith /* DATA BK */ 226fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep, 227fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->data_bk_ep); 228fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 229fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 230fb9987d0f748c983bb795a86f47522313f701a08Sujith 231fb9987d0f748c983bb795a86f47522313f701a08Sujith /* DATA VI */ 232fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep, 233fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->data_vi_ep); 234fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 235fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 236fb9987d0f748c983bb795a86f47522313f701a08Sujith 237fb9987d0f748c983bb795a86f47522313f701a08Sujith /* DATA VO */ 238fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep, 239fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->data_vo_ep); 240fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 241fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 242fb9987d0f748c983bb795a86f47522313f701a08Sujith 2436267dc709c6ef1c0926e18ff2859238992dea658Sujith /* 2446267dc709c6ef1c0926e18ff2859238992dea658Sujith * Setup required credits before initializing HTC. 2456267dc709c6ef1c0926e18ff2859238992dea658Sujith * This is a bit hacky, but, since queuing is done in 2466267dc709c6ef1c0926e18ff2859238992dea658Sujith * the HIF layer, shouldn't matter much. 2476267dc709c6ef1c0926e18ff2859238992dea658Sujith */ 2486267dc709c6ef1c0926e18ff2859238992dea658Sujith 249fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan if (drv_info & AR7010_DEVICE) 2506267dc709c6ef1c0926e18ff2859238992dea658Sujith priv->htc->credits = 45; 251fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan else 2524e63f768c3b85ae2b3ea6251231fd5cc46ec598dSujith priv->htc->credits = 33; 2536267dc709c6ef1c0926e18ff2859238992dea658Sujith 254fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = htc_init(priv->htc); 255fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 256fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 257fb9987d0f748c983bb795a86f47522313f701a08Sujith 2586267dc709c6ef1c0926e18ff2859238992dea658Sujith dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n", 2596267dc709c6ef1c0926e18ff2859238992dea658Sujith priv->htc->credits); 2606267dc709c6ef1c0926e18ff2859238992dea658Sujith 261fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 262fb9987d0f748c983bb795a86f47522313f701a08Sujith 263fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 264fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n"); 265fb9987d0f748c983bb795a86f47522313f701a08Sujith return ret; 266fb9987d0f748c983bb795a86f47522313f701a08Sujith} 267fb9987d0f748c983bb795a86f47522313f701a08Sujith 268fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_reg_notifier(struct wiphy *wiphy, 269fb9987d0f748c983bb795a86f47522313f701a08Sujith struct regulatory_request *request) 270fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 271fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 272fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = hw->priv; 273fb9987d0f748c983bb795a86f47522313f701a08Sujith 274fb9987d0f748c983bb795a86f47522313f701a08Sujith return ath_reg_notifier_apply(wiphy, request, 275fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_regulatory(priv->ah)); 276fb9987d0f748c983bb795a86f47522313f701a08Sujith} 277fb9987d0f748c983bb795a86f47522313f701a08Sujith 2784a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) 279fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 280fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 281fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 282fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 283fb9987d0f748c983bb795a86f47522313f701a08Sujith __be32 val, reg = cpu_to_be32(reg_offset); 284fb9987d0f748c983bb795a86f47522313f701a08Sujith int r; 285fb9987d0f748c983bb795a86f47522313f701a08Sujith 286fb9987d0f748c983bb795a86f47522313f701a08Sujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, 287fb9987d0f748c983bb795a86f47522313f701a08Sujith (u8 *) ®, sizeof(reg), 288fb9987d0f748c983bb795a86f47522313f701a08Sujith (u8 *) &val, sizeof(val), 289fb9987d0f748c983bb795a86f47522313f701a08Sujith 100); 290fb9987d0f748c983bb795a86f47522313f701a08Sujith if (unlikely(r)) { 291226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_WMI, 292226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "REGISTER READ FAILED: (0x%04x, %d)\n", 293226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches reg_offset, r); 294fb9987d0f748c983bb795a86f47522313f701a08Sujith return -EIO; 295fb9987d0f748c983bb795a86f47522313f701a08Sujith } 296fb9987d0f748c983bb795a86f47522313f701a08Sujith 297fb9987d0f748c983bb795a86f47522313f701a08Sujith return be32_to_cpu(val); 298fb9987d0f748c983bb795a86f47522313f701a08Sujith} 299fb9987d0f748c983bb795a86f47522313f701a08Sujith 3004a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) 301fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 302fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 303fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 304fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 30507b2fa5a2368accf0fe6cb16e7eca6d1150554edJoe Perches const __be32 buf[2] = { 306fb9987d0f748c983bb795a86f47522313f701a08Sujith cpu_to_be32(reg_offset), 307fb9987d0f748c983bb795a86f47522313f701a08Sujith cpu_to_be32(val), 308fb9987d0f748c983bb795a86f47522313f701a08Sujith }; 309fb9987d0f748c983bb795a86f47522313f701a08Sujith int r; 310fb9987d0f748c983bb795a86f47522313f701a08Sujith 311fb9987d0f748c983bb795a86f47522313f701a08Sujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, 312fb9987d0f748c983bb795a86f47522313f701a08Sujith (u8 *) &buf, sizeof(buf), 313fb9987d0f748c983bb795a86f47522313f701a08Sujith (u8 *) &val, sizeof(val), 314fb9987d0f748c983bb795a86f47522313f701a08Sujith 100); 315fb9987d0f748c983bb795a86f47522313f701a08Sujith if (unlikely(r)) { 316226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_WMI, 317226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "REGISTER WRITE FAILED:(0x%04x, %d)\n", 318226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches reg_offset, r); 319fb9987d0f748c983bb795a86f47522313f701a08Sujith } 320fb9987d0f748c983bb795a86f47522313f701a08Sujith} 321fb9987d0f748c983bb795a86f47522313f701a08Sujith 3224a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) 3234a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{ 3244a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 3254a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_common *common = ath9k_hw_common(ah); 3264a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 3274a22fe108e62367c10c3abeb469d6972ba3299f5Sujith u32 rsp_status; 3284a22fe108e62367c10c3abeb469d6972ba3299f5Sujith int r; 3294a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3304a22fe108e62367c10c3abeb469d6972ba3299f5Sujith mutex_lock(&priv->wmi->multi_write_mutex); 3314a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3324a22fe108e62367c10c3abeb469d6972ba3299f5Sujith /* Store the register/value */ 3334a22fe108e62367c10c3abeb469d6972ba3299f5Sujith priv->wmi->multi_write[priv->wmi->multi_write_idx].reg = 3344a22fe108e62367c10c3abeb469d6972ba3299f5Sujith cpu_to_be32(reg_offset); 3354a22fe108e62367c10c3abeb469d6972ba3299f5Sujith priv->wmi->multi_write[priv->wmi->multi_write_idx].val = 3364a22fe108e62367c10c3abeb469d6972ba3299f5Sujith cpu_to_be32(val); 3374a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3384a22fe108e62367c10c3abeb469d6972ba3299f5Sujith priv->wmi->multi_write_idx++; 3394a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3404a22fe108e62367c10c3abeb469d6972ba3299f5Sujith /* If the buffer is full, send it out. */ 3414a22fe108e62367c10c3abeb469d6972ba3299f5Sujith if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { 3424a22fe108e62367c10c3abeb469d6972ba3299f5Sujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, 3434a22fe108e62367c10c3abeb469d6972ba3299f5Sujith (u8 *) &priv->wmi->multi_write, 3444a22fe108e62367c10c3abeb469d6972ba3299f5Sujith sizeof(struct register_write) * priv->wmi->multi_write_idx, 3454a22fe108e62367c10c3abeb469d6972ba3299f5Sujith (u8 *) &rsp_status, sizeof(rsp_status), 3464a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 100); 3474a22fe108e62367c10c3abeb469d6972ba3299f5Sujith if (unlikely(r)) { 348226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_WMI, 349226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "REGISTER WRITE FAILED, multi len: %d\n", 350226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches priv->wmi->multi_write_idx); 3514a22fe108e62367c10c3abeb469d6972ba3299f5Sujith } 3524a22fe108e62367c10c3abeb469d6972ba3299f5Sujith priv->wmi->multi_write_idx = 0; 3534a22fe108e62367c10c3abeb469d6972ba3299f5Sujith } 3544a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3554a22fe108e62367c10c3abeb469d6972ba3299f5Sujith mutex_unlock(&priv->wmi->multi_write_mutex); 3564a22fe108e62367c10c3abeb469d6972ba3299f5Sujith} 3574a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3584a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset) 3594a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{ 3604a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 3614a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_common *common = ath9k_hw_common(ah); 3624a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 3634a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3644a22fe108e62367c10c3abeb469d6972ba3299f5Sujith if (atomic_read(&priv->wmi->mwrite_cnt)) 3654a22fe108e62367c10c3abeb469d6972ba3299f5Sujith ath9k_regwrite_buffer(hw_priv, val, reg_offset); 3664a22fe108e62367c10c3abeb469d6972ba3299f5Sujith else 3674a22fe108e62367c10c3abeb469d6972ba3299f5Sujith ath9k_regwrite_single(hw_priv, val, reg_offset); 3684a22fe108e62367c10c3abeb469d6972ba3299f5Sujith} 3694a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3704a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_enable_regwrite_buffer(void *hw_priv) 3714a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{ 3724a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 3734a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_common *common = ath9k_hw_common(ah); 3744a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 3754a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3764a22fe108e62367c10c3abeb469d6972ba3299f5Sujith atomic_inc(&priv->wmi->mwrite_cnt); 3774a22fe108e62367c10c3abeb469d6972ba3299f5Sujith} 3784a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3794a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_flush(void *hw_priv) 3804a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{ 3814a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 3824a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath_common *common = ath9k_hw_common(ah); 3834a22fe108e62367c10c3abeb469d6972ba3299f5Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 3844a22fe108e62367c10c3abeb469d6972ba3299f5Sujith u32 rsp_status; 3854a22fe108e62367c10c3abeb469d6972ba3299f5Sujith int r; 3864a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 387435c1610f46dc4d86a6633adb037b18109e6ffdcFelix Fietkau atomic_dec(&priv->wmi->mwrite_cnt); 388435c1610f46dc4d86a6633adb037b18109e6ffdcFelix Fietkau 3894a22fe108e62367c10c3abeb469d6972ba3299f5Sujith mutex_lock(&priv->wmi->multi_write_mutex); 3904a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 3914a22fe108e62367c10c3abeb469d6972ba3299f5Sujith if (priv->wmi->multi_write_idx) { 3924a22fe108e62367c10c3abeb469d6972ba3299f5Sujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, 3934a22fe108e62367c10c3abeb469d6972ba3299f5Sujith (u8 *) &priv->wmi->multi_write, 3944a22fe108e62367c10c3abeb469d6972ba3299f5Sujith sizeof(struct register_write) * priv->wmi->multi_write_idx, 3954a22fe108e62367c10c3abeb469d6972ba3299f5Sujith (u8 *) &rsp_status, sizeof(rsp_status), 3964a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 100); 3974a22fe108e62367c10c3abeb469d6972ba3299f5Sujith if (unlikely(r)) { 398226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_WMI, 399226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "REGISTER WRITE FAILED, multi len: %d\n", 400226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches priv->wmi->multi_write_idx); 4014a22fe108e62367c10c3abeb469d6972ba3299f5Sujith } 4024a22fe108e62367c10c3abeb469d6972ba3299f5Sujith priv->wmi->multi_write_idx = 0; 4034a22fe108e62367c10c3abeb469d6972ba3299f5Sujith } 4044a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 4054a22fe108e62367c10c3abeb469d6972ba3299f5Sujith mutex_unlock(&priv->wmi->multi_write_mutex); 4064a22fe108e62367c10c3abeb469d6972ba3299f5Sujith} 4074a22fe108e62367c10c3abeb469d6972ba3299f5Sujith 408fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic const struct ath_ops ath9k_common_ops = { 4094a22fe108e62367c10c3abeb469d6972ba3299f5Sujith .read = ath9k_regread, 4104a22fe108e62367c10c3abeb469d6972ba3299f5Sujith .write = ath9k_regwrite, 4114a22fe108e62367c10c3abeb469d6972ba3299f5Sujith .enable_write_buffer = ath9k_enable_regwrite_buffer, 4124a22fe108e62367c10c3abeb469d6972ba3299f5Sujith .write_flush = ath9k_regwrite_flush, 413fb9987d0f748c983bb795a86f47522313f701a08Sujith}; 414fb9987d0f748c983bb795a86f47522313f701a08Sujith 415fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath_usb_read_cachesize(struct ath_common *common, int *csz) 416fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 417fb9987d0f748c983bb795a86f47522313f701a08Sujith *csz = L1_CACHE_BYTES >> 2; 418fb9987d0f748c983bb795a86f47522313f701a08Sujith} 419fb9987d0f748c983bb795a86f47522313f701a08Sujith 420fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) 421fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 422fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = (struct ath_hw *) common->ah; 423fb9987d0f748c983bb795a86f47522313f701a08Sujith 424fb9987d0f748c983bb795a86f47522313f701a08Sujith (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); 425fb9987d0f748c983bb795a86f47522313f701a08Sujith 426fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_hw_wait(ah, 427fb9987d0f748c983bb795a86f47522313f701a08Sujith AR_EEPROM_STATUS_DATA, 428fb9987d0f748c983bb795a86f47522313f701a08Sujith AR_EEPROM_STATUS_DATA_BUSY | 429fb9987d0f748c983bb795a86f47522313f701a08Sujith AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, 430fb9987d0f748c983bb795a86f47522313f701a08Sujith AH_WAIT_TIMEOUT)) 431fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 432fb9987d0f748c983bb795a86f47522313f701a08Sujith 433fb9987d0f748c983bb795a86f47522313f701a08Sujith *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), 434fb9987d0f748c983bb795a86f47522313f701a08Sujith AR_EEPROM_STATUS_DATA_VAL); 435fb9987d0f748c983bb795a86f47522313f701a08Sujith 436fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 437fb9987d0f748c983bb795a86f47522313f701a08Sujith} 438fb9987d0f748c983bb795a86f47522313f701a08Sujith 439fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic const struct ath_bus_ops ath9k_usb_bus_ops = { 440497ad9adf44013dc9054f80c627acc44d4c90d37Sujith .ath_bus_type = ATH_USB, 441fb9987d0f748c983bb795a86f47522313f701a08Sujith .read_cachesize = ath_usb_read_cachesize, 442fb9987d0f748c983bb795a86f47522313f701a08Sujith .eeprom_read = ath_usb_eeprom_read, 443fb9987d0f748c983bb795a86f47522313f701a08Sujith}; 444fb9987d0f748c983bb795a86f47522313f701a08Sujith 445fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void setup_ht_cap(struct ath9k_htc_priv *priv, 446fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta_ht_cap *ht_info) 447fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 4486debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 4496debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith u8 tx_streams, rx_streams; 4506debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith int i; 4516debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith 452fb9987d0f748c983bb795a86f47522313f701a08Sujith ht_info->ht_supported = true; 453fb9987d0f748c983bb795a86f47522313f701a08Sujith ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 454fb9987d0f748c983bb795a86f47522313f701a08Sujith IEEE80211_HT_CAP_SM_PS | 455fb9987d0f748c983bb795a86f47522313f701a08Sujith IEEE80211_HT_CAP_SGI_40 | 456fb9987d0f748c983bb795a86f47522313f701a08Sujith IEEE80211_HT_CAP_DSSSCCK40; 457fb9987d0f748c983bb795a86f47522313f701a08Sujith 458b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) 459b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith ht_info->cap |= IEEE80211_HT_CAP_SGI_20; 460b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith 46117525f96aeeed156bd4a6dee21816100f77b0c71Sujith ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 46217525f96aeeed156bd4a6dee21816100f77b0c71Sujith 463fb9987d0f748c983bb795a86f47522313f701a08Sujith ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 464fb9987d0f748c983bb795a86f47522313f701a08Sujith ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; 465fb9987d0f748c983bb795a86f47522313f701a08Sujith 466fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); 4676debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith 4686debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith /* ath9k_htc supports only 1 or 2 stream devices */ 4696debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2); 4706debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2); 4716debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith 472226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_CONFIG, 473226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "TX streams %d, RX streams: %d\n", 474226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches tx_streams, rx_streams); 4756debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith 4766debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith if (tx_streams != rx_streams) { 4776debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; 4786debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith ht_info->mcs.tx_params |= ((tx_streams - 1) << 4796debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); 4806debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith } 4816debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith 4826debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith for (i = 0; i < rx_streams; i++) 4836debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith ht_info->mcs.rx_mask[i] = 0xff; 4846debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith 485fb9987d0f748c983bb795a86f47522313f701a08Sujith ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; 486fb9987d0f748c983bb795a86f47522313f701a08Sujith} 487fb9987d0f748c983bb795a86f47522313f701a08Sujith 488fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_init_queues(struct ath9k_htc_priv *priv) 489fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 490fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 491fb9987d0f748c983bb795a86f47522313f701a08Sujith int i; 492fb9987d0f748c983bb795a86f47522313f701a08Sujith 493fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) 494fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->hwq_map[i] = -1; 495fb9987d0f748c983bb795a86f47522313f701a08Sujith 496ca74b83b66dbd289a395c6243695d746c76676ccSujith priv->beaconq = ath9k_hw_beaconq_setup(priv->ah); 497ca74b83b66dbd289a395c6243695d746c76676ccSujith if (priv->beaconq == -1) { 4983800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to setup BEACON xmit queue\n"); 499ca74b83b66dbd289a395c6243695d746c76676ccSujith goto err; 500ca74b83b66dbd289a395c6243695d746c76676ccSujith } 501ca74b83b66dbd289a395c6243695d746c76676ccSujith 502ca74b83b66dbd289a395c6243695d746c76676ccSujith priv->cabq = ath9k_htc_cabq_setup(priv); 503ca74b83b66dbd289a395c6243695d746c76676ccSujith if (priv->cabq == -1) { 5043800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to setup CAB xmit queue\n"); 505ca74b83b66dbd289a395c6243695d746c76676ccSujith goto err; 506ca74b83b66dbd289a395c6243695d746c76676ccSujith } 507ca74b83b66dbd289a395c6243695d746c76676ccSujith 508e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) { 5093800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to setup xmit queue for BE traffic\n"); 510fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 511fb9987d0f748c983bb795a86f47522313f701a08Sujith } 512fb9987d0f748c983bb795a86f47522313f701a08Sujith 513e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) { 5143800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to setup xmit queue for BK traffic\n"); 515fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 516fb9987d0f748c983bb795a86f47522313f701a08Sujith } 517e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) { 5183800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to setup xmit queue for VI traffic\n"); 519fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 520fb9987d0f748c983bb795a86f47522313f701a08Sujith } 521e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) { 5223800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to setup xmit queue for VO traffic\n"); 523fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 524fb9987d0f748c983bb795a86f47522313f701a08Sujith } 525fb9987d0f748c983bb795a86f47522313f701a08Sujith 526fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 527fb9987d0f748c983bb795a86f47522313f701a08Sujith 528fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 529fb9987d0f748c983bb795a86f47522313f701a08Sujith return -EINVAL; 530fb9987d0f748c983bb795a86f47522313f701a08Sujith} 531fb9987d0f748c983bb795a86f47522313f701a08Sujith 532fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_crypto(struct ath9k_htc_priv *priv) 533fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 534fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 535fb9987d0f748c983bb795a86f47522313f701a08Sujith int i = 0; 536fb9987d0f748c983bb795a86f47522313f701a08Sujith 537fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Get the hardware key cache size. */ 538fb9987d0f748c983bb795a86f47522313f701a08Sujith common->keymax = priv->ah->caps.keycache_size; 539fb9987d0f748c983bb795a86f47522313f701a08Sujith if (common->keymax > ATH_KEYMAX) { 540226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_ANY, 541226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "Warning, using only %u entries in %u key cache\n", 542226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ATH_KEYMAX, common->keymax); 543fb9987d0f748c983bb795a86f47522313f701a08Sujith common->keymax = ATH_KEYMAX; 544fb9987d0f748c983bb795a86f47522313f701a08Sujith } 545fb9987d0f748c983bb795a86f47522313f701a08Sujith 546e2b626248b0799bd14be40ce290c6681a8419512Rajkumar Manoharan if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) 547e2b626248b0799bd14be40ce290c6681a8419512Rajkumar Manoharan common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; 548e2b626248b0799bd14be40ce290c6681a8419512Rajkumar Manoharan 549fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 550fb9987d0f748c983bb795a86f47522313f701a08Sujith * Reset the key cache since some parts do not 551fb9987d0f748c983bb795a86f47522313f701a08Sujith * reset the contents on initial power up. 552fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 553fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < common->keymax; i++) 554040e539e8e8d5585e1c3d7d15fa7215d3a691258Bruno Randolf ath_hw_keyreset(common, (u16) i); 555fb9987d0f748c983bb795a86f47522313f701a08Sujith} 556fb9987d0f748c983bb795a86f47522313f701a08Sujith 557fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) 558fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 559d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { 560fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->sbands[IEEE80211_BAND_2GHZ].channels = 561fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_2ghz_channels; 562fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; 563fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->sbands[IEEE80211_BAND_2GHZ].n_channels = 564fb9987d0f748c983bb795a86f47522313f701a08Sujith ARRAY_SIZE(ath9k_2ghz_channels); 565fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; 566fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = 567fb9987d0f748c983bb795a86f47522313f701a08Sujith ARRAY_SIZE(ath9k_legacy_rates); 568fb9987d0f748c983bb795a86f47522313f701a08Sujith } 569ea46e644e80bd4ac778964afd998df4f666486d4Sujith 570d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { 571ea46e644e80bd4ac778964afd998df4f666486d4Sujith priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; 572ea46e644e80bd4ac778964afd998df4f666486d4Sujith priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; 573ea46e644e80bd4ac778964afd998df4f666486d4Sujith priv->sbands[IEEE80211_BAND_5GHZ].n_channels = 574ea46e644e80bd4ac778964afd998df4f666486d4Sujith ARRAY_SIZE(ath9k_5ghz_channels); 575ea46e644e80bd4ac778964afd998df4f666486d4Sujith priv->sbands[IEEE80211_BAND_5GHZ].bitrates = 576ea46e644e80bd4ac778964afd998df4f666486d4Sujith ath9k_legacy_rates + 4; 577ea46e644e80bd4ac778964afd998df4f666486d4Sujith priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates = 578ea46e644e80bd4ac778964afd998df4f666486d4Sujith ARRAY_SIZE(ath9k_legacy_rates) - 4; 579ea46e644e80bd4ac778964afd998df4f666486d4Sujith } 580fb9987d0f748c983bb795a86f47522313f701a08Sujith} 581fb9987d0f748c983bb795a86f47522313f701a08Sujith 582fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_misc(struct ath9k_htc_priv *priv) 583fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 584fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 585fb9987d0f748c983bb795a86f47522313f701a08Sujith 586fb9987d0f748c983bb795a86f47522313f701a08Sujith common->tx_chainmask = priv->ah->caps.tx_chainmask; 587fb9987d0f748c983bb795a86f47522313f701a08Sujith common->rx_chainmask = priv->ah->caps.rx_chainmask; 588fb9987d0f748c983bb795a86f47522313f701a08Sujith 589364734fafbba0c3133e482db78149b9a823ae7a5Felix Fietkau memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); 590fb9987d0f748c983bb795a86f47522313f701a08Sujith 5919f01a84e81d10e38daa504348217895fe414a24bSujith priv->ah->opmode = NL80211_IFTYPE_STATION; 592fb9987d0f748c983bb795a86f47522313f701a08Sujith} 593fb9987d0f748c983bb795a86f47522313f701a08Sujith 59421cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic void ath9k_init_btcoex(struct ath9k_htc_priv *priv) 59521cb987914cb5334af78378141efed77505ea987Vivek Natarajan{ 59621cb987914cb5334af78378141efed77505ea987Vivek Natarajan int qnum; 59721cb987914cb5334af78378141efed77505ea987Vivek Natarajan 59821cb987914cb5334af78378141efed77505ea987Vivek Natarajan switch (priv->ah->btcoex_hw.scheme) { 59921cb987914cb5334af78378141efed77505ea987Vivek Natarajan case ATH_BTCOEX_CFG_NONE: 60021cb987914cb5334af78378141efed77505ea987Vivek Natarajan break; 60121cb987914cb5334af78378141efed77505ea987Vivek Natarajan case ATH_BTCOEX_CFG_3WIRE: 60221cb987914cb5334af78378141efed77505ea987Vivek Natarajan priv->ah->btcoex_hw.btactive_gpio = 7; 60321cb987914cb5334af78378141efed77505ea987Vivek Natarajan priv->ah->btcoex_hw.btpriority_gpio = 6; 60421cb987914cb5334af78378141efed77505ea987Vivek Natarajan priv->ah->btcoex_hw.wlanactive_gpio = 8; 60521cb987914cb5334af78378141efed77505ea987Vivek Natarajan priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; 60621cb987914cb5334af78378141efed77505ea987Vivek Natarajan ath9k_hw_btcoex_init_3wire(priv->ah); 60721cb987914cb5334af78378141efed77505ea987Vivek Natarajan ath_htc_init_btcoex_work(priv); 60821cb987914cb5334af78378141efed77505ea987Vivek Natarajan qnum = priv->hwq_map[WME_AC_BE]; 60921cb987914cb5334af78378141efed77505ea987Vivek Natarajan ath9k_hw_init_btcoex_hw(priv->ah, qnum); 61021cb987914cb5334af78378141efed77505ea987Vivek Natarajan break; 61121cb987914cb5334af78378141efed77505ea987Vivek Natarajan default: 61221cb987914cb5334af78378141efed77505ea987Vivek Natarajan WARN_ON(1); 61321cb987914cb5334af78378141efed77505ea987Vivek Natarajan break; 61421cb987914cb5334af78378141efed77505ea987Vivek Natarajan } 61521cb987914cb5334af78378141efed77505ea987Vivek Natarajan} 61621cb987914cb5334af78378141efed77505ea987Vivek Natarajan 61721cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic int ath9k_init_priv(struct ath9k_htc_priv *priv, 618fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan u16 devid, char *product, 619fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan u32 drv_info) 620fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 621fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = NULL; 622fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common; 623fb9987d0f748c983bb795a86f47522313f701a08Sujith int ret = 0, csz = 0; 624fb9987d0f748c983bb795a86f47522313f701a08Sujith 625fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->op_flags |= OP_INVALID; 626fb9987d0f748c983bb795a86f47522313f701a08Sujith 627fb9987d0f748c983bb795a86f47522313f701a08Sujith ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); 628fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ah) 629fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ENOMEM; 630fb9987d0f748c983bb795a86f47522313f701a08Sujith 631fb9987d0f748c983bb795a86f47522313f701a08Sujith ah->hw_version.devid = devid; 632fb9987d0f748c983bb795a86f47522313f701a08Sujith ah->hw_version.subsysid = 0; /* FIXME */ 633f8afa42b01c7a9f45b7cbaadb0481a0eeb96f18dFelix Fietkau ah->ah_flags |= AH_USE_EEPROM; 634fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->ah = ah; 635fb9987d0f748c983bb795a86f47522313f701a08Sujith 636fb9987d0f748c983bb795a86f47522313f701a08Sujith common = ath9k_hw_common(ah); 637fb9987d0f748c983bb795a86f47522313f701a08Sujith common->ops = &ath9k_common_ops; 638fb9987d0f748c983bb795a86f47522313f701a08Sujith common->bus_ops = &ath9k_usb_bus_ops; 639fb9987d0f748c983bb795a86f47522313f701a08Sujith common->ah = ah; 640fb9987d0f748c983bb795a86f47522313f701a08Sujith common->hw = priv->hw; 641fb9987d0f748c983bb795a86f47522313f701a08Sujith common->priv = priv; 642fb9987d0f748c983bb795a86f47522313f701a08Sujith common->debug_mask = ath9k_debug; 643fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan common->driver_info = drv_info; 644fb9987d0f748c983bb795a86f47522313f701a08Sujith 645fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_init(&priv->wmi->wmi_lock); 646fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_init(&priv->beacon_lock); 6477757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith spin_lock_init(&priv->tx_lock); 648fb9987d0f748c983bb795a86f47522313f701a08Sujith mutex_init(&priv->mutex); 649bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan mutex_init(&priv->htc_pm_lock); 650fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet, 651fb9987d0f748c983bb795a86f47522313f701a08Sujith (unsigned long)priv); 652fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, 653fb9987d0f748c983bb795a86f47522313f701a08Sujith (unsigned long)priv); 654fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv); 655fb9987d0f748c983bb795a86f47522313f701a08Sujith INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); 656bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan INIT_WORK(&priv->ps_work, ath9k_ps_work); 657fb9987d0f748c983bb795a86f47522313f701a08Sujith 658fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 659fb9987d0f748c983bb795a86f47522313f701a08Sujith * Cache line size is used to size and align various 660fb9987d0f748c983bb795a86f47522313f701a08Sujith * structures used to communicate with the hardware. 661fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 662fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_read_cachesize(common, &csz); 663fb9987d0f748c983bb795a86f47522313f701a08Sujith common->cachelsz = csz << 2; /* convert to bytes */ 664fb9987d0f748c983bb795a86f47522313f701a08Sujith 665fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_hw_init(ah); 666fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) { 6673800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, 6683800276a40751539a920ef8e0537ef2e19126799Joe Perches "Unable to initialize hardware; initialization status: %d\n", 6693800276a40751539a920ef8e0537ef2e19126799Joe Perches ret); 670fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_hw; 671fb9987d0f748c983bb795a86f47522313f701a08Sujith } 672fb9987d0f748c983bb795a86f47522313f701a08Sujith 673e1572c5eeca8ef87a250322364584458b2dadb35Sujith ret = ath9k_htc_init_debug(ah); 674fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) { 6753800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to create debugfs files\n"); 676fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_debug; 677fb9987d0f748c983bb795a86f47522313f701a08Sujith } 678fb9987d0f748c983bb795a86f47522313f701a08Sujith 679fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_init_queues(priv); 680fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 681fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_queues; 682fb9987d0f748c983bb795a86f47522313f701a08Sujith 683fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_init_crypto(priv); 684fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_init_channels_rates(priv); 685fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_init_misc(priv); 686fb9987d0f748c983bb795a86f47522313f701a08Sujith 68721cb987914cb5334af78378141efed77505ea987Vivek Natarajan if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) { 68821cb987914cb5334af78378141efed77505ea987Vivek Natarajan ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE; 68921cb987914cb5334af78378141efed77505ea987Vivek Natarajan ath9k_init_btcoex(priv); 69021cb987914cb5334af78378141efed77505ea987Vivek Natarajan } 69121cb987914cb5334af78378141efed77505ea987Vivek Natarajan 692fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 693fb9987d0f748c983bb795a86f47522313f701a08Sujith 694fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_queues: 695e1572c5eeca8ef87a250322364584458b2dadb35Sujith ath9k_htc_exit_debug(ah); 696fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_debug: 697fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_deinit(ah); 698fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_hw: 699fb9987d0f748c983bb795a86f47522313f701a08Sujith 700fb9987d0f748c983bb795a86f47522313f701a08Sujith kfree(ah); 701fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->ah = NULL; 702fb9987d0f748c983bb795a86f47522313f701a08Sujith 703fb9987d0f748c983bb795a86f47522313f701a08Sujith return ret; 704fb9987d0f748c983bb795a86f47522313f701a08Sujith} 705fb9987d0f748c983bb795a86f47522313f701a08Sujith 706fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, 707fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw) 708fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 709fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 710fb9987d0f748c983bb795a86f47522313f701a08Sujith 711fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->flags = IEEE80211_HW_SIGNAL_DBM | 712fb9987d0f748c983bb795a86f47522313f701a08Sujith IEEE80211_HW_AMPDU_AGGREGATION | 713fb9987d0f748c983bb795a86f47522313f701a08Sujith IEEE80211_HW_SPECTRUM_MGMT | 71432fbccafed7e935432b601f0453c2b702a385a25Sujith IEEE80211_HW_HAS_RATE_CONTROL | 715bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan IEEE80211_HW_RX_INCLUDES_FCS | 716bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan IEEE80211_HW_SUPPORTS_PS | 717bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan IEEE80211_HW_PS_NULLFUNC_STACK; 718fb9987d0f748c983bb795a86f47522313f701a08Sujith 719fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->wiphy->interface_modes = 720fb9987d0f748c983bb795a86f47522313f701a08Sujith BIT(NL80211_IFTYPE_STATION) | 721fb9987d0f748c983bb795a86f47522313f701a08Sujith BIT(NL80211_IFTYPE_ADHOC); 722fb9987d0f748c983bb795a86f47522313f701a08Sujith 723bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 724bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 725fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->queues = 4; 726fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->channel_change_time = 5000; 727fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->max_listen_interval = 10; 728fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->vif_data_size = sizeof(struct ath9k_htc_vif); 729fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->sta_data_size = sizeof(struct ath9k_htc_sta); 730fb9987d0f748c983bb795a86f47522313f701a08Sujith 731fb9987d0f748c983bb795a86f47522313f701a08Sujith /* tx_frame_hdr is larger than tx_mgmt_hdr anyway */ 732fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) + 733fb9987d0f748c983bb795a86f47522313f701a08Sujith sizeof(struct htc_frame_hdr) + 4; 734fb9987d0f748c983bb795a86f47522313f701a08Sujith 735d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 736fb9987d0f748c983bb795a86f47522313f701a08Sujith hw->wiphy->bands[IEEE80211_BAND_2GHZ] = 737fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->sbands[IEEE80211_BAND_2GHZ]; 738d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 739ea46e644e80bd4ac778964afd998df4f666486d4Sujith hw->wiphy->bands[IEEE80211_BAND_5GHZ] = 740ea46e644e80bd4ac778964afd998df4f666486d4Sujith &priv->sbands[IEEE80211_BAND_5GHZ]; 741fb9987d0f748c983bb795a86f47522313f701a08Sujith 742fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { 743d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 744fb9987d0f748c983bb795a86f47522313f701a08Sujith setup_ht_cap(priv, 745fb9987d0f748c983bb795a86f47522313f701a08Sujith &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); 746d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 747ea46e644e80bd4ac778964afd998df4f666486d4Sujith setup_ht_cap(priv, 748ea46e644e80bd4ac778964afd998df4f666486d4Sujith &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); 749fb9987d0f748c983bb795a86f47522313f701a08Sujith } 750fb9987d0f748c983bb795a86f47522313f701a08Sujith 751fb9987d0f748c983bb795a86f47522313f701a08Sujith SET_IEEE80211_PERM_ADDR(hw, common->macaddr); 752fb9987d0f748c983bb795a86f47522313f701a08Sujith} 753fb9987d0f748c983bb795a86f47522313f701a08Sujith 75421cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic int ath9k_init_device(struct ath9k_htc_priv *priv, 755fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan u16 devid, char *product, u32 drv_info) 756fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 757fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = priv->hw; 758fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common; 759fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah; 760fb9987d0f748c983bb795a86f47522313f701a08Sujith int error = 0; 761fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_regulatory *reg; 762fb9987d0f748c983bb795a86f47522313f701a08Sujith 763fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Bring up device */ 764fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan error = ath9k_init_priv(priv, devid, product, drv_info); 765fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error != 0) 766fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_init; 767fb9987d0f748c983bb795a86f47522313f701a08Sujith 768fb9987d0f748c983bb795a86f47522313f701a08Sujith ah = priv->ah; 769fb9987d0f748c983bb795a86f47522313f701a08Sujith common = ath9k_hw_common(ah); 770fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_set_hw_capab(priv, hw); 771fb9987d0f748c983bb795a86f47522313f701a08Sujith 772fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Initialize regulatory */ 773fb9987d0f748c983bb795a86f47522313f701a08Sujith error = ath_regd_init(&common->regulatory, priv->hw->wiphy, 774fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_reg_notifier); 775fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error) 776fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_regd; 777fb9987d0f748c983bb795a86f47522313f701a08Sujith 778fb9987d0f748c983bb795a86f47522313f701a08Sujith reg = &common->regulatory; 779fb9987d0f748c983bb795a86f47522313f701a08Sujith 780fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Setup TX */ 781fb9987d0f748c983bb795a86f47522313f701a08Sujith error = ath9k_tx_init(priv); 782fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error != 0) 783fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_tx; 784fb9987d0f748c983bb795a86f47522313f701a08Sujith 785fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Setup RX */ 786fb9987d0f748c983bb795a86f47522313f701a08Sujith error = ath9k_rx_init(priv); 787fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error != 0) 788fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_rx; 789fb9987d0f748c983bb795a86f47522313f701a08Sujith 790fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Register with mac80211 */ 791fb9987d0f748c983bb795a86f47522313f701a08Sujith error = ieee80211_register_hw(hw); 792fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error) 793fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_register; 794fb9987d0f748c983bb795a86f47522313f701a08Sujith 795fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Handle world regulatory */ 796fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath_is_world_regd(reg)) { 797fb9987d0f748c983bb795a86f47522313f701a08Sujith error = regulatory_hint(hw->wiphy, reg->alpha2); 798fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error) 799fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_world; 800fb9987d0f748c983bb795a86f47522313f701a08Sujith } 801fb9987d0f748c983bb795a86f47522313f701a08Sujith 802fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_init_leds(priv); 803fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_start_rfkill_poll(priv); 804fb9987d0f748c983bb795a86f47522313f701a08Sujith 805fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 806fb9987d0f748c983bb795a86f47522313f701a08Sujith 807fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_world: 808fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_unregister_hw(hw); 809fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_register: 810fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_rx_cleanup(priv); 811fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_rx: 812fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_tx_cleanup(priv); 813fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_tx: 814fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Nothing */ 815fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_regd: 816fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_deinit_priv(priv); 817fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init: 818fb9987d0f748c983bb795a86f47522313f701a08Sujith return error; 819fb9987d0f748c983bb795a86f47522313f701a08Sujith} 820fb9987d0f748c983bb795a86f47522313f701a08Sujith 821fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, 822fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan u16 devid, char *product, u32 drv_info) 823fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 824fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw; 825fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv; 826fb9987d0f748c983bb795a86f47522313f701a08Sujith int ret; 827fb9987d0f748c983bb795a86f47522313f701a08Sujith 828fb9987d0f748c983bb795a86f47522313f701a08Sujith hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops); 829fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!hw) 830fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ENOMEM; 831fb9987d0f748c983bb795a86f47522313f701a08Sujith 832fb9987d0f748c983bb795a86f47522313f701a08Sujith priv = hw->priv; 833fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->hw = hw; 834fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->htc = htc_handle; 835fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->dev = dev; 836fb9987d0f748c983bb795a86f47522313f701a08Sujith htc_handle->drv_priv = priv; 837fb9987d0f748c983bb795a86f47522313f701a08Sujith SET_IEEE80211_DEV(hw, priv->dev); 838fb9987d0f748c983bb795a86f47522313f701a08Sujith 839fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = ath9k_htc_wait_for_target(priv); 840fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 841fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_free; 842fb9987d0f748c983bb795a86f47522313f701a08Sujith 843fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->wmi = ath9k_init_wmi(priv); 844fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!priv->wmi) { 845fb9987d0f748c983bb795a86f47522313f701a08Sujith ret = -EINVAL; 846fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_free; 847fb9987d0f748c983bb795a86f47522313f701a08Sujith } 848fb9987d0f748c983bb795a86f47522313f701a08Sujith 849fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan ret = ath9k_init_htc_services(priv, devid, drv_info); 850fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 851fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_init; 852fb9987d0f748c983bb795a86f47522313f701a08Sujith 853a3be14b76da111ebe4d245b0542613f9317104e7Sujith /* The device may have been unplugged earlier. */ 854a3be14b76da111ebe4d245b0542613f9317104e7Sujith priv->op_flags &= ~OP_UNPLUGGED; 855a3be14b76da111ebe4d245b0542613f9317104e7Sujith 856fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan ret = ath9k_init_device(priv, devid, product, drv_info); 857fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 858fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_init; 859fb9987d0f748c983bb795a86f47522313f701a08Sujith 860fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 861fb9987d0f748c983bb795a86f47522313f701a08Sujith 862fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init: 863fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_deinit_wmi(priv); 864fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_free: 865fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_free_hw(hw); 866fb9987d0f748c983bb795a86f47522313f701a08Sujith return ret; 867fb9987d0f748c983bb795a86f47522313f701a08Sujith} 868fb9987d0f748c983bb795a86f47522313f701a08Sujith 869fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) 870fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 871fb9987d0f748c983bb795a86f47522313f701a08Sujith if (htc_handle->drv_priv) { 872a3be14b76da111ebe4d245b0542613f9317104e7Sujith 873a3be14b76da111ebe4d245b0542613f9317104e7Sujith /* Check if the device has been yanked out. */ 874a3be14b76da111ebe4d245b0542613f9317104e7Sujith if (hotunplug) 875a3be14b76da111ebe4d245b0542613f9317104e7Sujith htc_handle->drv_priv->op_flags |= OP_UNPLUGGED; 876a3be14b76da111ebe4d245b0542613f9317104e7Sujith 877fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_deinit_device(htc_handle->drv_priv); 878fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_deinit_wmi(htc_handle->drv_priv); 879fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_free_hw(htc_handle->drv_priv->hw); 880fb9987d0f748c983bb795a86f47522313f701a08Sujith } 881fb9987d0f748c983bb795a86f47522313f701a08Sujith} 882fb9987d0f748c983bb795a86f47522313f701a08Sujith 883fb9987d0f748c983bb795a86f47522313f701a08Sujith#ifdef CONFIG_PM 884fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_resume(struct htc_target *htc_handle) 885fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 886fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan struct ath9k_htc_priv *priv = htc_handle->drv_priv; 887fb9987d0f748c983bb795a86f47522313f701a08Sujith int ret; 888fb9987d0f748c983bb795a86f47522313f701a08Sujith 889fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan ret = ath9k_htc_wait_for_target(priv); 890fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ret) 891fb9987d0f748c983bb795a86f47522313f701a08Sujith return ret; 892fb9987d0f748c983bb795a86f47522313f701a08Sujith 893fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid, 894fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan priv->ah->common.driver_info); 895fb9987d0f748c983bb795a86f47522313f701a08Sujith return ret; 896fb9987d0f748c983bb795a86f47522313f701a08Sujith} 897fb9987d0f748c983bb795a86f47522313f701a08Sujith#endif 898fb9987d0f748c983bb795a86f47522313f701a08Sujith 899fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int __init ath9k_htc_init(void) 900fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 901fb9987d0f748c983bb795a86f47522313f701a08Sujith int error; 902fb9987d0f748c983bb795a86f47522313f701a08Sujith 903e1572c5eeca8ef87a250322364584458b2dadb35Sujith error = ath9k_htc_debug_create_root(); 904fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error < 0) { 905fb9987d0f748c983bb795a86f47522313f701a08Sujith printk(KERN_ERR 906fb9987d0f748c983bb795a86f47522313f701a08Sujith "ath9k_htc: Unable to create debugfs root: %d\n", 907fb9987d0f748c983bb795a86f47522313f701a08Sujith error); 908fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_dbg; 909fb9987d0f748c983bb795a86f47522313f701a08Sujith } 910fb9987d0f748c983bb795a86f47522313f701a08Sujith 911fb9987d0f748c983bb795a86f47522313f701a08Sujith error = ath9k_hif_usb_init(); 912fb9987d0f748c983bb795a86f47522313f701a08Sujith if (error < 0) { 913fb9987d0f748c983bb795a86f47522313f701a08Sujith printk(KERN_ERR 914fb9987d0f748c983bb795a86f47522313f701a08Sujith "ath9k_htc: No USB devices found," 915fb9987d0f748c983bb795a86f47522313f701a08Sujith " driver not installed.\n"); 916fb9987d0f748c983bb795a86f47522313f701a08Sujith error = -ENODEV; 917fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err_usb; 918fb9987d0f748c983bb795a86f47522313f701a08Sujith } 919fb9987d0f748c983bb795a86f47522313f701a08Sujith 920fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 921fb9987d0f748c983bb795a86f47522313f701a08Sujith 922fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_usb: 923e1572c5eeca8ef87a250322364584458b2dadb35Sujith ath9k_htc_debug_remove_root(); 924fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_dbg: 925fb9987d0f748c983bb795a86f47522313f701a08Sujith return error; 926fb9987d0f748c983bb795a86f47522313f701a08Sujith} 927fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_init(ath9k_htc_init); 928fb9987d0f748c983bb795a86f47522313f701a08Sujith 929fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void __exit ath9k_htc_exit(void) 930fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 931fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hif_usb_exit(); 932e1572c5eeca8ef87a250322364584458b2dadb35Sujith ath9k_htc_debug_remove_root(); 933fb9987d0f748c983bb795a86f47522313f701a08Sujith printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); 934fb9987d0f748c983bb795a86f47522313f701a08Sujith} 935fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_exit(ath9k_htc_exit); 936