1fb9987d0SSujith /* 2fb9987d0SSujith * Copyright (c) 2010 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 17fb9987d0SSujith #include "htc.h" 18fb9987d0SSujith 19fb9987d0SSujith #ifdef CONFIG_ATH9K_HTC_DEBUGFS 20fb9987d0SSujith static struct dentry *ath9k_debugfs_root; 21fb9987d0SSujith #endif 22fb9987d0SSujith 23fb9987d0SSujith /*************/ 24fb9987d0SSujith /* Utilities */ 25fb9987d0SSujith /*************/ 26fb9987d0SSujith 27fb9987d0SSujith static void ath_update_txpow(struct ath9k_htc_priv *priv) 28fb9987d0SSujith { 29fb9987d0SSujith struct ath_hw *ah = priv->ah; 30fb9987d0SSujith u32 txpow; 31fb9987d0SSujith 32fb9987d0SSujith if (priv->curtxpow != priv->txpowlimit) { 33fb9987d0SSujith ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit); 34fb9987d0SSujith /* read back in case value is clamped */ 35fb9987d0SSujith ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); 36fb9987d0SSujith priv->curtxpow = txpow; 37fb9987d0SSujith } 38fb9987d0SSujith } 39fb9987d0SSujith 40fb9987d0SSujith /* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */ 41fb9987d0SSujith static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, 42fb9987d0SSujith struct ath9k_channel *ichan) 43fb9987d0SSujith { 44fb9987d0SSujith enum htc_phymode mode; 45fb9987d0SSujith 46fb9987d0SSujith mode = HTC_MODE_AUTO; 47fb9987d0SSujith 48fb9987d0SSujith switch (ichan->chanmode) { 49fb9987d0SSujith case CHANNEL_G: 50fb9987d0SSujith case CHANNEL_G_HT20: 51fb9987d0SSujith case CHANNEL_G_HT40PLUS: 52fb9987d0SSujith case CHANNEL_G_HT40MINUS: 53fb9987d0SSujith mode = HTC_MODE_11NG; 54fb9987d0SSujith break; 55fb9987d0SSujith case CHANNEL_A: 56fb9987d0SSujith case CHANNEL_A_HT20: 57fb9987d0SSujith case CHANNEL_A_HT40PLUS: 58fb9987d0SSujith case CHANNEL_A_HT40MINUS: 59fb9987d0SSujith mode = HTC_MODE_11NA; 60fb9987d0SSujith break; 61fb9987d0SSujith default: 62fb9987d0SSujith break; 63fb9987d0SSujith } 64fb9987d0SSujith 65fb9987d0SSujith return mode; 66fb9987d0SSujith } 67fb9987d0SSujith 68bde748a4SVivek Natarajan static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, 69bde748a4SVivek Natarajan enum ath9k_power_mode mode) 70bde748a4SVivek Natarajan { 71bde748a4SVivek Natarajan bool ret; 72bde748a4SVivek Natarajan 73bde748a4SVivek Natarajan mutex_lock(&priv->htc_pm_lock); 74bde748a4SVivek Natarajan ret = ath9k_hw_setpower(priv->ah, mode); 75bde748a4SVivek Natarajan mutex_unlock(&priv->htc_pm_lock); 76bde748a4SVivek Natarajan 77bde748a4SVivek Natarajan return ret; 78bde748a4SVivek Natarajan } 79bde748a4SVivek Natarajan 80bde748a4SVivek Natarajan void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv) 81bde748a4SVivek Natarajan { 82bde748a4SVivek Natarajan mutex_lock(&priv->htc_pm_lock); 83bde748a4SVivek Natarajan if (++priv->ps_usecount != 1) 84bde748a4SVivek Natarajan goto unlock; 85bde748a4SVivek Natarajan ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE); 86bde748a4SVivek Natarajan 87bde748a4SVivek Natarajan unlock: 88bde748a4SVivek Natarajan mutex_unlock(&priv->htc_pm_lock); 89bde748a4SVivek Natarajan } 90bde748a4SVivek Natarajan 91bde748a4SVivek Natarajan void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv) 92bde748a4SVivek Natarajan { 93bde748a4SVivek Natarajan mutex_lock(&priv->htc_pm_lock); 94bde748a4SVivek Natarajan if (--priv->ps_usecount != 0) 95bde748a4SVivek Natarajan goto unlock; 96bde748a4SVivek Natarajan 978a8572a8SVivek Natarajan if (priv->ps_idle) 988a8572a8SVivek Natarajan ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP); 998a8572a8SVivek Natarajan else if (priv->ps_enabled) 100bde748a4SVivek Natarajan ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP); 1018a8572a8SVivek Natarajan 102bde748a4SVivek Natarajan unlock: 103bde748a4SVivek Natarajan mutex_unlock(&priv->htc_pm_lock); 104bde748a4SVivek Natarajan } 105bde748a4SVivek Natarajan 106bde748a4SVivek Natarajan void ath9k_ps_work(struct work_struct *work) 107bde748a4SVivek Natarajan { 108bde748a4SVivek Natarajan struct ath9k_htc_priv *priv = 109bde748a4SVivek Natarajan container_of(work, struct ath9k_htc_priv, 110bde748a4SVivek Natarajan ps_work); 111bde748a4SVivek Natarajan ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); 112bde748a4SVivek Natarajan 113bde748a4SVivek Natarajan /* The chip wakes up after receiving the first beacon 114bde748a4SVivek Natarajan while network sleep is enabled. For the driver to 115bde748a4SVivek Natarajan be in sync with the hw, set the chip to awake and 116bde748a4SVivek Natarajan only then set it to sleep. 117bde748a4SVivek Natarajan */ 118bde748a4SVivek Natarajan ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); 119bde748a4SVivek Natarajan } 120bde748a4SVivek Natarajan 121fb9987d0SSujith static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, 122fb9987d0SSujith struct ieee80211_hw *hw, 123fb9987d0SSujith struct ath9k_channel *hchan) 124fb9987d0SSujith { 125fb9987d0SSujith struct ath_hw *ah = priv->ah; 126fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 127fb9987d0SSujith struct ieee80211_conf *conf = &common->hw->conf; 128fb9987d0SSujith bool fastcc = true; 129fb9987d0SSujith struct ieee80211_channel *channel = hw->conf.channel; 130fb9987d0SSujith enum htc_phymode mode; 1317f1f5a00SSujith __be16 htc_mode; 132fb9987d0SSujith u8 cmd_rsp; 133fb9987d0SSujith int ret; 134fb9987d0SSujith 135fb9987d0SSujith if (priv->op_flags & OP_INVALID) 136fb9987d0SSujith return -EIO; 137fb9987d0SSujith 138fb9987d0SSujith if (priv->op_flags & OP_FULL_RESET) 139fb9987d0SSujith fastcc = false; 140fb9987d0SSujith 141fb9987d0SSujith /* Fiddle around with fastcc later on, for now just use full reset */ 142fb9987d0SSujith fastcc = false; 143bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 144fb9987d0SSujith htc_stop(priv->htc); 145fb9987d0SSujith WMI_CMD(WMI_DISABLE_INTR_CMDID); 146fb9987d0SSujith WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); 147fb9987d0SSujith WMI_CMD(WMI_STOP_RECV_CMDID); 148fb9987d0SSujith 149fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 150fb9987d0SSujith "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n", 151fb9987d0SSujith priv->ah->curchan->channel, 152fb9987d0SSujith channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf)); 153fb9987d0SSujith 154fb9987d0SSujith ret = ath9k_hw_reset(ah, hchan, fastcc); 155fb9987d0SSujith if (ret) { 156fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 157fb9987d0SSujith "Unable to reset channel (%u Mhz) " 158fb9987d0SSujith "reset status %d\n", channel->center_freq, ret); 159fb9987d0SSujith goto err; 160fb9987d0SSujith } 161fb9987d0SSujith 162fb9987d0SSujith ath_update_txpow(priv); 163fb9987d0SSujith 164fb9987d0SSujith WMI_CMD(WMI_START_RECV_CMDID); 165fb9987d0SSujith if (ret) 166fb9987d0SSujith goto err; 167fb9987d0SSujith 168fb9987d0SSujith ath9k_host_rx_init(priv); 169fb9987d0SSujith 170fb9987d0SSujith mode = ath9k_htc_get_curmode(priv, hchan); 171fb9987d0SSujith htc_mode = cpu_to_be16(mode); 172fb9987d0SSujith WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); 173fb9987d0SSujith if (ret) 174fb9987d0SSujith goto err; 175fb9987d0SSujith 176fb9987d0SSujith WMI_CMD(WMI_ENABLE_INTR_CMDID); 177fb9987d0SSujith if (ret) 178fb9987d0SSujith goto err; 179fb9987d0SSujith 180fb9987d0SSujith htc_start(priv->htc); 181fb9987d0SSujith 182fb9987d0SSujith priv->op_flags &= ~OP_FULL_RESET; 183fb9987d0SSujith err: 184bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 185fb9987d0SSujith return ret; 186fb9987d0SSujith } 187fb9987d0SSujith 188fb9987d0SSujith static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) 189fb9987d0SSujith { 190fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 191fb9987d0SSujith struct ath9k_htc_target_vif hvif; 192fb9987d0SSujith int ret = 0; 193fb9987d0SSujith u8 cmd_rsp; 194fb9987d0SSujith 195fb9987d0SSujith if (priv->nvifs > 0) 196fb9987d0SSujith return -ENOBUFS; 197fb9987d0SSujith 198fb9987d0SSujith memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); 199fb9987d0SSujith memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); 200fb9987d0SSujith 201fb9987d0SSujith hvif.opmode = cpu_to_be32(HTC_M_MONITOR); 202fb9987d0SSujith priv->ah->opmode = NL80211_IFTYPE_MONITOR; 203fb9987d0SSujith hvif.index = priv->nvifs; 204fb9987d0SSujith 205fb9987d0SSujith WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); 206fb9987d0SSujith if (ret) 207fb9987d0SSujith return ret; 208fb9987d0SSujith 209fb9987d0SSujith priv->nvifs++; 210fb9987d0SSujith return 0; 211fb9987d0SSujith } 212fb9987d0SSujith 213fb9987d0SSujith static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) 214fb9987d0SSujith { 215fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 216fb9987d0SSujith struct ath9k_htc_target_vif hvif; 217fb9987d0SSujith int ret = 0; 218fb9987d0SSujith u8 cmd_rsp; 219fb9987d0SSujith 220fb9987d0SSujith memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); 221fb9987d0SSujith memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); 222fb9987d0SSujith hvif.index = 0; /* Should do for now */ 223fb9987d0SSujith WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); 224fb9987d0SSujith priv->nvifs--; 225fb9987d0SSujith 226fb9987d0SSujith return ret; 227fb9987d0SSujith } 228fb9987d0SSujith 229fb9987d0SSujith static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, 230fb9987d0SSujith struct ieee80211_vif *vif, 231fb9987d0SSujith struct ieee80211_sta *sta) 232fb9987d0SSujith { 233fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 234fb9987d0SSujith struct ath9k_htc_target_sta tsta; 235fb9987d0SSujith struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; 236fb9987d0SSujith struct ath9k_htc_sta *ista; 237fb9987d0SSujith int ret; 238fb9987d0SSujith u8 cmd_rsp; 239fb9987d0SSujith 240fb9987d0SSujith if (priv->nstations >= ATH9K_HTC_MAX_STA) 241fb9987d0SSujith return -ENOBUFS; 242fb9987d0SSujith 243fb9987d0SSujith memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); 244fb9987d0SSujith 245fb9987d0SSujith if (sta) { 246fb9987d0SSujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 247fb9987d0SSujith memcpy(&tsta.macaddr, sta->addr, ETH_ALEN); 248fb9987d0SSujith memcpy(&tsta.bssid, common->curbssid, ETH_ALEN); 249fb9987d0SSujith tsta.associd = common->curaid; 250fb9987d0SSujith tsta.is_vif_sta = 0; 251fb9987d0SSujith tsta.valid = true; 252fb9987d0SSujith ista->index = priv->nstations; 253fb9987d0SSujith } else { 254fb9987d0SSujith memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); 255fb9987d0SSujith tsta.is_vif_sta = 1; 256fb9987d0SSujith } 257fb9987d0SSujith 258fb9987d0SSujith tsta.sta_index = priv->nstations; 259fb9987d0SSujith tsta.vif_index = avp->index; 260fb9987d0SSujith tsta.maxampdu = 0xffff; 261fb9987d0SSujith if (sta && sta->ht_cap.ht_supported) 262fb9987d0SSujith tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); 263fb9987d0SSujith 264fb9987d0SSujith WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); 265fb9987d0SSujith if (ret) { 266fb9987d0SSujith if (sta) 267fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 268fb9987d0SSujith "Unable to add station entry for: %pM\n", sta->addr); 269fb9987d0SSujith return ret; 270fb9987d0SSujith } 271fb9987d0SSujith 272fb9987d0SSujith if (sta) 273fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 274fb9987d0SSujith "Added a station entry for: %pM (idx: %d)\n", 275fb9987d0SSujith sta->addr, tsta.sta_index); 276fb9987d0SSujith 277fb9987d0SSujith priv->nstations++; 278fb9987d0SSujith return 0; 279fb9987d0SSujith } 280fb9987d0SSujith 281fb9987d0SSujith static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, 282fb9987d0SSujith struct ieee80211_vif *vif, 283fb9987d0SSujith struct ieee80211_sta *sta) 284fb9987d0SSujith { 285fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 286fb9987d0SSujith struct ath9k_htc_sta *ista; 287fb9987d0SSujith int ret; 288fb9987d0SSujith u8 cmd_rsp, sta_idx; 289fb9987d0SSujith 290fb9987d0SSujith if (sta) { 291fb9987d0SSujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 292fb9987d0SSujith sta_idx = ista->index; 293fb9987d0SSujith } else { 294fb9987d0SSujith sta_idx = 0; 295fb9987d0SSujith } 296fb9987d0SSujith 297fb9987d0SSujith WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); 298fb9987d0SSujith if (ret) { 299fb9987d0SSujith if (sta) 300fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 301fb9987d0SSujith "Unable to remove station entry for: %pM\n", 302fb9987d0SSujith sta->addr); 303fb9987d0SSujith return ret; 304fb9987d0SSujith } 305fb9987d0SSujith 306fb9987d0SSujith if (sta) 307fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 308fb9987d0SSujith "Removed a station entry for: %pM (idx: %d)\n", 309fb9987d0SSujith sta->addr, sta_idx); 310fb9987d0SSujith 311fb9987d0SSujith priv->nstations--; 312fb9987d0SSujith return 0; 313fb9987d0SSujith } 314fb9987d0SSujith 315fb9987d0SSujith static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) 316fb9987d0SSujith { 317fb9987d0SSujith struct ath9k_htc_cap_target tcap; 318fb9987d0SSujith int ret; 319fb9987d0SSujith u8 cmd_rsp; 320fb9987d0SSujith 321fb9987d0SSujith memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target)); 322fb9987d0SSujith 323fb9987d0SSujith /* FIXME: Values are hardcoded */ 324fb9987d0SSujith tcap.flags = 0x240c40; 325fb9987d0SSujith tcap.flags_ext = 0x80601000; 326fb9987d0SSujith tcap.ampdu_limit = 0xffff0000; 327fb9987d0SSujith tcap.ampdu_subframes = 20; 328fb9987d0SSujith tcap.tx_chainmask_legacy = 1; 329fb9987d0SSujith tcap.protmode = 1; 330fb9987d0SSujith tcap.tx_chainmask = 1; 331fb9987d0SSujith 332fb9987d0SSujith WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); 333fb9987d0SSujith 334fb9987d0SSujith return ret; 335fb9987d0SSujith } 336fb9987d0SSujith 337fb9987d0SSujith static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv, 338fb9987d0SSujith struct ieee80211_vif *vif, 339fb9987d0SSujith struct ieee80211_sta *sta) 340fb9987d0SSujith { 341fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 342fb9987d0SSujith struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; 343fb9987d0SSujith struct ieee80211_supported_band *sband; 344fb9987d0SSujith struct ath9k_htc_target_rate trate; 345fb9987d0SSujith u32 caps = 0; 346fb9987d0SSujith u8 cmd_rsp; 347fb9987d0SSujith int i, j, ret; 348fb9987d0SSujith 349fb9987d0SSujith memset(&trate, 0, sizeof(trate)); 350fb9987d0SSujith 351fb9987d0SSujith /* Only 2GHz is supported */ 352fb9987d0SSujith sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; 353fb9987d0SSujith 354fb9987d0SSujith for (i = 0, j = 0; i < sband->n_bitrates; i++) { 355fb9987d0SSujith if (sta->supp_rates[sband->band] & BIT(i)) { 356fb9987d0SSujith priv->tgt_rate.rates.legacy_rates.rs_rates[j] 357fb9987d0SSujith = (sband->bitrates[i].bitrate * 2) / 10; 358fb9987d0SSujith j++; 359fb9987d0SSujith } 360fb9987d0SSujith } 361fb9987d0SSujith priv->tgt_rate.rates.legacy_rates.rs_nrates = j; 362fb9987d0SSujith 363fb9987d0SSujith if (sta->ht_cap.ht_supported) { 364fb9987d0SSujith for (i = 0, j = 0; i < 77; i++) { 365fb9987d0SSujith if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) 366fb9987d0SSujith priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i; 367fb9987d0SSujith if (j == ATH_HTC_RATE_MAX) 368fb9987d0SSujith break; 369fb9987d0SSujith } 370fb9987d0SSujith priv->tgt_rate.rates.ht_rates.rs_nrates = j; 371fb9987d0SSujith 372fb9987d0SSujith caps = WLAN_RC_HT_FLAG; 373fb9987d0SSujith if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) 374fb9987d0SSujith caps |= WLAN_RC_40_FLAG; 375fb9987d0SSujith if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) 376fb9987d0SSujith caps |= WLAN_RC_SGI_FLAG; 377fb9987d0SSujith 378fb9987d0SSujith } 379fb9987d0SSujith 380fb9987d0SSujith priv->tgt_rate.sta_index = ista->index; 381fb9987d0SSujith priv->tgt_rate.isnew = 1; 382fb9987d0SSujith trate = priv->tgt_rate; 3837f1f5a00SSujith priv->tgt_rate.capflags = cpu_to_be32(caps); 384fb9987d0SSujith trate.capflags = cpu_to_be32(caps); 385fb9987d0SSujith 386fb9987d0SSujith WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); 387fb9987d0SSujith if (ret) { 388fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 389fb9987d0SSujith "Unable to initialize Rate information on target\n"); 390fb9987d0SSujith return ret; 391fb9987d0SSujith } 392fb9987d0SSujith 393fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 394fb9987d0SSujith "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps); 395fb9987d0SSujith return 0; 396fb9987d0SSujith } 397fb9987d0SSujith 398fb9987d0SSujith static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40) 399fb9987d0SSujith { 400fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 401fb9987d0SSujith struct ieee80211_conf *conf = &hw->conf; 402fb9987d0SSujith 403fb9987d0SSujith if (!conf_is_ht(conf)) 404fb9987d0SSujith return false; 405fb9987d0SSujith 406fb9987d0SSujith if (!(priv->op_flags & OP_ASSOCIATED) || 407fb9987d0SSujith (priv->op_flags & OP_SCANNING)) 408fb9987d0SSujith return false; 409fb9987d0SSujith 410fb9987d0SSujith if (conf_is_ht40(conf)) { 411fb9987d0SSujith if (priv->ah->curchan->chanmode & 412fb9987d0SSujith (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) { 413fb9987d0SSujith return false; 414fb9987d0SSujith } else { 415fb9987d0SSujith *cw40 = true; 416fb9987d0SSujith return true; 417fb9987d0SSujith } 418fb9987d0SSujith } else { /* ht20 */ 419fb9987d0SSujith if (priv->ah->curchan->chanmode & CHANNEL_HT20) 420fb9987d0SSujith return false; 421fb9987d0SSujith else 422fb9987d0SSujith return true; 423fb9987d0SSujith } 424fb9987d0SSujith } 425fb9987d0SSujith 426fb9987d0SSujith static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40) 427fb9987d0SSujith { 428fb9987d0SSujith struct ath9k_htc_target_rate trate; 429fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 430fb9987d0SSujith int ret; 4317f1f5a00SSujith u32 caps = be32_to_cpu(priv->tgt_rate.capflags); 432fb9987d0SSujith u8 cmd_rsp; 433fb9987d0SSujith 434fb9987d0SSujith memset(&trate, 0, sizeof(trate)); 435fb9987d0SSujith 436fb9987d0SSujith trate = priv->tgt_rate; 437fb9987d0SSujith 438fb9987d0SSujith if (is_cw40) 4397f1f5a00SSujith caps |= WLAN_RC_40_FLAG; 440fb9987d0SSujith else 4417f1f5a00SSujith caps &= ~WLAN_RC_40_FLAG; 442fb9987d0SSujith 4437f1f5a00SSujith priv->tgt_rate.capflags = cpu_to_be32(caps); 4447f1f5a00SSujith trate.capflags = cpu_to_be32(caps); 445fb9987d0SSujith 446fb9987d0SSujith WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); 447fb9987d0SSujith if (ret) { 448fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 449fb9987d0SSujith "Unable to update Rate information on target\n"); 450fb9987d0SSujith return; 451fb9987d0SSujith } 452fb9987d0SSujith 453fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "Rate control updated with " 454fb9987d0SSujith "caps:0x%x on target\n", priv->tgt_rate.capflags); 455fb9987d0SSujith } 456fb9987d0SSujith 457fb9987d0SSujith static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv, 458fb9987d0SSujith struct ieee80211_vif *vif, 459fb9987d0SSujith u8 *sta_addr, u8 tid, bool oper) 460fb9987d0SSujith { 461fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 462fb9987d0SSujith struct ath9k_htc_target_aggr aggr; 463fb9987d0SSujith struct ieee80211_sta *sta = NULL; 464277a64d1SDan Carpenter struct ath9k_htc_sta *ista; 465fb9987d0SSujith int ret = 0; 466fb9987d0SSujith u8 cmd_rsp; 467fb9987d0SSujith 468*0730d114SDan Carpenter if (tid >= ATH9K_HTC_MAX_TID) 469fb9987d0SSujith return -EINVAL; 470fb9987d0SSujith 471fb9987d0SSujith memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr)); 472fb9987d0SSujith 473ef98c3cdSSujith rcu_read_lock(); 474ef98c3cdSSujith 475ef98c3cdSSujith /* Check if we are able to retrieve the station */ 476ef98c3cdSSujith sta = ieee80211_find_sta(vif, sta_addr); 477ef98c3cdSSujith if (!sta) { 478fb9987d0SSujith rcu_read_unlock(); 479ef98c3cdSSujith return -EINVAL; 480ef98c3cdSSujith } 481ef98c3cdSSujith 482ef98c3cdSSujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 483fb9987d0SSujith 484fb9987d0SSujith if (oper) 485fb9987d0SSujith ista->tid_state[tid] = AGGR_START; 486fb9987d0SSujith else 487fb9987d0SSujith ista->tid_state[tid] = AGGR_STOP; 488fb9987d0SSujith 489ef98c3cdSSujith aggr.sta_index = ista->index; 490ef98c3cdSSujith 491ef98c3cdSSujith rcu_read_unlock(); 492ef98c3cdSSujith 493ef98c3cdSSujith aggr.tidno = tid; 494ef98c3cdSSujith aggr.aggr_enable = oper; 495ef98c3cdSSujith 496fb9987d0SSujith WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr); 497fb9987d0SSujith if (ret) 498fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 499fb9987d0SSujith "Unable to %s TX aggregation for (%pM, %d)\n", 500fb9987d0SSujith (oper) ? "start" : "stop", sta->addr, tid); 501fb9987d0SSujith else 502fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 503fb9987d0SSujith "%s aggregation for (%pM, %d)\n", 504fb9987d0SSujith (oper) ? "Starting" : "Stopping", sta->addr, tid); 505fb9987d0SSujith 506fb9987d0SSujith return ret; 507fb9987d0SSujith } 508fb9987d0SSujith 509fb9987d0SSujith void ath9k_htc_aggr_work(struct work_struct *work) 510fb9987d0SSujith { 511fb9987d0SSujith int ret = 0; 512fb9987d0SSujith struct ath9k_htc_priv *priv = 513fb9987d0SSujith container_of(work, struct ath9k_htc_priv, 514fb9987d0SSujith ath9k_aggr_work.work); 515fb9987d0SSujith struct ath9k_htc_aggr_work *wk = &priv->aggr_work; 516fb9987d0SSujith 517fb9987d0SSujith mutex_lock(&wk->mutex); 518fb9987d0SSujith 519fb9987d0SSujith switch (wk->action) { 520fb9987d0SSujith case IEEE80211_AMPDU_TX_START: 521fb9987d0SSujith ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr, 522fb9987d0SSujith wk->tid, true); 523fb9987d0SSujith if (!ret) 524fb9987d0SSujith ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr, 525fb9987d0SSujith wk->tid); 526fb9987d0SSujith break; 527fb9987d0SSujith case IEEE80211_AMPDU_TX_STOP: 528fb9987d0SSujith ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr, 529fb9987d0SSujith wk->tid, false); 530fb9987d0SSujith ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid); 531fb9987d0SSujith break; 532fb9987d0SSujith default: 533fb9987d0SSujith ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, 534fb9987d0SSujith "Unknown AMPDU action\n"); 535fb9987d0SSujith } 536fb9987d0SSujith 537fb9987d0SSujith mutex_unlock(&wk->mutex); 538fb9987d0SSujith } 539fb9987d0SSujith 540fb9987d0SSujith /*********/ 541fb9987d0SSujith /* DEBUG */ 542fb9987d0SSujith /*********/ 543fb9987d0SSujith 544fb9987d0SSujith #ifdef CONFIG_ATH9K_HTC_DEBUGFS 545fb9987d0SSujith 546fb9987d0SSujith static int ath9k_debugfs_open(struct inode *inode, struct file *file) 547fb9987d0SSujith { 548fb9987d0SSujith file->private_data = inode->i_private; 549fb9987d0SSujith return 0; 550fb9987d0SSujith } 551fb9987d0SSujith 552fb9987d0SSujith static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, 553fb9987d0SSujith size_t count, loff_t *ppos) 554fb9987d0SSujith { 555fb9987d0SSujith struct ath9k_htc_priv *priv = 556fb9987d0SSujith (struct ath9k_htc_priv *) file->private_data; 557fb9987d0SSujith struct ath9k_htc_target_stats cmd_rsp; 558fb9987d0SSujith char buf[512]; 559fb9987d0SSujith unsigned int len = 0; 560fb9987d0SSujith int ret = 0; 561fb9987d0SSujith 562fb9987d0SSujith memset(&cmd_rsp, 0, sizeof(cmd_rsp)); 563fb9987d0SSujith 564fb9987d0SSujith WMI_CMD(WMI_TGT_STATS_CMDID); 565fb9987d0SSujith if (ret) 566fb9987d0SSujith return -EINVAL; 567fb9987d0SSujith 568fb9987d0SSujith 569fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 570fb9987d0SSujith "%19s : %10u\n", "TX Short Retries", 571fb9987d0SSujith be32_to_cpu(cmd_rsp.tx_shortretry)); 572fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 573fb9987d0SSujith "%19s : %10u\n", "TX Long Retries", 574fb9987d0SSujith be32_to_cpu(cmd_rsp.tx_longretry)); 575fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 576fb9987d0SSujith "%19s : %10u\n", "TX Xretries", 577fb9987d0SSujith be32_to_cpu(cmd_rsp.tx_xretries)); 578fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 579fb9987d0SSujith "%19s : %10u\n", "TX Unaggr. Xretries", 580fb9987d0SSujith be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); 581fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 582fb9987d0SSujith "%19s : %10u\n", "TX Xretries (HT)", 583fb9987d0SSujith be32_to_cpu(cmd_rsp.ht_tx_xretries)); 584fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 585fb9987d0SSujith "%19s : %10u\n", "TX Rate", priv->debug.txrate); 586fb9987d0SSujith 587fb9987d0SSujith return simple_read_from_buffer(user_buf, count, ppos, buf, len); 588fb9987d0SSujith } 589fb9987d0SSujith 590fb9987d0SSujith static const struct file_operations fops_tgt_stats = { 591fb9987d0SSujith .read = read_file_tgt_stats, 592fb9987d0SSujith .open = ath9k_debugfs_open, 593fb9987d0SSujith .owner = THIS_MODULE 594fb9987d0SSujith }; 595fb9987d0SSujith 596fb9987d0SSujith static ssize_t read_file_xmit(struct file *file, char __user *user_buf, 597fb9987d0SSujith size_t count, loff_t *ppos) 598fb9987d0SSujith { 599fb9987d0SSujith struct ath9k_htc_priv *priv = 600fb9987d0SSujith (struct ath9k_htc_priv *) file->private_data; 601fb9987d0SSujith char buf[512]; 602fb9987d0SSujith unsigned int len = 0; 603fb9987d0SSujith 604fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 605fb9987d0SSujith "%20s : %10u\n", "Buffers queued", 606fb9987d0SSujith priv->debug.tx_stats.buf_queued); 607fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 608fb9987d0SSujith "%20s : %10u\n", "Buffers completed", 609fb9987d0SSujith priv->debug.tx_stats.buf_completed); 610fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 611fb9987d0SSujith "%20s : %10u\n", "SKBs queued", 612fb9987d0SSujith priv->debug.tx_stats.skb_queued); 613fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 614fb9987d0SSujith "%20s : %10u\n", "SKBs completed", 615fb9987d0SSujith priv->debug.tx_stats.skb_completed); 616eac8e385SSujith len += snprintf(buf + len, sizeof(buf) - len, 617eac8e385SSujith "%20s : %10u\n", "SKBs dropped", 618eac8e385SSujith priv->debug.tx_stats.skb_dropped); 619fb9987d0SSujith 620fb9987d0SSujith return simple_read_from_buffer(user_buf, count, ppos, buf, len); 621fb9987d0SSujith } 622fb9987d0SSujith 623fb9987d0SSujith static const struct file_operations fops_xmit = { 624fb9987d0SSujith .read = read_file_xmit, 625fb9987d0SSujith .open = ath9k_debugfs_open, 626fb9987d0SSujith .owner = THIS_MODULE 627fb9987d0SSujith }; 628fb9987d0SSujith 629fb9987d0SSujith static ssize_t read_file_recv(struct file *file, char __user *user_buf, 630fb9987d0SSujith size_t count, loff_t *ppos) 631fb9987d0SSujith { 632fb9987d0SSujith struct ath9k_htc_priv *priv = 633fb9987d0SSujith (struct ath9k_htc_priv *) file->private_data; 634fb9987d0SSujith char buf[512]; 635fb9987d0SSujith unsigned int len = 0; 636fb9987d0SSujith 637fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 638fb9987d0SSujith "%20s : %10u\n", "SKBs allocated", 639fb9987d0SSujith priv->debug.rx_stats.skb_allocated); 640fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 641fb9987d0SSujith "%20s : %10u\n", "SKBs completed", 642fb9987d0SSujith priv->debug.rx_stats.skb_completed); 643fb9987d0SSujith len += snprintf(buf + len, sizeof(buf) - len, 644fb9987d0SSujith "%20s : %10u\n", "SKBs Dropped", 645fb9987d0SSujith priv->debug.rx_stats.skb_dropped); 646fb9987d0SSujith 647fb9987d0SSujith return simple_read_from_buffer(user_buf, count, ppos, buf, len); 648fb9987d0SSujith } 649fb9987d0SSujith 650fb9987d0SSujith static const struct file_operations fops_recv = { 651fb9987d0SSujith .read = read_file_recv, 652fb9987d0SSujith .open = ath9k_debugfs_open, 653fb9987d0SSujith .owner = THIS_MODULE 654fb9987d0SSujith }; 655fb9987d0SSujith 656e1572c5eSSujith int ath9k_htc_init_debug(struct ath_hw *ah) 657fb9987d0SSujith { 658fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 659fb9987d0SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 660fb9987d0SSujith 661fb9987d0SSujith if (!ath9k_debugfs_root) 662fb9987d0SSujith return -ENOENT; 663fb9987d0SSujith 664fb9987d0SSujith priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), 665fb9987d0SSujith ath9k_debugfs_root); 666fb9987d0SSujith if (!priv->debug.debugfs_phy) 667fb9987d0SSujith goto err; 668fb9987d0SSujith 669fb9987d0SSujith priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, 670fb9987d0SSujith priv->debug.debugfs_phy, 671fb9987d0SSujith priv, &fops_tgt_stats); 672fb9987d0SSujith if (!priv->debug.debugfs_tgt_stats) 673fb9987d0SSujith goto err; 674fb9987d0SSujith 675fb9987d0SSujith 676fb9987d0SSujith priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, 677fb9987d0SSujith priv->debug.debugfs_phy, 678fb9987d0SSujith priv, &fops_xmit); 679fb9987d0SSujith if (!priv->debug.debugfs_xmit) 680fb9987d0SSujith goto err; 681fb9987d0SSujith 682fb9987d0SSujith priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, 683fb9987d0SSujith priv->debug.debugfs_phy, 684fb9987d0SSujith priv, &fops_recv); 685fb9987d0SSujith if (!priv->debug.debugfs_recv) 686fb9987d0SSujith goto err; 687fb9987d0SSujith 688fb9987d0SSujith return 0; 689fb9987d0SSujith 690fb9987d0SSujith err: 691e1572c5eSSujith ath9k_htc_exit_debug(ah); 692fb9987d0SSujith return -ENOMEM; 693fb9987d0SSujith } 694fb9987d0SSujith 695e1572c5eSSujith void ath9k_htc_exit_debug(struct ath_hw *ah) 696fb9987d0SSujith { 697fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 698fb9987d0SSujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 699fb9987d0SSujith 700fb9987d0SSujith debugfs_remove(priv->debug.debugfs_recv); 701fb9987d0SSujith debugfs_remove(priv->debug.debugfs_xmit); 702fb9987d0SSujith debugfs_remove(priv->debug.debugfs_tgt_stats); 703fb9987d0SSujith debugfs_remove(priv->debug.debugfs_phy); 704fb9987d0SSujith } 705fb9987d0SSujith 706e1572c5eSSujith int ath9k_htc_debug_create_root(void) 707fb9987d0SSujith { 708fb9987d0SSujith ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 709fb9987d0SSujith if (!ath9k_debugfs_root) 710fb9987d0SSujith return -ENOENT; 711fb9987d0SSujith 712fb9987d0SSujith return 0; 713fb9987d0SSujith } 714fb9987d0SSujith 715e1572c5eSSujith void ath9k_htc_debug_remove_root(void) 716fb9987d0SSujith { 717fb9987d0SSujith debugfs_remove(ath9k_debugfs_root); 718fb9987d0SSujith ath9k_debugfs_root = NULL; 719fb9987d0SSujith } 720fb9987d0SSujith 721fb9987d0SSujith #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ 722fb9987d0SSujith 723fb9987d0SSujith /*******/ 724fb9987d0SSujith /* ANI */ 725fb9987d0SSujith /*******/ 726fb9987d0SSujith 727fb9987d0SSujith static void ath_start_ani(struct ath9k_htc_priv *priv) 728fb9987d0SSujith { 729fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 730fb9987d0SSujith unsigned long timestamp = jiffies_to_msecs(jiffies); 731fb9987d0SSujith 732fb9987d0SSujith common->ani.longcal_timer = timestamp; 733fb9987d0SSujith common->ani.shortcal_timer = timestamp; 734fb9987d0SSujith common->ani.checkani_timer = timestamp; 735fb9987d0SSujith 736fb9987d0SSujith ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, 737fb9987d0SSujith msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); 738fb9987d0SSujith } 739fb9987d0SSujith 740fb9987d0SSujith void ath9k_ani_work(struct work_struct *work) 741fb9987d0SSujith { 742fb9987d0SSujith struct ath9k_htc_priv *priv = 743fb9987d0SSujith container_of(work, struct ath9k_htc_priv, 744fb9987d0SSujith ath9k_ani_work.work); 745fb9987d0SSujith struct ath_hw *ah = priv->ah; 746fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 747fb9987d0SSujith bool longcal = false; 748fb9987d0SSujith bool shortcal = false; 749fb9987d0SSujith bool aniflag = false; 750fb9987d0SSujith unsigned int timestamp = jiffies_to_msecs(jiffies); 751fb9987d0SSujith u32 cal_interval, short_cal_interval; 752fb9987d0SSujith 753fb9987d0SSujith short_cal_interval = ATH_STA_SHORT_CALINTERVAL; 754fb9987d0SSujith 755bde748a4SVivek Natarajan /* Only calibrate if awake */ 756bde748a4SVivek Natarajan if (ah->power_mode != ATH9K_PM_AWAKE) 757bde748a4SVivek Natarajan goto set_timer; 758bde748a4SVivek Natarajan 759fb9987d0SSujith /* Long calibration runs independently of short calibration. */ 760fb9987d0SSujith if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { 761fb9987d0SSujith longcal = true; 762fb9987d0SSujith ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); 763fb9987d0SSujith common->ani.longcal_timer = timestamp; 764fb9987d0SSujith } 765fb9987d0SSujith 766fb9987d0SSujith /* Short calibration applies only while caldone is false */ 767fb9987d0SSujith if (!common->ani.caldone) { 768fb9987d0SSujith if ((timestamp - common->ani.shortcal_timer) >= 769fb9987d0SSujith short_cal_interval) { 770fb9987d0SSujith shortcal = true; 771fb9987d0SSujith ath_print(common, ATH_DBG_ANI, 772fb9987d0SSujith "shortcal @%lu\n", jiffies); 773fb9987d0SSujith common->ani.shortcal_timer = timestamp; 774fb9987d0SSujith common->ani.resetcal_timer = timestamp; 775fb9987d0SSujith } 776fb9987d0SSujith } else { 777fb9987d0SSujith if ((timestamp - common->ani.resetcal_timer) >= 778fb9987d0SSujith ATH_RESTART_CALINTERVAL) { 779fb9987d0SSujith common->ani.caldone = ath9k_hw_reset_calvalid(ah); 780fb9987d0SSujith if (common->ani.caldone) 781fb9987d0SSujith common->ani.resetcal_timer = timestamp; 782fb9987d0SSujith } 783fb9987d0SSujith } 784fb9987d0SSujith 785fb9987d0SSujith /* Verify whether we must check ANI */ 786fb9987d0SSujith if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { 787fb9987d0SSujith aniflag = true; 788fb9987d0SSujith common->ani.checkani_timer = timestamp; 789fb9987d0SSujith } 790fb9987d0SSujith 791fb9987d0SSujith /* Skip all processing if there's nothing to do. */ 792fb9987d0SSujith if (longcal || shortcal || aniflag) { 793bde748a4SVivek Natarajan 794bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 795bde748a4SVivek Natarajan 796fb9987d0SSujith /* Call ANI routine if necessary */ 797fb9987d0SSujith if (aniflag) 798fb9987d0SSujith ath9k_hw_ani_monitor(ah, ah->curchan); 799fb9987d0SSujith 800fb9987d0SSujith /* Perform calibration if necessary */ 801fb9987d0SSujith if (longcal || shortcal) { 802fb9987d0SSujith common->ani.caldone = 803fb9987d0SSujith ath9k_hw_calibrate(ah, ah->curchan, 804fb9987d0SSujith common->rx_chainmask, 805fb9987d0SSujith longcal); 806fb9987d0SSujith 807fb9987d0SSujith if (longcal) 808fb9987d0SSujith common->ani.noise_floor = 809fb9987d0SSujith ath9k_hw_getchan_noise(ah, ah->curchan); 810fb9987d0SSujith 811fb9987d0SSujith ath_print(common, ATH_DBG_ANI, 812fb9987d0SSujith " calibrate chan %u/%x nf: %d\n", 813fb9987d0SSujith ah->curchan->channel, 814fb9987d0SSujith ah->curchan->channelFlags, 815fb9987d0SSujith common->ani.noise_floor); 816fb9987d0SSujith } 817bde748a4SVivek Natarajan 818bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 819fb9987d0SSujith } 820fb9987d0SSujith 821bde748a4SVivek Natarajan set_timer: 822fb9987d0SSujith /* 823fb9987d0SSujith * Set timer interval based on previous results. 824fb9987d0SSujith * The interval must be the shortest necessary to satisfy ANI, 825fb9987d0SSujith * short calibration and long calibration. 826fb9987d0SSujith */ 827fb9987d0SSujith cal_interval = ATH_LONG_CALINTERVAL; 828fb9987d0SSujith if (priv->ah->config.enable_ani) 829fb9987d0SSujith cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); 830fb9987d0SSujith if (!common->ani.caldone) 831fb9987d0SSujith cal_interval = min(cal_interval, (u32)short_cal_interval); 832fb9987d0SSujith 833fb9987d0SSujith ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, 834fb9987d0SSujith msecs_to_jiffies(cal_interval)); 835fb9987d0SSujith } 836fb9987d0SSujith 837fb9987d0SSujith /*******/ 838fb9987d0SSujith /* LED */ 839fb9987d0SSujith /*******/ 840fb9987d0SSujith 841fb9987d0SSujith static void ath9k_led_blink_work(struct work_struct *work) 842fb9987d0SSujith { 843fb9987d0SSujith struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, 844fb9987d0SSujith ath9k_led_blink_work.work); 845fb9987d0SSujith 846fb9987d0SSujith if (!(priv->op_flags & OP_LED_ASSOCIATED)) 847fb9987d0SSujith return; 848fb9987d0SSujith 849fb9987d0SSujith if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || 850fb9987d0SSujith (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) 851fb9987d0SSujith ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); 852fb9987d0SSujith else 853fb9987d0SSujith ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 854fb9987d0SSujith (priv->op_flags & OP_LED_ON) ? 1 : 0); 855fb9987d0SSujith 856fb9987d0SSujith ieee80211_queue_delayed_work(priv->hw, 857fb9987d0SSujith &priv->ath9k_led_blink_work, 858fb9987d0SSujith (priv->op_flags & OP_LED_ON) ? 859fb9987d0SSujith msecs_to_jiffies(priv->led_off_duration) : 860fb9987d0SSujith msecs_to_jiffies(priv->led_on_duration)); 861fb9987d0SSujith 862fb9987d0SSujith priv->led_on_duration = priv->led_on_cnt ? 863fb9987d0SSujith max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : 864fb9987d0SSujith ATH_LED_ON_DURATION_IDLE; 865fb9987d0SSujith priv->led_off_duration = priv->led_off_cnt ? 866fb9987d0SSujith max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : 867fb9987d0SSujith ATH_LED_OFF_DURATION_IDLE; 868fb9987d0SSujith priv->led_on_cnt = priv->led_off_cnt = 0; 869fb9987d0SSujith 870fb9987d0SSujith if (priv->op_flags & OP_LED_ON) 871fb9987d0SSujith priv->op_flags &= ~OP_LED_ON; 872fb9987d0SSujith else 873fb9987d0SSujith priv->op_flags |= OP_LED_ON; 874fb9987d0SSujith } 875fb9987d0SSujith 876fb9987d0SSujith static void ath9k_led_brightness_work(struct work_struct *work) 877fb9987d0SSujith { 878fb9987d0SSujith struct ath_led *led = container_of(work, struct ath_led, 879fb9987d0SSujith brightness_work.work); 880fb9987d0SSujith struct ath9k_htc_priv *priv = led->priv; 881fb9987d0SSujith 882fb9987d0SSujith switch (led->brightness) { 883fb9987d0SSujith case LED_OFF: 884fb9987d0SSujith if (led->led_type == ATH_LED_ASSOC || 885fb9987d0SSujith led->led_type == ATH_LED_RADIO) { 886fb9987d0SSujith ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 887fb9987d0SSujith (led->led_type == ATH_LED_RADIO)); 888fb9987d0SSujith priv->op_flags &= ~OP_LED_ASSOCIATED; 889fb9987d0SSujith if (led->led_type == ATH_LED_RADIO) 890fb9987d0SSujith priv->op_flags &= ~OP_LED_ON; 891fb9987d0SSujith } else { 892fb9987d0SSujith priv->led_off_cnt++; 893fb9987d0SSujith } 894fb9987d0SSujith break; 895fb9987d0SSujith case LED_FULL: 896fb9987d0SSujith if (led->led_type == ATH_LED_ASSOC) { 897fb9987d0SSujith priv->op_flags |= OP_LED_ASSOCIATED; 898fb9987d0SSujith ieee80211_queue_delayed_work(priv->hw, 899fb9987d0SSujith &priv->ath9k_led_blink_work, 0); 900fb9987d0SSujith } else if (led->led_type == ATH_LED_RADIO) { 901fb9987d0SSujith ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); 902fb9987d0SSujith priv->op_flags |= OP_LED_ON; 903fb9987d0SSujith } else { 904fb9987d0SSujith priv->led_on_cnt++; 905fb9987d0SSujith } 906fb9987d0SSujith break; 907fb9987d0SSujith default: 908fb9987d0SSujith break; 909fb9987d0SSujith } 910fb9987d0SSujith } 911fb9987d0SSujith 912fb9987d0SSujith static void ath9k_led_brightness(struct led_classdev *led_cdev, 913fb9987d0SSujith enum led_brightness brightness) 914fb9987d0SSujith { 915fb9987d0SSujith struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); 916fb9987d0SSujith struct ath9k_htc_priv *priv = led->priv; 917fb9987d0SSujith 918fb9987d0SSujith led->brightness = brightness; 919fb9987d0SSujith if (!(priv->op_flags & OP_LED_DEINIT)) 920fb9987d0SSujith ieee80211_queue_delayed_work(priv->hw, 921fb9987d0SSujith &led->brightness_work, 0); 922fb9987d0SSujith } 923fb9987d0SSujith 924fb9987d0SSujith static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) 925fb9987d0SSujith { 926fb9987d0SSujith cancel_delayed_work_sync(&priv->radio_led.brightness_work); 927fb9987d0SSujith cancel_delayed_work_sync(&priv->assoc_led.brightness_work); 928fb9987d0SSujith cancel_delayed_work_sync(&priv->tx_led.brightness_work); 929fb9987d0SSujith cancel_delayed_work_sync(&priv->rx_led.brightness_work); 930fb9987d0SSujith } 931fb9987d0SSujith 932fb9987d0SSujith static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, 933fb9987d0SSujith char *trigger) 934fb9987d0SSujith { 935fb9987d0SSujith int ret; 936fb9987d0SSujith 937fb9987d0SSujith led->priv = priv; 938fb9987d0SSujith led->led_cdev.name = led->name; 939fb9987d0SSujith led->led_cdev.default_trigger = trigger; 940fb9987d0SSujith led->led_cdev.brightness_set = ath9k_led_brightness; 941fb9987d0SSujith 942fb9987d0SSujith ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); 943fb9987d0SSujith if (ret) 944fb9987d0SSujith ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, 945fb9987d0SSujith "Failed to register led:%s", led->name); 946fb9987d0SSujith else 947fb9987d0SSujith led->registered = 1; 948fb9987d0SSujith 949fb9987d0SSujith INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); 950fb9987d0SSujith 951fb9987d0SSujith return ret; 952fb9987d0SSujith } 953fb9987d0SSujith 954fb9987d0SSujith static void ath9k_unregister_led(struct ath_led *led) 955fb9987d0SSujith { 956fb9987d0SSujith if (led->registered) { 957fb9987d0SSujith led_classdev_unregister(&led->led_cdev); 958fb9987d0SSujith led->registered = 0; 959fb9987d0SSujith } 960fb9987d0SSujith } 961fb9987d0SSujith 962fb9987d0SSujith void ath9k_deinit_leds(struct ath9k_htc_priv *priv) 963fb9987d0SSujith { 964fb9987d0SSujith priv->op_flags |= OP_LED_DEINIT; 965fb9987d0SSujith ath9k_unregister_led(&priv->assoc_led); 966fb9987d0SSujith priv->op_flags &= ~OP_LED_ASSOCIATED; 967fb9987d0SSujith ath9k_unregister_led(&priv->tx_led); 968fb9987d0SSujith ath9k_unregister_led(&priv->rx_led); 969fb9987d0SSujith ath9k_unregister_led(&priv->radio_led); 970fb9987d0SSujith } 971fb9987d0SSujith 972fb9987d0SSujith void ath9k_init_leds(struct ath9k_htc_priv *priv) 973fb9987d0SSujith { 974fb9987d0SSujith char *trigger; 975fb9987d0SSujith int ret; 976fb9987d0SSujith 977fb9987d0SSujith if (AR_SREV_9287(priv->ah)) 978fb9987d0SSujith priv->ah->led_pin = ATH_LED_PIN_9287; 979fb9987d0SSujith else if (AR_SREV_9271(priv->ah)) 980fb9987d0SSujith priv->ah->led_pin = ATH_LED_PIN_9271; 981fb9987d0SSujith else 982fb9987d0SSujith priv->ah->led_pin = ATH_LED_PIN_DEF; 983fb9987d0SSujith 984fb9987d0SSujith /* Configure gpio 1 for output */ 985fb9987d0SSujith ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, 986fb9987d0SSujith AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 987fb9987d0SSujith /* LED off, active low */ 988fb9987d0SSujith ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); 989fb9987d0SSujith 990fb9987d0SSujith INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); 991fb9987d0SSujith 992fb9987d0SSujith trigger = ieee80211_get_radio_led_name(priv->hw); 993fb9987d0SSujith snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), 994fb9987d0SSujith "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); 995fb9987d0SSujith ret = ath9k_register_led(priv, &priv->radio_led, trigger); 996fb9987d0SSujith priv->radio_led.led_type = ATH_LED_RADIO; 997fb9987d0SSujith if (ret) 998fb9987d0SSujith goto fail; 999fb9987d0SSujith 1000fb9987d0SSujith trigger = ieee80211_get_assoc_led_name(priv->hw); 1001fb9987d0SSujith snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), 1002fb9987d0SSujith "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); 1003fb9987d0SSujith ret = ath9k_register_led(priv, &priv->assoc_led, trigger); 1004fb9987d0SSujith priv->assoc_led.led_type = ATH_LED_ASSOC; 1005fb9987d0SSujith if (ret) 1006fb9987d0SSujith goto fail; 1007fb9987d0SSujith 1008fb9987d0SSujith trigger = ieee80211_get_tx_led_name(priv->hw); 1009fb9987d0SSujith snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), 1010fb9987d0SSujith "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); 1011fb9987d0SSujith ret = ath9k_register_led(priv, &priv->tx_led, trigger); 1012fb9987d0SSujith priv->tx_led.led_type = ATH_LED_TX; 1013fb9987d0SSujith if (ret) 1014fb9987d0SSujith goto fail; 1015fb9987d0SSujith 1016fb9987d0SSujith trigger = ieee80211_get_rx_led_name(priv->hw); 1017fb9987d0SSujith snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), 1018fb9987d0SSujith "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); 1019fb9987d0SSujith ret = ath9k_register_led(priv, &priv->rx_led, trigger); 1020fb9987d0SSujith priv->rx_led.led_type = ATH_LED_RX; 1021fb9987d0SSujith if (ret) 1022fb9987d0SSujith goto fail; 1023fb9987d0SSujith 1024fb9987d0SSujith priv->op_flags &= ~OP_LED_DEINIT; 1025fb9987d0SSujith 1026fb9987d0SSujith return; 1027fb9987d0SSujith 1028fb9987d0SSujith fail: 1029fb9987d0SSujith cancel_delayed_work_sync(&priv->ath9k_led_blink_work); 1030fb9987d0SSujith ath9k_deinit_leds(priv); 1031fb9987d0SSujith } 1032fb9987d0SSujith 1033fb9987d0SSujith /*******************/ 1034fb9987d0SSujith /* Rfkill */ 1035fb9987d0SSujith /*******************/ 1036fb9987d0SSujith 1037fb9987d0SSujith static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) 1038fb9987d0SSujith { 1039fb9987d0SSujith return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == 1040fb9987d0SSujith priv->ah->rfkill_polarity; 1041fb9987d0SSujith } 1042fb9987d0SSujith 1043fb9987d0SSujith static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) 1044fb9987d0SSujith { 1045fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1046fb9987d0SSujith bool blocked = !!ath_is_rfkill_set(priv); 1047fb9987d0SSujith 1048fb9987d0SSujith wiphy_rfkill_set_hw_state(hw->wiphy, blocked); 1049fb9987d0SSujith } 1050fb9987d0SSujith 1051fb9987d0SSujith void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) 1052fb9987d0SSujith { 1053fb9987d0SSujith if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) 1054fb9987d0SSujith wiphy_rfkill_start_polling(priv->hw->wiphy); 1055fb9987d0SSujith } 1056fb9987d0SSujith 1057fb9987d0SSujith /**********************/ 1058fb9987d0SSujith /* mac80211 Callbacks */ 1059fb9987d0SSujith /**********************/ 1060fb9987d0SSujith 1061fb9987d0SSujith static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) 1062fb9987d0SSujith { 1063fb9987d0SSujith struct ieee80211_hdr *hdr; 1064fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 10657757dfedSSujith int padpos, padsize, ret; 1066fb9987d0SSujith 1067fb9987d0SSujith hdr = (struct ieee80211_hdr *) skb->data; 1068fb9987d0SSujith 1069fb9987d0SSujith /* Add the padding after the header if this is not already done */ 1070fb9987d0SSujith padpos = ath9k_cmn_padpos(hdr->frame_control); 1071fb9987d0SSujith padsize = padpos & 3; 1072fb9987d0SSujith if (padsize && skb->len > padpos) { 1073fb9987d0SSujith if (skb_headroom(skb) < padsize) 1074fb9987d0SSujith return -1; 1075fb9987d0SSujith skb_push(skb, padsize); 1076fb9987d0SSujith memmove(skb->data, skb->data + padsize, padpos); 1077fb9987d0SSujith } 1078fb9987d0SSujith 10797757dfedSSujith ret = ath9k_htc_tx_start(priv, skb); 10807757dfedSSujith if (ret != 0) { 10817757dfedSSujith if (ret == -ENOMEM) { 10827757dfedSSujith ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, 10837757dfedSSujith "Stopping TX queues\n"); 10847757dfedSSujith ieee80211_stop_queues(hw); 10857757dfedSSujith spin_lock_bh(&priv->tx_lock); 10867757dfedSSujith priv->tx_queues_stop = true; 10877757dfedSSujith spin_unlock_bh(&priv->tx_lock); 10887757dfedSSujith } else { 10897757dfedSSujith ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, 10907757dfedSSujith "Tx failed"); 10917757dfedSSujith } 1092fb9987d0SSujith goto fail_tx; 1093fb9987d0SSujith } 1094fb9987d0SSujith 1095fb9987d0SSujith return 0; 1096fb9987d0SSujith 1097fb9987d0SSujith fail_tx: 1098fb9987d0SSujith dev_kfree_skb_any(skb); 1099fb9987d0SSujith return 0; 1100fb9987d0SSujith } 1101fb9987d0SSujith 11022ff6575bSSujith static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) 1103fb9987d0SSujith { 1104fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1105fb9987d0SSujith struct ath_hw *ah = priv->ah; 1106fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 1107fb9987d0SSujith struct ieee80211_channel *curchan = hw->conf.channel; 1108fb9987d0SSujith struct ath9k_channel *init_channel; 1109fb9987d0SSujith int ret = 0; 1110fb9987d0SSujith enum htc_phymode mode; 11117f1f5a00SSujith __be16 htc_mode; 1112fb9987d0SSujith u8 cmd_rsp; 1113fb9987d0SSujith 1114fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 1115fb9987d0SSujith "Starting driver with initial channel: %d MHz\n", 1116fb9987d0SSujith curchan->center_freq); 1117fb9987d0SSujith 1118fb9987d0SSujith /* setup initial channel */ 1119fb9987d0SSujith init_channel = ath9k_cmn_get_curchannel(hw, ah); 1120fb9987d0SSujith 1121fb9987d0SSujith /* Reset SERDES registers */ 1122fb9987d0SSujith ath9k_hw_configpcipowersave(ah, 0, 0); 1123fb9987d0SSujith 1124fb9987d0SSujith ath9k_hw_htc_resetinit(ah); 1125fb9987d0SSujith ret = ath9k_hw_reset(ah, init_channel, false); 1126fb9987d0SSujith if (ret) { 1127fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 1128fb9987d0SSujith "Unable to reset hardware; reset status %d " 1129fb9987d0SSujith "(freq %u MHz)\n", ret, curchan->center_freq); 11308a8572a8SVivek Natarajan return ret; 1131fb9987d0SSujith } 1132fb9987d0SSujith 1133fb9987d0SSujith ath_update_txpow(priv); 1134fb9987d0SSujith 1135fb9987d0SSujith mode = ath9k_htc_get_curmode(priv, init_channel); 1136fb9987d0SSujith htc_mode = cpu_to_be16(mode); 1137fb9987d0SSujith WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); 1138fb9987d0SSujith WMI_CMD(WMI_ATH_INIT_CMDID); 1139fb9987d0SSujith WMI_CMD(WMI_START_RECV_CMDID); 1140fb9987d0SSujith 1141fb9987d0SSujith ath9k_host_rx_init(priv); 1142fb9987d0SSujith 1143fb9987d0SSujith priv->op_flags &= ~OP_INVALID; 1144fb9987d0SSujith htc_start(priv->htc); 1145fb9987d0SSujith 11467757dfedSSujith spin_lock_bh(&priv->tx_lock); 11477757dfedSSujith priv->tx_queues_stop = false; 11487757dfedSSujith spin_unlock_bh(&priv->tx_lock); 11497757dfedSSujith 11502ff6575bSSujith if (led) { 11512ff6575bSSujith /* Enable LED */ 11522ff6575bSSujith ath9k_hw_cfg_output(ah, ah->led_pin, 11532ff6575bSSujith AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 11542ff6575bSSujith ath9k_hw_set_gpio(ah, ah->led_pin, 0); 11552ff6575bSSujith } 11562ff6575bSSujith 11577757dfedSSujith ieee80211_wake_queues(hw); 11587757dfedSSujith 1159fb9987d0SSujith return ret; 1160fb9987d0SSujith } 1161fb9987d0SSujith 11628a8572a8SVivek Natarajan static int ath9k_htc_start(struct ieee80211_hw *hw) 11638a8572a8SVivek Natarajan { 11648a8572a8SVivek Natarajan struct ath9k_htc_priv *priv = hw->priv; 11658a8572a8SVivek Natarajan int ret = 0; 11668a8572a8SVivek Natarajan 11678a8572a8SVivek Natarajan mutex_lock(&priv->mutex); 11682ff6575bSSujith ret = ath9k_htc_radio_enable(hw, false); 11698a8572a8SVivek Natarajan mutex_unlock(&priv->mutex); 11708a8572a8SVivek Natarajan 11718a8572a8SVivek Natarajan return ret; 11728a8572a8SVivek Natarajan } 11738a8572a8SVivek Natarajan 11742ff6575bSSujith static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) 1175fb9987d0SSujith { 1176fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1177fb9987d0SSujith struct ath_hw *ah = priv->ah; 1178fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 1179fb9987d0SSujith int ret = 0; 1180fb9987d0SSujith u8 cmd_rsp; 1181fb9987d0SSujith 1182fb9987d0SSujith if (priv->op_flags & OP_INVALID) { 1183fb9987d0SSujith ath_print(common, ATH_DBG_ANY, "Device not present\n"); 1184fb9987d0SSujith return; 1185fb9987d0SSujith } 1186fb9987d0SSujith 11872ff6575bSSujith if (led) { 11882ff6575bSSujith /* Disable LED */ 11892ff6575bSSujith ath9k_hw_set_gpio(ah, ah->led_pin, 1); 11902ff6575bSSujith ath9k_hw_cfg_gpio_input(ah, ah->led_pin); 11912ff6575bSSujith } 11922ff6575bSSujith 11937073daa6SSujith /* Cancel all the running timers/work .. */ 11947073daa6SSujith cancel_work_sync(&priv->ps_work); 11957073daa6SSujith cancel_delayed_work_sync(&priv->ath9k_ani_work); 11967073daa6SSujith cancel_delayed_work_sync(&priv->ath9k_aggr_work); 11977073daa6SSujith cancel_delayed_work_sync(&priv->ath9k_led_blink_work); 11987073daa6SSujith ath9k_led_stop_brightness(priv); 11997073daa6SSujith 1200bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 1201fb9987d0SSujith htc_stop(priv->htc); 1202fb9987d0SSujith WMI_CMD(WMI_DISABLE_INTR_CMDID); 1203fb9987d0SSujith WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); 1204fb9987d0SSujith WMI_CMD(WMI_STOP_RECV_CMDID); 1205fb9987d0SSujith ath9k_hw_phy_disable(ah); 1206fb9987d0SSujith ath9k_hw_disable(ah); 1207fb9987d0SSujith ath9k_hw_configpcipowersave(ah, 1, 1); 1208bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 1209bde748a4SVivek Natarajan ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); 1210fb9987d0SSujith 1211fb9987d0SSujith skb_queue_purge(&priv->tx_queue); 1212fb9987d0SSujith 1213fb9987d0SSujith /* Remove monitor interface here */ 1214fb9987d0SSujith if (ah->opmode == NL80211_IFTYPE_MONITOR) { 1215fb9987d0SSujith if (ath9k_htc_remove_monitor_interface(priv)) 1216fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 1217fb9987d0SSujith "Unable to remove monitor interface\n"); 1218fb9987d0SSujith else 1219fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 1220fb9987d0SSujith "Monitor interface removed\n"); 1221fb9987d0SSujith } 1222fb9987d0SSujith 1223fb9987d0SSujith priv->op_flags |= OP_INVALID; 1224fb9987d0SSujith 1225fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); 1226fb9987d0SSujith } 1227fb9987d0SSujith 12288a8572a8SVivek Natarajan static void ath9k_htc_stop(struct ieee80211_hw *hw) 12298a8572a8SVivek Natarajan { 12308a8572a8SVivek Natarajan struct ath9k_htc_priv *priv = hw->priv; 12318a8572a8SVivek Natarajan 12328a8572a8SVivek Natarajan mutex_lock(&priv->mutex); 12332ff6575bSSujith ath9k_htc_radio_disable(hw, false); 12348a8572a8SVivek Natarajan mutex_unlock(&priv->mutex); 12358a8572a8SVivek Natarajan } 12368a8572a8SVivek Natarajan 12378a8572a8SVivek Natarajan 1238fb9987d0SSujith static int ath9k_htc_add_interface(struct ieee80211_hw *hw, 1239fb9987d0SSujith struct ieee80211_vif *vif) 1240fb9987d0SSujith { 1241fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1242fb9987d0SSujith struct ath9k_htc_vif *avp = (void *)vif->drv_priv; 1243fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 1244fb9987d0SSujith struct ath9k_htc_target_vif hvif; 1245fb9987d0SSujith int ret = 0; 1246fb9987d0SSujith u8 cmd_rsp; 1247fb9987d0SSujith 1248fb9987d0SSujith mutex_lock(&priv->mutex); 1249fb9987d0SSujith 1250fb9987d0SSujith /* Only one interface for now */ 1251fb9987d0SSujith if (priv->nvifs > 0) { 1252fb9987d0SSujith ret = -ENOBUFS; 1253fb9987d0SSujith goto out; 1254fb9987d0SSujith } 1255fb9987d0SSujith 1256bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 1257fb9987d0SSujith memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); 1258fb9987d0SSujith memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); 1259fb9987d0SSujith 1260fb9987d0SSujith switch (vif->type) { 1261fb9987d0SSujith case NL80211_IFTYPE_STATION: 1262fb9987d0SSujith hvif.opmode = cpu_to_be32(HTC_M_STA); 1263fb9987d0SSujith break; 1264fb9987d0SSujith case NL80211_IFTYPE_ADHOC: 1265fb9987d0SSujith hvif.opmode = cpu_to_be32(HTC_M_IBSS); 1266fb9987d0SSujith break; 1267fb9987d0SSujith default: 1268fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 1269fb9987d0SSujith "Interface type %d not yet supported\n", vif->type); 1270fb9987d0SSujith ret = -EOPNOTSUPP; 1271fb9987d0SSujith goto out; 1272fb9987d0SSujith } 1273fb9987d0SSujith 1274fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 1275fb9987d0SSujith "Attach a VIF of type: %d\n", vif->type); 1276fb9987d0SSujith 1277fb9987d0SSujith priv->ah->opmode = vif->type; 1278fb9987d0SSujith 1279fb9987d0SSujith /* Index starts from zero on the target */ 1280fb9987d0SSujith avp->index = hvif.index = priv->nvifs; 1281fb9987d0SSujith hvif.rtsthreshold = cpu_to_be16(2304); 1282fb9987d0SSujith WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); 1283fb9987d0SSujith if (ret) 1284fb9987d0SSujith goto out; 1285fb9987d0SSujith 1286fb9987d0SSujith priv->nvifs++; 1287fb9987d0SSujith 1288fb9987d0SSujith /* 1289fb9987d0SSujith * We need a node in target to tx mgmt frames 1290fb9987d0SSujith * before association. 1291fb9987d0SSujith */ 1292fb9987d0SSujith ret = ath9k_htc_add_station(priv, vif, NULL); 1293fb9987d0SSujith if (ret) 1294fb9987d0SSujith goto out; 1295fb9987d0SSujith 1296fb9987d0SSujith ret = ath9k_htc_update_cap_target(priv); 1297fb9987d0SSujith if (ret) 1298fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "Failed to update" 1299fb9987d0SSujith " capability in target \n"); 1300fb9987d0SSujith 1301fb9987d0SSujith priv->vif = vif; 1302fb9987d0SSujith out: 1303bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 1304fb9987d0SSujith mutex_unlock(&priv->mutex); 1305fb9987d0SSujith return ret; 1306fb9987d0SSujith } 1307fb9987d0SSujith 1308fb9987d0SSujith static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, 1309fb9987d0SSujith struct ieee80211_vif *vif) 1310fb9987d0SSujith { 1311fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1312fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 1313fb9987d0SSujith struct ath9k_htc_vif *avp = (void *)vif->drv_priv; 1314fb9987d0SSujith struct ath9k_htc_target_vif hvif; 1315fb9987d0SSujith int ret = 0; 1316fb9987d0SSujith u8 cmd_rsp; 1317fb9987d0SSujith 1318fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); 1319fb9987d0SSujith 1320fb9987d0SSujith mutex_lock(&priv->mutex); 1321fb9987d0SSujith 1322fb9987d0SSujith memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); 1323fb9987d0SSujith memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); 1324fb9987d0SSujith hvif.index = avp->index; 1325fb9987d0SSujith WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); 1326fb9987d0SSujith priv->nvifs--; 1327fb9987d0SSujith 1328fb9987d0SSujith ath9k_htc_remove_station(priv, vif, NULL); 1329fb9987d0SSujith priv->vif = NULL; 1330fb9987d0SSujith 1331fb9987d0SSujith mutex_unlock(&priv->mutex); 1332fb9987d0SSujith } 1333fb9987d0SSujith 1334fb9987d0SSujith static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) 1335fb9987d0SSujith { 1336fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1337fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 1338fb9987d0SSujith struct ieee80211_conf *conf = &hw->conf; 1339fb9987d0SSujith 1340fb9987d0SSujith mutex_lock(&priv->mutex); 1341fb9987d0SSujith 13428a8572a8SVivek Natarajan if (changed & IEEE80211_CONF_CHANGE_IDLE) { 13438a8572a8SVivek Natarajan bool enable_radio = false; 13448a8572a8SVivek Natarajan bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); 13458a8572a8SVivek Natarajan 13468a8572a8SVivek Natarajan if (!idle && priv->ps_idle) 13478a8572a8SVivek Natarajan enable_radio = true; 13488a8572a8SVivek Natarajan 13498a8572a8SVivek Natarajan priv->ps_idle = idle; 13508a8572a8SVivek Natarajan 13518a8572a8SVivek Natarajan if (enable_radio) { 13528a8572a8SVivek Natarajan ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); 13532ff6575bSSujith ath9k_htc_radio_enable(hw, true); 13548a8572a8SVivek Natarajan ath_print(common, ATH_DBG_CONFIG, 13558a8572a8SVivek Natarajan "not-idle: enabling radio\n"); 13568a8572a8SVivek Natarajan } 13578a8572a8SVivek Natarajan } 13588a8572a8SVivek Natarajan 1359fb9987d0SSujith if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 1360fb9987d0SSujith struct ieee80211_channel *curchan = hw->conf.channel; 1361fb9987d0SSujith int pos = curchan->hw_value; 1362fb9987d0SSujith bool is_cw40 = false; 1363fb9987d0SSujith 1364fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", 1365fb9987d0SSujith curchan->center_freq); 1366fb9987d0SSujith 1367fb9987d0SSujith if (check_rc_update(hw, &is_cw40)) 1368fb9987d0SSujith ath9k_htc_rc_update(priv, is_cw40); 1369fb9987d0SSujith 1370fb9987d0SSujith ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]); 1371fb9987d0SSujith 1372fb9987d0SSujith if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { 1373fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 1374fb9987d0SSujith "Unable to set channel\n"); 1375fb9987d0SSujith mutex_unlock(&priv->mutex); 1376fb9987d0SSujith return -EINVAL; 1377fb9987d0SSujith } 1378fb9987d0SSujith 1379fb9987d0SSujith } 1380bde748a4SVivek Natarajan if (changed & IEEE80211_CONF_CHANGE_PS) { 1381bde748a4SVivek Natarajan if (conf->flags & IEEE80211_CONF_PS) { 1382bde748a4SVivek Natarajan ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); 1383bde748a4SVivek Natarajan priv->ps_enabled = true; 1384bde748a4SVivek Natarajan } else { 1385bde748a4SVivek Natarajan priv->ps_enabled = false; 1386bde748a4SVivek Natarajan cancel_work_sync(&priv->ps_work); 1387bde748a4SVivek Natarajan ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); 1388bde748a4SVivek Natarajan } 1389bde748a4SVivek Natarajan } 1390fb9987d0SSujith 1391fb9987d0SSujith if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 1392fb9987d0SSujith if (conf->flags & IEEE80211_CONF_MONITOR) { 1393fb9987d0SSujith if (ath9k_htc_add_monitor_interface(priv)) 1394fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, 1395fb9987d0SSujith "Failed to set monitor mode\n"); 1396fb9987d0SSujith else 1397fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 1398fb9987d0SSujith "HW opmode set to Monitor mode\n"); 1399fb9987d0SSujith } 1400fb9987d0SSujith } 1401fb9987d0SSujith 14028a8572a8SVivek Natarajan if (priv->ps_idle) { 14038a8572a8SVivek Natarajan ath_print(common, ATH_DBG_CONFIG, 14048a8572a8SVivek Natarajan "idle: disabling radio\n"); 14052ff6575bSSujith ath9k_htc_radio_disable(hw, true); 14068a8572a8SVivek Natarajan } 14078a8572a8SVivek Natarajan 1408fb9987d0SSujith mutex_unlock(&priv->mutex); 1409fb9987d0SSujith 1410fb9987d0SSujith return 0; 1411fb9987d0SSujith } 1412fb9987d0SSujith 1413fb9987d0SSujith #define SUPPORTED_FILTERS \ 1414fb9987d0SSujith (FIF_PROMISC_IN_BSS | \ 1415fb9987d0SSujith FIF_ALLMULTI | \ 1416fb9987d0SSujith FIF_CONTROL | \ 1417fb9987d0SSujith FIF_PSPOLL | \ 1418fb9987d0SSujith FIF_OTHER_BSS | \ 1419fb9987d0SSujith FIF_BCN_PRBRESP_PROMISC | \ 1420fb9987d0SSujith FIF_FCSFAIL) 1421fb9987d0SSujith 1422fb9987d0SSujith static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, 1423fb9987d0SSujith unsigned int changed_flags, 1424fb9987d0SSujith unsigned int *total_flags, 1425fb9987d0SSujith u64 multicast) 1426fb9987d0SSujith { 1427fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1428fb9987d0SSujith u32 rfilt; 1429fb9987d0SSujith 1430fb9987d0SSujith mutex_lock(&priv->mutex); 1431fb9987d0SSujith 1432bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 1433fb9987d0SSujith changed_flags &= SUPPORTED_FILTERS; 1434fb9987d0SSujith *total_flags &= SUPPORTED_FILTERS; 1435fb9987d0SSujith 1436fb9987d0SSujith priv->rxfilter = *total_flags; 14370995d110SSujith rfilt = ath9k_htc_calcrxfilter(priv); 1438fb9987d0SSujith ath9k_hw_setrxfilter(priv->ah, rfilt); 1439fb9987d0SSujith 1440fb9987d0SSujith ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG, 1441fb9987d0SSujith "Set HW RX filter: 0x%x\n", rfilt); 1442fb9987d0SSujith 1443bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 1444fb9987d0SSujith mutex_unlock(&priv->mutex); 1445fb9987d0SSujith } 1446fb9987d0SSujith 1447fb9987d0SSujith static void ath9k_htc_sta_notify(struct ieee80211_hw *hw, 1448fb9987d0SSujith struct ieee80211_vif *vif, 1449fb9987d0SSujith enum sta_notify_cmd cmd, 1450fb9987d0SSujith struct ieee80211_sta *sta) 1451fb9987d0SSujith { 1452fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1453fb9987d0SSujith int ret; 1454fb9987d0SSujith 1455fb9987d0SSujith switch (cmd) { 1456fb9987d0SSujith case STA_NOTIFY_ADD: 1457fb9987d0SSujith ret = ath9k_htc_add_station(priv, vif, sta); 1458fb9987d0SSujith if (!ret) 1459fb9987d0SSujith ath9k_htc_init_rate(priv, vif, sta); 1460fb9987d0SSujith break; 1461fb9987d0SSujith case STA_NOTIFY_REMOVE: 1462fb9987d0SSujith ath9k_htc_remove_station(priv, vif, sta); 1463fb9987d0SSujith break; 1464fb9987d0SSujith default: 1465fb9987d0SSujith break; 1466fb9987d0SSujith } 1467fb9987d0SSujith } 1468fb9987d0SSujith 1469fb9987d0SSujith static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, 1470fb9987d0SSujith const struct ieee80211_tx_queue_params *params) 1471fb9987d0SSujith { 1472fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1473fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 1474fb9987d0SSujith struct ath9k_tx_queue_info qi; 1475fb9987d0SSujith int ret = 0, qnum; 1476fb9987d0SSujith 1477fb9987d0SSujith if (queue >= WME_NUM_AC) 1478fb9987d0SSujith return 0; 1479fb9987d0SSujith 1480fb9987d0SSujith mutex_lock(&priv->mutex); 1481fb9987d0SSujith 1482fb9987d0SSujith memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); 1483fb9987d0SSujith 1484fb9987d0SSujith qi.tqi_aifs = params->aifs; 1485fb9987d0SSujith qi.tqi_cwmin = params->cw_min; 1486fb9987d0SSujith qi.tqi_cwmax = params->cw_max; 1487fb9987d0SSujith qi.tqi_burstTime = params->txop; 1488fb9987d0SSujith 1489fb9987d0SSujith qnum = get_hw_qnum(queue, priv->hwq_map); 1490fb9987d0SSujith 1491fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 1492fb9987d0SSujith "Configure tx [queue/hwq] [%d/%d], " 1493fb9987d0SSujith "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", 1494fb9987d0SSujith queue, qnum, params->aifs, params->cw_min, 1495fb9987d0SSujith params->cw_max, params->txop); 1496fb9987d0SSujith 1497e1572c5eSSujith ret = ath_htc_txq_update(priv, qnum, &qi); 1498fb9987d0SSujith if (ret) 1499fb9987d0SSujith ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); 1500fb9987d0SSujith 1501fb9987d0SSujith mutex_unlock(&priv->mutex); 1502fb9987d0SSujith 1503fb9987d0SSujith return ret; 1504fb9987d0SSujith } 1505fb9987d0SSujith 1506fb9987d0SSujith static int ath9k_htc_set_key(struct ieee80211_hw *hw, 1507fb9987d0SSujith enum set_key_cmd cmd, 1508fb9987d0SSujith struct ieee80211_vif *vif, 1509fb9987d0SSujith struct ieee80211_sta *sta, 1510fb9987d0SSujith struct ieee80211_key_conf *key) 1511fb9987d0SSujith { 1512fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1513fb9987d0SSujith struct ath_common *common = ath9k_hw_common(priv->ah); 1514fb9987d0SSujith int ret = 0; 1515fb9987d0SSujith 1516e1572c5eSSujith if (htc_modparam_nohwcrypt) 1517fb9987d0SSujith return -ENOSPC; 1518fb9987d0SSujith 1519fb9987d0SSujith mutex_lock(&priv->mutex); 1520fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n"); 1521bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 1522fb9987d0SSujith 1523fb9987d0SSujith switch (cmd) { 1524fb9987d0SSujith case SET_KEY: 1525fb9987d0SSujith ret = ath9k_cmn_key_config(common, vif, sta, key); 1526fb9987d0SSujith if (ret >= 0) { 1527fb9987d0SSujith key->hw_key_idx = ret; 1528fb9987d0SSujith /* push IV and Michael MIC generation to stack */ 1529fb9987d0SSujith key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 1530fb9987d0SSujith if (key->alg == ALG_TKIP) 1531fb9987d0SSujith key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; 1532fb9987d0SSujith if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP) 1533fb9987d0SSujith key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; 1534fb9987d0SSujith ret = 0; 1535fb9987d0SSujith } 1536fb9987d0SSujith break; 1537fb9987d0SSujith case DISABLE_KEY: 1538fb9987d0SSujith ath9k_cmn_key_delete(common, key); 1539fb9987d0SSujith break; 1540fb9987d0SSujith default: 1541fb9987d0SSujith ret = -EINVAL; 1542fb9987d0SSujith } 1543fb9987d0SSujith 1544bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 1545fb9987d0SSujith mutex_unlock(&priv->mutex); 1546fb9987d0SSujith 1547fb9987d0SSujith return ret; 1548fb9987d0SSujith } 1549fb9987d0SSujith 1550fb9987d0SSujith static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, 1551fb9987d0SSujith struct ieee80211_vif *vif, 1552fb9987d0SSujith struct ieee80211_bss_conf *bss_conf, 1553fb9987d0SSujith u32 changed) 1554fb9987d0SSujith { 1555fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1556fb9987d0SSujith struct ath_hw *ah = priv->ah; 1557fb9987d0SSujith struct ath_common *common = ath9k_hw_common(ah); 1558fb9987d0SSujith 1559fb9987d0SSujith mutex_lock(&priv->mutex); 1560bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 1561fb9987d0SSujith 1562fb9987d0SSujith if (changed & BSS_CHANGED_ASSOC) { 1563fb9987d0SSujith common->curaid = bss_conf->assoc ? 1564fb9987d0SSujith bss_conf->aid : 0; 1565fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", 1566fb9987d0SSujith bss_conf->assoc); 1567fb9987d0SSujith 1568fb9987d0SSujith if (bss_conf->assoc) { 1569fb9987d0SSujith priv->op_flags |= OP_ASSOCIATED; 1570fb9987d0SSujith ath_start_ani(priv); 1571fb9987d0SSujith } else { 1572fb9987d0SSujith priv->op_flags &= ~OP_ASSOCIATED; 1573bde748a4SVivek Natarajan cancel_work_sync(&priv->ps_work); 1574fb9987d0SSujith cancel_delayed_work_sync(&priv->ath9k_ani_work); 1575fb9987d0SSujith } 1576fb9987d0SSujith } 1577fb9987d0SSujith 1578fb9987d0SSujith if (changed & BSS_CHANGED_BSSID) { 1579fb9987d0SSujith /* Set BSSID */ 1580fb9987d0SSujith memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); 1581fb9987d0SSujith ath9k_hw_write_associd(ah); 1582fb9987d0SSujith 1583fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, 1584fb9987d0SSujith "BSSID: %pM aid: 0x%x\n", 1585fb9987d0SSujith common->curbssid, common->curaid); 1586fb9987d0SSujith } 1587fb9987d0SSujith 1588fb9987d0SSujith if ((changed & BSS_CHANGED_BEACON_INT) || 1589fb9987d0SSujith (changed & BSS_CHANGED_BEACON) || 1590fb9987d0SSujith ((changed & BSS_CHANGED_BEACON_ENABLED) && 1591fb9987d0SSujith bss_conf->enable_beacon)) { 1592fb9987d0SSujith priv->op_flags |= OP_ENABLE_BEACON; 15931c3652a5SVivek Natarajan ath9k_htc_beacon_config(priv, vif); 1594fb9987d0SSujith } 1595fb9987d0SSujith 1596fb9987d0SSujith if ((changed & BSS_CHANGED_BEACON_ENABLED) && 1597fb9987d0SSujith !bss_conf->enable_beacon) { 1598fb9987d0SSujith priv->op_flags &= ~OP_ENABLE_BEACON; 15991c3652a5SVivek Natarajan ath9k_htc_beacon_config(priv, vif); 1600fb9987d0SSujith } 1601fb9987d0SSujith 1602fb9987d0SSujith if (changed & BSS_CHANGED_ERP_PREAMBLE) { 1603fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", 1604fb9987d0SSujith bss_conf->use_short_preamble); 1605fb9987d0SSujith if (bss_conf->use_short_preamble) 1606fb9987d0SSujith priv->op_flags |= OP_PREAMBLE_SHORT; 1607fb9987d0SSujith else 1608fb9987d0SSujith priv->op_flags &= ~OP_PREAMBLE_SHORT; 1609fb9987d0SSujith } 1610fb9987d0SSujith 1611fb9987d0SSujith if (changed & BSS_CHANGED_ERP_CTS_PROT) { 1612fb9987d0SSujith ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", 1613fb9987d0SSujith bss_conf->use_cts_prot); 1614fb9987d0SSujith if (bss_conf->use_cts_prot && 1615fb9987d0SSujith hw->conf.channel->band != IEEE80211_BAND_5GHZ) 1616fb9987d0SSujith priv->op_flags |= OP_PROTECT_ENABLE; 1617fb9987d0SSujith else 1618fb9987d0SSujith priv->op_flags &= ~OP_PROTECT_ENABLE; 1619fb9987d0SSujith } 1620fb9987d0SSujith 1621fb9987d0SSujith if (changed & BSS_CHANGED_ERP_SLOT) { 1622fb9987d0SSujith if (bss_conf->use_short_slot) 1623fb9987d0SSujith ah->slottime = 9; 1624fb9987d0SSujith else 1625fb9987d0SSujith ah->slottime = 20; 1626fb9987d0SSujith 1627fb9987d0SSujith ath9k_hw_init_global_settings(ah); 1628fb9987d0SSujith } 1629fb9987d0SSujith 1630bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 1631fb9987d0SSujith mutex_unlock(&priv->mutex); 1632fb9987d0SSujith } 1633fb9987d0SSujith 1634fb9987d0SSujith static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) 1635fb9987d0SSujith { 1636fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1637fb9987d0SSujith u64 tsf; 1638fb9987d0SSujith 1639fb9987d0SSujith mutex_lock(&priv->mutex); 1640fb9987d0SSujith tsf = ath9k_hw_gettsf64(priv->ah); 1641fb9987d0SSujith mutex_unlock(&priv->mutex); 1642fb9987d0SSujith 1643fb9987d0SSujith return tsf; 1644fb9987d0SSujith } 1645fb9987d0SSujith 1646fb9987d0SSujith static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) 1647fb9987d0SSujith { 1648fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1649fb9987d0SSujith 1650fb9987d0SSujith mutex_lock(&priv->mutex); 1651fb9987d0SSujith ath9k_hw_settsf64(priv->ah, tsf); 1652fb9987d0SSujith mutex_unlock(&priv->mutex); 1653fb9987d0SSujith } 1654fb9987d0SSujith 1655fb9987d0SSujith static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) 1656fb9987d0SSujith { 1657fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1658fb9987d0SSujith 1659bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 1660fb9987d0SSujith mutex_lock(&priv->mutex); 1661fb9987d0SSujith ath9k_hw_reset_tsf(priv->ah); 1662fb9987d0SSujith mutex_unlock(&priv->mutex); 1663bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 1664fb9987d0SSujith } 1665fb9987d0SSujith 1666fb9987d0SSujith static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, 1667fb9987d0SSujith struct ieee80211_vif *vif, 1668fb9987d0SSujith enum ieee80211_ampdu_mlme_action action, 1669fb9987d0SSujith struct ieee80211_sta *sta, 1670fb9987d0SSujith u16 tid, u16 *ssn) 1671fb9987d0SSujith { 1672fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1673fb9987d0SSujith struct ath9k_htc_aggr_work *work = &priv->aggr_work; 1674fb9987d0SSujith struct ath9k_htc_sta *ista; 1675fb9987d0SSujith 1676fb9987d0SSujith switch (action) { 1677fb9987d0SSujith case IEEE80211_AMPDU_RX_START: 1678fb9987d0SSujith break; 1679fb9987d0SSujith case IEEE80211_AMPDU_RX_STOP: 1680fb9987d0SSujith break; 1681fb9987d0SSujith case IEEE80211_AMPDU_TX_START: 1682fb9987d0SSujith case IEEE80211_AMPDU_TX_STOP: 1683fb9987d0SSujith if (!(priv->op_flags & OP_TXAGGR)) 1684fb9987d0SSujith return -ENOTSUPP; 1685fb9987d0SSujith memcpy(work->sta_addr, sta->addr, ETH_ALEN); 1686fb9987d0SSujith work->hw = hw; 1687fb9987d0SSujith work->vif = vif; 1688fb9987d0SSujith work->action = action; 1689fb9987d0SSujith work->tid = tid; 1690fb9987d0SSujith ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0); 1691fb9987d0SSujith break; 1692fb9987d0SSujith case IEEE80211_AMPDU_TX_OPERATIONAL: 1693fb9987d0SSujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 1694fb9987d0SSujith ista->tid_state[tid] = AGGR_OPERATIONAL; 1695fb9987d0SSujith break; 1696fb9987d0SSujith default: 1697fb9987d0SSujith ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, 1698fb9987d0SSujith "Unknown AMPDU action\n"); 1699fb9987d0SSujith } 1700fb9987d0SSujith 1701fb9987d0SSujith return 0; 1702fb9987d0SSujith } 1703fb9987d0SSujith 1704fb9987d0SSujith static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) 1705fb9987d0SSujith { 1706fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1707fb9987d0SSujith 1708fb9987d0SSujith mutex_lock(&priv->mutex); 1709fb9987d0SSujith spin_lock_bh(&priv->beacon_lock); 1710fb9987d0SSujith priv->op_flags |= OP_SCANNING; 1711fb9987d0SSujith spin_unlock_bh(&priv->beacon_lock); 1712bde748a4SVivek Natarajan cancel_work_sync(&priv->ps_work); 1713fb9987d0SSujith cancel_delayed_work_sync(&priv->ath9k_ani_work); 1714fb9987d0SSujith mutex_unlock(&priv->mutex); 1715fb9987d0SSujith } 1716fb9987d0SSujith 1717fb9987d0SSujith static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) 1718fb9987d0SSujith { 1719fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1720fb9987d0SSujith 1721bde748a4SVivek Natarajan ath9k_htc_ps_wakeup(priv); 1722fb9987d0SSujith mutex_lock(&priv->mutex); 1723fb9987d0SSujith spin_lock_bh(&priv->beacon_lock); 1724fb9987d0SSujith priv->op_flags &= ~OP_SCANNING; 1725fb9987d0SSujith spin_unlock_bh(&priv->beacon_lock); 1726fb9987d0SSujith priv->op_flags |= OP_FULL_RESET; 17271c3652a5SVivek Natarajan if (priv->op_flags & OP_ASSOCIATED) 1728fcb9392fSSujith ath9k_htc_beacon_config(priv, priv->vif); 1729fb9987d0SSujith ath_start_ani(priv); 1730fb9987d0SSujith mutex_unlock(&priv->mutex); 1731bde748a4SVivek Natarajan ath9k_htc_ps_restore(priv); 1732fb9987d0SSujith } 1733fb9987d0SSujith 1734fb9987d0SSujith static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 1735fb9987d0SSujith { 1736fb9987d0SSujith return 0; 1737fb9987d0SSujith } 1738fb9987d0SSujith 1739fb9987d0SSujith static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, 1740fb9987d0SSujith u8 coverage_class) 1741fb9987d0SSujith { 1742fb9987d0SSujith struct ath9k_htc_priv *priv = hw->priv; 1743fb9987d0SSujith 1744fb9987d0SSujith mutex_lock(&priv->mutex); 1745fb9987d0SSujith priv->ah->coverage_class = coverage_class; 1746fb9987d0SSujith ath9k_hw_init_global_settings(priv->ah); 1747fb9987d0SSujith mutex_unlock(&priv->mutex); 1748fb9987d0SSujith } 1749fb9987d0SSujith 1750fb9987d0SSujith struct ieee80211_ops ath9k_htc_ops = { 1751fb9987d0SSujith .tx = ath9k_htc_tx, 1752fb9987d0SSujith .start = ath9k_htc_start, 1753fb9987d0SSujith .stop = ath9k_htc_stop, 1754fb9987d0SSujith .add_interface = ath9k_htc_add_interface, 1755fb9987d0SSujith .remove_interface = ath9k_htc_remove_interface, 1756fb9987d0SSujith .config = ath9k_htc_config, 1757fb9987d0SSujith .configure_filter = ath9k_htc_configure_filter, 1758fb9987d0SSujith .sta_notify = ath9k_htc_sta_notify, 1759fb9987d0SSujith .conf_tx = ath9k_htc_conf_tx, 1760fb9987d0SSujith .bss_info_changed = ath9k_htc_bss_info_changed, 1761fb9987d0SSujith .set_key = ath9k_htc_set_key, 1762fb9987d0SSujith .get_tsf = ath9k_htc_get_tsf, 1763fb9987d0SSujith .set_tsf = ath9k_htc_set_tsf, 1764fb9987d0SSujith .reset_tsf = ath9k_htc_reset_tsf, 1765fb9987d0SSujith .ampdu_action = ath9k_htc_ampdu_action, 1766fb9987d0SSujith .sw_scan_start = ath9k_htc_sw_scan_start, 1767fb9987d0SSujith .sw_scan_complete = ath9k_htc_sw_scan_complete, 1768fb9987d0SSujith .set_rts_threshold = ath9k_htc_set_rts_threshold, 1769fb9987d0SSujith .rfkill_poll = ath9k_htc_rfkill_poll_state, 1770fb9987d0SSujith .set_coverage_class = ath9k_htc_set_coverage_class, 1771fb9987d0SSujith }; 1772