Commit 4b7679a5 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: clean up rate control API

Long awaited, hard work. This patch totally cleans up the rate control
API to remove the requirement to include internal headers outside of
net/mac80211/.

There's one internal use in the PID algorithm left for mesh networking,
we'll have to figure out a way to clean that one up and decide how to
do the peer link evaluation, possibly independent of the rate control
algorithm or via new API.

Additionally, ath9k is left using the cross-inclusion hack for now, we
will add new API where necessary to make this work properly, but right
now I'm not expert enough to do it. It's still off better than before.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2ff6a6d4
......@@ -20,6 +20,7 @@
*/
#include "core.h"
/* FIXME: remove this include! */
#include "../net/mac80211/rate.h"
static u32 tx_triglevel_max;
......@@ -1812,20 +1813,18 @@ static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv)
}
static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta)
static void ath_setup_rates(struct ath_softc *sc,
struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta,
struct ath_rate_node *rc_priv)
{
struct ieee80211_supported_band *sband;
struct ieee80211_hw *hw = local_to_hw(local);
struct ath_softc *sc = hw->priv;
struct ath_rate_node *rc_priv = sta->rate_ctrl_priv;
int i, j = 0;
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
for (i = 0; i < sband->n_bitrates; i++) {
if (sta->sta.supp_rates[local->hw.conf.channel->band] & BIT(i)) {
if (sta->supp_rates[sband->band] & BIT(i)) {
rc_priv->neg_rates.rs_rates[j]
= (sband->bitrates[i].bitrate * 2) / 10;
j++;
......@@ -1852,19 +1851,17 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
}
/* Rate Control callbacks */
static void ath_tx_status(void *priv, struct net_device *dev,
static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
{
struct ath_softc *sc = priv;
struct ath_tx_info_priv *tx_info_priv;
struct ath_node *an;
struct sta_info *sta;
struct ieee80211_local *local;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
__le16 fc;
local = hw_to_local(sc->hw);
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
......@@ -1873,8 +1870,7 @@ static void ath_tx_status(void *priv, struct net_device *dev,
an = ath_node_find(sc, hdr->addr1);
spin_unlock_bh(&sc->node_lock);
sta = sta_info_get(local, hdr->addr1);
if (!an || !sta || !ieee80211_is_data(fc)) {
if (!an || !priv_sta || !ieee80211_is_data(fc)) {
if (tx_info->driver_data[0] != NULL) {
kfree(tx_info->driver_data[0]);
tx_info->driver_data[0] = NULL;
......@@ -1882,24 +1878,22 @@ static void ath_tx_status(void *priv, struct net_device *dev,
return;
}
if (tx_info->driver_data[0] != NULL) {
ath_rate_tx_complete(sc, an, sta->rate_ctrl_priv, tx_info_priv);
ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
kfree(tx_info->driver_data[0]);
tx_info->driver_data[0] = NULL;
}
}
static void ath_tx_aggr_resp(struct ath_softc *sc,
struct sta_info *sta,
struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta,
struct ath_node *an,
u8 tidno)
{
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_local *local;
struct ath_atx_tid *txtid;
struct ieee80211_supported_band *sband;
u16 buffersize = 0;
int state;
DECLARE_MAC_BUF(mac);
struct sta_info *si;
if (!(sc->sc_flags & SC_OP_TXAGGR))
return;
......@@ -1908,11 +1902,16 @@ static void ath_tx_aggr_resp(struct ath_softc *sc,
if (!txtid->paused)
return;
local = hw_to_local(sc->hw);
sband = hw->wiphy->bands[hw->conf.channel->band];
/*
* XXX: This is entirely busted, we aren't supposed to
* access the sta from here because it's internal
* to mac80211, and looking at the state without
* locking is wrong too.
*/
si = container_of(sta, struct sta_info, sta);
buffersize = IEEE80211_MIN_AMPDU_BUF <<
sband->ht_info.ampdu_factor; /* FIXME */
state = sta->ampdu_mlme.tid_state_tx[tidno];
state = si->ampdu_mlme.tid_state_tx[tidno];
if (state & HT_ADDBA_RECEIVED_MSK) {
txtid->addba_exchangecomplete = 1;
......@@ -1928,18 +1927,15 @@ static void ath_tx_aggr_resp(struct ath_softc *sc,
}
}
static void ath_get_rate(void *priv, struct net_device *dev,
struct ieee80211_supported_band *sband,
struct sk_buff *skb,
struct rate_selection *sel)
static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb, struct rate_selection *sel)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ath_softc *sc = (struct ath_softc *)priv;
struct ath_softc *sc = priv;
struct ieee80211_hw *hw = sc->hw;
struct ath_tx_info_priv *tx_info_priv;
struct ath_rate_node *ath_rc_priv;
struct ath_rate_node *ath_rc_priv = priv_sta;
struct ath_node *an;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
int is_probe = FALSE, chk, ret;
......@@ -1955,8 +1951,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
ASSERT(tx_info->driver_data[0] != NULL);
tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
sta = sta_info_get(local, hdr->addr1);
lowest_idx = rate_lowest_index(local, sband, sta);
lowest_idx = rate_lowest_index(sband, sta);
tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
/* lowest rate for management and multicast/broadcast frames */
if (!ieee80211_is_data(fc) ||
......@@ -1965,8 +1960,6 @@ static void ath_get_rate(void *priv, struct net_device *dev,
return;
}
ath_rc_priv = sta->rate_ctrl_priv;
/* Find tx rate for unicast frames */
ath_rate_findrate(sc, ath_rc_priv,
ATH_11N_TXMAXTRY, 4,
......@@ -1975,8 +1968,7 @@ static void ath_get_rate(void *priv, struct net_device *dev,
&is_probe,
false);
if (is_probe)
sel->probe_idx = ((struct ath_tx_ratectrl *)
sta->rate_ctrl_priv)->probe_rate;
sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
/* Ratecontrol sometimes returns invalid rate index */
if (tx_info_priv->rcs[0].rix != 0xff)
......@@ -2020,37 +2012,31 @@ static void ath_get_rate(void *priv, struct net_device *dev,
__func__,
print_mac(mac, hdr->addr1));
} else if (chk == AGGR_EXCHANGE_PROGRESS)
ath_tx_aggr_resp(sc, sta, an, tid);
ath_tx_aggr_resp(sc, sband, sta, an, tid);
}
}
}
static void ath_rate_init(void *priv, void *priv_sta,
struct ieee80211_local *local,
struct sta_info *sta)
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
struct ieee80211_supported_band *sband;
struct ieee80211_hw *hw = local_to_hw(local);
struct ieee80211_conf *conf = &local->hw.conf;
struct ath_softc *sc = hw->priv;
struct ath_softc *sc = priv;
struct ath_rate_node *ath_rc_priv = priv_sta;
int i, j = 0;
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
ath_setup_rates(local, sta);
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
ath_setup_rates(sc, sband, sta, ath_rc_priv);
if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
for (i = 0; i < MCS_SET_SIZE; i++) {
if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
if (j == ATH_RATE_MAX)
break;
}
ath_rc_priv->neg_ht_rates.rs_nrates = j;
}
ath_rc_node_update(hw, priv_sta);
ath_rc_node_update(sc->hw, priv_sta);
}
static void ath_rate_clear(void *priv)
......@@ -2058,13 +2044,12 @@ static void ath_rate_clear(void *priv)
return;
}
static void *ath_rate_alloc(struct ieee80211_local *local)
static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{
struct ieee80211_hw *hw = local_to_hw(local);
struct ath_softc *sc = hw->priv;
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
return local->hw.priv;
return hw->priv;
}
static void ath_rate_free(void *priv)
......@@ -2072,7 +2057,7 @@ static void ath_rate_free(void *priv)
return;
}
static void *ath_rate_alloc_sta(void *priv, gfp_t gfp)
static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{
struct ath_softc *sc = priv;
struct ath_vap *avp = sc->sc_vaps[0];
......@@ -2092,7 +2077,8 @@ static void *ath_rate_alloc_sta(void *priv, gfp_t gfp)
return rate_priv;
}
static void ath_rate_free_sta(void *priv, void *priv_sta)
static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
void *priv_sta)
{
struct ath_rate_node *rate_priv = priv_sta;
struct ath_softc *sc = priv;
......@@ -2111,7 +2097,7 @@ static struct rate_control_ops ath_rate_ops = {
.alloc = ath_rate_alloc,
.free = ath_rate_free,
.alloc_sta = ath_rate_alloc_sta,
.free_sta = ath_rate_free_sta
.free_sta = ath_rate_free_sta,
};
int ath_rate_control_register(void)
......
......@@ -36,8 +36,6 @@
#include <linux/workqueue.h>
#include "../net/mac80211/rate.h"
#include "iwl-3945.h"
#define RS_NAME "iwl-3945-rs"
......@@ -319,10 +317,10 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
}
}
static void rs_rate_init(void *priv_rate, void *priv_sta,
struct ieee80211_local *local, struct sta_info *sta)
static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
struct iwl3945_rs_sta *rs_sta = (void *)sta->rate_ctrl_priv;
struct iwl3945_rs_sta *rs_sta = priv_sta;
int i;
IWL_DEBUG_RATE("enter\n");
......@@ -333,22 +331,22 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
* after assoc.. */
for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
if (sta->sta.supp_rates[local->hw.conf.channel->band] & (1 << i)) {
if (sta->supp_rates[sband->band] & (1 << i)) {
rs_sta->last_txrate_idx = i;
break;
}
}
/* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
if (sband->band == IEEE80211_BAND_5GHZ)
rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
IWL_DEBUG_RATE("leave\n");
}
static void *rs_alloc(struct ieee80211_local *local)
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{
return local->hw.priv;
return hw->priv;
}
/* rate scale requires free function to be implemented */
......@@ -356,17 +354,24 @@ static void rs_free(void *priv)
{
return;
}
static void rs_clear(void *priv)
{
return;
}
static void *rs_alloc_sta(void *priv, gfp_t gfp)
static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{
struct iwl3945_rs_sta *rs_sta;
struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
int i;
/*
* XXX: If it's using sta->drv_priv anyway, it might
* as well just put all the information there.
*/
IWL_DEBUG_RATE("enter\n");
rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp);
......@@ -375,6 +380,8 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp)
return NULL;
}
psta->rs_sta = rs_sta;
spin_lock_init(&rs_sta->lock);
rs_sta->start_rate = IWL_RATE_INVALID;
......@@ -400,10 +407,14 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp)
return rs_sta;
}
static void rs_free_sta(void *priv, void *priv_sta)
static void rs_free_sta(void *priv, struct ieee80211_sta *sta,
void *priv_sta)
{
struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
struct iwl3945_rs_sta *rs_sta = priv_sta;
psta->rs_sta = NULL;
IWL_DEBUG_RATE("enter\n");
del_timer_sync(&rs_sta->rate_scale_flush);
kfree(rs_sta);
......@@ -445,26 +456,19 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
* NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by
* the hardware for each rate.
*/
static void rs_tx_status(void *priv_rate,
struct net_device *dev,
static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
{
u8 retries, current_count;
int scale_rate_index, first_index, last_index;
unsigned long flags;
struct sta_info *sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iwl3945_rs_sta *rs_sta;
struct ieee80211_supported_band *sband;
struct iwl3945_rs_sta *rs_sta = priv_sta;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE("enter\n");
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
retries = info->status.retry_count;
first_index = sband->bitrates[info->tx_rate_idx].hw_value;
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
......@@ -472,17 +476,11 @@ static void rs_tx_status(void *priv_rate,
return;
}
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
if (!sta || !sta->rate_ctrl_priv) {
rcu_read_unlock();
if (!priv_sta) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
return;
}
rs_sta = (void *)sta->rate_ctrl_priv;
rs_sta->tx_packets++;
scale_rate_index = first_index;
......@@ -549,8 +547,6 @@ static void rs_tx_status(void *priv_rate,
spin_unlock_irqrestore(&rs_sta->lock, flags);
rcu_read_unlock();
IWL_DEBUG_RATE("leave\n");
return;
......@@ -634,16 +630,15 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
* rate table and must reference the driver allocated rate table
*
*/
static void rs_get_rate(void *priv_rate, struct net_device *dev,
struct ieee80211_supported_band *sband,
struct sk_buff *skb,
struct rate_selection *sel)
static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb, struct rate_selection *sel)
{
u8 low = IWL_RATE_INVALID;
u8 high = IWL_RATE_INVALID;
u16 high_low;
int index;
struct iwl3945_rs_sta *rs_sta;
struct iwl3945_rs_sta *rs_sta = priv_sta;
struct iwl3945_rate_scale_data *window = NULL;
int current_tpt = IWL_INV_TPT;
int low_tpt = IWL_INV_TPT;
......@@ -651,34 +646,25 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
u32 fail_count;
s8 scale_action = 0;
unsigned long flags;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct sta_info *sta;
u16 fc, rate_mask;
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
DECLARE_MAC_BUF(mac);
IWL_DEBUG_RATE("enter\n");
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
* rate. */
fc = le16_to_cpu(hdr->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) {
!sta || !priv_sta) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
sel->rate_idx = rate_lowest_index(local, sband, sta);
rcu_read_unlock();
sel->rate_idx = rate_lowest_index(sband, sta);
return;
}
rs_sta = (void *)sta->rate_ctrl_priv;
rate_mask = sta->sta.supp_rates[sband->band];
rate_mask = sta->supp_rates[sband->band];
index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
if (sband->band == IEEE80211_BAND_5GHZ)
......@@ -811,8 +797,6 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
else
sel->rate_idx = rs_sta->last_txrate_idx;
rcu_read_unlock();
IWL_DEBUG_RATE("leave: %d\n", index);
}
......@@ -829,114 +813,28 @@ static struct rate_control_ops rs_ops = {
.free_sta = rs_free_sta,
};
int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
{
struct ieee80211_local *local = hw_to_local(hw);
struct iwl3945_priv *priv = hw->priv;
struct iwl3945_rs_sta *rs_sta;
struct sta_info *sta;
unsigned long flags;
int count = 0, i;
u32 samples = 0, success = 0, good = 0;
unsigned long now = jiffies;
u32 max_time = 0;
rcu_read_lock();
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
if (sta)
IWL_DEBUG_RATE("leave - no private rate data!\n");
else
IWL_DEBUG_RATE("leave - no station!\n");
rcu_read_unlock();
return sprintf(buf, "station %d not found\n", sta_id);
}
rs_sta = (void *)sta->rate_ctrl_priv;
spin_lock_irqsave(&rs_sta->lock, flags);
i = IWL_RATE_54M_INDEX;
while (1) {
u64 mask;
int j;
count +=
sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2);
mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
buf[count++] =
(rs_sta->win[i].data & mask) ? '1' : '0';
samples += rs_sta->win[i].counter;
good += rs_sta->win[i].success_counter;
success += rs_sta->win[i].success_counter *
iwl3945_rates[i].ieee;
if (rs_sta->win[i].stamp) {
int delta =
jiffies_to_msecs(now - rs_sta->win[i].stamp);
if (delta > max_time)
max_time = delta;
count += sprintf(&buf[count], "%5dms\n", delta);
} else
buf[count++] = '\n';
j = iwl3945_get_prev_ieee_rate(i);
if (j == i)
break;
i = j;
}
spin_unlock_irqrestore(&rs_sta->lock, flags);
rcu_read_unlock();
/* Display the average rate of all samples taken.
*
* NOTE: We multiple # of samples by 2 since the IEEE measurement
* added from iwl3945_rates is actually 2X the rate */
if (samples)
count += sprintf(
&buf[count],
"\nAverage rate is %3d.%02dMbs over last %4dms\n"
"%3d%% success (%d good packets over %d tries)\n",
success / (2 * samples), (success * 5 / samples) % 10,
max_time, good * 100 / samples, good, samples);
else
count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
return count;
}
void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
{
struct iwl3945_priv *priv = hw->priv;
s32 rssi = 0;
unsigned long flags;
struct ieee80211_local *local = hw_to_local(hw);
struct iwl3945_rs_sta *rs_sta;
struct sta_info *sta;
struct ieee80211_sta *sta;
struct iwl3945_sta_priv *psta;
IWL_DEBUG_RATE("enter\n");
if (!local->rate_ctrl->ops->name ||
strcmp(local->rate_ctrl->ops->name, RS_NAME)) {
IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n");
IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n");
return;
}
rcu_read_lock();
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
psta = (void *) sta->drv_priv;
if (!sta || !psta) {
IWL_DEBUG_RATE("leave - no private rate data!\n");
rcu_read_unlock();
return;
}
rs_sta = (void *)sta->rate_ctrl_priv;
rs_sta = psta->rs_sta;
spin_lock_irqsave(&rs_sta->lock, flags);
......
......@@ -175,15 +175,6 @@ static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
return rate;
}
/**
* iwl3945_fill_rs_info - Fill an output text buffer with the rate representation
*
* NOTE: This is provided as a quick mechanism for a user to visualize
* the performance of the rate control algorithm and is not meant to be
* parsed software.
*/
extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
/**
* iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
*
......
......@@ -73,6 +73,10 @@ extern struct pci_device_id iwl3945_hw_card_ids[];
extern int iwl3945_param_hwcrypto;
extern int iwl3945_param_queues_num;
struct iwl3945_sta_priv {
struct iwl3945_rs_sta *rs_sta;
};
enum iwl3945_antenna {
IWL_ANTENNA_DIVERSITY,
IWL_ANTENNA_MAIN,