static void ath9k_htc_stop(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);
	int ret = 0;
	u8 cmd_rsp;

	mutex_lock(&priv->mutex);

	if (priv->op_flags & OP_INVALID) {
		ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
		mutex_unlock(&priv->mutex);
		return;
	}

	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);

	tasklet_kill(&priv->swba_tasklet);
	tasklet_kill(&priv->rx_tasklet);
	tasklet_kill(&priv->tx_tasklet);

	skb_queue_purge(&priv->tx_queue);

	mutex_unlock(&priv->mutex);

	/* Cancel all the running timers/work .. */
	cancel_work_sync(&priv->fatal_work);
	cancel_work_sync(&priv->ps_work);
	cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
	ath9k_htc_stop_ani(priv);
	ath9k_led_stop_brightness(priv);

	mutex_lock(&priv->mutex);

	if (ah->btcoex_hw.enabled) {
		ath9k_hw_btcoex_disable(ah);
		if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
			ath_htc_cancel_btcoex_work(priv);
	}

	/* Remove a monitor interface if it's present. */
	if (priv->ah->is_monitoring)
		ath9k_htc_remove_monitor_interface(priv);

	ath9k_hw_phy_disable(ah);
	ath9k_hw_disable(ah);
	ath9k_htc_ps_restore(priv);
	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);

	priv->op_flags |= OP_INVALID;

	ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
	mutex_unlock(&priv->mutex);
}
示例#2
0
static void ath9k_htc_stop(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);
	int ret __attribute__ ((unused));
	u8 cmd_rsp;

	mutex_lock(&priv->mutex);

	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
		ath_dbg(common, ANY, "Device not present\n");
		mutex_unlock(&priv->mutex);
		return;
	}

	ath9k_htc_ps_wakeup(priv);

	WMI_CMD(WMI_DISABLE_INTR_CMDID);
	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
	WMI_CMD(WMI_STOP_RECV_CMDID);

	tasklet_kill(&priv->rx_tasklet);

	del_timer_sync(&priv->tx.cleanup_timer);
	ath9k_htc_tx_drain(priv);
	ath9k_wmi_event_drain(priv);

	mutex_unlock(&priv->mutex);

	/* Cancel all the running timers/work .. */
	cancel_work_sync(&priv->fatal_work);
	cancel_work_sync(&priv->ps_work);

#ifdef CPTCFG_MAC80211_LEDS
	cancel_work_sync(&priv->led_work);
#endif
	ath9k_htc_stop_ani(priv);

	mutex_lock(&priv->mutex);

	ath9k_htc_stop_btcoex(priv);

	/* Remove a monitor interface if it's present. */
	if (priv->ah->is_monitoring)
		ath9k_htc_remove_monitor_interface(priv);

	ath9k_hw_phy_disable(ah);
	ath9k_hw_disable(ah);
	ath9k_htc_ps_restore(priv);
	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);

	set_bit(ATH_OP_INVALID, &common->op_flags);

	ath_dbg(common, CONFIG, "Driver halt\n");
	mutex_unlock(&priv->mutex);
}
示例#3
0
static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath_common *common = ath9k_hw_common(priv->ah);
	struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
	struct ath9k_htc_target_vif hvif;
	int ret = 0;
	u8 cmd_rsp;

	mutex_lock(&priv->mutex);
	ath9k_htc_ps_wakeup(priv);

	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
	hvif.index = avp->index;
	WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
	if (ret) {
		ath_err(common, "Unable to remove interface at idx: %d\n",
			avp->index);
	}
	priv->nvifs--;
	priv->vif_slot &= ~(1 << avp->index);

	if (priv->csa_vif == vif)
		priv->csa_vif = NULL;

	ath9k_htc_remove_station(priv, vif, NULL);

	DEC_VIF(priv, vif->type);

	if ((vif->type == NL80211_IFTYPE_AP) ||
	     vif->type == NL80211_IFTYPE_MESH_POINT ||
	    (vif->type == NL80211_IFTYPE_ADHOC))
		ath9k_htc_remove_bslot(priv, vif);

	ath9k_htc_set_opmode(priv);

	ath9k_htc_set_mac_bssid_mask(priv, vif);

	/*
	 * Stop ANI only if there are no associated station interfaces.
	 */
	if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {
		priv->rearm_ani = false;
		ieee80211_iterate_active_interfaces_atomic(
			priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
			ath9k_htc_vif_iter, priv);
		if (!priv->rearm_ani)
			ath9k_htc_stop_ani(priv);
	}

	ath_dbg(common, CONFIG, "Detach Interface at idx: %d\n", avp->index);

	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);
}
示例#4
0
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.chandef.chan;
	struct ath9k_hw_cal_data *caldata = NULL;
	enum htc_phymode mode;
	__be16 htc_mode;
	u8 cmd_rsp;
	int ret;

	mutex_lock(&priv->mutex);
	ath9k_htc_ps_wakeup(priv);

	ath9k_htc_stop_ani(priv);
	ieee80211_stop_queues(priv->hw);

	del_timer_sync(&priv->tx.cleanup_timer);
	ath9k_htc_tx_drain(priv);

	WMI_CMD(WMI_DISABLE_INTR_CMDID);
	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
	WMI_CMD(WMI_STOP_RECV_CMDID);

	ath9k_wmi_event_drain(priv);

	caldata = &priv->caldata;
	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);
	}

	ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit,
			       &priv->curtxpow);

	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);
	ath9k_htc_vif_reconfig(priv);
	ieee80211_wake_queues(priv->hw);

	mod_timer(&priv->tx.cleanup_timer,
		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));

	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);
}
static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
{
	struct ath9k_htc_priv *priv = hw->priv;

	mutex_lock(&priv->mutex);
	spin_lock_bh(&priv->beacon_lock);
	set_bit(OP_SCANNING, &priv->op_flags);
	spin_unlock_bh(&priv->beacon_lock);
	cancel_work_sync(&priv->ps_work);
	ath9k_htc_stop_ani(priv);
	mutex_unlock(&priv->mutex);
}
示例#6
0
static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw,
				    struct ieee80211_vif *vif,
				    const u8 *mac_addr)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath_common *common = ath9k_hw_common(priv->ah);

	mutex_lock(&priv->mutex);
	spin_lock_bh(&priv->beacon_lock);
	set_bit(ATH_OP_SCANNING, &common->op_flags);
	spin_unlock_bh(&priv->beacon_lock);
	cancel_work_sync(&priv->ps_work);
	ath9k_htc_stop_ani(priv);
	mutex_unlock(&priv->mutex);
}
示例#7
0
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.chandef.chan;
	struct ath9k_hw_cal_data *caldata = NULL;
	enum htc_phymode mode;
	__be16 htc_mode;
	u8 cmd_rsp;
	int ret;

	if (test_bit(ATH_OP_INVALID, &common->op_flags))
		return -EIO;

	fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);

	ath9k_htc_ps_wakeup(priv);

	ath9k_htc_stop_ani(priv);
	del_timer_sync(&priv->tx.cleanup_timer);
	ath9k_htc_tx_drain(priv);

	WMI_CMD(WMI_DISABLE_INTR_CMDID);
	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
	WMI_CMD(WMI_STOP_RECV_CMDID);

	ath9k_wmi_event_drain(priv);

	ath_dbg(common, 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);

	if (!fastcc)
		caldata = &priv->caldata;

	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;
	}

	ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit,
			       &priv->curtxpow);

	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);

	if (!test_bit(ATH_OP_SCANNING, &common->op_flags) &&
	    !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
		ath9k_htc_vif_reconfig(priv);

	mod_timer(&priv->tx.cleanup_timer,
		  jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));

err:
	ath9k_htc_ps_restore(priv);
	return ret;
}
示例#8
0
static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif,
				       struct ieee80211_bss_conf *bss_conf,
				       u32 changed)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath_hw *ah = priv->ah;
	struct ath_common *common = ath9k_hw_common(ah);
	int slottime;

	mutex_lock(&priv->mutex);
	ath9k_htc_ps_wakeup(priv);

	if (changed & BSS_CHANGED_ASSOC) {
		ath_dbg(common, CONFIG, "BSS Changed ASSOC %d\n",
			bss_conf->assoc);

		bss_conf->assoc ?
			priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;

		if (!bss_conf->assoc)
			clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);

		if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
			ath9k_htc_choose_set_bssid(priv);
			if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
				ath9k_htc_start_ani(priv);
			else if (priv->num_sta_assoc_vif == 0)
				ath9k_htc_stop_ani(priv);
		}
	}

	if (changed & BSS_CHANGED_IBSS) {
		if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
			common->curaid = bss_conf->aid;
			memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
			ath9k_htc_set_bssid(priv);
		}
	}

	if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
		ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",
			bss_conf->bssid);
		ath9k_htc_set_tsfadjust(priv, vif);
		priv->cur_beacon_conf.enable_beacon = 1;
		ath9k_htc_beacon_config(priv, vif);
	}

	if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
		/*
		 * Disable SWBA interrupt only if there are no
		 * concurrent AP/mesh or IBSS interfaces.
		 */
		if ((priv->num_ap_vif + priv->num_mbss_vif <= 1) ||
		     priv->num_ibss_vif) {
			ath_dbg(common, CONFIG,
				"Beacon disabled for BSS: %pM\n",
				bss_conf->bssid);
			priv->cur_beacon_conf.enable_beacon = 0;
			ath9k_htc_beacon_config(priv, vif);
		}
	}

	if (changed & BSS_CHANGED_BEACON_INT) {
		/*
		 * Reset the HW TSF for the first AP or mesh interface.
		 */
		if (priv->nvifs == 1 &&
		    ((priv->ah->opmode == NL80211_IFTYPE_AP &&
		      vif->type == NL80211_IFTYPE_AP &&
		      priv->num_ap_vif == 1) ||
		    (priv->ah->opmode == NL80211_IFTYPE_MESH_POINT &&
		      vif->type == NL80211_IFTYPE_MESH_POINT &&
		      priv->num_mbss_vif == 1))) {
			set_bit(OP_TSF_RESET, &priv->op_flags);
		}
		ath_dbg(common, CONFIG,
			"Beacon interval changed for BSS: %pM\n",
			bss_conf->bssid);
		ath9k_htc_beacon_config(priv, vif);
	}

	if (changed & BSS_CHANGED_ERP_SLOT) {
		if (bss_conf->use_short_slot)
			slottime = 9;
		else
			slottime = 20;
		if (vif->type == NL80211_IFTYPE_AP) {
			/*
			 * Defer update, so that connected stations can adjust
			 * their settings at the same time.
			 * See beacon.c for more details
			 */
			priv->beacon.slottime = slottime;
			priv->beacon.updateslot = UPDATE;
		} else {
			ah->slottime = slottime;
			ath9k_hw_init_global_settings(ah);
		}
	}

	if (changed & BSS_CHANGED_HT)
		ath9k_htc_update_rate(priv, vif, bss_conf);

	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);
}
static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif,
				       struct ieee80211_bss_conf *bss_conf,
				       u32 changed)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath_hw *ah = priv->ah;
	struct ath_common *common = ath9k_hw_common(ah);

	mutex_lock(&priv->mutex);
	ath9k_htc_ps_wakeup(priv);

	if (changed & BSS_CHANGED_ASSOC) {
		ath_dbg(common, CONFIG, "BSS Changed ASSOC %d\n",
			bss_conf->assoc);

		bss_conf->assoc ?
			priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;

		if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
			ath9k_htc_choose_set_bssid(priv);
			if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
				ath9k_htc_start_ani(priv);
			else if (priv->num_sta_assoc_vif == 0)
				ath9k_htc_stop_ani(priv);
		}
	}

	if (changed & BSS_CHANGED_IBSS) {
		if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
			common->curaid = bss_conf->aid;
			memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
			ath9k_htc_set_bssid(priv);
		}
	}

	if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
		ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",
			bss_conf->bssid);
		ath9k_htc_set_tsfadjust(priv, vif);
		set_bit(OP_ENABLE_BEACON, &priv->op_flags);
		ath9k_htc_beacon_config(priv, vif);
	}

	if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
		/*
		 * Disable SWBA interrupt only if there are no
		 * AP/IBSS interfaces.
		 */
		if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) {
			ath_dbg(common, CONFIG,
				"Beacon disabled for BSS: %pM\n",
				bss_conf->bssid);
			clear_bit(OP_ENABLE_BEACON, &priv->op_flags);
			ath9k_htc_beacon_config(priv, vif);
		}
	}

	if (changed & BSS_CHANGED_BEACON_INT) {
		/*
		 * Reset the HW TSF for the first AP interface.
		 */
		if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
		    (priv->nvifs == 1) &&
		    (priv->num_ap_vif == 1) &&
		    (vif->type == NL80211_IFTYPE_AP)) {
			set_bit(OP_TSF_RESET, &priv->op_flags);
		}
		ath_dbg(common, CONFIG,
			"Beacon interval changed for BSS: %pM\n",
			bss_conf->bssid);
		ath9k_htc_beacon_config(priv, vif);
	}

	if (changed & BSS_CHANGED_ERP_SLOT) {
		if (bss_conf->use_short_slot)
			ah->slottime = 9;
		else
			ah->slottime = 20;

		ath9k_hw_init_global_settings(ah);
	}

	if (changed & BSS_CHANGED_HT)
		ath9k_htc_update_rate(priv, vif, bss_conf);

	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);
}
static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif,
				       struct ieee80211_bss_conf *bss_conf,
				       u32 changed)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath_hw *ah = priv->ah;
	struct ath_common *common = ath9k_hw_common(ah);
	bool set_assoc;

	mutex_lock(&priv->mutex);
	ath9k_htc_ps_wakeup(priv);

	/*
	 * Set the HW AID/BSSID only for the first station interface
	 * or in IBSS mode.
	 */
	set_assoc = !!((priv->ah->opmode == NL80211_IFTYPE_ADHOC) ||
		       ((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
			(priv->num_sta_vif == 1)));


	if (changed & BSS_CHANGED_ASSOC) {
		if (set_assoc) {
			ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
				bss_conf->assoc);

			common->curaid = bss_conf->assoc ?
				bss_conf->aid : 0;

			if (bss_conf->assoc)
				ath9k_htc_start_ani(priv);
			else
				ath9k_htc_stop_ani(priv);
		}
	}

	if (changed & BSS_CHANGED_BSSID) {
		if (set_assoc) {
			memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
			ath9k_hw_write_associd(ah);

			ath_dbg(common, ATH_DBG_CONFIG,
				"BSSID: %pM aid: 0x%x\n",
				common->curbssid, common->curaid);
		}
	}

	if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
		ath_dbg(common, ATH_DBG_CONFIG,
			"Beacon enabled for BSS: %pM\n", bss_conf->bssid);
		priv->op_flags |= OP_ENABLE_BEACON;
		ath9k_htc_beacon_config(priv, vif);
	}

	if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
		/*
		 * Disable SWBA interrupt only if there are no
		 * AP/IBSS interfaces.
		 */
		if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) {
			ath_dbg(common, ATH_DBG_CONFIG,
				"Beacon disabled for BSS: %pM\n",
				bss_conf->bssid);
			priv->op_flags &= ~OP_ENABLE_BEACON;
			ath9k_htc_beacon_config(priv, vif);
		}
	}

	if (changed & BSS_CHANGED_BEACON_INT) {
		/*
		 * Reset the HW TSF for the first AP interface.
		 */
		if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
		    (priv->nvifs == 1) &&
		    (priv->num_ap_vif == 1) &&
		    (vif->type == NL80211_IFTYPE_AP)) {
			priv->op_flags |= OP_TSF_RESET;
		}
		ath_dbg(common, ATH_DBG_CONFIG,
			"Beacon interval changed for BSS: %pM\n",
			bss_conf->bssid);
		ath9k_htc_beacon_config(priv, vif);
	}

	if (changed & BSS_CHANGED_ERP_SLOT) {
		if (bss_conf->use_short_slot)
			ah->slottime = 9;
		else
			ah->slottime = 20;

		ath9k_hw_init_global_settings(ah);
	}

	if (changed & BSS_CHANGED_HT)
		ath9k_htc_update_rate(priv, vif, bss_conf);

	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);
}