brintos

brintos / linux-shallow public Read only

0
0
Text · 22.1 KiB · d81b2ad Raw
826 lines · c
1/*-2 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting3 * Copyright (c) 2004-2005 Atheros Communications, Inc.4 * Copyright (c) 2006 Devicescape Software, Inc.5 * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>6 * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>7 * Copyright (c) 2010 Bruno Randolf <br1@einfach.org>8 *9 * All rights reserved.10 *11 * Redistribution and use in source and binary forms, with or without12 * modification, are permitted provided that the following conditions13 * are met:14 * 1. Redistributions of source code must retain the above copyright15 *    notice, this list of conditions and the following disclaimer,16 *    without modification.17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer18 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any19 *    redistribution must be conditioned upon including a substantially20 *    similar Disclaimer requirement for further binary redistribution.21 * 3. Neither the names of the above-listed copyright holders nor the names22 *    of any contributors may be used to endorse or promote products derived23 *    from this software without specific prior written permission.24 *25 * Alternatively, this software may be distributed under the terms of the26 * GNU General Public License ("GPL") version 2 as published by the Free27 * Software Foundation.28 *29 * NO WARRANTY30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT32 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY33 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL34 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,35 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER38 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF40 * THE POSSIBILITY OF SUCH DAMAGES.41 *42 */43 44#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt45 46#include <net/mac80211.h>47#include <linux/unaligned.h>48 49#include "ath5k.h"50#include "base.h"51#include "reg.h"52 53/********************\54* Mac80211 functions *55\********************/56 57static void58ath5k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,59	 struct sk_buff *skb)60{61	struct ath5k_hw *ah = hw->priv;62	u16 qnum = skb_get_queue_mapping(skb);63 64	if (WARN_ON(qnum >= ah->ah_capabilities.cap_queues.q_tx_num)) {65		ieee80211_free_txskb(hw, skb);66		return;67	}68 69	ath5k_tx_queue(hw, skb, &ah->txqs[qnum], control);70}71 72 73static int74ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)75{76	struct ath5k_hw *ah = hw->priv;77	int ret;78	struct ath5k_vif *avf = (void *)vif->drv_priv;79 80	mutex_lock(&ah->lock);81 82	if ((vif->type == NL80211_IFTYPE_AP ||83	     vif->type == NL80211_IFTYPE_ADHOC)84	    && (ah->num_ap_vifs + ah->num_adhoc_vifs) >= ATH_BCBUF) {85		ret = -ELNRNG;86		goto end;87	}88 89	/* Don't allow other interfaces if one ad-hoc is configured.90	 * TODO: Fix the problems with ad-hoc and multiple other interfaces.91	 * We would need to operate the HW in ad-hoc mode to allow TSF updates92	 * for the IBSS, but this breaks with additional AP or STA interfaces93	 * at the moment. */94	if (ah->num_adhoc_vifs ||95	    (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {96		ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n");97		ret = -ELNRNG;98		goto end;99	}100 101	switch (vif->type) {102	case NL80211_IFTYPE_AP:103	case NL80211_IFTYPE_STATION:104	case NL80211_IFTYPE_ADHOC:105	case NL80211_IFTYPE_MESH_POINT:106		avf->opmode = vif->type;107		break;108	default:109		ret = -EOPNOTSUPP;110		goto end;111	}112 113	ah->nvifs++;114	ATH5K_DBG(ah, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);115 116	/* Assign the vap/adhoc to a beacon xmit slot. */117	if ((avf->opmode == NL80211_IFTYPE_AP) ||118	    (avf->opmode == NL80211_IFTYPE_ADHOC) ||119	    (avf->opmode == NL80211_IFTYPE_MESH_POINT)) {120		int slot;121 122		WARN_ON(list_empty(&ah->bcbuf));123		avf->bbuf = list_first_entry(&ah->bcbuf, struct ath5k_buf,124					     list);125		list_del(&avf->bbuf->list);126 127		avf->bslot = 0;128		for (slot = 0; slot < ATH_BCBUF; slot++) {129			if (!ah->bslot[slot]) {130				avf->bslot = slot;131				break;132			}133		}134		BUG_ON(ah->bslot[avf->bslot] != NULL);135		ah->bslot[avf->bslot] = vif;136		if (avf->opmode == NL80211_IFTYPE_AP)137			ah->num_ap_vifs++;138		else if (avf->opmode == NL80211_IFTYPE_ADHOC)139			ah->num_adhoc_vifs++;140		else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)141			ah->num_mesh_vifs++;142	}143 144	/* Any MAC address is fine, all others are included through the145	 * filter.146	 */147	ath5k_hw_set_lladdr(ah, vif->addr);148 149	ath5k_update_bssid_mask_and_opmode(ah, vif);150	ret = 0;151end:152	mutex_unlock(&ah->lock);153	return ret;154}155 156 157static void158ath5k_remove_interface(struct ieee80211_hw *hw,159		       struct ieee80211_vif *vif)160{161	struct ath5k_hw *ah = hw->priv;162	struct ath5k_vif *avf = (void *)vif->drv_priv;163	unsigned int i;164 165	mutex_lock(&ah->lock);166	ah->nvifs--;167 168	if (avf->bbuf) {169		ath5k_txbuf_free_skb(ah, avf->bbuf);170		list_add_tail(&avf->bbuf->list, &ah->bcbuf);171		for (i = 0; i < ATH_BCBUF; i++) {172			if (ah->bslot[i] == vif) {173				ah->bslot[i] = NULL;174				break;175			}176		}177		avf->bbuf = NULL;178	}179	if (avf->opmode == NL80211_IFTYPE_AP)180		ah->num_ap_vifs--;181	else if (avf->opmode == NL80211_IFTYPE_ADHOC)182		ah->num_adhoc_vifs--;183	else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)184		ah->num_mesh_vifs--;185 186	ath5k_update_bssid_mask_and_opmode(ah, NULL);187	mutex_unlock(&ah->lock);188}189 190 191/*192 * TODO: Phy disable/diversity etc193 */194static int195ath5k_config(struct ieee80211_hw *hw, u32 changed)196{197	struct ath5k_hw *ah = hw->priv;198	struct ieee80211_conf *conf = &hw->conf;199	int ret = 0;200	int i;201 202	mutex_lock(&ah->lock);203 204	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {205		ret = ath5k_chan_set(ah, &conf->chandef);206		if (ret < 0)207			goto unlock;208	}209 210	if ((changed & IEEE80211_CONF_CHANGE_POWER) &&211	(ah->ah_txpower.txp_requested != conf->power_level)) {212		ah->ah_txpower.txp_requested = conf->power_level;213 214		/* Half dB steps */215		ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));216	}217 218	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {219		ah->ah_retry_long = conf->long_frame_max_tx_count;220		ah->ah_retry_short = conf->short_frame_max_tx_count;221 222		for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++)223			ath5k_hw_set_tx_retry_limits(ah, i);224	}225 226	/* TODO:227	 * 1) Move this on config_interface and handle each case228	 * separately eg. when we have only one STA vif, use229	 * AR5K_ANTMODE_SINGLE_AP230	 *231	 * 2) Allow the user to change antenna mode eg. when only232	 * one antenna is present233	 *234	 * 3) Allow the user to set default/tx antenna when possible235	 *236	 * 4) Default mode should handle 90% of the cases, together237	 * with fixed a/b and single AP modes we should be able to238	 * handle 99%. Sectored modes are extreme cases and i still239	 * haven't found a usage for them. If we decide to support them,240	 * then we must allow the user to set how many tx antennas we241	 * have available242	 */243	ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);244 245unlock:246	mutex_unlock(&ah->lock);247	return ret;248}249 250 251static void252ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,253		       struct ieee80211_bss_conf *bss_conf, u64 changes)254{255	struct ath5k_vif *avf = (void *)vif->drv_priv;256	struct ath5k_hw *ah = hw->priv;257	struct ath_common *common = ath5k_hw_common(ah);258 259	mutex_lock(&ah->lock);260 261	if (changes & BSS_CHANGED_BSSID) {262		/* Cache for later use during resets */263		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);264		common->curaid = 0;265		ath5k_hw_set_bssid(ah);266	}267 268	if (changes & BSS_CHANGED_BEACON_INT)269		ah->bintval = bss_conf->beacon_int;270 271	if (changes & BSS_CHANGED_ERP_SLOT) {272		int slot_time;273 274		ah->ah_short_slot = bss_conf->use_short_slot;275		slot_time = ath5k_hw_get_default_slottime(ah) +276			    3 * ah->ah_coverage_class;277		ath5k_hw_set_ifs_intervals(ah, slot_time);278	}279 280	if (changes & BSS_CHANGED_ASSOC) {281		avf->assoc = vif->cfg.assoc;282		if (vif->cfg.assoc)283			ah->assoc = vif->cfg.assoc;284		else285			ah->assoc = ath5k_any_vif_assoc(ah);286 287		if (ah->opmode == NL80211_IFTYPE_STATION)288			ath5k_set_beacon_filter(hw, ah->assoc);289		ath5k_hw_set_ledstate(ah, ah->assoc ?290			AR5K_LED_ASSOC : AR5K_LED_INIT);291		if (vif->cfg.assoc) {292			ATH5K_DBG(ah, ATH5K_DEBUG_ANY,293				  "Bss Info ASSOC %d, bssid: %pM\n",294				  vif->cfg.aid, common->curbssid);295			common->curaid = vif->cfg.aid;296			ath5k_hw_set_bssid(ah);297			/* Once ANI is available you would start it here */298		}299	}300 301	if (changes & BSS_CHANGED_BEACON) {302		spin_lock_bh(&ah->block);303		ath5k_beacon_update(hw, vif);304		spin_unlock_bh(&ah->block);305	}306 307	if (changes & BSS_CHANGED_BEACON_ENABLED)308		ah->enable_beacon = bss_conf->enable_beacon;309 310	if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |311		       BSS_CHANGED_BEACON_INT))312		ath5k_beacon_config(ah);313 314	mutex_unlock(&ah->lock);315}316 317 318static u64319ath5k_prepare_multicast(struct ieee80211_hw *hw,320			struct netdev_hw_addr_list *mc_list)321{322	u32 mfilt[2], val;323	u8 pos;324	struct netdev_hw_addr *ha;325 326	mfilt[0] = 0;327	mfilt[1] = 0;328 329	netdev_hw_addr_list_for_each(ha, mc_list) {330		/* calculate XOR of eight 6-bit values */331		val = get_unaligned_le32(ha->addr + 0);332		pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;333		val = get_unaligned_le32(ha->addr + 3);334		pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;335		pos &= 0x3f;336		mfilt[pos / 32] |= (1 << (pos % 32));337		/* XXX: we might be able to just do this instead,338		* but not sure, needs testing, if we do use this we'd339		* need to inform below not to reset the mcast */340		/* ath5k_hw_set_mcast_filterindex(ah,341		 *      ha->addr[5]); */342	}343 344	return ((u64)(mfilt[1]) << 32) | mfilt[0];345}346 347 348/*349 * o always accept unicast, broadcast, and multicast traffic350 * o multicast traffic for all BSSIDs will be enabled if mac80211351 *   says it should be352 * o maintain current state of phy ofdm or phy cck error reception.353 *   If the hardware detects any of these type of errors then354 *   ath5k_hw_get_rx_filter() will pass to us the respective355 *   hardware filters to be able to receive these type of frames.356 * o probe request frames are accepted only when operating in357 *   hostap, adhoc, or monitor modes358 * o enable promiscuous mode according to the interface state359 * o accept beacons:360 *   - when operating in adhoc mode so the 802.11 layer creates361 *     node table entries for peers,362 *   - when operating in station mode for collecting rssi data when363 *     the station is otherwise quiet, or364 *   - when scanning365 */366static void367ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,368		       unsigned int *new_flags, u64 multicast)369{370#define SUPPORTED_FIF_FLAGS \371	(FIF_ALLMULTI | FIF_FCSFAIL | \372	FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \373	FIF_BCN_PRBRESP_PROMISC)374 375	struct ath5k_hw *ah = hw->priv;376	u32 mfilt[2], rfilt;377	struct ath5k_vif_iter_data iter_data; /* to count STA interfaces */378 379	mutex_lock(&ah->lock);380 381	mfilt[0] = multicast;382	mfilt[1] = multicast >> 32;383 384	/* Only deal with supported flags */385	*new_flags &= SUPPORTED_FIF_FLAGS;386 387	/* If HW detects any phy or radar errors, leave those filters on.388	 * Also, always enable Unicast, Broadcasts and Multicast389	 * XXX: move unicast, bssid broadcasts and multicast to mac80211 */390	rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |391		(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |392		AR5K_RX_FILTER_MCAST);393 394	/* Note, AR5K_RX_FILTER_MCAST is already enabled */395	if (*new_flags & FIF_ALLMULTI) {396		mfilt[0] =  ~0;397		mfilt[1] =  ~0;398	}399 400	/* This is the best we can do */401	if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))402		rfilt |= AR5K_RX_FILTER_PHYERR;403 404	/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons405	* and probes for any BSSID */406	if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))407		rfilt |= AR5K_RX_FILTER_BEACON;408 409	/* FIF_CONTROL doc says we should only pass on control frames for this410	 * station. This needs testing. I believe right now this411	 * enables *all* control frames, which is OK.. but412	 * we should see if we can improve on granularity */413	if (*new_flags & FIF_CONTROL)414		rfilt |= AR5K_RX_FILTER_CONTROL;415 416	/* Additional settings per mode -- this is per ath5k */417 418	/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */419 420	switch (ah->opmode) {421	case NL80211_IFTYPE_MESH_POINT:422		rfilt |= AR5K_RX_FILTER_CONTROL |423			 AR5K_RX_FILTER_BEACON |424			 AR5K_RX_FILTER_PROBEREQ |425			 AR5K_RX_FILTER_PROM;426		break;427	case NL80211_IFTYPE_AP:428	case NL80211_IFTYPE_ADHOC:429		rfilt |= AR5K_RX_FILTER_PROBEREQ |430			 AR5K_RX_FILTER_BEACON;431		break;432	case NL80211_IFTYPE_STATION:433		if (ah->assoc)434			rfilt |= AR5K_RX_FILTER_BEACON;435		break;436	default:437		break;438	}439 440	iter_data.hw_macaddr = NULL;441	iter_data.n_stas = 0;442	iter_data.need_set_hw_addr = false;443	ieee80211_iterate_active_interfaces_atomic(444		ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,445		ath5k_vif_iter, &iter_data);446 447	/* Set up RX Filter */448	if (iter_data.n_stas > 1) {449		/* If you have multiple STA interfaces connected to450		 * different APs, ARPs are not received (most of the time?)451		 * Enabling PROMISC appears to fix that problem.452		 */453		rfilt |= AR5K_RX_FILTER_PROM;454	}455 456	/* Set filters */457	ath5k_hw_set_rx_filter(ah, rfilt);458 459	/* Set multicast bits */460	ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);461	/* Set the cached hw filter flags, this will later actually462	 * be set in HW */463	ah->filter_flags = rfilt;464	/* Store current FIF filter flags */465	ah->fif_filter_flags = *new_flags;466 467	mutex_unlock(&ah->lock);468}469 470 471static int472ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,473	      struct ieee80211_vif *vif, struct ieee80211_sta *sta,474	      struct ieee80211_key_conf *key)475{476	struct ath5k_hw *ah = hw->priv;477	struct ath_common *common = ath5k_hw_common(ah);478	int ret = 0;479 480	if (ath5k_modparam_nohwcrypt)481		return -EOPNOTSUPP;482 483	if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT)484		return -EOPNOTSUPP;485 486	if (vif->type == NL80211_IFTYPE_ADHOC &&487	    (key->cipher == WLAN_CIPHER_SUITE_TKIP ||488	     key->cipher == WLAN_CIPHER_SUITE_CCMP) &&489	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {490		/* don't program group keys when using IBSS_RSN */491		return -EOPNOTSUPP;492	}493 494	switch (key->cipher) {495	case WLAN_CIPHER_SUITE_WEP40:496	case WLAN_CIPHER_SUITE_WEP104:497	case WLAN_CIPHER_SUITE_TKIP:498		break;499	case WLAN_CIPHER_SUITE_CCMP:500		if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)501			break;502		return -EOPNOTSUPP;503	default:504		return -EOPNOTSUPP;505	}506 507	mutex_lock(&ah->lock);508 509	switch (cmd) {510	case SET_KEY:511		ret = ath_key_config(common, vif, sta, key);512		if (ret >= 0) {513			key->hw_key_idx = ret;514			/* push IV and Michael MIC generation to stack */515			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;516			if (key->cipher == WLAN_CIPHER_SUITE_TKIP)517				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;518			if (key->cipher == WLAN_CIPHER_SUITE_CCMP)519				key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;520			ret = 0;521		}522		break;523	case DISABLE_KEY:524		ath_key_delete(common, key->hw_key_idx);525		break;526	default:527		ret = -EINVAL;528	}529 530	mutex_unlock(&ah->lock);531	return ret;532}533 534 535static void536ath5k_sw_scan_start(struct ieee80211_hw *hw,537		    struct ieee80211_vif *vif,538		    const u8 *mac_addr)539{540	struct ath5k_hw *ah = hw->priv;541	if (!ah->assoc)542		ath5k_hw_set_ledstate(ah, AR5K_LED_SCAN);543}544 545 546static void547ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)548{549	struct ath5k_hw *ah = hw->priv;550	ath5k_hw_set_ledstate(ah, ah->assoc ?551		AR5K_LED_ASSOC : AR5K_LED_INIT);552}553 554 555static int556ath5k_get_stats(struct ieee80211_hw *hw,557		struct ieee80211_low_level_stats *stats)558{559	struct ath5k_hw *ah = hw->priv;560 561	/* Force update */562	ath5k_hw_update_mib_counters(ah);563 564	stats->dot11ACKFailureCount = ah->stats.ack_fail;565	stats->dot11RTSFailureCount = ah->stats.rts_fail;566	stats->dot11RTSSuccessCount = ah->stats.rts_ok;567	stats->dot11FCSErrorCount = ah->stats.fcs_error;568 569	return 0;570}571 572 573static int574ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,575	      unsigned int link_id, u16 queue,576	      const struct ieee80211_tx_queue_params *params)577{578	struct ath5k_hw *ah = hw->priv;579	struct ath5k_txq_info qi;580	int ret = 0;581 582	if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)583		return 0;584 585	mutex_lock(&ah->lock);586 587	ath5k_hw_get_tx_queueprops(ah, queue, &qi);588 589	qi.tqi_aifs = params->aifs;590	qi.tqi_cw_min = params->cw_min;591	qi.tqi_cw_max = params->cw_max;592	qi.tqi_burst_time = params->txop * 32;593 594	ATH5K_DBG(ah, ATH5K_DEBUG_ANY,595		  "Configure tx [queue %d],  "596		  "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",597		  queue, params->aifs, params->cw_min,598		  params->cw_max, params->txop);599 600	if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {601		ATH5K_ERR(ah,602			  "Unable to update hardware queue %u!\n", queue);603		ret = -EIO;604	} else605		ath5k_hw_reset_tx_queue(ah, queue);606 607	mutex_unlock(&ah->lock);608 609	return ret;610}611 612 613static u64614ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)615{616	struct ath5k_hw *ah = hw->priv;617 618	return ath5k_hw_get_tsf64(ah);619}620 621 622static void623ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)624{625	struct ath5k_hw *ah = hw->priv;626 627	ath5k_hw_set_tsf64(ah, tsf);628}629 630 631static void632ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)633{634	struct ath5k_hw *ah = hw->priv;635 636	/*637	 * in IBSS mode we need to update the beacon timers too.638	 * this will also reset the TSF if we call it with 0639	 */640	if (ah->opmode == NL80211_IFTYPE_ADHOC)641		ath5k_beacon_update_timers(ah, 0);642	else643		ath5k_hw_reset_tsf(ah);644}645 646 647static int648ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)649{650	struct ath5k_hw *ah = hw->priv;651	struct ieee80211_conf *conf = &hw->conf;652	struct ath_common *common = ath5k_hw_common(ah);653	struct ath_cycle_counters *cc = &common->cc_survey;654	unsigned int div = common->clockrate * 1000;655 656	if (idx != 0)657		return -ENOENT;658 659	spin_lock_bh(&common->cc_lock);660	ath_hw_cycle_counters_update(common);661	if (cc->cycles > 0) {662		ah->survey.time += cc->cycles / div;663		ah->survey.time_busy += cc->rx_busy / div;664		ah->survey.time_rx += cc->rx_frame / div;665		ah->survey.time_tx += cc->tx_frame / div;666	}667	memset(cc, 0, sizeof(*cc));668	spin_unlock_bh(&common->cc_lock);669 670	memcpy(survey, &ah->survey, sizeof(*survey));671 672	survey->channel = conf->chandef.chan;673	survey->noise = ah->ah_noise_floor;674	survey->filled = SURVEY_INFO_NOISE_DBM |675			SURVEY_INFO_IN_USE |676			SURVEY_INFO_TIME |677			SURVEY_INFO_TIME_BUSY |678			SURVEY_INFO_TIME_RX |679			SURVEY_INFO_TIME_TX;680 681	return 0;682}683 684 685/**686 * ath5k_set_coverage_class - Set IEEE 802.11 coverage class687 *688 * @hw: struct ieee80211_hw pointer689 * @coverage_class: IEEE 802.11 coverage class number690 *691 * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given692 * coverage class. The values are persistent, they are restored after device693 * reset.694 */695static void696ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)697{698	struct ath5k_hw *ah = hw->priv;699 700	mutex_lock(&ah->lock);701	ath5k_hw_set_coverage_class(ah, coverage_class);702	mutex_unlock(&ah->lock);703}704 705 706static int707ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)708{709	struct ath5k_hw *ah = hw->priv;710 711	if (tx_ant == 1 && rx_ant == 1)712		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);713	else if (tx_ant == 2 && rx_ant == 2)714		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);715	else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)716		ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);717	else718		return -EINVAL;719	return 0;720}721 722 723static int724ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)725{726	struct ath5k_hw *ah = hw->priv;727 728	switch (ah->ah_ant_mode) {729	case AR5K_ANTMODE_FIXED_A:730		*tx_ant = 1; *rx_ant = 1; break;731	case AR5K_ANTMODE_FIXED_B:732		*tx_ant = 2; *rx_ant = 2; break;733	case AR5K_ANTMODE_DEFAULT:734		*tx_ant = 3; *rx_ant = 3; break;735	}736	return 0;737}738 739 740static void ath5k_get_ringparam(struct ieee80211_hw *hw,741				u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)742{743	struct ath5k_hw *ah = hw->priv;744 745	*tx = ah->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max;746 747	*tx_max = ATH5K_TXQ_LEN_MAX;748	*rx = *rx_max = ATH_RXBUF;749}750 751 752static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx)753{754	struct ath5k_hw *ah = hw->priv;755	u16 qnum;756 757	/* only support setting tx ring size for now */758	if (rx != ATH_RXBUF)759		return -EINVAL;760 761	/* restrict tx ring size min/max */762	if (!tx || tx > ATH5K_TXQ_LEN_MAX)763		return -EINVAL;764 765	for (qnum = 0; qnum < ARRAY_SIZE(ah->txqs); qnum++) {766		if (!ah->txqs[qnum].setup)767			continue;768		if (ah->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN ||769		    ah->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX)770			continue;771 772		ah->txqs[qnum].txq_max = tx;773		if (ah->txqs[qnum].txq_len >= ah->txqs[qnum].txq_max)774			ieee80211_stop_queue(hw, ah->txqs[qnum].qnum);775	}776 777	return 0;778}779 780 781const struct ieee80211_ops ath5k_hw_ops = {782	.add_chanctx = ieee80211_emulate_add_chanctx,783	.remove_chanctx = ieee80211_emulate_remove_chanctx,784	.change_chanctx = ieee80211_emulate_change_chanctx,785	.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,786	.tx			= ath5k_tx,787	.wake_tx_queue		= ieee80211_handle_wake_tx_queue,788	.start			= ath5k_start,789	.stop			= ath5k_stop,790	.add_interface		= ath5k_add_interface,791	/* .change_interface	= not implemented */792	.remove_interface	= ath5k_remove_interface,793	.config			= ath5k_config,794	.bss_info_changed	= ath5k_bss_info_changed,795	.prepare_multicast	= ath5k_prepare_multicast,796	.configure_filter	= ath5k_configure_filter,797	/* .set_tim		= not implemented */798	.set_key		= ath5k_set_key,799	/* .update_tkip_key	= not implemented */800	/* .hw_scan		= not implemented */801	.sw_scan_start		= ath5k_sw_scan_start,802	.sw_scan_complete	= ath5k_sw_scan_complete,803	.get_stats		= ath5k_get_stats,804	/* .set_frag_threshold	= not implemented */805	/* .set_rts_threshold	= not implemented */806	/* .sta_add		= not implemented */807	/* .sta_remove		= not implemented */808	/* .sta_notify		= not implemented */809	.conf_tx		= ath5k_conf_tx,810	.get_tsf		= ath5k_get_tsf,811	.set_tsf		= ath5k_set_tsf,812	.reset_tsf		= ath5k_reset_tsf,813	/* .tx_last_beacon	= not implemented */814	/* .ampdu_action	= not needed */815	.get_survey		= ath5k_get_survey,816	.set_coverage_class	= ath5k_set_coverage_class,817	/* .rfkill_poll		= not implemented */818	/* .flush		= not implemented */819	/* .channel_switch	= not implemented */820	/* .napi_poll		= not implemented */821	.set_antenna		= ath5k_set_antenna,822	.get_antenna		= ath5k_get_antenna,823	.set_ringparam		= ath5k_set_ringparam,824	.get_ringparam		= ath5k_get_ringparam,825};826