Commit a8679be2 authored by David S. Miller's avatar David S. Miller
parents 22f6dacd 9dfd6ba3
......@@ -500,5 +500,6 @@ source "drivers/net/wireless/b43legacy/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
endmenu
......@@ -58,3 +58,5 @@ obj-$(CONFIG_P54_COMMON) += p54/
obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_WL12XX) += wl12xx/
......@@ -1311,18 +1311,20 @@ static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
return 0;
}
static int adm8211_config_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
static void adm8211_bss_info_changed(struct ieee80211_hw *dev,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf,
u32 changes)
{
struct adm8211_priv *priv = dev->priv;
if (!(changes & BSS_CHANGED_BSSID))
return;
if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
adm8211_set_bssid(dev, conf->bssid);
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
}
return 0;
}
static void adm8211_configure_filter(struct ieee80211_hw *dev,
......@@ -1753,7 +1755,7 @@ static const struct ieee80211_ops adm8211_ops = {
.add_interface = adm8211_add_interface,
.remove_interface = adm8211_remove_interface,
.config = adm8211_config,
.config_interface = adm8211_config_interface,
.bss_info_changed = adm8211_bss_info_changed,
.configure_filter = adm8211_configure_filter,
.get_stats = adm8211_get_stats,
.get_tx_stats = adm8211_get_tx_stats,
......
......@@ -1965,13 +1965,18 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed)
return 0;
}
static int at76_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
static void at76_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf,
u32 changed)
{
struct at76_priv *priv = hw->priv;
at76_dbg(DBG_MAC80211, "%s():", __func__);
if (!(changed & BSS_CHANGED_BSSID))
return;
at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:");
mutex_lock(&priv->mtx);
......@@ -1983,8 +1988,6 @@ static int at76_config_interface(struct ieee80211_hw *hw,
at76_join(priv);
mutex_unlock(&priv->mtx);
return 0;
}
/* must be atomic */
......@@ -2076,7 +2079,7 @@ static const struct ieee80211_ops at76_ops = {
.add_interface = at76_add_interface,
.remove_interface = at76_remove_interface,
.config = at76_config,
.config_interface = at76_config_interface,
.bss_info_changed = at76_bss_info_changed,
.configure_filter = at76_configure_filter,
.start = at76_mac80211_start,
.stop = at76_mac80211_stop,
......
......@@ -207,6 +207,8 @@ enum ar9170_cmd {
#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44)
#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48)
#define AR9170_MAC_REG_AMPDU_SET (AR9170_MAC_REG_BASE + 0xba0)
#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00)
#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50)
......
......@@ -72,6 +72,24 @@ int ar9170_set_qos(struct ar9170 *ar)
return ar9170_regwrite_result();
}
static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity)
{
u32 val;
/* don't allow AMPDU density > 8us */
if (mpdudensity > 6)
return -EINVAL;
/* Watch out! Otus uses slightly different density values. */
val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0);
ar9170_regwrite_begin(ar);
ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val);
ar9170_regwrite_finish();
return ar9170_regwrite_result();
}
int ar9170_init_mac(struct ar9170 *ar)
{
ar9170_regwrite_begin(ar);
......@@ -265,9 +283,9 @@ int ar9170_set_operating_mode(struct ar9170 *ar)
case NL80211_IFTYPE_ADHOC:
pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS;
break;
/* case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP:
pm_mode |= AR9170_MAC_REG_POWERMGT_AP;
break;*/
break;
case NL80211_IFTYPE_WDS:
pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS;
break;
......@@ -296,6 +314,11 @@ int ar9170_set_operating_mode(struct ar9170 *ar)
if (err)
return err;
/* set AMPDU density to 8us. */
err = ar9170_set_ampdu_density(ar, 6);
if (err)
return err;
ar9170_regwrite_begin(ar);
ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode);
......@@ -316,9 +339,9 @@ int ar9170_set_beacon_timers(struct ar9170 *ar)
u32 v = 0;
u32 pretbtt = 0;
v |= ar->hw->conf.beacon_int;
if (ar->vif) {
v |= ar->vif->bss_conf.beacon_int;
switch (ar->vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
......@@ -326,7 +349,7 @@ int ar9170_set_beacon_timers(struct ar9170 *ar)
break;
case NL80211_IFTYPE_AP:
v |= BIT(24);
pretbtt = (ar->hw->conf.beacon_int - 6) << 16;
pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16;
break;
default:
break;
......
......@@ -151,8 +151,8 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
IEEE80211_HT_CAP_SGI_40 | \
IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = 3, /* ?? */ \
.ampdu_density = 7, /* ?? */ \
.ampdu_factor = 3, \
.ampdu_density = 6, \
.mcs = { \
.rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
}, \
......@@ -1337,7 +1337,7 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
goto out;
}
if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) {
if (changed & BSS_CHANGED_BEACON_INT) {
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
......@@ -1360,33 +1360,6 @@ out:
return err;
}
static int ar9170_op_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
struct ar9170 *ar = hw->priv;
int err = 0;
mutex_lock(&ar->mutex);
if (conf->changed & IEEE80211_IFCC_BSSID) {
memcpy(ar->bssid, conf->bssid, ETH_ALEN);
err = ar9170_set_operating_mode(ar);
}
if (conf->changed & IEEE80211_IFCC_BEACON) {
err = ar9170_update_beacon(ar);
if (err)
goto out;
err = ar9170_set_beacon_timers(ar);
}
out:
mutex_unlock(&ar->mutex);
return err;
}
static void ar9170_set_filters(struct work_struct *work)
{
struct ar9170 *ar = container_of(work, struct ar9170,
......@@ -1488,6 +1461,17 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&ar->mutex);
if (changed & BSS_CHANGED_BSSID) {
memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN);
err = ar9170_set_operating_mode(ar);
}
if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
err = ar9170_update_beacon(ar);
if (!err)
ar9170_set_beacon_timers(ar);
}
ar9170_regwrite_begin(ar);
if (changed & BSS_CHANGED_ASSOC) {
......@@ -1499,6 +1483,9 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
#endif /* CONFIG_AR9170_LEDS */
}
if (changed & BSS_CHANGED_BEACON_INT)
err = ar9170_set_beacon_timers(ar);
if (changed & BSS_CHANGED_HT) {
/* TODO */
err = 0;
......@@ -1793,7 +1780,6 @@ static const struct ieee80211_ops ar9170_ops = {
.add_interface = ar9170_op_add_interface,
.remove_interface = ar9170_op_remove_interface,
.config = ar9170_op_config,
.config_interface = ar9170_op_config_interface,
.configure_filter = ar9170_op_configure_filter,
.conf_tx = ar9170_conf_tx,
.bss_info_changed = ar9170_op_bss_info_changed,
......
......@@ -350,7 +350,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd,
goto err_unbuf;
}
if (outlen >= 0 && aru->readlen != outlen) {
if (aru->readlen != outlen) {
err = -EMSGSIZE;
goto err_unbuf;
}
......@@ -689,6 +689,9 @@ static int ar9170_usb_probe(struct usb_interface *intf,
aru->common.exec_cmd = ar9170_usb_exec_cmd;
aru->common.callback_cmd = ar9170_usb_callback_cmd;
#ifdef CONFIG_PM
udev->reset_resume = 1;
#endif
err = ar9170_usb_reset(aru);
if (err)
goto err_freehw;
......@@ -805,6 +808,7 @@ static struct usb_driver ar9170_driver = {
#ifdef CONFIG_PM
.suspend = ar9170_suspend,
.resume = ar9170_resume,
.reset_resume = ar9170_resume,
#endif /* CONFIG_PM */
};
......
......@@ -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];
......@@ -1100,11 +1113,12 @@ struct ath5k_hw {
/* Values in 0.25dB units */
s16 txp_min_pwr;
s16 txp_max_pwr;
/* Values in 0.5dB units */
s16 txp_offset;
s16 txp_ofdm;
/* Values in dB units */
s16 txp_cck_ofdm_pwr_delta;
s16 txp_cck_ofdm_gainf_delta;
/* Value in dB units */
s16 txp_cck_ofdm_pwr_delta;
} ah_txpower;
struct {
......@@ -1264,14 +1278,21 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann
/* PHY calibration */
extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
/* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
/* 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 ee_mode, u8 txpower);
extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
/*
* Functions used internaly
......
......@@ -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
......
......@@ -227,9 +227,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
static void ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
static int ath5k_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf);
static void ath5k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
......@@ -259,7 +256,6 @@ static const struct ieee80211_ops ath5k_hw_ops = {
.add_interface = ath5k_add_interface,
.remove_interface = ath5k_remove_interface,
.config = ath5k_config,
.config_interface = ath5k_config_interface,
.configure_filter = ath5k_configure_filter,
.set_key = ath5k_set_key,
.get_stats = ath5k_get_stats,
......@@ -520,6 +516,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
IEEE80211_HW_NOISE_DBM;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
......@@ -1282,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;
......@@ -1742,35 +1739,6 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
}
}
static void ath5k_tasklet_beacon(unsigned long data)
{
struct ath5k_softc *sc = (struct ath5k_softc *) data;
/*
* Software beacon alert--time to send a beacon.
*
* In IBSS mode we use this interrupt just to
* keep track of the next TBTT (target beacon
* transmission time) in order to detect wether
* automatic TSF updates happened.
*/
if (sc->opmode == NL80211_IFTYPE_ADHOC) {
/* XXX: only if VEOL suppported */
u64 tsf = ath5k_hw_get_tsf64(sc->ah);
sc->nexttbtt += sc->bintval;
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
"SWBA nexttbtt: %x hw_tu: %x "
"TSF: %llx\n",
sc->nexttbtt,
TSF_TO_TU(tsf),
(unsigned long long) tsf);
} else {
spin_lock(&sc->block);
ath5k_beacon_send(sc);
spin_unlock(&sc->block);
}
}
static void
ath5k_tasklet_rx(unsigned long data)
{
......@@ -2041,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,
......@@ -2055,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
......@@ -2124,7 +2105,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
sc->bmisscount++;
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
"missed %u consecutive beacons\n", sc->bmisscount);
if (sc->bmisscount > 3) { /* NB: 3 is a guess */
if (sc->bmisscount > 10) { /* NB: 10 is a guess */
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
"stuck beacon time (%u missed)\n",
sc->bmisscount);
......@@ -2145,10 +2126,12 @@ ath5k_beacon_send(struct ath5k_softc *sc)
* are still pending on the queue.
*/
if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq);
ATH5K_WARN(sc, "beacon queue %u didn't start/stop ?\n", sc->bhalq);
/* NB: hw still stops DMA, so proceed */
}
/* Note: Beacon buffer is updated on beacon_update when mac80211
* calls config_interface */
ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
ath5k_hw_start_tx_dma(ah, sc->bhalq);
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
......@@ -2305,6 +2288,35 @@ ath5k_beacon_config(struct ath5k_softc *sc)
ath5k_hw_set_imr(ah, sc->imask);
}
static void ath5k_tasklet_beacon(unsigned long data)
{
struct ath5k_softc *sc = (struct ath5k_softc *) data;
/*
* Software beacon alert--time to send a beacon.
*
* In IBSS mode we use this interrupt just to
* keep track of the next TBTT (target beacon
* transmission time) in order to detect wether
* automatic TSF updates happened.
*/
if (sc->opmode == NL80211_IFTYPE_ADHOC) {
/* XXX: only if VEOL suppported */
u64 tsf = ath5k_hw_get_tsf64(sc->ah);
sc->nexttbtt += sc->bintval;
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
"SWBA nexttbtt: %x hw_tu: %x "
"TSF: %llx\n",
sc->nexttbtt,
TSF_TO_TU(tsf),
(unsigned long long) tsf);
} else {
spin_lock(&sc->block);
ath5k_beacon_send(sc);
spin_unlock(&sc->block);
}
}
/********************\
* Interrupt handling *
......@@ -2509,7 +2521,7 @@ ath5k_intr(int irq, void *dev_id)
ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
}
}
} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
} while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
if (unlikely(!counter))
ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
......@@ -2751,56 +2763,47 @@ static int
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;