Skip to content

Commit

Permalink
ath5k: Implement antenna control
Browse files Browse the repository at this point in the history
* 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: Nick Kossifidis <mickflemm@gmail.com>
 Signed-off-by: Bob Copeland <me@bobcopeland.com>

Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Nick Kossifidis authored and John W. Linville committed May 6, 2009
1 parent 6f5f39c commit 2bed03e
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 51 deletions.
25 changes: 20 additions & 5 deletions drivers/net/wireless/ath/ath5k/ath5k.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/ath/ath5k/attach.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 50 additions & 16 deletions drivers/net/wireless/ath/ath5k/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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 (antenna == 0)
antenna = sc->bsent & 4 ? 2 : 1;
}

/*
* 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 (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
Expand Down Expand Up @@ -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;
Expand All @@ -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 \
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/wireless/ath/ath5k/eeprom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) |
Expand Down
11 changes: 6 additions & 5 deletions drivers/net/wireless/ath/ath5k/eeprom.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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

0 comments on commit 2bed03e

Please sign in to comment.