1fb9987d0SSujith /* 25b68138eSSujith Manoharan * Copyright (c) 2010-2011 Atheros Communications Inc. 3fb9987d0SSujith * 4fb9987d0SSujith * Permission to use, copy, modify, and/or distribute this software for any 5fb9987d0SSujith * purpose with or without fee is hereby granted, provided that the above 6fb9987d0SSujith * copyright notice and this permission notice appear in all copies. 7fb9987d0SSujith * 8fb9987d0SSujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9fb9987d0SSujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10fb9987d0SSujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11fb9987d0SSujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12fb9987d0SSujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13fb9987d0SSujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14fb9987d0SSujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15fb9987d0SSujith */ 16fb9987d0SSujith 17516304b0SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 18516304b0SJoe Perches 19fb9987d0SSujith #include "htc.h" 20fb9987d0SSujith 21fb9987d0SSujith MODULE_AUTHOR("Atheros Communications"); 22fb9987d0SSujith MODULE_LICENSE("Dual BSD/GPL"); 23fb9987d0SSujith MODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices"); 24fb9987d0SSujith 25fb9987d0SSujith static unsigned int ath9k_debug = ATH_DBG_DEFAULT; 26fb9987d0SSujith module_param_named(debug, ath9k_debug, uint, 0); 27fb9987d0SSujith MODULE_PARM_DESC(debug, "Debugging mask"); 28fb9987d0SSujith 29e1572c5eSSujith int htc_modparam_nohwcrypt; 30e1572c5eSSujith module_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444); 31fb9987d0SSujith MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); 32fb9987d0SSujith 337f34778eSMohammed Shafi Shajakhan static int ath9k_htc_btcoex_enable; 347f34778eSMohammed Shafi Shajakhan module_param_named(btcoex_enable, ath9k_htc_btcoex_enable, int, 0444); 357f34778eSMohammed Shafi Shajakhan MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); 367f34778eSMohammed Shafi Shajakhan 376bca610dSOleksij Rempel static int ath9k_ps_enable; 386bca610dSOleksij Rempel module_param_named(ps_enable, ath9k_ps_enable, int, 0444); 396bca610dSOleksij Rempel MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); 406bca610dSOleksij Rempel 41fb9987d0SSujith #define CHAN2G(_freq, _idx) { \ 42fb9987d0SSujith .center_freq = (_freq), \ 43fb9987d0SSujith .hw_value = (_idx), \ 44fb9987d0SSujith .max_power = 20, \ 45fb9987d0SSujith } 46fb9987d0SSujith 47ea46e644SSujith #define CHAN5G(_freq, _idx) { \ 48ea46e644SSujith .band = IEEE80211_BAND_5GHZ, \ 49ea46e644SSujith .center_freq = (_freq), \ 50ea46e644SSujith .hw_value = (_idx), \ 51ea46e644SSujith .max_power = 20, \ 52ea46e644SSujith } 53ea46e644SSujith 54fb9987d0SSujith static struct ieee80211_channel ath9k_2ghz_channels[] = { 55fb9987d0SSujith CHAN2G(2412, 0), /* Channel 1 */ 56fb9987d0SSujith CHAN2G(2417, 1), /* Channel 2 */ 57fb9987d0SSujith CHAN2G(2422, 2), /* Channel 3 */ 58fb9987d0SSujith CHAN2G(2427, 3), /* Channel 4 */ 59fb9987d0SSujith CHAN2G(2432, 4), /* Channel 5 */ 60fb9987d0SSujith CHAN2G(2437, 5), /* Channel 6 */ 61fb9987d0SSujith CHAN2G(2442, 6), /* Channel 7 */ 62fb9987d0SSujith CHAN2G(2447, 7), /* Channel 8 */ 63fb9987d0SSujith CHAN2G(2452, 8), /* Channel 9 */ 64fb9987d0SSujith CHAN2G(2457, 9), /* Channel 10 */ 65fb9987d0SSujith CHAN2G(2462, 10), /* Channel 11 */ 66fb9987d0SSujith CHAN2G(2467, 11), /* Channel 12 */ 67fb9987d0SSujith CHAN2G(2472, 12), /* Channel 13 */ 68fb9987d0SSujith CHAN2G(2484, 13), /* Channel 14 */ 69fb9987d0SSujith }; 70fb9987d0SSujith 71ea46e644SSujith static struct ieee80211_channel ath9k_5ghz_channels[] = { 72ea46e644SSujith /* _We_ call this UNII 1 */ 73ea46e644SSujith CHAN5G(5180, 14), /* Channel 36 */ 74ea46e644SSujith CHAN5G(5200, 15), /* Channel 40 */ 75ea46e644SSujith CHAN5G(5220, 16), /* Channel 44 */ 76ea46e644SSujith CHAN5G(5240, 17), /* Channel 48 */ 77ea46e644SSujith /* _We_ call this UNII 2 */ 78ea46e644SSujith CHAN5G(5260, 18), /* Channel 52 */ 79ea46e644SSujith CHAN5G(5280, 19), /* Channel 56 */ 80ea46e644SSujith CHAN5G(5300, 20), /* Channel 60 */ 81ea46e644SSujith CHAN5G(5320, 21), /* Channel 64 */ 82ea46e644SSujith /* _We_ call this "Middle band" */ 83ea46e644SSujith CHAN5G(5500, 22), /* Channel 100 */ 84ea46e644SSujith CHAN5G(5520, 23), /* Channel 104 */ 85ea46e644SSujith CHAN5G(5540, 24), /* Channel 108 */ 86ea46e644SSujith CHAN5G(5560, 25), /* Channel 112 */ 87ea46e644SSujith CHAN5G(5580, 26), /* Channel 116 */ 88ea46e644SSujith CHAN5G(5600, 27), /* Channel 120 */ 89ea46e644SSujith CHAN5G(5620, 28), /* Channel 124 */ 90ea46e644SSujith CHAN5G(5640, 29), /* Channel 128 */ 91ea46e644SSujith CHAN5G(5660, 30), /* Channel 132 */ 92ea46e644SSujith CHAN5G(5680, 31), /* Channel 136 */ 93ea46e644SSujith CHAN5G(5700, 32), /* Channel 140 */ 94ea46e644SSujith /* _We_ call this UNII 3 */ 95ea46e644SSujith CHAN5G(5745, 33), /* Channel 149 */ 96ea46e644SSujith CHAN5G(5765, 34), /* Channel 153 */ 97ea46e644SSujith CHAN5G(5785, 35), /* Channel 157 */ 98ea46e644SSujith CHAN5G(5805, 36), /* Channel 161 */ 99ea46e644SSujith CHAN5G(5825, 37), /* Channel 165 */ 100ea46e644SSujith }; 101ea46e644SSujith 102fb9987d0SSujith /* Atheros hardware rate code addition for short premble */ 103fb9987d0SSujith #define SHPCHECK(__hw_rate, __flags) \ 104fb9987d0SSujith ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) 105fb9987d0SSujith 106fb9987d0SSujith #define RATE(_bitrate, _hw_rate, _flags) { \ 107fb9987d0SSujith .bitrate = (_bitrate), \ 108fb9987d0SSujith .flags = (_flags), \ 109fb9987d0SSujith .hw_value = (_hw_rate), \ 110fb9987d0SSujith .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ 111fb9987d0SSujith } 112fb9987d0SSujith 113fb9987d0SSujith static struct ieee80211_rate ath9k_legacy_rates[] = { 114fb9987d0SSujith RATE(10, 0x1b, 0), 115fb9987d0SSujith RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ 116fb9987d0SSujith RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ 117fb9987d0SSujith RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ 118fb9987d0SSujith RATE(60, 0x0b, 0), 119fb9987d0SSujith RATE(90, 0x0f, 0), 120fb9987d0SSujith RATE(120, 0x0a, 0), 121fb9987d0SSujith RATE(180, 0x0e, 0), 122fb9987d0SSujith RATE(240, 0x09, 0), 123fb9987d0SSujith RATE(360, 0x0d, 0), 124fb9987d0SSujith RATE(480, 0x08, 0), 125fb9987d0SSujith RATE(540, 0x0c, 0), 126fb9987d0SSujith }; 127fb9987d0SSujith 128d244f21eSSujith Manoharan #ifdef CONFIG_MAC80211_LEDS 129d244f21eSSujith Manoharan static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { 130d244f21eSSujith Manoharan { .throughput = 0 * 1024, .blink_time = 334 }, 131d244f21eSSujith Manoharan { .throughput = 1 * 1024, .blink_time = 260 }, 132d244f21eSSujith Manoharan { .throughput = 5 * 1024, .blink_time = 220 }, 133d244f21eSSujith Manoharan { .throughput = 10 * 1024, .blink_time = 190 }, 134d244f21eSSujith Manoharan { .throughput = 20 * 1024, .blink_time = 170 }, 135d244f21eSSujith Manoharan { .throughput = 50 * 1024, .blink_time = 150 }, 136d244f21eSSujith Manoharan { .throughput = 70 * 1024, .blink_time = 130 }, 137d244f21eSSujith Manoharan { .throughput = 100 * 1024, .blink_time = 110 }, 138d244f21eSSujith Manoharan { .throughput = 200 * 1024, .blink_time = 80 }, 139d244f21eSSujith Manoharan { .throughput = 300 * 1024, .blink_time = 50 }, 140d244f21eSSujith Manoharan }; 141d244f21eSSujith Manoharan #endif 142d244f21eSSujith Manoharan 143fb9987d0SSujith static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) 144fb9987d0SSujith { 145fb9987d0SSujith int time_left; 146fb9987d0SSujith 147d8c49ffbSSujith.Manoharan@atheros.com if (atomic_read(&priv->htc->tgt_ready) > 0) { 148d8c49ffbSSujith.Manoharan@atheros.com atomic_dec(&priv->htc->tgt_ready); 149d8c49ffbSSujith.Manoharan@atheros.com return 0; 150d8c49ffbSSujith.Manoharan@atheros.com } 151d8c49ffbSSujith.Manoharan@atheros.com 152fb9987d0SSujith /* Firmware can take up to 50ms to get ready, to be safe use 1 second */ 153fb9987d0SSujith time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ); 154fb9987d0SSujith if (!time_left) { 155fb9987d0SSujith dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n"); 156fb9987d0SSujith return -ETIMEDOUT; 157fb9987d0SSujith } 158fb9987d0SSujith 159d8c49ffbSSujith.Manoharan@atheros.com atomic_dec(&priv->htc->tgt_ready); 160d8c49ffbSSujith.Manoharan@atheros.com 161fb9987d0SSujith return 0; 162fb9987d0SSujith } 163fb9987d0SSujith 164fb9987d0SSujith static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) 165fb9987d0SSujith { 166fb9987d0SSujith ath9k_hw_deinit(priv->ah); 167fb9987d0SSujith kfree(priv->ah); 168fb9987d0SSujith priv->ah = NULL; 169fb9987d0SSujith } 170fb9987d0SSujith 171fb9987d0SSujith static void ath9k_deinit_device(struct ath9k_htc_priv *priv) 172fb9987d0SSujith { 173fb9987d0SSujith struct ieee80211_hw *hw = priv->hw; 174fb9987d0SSujith 175fb9987d0SSujith wiphy_rfkill_stop_polling(hw->wiphy); 176fb9987d0SSujith ath9k_deinit_leds(priv); 177fb9987d0SSujith ieee80211_unregister_hw(hw); 178fb9987d0SSujith ath9k_rx_cleanup(priv); 179fb9987d0SSujith ath9k_tx_cleanup(priv); 180fb9987d0SSujith ath9k_deinit_priv(priv); 181fb9987d0SSujith } 182fb9987d0SSujith 183fb9987d0SSujith static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv, 184fb9987d0SSujith u16 service_id, 185fb9987d0SSujith void (*tx) (void *, 186fb9987d0SSujith struct sk_buff *, 187fb9987d0SSujith enum htc_endpoint_id, 188fb9987d0SSujith bool txok), 189fb9987d0SSujith enum htc_endpoint_id *ep_id) 190fb9987d0SSujith { 191fb9987d0SSujith struct htc_service_connreq req; 192fb9987d0SSujith 193fb9987d0SSujith memset(&req, 0, sizeof(struct htc_service_connreq)); 194fb9987d0SSujith 195fb9987d0SSujith req.service_id = service_id; 196fb9987d0SSujith req.ep_callbacks.priv = priv; 197fb9987d0SSujith req.ep_callbacks.rx = ath9k_htc_rxep; 198fb9987d0SSujith req.ep_callbacks.tx = tx; 199fb9987d0SSujith 200fb9987d0SSujith return htc_connect_service(priv->htc, &req, ep_id); 201fb9987d0SSujith } 202fb9987d0SSujith 203fa6e15e0SRajkumar Manoharan static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid, 204fa6e15e0SRajkumar Manoharan u32 drv_info) 205fb9987d0SSujith { 206fb9987d0SSujith int ret; 207fb9987d0SSujith 208fb9987d0SSujith /* WMI CMD*/ 209fb9987d0SSujith ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep); 210fb9987d0SSujith if (ret) 211fb9987d0SSujith goto err; 212fb9987d0SSujith 213fb9987d0SSujith /* Beacon */ 2149c6dda4eSSujith ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep, 215fb9987d0SSujith &priv->beacon_ep); 216fb9987d0SSujith if (ret) 217fb9987d0SSujith goto err; 218fb9987d0SSujith 219fb9987d0SSujith /* CAB */ 220fb9987d0SSujith ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep, 221fb9987d0SSujith &priv->cab_ep); 222fb9987d0SSujith if (ret) 223fb9987d0SSujith goto err; 224fb9987d0SSujith 225fb9987d0SSujith 226fb9987d0SSujith /* UAPSD */ 227fb9987d0SSujith ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep, 228fb9987d0SSujith &priv->uapsd_ep); 229fb9987d0SSujith if (ret) 230fb9987d0SSujith goto err; 231fb9987d0SSujith 232fb9987d0SSujith /* MGMT */ 233fb9987d0SSujith ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep, 234fb9987d0SSujith &priv->mgmt_ep); 235fb9987d0SSujith if (ret) 236fb9987d0SSujith goto err; 237fb9987d0SSujith 238fb9987d0SSujith /* DATA BE */ 239fb9987d0SSujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep, 240fb9987d0SSujith &priv->data_be_ep); 241fb9987d0SSujith if (ret) 242fb9987d0SSujith goto err; 243fb9987d0SSujith 244fb9987d0SSujith /* DATA BK */ 245fb9987d0SSujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep, 246fb9987d0SSujith &priv->data_bk_ep); 247fb9987d0SSujith if (ret) 248fb9987d0SSujith goto err; 249fb9987d0SSujith 250fb9987d0SSujith /* DATA VI */ 251fb9987d0SSujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep, 252fb9987d0SSujith &priv->data_vi_ep); 253fb9987d0SSujith if (ret) 254fb9987d0SSujith goto err; 255fb9987d0SSujith 256fb9987d0SSujith /* DATA VO */ 257fb9987d0SSujith ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep, 258fb9987d0SSujith &priv->data_vo_ep); 259fb9987d0SSujith if (ret) 260fb9987d0SSujith goto err; 261fb9987d0SSujith 2626267dc70SSujith /* 2636267dc70SSujith * Setup required credits before initializing HTC. 2646267dc70SSujith * This is a bit hacky, but, since queuing is done in 2656267dc70SSujith * the HIF layer, shouldn't matter much. 2666267dc70SSujith */ 2676267dc70SSujith 2680b5ead91SSujith Manoharan if (IS_AR7010_DEVICE(drv_info)) 269d108e8b9SSujith Manoharan priv->htc->credits = 45; 270fa6e15e0SRajkumar Manoharan else 2714e63f768SSujith priv->htc->credits = 33; 2726267dc70SSujith 273fb9987d0SSujith ret = htc_init(priv->htc); 274fb9987d0SSujith if (ret) 275fb9987d0SSujith goto err; 276fb9987d0SSujith 2776267dc70SSujith dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n", 2786267dc70SSujith priv->htc->credits); 2796267dc70SSujith 280fb9987d0SSujith return 0; 281fb9987d0SSujith 282fb9987d0SSujith err: 283fb9987d0SSujith dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n"); 284fb9987d0SSujith return ret; 285fb9987d0SSujith } 286fb9987d0SSujith 2870c0280bdSLuis R. Rodriguez static void ath9k_reg_notifier(struct wiphy *wiphy, 288fb9987d0SSujith struct regulatory_request *request) 289fb9987d0SSujith { 290fb9987d0SSujith struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 291fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 292fb9987d0SSujith 2930c0280bdSLuis R. Rodriguez ath_reg_notifier_apply(wiphy, request, 294fb9987d0SSujith ath9k_hw_regulatory(priv->ah)); 295fb9987d0SSujith } 296fb9987d0SSujith 2974a22fe10SSujith static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) 298fb9987d0SSujith { 299fb9987d0SSujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 300fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 301fb9987d0SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 302fb9987d0SSujith __be32 val, reg = cpu_to_be32(reg_offset); 303fb9987d0SSujith int r; 304fb9987d0SSujith 305fb9987d0SSujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, 306fb9987d0SSujith (u8 *) ®, sizeof(reg), 307fb9987d0SSujith (u8 *) &val, sizeof(val), 308fb9987d0SSujith 100); 309fb9987d0SSujith if (unlikely(r)) { 310d2182b69SJoe Perches ath_dbg(common, WMI, "REGISTER READ FAILED: (0x%04x, %d)\n", 311fb9987d0SSujith reg_offset, r); 312fb9987d0SSujith return -EIO; 313fb9987d0SSujith } 314fb9987d0SSujith 315fb9987d0SSujith return be32_to_cpu(val); 316fb9987d0SSujith } 317fb9987d0SSujith 31809a525d3SSujith Manoharan static void ath9k_multi_regread(void *hw_priv, u32 *addr, 31909a525d3SSujith Manoharan u32 *val, u16 count) 32009a525d3SSujith Manoharan { 32109a525d3SSujith Manoharan struct ath_hw *ah = (struct ath_hw *) hw_priv; 32209a525d3SSujith Manoharan struct ath_common *common = ath9k_hw_common(ah); 32309a525d3SSujith Manoharan struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 32409a525d3SSujith Manoharan __be32 tmpaddr[8]; 32509a525d3SSujith Manoharan __be32 tmpval[8]; 32609a525d3SSujith Manoharan int i, ret; 32709a525d3SSujith Manoharan 32809a525d3SSujith Manoharan for (i = 0; i < count; i++) { 32909a525d3SSujith Manoharan tmpaddr[i] = cpu_to_be32(addr[i]); 33009a525d3SSujith Manoharan } 33109a525d3SSujith Manoharan 33209a525d3SSujith Manoharan ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, 33309a525d3SSujith Manoharan (u8 *)tmpaddr , sizeof(u32) * count, 33409a525d3SSujith Manoharan (u8 *)tmpval, sizeof(u32) * count, 33509a525d3SSujith Manoharan 100); 33609a525d3SSujith Manoharan if (unlikely(ret)) { 337d2182b69SJoe Perches ath_dbg(common, WMI, 33809a525d3SSujith Manoharan "Multiple REGISTER READ FAILED (count: %d)\n", count); 33909a525d3SSujith Manoharan } 34009a525d3SSujith Manoharan 34109a525d3SSujith Manoharan for (i = 0; i < count; i++) { 34209a525d3SSujith Manoharan val[i] = be32_to_cpu(tmpval[i]); 34309a525d3SSujith Manoharan } 34409a525d3SSujith Manoharan } 34509a525d3SSujith Manoharan 3464a22fe10SSujith static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) 347fb9987d0SSujith { 348fb9987d0SSujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 349fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 350fb9987d0SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 35107b2fa5aSJoe Perches const __be32 buf[2] = { 352fb9987d0SSujith cpu_to_be32(reg_offset), 353fb9987d0SSujith cpu_to_be32(val), 354fb9987d0SSujith }; 355fb9987d0SSujith int r; 356fb9987d0SSujith 357fb9987d0SSujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, 358fb9987d0SSujith (u8 *) &buf, sizeof(buf), 359fb9987d0SSujith (u8 *) &val, sizeof(val), 360fb9987d0SSujith 100); 361fb9987d0SSujith if (unlikely(r)) { 362d2182b69SJoe Perches ath_dbg(common, WMI, "REGISTER WRITE FAILED:(0x%04x, %d)\n", 363fb9987d0SSujith reg_offset, r); 364fb9987d0SSujith } 365fb9987d0SSujith } 366fb9987d0SSujith 3674a22fe10SSujith static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) 3684a22fe10SSujith { 3694a22fe10SSujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 3704a22fe10SSujith struct ath_common *common = ath9k_hw_common(ah); 3714a22fe10SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 3724a22fe10SSujith u32 rsp_status; 3734a22fe10SSujith int r; 3744a22fe10SSujith 3754a22fe10SSujith mutex_lock(&priv->wmi->multi_write_mutex); 3764a22fe10SSujith 3774a22fe10SSujith /* Store the register/value */ 3784a22fe10SSujith priv->wmi->multi_write[priv->wmi->multi_write_idx].reg = 3794a22fe10SSujith cpu_to_be32(reg_offset); 3804a22fe10SSujith priv->wmi->multi_write[priv->wmi->multi_write_idx].val = 3814a22fe10SSujith cpu_to_be32(val); 3824a22fe10SSujith 3834a22fe10SSujith priv->wmi->multi_write_idx++; 3844a22fe10SSujith 3854a22fe10SSujith /* If the buffer is full, send it out. */ 3864a22fe10SSujith if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { 3874a22fe10SSujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, 3884a22fe10SSujith (u8 *) &priv->wmi->multi_write, 3894a22fe10SSujith sizeof(struct register_write) * priv->wmi->multi_write_idx, 3904a22fe10SSujith (u8 *) &rsp_status, sizeof(rsp_status), 3914a22fe10SSujith 100); 3924a22fe10SSujith if (unlikely(r)) { 393d2182b69SJoe Perches ath_dbg(common, WMI, 3944a22fe10SSujith "REGISTER WRITE FAILED, multi len: %d\n", 3954a22fe10SSujith priv->wmi->multi_write_idx); 3964a22fe10SSujith } 3974a22fe10SSujith priv->wmi->multi_write_idx = 0; 3984a22fe10SSujith } 3994a22fe10SSujith 4004a22fe10SSujith mutex_unlock(&priv->wmi->multi_write_mutex); 4014a22fe10SSujith } 4024a22fe10SSujith 4034a22fe10SSujith static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset) 4044a22fe10SSujith { 4054a22fe10SSujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 4064a22fe10SSujith struct ath_common *common = ath9k_hw_common(ah); 4074a22fe10SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 4084a22fe10SSujith 4094a22fe10SSujith if (atomic_read(&priv->wmi->mwrite_cnt)) 4104a22fe10SSujith ath9k_regwrite_buffer(hw_priv, val, reg_offset); 4114a22fe10SSujith else 4124a22fe10SSujith ath9k_regwrite_single(hw_priv, val, reg_offset); 4134a22fe10SSujith } 4144a22fe10SSujith 4154a22fe10SSujith static void ath9k_enable_regwrite_buffer(void *hw_priv) 4164a22fe10SSujith { 4174a22fe10SSujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 4184a22fe10SSujith struct ath_common *common = ath9k_hw_common(ah); 4194a22fe10SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 4204a22fe10SSujith 4214a22fe10SSujith atomic_inc(&priv->wmi->mwrite_cnt); 4224a22fe10SSujith } 4234a22fe10SSujith 4244a22fe10SSujith static void ath9k_regwrite_flush(void *hw_priv) 4254a22fe10SSujith { 4264a22fe10SSujith struct ath_hw *ah = (struct ath_hw *) hw_priv; 4274a22fe10SSujith struct ath_common *common = ath9k_hw_common(ah); 4284a22fe10SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 4294a22fe10SSujith u32 rsp_status; 4304a22fe10SSujith int r; 4314a22fe10SSujith 432435c1610SFelix Fietkau atomic_dec(&priv->wmi->mwrite_cnt); 433435c1610SFelix Fietkau 4344a22fe10SSujith mutex_lock(&priv->wmi->multi_write_mutex); 4354a22fe10SSujith 4364a22fe10SSujith if (priv->wmi->multi_write_idx) { 4374a22fe10SSujith r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, 4384a22fe10SSujith (u8 *) &priv->wmi->multi_write, 4394a22fe10SSujith sizeof(struct register_write) * priv->wmi->multi_write_idx, 4404a22fe10SSujith (u8 *) &rsp_status, sizeof(rsp_status), 4414a22fe10SSujith 100); 4424a22fe10SSujith if (unlikely(r)) { 443d2182b69SJoe Perches ath_dbg(common, WMI, 4444a22fe10SSujith "REGISTER WRITE FAILED, multi len: %d\n", 4454a22fe10SSujith priv->wmi->multi_write_idx); 4464a22fe10SSujith } 4474a22fe10SSujith priv->wmi->multi_write_idx = 0; 4484a22fe10SSujith } 4494a22fe10SSujith 4504a22fe10SSujith mutex_unlock(&priv->wmi->multi_write_mutex); 4514a22fe10SSujith } 4524a22fe10SSujith 453845e03c9SFelix Fietkau static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) 454845e03c9SFelix Fietkau { 455845e03c9SFelix Fietkau u32 val; 456845e03c9SFelix Fietkau 457845e03c9SFelix Fietkau val = ath9k_regread(hw_priv, reg_offset); 458845e03c9SFelix Fietkau val &= ~clr; 459845e03c9SFelix Fietkau val |= set; 460845e03c9SFelix Fietkau ath9k_regwrite(hw_priv, val, reg_offset); 461845e03c9SFelix Fietkau return val; 462845e03c9SFelix Fietkau } 463845e03c9SFelix Fietkau 464fb9987d0SSujith static void ath_usb_read_cachesize(struct ath_common *common, int *csz) 465fb9987d0SSujith { 466fb9987d0SSujith *csz = L1_CACHE_BYTES >> 2; 467fb9987d0SSujith } 468fb9987d0SSujith 469fb9987d0SSujith static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) 470fb9987d0SSujith { 471fb9987d0SSujith struct ath_hw *ah = (struct ath_hw *) common->ah; 472fb9987d0SSujith 473fb9987d0SSujith (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); 474fb9987d0SSujith 475fb9987d0SSujith if (!ath9k_hw_wait(ah, 476fb9987d0SSujith AR_EEPROM_STATUS_DATA, 477fb9987d0SSujith AR_EEPROM_STATUS_DATA_BUSY | 478fb9987d0SSujith AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, 479fb9987d0SSujith AH_WAIT_TIMEOUT)) 480fb9987d0SSujith return false; 481fb9987d0SSujith 482fb9987d0SSujith *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), 483fb9987d0SSujith AR_EEPROM_STATUS_DATA_VAL); 484fb9987d0SSujith 485fb9987d0SSujith return true; 486fb9987d0SSujith } 487fb9987d0SSujith 488fb9987d0SSujith static const struct ath_bus_ops ath9k_usb_bus_ops = { 489497ad9adSSujith .ath_bus_type = ATH_USB, 490fb9987d0SSujith .read_cachesize = ath_usb_read_cachesize, 491fb9987d0SSujith .eeprom_read = ath_usb_eeprom_read, 492fb9987d0SSujith }; 493fb9987d0SSujith 494fb9987d0SSujith static void setup_ht_cap(struct ath9k_htc_priv *priv, 495fb9987d0SSujith struct ieee80211_sta_ht_cap *ht_info) 496fb9987d0SSujith { 4976debecadSSujith struct ath_common *common = ath9k_hw_common(priv->ah); 4986debecadSSujith u8 tx_streams, rx_streams; 4996debecadSSujith int i; 5006debecadSSujith 501fb9987d0SSujith ht_info->ht_supported = true; 502fb9987d0SSujith ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 503fb9987d0SSujith IEEE80211_HT_CAP_SM_PS | 504fb9987d0SSujith IEEE80211_HT_CAP_SGI_40 | 505fb9987d0SSujith IEEE80211_HT_CAP_DSSSCCK40; 506fb9987d0SSujith 507b4dec5e8SSujith if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) 508b4dec5e8SSujith ht_info->cap |= IEEE80211_HT_CAP_SGI_20; 509b4dec5e8SSujith 51017525f96SSujith ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 51117525f96SSujith 512fb9987d0SSujith ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 513fb9987d0SSujith ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; 514fb9987d0SSujith 515fb9987d0SSujith memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); 5166debecadSSujith 5176debecadSSujith /* ath9k_htc supports only 1 or 2 stream devices */ 51882b2d334SFelix Fietkau tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); 51982b2d334SFelix Fietkau rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); 5206debecadSSujith 521d2182b69SJoe Perches ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", 5226debecadSSujith tx_streams, rx_streams); 5236debecadSSujith 524a226c3d9SOleksij Rempel if (tx_streams >= 2) 525a226c3d9SOleksij Rempel ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; 526a226c3d9SOleksij Rempel 5276debecadSSujith if (tx_streams != rx_streams) { 5286debecadSSujith ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; 5296debecadSSujith ht_info->mcs.tx_params |= ((tx_streams - 1) << 5306debecadSSujith IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); 5316debecadSSujith } 5326debecadSSujith 5336debecadSSujith for (i = 0; i < rx_streams; i++) 5346debecadSSujith ht_info->mcs.rx_mask[i] = 0xff; 5356debecadSSujith 536fb9987d0SSujith ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; 537fb9987d0SSujith } 538fb9987d0SSujith 539fb9987d0SSujith static int ath9k_init_queues(struct ath9k_htc_priv *priv) 540fb9987d0SSujith { 541fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 542fb9987d0SSujith int i; 543fb9987d0SSujith 544fb9987d0SSujith for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) 545fb9987d0SSujith priv->hwq_map[i] = -1; 546fb9987d0SSujith 547ca74b83bSSujith priv->beaconq = ath9k_hw_beaconq_setup(priv->ah); 548ca74b83bSSujith if (priv->beaconq == -1) { 5493800276aSJoe Perches ath_err(common, "Unable to setup BEACON xmit queue\n"); 550ca74b83bSSujith goto err; 551ca74b83bSSujith } 552ca74b83bSSujith 553ca74b83bSSujith priv->cabq = ath9k_htc_cabq_setup(priv); 554ca74b83bSSujith if (priv->cabq == -1) { 5553800276aSJoe Perches ath_err(common, "Unable to setup CAB xmit queue\n"); 556ca74b83bSSujith goto err; 557ca74b83bSSujith } 558ca74b83bSSujith 559bea843c7SSujith Manoharan if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BE)) { 5603800276aSJoe Perches ath_err(common, "Unable to setup xmit queue for BE traffic\n"); 561fb9987d0SSujith goto err; 562fb9987d0SSujith } 563fb9987d0SSujith 564bea843c7SSujith Manoharan if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BK)) { 5653800276aSJoe Perches ath_err(common, "Unable to setup xmit queue for BK traffic\n"); 566fb9987d0SSujith goto err; 567fb9987d0SSujith } 568bea843c7SSujith Manoharan if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VI)) { 5693800276aSJoe Perches ath_err(common, "Unable to setup xmit queue for VI traffic\n"); 570fb9987d0SSujith goto err; 571fb9987d0SSujith } 572bea843c7SSujith Manoharan if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VO)) { 5733800276aSJoe Perches ath_err(common, "Unable to setup xmit queue for VO traffic\n"); 574fb9987d0SSujith goto err; 575fb9987d0SSujith } 576fb9987d0SSujith 577fb9987d0SSujith return 0; 578fb9987d0SSujith 579fb9987d0SSujith err: 580fb9987d0SSujith return -EINVAL; 581fb9987d0SSujith } 582fb9987d0SSujith 583fb9987d0SSujith static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) 584fb9987d0SSujith { 585d4659912SFelix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { 586fb9987d0SSujith priv->sbands[IEEE80211_BAND_2GHZ].channels = 587fb9987d0SSujith ath9k_2ghz_channels; 588fb9987d0SSujith priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; 589fb9987d0SSujith priv->sbands[IEEE80211_BAND_2GHZ].n_channels = 590fb9987d0SSujith ARRAY_SIZE(ath9k_2ghz_channels); 591fb9987d0SSujith priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; 592fb9987d0SSujith priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = 593fb9987d0SSujith ARRAY_SIZE(ath9k_legacy_rates); 594fb9987d0SSujith } 595ea46e644SSujith 596d4659912SFelix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { 597ea46e644SSujith priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; 598ea46e644SSujith priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; 599ea46e644SSujith priv->sbands[IEEE80211_BAND_5GHZ].n_channels = 600ea46e644SSujith ARRAY_SIZE(ath9k_5ghz_channels); 601ea46e644SSujith priv->sbands[IEEE80211_BAND_5GHZ].bitrates = 602ea46e644SSujith ath9k_legacy_rates + 4; 603ea46e644SSujith priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates = 604ea46e644SSujith ARRAY_SIZE(ath9k_legacy_rates) - 4; 605ea46e644SSujith } 606fb9987d0SSujith } 607fb9987d0SSujith 608fb9987d0SSujith static void ath9k_init_misc(struct ath9k_htc_priv *priv) 609fb9987d0SSujith { 610fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 611fb9987d0SSujith 612fb9987d0SSujith memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); 613fb9987d0SSujith 6149f01a84eSSujith priv->ah->opmode = NL80211_IFTYPE_STATION; 615fb9987d0SSujith } 616fb9987d0SSujith 61721cb9879SVivek Natarajan static int ath9k_init_priv(struct ath9k_htc_priv *priv, 618fa6e15e0SRajkumar Manoharan u16 devid, char *product, 619fa6e15e0SRajkumar Manoharan u32 drv_info) 620fb9987d0SSujith { 621fb9987d0SSujith struct ath_hw *ah = NULL; 622fb9987d0SSujith struct ath_common *common; 623832f6a18SSujith Manoharan int i, ret = 0, csz = 0; 624fb9987d0SSujith 625d8a2c51cSSujith Manoharan set_bit(OP_INVALID, &priv->op_flags); 626fb9987d0SSujith 627fb9987d0SSujith ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); 628fb9987d0SSujith if (!ah) 629fb9987d0SSujith return -ENOMEM; 630fb9987d0SSujith 631fb9987d0SSujith ah->hw_version.devid = devid; 6320b5ead91SSujith Manoharan ah->hw_version.usbdev = drv_info; 633f8afa42bSFelix Fietkau ah->ah_flags |= AH_USE_EEPROM; 634f9f84e96SFelix Fietkau ah->reg_ops.read = ath9k_regread; 635f9f84e96SFelix Fietkau ah->reg_ops.multi_read = ath9k_multi_regread; 636f9f84e96SFelix Fietkau ah->reg_ops.write = ath9k_regwrite; 637f9f84e96SFelix Fietkau ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; 638f9f84e96SFelix Fietkau ah->reg_ops.write_flush = ath9k_regwrite_flush; 639845e03c9SFelix Fietkau ah->reg_ops.rmw = ath9k_reg_rmw; 640fb9987d0SSujith priv->ah = ah; 641fb9987d0SSujith 642fb9987d0SSujith common = ath9k_hw_common(ah); 643f9f84e96SFelix Fietkau common->ops = &ah->reg_ops; 644fb9987d0SSujith common->bus_ops = &ath9k_usb_bus_ops; 645fb9987d0SSujith common->ah = ah; 646fb9987d0SSujith common->hw = priv->hw; 647fb9987d0SSujith common->priv = priv; 648fb9987d0SSujith common->debug_mask = ath9k_debug; 6497f34778eSMohammed Shafi Shajakhan common->btcoex_enabled = ath9k_htc_btcoex_enable == 1; 650fb9987d0SSujith 651fb9987d0SSujith spin_lock_init(&priv->beacon_lock); 652658ef04fSSujith Manoharan spin_lock_init(&priv->tx.tx_lock); 653fb9987d0SSujith mutex_init(&priv->mutex); 654bde748a4SVivek Natarajan mutex_init(&priv->htc_pm_lock); 655fb9987d0SSujith tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, 656fb9987d0SSujith (unsigned long)priv); 65727876a29SSujith Manoharan tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet, 65873908674SSujith Manoharan (unsigned long)priv); 659a236254cSSujith Manoharan INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); 660bde748a4SVivek Natarajan INIT_WORK(&priv->ps_work, ath9k_ps_work); 66173908674SSujith Manoharan INIT_WORK(&priv->fatal_work, ath9k_fatal_work); 662859c3ca1SSujith Manoharan setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer, 663859c3ca1SSujith Manoharan (unsigned long)priv); 664fb9987d0SSujith 665fb9987d0SSujith /* 666fb9987d0SSujith * Cache line size is used to size and align various 667fb9987d0SSujith * structures used to communicate with the hardware. 668fb9987d0SSujith */ 669fb9987d0SSujith ath_read_cachesize(common, &csz); 670fb9987d0SSujith common->cachelsz = csz << 2; /* convert to bytes */ 671fb9987d0SSujith 672fb9987d0SSujith ret = ath9k_hw_init(ah); 673fb9987d0SSujith if (ret) { 6743800276aSJoe Perches ath_err(common, 6753800276aSJoe Perches "Unable to initialize hardware; initialization status: %d\n", 6763800276aSJoe Perches ret); 677fb9987d0SSujith goto err_hw; 678fb9987d0SSujith } 679fb9987d0SSujith 680fb9987d0SSujith ret = ath9k_init_queues(priv); 681fb9987d0SSujith if (ret) 682fb9987d0SSujith goto err_queues; 683fb9987d0SSujith 684832f6a18SSujith Manoharan for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) 685832f6a18SSujith Manoharan priv->cur_beacon_conf.bslot[i] = NULL; 686832f6a18SSujith Manoharan 687f82b4bdeSRajkumar Manoharan ath9k_cmn_init_crypto(ah); 688fb9987d0SSujith ath9k_init_channels_rates(priv); 689fb9987d0SSujith ath9k_init_misc(priv); 690cee5341dSSujith Manoharan ath9k_htc_init_btcoex(priv, product); 69121cb9879SVivek Natarajan 692fb9987d0SSujith return 0; 693fb9987d0SSujith 694fb9987d0SSujith err_queues: 695fb9987d0SSujith ath9k_hw_deinit(ah); 696fb9987d0SSujith err_hw: 697fb9987d0SSujith 698fb9987d0SSujith kfree(ah); 699fb9987d0SSujith priv->ah = NULL; 700fb9987d0SSujith 701fb9987d0SSujith return ret; 702fb9987d0SSujith } 703fb9987d0SSujith 7048b0b6be5SMohammed Shafi Shajakhan static const struct ieee80211_iface_limit if_limits[] = { 7058b0b6be5SMohammed Shafi Shajakhan { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | 7068b0b6be5SMohammed Shafi Shajakhan BIT(NL80211_IFTYPE_P2P_CLIENT) }, 7078b0b6be5SMohammed Shafi Shajakhan { .max = 2, .types = BIT(NL80211_IFTYPE_AP) | 7080c9acaa8SThomas Pedersen #ifdef CONFIG_MAC80211_MESH 7090c9acaa8SThomas Pedersen BIT(NL80211_IFTYPE_MESH_POINT) | 7100c9acaa8SThomas Pedersen #endif 7110c9acaa8SThomas Pedersen BIT(NL80211_IFTYPE_P2P_GO) }, 7128b0b6be5SMohammed Shafi Shajakhan }; 7138b0b6be5SMohammed Shafi Shajakhan 7148b0b6be5SMohammed Shafi Shajakhan static const struct ieee80211_iface_combination if_comb = { 7158b0b6be5SMohammed Shafi Shajakhan .limits = if_limits, 7168b0b6be5SMohammed Shafi Shajakhan .n_limits = ARRAY_SIZE(if_limits), 7178b0b6be5SMohammed Shafi Shajakhan .max_interfaces = 2, 7188b0b6be5SMohammed Shafi Shajakhan .num_different_channels = 1, 7198b0b6be5SMohammed Shafi Shajakhan }; 7208b0b6be5SMohammed Shafi Shajakhan 721fb9987d0SSujith static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, 722fb9987d0SSujith struct ieee80211_hw *hw) 723fb9987d0SSujith { 724fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 725156652bbSBen Greear struct base_eep_header *pBase; 726fb9987d0SSujith 727fb9987d0SSujith hw->flags = IEEE80211_HW_SIGNAL_DBM | 728fb9987d0SSujith IEEE80211_HW_AMPDU_AGGREGATION | 729fb9987d0SSujith IEEE80211_HW_SPECTRUM_MGMT | 73032fbccafSSujith IEEE80211_HW_HAS_RATE_CONTROL | 731bde748a4SVivek Natarajan IEEE80211_HW_RX_INCLUDES_FCS | 7327d547eb4SSujith Manoharan IEEE80211_HW_PS_NULLFUNC_STACK | 7338ae2e12fSRajkumar Manoharan IEEE80211_HW_REPORTS_TX_ACK_STATUS | 734bd4a85eeSJavier Cardona IEEE80211_HW_MFP_CAPABLE | 7357d547eb4SSujith Manoharan IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; 736fb9987d0SSujith 7376bca610dSOleksij Rempel if (ath9k_ps_enable) 7386bca610dSOleksij Rempel hw->flags |= IEEE80211_HW_SUPPORTS_PS; 7396bca610dSOleksij Rempel 740fb9987d0SSujith hw->wiphy->interface_modes = 741fb9987d0SSujith BIT(NL80211_IFTYPE_STATION) | 74209d5b94dSSujith Manoharan BIT(NL80211_IFTYPE_ADHOC) | 74309d5b94dSSujith Manoharan BIT(NL80211_IFTYPE_AP) | 74409d5b94dSSujith Manoharan BIT(NL80211_IFTYPE_P2P_GO) | 745594e65b6SJavier Cardona BIT(NL80211_IFTYPE_P2P_CLIENT) | 746594e65b6SJavier Cardona BIT(NL80211_IFTYPE_MESH_POINT); 747fb9987d0SSujith 7488b0b6be5SMohammed Shafi Shajakhan hw->wiphy->iface_combinations = &if_comb; 7498b0b6be5SMohammed Shafi Shajakhan hw->wiphy->n_iface_combinations = 1; 7508b0b6be5SMohammed Shafi Shajakhan 751bde748a4SVivek Natarajan hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 752bde748a4SVivek Natarajan 75381ddbb5cSJohannes Berg hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | 75481ddbb5cSJohannes Berg WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 755d7d312caSAntonio Quartulli 756fb9987d0SSujith hw->queues = 4; 757fb1c078eSSujith Manoharan hw->max_listen_interval = 1; 7583a0593efSSujith Manoharan 759fb9987d0SSujith hw->vif_data_size = sizeof(struct ath9k_htc_vif); 760fb9987d0SSujith hw->sta_data_size = sizeof(struct ath9k_htc_sta); 761fb9987d0SSujith 762fb9987d0SSujith /* tx_frame_hdr is larger than tx_mgmt_hdr anyway */ 763fb9987d0SSujith hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) + 764fb9987d0SSujith sizeof(struct htc_frame_hdr) + 4; 765fb9987d0SSujith 766d4659912SFelix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 767fb9987d0SSujith hw->wiphy->bands[IEEE80211_BAND_2GHZ] = 768fb9987d0SSujith &priv->sbands[IEEE80211_BAND_2GHZ]; 769d4659912SFelix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 770ea46e644SSujith hw->wiphy->bands[IEEE80211_BAND_5GHZ] = 771ea46e644SSujith &priv->sbands[IEEE80211_BAND_5GHZ]; 772fb9987d0SSujith 773fb9987d0SSujith if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { 774d4659912SFelix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 775fb9987d0SSujith setup_ht_cap(priv, 776fb9987d0SSujith &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); 777d4659912SFelix Fietkau if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 778ea46e644SSujith setup_ht_cap(priv, 779ea46e644SSujith &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); 780fb9987d0SSujith } 781fb9987d0SSujith 782156652bbSBen Greear pBase = ath9k_htc_get_eeprom_base(priv); 783156652bbSBen Greear if (pBase) { 784156652bbSBen Greear hw->wiphy->available_antennas_rx = pBase->rxMask; 785156652bbSBen Greear hw->wiphy->available_antennas_tx = pBase->txMask; 786156652bbSBen Greear } 787156652bbSBen Greear 788fb9987d0SSujith SET_IEEE80211_PERM_ADDR(hw, common->macaddr); 789fb9987d0SSujith } 790fb9987d0SSujith 79129bbfb24SSujith Manoharan static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) 79229bbfb24SSujith Manoharan { 79329bbfb24SSujith Manoharan struct ieee80211_hw *hw = priv->hw; 79429bbfb24SSujith Manoharan struct wmi_fw_version cmd_rsp; 79529bbfb24SSujith Manoharan int ret; 79629bbfb24SSujith Manoharan 79729bbfb24SSujith Manoharan memset(&cmd_rsp, 0, sizeof(cmd_rsp)); 79829bbfb24SSujith Manoharan 79929bbfb24SSujith Manoharan WMI_CMD(WMI_GET_FW_VERSION); 80029bbfb24SSujith Manoharan if (ret) 80129bbfb24SSujith Manoharan return -EINVAL; 80229bbfb24SSujith Manoharan 80329bbfb24SSujith Manoharan priv->fw_version_major = be16_to_cpu(cmd_rsp.major); 80429bbfb24SSujith Manoharan priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor); 80529bbfb24SSujith Manoharan 80681135548SJiri Pirko snprintf(hw->wiphy->fw_version, sizeof(hw->wiphy->fw_version), "%d.%d", 80729bbfb24SSujith Manoharan priv->fw_version_major, 80829bbfb24SSujith Manoharan priv->fw_version_minor); 80929bbfb24SSujith Manoharan 81029bbfb24SSujith Manoharan dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n", 81129bbfb24SSujith Manoharan priv->fw_version_major, 81229bbfb24SSujith Manoharan priv->fw_version_minor); 81329bbfb24SSujith Manoharan 8143a0593efSSujith Manoharan /* 8153a0593efSSujith Manoharan * Check if the available FW matches the driver's 8163a0593efSSujith Manoharan * required version. 8173a0593efSSujith Manoharan */ 8183a0593efSSujith Manoharan if (priv->fw_version_major != MAJOR_VERSION_REQ || 819319e7bd9SFelix Fietkau priv->fw_version_minor < MINOR_VERSION_REQ) { 8203a0593efSSujith Manoharan dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n", 8213a0593efSSujith Manoharan MAJOR_VERSION_REQ, MINOR_VERSION_REQ); 8223a0593efSSujith Manoharan return -EINVAL; 8233a0593efSSujith Manoharan } 8243a0593efSSujith Manoharan 82529bbfb24SSujith Manoharan return 0; 82629bbfb24SSujith Manoharan } 82729bbfb24SSujith Manoharan 82821cb9879SVivek Natarajan static int ath9k_init_device(struct ath9k_htc_priv *priv, 829fa6e15e0SRajkumar Manoharan u16 devid, char *product, u32 drv_info) 830fb9987d0SSujith { 831fb9987d0SSujith struct ieee80211_hw *hw = priv->hw; 832fb9987d0SSujith struct ath_common *common; 833fb9987d0SSujith struct ath_hw *ah; 834fb9987d0SSujith int error = 0; 835fb9987d0SSujith struct ath_regulatory *reg; 8363e3f1d19SSujith Manoharan char hw_name[64]; 837fb9987d0SSujith 838fb9987d0SSujith /* Bring up device */ 839fa6e15e0SRajkumar Manoharan error = ath9k_init_priv(priv, devid, product, drv_info); 840fb9987d0SSujith if (error != 0) 841fb9987d0SSujith goto err_init; 842fb9987d0SSujith 843fb9987d0SSujith ah = priv->ah; 844fb9987d0SSujith common = ath9k_hw_common(ah); 845fb9987d0SSujith ath9k_set_hw_capab(priv, hw); 846fb9987d0SSujith 84729bbfb24SSujith Manoharan error = ath9k_init_firmware_version(priv); 84829bbfb24SSujith Manoharan if (error != 0) 84929bbfb24SSujith Manoharan goto err_fw; 85029bbfb24SSujith Manoharan 851fb9987d0SSujith /* Initialize regulatory */ 852fb9987d0SSujith error = ath_regd_init(&common->regulatory, priv->hw->wiphy, 853fb9987d0SSujith ath9k_reg_notifier); 854fb9987d0SSujith if (error) 855fb9987d0SSujith goto err_regd; 856fb9987d0SSujith 857fb9987d0SSujith reg = &common->regulatory; 858fb9987d0SSujith 859fb9987d0SSujith /* Setup TX */ 860fb9987d0SSujith error = ath9k_tx_init(priv); 861fb9987d0SSujith if (error != 0) 862fb9987d0SSujith goto err_tx; 863fb9987d0SSujith 864fb9987d0SSujith /* Setup RX */ 865fb9987d0SSujith error = ath9k_rx_init(priv); 866fb9987d0SSujith if (error != 0) 867fb9987d0SSujith goto err_rx; 868fb9987d0SSujith 869dc2a87f5SOleksij Rempel ath9k_hw_disable(priv->ah); 870d244f21eSSujith Manoharan #ifdef CONFIG_MAC80211_LEDS 871d244f21eSSujith Manoharan /* must be initialized before ieee80211_register_hw */ 872d244f21eSSujith Manoharan priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, 873d244f21eSSujith Manoharan IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink, 874d244f21eSSujith Manoharan ARRAY_SIZE(ath9k_htc_tpt_blink)); 875d244f21eSSujith Manoharan #endif 876d244f21eSSujith Manoharan 877fb9987d0SSujith /* Register with mac80211 */ 878fb9987d0SSujith error = ieee80211_register_hw(hw); 879fb9987d0SSujith if (error) 880fb9987d0SSujith goto err_register; 881fb9987d0SSujith 882fb9987d0SSujith /* Handle world regulatory */ 883fb9987d0SSujith if (!ath_is_world_regd(reg)) { 884fb9987d0SSujith error = regulatory_hint(hw->wiphy, reg->alpha2); 885fb9987d0SSujith if (error) 886fb9987d0SSujith goto err_world; 887fb9987d0SSujith } 888fb9987d0SSujith 889e5facc75SRajkumar Manoharan error = ath9k_htc_init_debug(priv->ah); 890e5facc75SRajkumar Manoharan if (error) { 891e5facc75SRajkumar Manoharan ath_err(common, "Unable to create debugfs files\n"); 892e5facc75SRajkumar Manoharan goto err_world; 893e5facc75SRajkumar Manoharan } 894e5facc75SRajkumar Manoharan 895d2182b69SJoe Perches ath_dbg(common, CONFIG, 896d2182b69SJoe Perches "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, BE:%d, BK:%d, VI:%d, VO:%d\n", 8973e3f1d19SSujith Manoharan priv->wmi_cmd_ep, 8983e3f1d19SSujith Manoharan priv->beacon_ep, 8993e3f1d19SSujith Manoharan priv->cab_ep, 9003e3f1d19SSujith Manoharan priv->uapsd_ep, 9013e3f1d19SSujith Manoharan priv->mgmt_ep, 9023e3f1d19SSujith Manoharan priv->data_be_ep, 9033e3f1d19SSujith Manoharan priv->data_bk_ep, 9043e3f1d19SSujith Manoharan priv->data_vi_ep, 9053e3f1d19SSujith Manoharan priv->data_vo_ep); 9063e3f1d19SSujith Manoharan 9073e3f1d19SSujith Manoharan ath9k_hw_name(priv->ah, hw_name, sizeof(hw_name)); 9083e3f1d19SSujith Manoharan wiphy_info(hw->wiphy, "%s\n", hw_name); 9093e3f1d19SSujith Manoharan 910fb9987d0SSujith ath9k_init_leds(priv); 911fb9987d0SSujith ath9k_start_rfkill_poll(priv); 912fb9987d0SSujith 913fb9987d0SSujith return 0; 914fb9987d0SSujith 915fb9987d0SSujith err_world: 916fb9987d0SSujith ieee80211_unregister_hw(hw); 917fb9987d0SSujith err_register: 918fb9987d0SSujith ath9k_rx_cleanup(priv); 919fb9987d0SSujith err_rx: 920fb9987d0SSujith ath9k_tx_cleanup(priv); 921fb9987d0SSujith err_tx: 922fb9987d0SSujith /* Nothing */ 923fb9987d0SSujith err_regd: 92429bbfb24SSujith Manoharan /* Nothing */ 92529bbfb24SSujith Manoharan err_fw: 926fb9987d0SSujith ath9k_deinit_priv(priv); 927fb9987d0SSujith err_init: 928fb9987d0SSujith return error; 929fb9987d0SSujith } 930fb9987d0SSujith 931fb9987d0SSujith int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, 932fa6e15e0SRajkumar Manoharan u16 devid, char *product, u32 drv_info) 933fb9987d0SSujith { 934fb9987d0SSujith struct ieee80211_hw *hw; 935fb9987d0SSujith struct ath9k_htc_priv *priv; 936fb9987d0SSujith int ret; 937fb9987d0SSujith 938fb9987d0SSujith hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops); 939fb9987d0SSujith if (!hw) 940fb9987d0SSujith return -ENOMEM; 941fb9987d0SSujith 942fb9987d0SSujith priv = hw->priv; 943fb9987d0SSujith priv->hw = hw; 944fb9987d0SSujith priv->htc = htc_handle; 945fb9987d0SSujith priv->dev = dev; 946fb9987d0SSujith htc_handle->drv_priv = priv; 947fb9987d0SSujith SET_IEEE80211_DEV(hw, priv->dev); 948fb9987d0SSujith 949fb9987d0SSujith ret = ath9k_htc_wait_for_target(priv); 950fb9987d0SSujith if (ret) 951fb9987d0SSujith goto err_free; 952fb9987d0SSujith 953fb9987d0SSujith priv->wmi = ath9k_init_wmi(priv); 954fb9987d0SSujith if (!priv->wmi) { 955fb9987d0SSujith ret = -EINVAL; 956fb9987d0SSujith goto err_free; 957fb9987d0SSujith } 958fb9987d0SSujith 959fa6e15e0SRajkumar Manoharan ret = ath9k_init_htc_services(priv, devid, drv_info); 960fb9987d0SSujith if (ret) 961fb9987d0SSujith goto err_init; 962fb9987d0SSujith 963fa6e15e0SRajkumar Manoharan ret = ath9k_init_device(priv, devid, product, drv_info); 964fb9987d0SSujith if (ret) 965fb9987d0SSujith goto err_init; 966fb9987d0SSujith 967fb9987d0SSujith return 0; 968fb9987d0SSujith 969fb9987d0SSujith err_init: 970fb9987d0SSujith ath9k_deinit_wmi(priv); 971fb9987d0SSujith err_free: 972fb9987d0SSujith ieee80211_free_hw(hw); 973fb9987d0SSujith return ret; 974fb9987d0SSujith } 975fb9987d0SSujith 976fb9987d0SSujith void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) 977fb9987d0SSujith { 978fb9987d0SSujith if (htc_handle->drv_priv) { 979a3be14b7SSujith 980a3be14b7SSujith /* Check if the device has been yanked out. */ 981a3be14b7SSujith if (hotunplug) 98297dcec57SSujith Manoharan htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED; 983a3be14b7SSujith 984fb9987d0SSujith ath9k_deinit_device(htc_handle->drv_priv); 985fb9987d0SSujith ath9k_deinit_wmi(htc_handle->drv_priv); 986fb9987d0SSujith ieee80211_free_hw(htc_handle->drv_priv->hw); 987fb9987d0SSujith } 988fb9987d0SSujith } 989fb9987d0SSujith 990fb9987d0SSujith #ifdef CONFIG_PM 991f933ebedSSujith Manoharan 992f933ebedSSujith Manoharan void ath9k_htc_suspend(struct htc_target *htc_handle) 993f933ebedSSujith Manoharan { 994f933ebedSSujith Manoharan ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP); 995f933ebedSSujith Manoharan } 996f933ebedSSujith Manoharan 997fb9987d0SSujith int ath9k_htc_resume(struct htc_target *htc_handle) 998fb9987d0SSujith { 999fa6e15e0SRajkumar Manoharan struct ath9k_htc_priv *priv = htc_handle->drv_priv; 1000fb9987d0SSujith int ret; 1001fb9987d0SSujith 1002fa6e15e0SRajkumar Manoharan ret = ath9k_htc_wait_for_target(priv); 1003fb9987d0SSujith if (ret) 1004fb9987d0SSujith return ret; 1005fb9987d0SSujith 1006fa6e15e0SRajkumar Manoharan ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid, 10070b5ead91SSujith Manoharan priv->ah->hw_version.usbdev); 10081e51acaaSOleksij Rempel ath9k_configure_leds(priv); 10091e51acaaSOleksij Rempel 1010fb9987d0SSujith return ret; 1011fb9987d0SSujith } 1012fb9987d0SSujith #endif 1013fb9987d0SSujith 1014fb9987d0SSujith static int __init ath9k_htc_init(void) 1015fb9987d0SSujith { 1016e5facc75SRajkumar Manoharan if (ath9k_hif_usb_init() < 0) { 1017516304b0SJoe Perches pr_err("No USB devices found, driver not installed\n"); 1018e5facc75SRajkumar Manoharan return -ENODEV; 1019fb9987d0SSujith } 1020fb9987d0SSujith 1021fb9987d0SSujith return 0; 1022fb9987d0SSujith } 1023fb9987d0SSujith module_init(ath9k_htc_init); 1024fb9987d0SSujith 1025fb9987d0SSujith static void __exit ath9k_htc_exit(void) 1026fb9987d0SSujith { 1027fb9987d0SSujith ath9k_hif_usb_exit(); 1028516304b0SJoe Perches pr_info("Driver unloaded\n"); 1029fb9987d0SSujith } 1030fb9987d0SSujith module_exit(ath9k_htc_exit); 1031