Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2009-12-30 13:51:29 -08:00
commit 3a999e6eb5
99 changed files with 4107 additions and 3211 deletions

View file

@ -88,27 +88,6 @@ Who: Luis R. Rodriguez <lrodriguez@atheros.com>
---------------------------
What: CONFIG_WIRELESS_OLD_REGULATORY - old static regulatory information
When: March 2010 / desktop catchup
Why: The old regulatory infrastructure has been replaced with a new one
which does not require statically defined regulatory domains. We do
not want to keep static regulatory domains in the kernel due to the
the dynamic nature of regulatory law and localization. We kept around
the old static definitions for the regulatory domains of:
* US
* JP
* EU
and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was
set. We will remove this option once the standard Linux desktop catches
up with the new userspace APIs we have implemented.
Who: Luis R. Rodriguez <lrodriguez@atheros.com>
---------------------------
What: dev->power.power_state
When: July 2007
Why: Broken design for runtime control over driver power states, confusing

View file

@ -1400,15 +1400,15 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
}
static int adm8211_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct adm8211_priv *priv = dev->priv;
if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
priv->mode = vif->type;
break;
default:
return -EOPNOTSUPP;
@ -1416,8 +1416,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
ADM8211_IDLE();
ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr));
ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)vif->addr));
ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(vif->addr + 4)));
adm8211_update_mode(dev);
@ -1427,7 +1427,7 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
}
static void adm8211_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct adm8211_priv *priv = dev->priv;
priv->mode = NL80211_IFTYPE_MONITOR;

View file

@ -1789,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
}
static int at76_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct at76_priv *priv = hw->priv;
int ret = 0;
@ -1798,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw,
mutex_lock(&priv->mtx);
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
priv->iw_mode = IW_MODE_INFRA;
break;
@ -1814,7 +1814,7 @@ static int at76_add_interface(struct ieee80211_hw *hw,
}
static void at76_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
at76_dbg(DBG_MAC80211, "%s()", __func__);
}

View file

@ -1939,7 +1939,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
}
static int ar9170_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct ar9170 *ar = hw->priv;
struct ath_common *common = &ar->common;
@ -1952,8 +1952,8 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
goto unlock;
}
ar->vif = conf->vif;
memcpy(common->macaddr, conf->mac_addr, ETH_ALEN);
ar->vif = vif;
memcpy(common->macaddr, vif->addr, ETH_ALEN);
if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
ar->rx_software_decryption = true;
@ -1973,7 +1973,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
}
static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct ar9170 *ar = hw->priv;

View file

@ -225,9 +225,9 @@ static int ath5k_reset_wake(struct ath5k_softc *sc);
static int ath5k_start(struct ieee80211_hw *hw);
static void ath5k_stop(struct ieee80211_hw *hw);
static int ath5k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
static void ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
int mc_count, struct dev_addr_list *mc_list);
@ -1903,17 +1903,6 @@ ath5k_tasklet_rx(unsigned long data)
rxs->noise = sc->ah->ah_noise_floor;
rxs->signal = rxs->noise + rs.rs_rssi;
/* An rssi of 35 indicates you should be able use
* 54 Mbps reliably. A more elaborate scheme can be used
* here but it requires a map of SNR/throughput for each
* possible mode used */
rxs->qual = rs.rs_rssi * 100 / 35;
/* rssi can be more than 35 though, anything above that
* should be considered at 100% */
if (rxs->qual > 100)
rxs->qual = 100;
rxs->antenna = rs.rs_antenna;
rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
@ -2381,6 +2370,9 @@ ath5k_init(struct ath5k_softc *sc)
*/
ath5k_stop_locked(sc);
/* Set PHY calibration interval */
ah->ah_cal_intval = ath5k_calinterval;
/*
* The basic interface to setting the hardware in a good
* state is ``reset''. On return the hardware is known to
@ -2408,10 +2400,6 @@ ath5k_init(struct ath5k_softc *sc)
/* Set ack to be sent at low bit-rates */
ath5k_hw_set_ack_bitrate_high(ah, false);
/* Set PHY calibration inteval */
ah->ah_cal_intval = ath5k_calinterval;
ret = 0;
done:
mmiowb();
@ -2785,7 +2773,7 @@ static void ath5k_stop(struct ieee80211_hw *hw)
}
static int ath5k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
int ret;
@ -2796,22 +2784,22 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
goto end;
}
sc->vif = conf->vif;
sc->vif = vif;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_MONITOR:
sc->opmode = conf->type;
sc->opmode = vif->type;
break;
default:
ret = -EOPNOTSUPP;
goto end;
}
ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
ath5k_hw_set_lladdr(sc->ah, vif->addr);
ath5k_mode_setup(sc);
ret = 0;
@ -2822,13 +2810,13 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
static void
ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
u8 mac[ETH_ALEN] = {};
mutex_lock(&sc->lock);
if (sc->vif != conf->vif)
if (sc->vif != vif)
goto end;
ath5k_hw_set_lladdr(sc->ah, mac);

View file

@ -77,6 +77,9 @@
#define ATH9K_TXERR_XTXOP 0x08
#define ATH9K_TXERR_TIMER_EXPIRED 0x10
#define ATH9K_TX_ACKED 0x20
#define ATH9K_TXERR_MASK \
(ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO | \
ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED)
#define ATH9K_TX_BA 0x01
#define ATH9K_TX_PWRMGMT 0x02

View file

@ -2504,6 +2504,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
return; /* another wiphy still in use */
}
/* Ensure HW is awake when we try to shut it down. */
ath9k_ps_wakeup(sc);
if (ah->btcoex_hw.enabled) {
ath9k_hw_btcoex_disable(ah);
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@ -2524,6 +2527,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(ah);
ath9k_hw_configpcipowersave(ah, 1, 1);
ath9k_ps_restore(sc);
/* Finally, put the chip in FULL SLEEP mode */
ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
sc->sc_flags |= SC_OP_INVALID;
@ -2534,12 +2540,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
}
static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)conf->vif->drv_priv;
struct ath_vif *avp = (void *)vif->drv_priv;
enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
int ret = 0;
@ -2551,7 +2557,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
goto out;
}
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
ic_opmode = NL80211_IFTYPE_STATION;
break;
@ -2562,11 +2568,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ret = -ENOBUFS;
goto out;
}
ic_opmode = conf->type;
ic_opmode = vif->type;
break;
default:
ath_print(common, ATH_DBG_FATAL,
"Interface type %d not yet supported\n", conf->type);
"Interface type %d not yet supported\n", vif->type);
ret = -EOPNOTSUPP;
goto out;
}
@ -2598,18 +2604,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
* Enable MIB interrupts when there are hardware phy counters.
* Note we only do this (at the moment) for station mode.
*/
if ((conf->type == NL80211_IFTYPE_STATION) ||
(conf->type == NL80211_IFTYPE_ADHOC) ||
(conf->type == NL80211_IFTYPE_MESH_POINT)) {
if ((vif->type == NL80211_IFTYPE_STATION) ||
(vif->type == NL80211_IFTYPE_ADHOC) ||
(vif->type == NL80211_IFTYPE_MESH_POINT)) {
sc->imask |= ATH9K_INT_MIB;
sc->imask |= ATH9K_INT_TSFOOR;
}
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
if (conf->type == NL80211_IFTYPE_AP ||
conf->type == NL80211_IFTYPE_ADHOC ||
conf->type == NL80211_IFTYPE_MONITOR)
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(common);
out:
@ -2618,12 +2624,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
}
static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)conf->vif->drv_priv;
struct ath_vif *avp = (void *)vif->drv_priv;
int i;
ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
@ -2637,14 +2643,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
(sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
ath9k_ps_wakeup(sc);
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
ath_beacon_return(sc, avp);
ath9k_ps_restore(sc);
}
sc->sc_flags &= ~SC_OP_BEACONS;
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
if (sc->beacon.bslot[i] == conf->vif) {
if (sc->beacon.bslot[i] == vif) {
printk(KERN_DEBUG "%s: vif had allocated beacon "
"slot\n", __func__);
sc->beacon.bslot[i] = NULL;
@ -3087,15 +3095,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
ath9k_ps_wakeup(sc);
ath_tx_aggr_start(sc, sta, tid, ssn);
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_STOP:
ath9k_ps_wakeup(sc);
ath_tx_aggr_stop(sc, sta, tid);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
ath9k_ps_wakeup(sc);
ath_tx_aggr_resume(sc, sta, tid);
ath9k_ps_restore(sc);
break;
default:
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,

View file

@ -96,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
}
const static struct ath_bus_ops ath_pci_bus_ops = {
static const struct ath_bus_ops ath_pci_bus_ops = {
.read_cachesize = ath_pci_read_cachesize,
.cleanup = ath_pci_cleanup,
.eeprom_read = ath_pci_eeprom_read,

View file

@ -2072,7 +2072,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
&txq->axq_q, lastbf->list.prev);
txq->axq_depth--;
txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_FILT);
txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK);
txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock);

View file

@ -3,6 +3,7 @@ config B43
depends on SSB_POSSIBLE && MAC80211 && HAS_DMA
select SSB
select FW_LOADER
select SSB_BLOCKIO
---help---
b43 is a driver for the Broadcom 43xx series wireless devices.
@ -78,14 +79,6 @@ config B43_SDIO
If unsure, say N.
# Data transfers to the device via PIO
# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly.
config B43_PIO
bool
depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO)
select SSB_BLOCKIO
default y
config B43_NPHY
bool "Pre IEEE 802.11n support (BROKEN)"
depends on B43 && EXPERIMENTAL && BROKEN
@ -137,12 +130,4 @@ config B43_DEBUG
for production use.
Only say Y, if you are debugging a problem in the b43 driver sourcecode.
config B43_FORCE_PIO
bool "Force usage of PIO instead of DMA"
depends on B43 && B43_DEBUG
---help---
This will disable DMA and always enable PIO instead.
Say N!
This is only for debugging the PIO engine code. You do
_NOT_ want to enable this.

View file

@ -12,7 +12,7 @@ b43-y += xmit.o
b43-y += lo.o
b43-y += wa.o
b43-y += dma.o
b43-$(CONFIG_B43_PIO) += pio.o
b43-y += pio.o
b43-y += rfkill.o
b43-$(CONFIG_B43_LEDS) += leds.o
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o

View file

@ -821,11 +821,9 @@ struct b43_wl {
/* The device LEDs. */
struct b43_leds leds;
#ifdef CONFIG_B43_PIO
/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
u8 pio_tailspace[4] __attribute__((__aligned__(8)));
#endif /* CONFIG_B43_PIO */
};
static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
@ -876,20 +874,9 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
{
#ifdef CONFIG_B43_PIO
return dev->__using_pio_transfers;
#else
return 0;
#endif
}
#ifdef CONFIG_B43_FORCE_PIO
# define B43_FORCE_PIO 1
#else
# define B43_FORCE_PIO 0
#endif
/* Message printing */
void b43info(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));

View file

@ -383,160 +383,44 @@ static inline
}
}
/* Check if a DMA region fits the device constraints.
* Returns true, if the region is OK for usage with this device. */
static inline bool b43_dma_address_ok(struct b43_dmaring *ring,
dma_addr_t addr, size_t size)
{
switch (ring->type) {
case B43_DMA_30BIT:
if ((u64)addr + size > (1ULL << 30))
return 0;
break;
case B43_DMA_32BIT:
if ((u64)addr + size > (1ULL << 32))
return 0;
break;
case B43_DMA_64BIT:
/* Currently we can't have addresses beyond
* 64bit in the kernel. */
break;
}
return 1;
}
#define is_4k_aligned(addr) (((u64)(addr) & 0x0FFFull) == 0)
#define is_8k_aligned(addr) (((u64)(addr) & 0x1FFFull) == 0)
static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base,
dma_addr_t dmaaddr, size_t size)
{
ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE);
free_pages((unsigned long)base, get_order(size));
}
static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring,
dma_addr_t *dmaaddr, size_t size,
gfp_t gfp_flags)
{
void *base;
base = (void *)__get_free_pages(gfp_flags, get_order(size));
if (!base)
return NULL;
memset(base, 0, size);
*dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size,
DMA_TO_DEVICE);
if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) {
free_pages((unsigned long)base, get_order(size));
return NULL;
}
return base;
}
static void * b43_get_and_map_ringmem(struct b43_dmaring *ring,
dma_addr_t *dmaaddr, size_t size)
{
void *base;
base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
GFP_KERNEL);
if (!base) {
b43err(ring->dev->wl, "Failed to allocate or map pages "
"for DMA ringmemory\n");
return NULL;
}
if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
/* The memory does not fit our device constraints.
* Retry with GFP_DMA set to get lower memory. */
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
GFP_KERNEL | GFP_DMA);
if (!base) {
b43err(ring->dev->wl, "Failed to allocate or map pages "
"in the GFP_DMA region for DMA ringmemory\n");
return NULL;
}
if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
b43err(ring->dev->wl, "Failed to allocate DMA "
"ringmemory that fits device constraints\n");
return NULL;
}
}
/* We expect the memory to be 4k aligned, at least. */
if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) {
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
return NULL;
}
return base;
}
static int alloc_ringmemory(struct b43_dmaring *ring)
{
unsigned int required;
void *base;
dma_addr_t dmaaddr;
gfp_t flags = GFP_KERNEL;
/* There are several requirements to the descriptor ring memory:
* - The memory region needs to fit the address constraints for the
* device (same as for frame buffers).
* - For 30/32bit DMA devices, the descriptor ring must be 4k aligned.
* - For 64bit DMA devices, the descriptor ring must be 8k aligned.
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
* alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
* has shown that 4K is sufficient for the latter as long as the buffer
* does not cross an 8K boundary.
*
* For unknown reasons - possibly a hardware error - the BCM4311 rev
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
* which accounts for the GFP_DMA flag below.
*
* The flags here must match the flags in free_ringmemory below!
*/
if (ring->type == B43_DMA_64BIT)
required = ring->nr_slots * sizeof(struct b43_dmadesc64);
else
required = ring->nr_slots * sizeof(struct b43_dmadesc32);
if (B43_WARN_ON(required > 0x1000))
flags |= GFP_DMA;
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
B43_DMA_RINGMEMSIZE,
&(ring->dmabase), flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
return -ENOMEM;
ring->alloc_descsize = 0x1000;
base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
if (!base)
return -ENOMEM;
ring->alloc_descbase = base;
ring->alloc_dmabase = dmaaddr;
if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) {
/* We're on <=32bit DMA, or we already got 8k aligned memory.
* That's all we need, so we're fine. */
ring->descbase = base;
ring->dmabase = dmaaddr;
return 0;
}
b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize);
/* Ok, we failed at the 8k alignment requirement.
* Try to force-align the memory region now. */
ring->alloc_descsize = 0x2000;
base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
if (!base)
return -ENOMEM;
ring->alloc_descbase = base;
ring->alloc_dmabase = dmaaddr;
if (is_8k_aligned(dmaaddr)) {
/* We're already 8k aligned. That Ok, too. */
ring->descbase = base;
ring->dmabase = dmaaddr;
return 0;
}
/* Force-align it to 8k */
ring->descbase = (void *)((u8 *)base + 0x1000);
ring->dmabase = dmaaddr + 0x1000;
B43_WARN_ON(!is_8k_aligned(ring->dmabase));
memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
return 0;
}
static void free_ringmemory(struct b43_dmaring *ring)
{
b43_unmap_and_free_ringmem(ring, ring->alloc_descbase,
ring->alloc_dmabase, ring->alloc_descsize);
gfp_t flags = GFP_KERNEL;
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
ring->descbase, ring->dmabase, flags);
}
/* Reset the RX DMA channel */
@ -646,14 +530,29 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
return 1;
if (!b43_dma_address_ok(ring, addr, buffersize)) {
/* We can't support this address. Unmap it again. */
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
return 1;
switch (ring->type) {
case B43_DMA_30BIT:
if ((u64)addr + buffersize > (1ULL << 30))
goto address_error;
break;
case B43_DMA_32BIT:
if ((u64)addr + buffersize > (1ULL << 32))
goto address_error;
break;
case B43_DMA_64BIT:
/* Currently we can't have addresses beyond
* 64bit in the kernel. */
break;
}
/* The address is OK. */
return 0;
address_error:
/* We can't support this address. Unmap it again. */
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
return 1;
}
static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
@ -715,9 +614,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
meta->dmaaddr = dmaaddr;
ring->ops->fill_descriptor(ring, desc, dmaaddr,
ring->rx_buffersize, 0, 0, 0);
ssb_dma_sync_single_for_device(ring->dev->dev,
ring->alloc_dmabase,
ring->alloc_descsize, DMA_TO_DEVICE);
return 0;
}
@ -1354,9 +1250,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
}
/* Now transfer the whole frame. */
wmb();
ssb_dma_sync_single_for_device(ring->dev->dev,
ring->alloc_dmabase,
ring->alloc_descsize, DMA_TO_DEVICE);
ops->poke_tx(ring, next_slot(ring, slot));
return 0;
@ -1760,7 +1653,6 @@ void b43_dma_tx_resume(struct b43_wldev *dev)
b43_power_saving_ctl_bits(dev, 0);
}
#ifdef CONFIG_B43_PIO
static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type,
u16 mmio_base, bool enable)
{
@ -1794,4 +1686,3 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
mmio_base = b43_dmacontroller_base(type, engine_index);
direct_fifo_rx(dev, type, mmio_base, enable);
}
#endif /* CONFIG_B43_PIO */

View file

@ -157,6 +157,7 @@ struct b43_dmadesc_generic {
} __attribute__ ((__packed__));
/* Misc DMA constants */
#define B43_DMA_RINGMEMSIZE PAGE_SIZE
#define B43_DMA0_RX_FRAMEOFFSET 30
/* DMA engine tuning knobs */
@ -246,12 +247,6 @@ struct b43_dmaring {
/* The QOS priority assigned to this ring. Only used for TX rings.
* This is the mac80211 "queue" value. */
u8 queue_prio;
/* Pointers and size of the originally allocated and mapped memory
* region for the descriptor ring. */
void *alloc_descbase;
dma_addr_t alloc_dmabase;
unsigned int alloc_descsize;
/* Pointer to our wireless device. */
struct b43_wldev *dev;
#ifdef CONFIG_B43_DEBUG
/* Maximum number of used slots. */

View file

@ -102,6 +102,9 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
module_param_named(verbose, b43_modparam_verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
static int modparam_pio;
module_param_named(pio, modparam_pio, int, 0444);
MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
static const struct ssb_device_id b43_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
@ -1786,8 +1789,8 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
dma_reason[4], dma_reason[5]);
b43err(dev->wl, "This device does not support DMA "
"on your system. Please use PIO instead.\n");
b43err(dev->wl, "CONFIG_B43_FORCE_PIO must be set in "
"your kernel configuration.\n");
b43err(dev->wl, "Unload the b43 module and reload "
"with 'pio=1'\n");
return;
}
if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
@ -4353,7 +4356,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
(dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
B43_FORCE_PIO) {
modparam_pio) {
dev->__using_pio_transfers = 1;
err = b43_pio_init(dev);
} else {
@ -4388,7 +4391,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
}
static int b43_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
@ -4396,24 +4399,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
/* TODO: allow WDS/AP devices to coexist */
if (conf->type != NL80211_IFTYPE_AP &&
conf->type != NL80211_IFTYPE_MESH_POINT &&
conf->type != NL80211_IFTYPE_STATION &&
conf->type != NL80211_IFTYPE_WDS &&
conf->type != NL80211_IFTYPE_ADHOC)
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_MESH_POINT &&
vif->type != NL80211_IFTYPE_STATION &&
vif->type != NL80211_IFTYPE_WDS &&
vif->type != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
mutex_lock(&wl->mutex);
if (wl->operating)
goto out_mutex_unlock;
b43dbg(wl, "Adding Interface type %d\n", conf->type);
b43dbg(wl, "Adding Interface type %d\n", vif->type);
dev = wl->current_dev;
wl->operating = 1;
wl->vif = conf->vif;
wl->if_type = conf->type;
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
wl->vif = vif;
wl->if_type = vif->type;
memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
b43_adjust_opmode(dev);
b43_set_pretbtt(dev);
@ -4428,17 +4431,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
}
static void b43_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev = wl->current_dev;
b43dbg(wl, "Removing Interface type %d\n", conf->type);
b43dbg(wl, "Removing Interface type %d\n", vif->type);
mutex_lock(&wl->mutex);
B43_WARN_ON(!wl->operating);
B43_WARN_ON(wl->vif != conf->vif);
B43_WARN_ON(wl->vif != vif);
wl->vif = NULL;
wl->operating = 0;

View file

@ -55,8 +55,6 @@
#define B43_PIO_MAX_NR_TXPACKETS 32
#ifdef CONFIG_B43_PIO
struct b43_pio_txpacket {
/* Pointer to the TX queue we belong to. */
struct b43_pio_txqueue *queue;
@ -169,42 +167,4 @@ void b43_pio_rx(struct b43_pio_rxqueue *q);
void b43_pio_tx_suspend(struct b43_wldev *dev);
void b43_pio_tx_resume(struct b43_wldev *dev);
#else /* CONFIG_B43_PIO */
static inline int b43_pio_init(struct b43_wldev *dev)
{
return 0;
}
static inline void b43_pio_free(struct b43_wldev *dev)
{
}
static inline void b43_pio_stop(struct b43_wldev *dev)
{
}
static inline int b43_pio_tx(struct b43_wldev *dev,
struct sk_buff *skb)
{
return 0;
}
static inline void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
}
static inline void b43_pio_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
}
static inline void b43_pio_rx(struct b43_pio_rxqueue *q)
{
}
static inline void b43_pio_tx_suspend(struct b43_wldev *dev)
{
}
static inline void b43_pio_tx_resume(struct b43_wldev *dev)
{
}
#endif /* CONFIG_B43_PIO */
#endif /* B43_PIO_H_ */

View file

@ -3361,7 +3361,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
}
static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev;
@ -3370,23 +3370,23 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
/* TODO: allow WDS/AP devices to coexist */
if (conf->type != NL80211_IFTYPE_AP &&
conf->type != NL80211_IFTYPE_STATION &&
conf->type != NL80211_IFTYPE_WDS &&
conf->type != NL80211_IFTYPE_ADHOC)
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_STATION &&
vif->type != NL80211_IFTYPE_WDS &&
vif->type != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
mutex_lock(&wl->mutex);
if (wl->operating)
goto out_mutex_unlock;
b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
b43legacydbg(wl, "Adding Interface type %d\n", vif->type);
dev = wl->current_dev;
wl->operating = 1;
wl->vif = conf->vif;
wl->if_type = conf->type;
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
wl->vif = vif;
wl->if_type = vif->type;
memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
spin_lock_irqsave(&wl->irq_lock, flags);
b43legacy_adjust_opmode(dev);
@ -3403,18 +3403,18 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
}
static void b43legacy_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev = wl->current_dev;
unsigned long flags;
b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
b43legacydbg(wl, "Removing Interface type %d\n", vif->type);
mutex_lock(&wl->mutex);
B43legacy_WARN_ON(!wl->operating);
B43legacy_WARN_ON(wl->vif != conf->vif);
B43legacy_WARN_ON(wl->vif != vif);
wl->vif = NULL;
wl->operating = 0;

View file

@ -681,19 +681,13 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
snr = rx_stats_sig_avg / rx_stats_noise_diff;
rx_status.noise = rx_status.signal -
iwl3945_calc_db_from_ratio(snr);
rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal,
rx_status.noise);
/* If noise info not available, calculate signal quality indicator (%)
* using just the dBm signal level. */
} else {
rx_status.noise = priv->last_rx_noise;
rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0);
}
IWL_DEBUG_STATS(priv, "Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
rx_status.signal, rx_status.noise, rx_status.qual,
IWL_DEBUG_STATS(priv, "Rssi %d noise %d sig_avg %d noise_diff %d\n",
rx_status.signal, rx_status.noise,
rx_stats_sig_avg, rx_stats_noise_diff);
header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);

View file

@ -222,7 +222,6 @@ struct iwl3945_ibss_seq {
*
*****************************************************************************/
extern int iwl3945_calc_db_from_ratio(int sig_ratio);
extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
extern void iwl3945_rx_replenish(void *data);
extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,

View file

@ -150,7 +150,7 @@ static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
};
/* mbps, mcs */
const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
{ "1", "BPSK DSSS"},
{ "2", "QPSK DSSS"},
{"5.5", "BPSK CCK"},

View file

@ -2584,12 +2584,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode)
EXPORT_SYMBOL(iwl_set_mode);
int iwl_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
if (priv->vif) {
IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
@ -2597,19 +2597,19 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
}
spin_lock_irqsave(&priv->lock, flags);
priv->vif = conf->vif;
priv->iw_mode = conf->type;
priv->vif = vif;
priv->iw_mode = vif->type;
spin_unlock_irqrestore(&priv->lock, flags);
mutex_lock(&priv->mutex);
if (conf->mac_addr) {
IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
if (vif->addr) {
IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
}
if (iwl_set_mode(priv, conf->type) == -EAGAIN)
if (iwl_set_mode(priv, vif->type) == -EAGAIN)
/* we are not ready, will run again when ready */
set_bit(STATUS_MODE_PENDING, &priv->status);
@ -2621,7 +2621,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
EXPORT_SYMBOL(iwl_mac_add_interface);
void iwl_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
@ -2634,7 +2634,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwlcore_commit_rxon(priv);
}
if (priv->vif == conf->vif) {
if (priv->vif == vif) {
priv->vif = NULL;
memset(priv->bssid, 0, ETH_ALEN);
}

View file

@ -332,9 +332,9 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
int iwl_commit_rxon(struct iwl_priv *priv);
int iwl_set_mode(struct iwl_priv *priv, int mode);
int iwl_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
void iwl_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
void iwl_config_ap(struct iwl_priv *priv);
int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,

View file

@ -650,47 +650,6 @@ void iwl_reply_statistics(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_reply_statistics);
#define PERFECT_RSSI (-20) /* dBm */
#define WORST_RSSI (-95) /* dBm */
#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
/* Calculate an indication of rx signal quality (a percentage, not dBm!).
* See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
* about formulas used below. */
static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
{
int sig_qual;
int degradation = PERFECT_RSSI - rssi_dbm;
/* If we get a noise measurement, use signal-to-noise ratio (SNR)
* as indicator; formula is (signal dbm - noise dbm).
* SNR at or above 40 is a great signal (100%).
* Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
* Weakest usable signal is usually 10 - 15 dB SNR. */
if (noise_dbm) {
if (rssi_dbm - noise_dbm >= 40)
return 100;
else if (rssi_dbm < noise_dbm)
return 0;
sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
/* Else use just the signal level.
* This formula is a least squares fit of data points collected and
* compared with a reference system that had a percentage (%) display
* for signal quality. */
} else
sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
(15 * RSSI_RANGE + 62 * degradation)) /
(RSSI_RANGE * RSSI_RANGE);
if (sig_qual > 100)
sig_qual = 100;
else if (sig_qual < 1)
sig_qual = 0;
return sig_qual;
}
/* Calc max signal level (dBm) among 3 possible receivers */
static inline int iwl_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp)
@ -1101,11 +1060,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
if (iwl_is_associated(priv) &&
!test_bit(STATUS_SCANNING, &priv->status)) {
rx_status.noise = priv->last_rx_noise;
rx_status.qual = iwl_calc_sig_qual(rx_status.signal,
rx_status.noise);
} else {
rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0);
}
/* Reset beacon noise level if not associated. */
@ -1118,8 +1074,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
iwl_dbg_report_frame(priv, phy_res, len, header, 1);
#endif
iwl_dbg_log_rx_data_frame(priv, len, header);
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
rx_status.signal, rx_status.noise, rx_status.qual,
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n",
rx_status.signal, rx_status.noise,
(unsigned long long)rx_status.mactime);
/*

View file

@ -1299,47 +1299,6 @@ int iwl3945_calc_db_from_ratio(int sig_ratio)
return (int)ratio2dB[sig_ratio];
}
#define PERFECT_RSSI (-20) /* dBm */
#define WORST_RSSI (-95) /* dBm */
#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
/* Calculate an indication of rx signal quality (a percentage, not dBm!).
* See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
* about formulas used below. */
int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm)
{
int sig_qual;
int degradation = PERFECT_RSSI - rssi_dbm;
/* If we get a noise measurement, use signal-to-noise ratio (SNR)
* as indicator; formula is (signal dbm - noise dbm).
* SNR at or above 40 is a great signal (100%).
* Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
* Weakest usable signal is usually 10 - 15 dB SNR. */
if (noise_dbm) {
if (rssi_dbm - noise_dbm >= 40)
return 100;
else if (rssi_dbm < noise_dbm)
return 0;
sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
/* Else use just the signal level.
* This formula is a least squares fit of data points collected and
* compared with a reference system that had a percentage (%) display
* for signal quality. */
} else
sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
(15 * RSSI_RANGE + 62 * degradation)) /
(RSSI_RANGE * RSSI_RANGE);
if (sig_qual > 100)
sig_qual = 100;
else if (sig_qual < 1)
sig_qual = 0;
return sig_qual;
}
/**
* iwl3945_rx_handle - Main entry function for receiving responses from uCode
*

View file

@ -268,7 +268,7 @@ struct iwm_priv {
struct sk_buff_head rx_list;
struct list_head rx_tickets;
struct list_head rx_packets[IWM_RX_ID_HASH];
struct list_head rx_packets[IWM_RX_ID_HASH + 1];
struct workqueue_struct *rx_wq;
struct work_struct rx_worker;

View file

@ -567,11 +567,8 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan)
chan_count = lbs_scan_create_channel_list(priv, chan_list);
netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev);
if (priv->mesh_dev) {
if (priv->mesh_dev)
netif_stop_queue(priv->mesh_dev);
netif_carrier_off(priv->mesh_dev);
}
/* Prepare to continue an interrupted scan */
lbs_deb_scan("chan_count %d, scan_channel %d\n",
@ -635,16 +632,13 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan)
priv->scan_channel = 0;
out:
if (priv->connect_status == LBS_CONNECTED) {
netif_carrier_on(priv->dev);
if (!priv->tx_pending_len)
netif_wake_queue(priv->dev);
}
if (priv->mesh_dev && lbs_mesh_connected(priv)) {
netif_carrier_on(priv->mesh_dev);
if (!priv->tx_pending_len)
netif_wake_queue(priv->mesh_dev);
}
if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
netif_wake_queue(priv->dev);
if (priv->mesh_dev && lbs_mesh_connected(priv) &&
!priv->tx_pending_len)
netif_wake_queue(priv->mesh_dev);
kfree(chan_list);
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);

View file

@ -318,14 +318,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
}
static int lbtf_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct lbtf_private *priv = hw->priv;
if (priv->vif != NULL)
return -EOPNOTSUPP;
priv->vif = conf->vif;
switch (conf->type) {
priv->vif = vif;
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
lbtf_set_mode(priv, LBTF_AP_MODE);
@ -337,12 +337,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
priv->vif = NULL;
return -EOPNOTSUPP;
}
lbtf_set_mac_address(priv, (u8 *) conf->mac_addr);
lbtf_set_mac_address(priv, (u8 *) vif->addr);
return 0;
}
static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct lbtf_private *priv = hw->priv;
@ -495,7 +495,6 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
stats.band = IEEE80211_BAND_2GHZ;
stats.signal = prxpd->snr;
stats.noise = prxpd->nf;
stats.qual = prxpd->snr - prxpd->nf;
/* Marvell rate index has a hole at value 4 */
if (prxpd->rx_rate > 4)
--prxpd->rx_rate;

View file

@ -584,24 +584,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
wiphy_name(hw->wiphy), __func__, conf->type,
conf->mac_addr);
hwsim_set_magic(conf->vif);
wiphy_name(hw->wiphy), __func__, vif->type,
vif->addr);
hwsim_set_magic(vif);
return 0;
}
static void mac80211_hwsim_remove_interface(
struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
wiphy_name(hw->wiphy), __func__, conf->type,
conf->mac_addr);
hwsim_check_magic(conf->vif);
hwsim_clear_magic(conf->vif);
wiphy_name(hw->wiphy), __func__, vif->type,
vif->addr);
hwsim_check_magic(vif);
hwsim_clear_magic(vif);
}
@ -896,6 +896,16 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
return 0;
}
static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
{
/*
* In this special case, there's nothing we need to
* do because hwsim does transmission synchronously.
* In the future, when it does transmissions via
* userspace, we may need to do something.
*/
}
static const struct ieee80211_ops mac80211_hwsim_ops =
{
@ -912,6 +922,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.conf_tx = mac80211_hwsim_conf_tx,
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
.ampdu_action = mac80211_hwsim_ampdu_action,
.flush = mac80211_hwsim_flush,
};

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@
#define MAX_RID_LEN 1024
/* Helper routine to record keys
* Do not call from interrupt context */
* It is called under orinoco_lock so it may not sleep */
static int orinoco_set_key(struct orinoco_private *priv, int index,
enum orinoco_alg alg, const u8 *key, int key_len,
const u8 *seq, int seq_len)
@ -32,14 +32,14 @@ static int orinoco_set_key(struct orinoco_private *priv, int index,
kzfree(priv->keys[index].seq);
if (key_len) {
priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
if (!priv->keys[index].key)
goto nomem;
} else
priv->keys[index].key = NULL;
if (seq_len) {
priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
if (!priv->keys[index].seq)
goto free_key;
} else

View file

@ -216,7 +216,7 @@ static void p54_stop(struct ieee80211_hw *dev)
}
static int p54_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct p54_common *priv = dev->priv;
@ -226,28 +226,28 @@ static int p54_add_interface(struct ieee80211_hw *dev,
return -EOPNOTSUPP;
}
priv->vif = conf->vif;
priv->vif = vif;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
priv->mode = conf->type;
priv->mode = vif->type;
break;
default:
mutex_unlock(&priv->conf_mutex);
return -EOPNOTSUPP;
}
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
p54_setup_mac(priv);
mutex_unlock(&priv->conf_mutex);
return 0;
}
static void p54_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct p54_common *priv = dev->priv;

View file

@ -54,12 +54,12 @@ config RT61PCI
When compiled as a module, this driver will be called rt61pci.
config RT2800PCI_PCI
tristate
boolean
depends on PCI
default y
config RT2800PCI_SOC
tristate
boolean
depends on RALINK_RT288X || RALINK_RT305X
default y

View file

@ -451,7 +451,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
/*
* RF2420 chipset don't need any additional actions.
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2420))
if (rt2x00_rf(rt2x00dev, RF2420))
return;
/*
@ -1343,8 +1343,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
!rt2x00_rf(&rt2x00dev->chip, RF2421)) {
if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}

View file

@ -440,8 +440,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E and RT5222 need to flip TX I/Q
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
rt2x00_rf(&rt2x00dev->chip, RF5222)) {
if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
@ -449,7 +448,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E does not need RX I/Q Flip.
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
if (rt2x00_rf(rt2x00dev, RF2525E))
rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
} else {
rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
@ -475,14 +474,14 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
* Switch on tuning bits.
* For RT2523 devices we do not need to update the R1 register.
*/
if (!rt2x00_rf(&rt2x00dev->chip, RF2523))
if (!rt2x00_rf(rt2x00dev, RF2523))
rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
/*
* For RT2525 we should first set the channel to half band higher.
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
if (rt2x00_rf(rt2x00dev, RF2525)) {
static const u32 vals[] = {
0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
@ -516,7 +515,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
* Switch off tuning bits.
* For RT2523 devices we do not need to update the R1 register.
*/
if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) {
if (!rt2x00_rf(rt2x00dev, RF2523)) {
rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
}
@ -640,7 +639,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
* up to version C the link tuning should halt after 20
* seconds while being associated.
*/
if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D &&
rt2x00dev->intf_associated && count > 20)
return;
@ -650,7 +649,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
* should go straight to dynamic CCA tuning when they
* are not associated.
*/
if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D ||
if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D ||
!rt2x00dev->intf_associated)
goto dynamic_cca_tune;
@ -1507,12 +1506,12 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
!rt2x00_rf(&rt2x00dev->chip, RF2523) &&
!rt2x00_rf(&rt2x00dev->chip, RF2524) &&
!rt2x00_rf(&rt2x00dev->chip, RF2525) &&
!rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
!rt2x00_rf(&rt2x00dev->chip, RF5222)) {
if (!rt2x00_rf(rt2x00dev, RF2522) &&
!rt2x00_rf(rt2x00dev, RF2523) &&
!rt2x00_rf(rt2x00dev, RF2524) &&
!rt2x00_rf(rt2x00dev, RF2525) &&
!rt2x00_rf(rt2x00dev, RF2525E) &&
!rt2x00_rf(rt2x00dev, RF5222)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@ -1744,22 +1743,22 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
if (rt2x00_rf(rt2x00dev, RF2522)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
spec->channels = rf_vals_bg_2522;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
} else if (rt2x00_rf(rt2x00dev, RF2523)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
spec->channels = rf_vals_bg_2523;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
} else if (rt2x00_rf(rt2x00dev, RF2524)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
spec->channels = rf_vals_bg_2524;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
} else if (rt2x00_rf(rt2x00dev, RF2525)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
spec->channels = rf_vals_bg_2525;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
} else if (rt2x00_rf(rt2x00dev, RF2525E)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
spec->channels = rf_vals_bg_2525e;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
} else if (rt2x00_rf(rt2x00dev, RF5222)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;

View file

@ -565,8 +565,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E and RT5222 need to flip TX I/Q
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
rt2x00_rf(&rt2x00dev->chip, RF5222)) {
if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
@ -574,7 +573,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
/*
* RT2525E does not need RX I/Q Flip.
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
if (rt2x00_rf(rt2x00dev, RF2525E))
rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
} else {
rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
@ -598,7 +597,7 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
/*
* For RT2525E we should first set the channel to half band higher.
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
if (rt2x00_rf(rt2x00dev, RF2525E)) {
static const u32 vals[] = {
0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
@ -793,7 +792,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) {
rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
rt2x00_set_field16(&reg, PHY_CSR2_LNA, 0);
} else {
@ -1411,19 +1410,18 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) ||
rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) ||
rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
!rt2x00_rf(&rt2x00dev->chip, RF2523) &&
!rt2x00_rf(&rt2x00dev->chip, RF2524) &&
!rt2x00_rf(&rt2x00dev->chip, RF2525) &&
!rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
!rt2x00_rf(&rt2x00dev->chip, RF5222)) {
if (!rt2x00_rf(rt2x00dev, RF2522) &&
!rt2x00_rf(rt2x00dev, RF2523) &&
!rt2x00_rf(rt2x00dev, RF2524) &&
!rt2x00_rf(rt2x00dev, RF2525) &&
!rt2x00_rf(rt2x00dev, RF2525E) &&
!rt2x00_rf(rt2x00dev, RF5222)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@ -1667,22 +1665,22 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
if (rt2x00_rf(rt2x00dev, RF2522)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
spec->channels = rf_vals_bg_2522;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
} else if (rt2x00_rf(rt2x00dev, RF2523)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
spec->channels = rf_vals_bg_2523;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
} else if (rt2x00_rf(rt2x00dev, RF2524)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
spec->channels = rf_vals_bg_2524;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
} else if (rt2x00_rf(rt2x00dev, RF2525)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
spec->channels = rf_vals_bg_2525;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
} else if (rt2x00_rf(rt2x00dev, RF2525E)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
spec->channels = rf_vals_bg_2525e;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
} else if (rt2x00_rf(rt2x00dev, RF5222)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;

View file

@ -37,7 +37,7 @@
#include <linux/module.h>
#include "rt2x00.h"
#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
#include "rt2x00usb.h"
#endif
#include "rt2800lib.h"
@ -220,8 +220,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
/*
* RT2880 and RT3052 don't support MCU requests.
*/
if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
rt2x00_rt(&rt2x00dev->chip, RT3052))
if (rt2x00_rt(rt2x00dev, RT2880) || rt2x00_rt(rt2x00dev, RT3052))
return;
mutex_lock(&rt2x00dev->csr_mutex);
@ -806,12 +805,12 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
unsigned int tx_pin;
u8 bbp;
if ((rt2x00_rt(&rt2x00dev->chip, RT3070) ||
rt2x00_rt(&rt2x00dev->chip, RT3090)) &&
(rt2x00_rf(&rt2x00dev->chip, RF2020) ||
rt2x00_rf(&rt2x00dev->chip, RF3020) ||
rt2x00_rf(&rt2x00dev->chip, RF3021) ||
rt2x00_rf(&rt2x00dev->chip, RF3022)))
if ((rt2x00_rt(rt2x00dev, RT3070) ||
rt2x00_rt(rt2x00dev, RT3090)) &&
(rt2x00_rf(rt2x00dev, RF2020) ||
rt2x00_rf(rt2x00dev, RF3020) ||
rt2x00_rf(rt2x00dev, RF3021) ||
rt2x00_rf(rt2x00dev, RF3022)))
rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info);
else
rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
@ -878,7 +877,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
rt2800_bbp_write(rt2x00dev, 3, bbp);
if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
if (conf_is_ht40(conf)) {
rt2800_bbp_write(rt2x00dev, 69, 0x1a);
rt2800_bbp_write(rt2x00dev, 70, 0x0a);
@ -1041,7 +1040,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION)
rt2x00_rev(rt2x00dev) == RT3070_VERSION)
return 0x1c + (2 * rt2x00dev->lna_gain);
else
return 0x2e + rt2x00dev->lna_gain;
@ -1072,7 +1071,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
const u32 count)
{
if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION)
if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)
return;
/*
@ -1121,7 +1120,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
if (rt2x00_intf_is_usb(rt2x00dev)) {
rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
USB_MODE_RESET, REGISTER_TIMEOUT);
#endif
@ -1158,7 +1157,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@ -1185,8 +1184,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION &&
rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION)
if (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION &&
rt2x00_rev(rt2x00dev) < RT3070_VERSION)
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
else
rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
@ -1465,22 +1464,22 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 103, 0x00);
rt2800_bbp_write(rt2x00dev, 105, 0x05);
if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
rt2800_bbp_write(rt2x00dev, 69, 0x16);
rt2800_bbp_write(rt2x00dev, 73, 0x12);
}
if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION)
if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION)
rt2800_bbp_write(rt2x00dev, 84, 0x19);
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
rt2800_bbp_write(rt2x00dev, 70, 0x0a);
rt2800_bbp_write(rt2x00dev, 84, 0x99);
rt2800_bbp_write(rt2x00dev, 105, 0x05);
}
if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
if (rt2x00_rt(rt2x00dev, RT3052)) {
rt2800_bbp_write(rt2x00dev, 31, 0x08);
rt2800_bbp_write(rt2x00dev, 78, 0x0e);
rt2800_bbp_write(rt2x00dev, 80, 0x08);
@ -1566,13 +1565,13 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
u8 bbp;
if (rt2x00_intf_is_usb(rt2x00dev) &&
rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
rt2x00_rev(rt2x00dev) != RT3070_VERSION)
return 0;
if (rt2x00_intf_is_pci(rt2x00dev)) {
if (!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
!rt2x00_rf(&rt2x00dev->chip, RF3021) &&
!rt2x00_rf(&rt2x00dev->chip, RF3022))
if (!rt2x00_rf(rt2x00dev, RF3020) &&
!rt2x00_rf(rt2x00dev, RF3021) &&
!rt2x00_rf(rt2x00dev, RF3022))
return 0;
}
@ -1737,7 +1736,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
} else if (rt2x00_rev(rt2x00dev) < RT2883_VERSION) {
/*
* There is a max of 2 RX streams for RT28x0 series
*/
@ -1839,17 +1838,15 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip_rf(rt2x00dev, value, reg);
if (rt2x00_intf_is_usb(rt2x00dev)) {
struct rt2x00_chip *chip = &rt2x00dev->chip;
/*
* The check for rt2860 is not a typo, some rt2870 hardware
* identifies itself as rt2860 in the CSR register.
*/
if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) ||
rt2x00_check_rev(chip, 0xfff00000, 0x28700000) ||
rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) {
if (rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28600000) ||
rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28700000) ||
rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28800000)) {
rt2x00_set_chip_rt(rt2x00dev, RT2870);
} else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) {
} else if (rt2x00_check_rev(rt2x00dev, 0xffff0000, 0x30700000)) {
rt2x00_set_chip_rt(rt2x00dev, RT3070);
} else {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
@ -1858,14 +1855,14 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
}
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
!rt2x00_rf(&rt2x00dev->chip, RF2850) &&
!rt2x00_rf(&rt2x00dev->chip, RF2720) &&
!rt2x00_rf(&rt2x00dev->chip, RF2750) &&
!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
!rt2x00_rf(&rt2x00dev->chip, RF2020) &&
!rt2x00_rf(&rt2x00dev->chip, RF3021) &&
!rt2x00_rf(&rt2x00dev->chip, RF3022)) {
if (!rt2x00_rf(rt2x00dev, RF2820) &&
!rt2x00_rf(rt2x00dev, RF2850) &&
!rt2x00_rf(rt2x00dev, RF2720) &&
!rt2x00_rf(rt2x00dev, RF2750) &&
!rt2x00_rf(rt2x00dev, RF3020) &&
!rt2x00_rf(rt2x00dev, RF2020) &&
!rt2x00_rf(rt2x00dev, RF3021) &&
!rt2x00_rf(rt2x00dev, RF3022)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@ -2013,7 +2010,6 @@ static const struct rf_channel rf_vals_302x[] = {
int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct rt2x00_chip *chip = &rt2x00dev->chip;
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
char *tx_power1;
@ -2049,19 +2045,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(chip, RF2820) ||
rt2x00_rf(chip, RF2720) ||
(rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) {
if (rt2x00_rf(rt2x00dev, RF2820) ||
rt2x00_rf(rt2x00dev, RF2720) ||
(rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(rt2x00dev, RF3052))) {
spec->num_channels = 14;
spec->channels = rf_vals;
} else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) {
} else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals);
spec->channels = rf_vals;
} else if (rt2x00_rf(chip, RF3020) ||
rt2x00_rf(chip, RF2020) ||
rt2x00_rf(chip, RF3021) ||
rt2x00_rf(chip, RF3022)) {
} else if (rt2x00_rf(rt2x00dev, RF3020) ||
rt2x00_rf(rt2x00dev, RF2020) ||
rt2x00_rf(rt2x00dev, RF3021) ||
rt2x00_rf(rt2x00dev, RF3022)) {
spec->num_channels = ARRAY_SIZE(rf_vals_302x);
spec->channels = rf_vals_302x;
}
@ -2069,7 +2065,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize HT information.
*/
if (!rt2x00_rf(chip, RF2020))
if (!rt2x00_rf(rt2x00dev, RF2020))
spec->ht.ht_supported = true;
else
spec->ht.ht_supported = false;

View file

@ -48,14 +48,6 @@
#include "rt2800.h"
#include "rt2800pci.h"
#ifdef CONFIG_RT2800PCI_PCI_MODULE
#define CONFIG_RT2800PCI_PCI
#endif
#ifdef CONFIG_RT2800PCI_WISOC_MODULE
#define CONFIG_RT2800PCI_WISOC
#endif
/*
* Allow hardware encryption to be disabled.
*/
@ -87,7 +79,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
#ifdef CONFIG_RT2800PCI_WISOC
#ifdef CONFIG_RT2800PCI_SOC
static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
@ -98,7 +90,7 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
}
#endif /* CONFIG_RT2800PCI_WISOC */
#endif /* CONFIG_RT2800PCI_SOC */
#ifdef CONFIG_RT2800PCI_PCI
static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@ -1129,8 +1121,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* This device requires firmware.
*/
if (!rt2x00_rt(&rt2x00dev->chip, RT2880) &&
!rt2x00_rt(&rt2x00dev->chip, RT3052))
if (!rt2x00_rt(rt2x00dev, RT2880) && !rt2x00_rt(rt2x00dev, RT3052))
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
@ -1251,7 +1242,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
#endif /* CONFIG_RT2800PCI_PCI */
MODULE_LICENSE("GPL");
#ifdef CONFIG_RT2800PCI_WISOC
#ifdef CONFIG_RT2800PCI_SOC
#if defined(CONFIG_RALINK_RT288X)
__rt2x00soc_probe(RT2880, &rt2800pci_ops);
#elif defined(CONFIG_RALINK_RT305X)
@ -1269,7 +1260,7 @@ static struct platform_driver rt2800soc_driver = {
.suspend = rt2x00soc_suspend,
.resume = rt2x00soc_resume,
};
#endif /* CONFIG_RT2800PCI_WISOC */
#endif /* CONFIG_RT2800PCI_SOC */
#ifdef CONFIG_RT2800PCI_PCI
static struct pci_driver rt2800pci_driver = {
@ -1286,7 +1277,7 @@ static int __init rt2800pci_init(void)
{
int ret = 0;
#ifdef CONFIG_RT2800PCI_WISOC
#ifdef CONFIG_RT2800PCI_SOC
ret = platform_driver_register(&rt2800soc_driver);
if (ret)
return ret;
@ -1294,7 +1285,7 @@ static int __init rt2800pci_init(void)
#ifdef CONFIG_RT2800PCI_PCI
ret = pci_register_driver(&rt2800pci_driver);
if (ret) {
#ifdef CONFIG_RT2800PCI_WISOC
#ifdef CONFIG_RT2800PCI_SOC
platform_driver_unregister(&rt2800soc_driver);
#endif
return ret;
@ -1309,7 +1300,7 @@ static void __exit rt2800pci_exit(void)
#ifdef CONFIG_RT2800PCI_PCI
pci_unregister_driver(&rt2800pci_driver);
#endif
#ifdef CONFIG_RT2800PCI_WISOC
#ifdef CONFIG_RT2800PCI_SOC
platform_driver_unregister(&rt2800soc_driver);
#endif
}

View file

@ -92,7 +92,7 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len)
static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
size_t offset = 0;
/*
@ -138,7 +138,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
u32 reg;
u32 offset;
u32 length;
u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
/*
* Check which section of the firmware we need.
@ -933,6 +933,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Logitec */
{ USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },

View file

@ -937,25 +937,25 @@ static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev)
rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
}
static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
{
return (chipset->rt == chip);
return (rt2x00dev->chip.rt == rt);
}
static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip)
static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
{
return (chipset->rf == chip);
return (rt2x00dev->chip.rf == rf);
}
static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset)
static inline u32 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
{
return chipset->rev;
return rt2x00dev->chip.rev;
}
static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset,
static inline bool rt2x00_check_rev(struct rt2x00_dev *rt2x00dev,
const u32 mask, const u32 rev)
{
return ((chipset->rev & mask) == rev);
return ((rt2x00dev->chip.rev & mask) == rev);
}
static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
@ -964,20 +964,20 @@ static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
rt2x00dev->chip.intf = intf;
}
static inline bool rt2x00_intf(const struct rt2x00_chip *chipset,
static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev,
enum rt2x00_chip_intf intf)
{
return (chipset->intf == intf);
return (rt2x00dev->chip.intf == intf);
}
static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev)
{
return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI);
return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
}
static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev)
{
return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB);
return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
}
/**
@ -1019,9 +1019,9 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
int rt2x00mac_start(struct ieee80211_hw *hw);
void rt2x00mac_stop(struct ieee80211_hw *hw);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,

View file

@ -187,10 +187,10 @@ void rt2x00mac_stop(struct ieee80211_hw *hw)
EXPORT_SYMBOL_GPL(rt2x00mac_stop);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(conf->vif);
struct rt2x00_intf *intf = vif_to_intf(vif);
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
struct queue_entry *entry = NULL;
unsigned int i;
@ -203,7 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return -ENODEV;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_AP:
/*
* We don't support mixed combinations of
@ -263,7 +263,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* increase interface count and start initialization.
*/
if (conf->type == NL80211_IFTYPE_AP)
if (vif->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count++;
else
rt2x00dev->intf_sta_count++;
@ -273,16 +273,16 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
if (conf->type == NL80211_IFTYPE_AP)
memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
if (vif->type == NL80211_IFTYPE_AP)
memcpy(&intf->bssid, vif->addr, ETH_ALEN);
memcpy(&intf->mac, vif->addr, ETH_ALEN);
/*
* The MAC adddress must be configured after the device
* has been initialized. Otherwise the device can reset
* the MAC registers.
*/
rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL);
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);
/*
* Some filters depend on the current working mode. We can force
@ -296,10 +296,10 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(conf->vif);
struct rt2x00_intf *intf = vif_to_intf(vif);
/*
* Don't allow interfaces to be remove while
@ -307,11 +307,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
* no interface is present.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
(conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
(conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
(vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
(vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
return;
if (conf->type == NL80211_IFTYPE_AP)
if (vif->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count--;
else
rt2x00dev->intf_sta_count--;

View file

@ -637,8 +637,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
rt61pci_bbp_read(rt2x00dev, 4, &r4);
rt61pci_bbp_read(rt2x00dev, 77, &r77);
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
rt2x00_rf(&rt2x00dev->chip, RF5325));
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325));
/*
* Configure the RX antenna.
@ -684,8 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
rt61pci_bbp_read(rt2x00dev, 4, &r4);
rt61pci_bbp_read(rt2x00dev, 77, &r77);
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
rt2x00_rf(&rt2x00dev->chip, RF2529));
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
!test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
@ -833,12 +831,11 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF5325))
if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325))
rt61pci_config_antenna_5x(rt2x00dev, ant);
else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
else if (rt2x00_rf(rt2x00dev, RF2527))
rt61pci_config_antenna_2x(rt2x00dev, ant);
else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
else if (rt2x00_rf(rt2x00dev, RF2529)) {
if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
rt61pci_config_antenna_2x(rt2x00dev, ant);
else
@ -879,8 +876,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF2527));
smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
rt61pci_bbp_read(rt2x00dev, 3, &r3);
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@ -2302,10 +2298,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
!rt2x00_rf(&rt2x00dev->chip, RF5325) &&
!rt2x00_rf(&rt2x00dev->chip, RF2527) &&
!rt2x00_rf(&rt2x00dev->chip, RF2529)) {
if (!rt2x00_rf(rt2x00dev, RF5225) &&
!rt2x00_rf(rt2x00dev, RF5325) &&
!rt2x00_rf(rt2x00dev, RF2527) &&
!rt2x00_rf(rt2x00dev, RF2529)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@ -2360,7 +2356,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* the antenna settings should be gathered from the NIC
* eeprom word.
*/
if (rt2x00_rf(&rt2x00dev->chip, RF2529) &&
if (rt2x00_rf(rt2x00dev, RF2529) &&
!test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
rt2x00dev->default_ant.rx =
ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
@ -2571,8 +2567,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->channels = rf_vals_seq;
}
if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF5325)) {
if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_seq);
}

View file

@ -136,8 +136,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
* all others contain 20 bits.
*/
rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF2527)));
20 + (rt2x00_rf(rt2x00dev, RF5225) ||
rt2x00_rf(rt2x00dev, RF2527)));
rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
@ -741,11 +741,9 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
rt2x00_rf(&rt2x00dev->chip, RF5225))
if (rt2x00_rf(rt2x00dev, RF5226) || rt2x00_rf(rt2x00dev, RF5225))
rt73usb_config_antenna_5x(rt2x00dev, ant);
else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
rt2x00_rf(&rt2x00dev->chip, RF2527))
else if (rt2x00_rf(rt2x00dev, RF2528) || rt2x00_rf(rt2x00dev, RF2527))
rt73usb_config_antenna_2x(rt2x00dev, ant);
}
@ -779,8 +777,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF2527));
smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
rt73usb_bbp_read(rt2x00dev, 3, &r3);
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@ -1210,8 +1207,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
reg = 0x000023b0;
if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF2527))
if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527))
rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
@ -1827,16 +1823,16 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) ||
rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) ||
rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
if (!rt2x00_rf(&rt2x00dev->chip, RF5226) &&
!rt2x00_rf(&rt2x00dev->chip, RF2528) &&
!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
!rt2x00_rf(&rt2x00dev->chip, RF2527)) {
if (!rt2x00_rf(rt2x00dev, RF5226) &&
!rt2x00_rf(rt2x00dev, RF2528) &&
!rt2x00_rf(rt2x00dev, RF5225) &&
!rt2x00_rf(rt2x00dev, RF2527)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
@ -2081,17 +2077,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
if (rt2x00_rf(rt2x00dev, RF2528)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
spec->channels = rf_vals_bg_2528;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
} else if (rt2x00_rf(rt2x00dev, RF5226)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5226);
spec->channels = rf_vals_5226;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
} else if (rt2x00_rf(rt2x00dev, RF2527)) {
spec->num_channels = 14;
spec->channels = rf_vals_5225_2527;
} else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
} else if (rt2x00_rf(rt2x00dev, RF5225)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
spec->channels = rf_vals_5225_2527;

View file

@ -60,7 +60,6 @@ struct rtl8180_priv {
struct rtl818x_csr __iomem *map;
const struct rtl818x_rf_ops *rf;
struct ieee80211_vif *vif;
int mode;
/* rtl8180 driver specific */
spinlock_t lock;

View file

@ -82,8 +82,6 @@ static const struct ieee80211_channel rtl818x_channels[] = {
};
void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
{
struct rtl8180_priv *priv = dev->priv;
@ -615,7 +613,6 @@ static int rtl8180_start(struct ieee80211_hw *dev)
reg |= RTL818X_CMD_TX_ENABLE;
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
priv->mode = NL80211_IFTYPE_MONITOR;
return 0;
err_free_rings:
@ -633,8 +630,6 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
u8 reg;
int i;
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
reg = rtl818x_ioread8(priv, &priv->map->CMD);
@ -657,38 +652,39 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
}
static int rtl8180_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct rtl8180_priv *priv = dev->priv;
if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
/*
* We only support one active interface at a time.
*/
if (priv->vif)
return -EBUSY;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
break;
default:
return -EOPNOTSUPP;
}
priv->vif = conf->vif;
priv->vif = vif;
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
le32_to_cpu(*(__le32 *)conf->mac_addr));
le32_to_cpu(*(__le32 *)vif->addr));
rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4],
le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
le16_to_cpu(*(__le16 *)(vif->addr + 4)));
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
return 0;
}
static void rtl8180_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct rtl8180_priv *priv = dev->priv;
priv->mode = NL80211_IFTYPE_MONITOR;
priv->vif = NULL;
}

View file

@ -92,7 +92,7 @@ struct rtl8187_priv {
struct rtl818x_csr *map;
const struct rtl818x_rf_ops *rf;
struct ieee80211_vif *vif;
int mode;
/* The mutex protects the TX loopback state.
* Any attempt to set channels concurrently locks the device.
*/

View file

@ -1018,31 +1018,30 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
}
static int rtl8187_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct rtl8187_priv *priv = dev->priv;
int i;
int ret = -EOPNOTSUPP;
mutex_lock(&priv->conf_mutex);
if (priv->mode != NL80211_IFTYPE_MONITOR)
if (priv->vif)
goto exit;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
break;
default:
goto exit;
}
ret = 0;
priv->vif = conf->vif;
priv->vif = vif;
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
for (i = 0; i < ETH_ALEN; i++)
rtl818x_iowrite8(priv, &priv->map->MAC[i],
((u8 *)conf->mac_addr)[i]);
((u8 *)vif->addr)[i]);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
exit:
@ -1051,11 +1050,10 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
}
static void rtl8187_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct rtl8187_priv *priv = dev->priv;
mutex_lock(&priv->conf_mutex);
priv->mode = NL80211_IFTYPE_MONITOR;
priv->vif = NULL;
mutex_unlock(&priv->conf_mutex);
}
@ -1365,7 +1363,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
priv->mode = NL80211_IFTYPE_MONITOR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_RX_INCLUDES_FCS;

View file

@ -33,7 +33,7 @@ static void led_turn_on(struct work_struct *work)
struct rtl8187_led *led = &priv->led_tx;
/* Don't change the LED, when the device is down. */
if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
return ;
/* Skip if the LED is not registered. */
@ -71,7 +71,7 @@ static void led_turn_off(struct work_struct *work)
struct rtl8187_led *led = &priv->led_tx;
/* Don't change the LED, when the device is down. */
if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
return ;
/* Skip if the LED is not registered. */

View file

@ -256,7 +256,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
}
}
if (loop >= INIT_LOOP) {
if (loop > INIT_LOOP) {
wl1251_error("timeout waiting for the hardware to "
"complete initialization");
return -EIO;

View file

@ -511,13 +511,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
}
static int wl1251_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct wl1251 *wl = hw->priv;
int ret = 0;
wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
conf->type, conf->mac_addr);
vif->type, vif->addr);
mutex_lock(&wl->mutex);
if (wl->vif) {
@ -525,9 +525,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
wl->vif = conf->vif;
wl->vif = vif;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS;
break;
@ -539,8 +539,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) {
memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
ret = wl1251_acx_station_id(wl);
if (ret < 0)
@ -553,7 +553,7 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
}
static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct wl1251 *wl = hw->priv;

View file

@ -107,10 +107,9 @@ enum {
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL)
#define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin"
#define WL1271_NVS_LEN 468
/*
* Enable/disable 802.11a support for WL1273
@ -276,6 +275,7 @@ struct wl1271_debugfs {
struct dentry *retry_count;
struct dentry *excessive_retries;
struct dentry *gpio_power;
};
#define NUM_TX_QUEUES 4
@ -322,6 +322,17 @@ struct wl1271 {
enum wl1271_state state;
struct mutex mutex;
#define WL1271_FLAG_STA_RATES_CHANGED (0)
#define WL1271_FLAG_STA_ASSOCIATED (1)
#define WL1271_FLAG_JOINED (2)
#define WL1271_FLAG_GPIO_POWER (3)
#define WL1271_FLAG_TX_QUEUE_STOPPED (4)
#define WL1271_FLAG_SCANNING (5)
#define WL1271_FLAG_IN_ELP (6)
#define WL1271_FLAG_PSM (7)
#define WL1271_FLAG_PSM_REQUESTED (8)
unsigned long flags;
struct wl1271_partition_set part;
struct wl1271_chip chip;
@ -359,7 +370,6 @@ struct wl1271 {
/* Frames scheduled for transmission, not handled yet */
struct sk_buff_head tx_queue;
bool tx_queue_stopped;
struct work_struct tx_work;
@ -387,14 +397,15 @@ struct wl1271 {
u32 mbox_ptr[2];
/* Are we currently scanning */
bool scanning;
struct wl1271_scan scan;
/* Our association ID */
u16 aid;
/* currently configured rate set */
u32 sta_rate_set;
u32 basic_rate_set;
u32 rate_set;
/* The current band */
enum ieee80211_band band;
@ -405,18 +416,9 @@ struct wl1271 {
unsigned int rx_config;
unsigned int rx_filter;
/* is firmware in elp mode */
bool elp;
struct completion *elp_compl;
struct delayed_work elp_work;
/* we can be in psm, but not in elp, we have to differentiate */
bool psm;
/* PSM mode requested */
bool psm_requested;
/* retry counter for PSM entries */
u8 psm_entry_retry;
@ -435,9 +437,6 @@ struct wl1271 {
struct ieee80211_vif *vif;
/* Used for a workaround to send disconnect before rejoining */
bool joined;
/* Current chipset configuration */
struct conf_drv_settings conf;
@ -455,7 +454,9 @@ int wl1271_plt_stop(struct wl1271 *wl);
#define WL1271_TX_QUEUE_MAX_LENGTH 20
/* WL1271 needs a 200ms sleep after power on */
/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
on in case is has been shut down shortly before */
#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
static inline bool wl1271_11a_enabled(void)

View file

@ -390,6 +390,35 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
return ret;
}
int wl1271_acx_dco_itrim_params(struct wl1271 *wl)
{
struct acx_dco_itrim_params *dco;
struct conf_itrim_settings *c = &wl->conf.itrim;
int ret;
wl1271_debug(DEBUG_ACX, "acx dco itrim parameters");
dco = kzalloc(sizeof(*dco), GFP_KERNEL);
if (!dco) {
ret = -ENOMEM;
goto out;
}
dco->enable = c->enable;
dco->timeout = cpu_to_le32(c->timeout);
ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS,
dco, sizeof(*dco));
if (ret < 0) {
wl1271_warning("failed to set dco itrim parameters: %d", ret);
goto out;
}
out:
kfree(dco);
return ret;
}
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
{
struct acx_beacon_filter_option *beacon_filter = NULL;
@ -758,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
return 0;
}
int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
int wl1271_acx_rate_policies(struct wl1271 *wl)
{
struct acx_rate_policy *acx;
struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
int idx = 0;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx rate policies");
@ -773,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
goto out;
}
/* configure one default (one-size-fits-all) rate class */
acx->rate_class_cnt = cpu_to_le32(1);
acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates);
acx->rate_class[0].short_retry_limit = c->short_retry_limit;
acx->rate_class[0].long_retry_limit = c->long_retry_limit;
acx->rate_class[0].aflags = c->aflags;
/* configure one basic rate class */
idx = ACX_TX_BASIC_RATE;
acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set);
acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
acx->rate_class[idx].aflags = c->aflags;
/* configure one AP supported rate class */
idx = ACX_TX_AP_FULL_RATE;
acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
acx->rate_class[idx].aflags = c->aflags;
acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
@ -1012,59 +1051,6 @@ int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
return ret;
}
int wl1271_acx_smart_reflex(struct wl1271 *wl)
{
struct acx_smart_reflex_state *sr_state = NULL;
struct acx_smart_reflex_config_params *sr_param = NULL;
int i, ret;
wl1271_debug(DEBUG_ACX, "acx smart reflex");
sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL);
if (!sr_param) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) {
struct conf_mart_reflex_err_table *e =
&(wl->conf.init.sr_err_tbl[i]);
sr_param->error_table[i].len = e->len;
sr_param->error_table[i].upper_limit = e->upper_limit;
memcpy(sr_param->error_table[i].values, e->values, e->len);
}
ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS,
sr_param, sizeof(*sr_param));
if (ret < 0) {
wl1271_warning("failed to set smart reflex params: %d", ret);
goto out;
}
sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
if (!sr_state) {
ret = -ENOMEM;
goto out;
}
/* enable smart reflex */
sr_state->enable = wl->conf.init.sr_enable;
ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE,
sr_state, sizeof(*sr_state));
if (ret < 0) {
wl1271_warning("failed to set smart reflex params: %d", ret);
goto out;
}
out:
kfree(sr_state);
kfree(sr_param);
return ret;
}
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
{
struct wl1271_acx_bet_enable *acx = NULL;
@ -1132,3 +1118,31 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
kfree(acx);
return ret;
}
int wl1271_acx_pm_config(struct wl1271 *wl)
{
struct wl1271_acx_pm_config *acx = NULL;
struct conf_pm_config_settings *c = &wl->conf.pm_config;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx pm config");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time);
acx->host_fast_wakeup_support = c->host_fast_wakeup_support;
ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx pm config failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}

View file

@ -415,23 +415,12 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __attribute__ ((packed));
struct acx_smart_reflex_state {
struct acx_dco_itrim_params {
struct acx_header header;
u8 enable;
u8 padding[3];
} __attribute__ ((packed));
struct smart_reflex_err_table {
u8 len;
s8 upper_limit;
s8 values[14];
} __attribute__ ((packed));
struct acx_smart_reflex_config_params {
struct acx_header header;
struct smart_reflex_err_table error_table[3];
__le32 timeout;
} __attribute__ ((packed));
#define PTA_ANTENNA_TYPE_DEF (0)
@ -837,6 +826,9 @@ struct acx_rate_class {
u8 reserved;
};
#define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1
#define ACX_TX_RATE_POLICY_CNT 2
struct acx_rate_policy {
struct acx_header header;
@ -877,8 +869,8 @@ struct acx_tx_config_options {
__le16 tx_compl_threshold; /* number of packets */
} __attribute__ ((packed));
#define ACX_RX_MEM_BLOCKS 64
#define ACX_TX_MIN_MEM_BLOCKS 64
#define ACX_RX_MEM_BLOCKS 70
#define ACX_TX_MIN_MEM_BLOCKS 40
#define ACX_TX_DESCRIPTORS 32
#define ACX_NUM_SSID_PROFILES 1
@ -969,6 +961,13 @@ struct wl1271_acx_arp_filter {
used. */
} __attribute__((packed));
struct wl1271_acx_pm_config {
struct acx_header header;
__le32 host_clk_settling_time;
u8 host_fast_wakeup_support;
u8 padding[3];
} __attribute__ ((packed));
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
@ -1027,13 +1026,13 @@ enum {
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
ACX_SET_SMART_REFLEX_DEBUG = 0x005A,
ACX_SET_SMART_REFLEX_STATE = 0x005B,
ACX_SET_SMART_REFLEX_PARAMS = 0x005F,
ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D,
DOT11_RX_DOT11_MODE = 0x1012,
DOT11_RTS_THRESHOLD = 0x1013,
DOT11_GROUP_ADDRESS_TBL = 0x1014,
ACX_PM_CONFIG = 0x1016,
MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
@ -1056,6 +1055,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
void *mc_list, u32 mc_list_len);
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
int wl1271_acx_conn_monit_params(struct wl1271 *wl);
@ -1069,7 +1069,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int wl1271_acx_cts_protect(struct wl1271 *wl,
enum acx_ctsprotect_type ctsprotect);
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates);
int wl1271_acx_rate_policies(struct wl1271 *wl);
int wl1271_acx_ac_cfg(struct wl1271 *wl);
int wl1271_acx_tid_cfg(struct wl1271 *wl);
int wl1271_acx_frag_threshold(struct wl1271 *wl);
@ -1081,5 +1081,6 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
u8 version);
int wl1271_acx_pm_config(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */

View file

@ -225,9 +225,15 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
if (nvs == NULL)
return -ENODEV;
if (wl->nvs_len < WL1271_NVS_LEN)
return -EINVAL;
nvs_ptr = nvs;
nvs_len = wl->nvs_len;
/* only the first part of the NVS needs to be uploaded */
nvs_len = WL1271_NVS_LEN;
/* FIXME: read init settings from the remaining part of the NVS */
/* Update the device MAC address into the nvs */
nvs[11] = wl->mac_addr[0];

View file

@ -209,6 +209,26 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
gen_parms->settings = g->settings;
gen_parms->sr_state = g->sr_state;
memcpy(gen_parms->srf1,
g->srf1,
CONF_MAX_SMART_REFLEX_PARAMS);
memcpy(gen_parms->srf2,
g->srf2,
CONF_MAX_SMART_REFLEX_PARAMS);
memcpy(gen_parms->srf3,
g->srf3,
CONF_MAX_SMART_REFLEX_PARAMS);
memcpy(gen_parms->sr_debug_table,
g->sr_debug_table,
CONF_MAX_SMART_REFLEX_PARAMS);
gen_parms->sr_sen_n_p = g->sr_sen_n_p;
gen_parms->sr_sen_n_p_gain = g->sr_sen_n_p_gain;
gen_parms->sr_sen_nrn = g->sr_sen_nrn;
gen_parms->sr_sen_prn = g->sr_sen_prn;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@ -253,6 +273,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_extreme, r->tx_rate_limits_extreme,
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
CONF_NUMBER_OF_CHANNELS_2_4);
@ -263,6 +285,11 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
radio_parms->degraded_low_to_normal_threshold =
r->degraded_low_to_normal_threshold;
radio_parms->degraded_normal_to_high_threshold =
r->degraded_normal_to_high_threshold;
for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
radio_parms->tx_ref_pd_voltage_5[i] =
@ -275,6 +302,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_degraded_5,
r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_rate_limits_extreme_5,
r->tx_rate_limits_extreme_5, CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->tx_channel_limits_ofdm_5,
r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
@ -283,6 +312,10 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
CONF_NUMBER_OF_RATE_GROUPS);
memcpy(radio_parms->rx_fem_insertion_loss_5,
r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
radio_parms->degraded_low_to_normal_threshold_5 =
r->degraded_low_to_normal_threshold_5;
radio_parms->degraded_normal_to_high_threshold_5 =
r->degraded_normal_to_high_threshold_5;
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
@ -311,19 +344,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
do_cal = false;
}
/* FIXME: This is a workaround, because with the current stack, we
* cannot know when we have disassociated. So, if we have already
* joined, we disconnect before joining again. */
if (wl->joined) {
ret = wl1271_cmd_disconnect(wl);
if (ret < 0) {
wl1271_error("failed to disconnect before rejoining");
goto out;
}
wl->joined = false;
}
join = kzalloc(sizeof(*join), GFP_KERNEL);
if (!join) {
ret = -ENOMEM;
@ -388,8 +408,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
goto out_free;
}
wl->joined = true;
/*
* ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
* simplify locking we just sleep instead, for now
@ -487,7 +505,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
return 0;
}
int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
{
struct cmd_enabledisable_path *cmd;
int ret;
@ -501,7 +519,8 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
goto out;
}
cmd->channel = channel;
/* the channel here is only used for calibration, so hardcoded to 1 */
cmd->channel = 1;
if (enable) {
cmd_rx = CMD_ENABLE_RX;
@ -514,22 +533,22 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("rx %s cmd for channel %d failed",
enable ? "start" : "stop", channel);
enable ? "start" : "stop", cmd->channel);
goto out;
}
wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
enable ? "start" : "stop", channel);
enable ? "start" : "stop", cmd->channel);
ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("tx %s cmd for channel %d failed",
enable ? "start" : "stop", channel);
enable ? "start" : "stop", cmd->channel);
return ret;
}
wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
enable ? "start" : "stop", channel);
enable ? "start" : "stop", cmd->channel);
out:
kfree(cmd);
@ -636,7 +655,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
channels = wl->hw->wiphy->bands[ieee_band]->channels;
n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
if (wl->scanning)
if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
return -EINVAL;
params = kzalloc(sizeof(*params), GFP_KERNEL);
@ -711,7 +730,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
wl->scanning = true;
set_bit(WL1271_FLAG_SCANNING, &wl->flags);
if (wl1271_11a_enabled()) {
wl->scan.state = band;
if (band == WL1271_SCAN_BAND_DUAL) {
@ -729,7 +748,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
if (ret < 0) {
wl1271_error("SCAN failed");
wl->scanning = false;
clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
goto out;
}
@ -777,7 +796,7 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
return ret;
}
static int wl1271_build_basic_rates(char *rates, u8 band)
static int wl1271_build_basic_rates(u8 *rates, u8 band)
{
u8 index = 0;
@ -804,7 +823,7 @@ static int wl1271_build_basic_rates(char *rates, u8 band)
return index;
}
static int wl1271_build_extended_rates(char *rates, u8 band)
static int wl1271_build_extended_rates(u8 *rates, u8 band)
{
u8 index = 0;

View file

@ -37,7 +37,7 @@ int wl1271_cmd_join(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
@ -437,6 +437,21 @@ struct wl1271_general_parms_cmd {
u8 tx_bip_fem_autodetect;
u8 tx_bip_fem_manufacturer;
u8 settings;
u8 sr_state;
s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
u8 padding[3];
} __attribute__ ((packed));
struct wl1271_radio_parms_cmd {
@ -458,11 +473,12 @@ struct wl1271_radio_parms_cmd {
/* Dynamic radio parameters */
/* 2.4GHz */
__le16 tx_ref_pd_voltage;
s8 tx_ref_power;
u8 tx_ref_power;
s8 tx_offset_db;
s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
@ -471,15 +487,19 @@ struct wl1271_radio_parms_cmd {
u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 padding2;
u8 degraded_low_to_normal_threshold;
u8 degraded_normal_to_high_threshold;
u8 padding1; /* our own padding, not in ref driver */
/* 5GHz */
__le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
@ -488,7 +508,10 @@ struct wl1271_radio_parms_cmd {
s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 padding3[2];
u8 degraded_low_to_normal_threshold_5;
u8 degraded_normal_to_high_threshold_5;
u8 padding2[2];
} __attribute__ ((packed));
struct wl1271_cmd_cal_channel_tune {

View file

@ -258,7 +258,8 @@ struct conf_rx_settings {
#define CONF_TX_MAX_RATE_CLASSES 8
#define CONF_TX_RATE_MASK_UNSPECIFIED 0
#define CONF_TX_RATE_MASK_ALL 0x1eff
#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS)
#define CONF_TX_RATE_RETRY_LIMIT 10
struct conf_tx_rate_class {
@ -722,31 +723,6 @@ struct conf_conn_settings {
u8 psm_entry_retries;
};
#define CONF_SR_ERR_TBL_MAX_VALUES 14
struct conf_mart_reflex_err_table {
/*
* Length of the error table values table.
*
* Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES
*/
u8 len;
/*
* Smart Reflex error table upper limit.
*
* Range: s8
*/
s8 upper_limit;
/*
* Smart Reflex error table values.
*
* Range: s8
*/
s8 values[CONF_SR_ERR_TBL_MAX_VALUES];
};
enum {
CONF_REF_CLK_19_2_E,
CONF_REF_CLK_26_E,
@ -759,6 +735,9 @@ enum single_dual_band_enum {
CONF_DUAL_BAND
};
#define CONF_MAX_SMART_REFLEX_PARAMS 16
struct conf_general_parms {
/*
* RF Reference Clock type / speed
@ -815,6 +794,20 @@ struct conf_general_parms {
* Range: Unknown
*/
u8 settings;
/* Smart reflex settings */
u8 sr_state;
s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
};
#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
@ -847,12 +840,13 @@ struct conf_radio_parms {
*
* Range: unknown
*/
s16 tx_ref_pd_voltage;
s8 tx_ref_power;
u16 tx_ref_pd_voltage;
u8 tx_ref_power;
s8 tx_offset_db;
s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
@ -861,17 +855,22 @@ struct conf_radio_parms {
u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 degraded_low_to_normal_threshold;
u8 degraded_normal_to_high_threshold;
/*
* Dynamic radio parameters for 5GHz
*
* Range: unknown
*/
s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
u16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
@ -879,23 +878,12 @@ struct conf_radio_parms {
/* FIXME: this is inconsistent with the types for 2.4GHz */
s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 degraded_low_to_normal_threshold_5;
u8 degraded_normal_to_high_threshold_5;
};
#define CONF_SR_ERR_TBL_COUNT 3
struct conf_init_settings {
/*
* Configure Smart Reflex error table values.
*/
struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT];
/*
* Smart Reflex enable flag.
*
* Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled
*/
u8 sr_enable;
/*
* Configure general parameters.
*/
@ -908,12 +896,38 @@ struct conf_init_settings {
};
struct conf_itrim_settings {
/* enable dco itrim */
u8 enable;
/* moderation timeout in microsecs from the last TX */
u32 timeout;
};
struct conf_pm_config_settings {
/*
* Host clock settling time
*
* Range: 0 - 30000 us
*/
u32 host_clk_settling_time;
/*
* Host fast wakeup support
*
* Range: true, false
*/
bool host_fast_wakeup_support;
};
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
struct conf_tx_settings tx;
struct conf_conn_settings conn;
struct conf_init_settings init;
struct conf_itrim_settings itrim;
struct conf_pm_config_settings pm_config;
};
#endif

View file

@ -237,6 +237,64 @@ static const struct file_operations tx_queue_len_ops = {
.open = wl1271_open_file_generic,
};
static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
int res;
char buf[10];
res = scnprintf(buf, sizeof(buf), "%d\n", state);
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
}
static ssize_t gpio_power_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
char buf[10];
size_t len;
unsigned long value;
int ret;
mutex_lock(&wl->mutex);
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len)) {
ret = -EFAULT;
goto out;
}
buf[len] = '\0';
ret = strict_strtoul(buf, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value in gpio_power");
goto out;
}
if (value) {
wl->set_power(true);
set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
} else {
wl->set_power(false);
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
}
out:
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations gpio_power_ops = {
.read = gpio_power_read,
.write = gpio_power_write,
.open = wl1271_open_file_generic
};
static void wl1271_debugfs_delete_files(struct wl1271 *wl)
{
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@ -333,6 +391,8 @@ static void wl1271_debugfs_delete_files(struct wl1271 *wl)
DEBUGFS_DEL(tx_queue_len);
DEBUGFS_DEL(retry_count);
DEBUGFS_DEL(excessive_retries);
DEBUGFS_DEL(gpio_power);
}
static int wl1271_debugfs_add_files(struct wl1271 *wl)
@ -434,6 +494,8 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir);
out:
if (ret < 0)
wl1271_debugfs_delete_files(wl);

View file

@ -35,7 +35,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
mbox->scheduled_scan_status);
if (wl->scanning) {
if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
NULL, size);
@ -43,7 +43,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
* to the wl1271_cmd_scan function that we are not
* scanning as it checks that.
*/
wl->scanning = false;
clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
wl->scan.active,
wl->scan.high_prio,
@ -62,7 +62,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
mutex_lock(&wl->mutex);
wl->scanning = false;
clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
}
}
return 0;
@ -78,7 +78,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
switch (mbox->ps_status) {
case EVENT_ENTER_POWER_SAVE_FAIL:
if (!wl->psm) {
if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
wl->psm_entry_retry = 0;
break;
}
@ -89,7 +89,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
} else {
wl1271_error("PSM entry failed, giving up.\n");
wl->psm_entry_retry = 0;
*beacon_loss = true;
}
break;
case EVENT_ENTER_POWER_SAVE_SUCCESS:
@ -136,7 +135,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
* filtering) is enabled. Without PSM, the stack will receive all
* beacons and can detect beacon loss by itself.
*/
if (vector & BSS_LOSE_EVENT_ID && wl->psm) {
if (vector & BSS_LOSE_EVENT_ID &&
test_bit(WL1271_FLAG_PSM, &wl->flags)) {
wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
/* indicate to the stack, that beacons have been lost */
@ -150,7 +150,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
return ret;
}
if (beacon_loss) {
if (wl->vif && beacon_loss) {
/* Obviously, it's dangerous to release the mutex while
we are holding many of the variables in the wl struct.
That's why it's done last in the function, and care must
@ -184,7 +184,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl)
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
{
struct event_mailbox mbox;
int ret;
@ -204,9 +204,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
return ret;
/* then we let the firmware know it can go on...*/
if (do_ack)
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG,
INTR_TRIG_EVENT_ACK);
wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
return 0;
}

View file

@ -112,6 +112,6 @@ struct event_mailbox {
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
#endif

View file

@ -229,6 +229,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
ret = wl1271_acx_dco_itrim_params(wl);
if (ret < 0)
goto out_free_memmap;
/* Initialize connection monitoring thresholds */
ret = wl1271_acx_conn_monit_params(wl);
if (ret < 0)
@ -280,12 +284,12 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Configure TX rate classes */
ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL);
ret = wl1271_acx_rate_policies(wl);
if (ret < 0)
goto out_free_memmap;
/* Enable data path */
ret = wl1271_cmd_data_path(wl, wl->channel, 1);
ret = wl1271_cmd_data_path(wl, 1);
if (ret < 0)
goto out_free_memmap;
@ -299,8 +303,8 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
/* Configure smart reflex */
ret = wl1271_acx_smart_reflex(wl);
/* configure PM */
ret = wl1271_acx_pm_config(wl);
if (ret < 0)
goto out_free_memmap;

View file

@ -47,6 +47,8 @@
#include "wl1271_cmd.h"
#include "wl1271_boot.h"
#define WL1271_BOOT_RETRIES 3
static struct conf_drv_settings default_conf = {
.sg = {
.per_threshold = 7500,
@ -67,16 +69,17 @@ static struct conf_drv_settings default_conf = {
.ps_poll_timeout = 15,
.upsd_timeout = 15,
.rts_threshold = 2347,
.rx_cca_threshold = 0xFFEF,
.irq_blk_threshold = 0,
.irq_pkt_threshold = USHORT_MAX,
.irq_timeout = 5,
.rx_cca_threshold = 0,
.irq_blk_threshold = 0xFFFF,
.irq_pkt_threshold = 0,
.irq_timeout = 600,
.queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
},
.tx = {
.tx_energy_detection = 0,
.rc_conf = {
.enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
.enabled_rates = CONF_HW_BIT_RATE_1MBPS |
CONF_HW_BIT_RATE_2MBPS,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0
@ -172,8 +175,8 @@ static struct conf_drv_settings default_conf = {
}
},
.frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
.tx_compl_timeout = 5,
.tx_compl_threshold = 5
.tx_compl_timeout = 700,
.tx_compl_threshold = 4
},
.conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
@ -186,12 +189,12 @@ static struct conf_drv_settings default_conf = {
.rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
}
},
.synch_fail_thold = 5,
.synch_fail_thold = 10,
.bss_lose_timeout = 100,
.beacon_rx_timeout = 10000,
.broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1,
.ps_poll_threshold = 4,
.ps_poll_threshold = 20,
.sig_trigger_count = 2,
.sig_trigger = {
[0] = {
@ -226,46 +229,35 @@ static struct conf_drv_settings default_conf = {
.psm_entry_retries = 3
},
.init = {
.sr_err_tbl = {
[0] = {
.len = 7,
.upper_limit = 0x03,
.values = {
0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
0x00 }
},
[1] = {
.len = 7,
.upper_limit = 0x03,
.values = {
0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
0x00 }
},
[2] = {
.len = 7,
.upper_limit = 0x03,
.values = {
0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
0x00 }
}
},
.sr_enable = 1,
.genparam = {
.ref_clk = CONF_REF_CLK_38_4_E,
.settling_time = 5,
.clk_valid_on_wakeup = 0,
.dc2dcmode = 0,
.single_dual_band = CONF_SINGLE_BAND,
.tx_bip_fem_autodetect = 0,
.tx_bip_fem_autodetect = 1,
.tx_bip_fem_manufacturer = 1,
.settings = 1,
.sr_state = 1,
.srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
.srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
.srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
.sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 },
.sr_sen_n_p = 0,
.sr_sen_n_p_gain = 0,
.sr_sen_nrn = 0,
.sr_sen_prn = 0,
},
.radioparam = {
.rx_trace_loss = 10,
.tx_trace_loss = 10,
.rx_trace_loss = 0x24,
.tx_trace_loss = 0x0,
.rx_rssi_and_proc_compens = {
0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8,
0x00, 0x0a, 0x14 },
.rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
.tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
@ -273,13 +265,15 @@ static struct conf_drv_settings default_conf = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00 },
.tx_ref_pd_voltage = 0x24e,
.tx_ref_power = 0x78,
.tx_ref_pd_voltage = 0x1a9,
.tx_ref_power = 0x80,
.tx_offset_db = 0x0,
.tx_rate_limits_normal = {
0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 },
.tx_rate_limits_degraded = {
0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 },
.tx_rate_limits_extreme = {
0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
.tx_channel_limits_11b = {
0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
@ -289,10 +283,12 @@ static struct conf_drv_settings default_conf = {
0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
0x20, 0x50 },
.tx_pdv_rate_offsets = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
0x07, 0x08, 0x04, 0x02, 0x02, 0x00 },
.tx_ibias = {
0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
.rx_fem_insertion_loss = 0x14,
0x11, 0x11, 0x15, 0x11, 0x15, 0x0f },
.rx_fem_insertion_loss = 0x0e,
.degraded_low_to_normal_threshold = 0x1e,
.degraded_normal_to_high_threshold = 0x2d,
.tx_ref_pd_voltage_5 = {
0x0190, 0x01a4, 0x01c3, 0x01d8,
0x020a, 0x021c },
@ -304,6 +300,8 @@ static struct conf_drv_settings default_conf = {
0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
.tx_rate_limits_degraded_5 = {
0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
.tx_rate_limits_extreme_5 = {
0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
.tx_channel_limits_ofdm_5 = {
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
@ -315,8 +313,18 @@ static struct conf_drv_settings default_conf = {
.tx_ibias_5 = {
0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
.rx_fem_insertion_loss_5 = {
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
.degraded_low_to_normal_threshold_5 = 0x00,
.degraded_normal_to_high_threshold_5 = 0x00
}
},
.itrim = {
.enable = false,
.timeout = 50000,
},
.pm_config = {
.host_clk_settling_time = 5000,
.host_fast_wakeup_support = false
}
};
@ -359,7 +367,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
return ret;
ret = wl1271_cmd_data_path(wl, wl->channel, 1);
ret = wl1271_cmd_data_path(wl, 1);
if (ret < 0)
return ret;
@ -374,11 +382,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl)
static void wl1271_power_off(struct wl1271 *wl)
{
wl->set_power(false);
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
}
static void wl1271_power_on(struct wl1271 *wl)
{
wl->set_power(true);
set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
}
static void wl1271_fw_status(struct wl1271 *wl,
@ -447,14 +457,13 @@ static void wl1271_irq_work(struct work_struct *work)
intr &= WL1271_INTR_MASK;
if (intr & WL1271_ACX_INTR_EVENT_A) {
bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
wl1271_event_handle(wl, 0, do_ack);
wl1271_event_handle(wl, 0);
}
if (intr & WL1271_ACX_INTR_EVENT_B) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
wl1271_event_handle(wl, 1, true);
wl1271_event_handle(wl, 1);
}
if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
@ -614,6 +623,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
struct wl1271_partition_set partition;
int ret = 0;
msleep(WL1271_PRE_POWER_ON_SLEEP);
wl1271_power_on(wl);
msleep(WL1271_POWER_ON_SLEEP);
wl1271_spi_reset(wl);
@ -643,7 +653,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
goto out_power_off;
goto out;
break;
case CHIP_ID_1271_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
@ -651,38 +661,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
goto out_power_off;
goto out;
break;
default:
wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out_power_off;
goto out;
}
if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
goto out_power_off;
goto out;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
ret = wl1271_fetch_nvs(wl);
if (ret < 0)
goto out_power_off;
goto out;
}
goto out;
out_power_off:
wl1271_power_off(wl);
out:
return ret;
}
int wl1271_plt_start(struct wl1271 *wl)
{
int retries = WL1271_BOOT_RETRIES;
int ret;
mutex_lock(&wl->mutex);
@ -696,35 +702,48 @@ int wl1271_plt_start(struct wl1271 *wl)
goto out;
}
wl->state = WL1271_STATE_PLT;
while (retries) {
retries--;
ret = wl1271_chip_wakeup(wl);
if (ret < 0)
goto power_off;
ret = wl1271_chip_wakeup(wl);
if (ret < 0)
ret = wl1271_boot(wl);
if (ret < 0)
goto power_off;
ret = wl1271_plt_init(wl);
if (ret < 0)
goto irq_disable;
/* Make sure power saving is disabled */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0)
goto irq_disable;
wl->state = WL1271_STATE_PLT;
wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver);
goto out;
ret = wl1271_boot(wl);
if (ret < 0)
goto out_power_off;
wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
ret = wl1271_plt_init(wl);
if (ret < 0)
goto out_irq_disable;
/* Make sure power saving is disabled */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0)
goto out_irq_disable;
goto out;
out_irq_disable:
wl1271_disable_interrupts(wl);
out_power_off:
wl1271_power_off(wl);
irq_disable:
wl1271_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
/* Unlocking the mutex in the middle of handling is
inherently unsafe. In this case we deem it safe to do,
because we need to let any possibly pending IRQ out of
the system (and while we are WL1271_STATE_OFF the IRQ
work function will not do anything.) Also, any other
possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */
cancel_work_sync(&wl->irq_work);
mutex_lock(&wl->mutex);
power_off:
wl1271_power_off(wl);
}
wl1271_error("firmware boot in PLT mode failed despite %d retries",
WL1271_BOOT_RETRIES);
out:
mutex_unlock(&wl->mutex);
@ -762,7 +781,20 @@ int wl1271_plt_stop(struct wl1271 *wl)
static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct wl1271 *wl = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = txinfo->control.sta;
unsigned long flags;
/* peek into the rates configured in the STA entry */
spin_lock_irqsave(&wl->wl_lock, flags);
if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
wl->sta_rate_set = sta->supp_rates[conf->channel->band];
set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
}
spin_unlock_irqrestore(&wl->wl_lock, flags);
/* queue the packet */
skb_queue_tail(&wl->tx_queue, skb);
/*
@ -784,7 +816,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* protected. Maybe fix this by removing the stupid
* variable altogether and checking the real queue state?
*/
wl->tx_queue_stopped = true;
set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
}
return NETDEV_TX_OK;
@ -880,6 +912,7 @@ static struct notifier_block wl1271_dev_notifier = {
static int wl1271_op_start(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
int retries = WL1271_BOOT_RETRIES;
int ret = 0;
wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@ -893,30 +926,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
goto out;
}
ret = wl1271_chip_wakeup(wl);
if (ret < 0)
while (retries) {
retries--;
ret = wl1271_chip_wakeup(wl);
if (ret < 0)
goto power_off;
ret = wl1271_boot(wl);
if (ret < 0)
goto power_off;
ret = wl1271_hw_init(wl);
if (ret < 0)
goto irq_disable;
wl->state = WL1271_STATE_ON;
wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
goto out;
ret = wl1271_boot(wl);
if (ret < 0)
goto out_power_off;
ret = wl1271_hw_init(wl);
if (ret < 0)
goto out_irq_disable;
wl->state = WL1271_STATE_ON;
wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
goto out;
out_irq_disable:
wl1271_disable_interrupts(wl);
out_power_off:
wl1271_power_off(wl);
irq_disable:
wl1271_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
/* Unlocking the mutex in the middle of handling is
inherently unsafe. In this case we deem it safe to do,
because we need to let any possibly pending IRQ out of
the system (and while we are WL1271_STATE_OFF the IRQ
work function will not do anything.) Also, any other
possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */
cancel_work_sync(&wl->irq_work);
mutex_lock(&wl->mutex);
power_off:
wl1271_power_off(wl);
}
wl1271_error("firmware boot failed despite %d retries",
WL1271_BOOT_RETRIES);
out:
mutex_unlock(&wl->mutex);
@ -944,11 +989,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
WARN_ON(wl->state != WL1271_STATE_ON);
if (wl->scanning) {
if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, true);
mutex_lock(&wl->mutex);
wl->scanning = false;
}
wl->state = WL1271_STATE_OFF;
@ -973,10 +1017,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->band = IEEE80211_BAND_2GHZ;
wl->rx_counter = 0;
wl->elp = false;
wl->psm = 0;
wl->psm_entry_retry = 0;
wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->tx_blocks_available = 0;
wl->tx_results_count = 0;
@ -986,7 +1027,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_security_seq_32 = 0;
wl->time_offset = 0;
wl->session_counter = 0;
wl->joined = false;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->sta_rate_set = 0;
wl->flags = 0;
for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0;
@ -996,13 +1039,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
}
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
int ret = 0;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
conf->type, conf->mac_addr);
vif->type, vif->addr);
mutex_lock(&wl->mutex);
if (wl->vif) {
@ -1010,9 +1053,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
wl->vif = conf->vif;
wl->vif = vif;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS;
break;
@ -1032,7 +1075,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
}
static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
@ -1109,6 +1152,51 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
}
#endif
static int wl1271_join_channel(struct wl1271 *wl, int channel)
{
int ret = 0;
/* we need to use a dummy BSSID for now */
static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
0xad, 0xbe, 0xef };
/* the dummy join is not required for ad-hoc */
if (wl->bss_type == BSS_TYPE_IBSS)
goto out;
/* disable mac filter, so we hear everything */
wl->rx_config &= ~CFG_BSSID_FILTER_EN;
wl->channel = channel;
memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
ret = wl1271_cmd_join(wl);
if (ret < 0)
goto out;
set_bit(WL1271_FLAG_JOINED, &wl->flags);
out:
return ret;
}
static int wl1271_unjoin_channel(struct wl1271 *wl)
{
int ret;
/* to stop listening to a channel, we disconnect */
ret = wl1271_cmd_disconnect(wl);
if (ret < 0)
goto out;
clear_bit(WL1271_FLAG_JOINED, &wl->flags);
wl->channel = 0;
memset(wl->bssid, 0, ETH_ALEN);
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
out:
return ret;
}
static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct wl1271 *wl = hw->priv;
@ -1117,10 +1205,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
channel,
conf->flags & IEEE80211_CONF_PS ? "on" : "off",
conf->power_level);
conf->power_level,
conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
mutex_lock(&wl->mutex);
@ -1130,34 +1219,44 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (ret < 0)
goto out;
if (channel != wl->channel) {
/*
* We assume that the stack will configure the right channel
* before associating, so we don't need to send a join
* command here. We will join the right channel when the
* BSSID changes
*/
wl->channel = channel;
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
if (conf->flags & IEEE80211_CONF_IDLE &&
test_bit(WL1271_FLAG_JOINED, &wl->flags))
wl1271_unjoin_channel(wl);
else if (!(conf->flags & IEEE80211_CONF_IDLE))
wl1271_join_channel(wl, channel);
if (conf->flags & IEEE80211_CONF_IDLE) {
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->sta_rate_set = 0;
wl1271_acx_rate_policies(wl);
}
}
if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
wl1271_info("psm enabled");
/* if the channel changes while joined, join again */
if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags))
wl1271_join_channel(wl, channel);
wl->psm_requested = true;
if (conf->flags & IEEE80211_CONF_PS &&
!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
/*
* We enter PSM only if we're already associated.
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
*/
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
wl1271_info("psm enabled");
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
}
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
wl->psm_requested) {
test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
wl1271_info("psm disabled");
wl->psm_requested = false;
clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
if (wl->psm)
if (test_bit(WL1271_FLAG_PSM, &wl->flags))
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
}
@ -1440,22 +1539,6 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret;
}
static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
{
struct ieee80211_supported_band *band;
u32 enabled_rates = 0;
int bit;
band = wl->hw->wiphy->bands[wl->band];
for (bit = 0; bit < band->n_bitrates; bit++) {
if (basic_rate_set & 0x1)
enabled_rates |= band->bitrates[bit].hw_value;
basic_rate_set >>= 1;
}
return enabled_rates;
}
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@ -1473,9 +1556,68 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
if ((changed & BSS_CHANGED_BSSID) &&
/*
* Now we know the correct bssid, so we send a new join command
* and enable the BSSID filter
*/
memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
wl->rx_config |= CFG_BSSID_FILTER_EN;
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
ret = wl1271_cmd_build_null_data(wl);
if (ret < 0) {
wl1271_warning("cmd buld null data failed %d",
ret);
goto out_sleep;
}
ret = wl1271_cmd_join(wl);
if (ret < 0) {
wl1271_warning("cmd join failed %d", ret);
goto out_sleep;
}
set_bit(WL1271_FLAG_JOINED, &wl->flags);
}
if (wl->bss_type == BSS_TYPE_IBSS) {
/* FIXME: This implements rudimentary ad-hoc support -
proper templates are on the wish list and notification
on when they change. This patch will update the templates
on every call to this function. Also, the firmware will not
answer to probe-requests as it does not have the proper
SSID set in the JOIN command. The probe-response template
is set nevertheless, as the FW will ASSERT without it */
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (beacon) {
struct ieee80211_hdr *hdr;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
beacon->data,
beacon->len);
if (ret < 0) {
dev_kfree_skb(beacon);
goto out_sleep;
}
hdr = (struct ieee80211_hdr *) beacon->data;
hdr->frame_control = cpu_to_le16(
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP);
ret = wl1271_cmd_template_set(wl,
CMD_TEMPL_PROBE_RESPONSE,
beacon->data,
beacon->len);
dev_kfree_skb(beacon);
if (ret < 0)
goto out_sleep;
}
}
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
/*
* with wl1271, we don't need to update the
@ -1492,7 +1634,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
goto out_sleep;
/* If we want to go in PSM but we're not there yet */
if (wl->psm_requested && !wl->psm) {
if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
mode = STATION_POWER_SAVE_MODE;
ret = wl1271_ps_set_mode(wl, mode);
if (ret < 0)
@ -1500,7 +1643,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
} else {
/* use defaults when not associated */
wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
}
@ -1535,17 +1678,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
if (changed & BSS_CHANGED_BASIC_RATES) {
wl->basic_rate_set = wl1271_enabled_rates_get(
wl, bss_conf->basic_rates);
ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
if (ret < 0) {
wl1271_warning("Set rate policies failed %d", ret);
goto out_sleep;
}
}
out_sleep:
wl1271_ps_elp_sleep(wl);
@ -1599,19 +1731,19 @@ static struct ieee80211_rate wl1271_rates[] = {
/* can't be const, mac80211 writes to this */
static struct ieee80211_channel wl1271_channels[] = {
{ .hw_value = 1, .center_freq = 2412},
{ .hw_value = 2, .center_freq = 2417},
{ .hw_value = 3, .center_freq = 2422},
{ .hw_value = 4, .center_freq = 2427},
{ .hw_value = 5, .center_freq = 2432},
{ .hw_value = 6, .center_freq = 2437},
{ .hw_value = 7, .center_freq = 2442},
{ .hw_value = 8, .center_freq = 2447},
{ .hw_value = 9, .center_freq = 2452},
{ .hw_value = 10, .center_freq = 2457},
{ .hw_value = 11, .center_freq = 2462},
{ .hw_value = 12, .center_freq = 2467},
{ .hw_value = 13, .center_freq = 2472},
{ .hw_value = 1, .center_freq = 2412, .max_power = 25 },
{ .hw_value = 2, .center_freq = 2417, .max_power = 25 },
{ .hw_value = 3, .center_freq = 2422, .max_power = 25 },
{ .hw_value = 4, .center_freq = 2427, .max_power = 25 },
{ .hw_value = 5, .center_freq = 2432, .max_power = 25 },
{ .hw_value = 6, .center_freq = 2437, .max_power = 25 },
{ .hw_value = 7, .center_freq = 2442, .max_power = 25 },
{ .hw_value = 8, .center_freq = 2447, .max_power = 25 },
{ .hw_value = 9, .center_freq = 2452, .max_power = 25 },
{ .hw_value = 10, .center_freq = 2457, .max_power = 25 },
{ .hw_value = 11, .center_freq = 2462, .max_power = 25 },
{ .hw_value = 12, .center_freq = 2467, .max_power = 25 },
{ .hw_value = 13, .center_freq = 2472, .max_power = 25 },
};
/* can't be const, mac80211 writes to this */
@ -1757,7 +1889,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_BEACON_FILTER |
IEEE80211_HW_SUPPORTS_PS;
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
@ -1818,21 +1951,18 @@ static int __devinit wl1271_probe(struct spi_device *spi)
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
wl->channel = WL1271_DEFAULT_CHANNEL;
wl->scanning = false;
wl->default_key = 0;
wl->rx_counter = 0;
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
wl->elp = false;
wl->psm = 0;
wl->psm_requested = false;
wl->psm_entry_retry = 0;
wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->sta_rate_set = 0;
wl->band = IEEE80211_BAND_2GHZ;
wl->vif = NULL;
wl->joined = false;
wl->flags = 0;
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;

View file

@ -39,12 +39,13 @@ void wl1271_elp_work(struct work_struct *work)
mutex_lock(&wl->mutex);
if (wl->elp || !wl->psm)
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
!test_bit(WL1271_FLAG_PSM, &wl->flags))
goto out;
wl1271_debug(DEBUG_PSM, "chip to elp");
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
wl->elp = true;
set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
out:
mutex_unlock(&wl->mutex);
@ -55,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work)
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
if (wl->psm) {
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
cancel_delayed_work(&wl->elp_work);
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(ELP_ENTRY_DELAY));
@ -70,7 +71,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
u32 start_time = jiffies;
bool pending = false;
if (!wl->elp)
if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
return 0;
wl1271_debug(DEBUG_PSM, "waking up chip from elp");
@ -101,7 +102,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
}
}
wl->elp = false;
clear_bit(WL1271_FLAG_IN_ELP, &wl->flags);
wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
jiffies_to_msecs(jiffies - start_time));
@ -143,7 +144,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
if (ret < 0)
return ret;
wl->psm = 1;
set_bit(WL1271_FLAG_PSM, &wl->flags);
break;
case STATION_ACTIVE_MODE:
default:
@ -166,7 +167,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
if (ret < 0)
return ret;
wl->psm = 0;
clear_bit(WL1271_FLAG_PSM, &wl->flags);
break;
}

View file

@ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
pad = pad - skb->len;
tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
/* if the packets are destined for AP (have a STA entry) send them
with AP rate policies, otherwise use default basic rates */
if (control->control.sta)
tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
desc->tx_attr = cpu_to_le16(tx_attr);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
@ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
return ret;
}
static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
{
struct ieee80211_supported_band *band;
u32 enabled_rates = 0;
int bit;
band = wl->hw->wiphy->bands[wl->band];
for (bit = 0; bit < band->n_bitrates; bit++) {
if (rate_set & 0x1)
enabled_rates |= band->bitrates[bit].hw_value;
rate_set >>= 1;
}
return enabled_rates;
}
void wl1271_tx_work(struct work_struct *work)
{
struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
struct sk_buff *skb;
bool woken_up = false;
u32 sta_rates = 0;
int ret;
/* check if the rates supported by the AP have changed */
if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
&wl->flags))) {
unsigned long flags;
spin_lock_irqsave(&wl->wl_lock, flags);
sta_rates = wl->sta_rate_set;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
/* if rates have changed, re-configure the rate policy */
if (unlikely(sta_rates)) {
wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
wl1271_acx_rate_policies(wl);
}
while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) {
ret = wl1271_ps_elp_wakeup(wl, false);
@ -240,18 +277,18 @@ void wl1271_tx_work(struct work_struct *work)
wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
"stop queues");
ieee80211_stop_queues(wl->hw);
wl->tx_queue_stopped = true;
set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
skb_queue_head(&wl->tx_queue, skb);
goto out;
} else if (ret < 0) {
dev_kfree_skb(skb);
goto out;
} else if (wl->tx_queue_stopped) {
} else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED,
&wl->flags)) {
/* firmware buffer has space, restart queues */
wl1271_debug(DEBUG_TX,
"complete_packet: waking queues");
ieee80211_wake_queues(wl->hw);
wl->tx_queue_stopped = false;
}
}

View file

@ -1325,151 +1325,11 @@ int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
return r;
}
static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
{
static const u16 constants[] = {
715, 655, 585, 540, 470, 410, 360, 315,
270, 235, 205, 175, 150, 125, 105, 85,
65, 50, 40, 25, 15
};
int i;
u32 x;
/* It seems that their quality parameter is somehow per signal
* and is now transferred per bit.
*/
switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_12M:
case ZD_OFDM_RATE_24M:
size *= 2;
break;
case ZD_OFDM_RATE_9M:
case ZD_OFDM_RATE_18M:
case ZD_OFDM_RATE_36M:
case ZD_OFDM_RATE_54M:
size *= 4;
size /= 3;
break;
case ZD_OFDM_RATE_48M:
size *= 3;
size /= 2;
break;
default:
return -EINVAL;
}
x = (10000 * status_quality)/size;
for (i = 0; i < ARRAY_SIZE(constants); i++) {
if (x > constants[i])
break;
}
switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_9M:
i += 3;
break;
case ZD_OFDM_RATE_12M:
case ZD_OFDM_RATE_18M:
i += 5;
break;
case ZD_OFDM_RATE_24M:
case ZD_OFDM_RATE_36M:
i += 9;
break;
case ZD_OFDM_RATE_48M:
case ZD_OFDM_RATE_54M:
i += 15;
break;
default:
return -EINVAL;
}
return i;
}
static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size)
{
int r;
r = ofdm_qual_db(status_quality, zd_rate, size);
ZD_ASSERT(r >= 0);
if (r < 0)
r = 0;
r = (r * 100)/29;
return r <= 100 ? r : 100;
}
static unsigned int log10times100(unsigned int x)
{
static const u8 log10[] = {
0,
0, 30, 47, 60, 69, 77, 84, 90, 95, 100,
104, 107, 111, 114, 117, 120, 123, 125, 127, 130,
132, 134, 136, 138, 139, 141, 143, 144, 146, 147,
149, 150, 151, 153, 154, 155, 156, 157, 159, 160,
161, 162, 163, 164, 165, 166, 167, 168, 169, 169,
170, 171, 172, 173, 174, 174, 175, 176, 177, 177,
178, 179, 179, 180, 181, 181, 182, 183, 183, 184,
185, 185, 186, 186, 187, 188, 188, 189, 189, 190,
190, 191, 191, 192, 192, 193, 193, 194, 194, 195,
195, 196, 196, 197, 197, 198, 198, 199, 199, 200,
200, 200, 201, 201, 202, 202, 202, 203, 203, 204,
204, 204, 205, 205, 206, 206, 206, 207, 207, 207,
208, 208, 208, 209, 209, 210, 210, 210, 211, 211,
211, 212, 212, 212, 213, 213, 213, 213, 214, 214,
214, 215, 215, 215, 216, 216, 216, 217, 217, 217,
217, 218, 218, 218, 219, 219, 219, 219, 220, 220,
220, 220, 221, 221, 221, 222, 222, 222, 222, 223,
223, 223, 223, 224, 224, 224, 224,
};
return x < ARRAY_SIZE(log10) ? log10[x] : 225;
}
enum {
MAX_CCK_EVM_DB = 45,
};
static int cck_evm_db(u8 status_quality)
{
return (20 * log10times100(status_quality)) / 100;
}
static int cck_snr_db(u8 status_quality)
{
int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality);
ZD_ASSERT(r >= 0);
return r;
}
static int cck_qual_percent(u8 status_quality)
{
int r;
r = cck_snr_db(status_quality);
r = (100*r)/17;
return r <= 100 ? r : 100;
}
static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame)
{
return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
}
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
const struct rx_status *status)
{
return (status->frame_status&ZD_RX_OFDM) ?
ofdm_qual_percent(status->signal_quality_ofdm,
zd_rate_from_ofdm_plcp_header(rx_frame),
size) :
cck_qual_percent(status->signal_quality_cck);
}
/**
* zd_rx_rate - report zd-rate
* @rx_frame - received frame

View file

@ -929,9 +929,6 @@ static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval)
struct rx_status;
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
const struct rx_status *status);
u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
struct zd_mc_hash {

View file

@ -828,9 +828,6 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
stats.band = IEEE80211_BAND_2GHZ;
stats.signal = status->signal_strength;
stats.qual = zd_rx_qual_percent(buffer,
length - sizeof(struct rx_status),
status);
rate = zd_rx_rate(buffer, status);
@ -872,7 +869,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
}
static int zd_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct zd_mac *mac = zd_hw_mac(hw);
@ -880,22 +877,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
return -EOPNOTSUPP;
switch (conf->type) {
switch (vif->type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
mac->type = conf->type;
mac->type = vif->type;
break;
default:
return -EOPNOTSUPP;
}
return zd_write_mac_addr(&mac->chip, conf->mac_addr);
return zd_write_mac_addr(&mac->chip, vif->addr);
}
static void zd_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
struct zd_mac *mac = zd_hw_mac(hw);
mac->type = NL80211_IFTYPE_UNSPECIFIED;

View file

@ -1085,12 +1085,12 @@ enum ieee80211_eid {
WLAN_EID_TIM = 5,
WLAN_EID_IBSS_PARAMS = 6,
WLAN_EID_CHALLENGE = 16,
/* 802.11d */
WLAN_EID_COUNTRY = 7,
WLAN_EID_HP_PARAMS = 8,
WLAN_EID_HP_TABLE = 9,
WLAN_EID_REQUEST = 10,
/* 802.11e */
WLAN_EID_QBSS_LOAD = 11,
WLAN_EID_EDCA_PARAM_SET = 12,
WLAN_EID_TSPEC = 13,
@ -1113,7 +1113,7 @@ enum ieee80211_eid {
WLAN_EID_PREP = 69,
WLAN_EID_PERR = 70,
WLAN_EID_RANN = 49, /* compatible with FreeBSD */
/* 802.11h */
WLAN_EID_PWR_CONSTRAINT = 32,
WLAN_EID_PWR_CAPABILITY = 33,
WLAN_EID_TPC_REQUEST = 34,
@ -1124,20 +1124,41 @@ enum ieee80211_eid {
WLAN_EID_MEASURE_REPORT = 39,
WLAN_EID_QUIET = 40,
WLAN_EID_IBSS_DFS = 41,
/* 802.11g */
WLAN_EID_ERP_INFO = 42,
WLAN_EID_EXT_SUPP_RATES = 50,
/* 802.11n */
WLAN_EID_HT_CAPABILITY = 45,
WLAN_EID_HT_INFORMATION = 61,
/* 802.11i */
WLAN_EID_RSN = 48,
WLAN_EID_TIMEOUT_INTERVAL = 56,
WLAN_EID_MMIE = 76 /* 802.11w */,
WLAN_EID_MMIE = 76,
WLAN_EID_WPA = 221,
WLAN_EID_GENERIC = 221,
WLAN_EID_VENDOR_SPECIFIC = 221,
WLAN_EID_QOS_PARAMETER = 222
WLAN_EID_QOS_PARAMETER = 222,
WLAN_EID_AP_CHAN_REPORT = 51,
WLAN_EID_NEIGHBOR_REPORT = 52,
WLAN_EID_RCPI = 53,
WLAN_EID_BSS_AVG_ACCESS_DELAY = 63,
WLAN_EID_ANTENNA_INFO = 64,
WLAN_EID_RSNI = 65,
WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66,
WLAN_EID_BSS_AVAILABLE_CAPACITY = 67,
WLAN_EID_BSS_AC_ACCESS_DELAY = 68,
WLAN_EID_RRM_ENABLED_CAPABILITIES = 70,
WLAN_EID_MULTIPLE_BSSID = 71,
WLAN_EID_MOBILITY_DOMAIN = 54,
WLAN_EID_FAST_BSS_TRANSITION = 55,
WLAN_EID_TIMEOUT_INTERVAL = 56,
WLAN_EID_RIC_DATA = 57,
WLAN_EID_RIC_DESCRIPTOR = 75,
WLAN_EID_DSE_REGISTERED_LOCATION = 58,
WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59,
WLAN_EID_EXT_CHANSWITCH_ANN = 60,
};
/* Action category code */

View file

@ -270,6 +270,31 @@
* @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
* associated with this wiphy must be down and will follow.
*
* @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
* channel for the specified amount of time. This can be used to do
* off-channel operations like transmit a Public Action frame and wait for
* a response while being associated to an AP on another channel.
* %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
* radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
* frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
* optionally used to specify additional channel parameters.
* %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
* to remain on the channel. This command is also used as an event to
* notify when the requested duration starts (it may take a while for the
* driver to schedule this time due to other concurrent needs for the
* radio).
* When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
* that will be included with any events pertaining to this request;
* the cookie is also used to cancel the request.
* @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
* pending remain-on-channel duration if the desired operation has been
* completed prior to expiration of the originally requested duration.
* %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
* radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
* uniquely identify the request.
* This command is also used as an event to notify when a requested
* remain-on-channel duration has expired.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -353,6 +378,9 @@ enum nl80211_commands {
NL80211_CMD_DEL_PMKSA,
NL80211_CMD_FLUSH_PMKSA,
NL80211_CMD_REMAIN_ON_CHANNEL,
NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -606,6 +634,10 @@ enum nl80211_commands {
* @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
* cache, a wiphy attribute.
*
* @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
*
* @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@ -743,6 +775,10 @@ enum nl80211_attrs {
NL80211_ATTR_PMKID,
NL80211_ATTR_MAX_NUM_PMKIDS,
NL80211_ATTR_DURATION,
NL80211_ATTR_COOKIE,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,

View file

@ -988,6 +988,15 @@ struct cfg80211_pmksa {
*
* @dump_survey: get site survey information.
*
* @remain_on_channel: Request the driver to remain awake on the specified
* channel for the specified duration to complete an off-channel
* operation (e.g., public action frame exchange). When the driver is
* ready on the requested channel, it must indicate this with an event
* notification by calling cfg80211_ready_on_channel().
* @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
* This allows the operation to be terminated prior to timeout based on
* the duration value.
*
* @testmode_cmd: run a test mode command
*
* @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
@ -1123,6 +1132,16 @@ struct cfg80211_ops {
struct cfg80211_pmksa *pmksa);
int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev);
int (*remain_on_channel)(struct wiphy *wiphy,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration,
u64 *cookie);
int (*cancel_remain_on_channel)(struct wiphy *wiphy,
struct net_device *dev,
u64 cookie);
/* some temporary stuff to finish wext */
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout);
@ -2147,5 +2166,45 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
void cfg80211_disconnected(struct net_device *dev, u16 reason,
u8 *ie, size_t ie_len, gfp_t gfp);
/**
* cfg80211_ready_on_channel - notification of remain_on_channel start
* @dev: network device
* @cookie: the request cookie
* @chan: The current channel (from remain_on_channel request)
* @channel_type: Channel type
* @duration: Duration in milliseconds that the driver intents to remain on the
* channel
* @gfp: allocation flags
*/
void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp);
/**
* cfg80211_remain_on_channel_expired - remain_on_channel duration expired
* @dev: network device
* @cookie: the request cookie
* @chan: The current channel (from remain_on_channel request)
* @channel_type: Channel type
* @gfp: allocation flags
*/
void cfg80211_remain_on_channel_expired(struct net_device *dev,
u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
gfp_t gfp);
/**
* cfg80211_new_sta - notify userspace about station
*
* @dev: the netdev
* @mac_addr: the station's address
* @sinfo: the station information
* @gfp: allocation flags
*/
void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);
#endif /* __NET_CFG80211_H */

View file

@ -547,7 +547,6 @@ enum mac80211_rx_flags {
* unspecified depending on the hardware capabilities flags
* @IEEE80211_HW_SIGNAL_*
* @noise: noise when receiving this frame, in dBm.
* @qual: overall signal quality indication, in percent (0-100).
* @antenna: antenna used
* @rate_idx: index of data rate into band's supported rates or MCS index if
* HT rates are use (RX_FLAG_HT)
@ -559,7 +558,6 @@ struct ieee80211_rx_status {
int freq;
int signal;
int noise;
int __deprecated qual;
int antenna;
int rate_idx;
int flag;
@ -701,33 +699,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
return false;
}
/**
* struct ieee80211_if_init_conf - initial configuration of an interface
*
* @vif: pointer to a driver-use per-interface structure. The pointer
* itself is also used for various functions including
* ieee80211_beacon_get() and ieee80211_get_buffered_bc().
* @type: one of &enum nl80211_iftype constants. Determines the type of
* added/removed interface.
* @mac_addr: pointer to MAC address of the interface. This pointer is valid
* until the interface is removed (i.e. it cannot be used after
* remove_interface() callback was called for this interface).
*
* This structure is used in add_interface() and remove_interface()
* callbacks of &struct ieee80211_hw.
*
* When you allow multiple interfaces to be added to your PHY, take care
* that the hardware can actually handle multiple MAC addresses. However,
* also take care that when there's no interface left with mac_addr != %NULL
* you remove the MAC address from the device to avoid acknowledging packets
* in pure monitor mode.
*/
struct ieee80211_if_init_conf {
enum nl80211_iftype type;
struct ieee80211_vif *vif;
void *mac_addr;
};
/**
* enum ieee80211_key_alg - key algorithm
* @ALG_WEP: WEP40 or WEP104
@ -1410,7 +1381,7 @@ enum ieee80211_ampdu_mlme_action {
* When the device is started it should not have a MAC address
* to avoid acknowledging frames before a non-monitor device
* is added.
* Must be implemented.
* Must be implemented and can sleep.
*
* @stop: Called after last netdevice attached to the hardware
* is disabled. This should turn off the hardware (at least
@ -1418,7 +1389,7 @@ enum ieee80211_ampdu_mlme_action {
* May be called right after add_interface if that rejects
* an interface. If you added any work onto the mac80211 workqueue
* you should ensure to cancel it on this callback.
* Must be implemented.
* Must be implemented and can sleep.
*
* @add_interface: Called when a netdevice attached to the hardware is
* enabled. Because it is not called for monitor mode devices, @start
@ -1428,7 +1399,7 @@ enum ieee80211_ampdu_mlme_action {
* interface is given in the conf parameter.
* The callback may refuse to add an interface by returning a
* negative error code (which will be seen in userspace.)
* Must be implemented.
* Must be implemented and can sleep.
*
* @remove_interface: Notifies a driver that an interface is going down.
* The @stop callback is called after this if it is the last interface
@ -1437,19 +1408,20 @@ enum ieee80211_ampdu_mlme_action {
* must be cleared so the device no longer acknowledges packets,
* the mac_addr member of the conf structure is, however, set to the
* MAC address of the device going away.
* Hence, this callback must be implemented.
* Hence, this callback must be implemented. It can sleep.
*
* @config: Handler for configuration requests. IEEE 802.11 code calls this
* function to change hardware configuration, e.g., channel.
* This function should never fail but returns a negative error code
* if it does.
* if it does. The callback can sleep.
*
* @bss_info_changed: Handler for configuration requests related to BSS
* parameters that may vary during BSS's lifespan, and may affect low
* level driver (e.g. assoc/disassoc status, erp parameters).
* This function should not be used if no BSS has been set, unless
* for association indication. The @changed parameter indicates which
* of the bss parameters has changed when a call is made.
* of the bss parameters has changed when a call is made. The callback
* can sleep.
*
* @prepare_multicast: Prepare for multicast filter configuration.
* This callback is optional, and its return value is passed
@ -1457,20 +1429,22 @@ enum ieee80211_ampdu_mlme_action {
*
* @configure_filter: Configure the device's RX filter.
* See the section "Frame filtering" for more information.
* This callback must be implemented.
* This callback must be implemented and can sleep.
*
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
* must be set or cleared for a given STA. Must be atomic.
*
* @set_key: See the section "Hardware crypto acceleration"
* This callback can sleep, and is only called between add_interface
* and remove_interface calls, i.e. while the given virtual interface
* This callback is only called between add_interface and
* remove_interface calls, i.e. while the given virtual interface
* is enabled.
* Returns a negative error code if the key can't be added.
* The callback can sleep.
*
* @update_tkip_key: See the section "Hardware crypto acceleration"
* This callback will be called in the context of Rx. Called for drivers
* which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
* The callback can sleep.
*
* @hw_scan: Ask the hardware to service the scan request, no need to start
* the scan state machine in stack. The scan must honour the channel
@ -1484,21 +1458,28 @@ enum ieee80211_ampdu_mlme_action {
* When the scan finishes, ieee80211_scan_completed() must be called;
* note that it also must be called when the scan cannot finish due to
* any error unless this callback returned a negative error code.
* The callback can sleep.
*
* @sw_scan_start: Notifier function that is called just before a software scan
* is started. Can be NULL, if the driver doesn't need this notification.
* The callback can sleep.
*
* @sw_scan_complete: Notifier function that is called just after a software scan
* finished. Can be NULL, if the driver doesn't need this notification.
* @sw_scan_complete: Notifier function that is called just after a
* software scan finished. Can be NULL, if the driver doesn't need
* this notification.
* The callback can sleep.
*
* @get_stats: Return low-level statistics.
* Returns zero if statistics are available.
* The callback can sleep.
*
* @get_tkip_seq: If your device implements TKIP encryption in hardware this
* callback should be provided to read the TKIP transmit IVs (both IV32
* and IV16) for the given key from hardware.
* The callback must be atomic.
*
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
* The callback can sleep.
*
* @sta_notify: Notifies low level driver about addition, removal or power
* state transition of an associated station, AP, IBSS/WDS/mesh peer etc.
@ -1507,30 +1488,36 @@ enum ieee80211_ampdu_mlme_action {
* @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
* bursting) for a hardware TX queue.
* Returns a negative error code on failure.
* The callback can sleep.
*
* @get_tx_stats: Get statistics of the current TX queue status. This is used
* to get number of currently queued packets (queue length), maximum queue
* size (limit), and total number of packets sent using each TX queue
* (count). The 'stats' pointer points to an array that has hw->queues
* items.
* The callback must be atomic.
*
* @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
* this is only used for IBSS mode BSSID merging and debugging. Is not a
* required function.
* The callback can sleep.
*
* @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
* Currently, this is only used for IBSS mode debugging. Is not a
* required function.
* The callback can sleep.
*
* @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
* with other STAs in the IBSS. This is only used in IBSS mode. This
* function is optional if the firmware/hardware takes full care of
* TSF synchronization.
* The callback can sleep.
*
* @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
* This is needed only for IBSS mode and the result of this function is
* used to determine whether to reply to Probe Requests.
* Returns non-zero if this device sent the last beacon.
* The callback can sleep.
*
* @ampdu_action: Perform a certain A-MPDU action
* The RA/TID combination determines the destination and TID we want
@ -1539,21 +1526,28 @@ enum ieee80211_ampdu_mlme_action {
* is the first frame we expect to perform the action on. Notice
* that TX/RX_STOP can pass NULL for this parameter.
* Returns a negative error code on failure.
* The callback must be atomic.
*
* @rfkill_poll: Poll rfkill hardware state. If you need this, you also
* need to set wiphy->rfkill_poll to %true before registration,
* and need to call wiphy_rfkill_set_hw_state() in the callback.
* The callback can sleep.
*
* @testmode_cmd: Implement a cfg80211 test mode command.
* The callback can sleep.
*
* @flush: Flush all pending frames from the hardware queue, making sure
* that the hardware queues are empty. If the parameter @drop is set
* to %true, pending frames may be dropped. The callback can sleep.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw);
int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
void (*remove_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
struct ieee80211_vif *vif);
int (*config)(struct ieee80211_hw *hw, u32 changed);
void (*bss_info_changed)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@ -1601,6 +1595,7 @@ struct ieee80211_ops {
#ifdef CONFIG_NL80211_TESTMODE
int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
#endif
void (*flush)(struct ieee80211_hw *hw, bool drop);
};
/**
@ -1840,7 +1835,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
/**
* ieee80211_beacon_get_tim - beacon generation function
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @tim_offset: pointer to variable that will receive the TIM IE offset.
* Set to 0 if invalid (in non-AP modes).
* @tim_length: pointer to variable that will receive the TIM IE length,
@ -1868,7 +1863,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
/**
* ieee80211_beacon_get - beacon generation function
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* See ieee80211_beacon_get_tim().
*/
@ -1881,7 +1876,7 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
/**
* ieee80211_rts_get - RTS frame generation function
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @frame: pointer to the frame that is going to be protected by the RTS.
* @frame_len: the frame length (in octets).
* @frame_txctl: &struct ieee80211_tx_info of the frame.
@ -1900,7 +1895,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/**
* ieee80211_rts_duration - Get the duration field for an RTS frame
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @frame_len: the length of the frame that is going to be protected by the RTS.
* @frame_txctl: &struct ieee80211_tx_info of the frame.
*
@ -1915,7 +1910,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
/**
* ieee80211_ctstoself_get - CTS-to-self frame generation function
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @frame: pointer to the frame that is going to be protected by the CTS-to-self.
* @frame_len: the frame length (in octets).
* @frame_txctl: &struct ieee80211_tx_info of the frame.
@ -1935,7 +1930,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
/**
* ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
* @frame_txctl: &struct ieee80211_tx_info of the frame.
*
@ -1951,7 +1946,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
/**
* ieee80211_generic_frame_duration - Calculate the duration field for a frame
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @frame_len: the length of the frame.
* @rate: the rate at which the frame is going to be transmitted.
*
@ -1966,7 +1961,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
/**
* ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
* @hw: pointer as obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* Function for accessing buffered broadcast and multicast frames. If
* hardware/firmware does not implement buffering of broadcast/multicast
@ -2134,7 +2129,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
/**
* ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
* @vif: &struct ieee80211_vif pointer from the add_interface callback
* @ra: receiver address of the BA session recipient.
* @tid: the TID to BA on.
*
@ -2145,7 +2140,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
/**
* ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
* @vif: &struct ieee80211_vif pointer from the add_interface callback
* @ra: receiver address of the BA session recipient.
* @tid: the TID to BA on.
*
@ -2173,7 +2168,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
/**
* ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
* @vif: &struct ieee80211_vif pointer from the add_interface callback
* @ra: receiver address of the BA session recipient.
* @tid: the desired TID to BA on.
*
@ -2184,7 +2179,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
/**
* ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
* @vif: &struct ieee80211_vif pointer from the add_interface callback
* @ra: receiver address of the BA session recipient.
* @tid: the desired TID to BA on.
*
@ -2263,7 +2258,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
/**
* ieee80211_beacon_loss - inform hardware does not receive beacons
*
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
* IEEE80211_CONF_PS is set, the driver needs to inform whenever the

View file

@ -6,10 +6,10 @@ mac80211-y := \
sta_info.o \
wep.o \
wpa.o \
scan.o \
scan.o offchannel.o \
ht.o agg-tx.o agg-rx.o \
ibss.o \
mlme.o \
mlme.o work.o \
iface.o \
rate.o \
michael.o \

View file

@ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int ret;
if (netif_running(dev))
if (ieee80211_sdata_running(sdata))
return -EBUSY;
if (!nl80211_params_check(type, params))
return -EINVAL;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ret = ieee80211_if_change_type(sdata, type);
if (ret)
return ret;
@ -1345,7 +1343,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
return 0;
}
ap = sdata->u.mgd.associated->cbss.bssid;
ap = sdata->u.mgd.associated->bssid;
if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
if (sdata->u.mgd.powersave)
@ -1443,6 +1441,28 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
return -EINVAL;
}
static int ieee80211_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration,
u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
duration, cookie);
}
static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev,
u64 cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
}
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@ -1489,4 +1509,6 @@ struct cfg80211_ops mac80211_config_ops = {
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
.set_power_mgmt = ieee80211_set_power_mgmt,
.set_bitrate_mask = ieee80211_set_bitrate_mask,
.remain_on_channel = ieee80211_remain_on_channel,
.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
};

View file

@ -133,7 +133,6 @@ IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
/* STA attributes */
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)
@ -270,7 +269,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(bssid, sta);
DEBUGFS_ADD(aid, sta);
DEBUGFS_ADD(capab, sta);
DEBUGFS_ADD_MODE(smps, 0600);
}

View file

@ -14,6 +14,8 @@ static inline int drv_start(struct ieee80211_local *local)
{
int ret;
might_sleep();
local->started = true;
smp_mb();
ret = local->ops->start(&local->hw);
@ -23,6 +25,8 @@ static inline int drv_start(struct ieee80211_local *local)
static inline void drv_stop(struct ieee80211_local *local)
{
might_sleep();
local->ops->stop(&local->hw);
trace_drv_stop(local);
@ -36,23 +40,33 @@ static inline void drv_stop(struct ieee80211_local *local)
}
static inline int drv_add_interface(struct ieee80211_local *local,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
int ret = local->ops->add_interface(&local->hw, conf);
trace_drv_add_interface(local, vif_to_sdata(conf->vif), ret);
int ret;
might_sleep();
ret = local->ops->add_interface(&local->hw, vif);
trace_drv_add_interface(local, vif_to_sdata(vif), ret);
return ret;
}
static inline void drv_remove_interface(struct ieee80211_local *local,
struct ieee80211_if_init_conf *conf)
struct ieee80211_vif *vif)
{
local->ops->remove_interface(&local->hw, conf);
trace_drv_remove_interface(local, vif_to_sdata(conf->vif));
might_sleep();
local->ops->remove_interface(&local->hw, vif);
trace_drv_remove_interface(local, vif_to_sdata(vif));
}
static inline int drv_config(struct ieee80211_local *local, u32 changed)
{
int ret = local->ops->config(&local->hw, changed);
int ret;
might_sleep();
ret = local->ops->config(&local->hw, changed);
trace_drv_config(local, changed, ret);
return ret;
}
@ -62,6 +76,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
struct ieee80211_bss_conf *info,
u32 changed)
{
might_sleep();
if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
trace_drv_bss_info_changed(local, sdata, info, changed);
@ -111,7 +127,11 @@ static inline int drv_set_key(struct ieee80211_local *local,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
int ret;
might_sleep();
ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
trace_drv_set_key(local, cmd, sdata, sta, key, ret);
return ret;
}
@ -121,6 +141,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
const u8 *address, u32 iv32,
u16 *phase1key)
{
might_sleep();
if (local->ops->update_tkip_key)
local->ops->update_tkip_key(&local->hw, conf, address,
iv32, phase1key);
@ -130,13 +152,19 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
static inline int drv_hw_scan(struct ieee80211_local *local,
struct cfg80211_scan_request *req)
{
int ret = local->ops->hw_scan(&local->hw, req);
int ret;
might_sleep();
ret = local->ops->hw_scan(&local->hw, req);
trace_drv_hw_scan(local, req, ret);
return ret;
}
static inline void drv_sw_scan_start(struct ieee80211_local *local)
{
might_sleep();
if (local->ops->sw_scan_start)
local->ops->sw_scan_start(&local->hw);
trace_drv_sw_scan_start(local);
@ -144,6 +172,8 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local)
static inline void drv_sw_scan_complete(struct ieee80211_local *local)
{
might_sleep();
if (local->ops->sw_scan_complete)
local->ops->sw_scan_complete(&local->hw);
trace_drv_sw_scan_complete(local);
@ -154,6 +184,8 @@ static inline int drv_get_stats(struct ieee80211_local *local,
{
int ret = -EOPNOTSUPP;
might_sleep();
if (local->ops->get_stats)
ret = local->ops->get_stats(&local->hw, stats);
trace_drv_get_stats(local, stats, ret);
@ -173,6 +205,9 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
u32 value)
{
int ret = 0;
might_sleep();
if (local->ops->set_rts_threshold)
ret = local->ops->set_rts_threshold(&local->hw, value);
trace_drv_set_rts_threshold(local, value, ret);
@ -193,6 +228,9 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
int ret = -EOPNOTSUPP;
might_sleep();
if (local->ops->conf_tx)
ret = local->ops->conf_tx(&local->hw, queue, params);
trace_drv_conf_tx(local, queue, params, ret);
@ -210,6 +248,9 @@ static inline int drv_get_tx_stats(struct ieee80211_local *local,
static inline u64 drv_get_tsf(struct ieee80211_local *local)
{
u64 ret = -1ULL;
might_sleep();
if (local->ops->get_tsf)
ret = local->ops->get_tsf(&local->hw);
trace_drv_get_tsf(local, ret);
@ -218,6 +259,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local)
static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
{
might_sleep();
if (local->ops->set_tsf)
local->ops->set_tsf(&local->hw, tsf);
trace_drv_set_tsf(local, tsf);
@ -225,6 +268,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
static inline void drv_reset_tsf(struct ieee80211_local *local)
{
might_sleep();
if (local->ops->reset_tsf)
local->ops->reset_tsf(&local->hw);
trace_drv_reset_tsf(local);
@ -233,6 +278,9 @@ static inline void drv_reset_tsf(struct ieee80211_local *local)
static inline int drv_tx_last_beacon(struct ieee80211_local *local)
{
int ret = 1;
might_sleep();
if (local->ops->tx_last_beacon)
ret = local->ops->tx_last_beacon(&local->hw);
trace_drv_tx_last_beacon(local, ret);
@ -256,7 +304,18 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
static inline void drv_rfkill_poll(struct ieee80211_local *local)
{
might_sleep();
if (local->ops->rfkill_poll)
local->ops->rfkill_poll(&local->hw);
}
static inline void drv_flush(struct ieee80211_local *local, bool drop)
{
might_sleep();
trace_drv_flush(local, drop);
if (local->ops->flush)
local->ops->flush(&local->hw, drop);
}
#endif /* __MAC80211_DRIVER_OPS */

View file

@ -690,6 +690,27 @@ TRACE_EVENT(drv_ampdu_action,
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
)
);
TRACE_EVENT(drv_flush,
TP_PROTO(struct ieee80211_local *local, bool drop),
TP_ARGS(local, drop),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(bool, drop)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->drop = drop;
),
TP_printk(
LOCAL_PR_FMT " drop:%d",
LOCAL_PR_ARG, __entry->drop
)
);
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH

View file

@ -187,15 +187,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss)
{
struct cfg80211_bss *cbss =
container_of((void *)bss, struct cfg80211_bss, priv);
struct ieee80211_supported_band *sband;
u32 basic_rates;
int i, j;
u16 beacon_int = bss->cbss.beacon_interval;
u16 beacon_int = cbss->beacon_interval;
if (beacon_int < 10)
beacon_int = 10;
sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band];
sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
basic_rates = 0;
@ -212,12 +214,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
}
__ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
__ieee80211_sta_join_ibss(sdata, cbss->bssid,
beacon_int,
bss->cbss.channel,
cbss->channel,
basic_rates,
bss->cbss.capability,
bss->cbss.tsf);
cbss->capability,
cbss->tsf);
}
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@ -229,6 +231,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
int freq;
struct cfg80211_bss *cbss;
struct ieee80211_bss *bss;
struct sta_info *sta;
struct ieee80211_channel *channel;
@ -283,8 +286,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (!bss)
return;
cbss = container_of((void *)bss, struct cfg80211_bss, priv);
/* was just updated in ieee80211_bss_info_update */
beacon_timestamp = bss->cbss.tsf;
beacon_timestamp = cbss->tsf;
/* check if we need to merge IBSS */
@ -297,11 +302,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
goto put_bss;
/* not an IBSS */
if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
goto put_bss;
/* different channel */
if (bss->cbss.channel != local->oper_channel)
if (cbss->channel != local->oper_channel)
goto put_bss;
/* different SSID */
@ -311,7 +316,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
goto put_bss;
/* same BSSID */
if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
goto put_bss;
if (rx_status->flag & RX_FLAG_TSFT) {
@ -382,6 +387,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
u8 *bssid,u8 *addr, u32 supp_rates)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
int band = local->hw.conf.channel->band;
@ -397,6 +403,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
return NULL;
}
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH)
return NULL;
if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
return NULL;
@ -514,7 +523,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct ieee80211_bss *bss;
struct cfg80211_bss *cbss;
struct ieee80211_channel *chan = NULL;
const u8 *bssid = NULL;
int active_ibss;
@ -538,21 +547,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
chan = ifibss->channel;
if (!is_zero_ether_addr(ifibss->bssid))
bssid = ifibss->bssid;
bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid,
ifibss->ssid, ifibss->ssid_len,
WLAN_CAPABILITY_IBSS |
WLAN_CAPABILITY_PRIVACY,
capability);
cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
ifibss->ssid, ifibss->ssid_len,
WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY,
capability);
if (bss) {
if (cbss) {
struct ieee80211_bss *bss;
bss = (void *)cbss->priv;
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG " sta_find_ibss: selected %pM current "
"%pM\n", bss->cbss.bssid, ifibss->bssid);
"%pM\n", cbss->bssid, ifibss->bssid);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
" based on configured SSID\n",
sdata->name, bss->cbss.bssid);
sdata->name, cbss->bssid);
ieee80211_sta_join_ibss(sdata, bss);
ieee80211_rx_bss_put(local, bss);
@ -744,7 +755,7 @@ static void ieee80211_ibss_work(struct work_struct *work)
if (WARN_ON(local->suspended))
return;
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
return;
if (local->scanning)
@ -827,7 +838,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
continue;

View file

@ -71,9 +71,6 @@ struct ieee80211_fragment_entry {
struct ieee80211_bss {
/* Yes, this is a hack */
struct cfg80211_bss cbss;
/* don't want to look up all the time */
size_t ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
@ -227,31 +224,78 @@ struct mesh_preq_queue {
u8 flags;
};
enum ieee80211_mgd_state {
IEEE80211_MGD_STATE_IDLE,
IEEE80211_MGD_STATE_PROBE,
IEEE80211_MGD_STATE_AUTH,
IEEE80211_MGD_STATE_ASSOC,
enum ieee80211_work_type {
IEEE80211_WORK_ABORT,
IEEE80211_WORK_DIRECT_PROBE,
IEEE80211_WORK_AUTH,
IEEE80211_WORK_ASSOC,
IEEE80211_WORK_REMAIN_ON_CHANNEL,
};
struct ieee80211_mgd_work {
/**
* enum work_done_result - indicates what to do after work was done
*
* @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
* @WORK_DONE_REQUEUE: This work item was reset to be reused, and
* should be requeued.
*/
enum work_done_result {
WORK_DONE_DESTROY,
WORK_DONE_REQUEUE,
};
struct ieee80211_work {
struct list_head list;
struct ieee80211_bss *bss;
int ie_len;
u8 prev_bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
struct rcu_head rcu_head;
struct ieee80211_sub_if_data *sdata;
enum work_done_result (*done)(struct ieee80211_work *wk,
struct sk_buff *skb);
struct ieee80211_channel *chan;
enum nl80211_channel_type chan_type;
unsigned long timeout;
enum ieee80211_mgd_state state;
u16 auth_alg, auth_transaction;
enum ieee80211_work_type type;
int tries;
u8 filter_ta[ETH_ALEN];
u8 key[WLAN_KEY_LEN_WEP104];
u8 key_len, key_idx;
bool started;
union {
struct {
int tries;
u16 algorithm, transaction;
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
u8 key[WLAN_KEY_LEN_WEP104];
u8 key_len, key_idx;
bool privacy;
} probe_auth;
struct {
struct cfg80211_bss *bss;
const u8 *supp_rates;
const u8 *ht_information_ie;
enum ieee80211_smps_mode smps;
int tries;
u16 capability;
u8 prev_bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
u8 supp_rates_len;
bool wmm_used, use_11n;
} assoc;
struct {
u32 duration;
bool started;
} remain;
};
int ie_len;
/* must be last */
u8 ie[0]; /* for auth or assoc frame, not probe */
u8 ie[0];
};
/* flags used in struct ieee80211_if_managed.flags */
@ -259,17 +303,11 @@ enum ieee80211_sta_flags {
IEEE80211_STA_BEACON_POLL = BIT(0),
IEEE80211_STA_CONNECTION_POLL = BIT(1),
IEEE80211_STA_CONTROL_PORT = BIT(2),
IEEE80211_STA_WMM_ENABLED = BIT(3),
IEEE80211_STA_DISABLE_11N = BIT(4),
IEEE80211_STA_CSA_RECEIVED = BIT(5),
IEEE80211_STA_MFP_ENABLED = BIT(6),
};
/* flags for MLME request */
enum ieee80211_sta_request {
IEEE80211_STA_REQ_SCAN,
};
struct ieee80211_if_managed {
struct timer_list timer;
struct timer_list conn_mon_timer;
@ -284,14 +322,11 @@ struct ieee80211_if_managed {
int probe_send_count;
struct mutex mtx;
struct ieee80211_bss *associated;
struct ieee80211_mgd_work *old_associate_work;
struct list_head work_list;
struct cfg80211_bss *associated;
u8 bssid[ETH_ALEN];
u16 aid;
u16 capab;
struct sk_buff_head skb_queue;
@ -300,8 +335,6 @@ struct ieee80211_if_managed {
enum ieee80211_smps_mode req_smps, /* requested smps mode */
ap_smps; /* smps mode AP thinks we're in */
unsigned long request;
unsigned int flags;
u32 beacon_crc;
@ -567,6 +600,15 @@ struct ieee80211_local {
const struct ieee80211_ops *ops;
/*
* work stuff, potentially off-channel (in the future)
*/
struct mutex work_mtx;
struct list_head work_list;
struct timer_list work_timer;
struct work_struct work_work;
struct sk_buff_head work_skb_queue;
/*
* private workqueue to mac80211. mac80211 makes this accessible
* via ieee80211_queue_work()
@ -695,6 +737,10 @@ struct ieee80211_local {
enum nl80211_channel_type oper_channel_type;
struct ieee80211_channel *oper_channel, *csa_channel;
/* Temporary remain-on-channel for off-channel operations */
struct ieee80211_channel *tmp_channel;
enum nl80211_channel_type tmp_channel_type;
/* SNMP counters */
/* dot11CountersTable */
u32 dot11TransmittedFragmentCount;
@ -752,7 +798,7 @@ struct ieee80211_local {
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
bool pspolling;
bool scan_ps_enabled;
bool offchannel_ps_enabled;
/*
* PS can only be enabled when we have exactly one managed
* interface (and monitors) in PS, this then points there.
@ -947,6 +993,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss);
/* off-channel helpers */
void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local);
void ieee80211_offchannel_stop_station(struct ieee80211_local *local);
void ieee80211_offchannel_return(struct ieee80211_local *local,
bool enable_beaconing);
/* interface handling */
int ieee80211_iface_init(void);
void ieee80211_iface_exit(void);
@ -960,6 +1012,11 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local);
u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
void ieee80211_recalc_idle(struct ieee80211_local *local);
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
{
return netif_running(sdata->dev);
}
/* tx handling */
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
void ieee80211_tx_pending(unsigned long data);
@ -1106,6 +1163,24 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
void ieee80211_recalc_smps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *forsdata);
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, size_t offset);
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
/* internal work items */
void ieee80211_work_init(struct ieee80211_local *local);
void ieee80211_add_work(struct ieee80211_work *wk);
void free_work(struct ieee80211_work *wk);
void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, u64 *cookie);
int ieee80211_wk_cancel_remain_on_channel(
struct ieee80211_sub_if_data *sdata, u64 cookie);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
#else

View file

@ -65,7 +65,7 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int ret;
if (netif_running(dev))
if (ieee80211_sdata_running(sdata))
return -EBUSY;
ret = eth_mac_addr(dev, addr);
@ -96,7 +96,6 @@ static int ieee80211_open(struct net_device *dev)
struct ieee80211_sub_if_data *nsdata;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct ieee80211_if_init_conf conf;
u32 changed = 0;
int res;
u32 hw_reconf_flags = 0;
@ -111,7 +110,7 @@ static int ieee80211_open(struct net_device *dev)
list_for_each_entry(nsdata, &local->interfaces, list) {
struct net_device *ndev = nsdata->dev;
if (ndev != dev && netif_running(ndev)) {
if (ndev != dev && ieee80211_sdata_running(nsdata)) {
/*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
@ -197,7 +196,7 @@ static int ieee80211_open(struct net_device *dev)
struct net_device *ndev = nsdata->dev;
/*
* No need to check netif_running since we do not allow
* No need to check running since we do not allow
* it to start up with this invalid address.
*/
if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
@ -248,10 +247,7 @@ static int ieee80211_open(struct net_device *dev)
ieee80211_configure_filter(local);
break;
default:
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
conf.mac_addr = sdata->vif.addr;
res = drv_add_interface(local, &conf);
res = drv_add_interface(local, &sdata->vif);
if (res)
goto err_stop;
@ -334,7 +330,7 @@ static int ieee80211_open(struct net_device *dev)
return 0;
err_del_interface:
drv_remove_interface(local, &conf);
drv_remove_interface(local, &sdata->vif);
err_stop:
if (!local->open_count)
drv_stop(local);
@ -349,7 +345,6 @@ static int ieee80211_stop(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_init_conf conf;
struct sta_info *sta;
unsigned long flags;
struct sk_buff *skb, *tmp;
@ -361,6 +356,11 @@ static int ieee80211_stop(struct net_device *dev)
*/
netif_stop_queue(dev);
/*
* Purge work for this interface.
*/
ieee80211_work_purge(sdata);
/*
* Now delete all active aggregation sessions.
*/
@ -528,12 +528,9 @@ static int ieee80211_stop(struct net_device *dev)
BSS_CHANGED_BEACON_ENABLED);
}
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
conf.mac_addr = sdata->vif.addr;
/* disable all keys for as long as this netdev is down */
ieee80211_disable_keys(sdata);
drv_remove_interface(local, &conf);
drv_remove_interface(local, &sdata->vif);
}
sdata->bss = NULL;
@ -756,7 +753,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
* and goes into the requested mode.
*/
if (netif_running(sdata->dev))
if (ieee80211_sdata_running(sdata))
return -EBUSY;
/* Purge and reset type-dependent state. */
@ -917,6 +914,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
wiphy_name(local->hw.wiphy));
#endif
drv_flush(local, false);
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
return IEEE80211_CONF_CHANGE_IDLE;
}
@ -926,16 +925,18 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
struct ieee80211_sub_if_data *sdata;
int count = 0;
if (!list_empty(&local->work_list))
return ieee80211_idle_off(local, "working");
if (local->scanning)
return ieee80211_idle_off(local, "scanning");
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
/* do not count disabled managed interfaces */
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
!sdata->u.mgd.associated &&
list_empty(&sdata->u.mgd.work_list))
!sdata->u.mgd.associated)
continue;
/* do not count unused IBSS interfaces */
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&

View file

@ -443,7 +443,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
add_todo(old_key, KEY_FLAG_TODO_DELETE);
add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
if (netif_running(sdata->dev))
if (ieee80211_sdata_running(sdata))
add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
spin_unlock_irqrestore(&sdata->local->key_lock, flags);
@ -509,7 +509,7 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
{
ASSERT_RTNL();
if (WARN_ON(!netif_running(sdata->dev)))
if (WARN_ON(!ieee80211_sdata_running(sdata)))
return;
ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);

View file

@ -107,6 +107,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
if (scan_chan) {
chan = scan_chan;
channel_type = NL80211_CHAN_NO_HT;
} else if (local->tmp_channel) {
chan = scan_chan = local->tmp_channel;
channel_type = local->tmp_channel_type;
} else {
chan = local->oper_channel;
channel_type = local->oper_channel_type;
@ -212,7 +215,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
if (local->quiescing || !netif_running(sdata->dev) ||
if (local->quiescing || !ieee80211_sdata_running(sdata) ||
test_bit(SCAN_SW_SCANNING, &local->scanning)) {
sdata->vif.bss_conf.enable_beacon = false;
} else {
@ -359,9 +362,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
WIPHY_FLAG_4ADDR_STATION;
wiphy->privid = mac80211_wiphy_privid;
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
sizeof(struct cfg80211_bss);
wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
local = wiphy_priv(wiphy);
@ -395,6 +396,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
ieee80211_work_init(local);
INIT_WORK(&local->restart_work, ieee80211_restart_work);
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);

View file

@ -645,7 +645,7 @@ static void ieee80211_mesh_work(struct work_struct *work)
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct sk_buff *skb;
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
return;
if (local->scanning)

File diff suppressed because it is too large Load diff

168
net/mac80211/offchannel.c Normal file
View file

@ -0,0 +1,168 @@
/*
* Off-channel operation helpers
*
* Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
* Copyright 2004, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <net/mac80211.h>
#include "ieee80211_i.h"
/*
* inform AP that we will go to sleep so that it will buffer the frames
* while we scan
*/
static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
local->offchannel_ps_enabled = false;
/* FIXME: what to do when local->pspolling is true? */
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->offchannel_ps_enabled = true;
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
if (!(local->offchannel_ps_enabled) ||
!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
/*
* If power save was enabled, no need to send a nullfunc
* frame because AP knows that we are sleeping. But if the
* hardware is creating the nullfunc frame for power save
* status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
* enabled) and power save was enabled, the firmware just
* sent a null frame with power save disabled. So we need
* to send a new nullfunc frame to inform the AP that we
* are again sleeping.
*/
ieee80211_send_nullfunc(local, sdata, 1);
}
/* inform AP that we are awake again, unless power save is enabled */
static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
if (!local->ps_sdata)
ieee80211_send_nullfunc(local, sdata, 0);
else if (local->offchannel_ps_enabled) {
/*
* In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
* will send a nullfunc frame with the powersave bit set
* even though the AP already knows that we are sleeping.
* This could be avoided by sending a null frame with power
* save bit disabled before enabling the power save, but
* this doesn't gain anything.
*
* When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
* to send a nullfunc frame because AP already knows that
* we are sleeping, let's just enable power save mode in
* hardware.
*/
local->hw.conf.flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
} else if (local->hw.conf.dynamic_ps_timeout > 0) {
/*
* If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
* had been running before leaving the operating channel,
* restart the timer now and send a nullfunc frame to inform
* the AP that we are awake.
*/
ieee80211_send_nullfunc(local, sdata, 0);
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
}
}
void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
/* disable beaconing */
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
ieee80211_bss_info_change_notify(
sdata, BSS_CHANGED_BEACON_ENABLED);
/*
* only handle non-STA interfaces here, STA interfaces
* are handled in ieee80211_offchannel_stop_station(),
* e.g., from the background scan state machine.
*
* In addition, do not stop monitor interface to allow it to be
* used from user space controlled off-channel operations.
*/
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_MONITOR)
netif_stop_queue(sdata->dev);
}
mutex_unlock(&local->iflist_mtx);
}
void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
/*
* notify the AP about us leaving the channel and stop all STA interfaces
*/
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
netif_stop_queue(sdata->dev);
if (sdata->u.mgd.associated)
ieee80211_offchannel_ps_enable(sdata);
}
}
mutex_unlock(&local->iflist_mtx);
}
void ieee80211_offchannel_return(struct ieee80211_local *local,
bool enable_beaconing)
{
struct ieee80211_sub_if_data *sdata;
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
/* Tell AP we're back */
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.associated)
ieee80211_offchannel_ps_disable(sdata);
netif_wake_queue(sdata->dev);
}
/* re-enable beaconing */
if (enable_beaconing &&
(sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT))
ieee80211_bss_info_change_notify(
sdata, BSS_CHANGED_BEACON_ENABLED);
}
mutex_unlock(&local->iflist_mtx);
}

View file

@ -10,7 +10,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_init_conf conf;
struct sta_info *sta;
unsigned long flags;
@ -93,17 +92,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
break;
}
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
/* disable beaconing */
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
conf.mac_addr = sdata->vif.addr;
drv_remove_interface(local, &conf);
drv_remove_interface(local, &sdata->vif);
}
/* stop hardware - this must stop RX */

View file

@ -289,7 +289,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
continue;
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
if (prev_dev) {
@ -1945,6 +1945,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
ieee80211_rx_result rxs;
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
@ -1952,6 +1953,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
return RX_DROP_MONITOR;
rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
if (rxs != RX_CONTINUE)
return rxs;
if (ieee80211_vif_is_mesh(&sdata->vif))
return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
@ -2056,7 +2061,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
skb->protocol = htons(ETH_P_802_2);
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
@ -2318,7 +2323,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if (!found_sta) {
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||

View file

@ -29,16 +29,19 @@ struct ieee80211_bss *
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
return (void *)cfg80211_get_bss(local->hw.wiphy,
ieee80211_get_channel(local->hw.wiphy,
freq),
bssid, ssid, ssid_len,
0, 0);
struct cfg80211_bss *cbss;
cbss = cfg80211_get_bss(local->hw.wiphy,
ieee80211_get_channel(local->hw.wiphy, freq),
bssid, ssid, ssid_len, 0, 0);
if (!cbss)
return NULL;
return (void *)cbss->priv;
}
static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
{
struct ieee80211_bss *bss = (void *)cbss;
struct ieee80211_bss *bss = (void *)cbss->priv;
kfree(bss_mesh_id(bss));
kfree(bss_mesh_cfg(bss));
@ -47,7 +50,9 @@ static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss)
{
cfg80211_put_bss((struct cfg80211_bss *)bss);
if (!bss)
return;
cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv));
}
struct ieee80211_bss *
@ -59,6 +64,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee80211_channel *channel,
bool beacon)
{
struct cfg80211_bss *cbss;
struct ieee80211_bss *bss;
int clen;
s32 signal = 0;
@ -68,13 +74,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
signal = (rx_status->signal * 100) / local->hw.max_signal;
bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
mgmt, len, signal, GFP_ATOMIC);
cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
mgmt, len, signal, GFP_ATOMIC);
if (!bss)
if (!cbss)
return NULL;
bss->cbss.free_priv = ieee80211_rx_bss_free;
cbss->free_priv = ieee80211_rx_bss_free;
bss = (void *)cbss->priv;
/* save the ERP value so that it is available at association time */
if (elems->erp_info && elems->erp_info_len >= 1) {
@ -220,82 +227,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
return true;
}
/*
* inform AP that we will go to sleep so that it will buffer the frames
* while we scan
*/
static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
local->scan_ps_enabled = false;
/* FIXME: what to do when local->pspolling is true? */
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->scan_ps_enabled = true;
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
if (!(local->scan_ps_enabled) ||
!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
/*
* If power save was enabled, no need to send a nullfunc
* frame because AP knows that we are sleeping. But if the
* hardware is creating the nullfunc frame for power save
* status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
* enabled) and power save was enabled, the firmware just
* sent a null frame with power save disabled. So we need
* to send a new nullfunc frame to inform the AP that we
* are again sleeping.
*/
ieee80211_send_nullfunc(local, sdata, 1);
}
/* inform AP that we are awake again, unless power save is enabled */
static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
if (!local->ps_sdata)
ieee80211_send_nullfunc(local, sdata, 0);
else if (local->scan_ps_enabled) {
/*
* In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
* will send a nullfunc frame with the powersave bit set
* even though the AP already knows that we are sleeping.
* This could be avoided by sending a null frame with power
* save bit disabled before enabling the power save, but
* this doesn't gain anything.
*
* When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
* to send a nullfunc frame because AP already knows that
* we are sleeping, let's just enable power save mode in
* hardware.
*/
local->hw.conf.flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
} else if (local->hw.conf.dynamic_ps_timeout > 0) {
/*
* If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
* had been running before leaving the operating channel,
* restart the timer now and send a nullfunc frame to inform
* the AP that we are awake.
*/
ieee80211_send_nullfunc(local, sdata, 0);
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
}
}
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
bool was_hw_scan;
mutex_lock(&local->scan_mtx);
@ -344,28 +278,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
drv_sw_scan_complete(local);
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
/* Tell AP we're back */
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.associated) {
ieee80211_scan_ps_disable(sdata);
netif_wake_queue(sdata->dev);
}
} else
netif_wake_queue(sdata->dev);
/* re-enable beaconing */
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
ieee80211_bss_info_change_notify(
sdata, BSS_CHANGED_BEACON_ENABLED);
}
mutex_unlock(&local->iflist_mtx);
ieee80211_offchannel_return(local, true);
done:
ieee80211_recalc_idle(local);
@ -377,8 +290,6 @@ EXPORT_SYMBOL(ieee80211_scan_completed);
static int ieee80211_start_sw_scan(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
/*
* Hardware/driver doesn't support hw_scan, so use software
* scanning instead. First send a nullfunc frame with power save
@ -394,33 +305,15 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
*/
drv_sw_scan_start(local);
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
/* disable beaconing */
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
ieee80211_bss_info_change_notify(
sdata, BSS_CHANGED_BEACON_ENABLED);
/*
* only handle non-STA interfaces here, STA interfaces
* are handled in the scan state machine
*/
if (sdata->vif.type != NL80211_IFTYPE_STATION)
netif_stop_queue(sdata->dev);
}
mutex_unlock(&local->iflist_mtx);
ieee80211_offchannel_stop_beaconing(local);
local->next_scan_state = SCAN_DECISION;
local->scan_channel_idx = 0;
drv_flush(local, false);
ieee80211_configure_filter(local);
/* TODO: start scan as soon as all nullfunc frames are ACKed */
ieee80211_queue_delayed_work(&local->hw,
&local->scan_work,
IEEE80211_CHANNEL_TIME);
@ -433,7 +326,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
int rc;
if (local->scan_req)
@ -463,11 +355,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
local->scan_req = req;
local->scan_sdata = sdata;
if (req != local->int_scan_req &&
sdata->vif.type == NL80211_IFTYPE_STATION &&
!list_empty(&ifmgd->work_list)) {
/* actually wait for the work it's doing to finish/time out */
set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
if (!list_empty(&local->work_list)) {
/* wait for the work to finish/time out */
return 0;
}
@ -526,7 +415,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
/* check if at least one STA interface is associated */
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
@ -564,56 +453,35 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
unsigned long *next_delay)
{
struct ieee80211_sub_if_data *sdata;
/*
* notify the AP about us leaving the channel and stop all STA interfaces
*/
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
netif_stop_queue(sdata->dev);
if (sdata->u.mgd.associated)
ieee80211_scan_ps_enable(sdata);
}
}
mutex_unlock(&local->iflist_mtx);
ieee80211_offchannel_stop_station(local);
__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
/*
* What if the nullfunc frames didn't arrive?
*/
drv_flush(local, false);
if (local->ops->flush)
*next_delay = 0;
else
*next_delay = HZ / 10;
/* advance to the next channel to be scanned */
*next_delay = HZ / 10;
local->next_scan_state = SCAN_SET_CHANNEL;
}
static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
unsigned long *next_delay)
{
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
/* switch back to the operating channel */
local->scan_channel = NULL;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
/*
* notify the AP about us being back and restart all STA interfaces
* Only re-enable station mode interface now; beaconing will be
* re-enabled once the full scan has been completed.
*/
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
/* Tell AP we're back */
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.associated)
ieee80211_scan_ps_disable(sdata);
netif_wake_queue(sdata->dev);
}
}
mutex_unlock(&local->iflist_mtx);
ieee80211_offchannel_return(local, false);
__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
@ -727,7 +595,7 @@ void ieee80211_scan_work(struct work_struct *work)
/*
* Avoid re-scheduling when the sdata is going away.
*/
if (!netif_running(sdata->dev)) {
if (!ieee80211_sdata_running(sdata)) {
ieee80211_scan_completed(&local->hw, true);
return;
}

View file

@ -359,6 +359,7 @@ int sta_info_insert(struct sta_info *sta)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct station_info sinfo;
unsigned long flags;
int err = 0;
@ -367,7 +368,7 @@ int sta_info_insert(struct sta_info *sta)
* something inserts a STA (on one CPU) without holding the RTNL
* and another CPU turns off the net device.
*/
if (unlikely(!netif_running(sdata->dev))) {
if (unlikely(!ieee80211_sdata_running(sdata))) {
err = -ENETDOWN;
goto out_free;
}
@ -408,6 +409,10 @@ int sta_info_insert(struct sta_info *sta)
spin_unlock_irqrestore(&local->sta_lock, flags);
sinfo.filled = 0;
sinfo.generation = local->sta_generation;
cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC);
#ifdef CONFIG_MAC80211_DEBUGFS
/*
* Debugfs entry adding might sleep, so schedule process

View file

@ -351,7 +351,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&

View file

@ -1418,6 +1418,10 @@ static bool need_dynamic_ps(struct ieee80211_local *local)
if (!local->ps_sdata)
return false;
/* No point if we're going to suspend */
if (local->quiescing)
return false;
return true;
}
@ -1469,7 +1473,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
list) {
if (!netif_running(tmp_sdata->dev))
if (!ieee80211_sdata_running(tmp_sdata))
continue;
if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
continue;

View file

@ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces(
case NL80211_IFTYPE_MESH_POINT:
break;
}
if (netif_running(sdata->dev))
if (ieee80211_sdata_running(sdata))
iterator(data, sdata->vif.addr,
&sdata->vif);
}
@ -502,7 +502,7 @@ void ieee80211_iterate_active_interfaces_atomic(
case NL80211_IFTYPE_MESH_POINT:
break;
}
if (netif_running(sdata->dev))
if (ieee80211_sdata_running(sdata))
iterator(data, sdata->vif.addr,
&sdata->vif);
}
@ -881,30 +881,66 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
enum ieee80211_band band)
{
struct ieee80211_supported_band *sband;
u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
int i;
u8 *pos;
size_t offset = 0, noffset;
int supp_rates_len, i;
sband = local->hw.wiphy->bands[band];
pos = buffer;
supp_rates_len = min_t(int, sband->n_bitrates, 8);
*pos++ = WLAN_EID_SUPP_RATES;
supp_rates_len = pos;
*pos++ = 0;
*pos++ = supp_rates_len;
for (i = 0; i < sband->n_bitrates; i++) {
struct ieee80211_rate *rate = &sband->bitrates[i];
for (i = 0; i < supp_rates_len; i++) {
int rate = sband->bitrates[i].bitrate;
*pos++ = (u8) (rate / 5);
}
if (esupp_rates_len) {
*esupp_rates_len += 1;
} else if (*supp_rates_len == 8) {
*pos++ = WLAN_EID_EXT_SUPP_RATES;
esupp_rates_len = pos;
*pos++ = 1;
} else
*supp_rates_len += 1;
/* insert "request information" if in custom IEs */
if (ie && ie_len) {
static const u8 before_extrates[] = {
WLAN_EID_SSID,
WLAN_EID_SUPP_RATES,
WLAN_EID_REQUEST,
};
noffset = ieee80211_ie_split(ie, ie_len,
before_extrates,
ARRAY_SIZE(before_extrates),
offset);
memcpy(pos, ie + offset, noffset - offset);
pos += noffset - offset;
offset = noffset;
}
*pos++ = rate->bitrate / 5;
if (sband->n_bitrates > i) {
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = sband->n_bitrates - i;
for (; i < sband->n_bitrates; i++) {
int rate = sband->bitrates[i].bitrate;
*pos++ = (u8) (rate / 5);
}
}
/* insert custom IEs that go before HT */
if (ie && ie_len) {
static const u8 before_ht[] = {
WLAN_EID_SSID,
WLAN_EID_SUPP_RATES,
WLAN_EID_REQUEST,
WLAN_EID_EXT_SUPP_RATES,
WLAN_EID_DS_PARAMS,
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
};
noffset = ieee80211_ie_split(ie, ie_len,
before_ht, ARRAY_SIZE(before_ht),
offset);
memcpy(pos, ie + offset, noffset - offset);
pos += noffset - offset;
offset = noffset;
}
if (sband->ht_cap.ht_supported) {
@ -936,9 +972,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
* that calculates local->scan_ies_len.
*/
if (ie) {
memcpy(pos, ie, ie_len);
pos += ie_len;
/* add any remaining custom IEs */
if (ie && ie_len) {
noffset = ie_len;
memcpy(pos, ie + offset, noffset - offset);
pos += noffset - offset;
}
return pos - buffer;
@ -1037,7 +1075,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
{
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_init_conf conf;
struct sta_info *sta;
unsigned long flags;
int res;
@ -1047,7 +1084,19 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* restart hardware */
if (local->open_count) {
/*
* Upon resume hardware can sometimes be goofy due to
* various platform / driver / bus issues, so restarting
* the device may at times not work immediately. Propagate
* the error.
*/
res = drv_start(local);
if (res) {
WARN(local->suspended, "Harware became unavailable "
"upon resume. This is could be a software issue"
"prior to suspend or a harware issue\n");
return res;
}
ieee80211_led_radio(local, true);
}
@ -1056,12 +1105,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
netif_running(sdata->dev)) {
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
conf.mac_addr = sdata->vif.addr;
res = drv_add_interface(local, &conf);
}
ieee80211_sdata_running(sdata))
res = drv_add_interface(local, &sdata->vif);
}
/* add STAs back */
@ -1103,7 +1148,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
u32 changed = ~0;
if (!netif_running(sdata->dev))
if (!ieee80211_sdata_running(sdata))
continue;
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@ -1131,7 +1176,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* add back keys */
list_for_each_entry(sdata, &local->interfaces, list)
if (netif_running(sdata->dev))
if (ieee80211_sdata_running(sdata))
ieee80211_enable_keys(sdata);
ieee80211_wake_queues_by_reason(hw,
@ -1252,3 +1297,59 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
/* changed flag is auto-detected for this */
ieee80211_hw_config(local, 0);
}
static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
{
int i;
for (i = 0; i < n_ids; i++)
if (ids[i] == id)
return true;
return false;
}
/**
* ieee80211_ie_split - split an IE buffer according to ordering
*
* @ies: the IE buffer
* @ielen: the length of the IE buffer
* @ids: an array with element IDs that are allowed before
* the split
* @n_ids: the size of the element ID array
* @offset: offset where to start splitting in the buffer
*
* This function splits an IE buffer by updating the @offset
* variable to point to the location where the buffer should be
* split.
*
* It assumes that the given IE buffer is well-formed, this
* has to be guaranteed by the caller!
*
* It also assumes that the IEs in the buffer are ordered
* correctly, if not the result of using this function will not
* be ordered correctly either, i.e. it does no reordering.
*
* The function returns the offset where the next part of the
* buffer starts, which may be @ielen if the entire (remainder)
* of the buffer should be used.
*/
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, size_t offset)
{
size_t pos = offset;
while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
pos += 2 + ies[pos + 1];
return pos;
}
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
{
size_t pos = offset;
while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
pos += 2 + ies[pos + 1];
return pos;
}

1086
net/mac80211/work.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -94,21 +94,6 @@ config CFG80211_DEBUGFS
If unsure, say N.
config WIRELESS_OLD_REGULATORY
bool "Old wireless static regulatory definitions"
default n
depends on CFG80211
---help---
This option enables the old static regulatory information
and uses it within the new framework. This option is available
for historical reasons and it is advised to leave it off.
For details see:
http://wireless.kernel.org/en/developers/Regulatory
Say N and if you say Y, please tell us why. The default is N.
config CFG80211_INTERNAL_REGDB
bool "use statically compiled regulatory rules database" if EMBEDDED
default n

View file

@ -41,12 +41,45 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev,
return result;
}
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
int freq, enum nl80211_channel_type channel_type)
{
struct ieee80211_channel *chan;
struct ieee80211_sta_ht_cap *ht_cap;
chan = ieee80211_get_channel(&rdev->wiphy, freq);
/* Primary channel not allowed */
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
return NULL;
if (channel_type == NL80211_CHAN_HT40MINUS &&
chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
return NULL;
else if (channel_type == NL80211_CHAN_HT40PLUS &&
chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
return NULL;
ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
if (channel_type != NL80211_CHAN_NO_HT) {
if (!ht_cap->ht_supported)
return NULL;
if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
return NULL;
}
return chan;
}
int rdev_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev,
int freq, enum nl80211_channel_type channel_type)
{
struct ieee80211_channel *chan;
struct ieee80211_sta_ht_cap *ht_cap;
int result;
if (rdev_fixed_channel(rdev, for_wdev))
@ -55,30 +88,10 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev,
if (!rdev->ops->set_channel)
return -EOPNOTSUPP;
chan = ieee80211_get_channel(&rdev->wiphy, freq);
/* Primary channel not allowed */
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
chan = rdev_freq_to_chan(rdev, freq, channel_type);
if (!chan)
return -EINVAL;
if (channel_type == NL80211_CHAN_HT40MINUS &&
chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
return -EINVAL;
else if (channel_type == NL80211_CHAN_HT40PLUS &&
chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
return -EINVAL;
ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
if (channel_type != NL80211_CHAN_NO_HT) {
if (!ht_cap->ht_supported)
return -EINVAL;
if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
return -EINVAL;
}
result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
if (result)
return result;

View file

@ -374,6 +374,9 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
struct ieee80211_channel *
rdev_fixed_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev);
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
int freq, enum nl80211_channel_type channel_type);
int rdev_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev,
int freq, enum nl80211_channel_type channel_type);

View file

@ -93,7 +93,18 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
}
}
WARN_ON(!bss);
/*
* We might be coming here because the driver reported
* a successful association at the same time as the
* user requested a deauth. In that case, we will have
* removed the BSS from the auth_bsses list due to the
* deauth request when the assoc response makes it. If
* the two code paths acquire the lock the other way
* around, that's just the standard situation of a
* deauth being requested while connected.
*/
if (!bss)
goto out;
} else if (wdev->conn) {
cfg80211_sme_failed_assoc(wdev);
/*
@ -680,3 +691,40 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
}
}
}
void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
duration, gfp);
}
EXPORT_SYMBOL(cfg80211_ready_on_channel);
void cfg80211_remain_on_channel_expired(struct net_device *dev,
u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
channel_type, gfp);
}
EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
}
EXPORT_SYMBOL(cfg80211_new_sta);

View file

@ -141,6 +141,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
[NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
.len = WLAN_PMKID_LEN },
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
};
/* policy for the attributes */
@ -569,6 +571,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(set_pmksa, SET_PMKSA);
CMD(del_pmksa, DEL_PMKSA);
CMD(flush_pmksa, FLUSH_PMKSA);
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@ -1639,7 +1642,7 @@ static int parse_station_flags(struct genl_info *info,
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
int flags, struct net_device *dev,
u8 *mac_addr, struct station_info *sinfo)
const u8 *mac_addr, struct station_info *sinfo)
{
void *hdr;
struct nlattr *sinfoattr, *txrate;
@ -2550,12 +2553,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
/* We ignore world regdom requests with the old regdom setup */
if (is_world_regdom(data))
return -EINVAL;
#endif
r = regulatory_hint_user(data);
return r;
@ -4289,6 +4286,143 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
}
static int nl80211_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
struct net_device *dev;
struct ieee80211_channel *chan;
struct sk_buff *msg;
void *hdr;
u64 cookie;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq, duration;
int err;
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
!info->attrs[NL80211_ATTR_DURATION])
return -EINVAL;
duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
/*
* We should be on that channel for at least one jiffie,
* and more than 5 seconds seems excessive.
*/
if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
return -EINVAL;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (!rdev->ops->remain_on_channel) {
err = -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) {
err = -ENETDOWN;
goto out;
}
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
channel_type = nla_get_u32(
info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
if (channel_type != NL80211_CHAN_NO_HT &&
channel_type != NL80211_CHAN_HT20 &&
channel_type != NL80211_CHAN_HT40PLUS &&
channel_type != NL80211_CHAN_HT40MINUS)
err = -EINVAL;
goto out;
}
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type);
if (chan == NULL) {
err = -EINVAL;
goto out;
}
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) {
err = -ENOMEM;
goto out;
}
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_REMAIN_ON_CHANNEL);
if (IS_ERR(hdr)) {
err = PTR_ERR(hdr);
goto free_msg;
}
err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan,
channel_type, duration, &cookie);
if (err)
goto free_msg;
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
genlmsg_end(msg, hdr);
err = genlmsg_reply(msg, info);
goto out;
nla_put_failure:
err = -ENOBUFS;
free_msg:
nlmsg_free(msg);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
}
static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
struct net_device *dev;
u64 cookie;
int err;
if (!info->attrs[NL80211_ATTR_COOKIE])
return -EINVAL;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (!rdev->ops->cancel_remain_on_channel) {
err = -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) {
err = -ENETDOWN;
goto out;
}
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
}
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@ -4551,8 +4685,20 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
.doit = nl80211_remain_on_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
.doit = nl80211_cancel_remain_on_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
.name = "mlme",
};
@ -5140,6 +5286,89 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
nlmsg_free(msg);
}
static void nl80211_send_remain_on_chan_event(
int cmd, struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
if (!hdr) {
nlmsg_free(msg);
return;
}
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type);
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
if (genlmsg_end(msg, hdr) < 0) {
nlmsg_free(msg);
return;
}
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return;
nla_put_failure:
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
rdev, netdev, cookie, chan,
channel_type, duration, gfp);
}
void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev, struct net_device *netdev,
u64 cookie, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, gfp_t gfp)
{
nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
rdev, netdev, cookie, chan,
channel_type, 0, gfp);
}
void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp)
{
struct sk_buff *msg;
msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
if (!msg)
return;
if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) {
nlmsg_free(msg);
return;
}
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
}
/* initialisation/exit functions */
int nl80211_init(void)

View file

@ -59,4 +59,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
gfp_t gfp);
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp);
void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev, struct net_device *netdev,
u64 cookie, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, gfp_t gfp);
void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);
#endif /* __NET_WIRELESS_NL80211_H */

View file

@ -129,78 +129,6 @@ static char *ieee80211_regdom = "00";
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
/*
* We assume 40 MHz bandwidth for the old regulatory work.
* We make emphasis we are using the exact same frequencies
* as before
*/
static const struct ieee80211_regdomain us_regdom = {
.n_reg_rules = 6,
.alpha2 = "US",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..11 */
REG_RULE(2412-10, 2462+10, 40, 6, 27, 0),
/* IEEE 802.11a, channel 36..48 */
REG_RULE(5180-10, 5240+10, 40, 6, 17, 0),
/* IEEE 802.11a, channels 48..64 */
REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS),
/* IEEE 802.11a, channels 100..124 */
REG_RULE(5500-10, 5590+10, 40, 6, 20, NL80211_RRF_DFS),
/* IEEE 802.11a, channels 132..144 */
REG_RULE(5660-10, 5700+10, 40, 6, 20, NL80211_RRF_DFS),
/* IEEE 802.11a, channels 149..165, outdoor */
REG_RULE(5745-10, 5825+10, 40, 6, 30, 0),
}
};
static const struct ieee80211_regdomain jp_regdom = {
.n_reg_rules = 6,
.alpha2 = "JP",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..11 */
REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
/* IEEE 802.11b/g, channels 12..13 */
REG_RULE(2467-10, 2472+10, 20, 6, 20, 0),
/* IEEE 802.11b/g, channel 14 */
REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_OFDM),
/* IEEE 802.11a, channels 36..48 */
REG_RULE(5180-10, 5240+10, 40, 6, 20, 0),
/* IEEE 802.11a, channels 52..64 */
REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS),
/* IEEE 802.11a, channels 100..144 */
REG_RULE(5500-10, 5700+10, 40, 6, 23, NL80211_RRF_DFS),
}
};
static const struct ieee80211_regdomain *static_regdom(char *alpha2)
{
if (alpha2[0] == 'U' && alpha2[1] == 'S')
return &us_regdom;
if (alpha2[0] == 'J' && alpha2[1] == 'P')
return &jp_regdom;
/* Use world roaming rules for "EU", since it was a pseudo
domain anyway... */
if (alpha2[0] == 'E' && alpha2[1] == 'U')
return &world_regdom;
/* Default, world roaming rules */
return &world_regdom;
}
static bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
{
if (rd == &us_regdom || rd == &jp_regdom || rd == &world_regdom)
return true;
return false;
}
#else
static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
{
return false;
}
#endif
static void reset_regdomains(void)
{
/* avoid freeing static information or freeing something twice */
@ -210,8 +138,6 @@ static void reset_regdomains(void)
cfg80211_world_regdom = NULL;
if (cfg80211_regdomain == &world_regdom)
cfg80211_regdomain = NULL;
if (is_old_static_regdom(cfg80211_regdomain))
cfg80211_regdomain = NULL;
kfree(cfg80211_regdomain);
kfree(cfg80211_world_regdom);
@ -1490,8 +1416,6 @@ static int ignore_request(struct wiphy *wiphy,
return REG_INTERSECT;
case NL80211_REGDOM_SET_BY_DRIVER:
if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
if (is_old_static_regdom(cfg80211_regdomain))
return 0;
if (regdom_changes(pending_request->alpha2))
return 0;
return -EALREADY;
@ -1528,8 +1452,7 @@ static int ignore_request(struct wiphy *wiphy,
return -EAGAIN;
}
if (!is_old_static_regdom(cfg80211_regdomain) &&
!regdom_changes(pending_request->alpha2))
if (!regdom_changes(pending_request->alpha2))
return -EALREADY;
return 0;
@ -2111,8 +2034,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
* If someone else asked us to change the rd lets only bother
* checking if the alpha2 changes if CRDA was already called
*/
if (!is_old_static_regdom(cfg80211_regdomain) &&
!regdom_changes(rd->alpha2))
if (!regdom_changes(rd->alpha2))
return -EINVAL;
}
@ -2311,15 +2233,8 @@ int regulatory_init(void)
spin_lock_init(&reg_requests_lock);
spin_lock_init(&reg_pending_beacons_lock);
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
cfg80211_regdomain = static_regdom(ieee80211_regdom);
printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
print_regdomain_info(cfg80211_regdomain);
#else
cfg80211_regdomain = cfg80211_world_regdom;
#endif
/* We always try to get an update for the static regdomain */
err = regulatory_hint_core(cfg80211_regdomain->alpha2);
if (err) {

View file

@ -601,7 +601,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
struct cfg80211_registered_device *rdev;
struct wiphy *wiphy;
struct iw_scan_req *wreq = NULL;
struct cfg80211_scan_request *creq;
struct cfg80211_scan_request *creq = NULL;
int i, err, n_channels = 0;
enum ieee80211_band band;
@ -694,8 +694,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
/* translate "Scan for SSID" request */
if (wreq) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
err = -EINVAL;
goto out;
}
memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
creq->ssids[0].ssid_len = wreq->essid_len;
}
@ -707,12 +709,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
err = rdev->ops->scan(wiphy, dev, creq);
if (err) {
rdev->scan_req = NULL;
kfree(creq);
/* creq will be freed below */
} else {
nl80211_send_scan_start(rdev, dev);
/* creq now owned by driver */
creq = NULL;
dev_hold(dev);
}
out:
kfree(creq);
cfg80211_unlock_rdev(rdev);
return err;
}