void ath9k_htc_reset(struct ath9k_htc_priv *priv) { struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = priv->hw->conf.channel; struct ath9k_hw_cal_data *caldata; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; int ret; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); if (priv->op_flags & OP_ASSOCIATED) cancel_delayed_work_sync(&priv->ath9k_ani_work); ieee80211_stop_queues(priv->hw); htc_stop(priv->htc); WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); caldata = &priv->caldata[channel->hw_value]; ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); if (ret) { ath_err(common, "Unable to reset device (%u Mhz) reset status %d\n", channel->center_freq, ret); } ath_update_txpow(priv); WMI_CMD(WMI_START_RECV_CMDID); ath9k_host_rx_init(priv); mode = ath9k_htc_get_curmode(priv, ah->curchan); htc_mode = cpu_to_be16(mode); WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); WMI_CMD(WMI_ENABLE_INTR_CMDID); htc_start(priv->htc); if (priv->op_flags & OP_ASSOCIATED) { ath9k_htc_beacon_config(priv, priv->vif); ath_start_ani(priv); } ieee80211_wake_queues(priv->hw); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); }
/* * To enable PHY (radio on) */ int ath_radio_enable(ath_dev_t dev) { struct ath_softc *sc = ATH_DEV_TO_SC(dev); struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; HAL_HT_MACMODE ht_macmode = sc->sc_ieee_ops->cwm_macmode(sc->sc_ieee); if (sc->sc_invalid) return -EIO; #if ATH_RESET_SERIAL ATH_RESET_ACQUIRE_MUTEX(sc); #endif ATH_PS_WAKEUP(sc); ath_pwrsave_awake(sc); /* Turn off PCIE ASPM when card is active */ ath_pcie_pwrsave_enable_on_phystate_change(sc, 0); ATH_USB_TX_STOP(sc->sc_osdev); #if ATH_C3_WAR STOP_C3_WAR_TIMER(sc); #endif #if !ATH_RESET_SERIAL ATH_LOCK_PCI_IRQ(sc); #endif if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, AH_FALSE, &status, sc->sc_scanning)) { printk("%s: unable to reset hardware; hal status %u\n", __func__, status); } #if !ATH_RESET_SERIAL ATH_UNLOCK_PCI_IRQ(sc); #endif ath_update_txpow(sc, sc->tx_power); /* update tx power state */ ath_beacon_config(sc, ATH_BEACON_CONFIG_REASON_RESET, ATH_IF_ID_ANY); /* restart beacons */ ath_hal_intrset(ah, sc->sc_imask); ath_wmi_start_recv(sc); if (ATH_STARTRECV(sc) != 0) { /* restart recv */ printk("%s: unable to start recv logic\n", __func__); } ATH_USB_TX_START(sc->sc_osdev); /* * notify LED module radio has been turned on * This function will access the hw, so we must call it after * the power save function. */ ath_led_enable(&sc->sc_led_control); ATH_PS_SLEEP(sc); #if ATH_RESET_SERIAL ATH_RESET_RELEASE_MUTEX(sc); #endif return 0; }
static int ath9k_htc_start(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *curchan = hw->conf.channel; struct ath9k_channel *init_channel; int ret = 0; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; mutex_lock(&priv->mutex); ath_dbg(common, ATH_DBG_CONFIG, "Starting driver with initial channel: %d MHz\n", curchan->center_freq); /* Ensure that HW is awake before flushing RX */ ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); WMI_CMD(WMI_FLUSH_RECV_CMDID); /* setup initial channel */ init_channel = ath9k_cmn_get_curchannel(hw, ah); ath9k_hw_htc_resetinit(ah); ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (ret) { ath_err(common, "Unable to reset hardware; reset status %d (freq %u MHz)\n", ret, curchan->center_freq); mutex_unlock(&priv->mutex); return ret; } ath_update_txpow(priv); mode = ath9k_htc_get_curmode(priv, init_channel); htc_mode = cpu_to_be16(mode); WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); WMI_CMD(WMI_ATH_INIT_CMDID); WMI_CMD(WMI_START_RECV_CMDID); ath9k_host_rx_init(priv); priv->op_flags &= ~OP_INVALID; htc_start(priv->htc); spin_lock_bh(&priv->tx_lock); priv->tx_queues_stop = false; spin_unlock_bh(&priv->tx_lock); ieee80211_wake_queues(hw); if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(ah); ath_htc_resume_btcoex_work(priv); } mutex_unlock(&priv->mutex); return ret; }
static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; bool fastcc; struct ieee80211_channel *channel = hw->conf.channel; struct ath9k_hw_cal_data *caldata; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; int ret; if (priv->op_flags & OP_INVALID) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); ath9k_htc_ps_wakeup(priv); htc_stop(priv->htc); WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", priv->ah->curchan->channel, channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), fastcc); caldata = &priv->caldata[channel->hw_value]; ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, "Unable to reset channel (%u Mhz) reset status %d\n", channel->center_freq, ret); goto err; } ath_update_txpow(priv); WMI_CMD(WMI_START_RECV_CMDID); if (ret) goto err; ath9k_host_rx_init(priv); mode = ath9k_htc_get_curmode(priv, hchan); htc_mode = cpu_to_be16(mode); WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); if (ret) goto err; WMI_CMD(WMI_ENABLE_INTR_CMDID); if (ret) goto err; htc_start(priv->htc); err: ath9k_htc_ps_restore(priv); return ret; }
static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_conf *conf = &hw->conf; mutex_lock(&priv->mutex); if (changed & IEEE80211_CONF_CHANGE_IDLE) { bool enable_radio = false; bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); mutex_lock(&priv->htc_pm_lock); if (!idle && priv->ps_idle) enable_radio = true; priv->ps_idle = idle; mutex_unlock(&priv->htc_pm_lock); if (enable_radio) { ath_dbg(common, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); ath9k_htc_radio_enable(hw); } } /* * Monitor interface should be added before * IEEE80211_CONF_CHANGE_CHANNEL is handled. */ if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (conf->flags & IEEE80211_CONF_MONITOR) { if (ath9k_htc_add_monitor_interface(priv)) ath_err(common, "Failed to set monitor mode\n"); else ath_dbg(common, ATH_DBG_CONFIG, "HW opmode set to Monitor mode\n"); } } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; int pos = curchan->hw_value; ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", curchan->center_freq); ath9k_cmn_update_ichannel(&priv->ah->channels[pos], hw->conf.channel, hw->conf.channel_type); if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { ath_err(common, "Unable to set channel\n"); mutex_unlock(&priv->mutex); return -EINVAL; } } if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); priv->ps_enabled = true; } else { priv->ps_enabled = false; cancel_work_sync(&priv->ps_work); ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); } } if (changed & IEEE80211_CONF_CHANGE_POWER) { priv->txpowlimit = 2 * conf->power_level; ath_update_txpow(priv); } if (changed & IEEE80211_CONF_CHANGE_IDLE) { mutex_lock(&priv->htc_pm_lock); if (!priv->ps_idle) { mutex_unlock(&priv->htc_pm_lock); goto out; } mutex_unlock(&priv->htc_pm_lock); ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); ath9k_htc_radio_disable(hw); } out: mutex_unlock(&priv->mutex); return 0; }