Commit 2bed03eb authored by Nick Kossifidis's avatar Nick Kossifidis Committed by John W. Linville
Browse files

ath5k: Implement antenna control



* Add code to support the various antenna scenarios supported by hw

 * For now hardcode the default scenario (single or dual omnis with
 tx/rx diversity working and tx antenna handled by session -hw keeps
 track on which antenna it got ack from each ap/station and maps each
 ap/station to one of the antennas-).

 Signed-off-by: default avatarNick Kossifidis <mickflemm@gmail.com>
 Signed-off-by: default avatarBob Copeland <me@bobcopeland.com>

Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 6f5f39c9
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -209,7 +209,6 @@
#define AR5K_TUNE_MAX_TXPOWER			63
#define AR5K_TUNE_DEFAULT_TXPOWER		25
#define AR5K_TUNE_TPC_TXPOWER			false
#define AR5K_TUNE_ANT_DIVERSITY			true
#define AR5K_TUNE_HWTXTRIES			4

#define AR5K_INIT_CARR_SENSE_EN			1
@@ -420,6 +419,17 @@ enum ath5k_driver_mode {
	AR5K_MODE_MAX		=	5
};

enum ath5k_ant_mode {
	AR5K_ANTMODE_DEFAULT	= 0,	/* default antenna setup */
	AR5K_ANTMODE_FIXED_A	= 1,	/* only antenna A is present */
	AR5K_ANTMODE_FIXED_B	= 2,	/* only antenna B is present */
	AR5K_ANTMODE_SINGLE_AP	= 3,	/* sta locked on a single ap */
	AR5K_ANTMODE_SECTOR_AP	= 4,	/* AP with tx antenna set on tx desc */
	AR5K_ANTMODE_SECTOR_STA	= 5,	/* STA with tx antenna set on tx desc */
	AR5K_ANTMODE_DEBUG	= 6,	/* Debug mode -A -> Rx, B-> Tx- */
	AR5K_ANTMODE_MAX,
};


/****************\
  TX DEFINITIONS
@@ -1051,8 +1061,11 @@ struct ath5k_hw {
	bool			ah_software_retry;
	u32			ah_limit_tx_retries;

	u32			ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
	bool			ah_ant_diversity;
	/* Antenna Control */
	u32			ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
	u8			ah_ant_mode;
	u8			ah_tx_ant;
	u8			ah_def_ant;

	u8			ah_sta_id[ETH_ALEN];

@@ -1267,9 +1280,11 @@ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
/* Misc PHY functions */
extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
/* Antenna control */
extern void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode);
extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant);
extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
/* TX power setup */
extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower);
extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
+0 −1
Original line number Diff line number Diff line
@@ -133,7 +133,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
	ah->ah_cw_min = AR5K_TUNE_CWMIN;
	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
	ah->ah_software_retry = false;
	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;

	/*
	 * Set the mac version based on the pci id
+50 −16
Original line number Diff line number Diff line
@@ -1279,7 +1279,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
		ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
		(sc->power_level * 2),
		hw_rate,
		info->control.rates[0].count, keyidx, 0, flags,
		info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
		cts_rate, duration);
	if (ret)
		goto err_unmap;
@@ -2009,7 +2009,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
	struct	ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct ath5k_hw *ah = sc->ah;
	struct ath5k_desc *ds;
	int ret, antenna = 0;
	int ret = 0;
	u8 antenna;
	u32 flags;

	bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
@@ -2023,23 +2024,35 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
	}

	ds = bf->desc;
	antenna = ah->ah_tx_ant;

	flags = AR5K_TXDESC_NOACK;
	if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) {
		ds->ds_link = bf->daddr;	/* self-linked */
		flags |= AR5K_TXDESC_VEOL;
		/*
		 * Let hardware handle antenna switching if txantenna is not set
		 */
	} else {
	} else
		ds->ds_link = 0;

	/*
		 * Switch antenna every 4 beacons if txantenna is not set
		 * XXX assumes two antennas
	 * If we use multiple antennas on AP and use
	 * the Sectored AP scenario, switch antenna every
	 * 4 beacons to make sure everybody hears our AP.
	 * When a client tries to associate, hw will keep
	 * track of the tx antenna to be used for this client
	 * automaticaly, based on ACKed packets.
	 *
	 * Note: AP still listens and transmits RTS on the
	 * default antenna which is supposed to be an omni.
	 *
	 * Note2: On sectored scenarios it's possible to have
	 * multiple antennas (1omni -the default- and 14 sectors)
	 * so if we choose to actually support this mode we need
	 * to allow user to set how many antennas we have and tweak
	 * the code below to send beacons on all of them.
	 */
		if (antenna == 0)
	if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP)
		antenna = sc->bsent & 4 ? 2 : 1;
	}


	/* FIXME: If we are in g mode and rate is a CCK rate
	 * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta
@@ -2752,12 +2765,16 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
	struct ath5k_softc *sc = hw->priv;
	struct ath5k_hw *ah = sc->ah;
	struct ieee80211_conf *conf = &hw->conf;
	int ret;
	int ret = 0;

	mutex_lock(&sc->lock);

	sc->bintval = conf->beacon_int;

	ret = ath5k_chan_set(sc, conf->channel);
	if (ret < 0)
		return ret;

	if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
	(sc->power_level != conf->power_level)) {
		sc->power_level = conf->power_level;
@@ -2766,10 +2783,27 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
		ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
	}

	ret = ath5k_chan_set(sc, conf->channel);
	/* TODO:
	 * 1) Move this on config_interface and handle each case
	 * separately eg. when we have only one STA vif, use
	 * AR5K_ANTMODE_SINGLE_AP
	 *
	 * 2) Allow the user to change antenna mode eg. when only
	 * one antenna is present
	 *
	 * 3) Allow the user to set default/tx antenna when possible
	 *
	 * 4) Default mode should handle 90% of the cases, together
	 * with fixed a/b and single AP modes we should be able to
	 * handle 99%. Sectored modes are extreme cases and i still
	 * haven't found a usage for them. If we decide to support them,
	 * then we must allow the user to set how many tx antennas we
	 * have available
	 */
	ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);

	mutex_unlock(&sc->lock);
	return ret;
	return 0;
}

#define SUPPORTED_FIF_FLAGS \
+4 −4
Original line number Diff line number Diff line
@@ -208,16 +208,16 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
	ee->ee_ant_control[mode][i++]	= val & 0x3f;

	/* Get antenna modes */
	ah->ah_antenna[mode][0] =
	/* Get antenna switch tables */
	ah->ah_ant_ctl[mode][AR5K_ANT_CTL] =
	    (ee->ee_ant_control[mode][0] << 4);
	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
	ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_A] =
	     ee->ee_ant_control[mode][1] 	|
	    (ee->ee_ant_control[mode][2] << 6) 	|
	    (ee->ee_ant_control[mode][3] << 12) |
	    (ee->ee_ant_control[mode][4] << 18) |
	    (ee->ee_ant_control[mode][5] << 24);
	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
	ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] =
	     ee->ee_ant_control[mode][6] 	|
	    (ee->ee_ant_control[mode][7] << 6) 	|
	    (ee->ee_ant_control[mode][8] << 12) |
+6 −5
Original line number Diff line number Diff line
@@ -240,11 +240,11 @@ enum ath5k_eeprom_freq_bands{
#define AR5K_EEPROM_READ_HDR(_o, _v)					\
	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\

enum ath5k_ant_setting {
	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
	AR5K_ANT_MAX		= 3,
enum ath5k_ant_table {
	AR5K_ANT_CTL		= 0,	/* Idle switch table settings */
	AR5K_ANT_SWTABLE_A	= 1,	/* Switch table for antenna A */
	AR5K_ANT_SWTABLE_B	= 2,	/* Switch table for antenna B */
	AR5K_ANT_MAX,
};

enum ath5k_ctl_mode {
@@ -461,6 +461,7 @@ struct ath5k_eeprom_info {
	/* Spur mitigation data (fbin values for spur channels) */
	u16	ee_spur_chans[AR5K_EEPROM_N_SPUR_CHANS][AR5K_EEPROM_N_FREQ_BANDS];

	/* Antenna raw switch tables */
	u32	ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
};
Loading