Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
Коммит
a8519de4a0
14
MAINTAINERS
14
MAINTAINERS
|
@ -3583,9 +3583,12 @@ M: "John W. Linville" <linville@tuxdriver.com>
|
|||
L: linux-wireless@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
|
||||
S: Maintained
|
||||
F: net/mac80211/
|
||||
F: net/rfkill/
|
||||
F: net/wireless/
|
||||
F: include/net/ieee80211*
|
||||
F: include/linux/wireless.h
|
||||
F: drivers/net/wireless/
|
||||
|
||||
NETWORKING DRIVERS
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -5577,7 +5580,16 @@ L: linux-wireless@vger.kernel.org
|
|||
W: http://wireless.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/wl12xx/wl1251*
|
||||
F: drivers/net/wireless/wl12xx/*
|
||||
X: drivers/net/wireless/wl12xx/wl1271*
|
||||
|
||||
WL1271 WIRELESS DRIVER
|
||||
M: Luciano Coelho <luciano.coelho@nokia.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://wireless.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/wl12xx/wl1271*
|
||||
|
||||
WL3501 WIRELESS PCMCIA CARD DRIVER
|
||||
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
|
||||
|
|
|
@ -233,6 +233,11 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
|
|||
{
|
||||
int status;
|
||||
|
||||
if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
|
||||
skb_queue_tail(&dev->rxq_pause, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
skb->protocol = eth_type_trans (skb, dev->net);
|
||||
dev->net->stats.rx_packets++;
|
||||
dev->net->stats.rx_bytes += skb->len;
|
||||
|
@ -525,6 +530,41 @@ static void intr_complete (struct urb *urb)
|
|||
deverr(dev, "intr resubmit --> %d", status);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void usbnet_pause_rx(struct usbnet *dev)
|
||||
{
|
||||
set_bit(EVENT_RX_PAUSED, &dev->flags);
|
||||
|
||||
if (netif_msg_rx_status(dev))
|
||||
devdbg(dev, "paused rx queue enabled");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbnet_pause_rx);
|
||||
|
||||
void usbnet_resume_rx(struct usbnet *dev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int num = 0;
|
||||
|
||||
clear_bit(EVENT_RX_PAUSED, &dev->flags);
|
||||
|
||||
while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) {
|
||||
usbnet_skb_return(dev, skb);
|
||||
num++;
|
||||
}
|
||||
|
||||
tasklet_schedule(&dev->bh);
|
||||
|
||||
if (netif_msg_rx_status(dev))
|
||||
devdbg(dev, "paused rx queue disabled, %d skbs requeued", num);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbnet_resume_rx);
|
||||
|
||||
void usbnet_purge_paused_rxq(struct usbnet *dev)
|
||||
{
|
||||
skb_queue_purge(&dev->rxq_pause);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
// unlink pending rx/tx; completion handlers do all other cleanup
|
||||
|
@ -623,6 +663,8 @@ int usbnet_stop (struct net_device *net)
|
|||
|
||||
usb_kill_urb(dev->interrupt);
|
||||
|
||||
usbnet_purge_paused_rxq(dev);
|
||||
|
||||
/* deferred work (task, timer, softirq) must also stop.
|
||||
* can't flush_scheduled_work() until we drop rtnl (later),
|
||||
* else workers could deadlock; so make workers a NOP.
|
||||
|
@ -1113,7 +1155,6 @@ static void usbnet_bh (unsigned long param)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* USB Device Driver support
|
||||
|
@ -1210,6 +1251,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
|
|||
skb_queue_head_init (&dev->rxq);
|
||||
skb_queue_head_init (&dev->txq);
|
||||
skb_queue_head_init (&dev->done);
|
||||
skb_queue_head_init(&dev->rxq_pause);
|
||||
dev->bh.func = usbnet_bh;
|
||||
dev->bh.data = (unsigned long) dev;
|
||||
INIT_WORK (&dev->kevent, kevent);
|
||||
|
|
|
@ -5,9 +5,7 @@ menuconfig ATH_COMMON
|
|||
---help---
|
||||
This will enable the support for the Atheros wireless drivers.
|
||||
ath5k, ath9k and ar9170 drivers share some common code, this option
|
||||
enables the common ath.ko module which currently shares just common
|
||||
regulatory EEPROM helpers but will likely be extended later to share
|
||||
more between modules.
|
||||
enables the common ath.ko module which shares common helpers.
|
||||
|
||||
For more information and documentation on this module you can visit:
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2009 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ATH_H
|
||||
#define ATH_H
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
struct ath_common {
|
||||
u16 cachelsz;
|
||||
};
|
||||
|
||||
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
||||
u32 len,
|
||||
gfp_t gfp_mask);
|
||||
|
||||
#endif /* ATH_H */
|
|
@ -919,6 +919,12 @@ enum ath5k_int {
|
|||
AR5K_INT_NOCARD = 0xffffffff
|
||||
};
|
||||
|
||||
/* Software interrupts used for calibration */
|
||||
enum ath5k_software_interrupt {
|
||||
AR5K_SWI_FULL_CALIBRATION = 0x01,
|
||||
AR5K_SWI_SHORT_CALIBRATION = 0x02,
|
||||
};
|
||||
|
||||
/*
|
||||
* Power management
|
||||
*/
|
||||
|
@ -1123,6 +1129,15 @@ struct ath5k_hw {
|
|||
/* noise floor from last periodic calibration */
|
||||
s32 ah_noise_floor;
|
||||
|
||||
/* Calibration timestamp */
|
||||
unsigned long ah_cal_tstamp;
|
||||
|
||||
/* Calibration interval (secs) */
|
||||
u8 ah_cal_intval;
|
||||
|
||||
/* Software interrupt mask */
|
||||
u8 ah_swi_mask;
|
||||
|
||||
/*
|
||||
* Function pointers
|
||||
*/
|
||||
|
@ -1157,6 +1172,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc);
|
|||
|
||||
/* Reset Functions */
|
||||
extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
|
||||
extern int ath5k_hw_on_hold(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
|
||||
/* Power management functions */
|
||||
extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
|
||||
|
@ -1275,6 +1291,7 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann
|
|||
/* PHY calibration */
|
||||
extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
|
||||
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
|
||||
extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
|
||||
/* Spur mitigation */
|
||||
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
|
||||
struct ieee80211_channel *channel);
|
||||
|
|
|
@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
|||
goto err_free;
|
||||
|
||||
/* Bring device out of sleep and reset it's units */
|
||||
ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true);
|
||||
ret = ath5k_hw_nic_wakeup(ah, 0, true);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
|
@ -252,28 +252,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write PCI-E power save settings
|
||||
*/
|
||||
if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
|
||||
ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
|
||||
/* Shut off RX when elecidle is asserted */
|
||||
ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
|
||||
/* TODO: EEPROM work */
|
||||
ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
|
||||
/* Shut off PLL and CLKREQ active in L1 */
|
||||
ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
|
||||
/* Preserce other settings */
|
||||
ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
|
||||
/* Reset SERDES to load new settings */
|
||||
ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* POST
|
||||
*/
|
||||
|
@ -283,7 +261,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
|||
|
||||
/* Enable pci core retry fix on Hainan (5213A) and later chips */
|
||||
if (srev >= AR5K_SREV_AR5213A)
|
||||
ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG);
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX);
|
||||
|
||||
/*
|
||||
* Get card capabilities, calibration values etc
|
||||
|
@ -295,6 +273,40 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write PCI-E power save settings
|
||||
*/
|
||||
if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
|
||||
ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
|
||||
|
||||
/* Shut off RX when elecidle is asserted */
|
||||
ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
|
||||
|
||||
/* If serdes programing is enabled, increase PCI-E
|
||||
* tx power for systems with long trace from host
|
||||
* to minicard connector. */
|
||||
if (ee->ee_serdes)
|
||||
ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
|
||||
else
|
||||
ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES);
|
||||
|
||||
/* Shut off PLL and CLKREQ active in L1 */
|
||||
ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
|
||||
|
||||
/* Preserve other settings */
|
||||
ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
|
||||
ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
|
||||
|
||||
/* Reset SERDES to load new settings */
|
||||
ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
/* Get misc capabilities */
|
||||
ret = ath5k_hw_set_capabilities(ah);
|
||||
if (ret) {
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
|
||||
static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
|
||||
static int modparam_nohwcrypt;
|
||||
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
|
||||
|
@ -376,7 +376,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc);
|
|||
static irqreturn_t ath5k_intr(int irq, void *dev_id);
|
||||
static void ath5k_tasklet_reset(unsigned long data);
|
||||
|
||||
static void ath5k_calibrate(unsigned long data);
|
||||
static void ath5k_tasklet_calibrate(unsigned long data);
|
||||
|
||||
/*
|
||||
* Module init/exit functions
|
||||
|
@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
|||
* DMA to work so force a reasonable value here if it
|
||||
* comes up zero.
|
||||
*/
|
||||
csz = L1_CACHE_BYTES / sizeof(u32);
|
||||
csz = L1_CACHE_BYTES >> 2;
|
||||
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
|
||||
}
|
||||
/*
|
||||
|
@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
|||
__set_bit(ATH_STAT_INVALID, sc->status);
|
||||
|
||||
sc->iobase = mem; /* So we can unmap it on detach */
|
||||
sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
|
||||
sc->common.cachelsz = csz << 2; /* convert to bytes */
|
||||
sc->opmode = NL80211_IFTYPE_STATION;
|
||||
sc->bintval = 1000;
|
||||
mutex_init(&sc->lock);
|
||||
|
@ -799,8 +799,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|||
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
|
||||
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
|
||||
tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
|
||||
tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
|
||||
tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
|
||||
setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
|
||||
|
||||
ret = ath5k_eeprom_read_mac(ah, mac);
|
||||
if (ret) {
|
||||
|
@ -1071,10 +1071,9 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
|
|||
}
|
||||
|
||||
/*
|
||||
* Set/change channels. If the channel is really being changed,
|
||||
* it's done by reseting the chip. To accomplish this we must
|
||||
* first cleanup any pending DMA, then restart stuff after a la
|
||||
* ath5k_init.
|
||||
* Set/change channels. We always reset the chip.
|
||||
* To accomplish this we must first cleanup any pending DMA,
|
||||
* then restart stuff after a la ath5k_init.
|
||||
*
|
||||
* Called with sc->lock.
|
||||
*/
|
||||
|
@ -1084,19 +1083,13 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
|
|||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
|
||||
sc->curchan->center_freq, chan->center_freq);
|
||||
|
||||
if (chan->center_freq != sc->curchan->center_freq ||
|
||||
chan->hw_value != sc->curchan->hw_value) {
|
||||
|
||||
/*
|
||||
* To switch channels clear any pending DMA operations;
|
||||
* wait long enough for the RX fifo to drain, reset the
|
||||
* hardware at the new frequency, and then re-enable
|
||||
* the relevant bits of the h/w.
|
||||
*/
|
||||
return ath5k_reset(sc, chan);
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* To switch channels clear any pending DMA operations;
|
||||
* wait long enough for the RX fifo to drain, reset the
|
||||
* hardware at the new frequency, and then re-enable
|
||||
* the relevant bits of the h/w.
|
||||
*/
|
||||
return ath5k_reset(sc, chan);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1158,27 +1151,20 @@ static
|
|||
struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
unsigned int off;
|
||||
|
||||
/*
|
||||
* Allocate buffer with headroom_needed space for the
|
||||
* fake physical layer header at the start.
|
||||
*/
|
||||
skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
|
||||
skb = ath_rxbuf_alloc(&sc->common,
|
||||
sc->rxbufsize + sc->common.cachelsz - 1,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (!skb) {
|
||||
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
|
||||
sc->rxbufsize + sc->cachelsz - 1);
|
||||
sc->rxbufsize + sc->common.cachelsz - 1);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Cache-line-align. This is important (for the
|
||||
* 5210 at least) as not doing so causes bogus data
|
||||
* in rx'd frames.
|
||||
*/
|
||||
off = ((unsigned long)skb->data) % sc->cachelsz;
|
||||
if (off != 0)
|
||||
skb_reserve(skb, sc->cachelsz - off);
|
||||
|
||||
*skb_addr = pci_map_single(sc->pdev,
|
||||
skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
|
||||
|
@ -1620,10 +1606,10 @@ ath5k_rx_start(struct ath5k_softc *sc)
|
|||
struct ath5k_buf *bf;
|
||||
int ret;
|
||||
|
||||
sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz);
|
||||
sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
|
||||
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
|
||||
sc->cachelsz, sc->rxbufsize);
|
||||
sc->common.cachelsz, sc->rxbufsize);
|
||||
|
||||
spin_lock_bh(&sc->rxbuflock);
|
||||
sc->rxlink = NULL;
|
||||
|
@ -2371,7 +2357,7 @@ ath5k_init(struct ath5k_softc *sc)
|
|||
sc->curband = &sc->sbands[sc->curchan->band];
|
||||
sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
|
||||
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
|
||||
AR5K_INT_FATAL | AR5K_INT_GLOBAL;
|
||||
AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI;
|
||||
ret = ath5k_reset(sc, NULL);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
@ -2388,8 +2374,8 @@ ath5k_init(struct ath5k_softc *sc)
|
|||
/* Set ack to be sent at low bit-rates */
|
||||
ath5k_hw_set_ack_bitrate_high(ah, false);
|
||||
|
||||
mod_timer(&sc->calib_tim, round_jiffies(jiffies +
|
||||
msecs_to_jiffies(ath5k_calinterval * 1000)));
|
||||
/* Set PHY calibration inteval */
|
||||
ah->ah_cal_intval = ath5k_calinterval;
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
|
@ -2453,37 +2439,39 @@ ath5k_stop_hw(struct ath5k_softc *sc)
|
|||
ret = ath5k_stop_locked(sc);
|
||||
if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
|
||||
/*
|
||||
* Set the chip in full sleep mode. Note that we are
|
||||
* careful to do this only when bringing the interface
|
||||
* completely to a stop. When the chip is in this state
|
||||
* it must be carefully woken up or references to
|
||||
* registers in the PCI clock domain may freeze the bus
|
||||
* (and system). This varies by chip and is mostly an
|
||||
* issue with newer parts that go to sleep more quickly.
|
||||
*/
|
||||
if (sc->ah->ah_mac_srev >= 0x78) {
|
||||
/*
|
||||
* XXX
|
||||
* don't put newer MAC revisions > 7.8 to sleep because
|
||||
* of the above mentioned problems
|
||||
*/
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "
|
||||
"not putting device to sleep\n");
|
||||
} else {
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
|
||||
"putting device to full sleep\n");
|
||||
ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
|
||||
}
|
||||
* Don't set the card in full sleep mode!
|
||||
*
|
||||
* a) When the device is in this state it must be carefully
|
||||
* woken up or references to registers in the PCI clock
|
||||
* domain may freeze the bus (and system). This varies
|
||||
* by chip and is mostly an issue with newer parts
|
||||
* (madwifi sources mentioned srev >= 0x78) that go to
|
||||
* sleep more quickly.
|
||||
*
|
||||
* b) On older chips full sleep results a weird behaviour
|
||||
* during wakeup. I tested various cards with srev < 0x78
|
||||
* and they don't wake up after module reload, a second
|
||||
* module reload is needed to bring the card up again.
|
||||
*
|
||||
* Until we figure out what's going on don't enable
|
||||
* full chip reset on any chip (this is what Legacy HAL
|
||||
* and Sam's HAL do anyway). Instead Perform a full reset
|
||||
* on the device (same as initial state after attach) and
|
||||
* leave it idle (keep MAC/BB on warm reset) */
|
||||
ret = ath5k_hw_on_hold(sc->ah);
|
||||
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
|
||||
"putting device to sleep\n");
|
||||
}
|
||||
ath5k_txbuf_free(sc, sc->bbuf);
|
||||
|
||||
mmiowb();
|
||||
mutex_unlock(&sc->lock);
|
||||
|
||||
del_timer_sync(&sc->calib_tim);
|
||||
tasklet_kill(&sc->rxtq);
|
||||
tasklet_kill(&sc->txtq);
|
||||
tasklet_kill(&sc->restq);
|
||||
tasklet_kill(&sc->calib);
|
||||
tasklet_kill(&sc->beacontq);
|
||||
|
||||
ath5k_rfkill_hw_stop(sc->ah);
|
||||
|
@ -2539,6 +2527,9 @@ ath5k_intr(int irq, void *dev_id)
|
|||
if (status & AR5K_INT_BMISS) {
|
||||
/* TODO */
|
||||
}
|
||||
if (status & AR5K_INT_SWI) {
|
||||
tasklet_schedule(&sc->calib);
|
||||
}
|
||||
if (status & AR5K_INT_MIB) {
|
||||
/*
|
||||
* These stats are also used for ANI i think
|
||||
|
@ -2555,6 +2546,8 @@ ath5k_intr(int irq, void *dev_id)
|
|||
if (unlikely(!counter))
|
||||
ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
|
||||
|
||||
ath5k_hw_calibration_poll(ah);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -2571,11 +2564,19 @@ ath5k_tasklet_reset(unsigned long data)
|
|||
* for temperature/environment changes.
|
||||
*/
|
||||
static void
|
||||
ath5k_calibrate(unsigned long data)
|
||||
ath5k_tasklet_calibrate(unsigned long data)
|
||||
{
|
||||
struct ath5k_softc *sc = (void *)data;
|
||||
struct ath5k_hw *ah = sc->ah;
|
||||
|
||||
/* Only full calibration for now */
|
||||
if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION)
|
||||
return;
|
||||
|
||||
/* Stop queues so that calibration
|
||||
* doesn't interfere with tx */
|
||||
ieee80211_stop_queues(sc->hw);
|
||||
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
|
||||
ieee80211_frequency_to_channel(sc->curchan->center_freq),
|
||||
sc->curchan->hw_value);
|
||||
|
@ -2593,8 +2594,11 @@ ath5k_calibrate(unsigned long data)
|
|||
ieee80211_frequency_to_channel(
|
||||
sc->curchan->center_freq));
|
||||
|
||||
mod_timer(&sc->calib_tim, round_jiffies(jiffies +
|
||||
msecs_to_jiffies(ath5k_calinterval * 1000)));
|
||||
ah->ah_swi_mask = 0;
|
||||
|
||||
/* Wake queues */
|
||||
ieee80211_wake_queues(sc->hw);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -2811,9 +2815,11 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
|
||||
mutex_lock(&sc->lock);
|
||||
|
||||
ret = ath5k_chan_set(sc, conf->channel);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
ret = ath5k_chan_set(sc, conf->channel);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
|
||||
(sc->power_level != conf->power_level)) {
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
|
||||
#include "ath5k.h"
|
||||
#include "debug.h"
|
||||
#include "../ath.h"
|
||||
|
||||
#define ATH_RXBUF 40 /* number of RX buffers */
|
||||
#define ATH_TXBUF 200 /* number of TX buffers */
|
||||
|
@ -112,6 +113,7 @@ struct ath5k_rfkill {
|
|||
* associated with an instance of a device */
|
||||
struct ath5k_softc {
|
||||
struct pci_dev *pdev; /* for dma mapping */
|
||||
struct ath_common common;
|
||||
void __iomem *iobase; /* address of the device */
|
||||
struct mutex lock; /* dev-level lock */
|
||||
struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
|
||||
|
@ -134,7 +136,6 @@ struct ath5k_softc {
|
|||
struct ath5k_desc *desc; /* TX/RX descriptors */
|
||||
dma_addr_t desc_daddr; /* DMA (physical) address */
|
||||
size_t desc_len; /* size of TX/RX descriptors */
|
||||
u16 cachelsz; /* cache line size */
|
||||
|
||||
DECLARE_BITMAP(status, 5);
|
||||
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
|
||||
|
@ -177,6 +178,8 @@ struct ath5k_softc {
|
|||
|
||||
struct ath5k_rfkill rf_kill;
|
||||
|
||||
struct tasklet_struct calib; /* calibration tasklet */
|
||||
|
||||
spinlock_t block; /* protects beacon */
|
||||
struct tasklet_struct beacontq; /* beacon intr tasklet */
|
||||
struct ath5k_buf *bbuf; /* beacon buffer */
|
||||
|
@ -187,7 +190,6 @@ struct ath5k_softc {
|
|||
unsigned int nexttbtt; /* next beacon time in TU */
|
||||
struct ath5k_txq *cabq; /* content after beacon */
|
||||
|
||||
struct timer_list calib_tim; /* calibration timer */
|
||||
int power_level; /* Requested tx power in dbm */
|
||||
bool assoc; /* assocate state */
|
||||
bool enable_beacon; /* true if beacons are on */
|
||||
|
|
|
@ -167,6 +167,16 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
|
|||
ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);
|
||||
ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false;
|
||||
|
||||
/* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION
|
||||
* and enable serdes programming if needed.
|
||||
*
|
||||
* XXX: Serdes values seem to be fixed so
|
||||
* no need to read them here, we write them
|
||||
* during ath5k_hw_attach */
|
||||
AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val);
|
||||
ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ?
|
||||
true : false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
/*
|
||||
* Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
|
||||
*/
|
||||
#define AR5K_EEPROM_PCIE_OFFSET 0x02 /* Contains offset to PCI-E infos */
|
||||
#define AR5K_EEPROM_PCIE_SERDES_SECTION 0x40 /* PCIE_OFFSET points here when
|
||||
* SERDES infos are present */
|
||||
#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */
|
||||
#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */
|
||||
#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */
|
||||
|
@ -391,6 +394,7 @@ struct ath5k_eeprom_info {
|
|||
u8 ee_rfkill_pin;
|
||||
bool ee_rfkill_pol;
|
||||
bool ee_is_hb63;
|
||||
bool ee_serdes;
|
||||
u16 ee_misc0;
|
||||
u16 ee_misc1;
|
||||
u16 ee_misc2;
|
||||
|
|
|
@ -740,13 +740,22 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
|||
AR5K_RF_XPD_GAIN, true);
|
||||
|
||||
} else {
|
||||
/* TODO: Set high and low gain bits */
|
||||
ath5k_hw_rfb_op(ah, rf_regs,
|
||||
ee->ee_x_gain[ee_mode],
|
||||
u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
|
||||
if (ee->ee_pd_gains[ee_mode] > 1) {
|
||||
ath5k_hw_rfb_op(ah, rf_regs,
|
||||
pdg_curve_to_idx[0],
|
||||
AR5K_RF_PD_GAIN_LO, true);
|
||||
ath5k_hw_rfb_op(ah, rf_regs,
|
||||
ee->ee_x_gain[ee_mode],
|
||||
ath5k_hw_rfb_op(ah, rf_regs,
|
||||
pdg_curve_to_idx[1],
|
||||
AR5K_RF_PD_GAIN_HI, true);
|
||||
} else {
|
||||
ath5k_hw_rfb_op(ah, rf_regs,
|
||||
pdg_curve_to_idx[0],
|
||||
AR5K_RF_PD_GAIN_LO, true);
|
||||
ath5k_hw_rfb_op(ah, rf_regs,
|
||||
pdg_curve_to_idx[0],
|
||||
AR5K_RF_PD_GAIN_HI, true);
|
||||
}
|
||||
|
||||
/* Lower synth voltage on Rev 2 */
|
||||
ath5k_hw_rfb_op(ah, rf_regs, 2,
|
||||
|
@ -1095,6 +1104,29 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
|
|||
PHY calibration
|
||||
\*****************/
|
||||
|
||||
void
|
||||
ath5k_hw_calibration_poll(struct ath5k_hw *ah)
|
||||
{
|
||||
/* Calibration interval in jiffies */
|
||||
unsigned long cal_intval;
|
||||
|
||||
cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000);
|
||||
|
||||
/* Initialize timestamp if needed */
|
||||
if (!ah->ah_cal_tstamp)
|
||||
ah->ah_cal_tstamp = jiffies;
|
||||
|
||||
/* For now we always do full calibration
|
||||
* Mark software interrupt mask and fire software
|
||||
* interrupt (bit gets auto-cleared) */
|
||||
if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) {
|
||||
ah->ah_cal_tstamp = jiffies;
|
||||
ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
|
||||
*
|
||||
|
@ -1896,8 +1928,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
|
|||
s16 min_pwrL, min_pwrR;
|
||||
s16 pwr_i;
|
||||
|
||||
if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1]))
|
||||
return 0;
|
||||
/* Some vendors write the same pcdac value twice !!! */
|
||||
if (stepL[0] == stepL[1] || stepR[0] == stepR[1])
|
||||
return max(pwrL[0], pwrR[0]);
|
||||
|
||||
if (pwrL[0] == pwrL[1])
|
||||
min_pwrL = pwrL[0];
|
||||
|
|
|
@ -362,7 +362,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
}
|
||||
|
||||
if (tq->tqi_ready_time &&
|
||||
(tq->tqi_type != AR5K_TX_QUEUE_ID_CAB))
|
||||
(tq->tqi_type != AR5K_TX_QUEUE_CAB))
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
|
||||
AR5K_QCU_RDYTIMECFG_INTVAL) |
|
||||
AR5K_QCU_RDYTIMECFG_ENABLE,
|
||||
|
|
|
@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
|
|||
if (!set_chip)
|
||||
goto commit;
|
||||
|
||||
/* Preserve sleep duration */
|
||||
data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
|
||||
|
||||
/* If card is down we 'll get 0xffff... so we
|
||||
* need to clean this up before we write the register
|
||||
*/
|
||||
if (data & 0xffc00000)
|
||||
data = 0;
|
||||
else
|
||||
data = data & 0xfffcffff;
|
||||
/* Preserve sleep duration etc */
|
||||
data = data & ~AR5K_SLEEP_CTL_SLE;
|
||||
|
||||
ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
|
||||
ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
|
||||
AR5K_SLEEP_CTL);
|
||||
udelay(15);
|
||||
|
||||
for (i = 50; i > 0; i--) {
|
||||
for (i = 200; i > 0; i--) {
|
||||
/* Check if the chip did wake up */
|
||||
if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
|
||||
AR5K_PCICFG_SPWR_DN) == 0)
|
||||
break;
|
||||
|
||||
/* Wait a bit and retry */
|
||||
udelay(200);
|
||||
ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
|
||||
udelay(50);
|
||||
ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
|
||||
AR5K_SLEEP_CTL);
|
||||
}
|
||||
|
||||
/* Fail if the chip didn't wake up */
|
||||
if (i <= 0)
|
||||
if (i == 0)
|
||||
return -EIO;
|
||||
|
||||
break;
|
||||
|
@ -295,6 +301,64 @@ commit:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put device on hold
|
||||
*
|
||||
* Put MAC and Baseband on warm reset and
|
||||
* keep that state (don't clean sleep control
|
||||
* register). After this MAC and Baseband are
|
||||
* disabled and a full reset is needed to come
|
||||
* back. This way we save as much power as possible
|
||||
* without puting the card on full sleep.
|
||||
*/
|
||||
int ath5k_hw_on_hold(struct ath5k_hw *ah)
|
||||
{
|
||||
struct pci_dev *pdev = ah->ah_sc->pdev;
|
||||
u32 bus_flags;
|
||||
int ret;
|
||||
|
||||
/* Make sure device is awake */
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put chipset on warm reset...
|
||||
*
|
||||
* Note: puting PCI core on warm reset on PCI-E cards
|
||||
* results card to hang and always return 0xffff... so
|
||||
* we ingore that flag for PCI-E cards. On PCI cards
|
||||
* this flag gets cleared after 64 PCI clocks.
|
||||
*/
|
||||
bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
||||
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
||||
mdelay(2);
|
||||
} else {
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_BASEBAND | bus_flags);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* ...wakeup again!*/
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bring up MAC + PHY Chips and program PLL
|
||||
* TODO: Half/Quarter rate support
|
||||
|
@ -318,6 +382,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put chipset on warm reset...
|
||||
*
|
||||
* Note: puting PCI core on warm reset on PCI-E cards
|
||||
* results card to hang and always return 0xffff... so
|
||||
* we ingore that flag for PCI-E cards. On PCI cards
|
||||
* this flag gets cleared after 64 PCI clocks.
|
||||
*/
|
||||
bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
||||
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
||||
mdelay(2);
|
||||
} else {
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_BASEBAND | bus_flags);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* ...wakeup again!...*/
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ...clear reset control register and pull device out of
|
||||
* warm reset */
|
||||
if (ath5k_hw_nic_reset(ah, 0)) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* On initialization skip PLL programming since we don't have
|
||||
* a channel / mode set yet */
|
||||
if (initial)
|
||||
return 0;
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
/*
|
||||
* Get channel mode flags
|
||||
|
@ -383,39 +491,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|||
AR5K_PHY_TURBO);
|
||||
}
|
||||
|
||||
/* reseting PCI on PCI-E cards results card to hang
|
||||
* and always return 0xffff... so we ingore that flag
|
||||
* for PCI-E cards */
|
||||
bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
|
||||
|
||||
/* Reset chipset */
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
||||
AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
||||
mdelay(2);
|
||||
} else {
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_BASEBAND | bus_flags);
|
||||
}
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* ...wakeup again!*/
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ...final warm reset */
|
||||
if (ath5k_hw_nic_reset(ah, 0)) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
|
||||
/* ...update PLL if needed */
|
||||
|
|
|
@ -6,7 +6,13 @@ config ATH9K
|
|||
select NEW_LEDS
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
|
||||
Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family
|
||||
of chipsets. For a specific list of supported external
|
||||
cards, laptops that already ship with these cards and
|
||||
APs that come with these cards refer to to ath9k wiki
|
||||
products page:
|
||||
|
||||
http://wireless.kernel.org/en/users/Drivers/ath9k/products
|
||||
|
||||
If you choose to build a module, it'll be called ath9k.
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
ath9k-y += hw.o \
|
||||
eeprom.o \
|
||||
eeprom_def.o \
|
||||
eeprom_4k.o \
|
||||
eeprom_9287.o \
|
||||
mac.o \
|
||||
calib.o \
|
||||
ani.o \
|
||||
|
|
|
@ -236,36 +236,35 @@ static void ath9k_ani_restart(struct ath_hw *ah)
|
|||
return;
|
||||
|
||||
aniState = ah->curani;
|
||||
|
||||
aniState->listenTime = 0;
|
||||
if (ah->has_hw_phycounters) {
|
||||
if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
|
||||
aniState->ofdmPhyErrBase = 0;
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"OFDM Trigger is too high for hw counters\n");
|
||||
} else {
|
||||
aniState->ofdmPhyErrBase =
|
||||
AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
|
||||
}
|
||||
if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
|
||||
aniState->cckPhyErrBase = 0;
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"CCK Trigger is too high for hw counters\n");
|
||||
} else {
|
||||
aniState->cckPhyErrBase =
|
||||
AR_PHY_COUNTMAX - aniState->cckTrigHigh;
|
||||
}
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"Writing ofdmbase=%u cckbase=%u\n",
|
||||
aniState->ofdmPhyErrBase,
|
||||
aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
|
||||
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
|
||||
aniState->ofdmPhyErrBase = 0;
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"OFDM Trigger is too high for hw counters\n");
|
||||
} else {
|
||||
aniState->ofdmPhyErrBase =
|
||||
AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
|
||||
}
|
||||
if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
|
||||
aniState->cckPhyErrBase = 0;
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"CCK Trigger is too high for hw counters\n");
|
||||
} else {
|
||||
aniState->cckPhyErrBase =
|
||||
AR_PHY_COUNTMAX - aniState->cckTrigHigh;
|
||||
}
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"Writing ofdmbase=%u cckbase=%u\n",
|
||||
aniState->ofdmPhyErrBase,
|
||||
aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
|
||||
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
|
||||
aniState->ofdmPhyErrCount = 0;
|
||||
aniState->cckPhyErrCount = 0;
|
||||
}
|
||||
|
@ -530,18 +529,12 @@ void ath9k_ani_reset(struct ath_hw *ah)
|
|||
if (aniState->firstepLevel != 0)
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
|
||||
aniState->firstepLevel);
|
||||
if (ah->has_hw_phycounters) {
|
||||
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
|
||||
~ATH9K_RX_FILTER_PHYERR);
|
||||
ath9k_ani_restart(ah);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
|
||||
|
||||
} else {
|
||||
ath9k_ani_restart(ah);
|
||||
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
|
||||
ATH9K_RX_FILTER_PHYERR);
|
||||
}
|
||||
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
|
||||
~ATH9K_RX_FILTER_PHYERR);
|
||||
ath9k_ani_restart(ah);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
|
||||
}
|
||||
|
||||
void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
||||
|
@ -550,6 +543,8 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
|||
{
|
||||
struct ar5416AniState *aniState;
|
||||
int32_t listenTime;
|
||||
u32 phyCnt1, phyCnt2;
|
||||
u32 ofdmPhyErrCnt, cckPhyErrCnt;
|
||||
|
||||
if (!DO_ANI(ah))
|
||||
return;
|
||||
|
@ -566,51 +561,46 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
|||
|
||||
aniState->listenTime += listenTime;
|
||||
|
||||
if (ah->has_hw_phycounters) {
|
||||
u32 phyCnt1, phyCnt2;
|
||||
u32 ofdmPhyErrCnt, cckPhyErrCnt;
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
|
||||
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
|
||||
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
|
||||
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
|
||||
|
||||
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
|
||||
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
|
||||
|
||||
if (phyCnt1 < aniState->ofdmPhyErrBase ||
|
||||
phyCnt2 < aniState->cckPhyErrBase) {
|
||||
if (phyCnt1 < aniState->ofdmPhyErrBase) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"phyCnt1 0x%x, resetting "
|
||||
"counter value to 0x%x\n",
|
||||
phyCnt1, aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1,
|
||||
aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1,
|
||||
AR_PHY_ERR_OFDM_TIMING);
|
||||
}
|
||||
if (phyCnt2 < aniState->cckPhyErrBase) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"phyCnt2 0x%x, resetting "
|
||||
"counter value to 0x%x\n",
|
||||
phyCnt2, aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2,
|
||||
aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2,
|
||||
AR_PHY_ERR_CCK_TIMING);
|
||||
}
|
||||
return;
|
||||
if (phyCnt1 < aniState->ofdmPhyErrBase ||
|
||||
phyCnt2 < aniState->cckPhyErrBase) {
|
||||
if (phyCnt1 < aniState->ofdmPhyErrBase) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"phyCnt1 0x%x, resetting "
|
||||
"counter value to 0x%x\n",
|
||||
phyCnt1, aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1,
|
||||
aniState->ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_1,
|
||||
AR_PHY_ERR_OFDM_TIMING);
|
||||
}
|
||||
|
||||
ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
|
||||
ah->stats.ast_ani_ofdmerrs +=
|
||||
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
|
||||
aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
|
||||
|
||||
cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
|
||||
ah->stats.ast_ani_cckerrs +=
|
||||
cckPhyErrCnt - aniState->cckPhyErrCount;
|
||||
aniState->cckPhyErrCount = cckPhyErrCnt;
|
||||
if (phyCnt2 < aniState->cckPhyErrBase) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"phyCnt2 0x%x, resetting "
|
||||
"counter value to 0x%x\n",
|
||||
phyCnt2, aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2,
|
||||
aniState->cckPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_MASK_2,
|
||||
AR_PHY_ERR_CCK_TIMING);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
|
||||
ah->stats.ast_ani_ofdmerrs +=
|
||||
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
|
||||
aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
|
||||
|
||||
cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
|
||||
ah->stats.ast_ani_cckerrs +=
|
||||
cckPhyErrCnt - aniState->cckPhyErrCount;
|
||||
aniState->cckPhyErrCount = cckPhyErrCnt;
|
||||
|
||||
if (aniState->listenTime > 5 * ah->aniperiod) {
|
||||
if (aniState->ofdmPhyErrCount <= aniState->listenTime *
|
||||
aniState->ofdmTrigLow / 1000 &&
|
||||
|
@ -632,11 +622,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
|||
}
|
||||
}
|
||||
|
||||
bool ath9k_hw_phycounters(struct ath_hw *ah)
|
||||
{
|
||||
return ah->has_hw_phycounters ? true : false;
|
||||
}
|
||||
|
||||
void ath9k_enable_mib_counters(struct ath_hw *ah)
|
||||
{
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
|
||||
|
@ -781,9 +766,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
|
|||
{
|
||||
int i;
|
||||
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
|
||||
|
||||
ah->has_hw_phycounters = 1;
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n");
|
||||
|
||||
memset(ah->ani, 0, sizeof(ah->ani));
|
||||
for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
|
||||
|
@ -799,24 +782,22 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
|
|||
ATH9K_ANI_CCK_WEAK_SIG_THR;
|
||||
ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
||||
ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
||||
if (ah->has_hw_phycounters) {
|
||||
ah->ani[i].ofdmPhyErrBase =
|
||||
AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ah->ani[i].cckPhyErrBase =
|
||||
AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
}
|
||||
ah->ani[i].ofdmPhyErrBase =
|
||||
AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ah->ani[i].cckPhyErrBase =
|
||||
AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
}
|
||||
if (ah->has_hw_phycounters) {
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"Setting OfdmErrBase = 0x%08x\n",
|
||||
ah->ani[0].ofdmPhyErrBase);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
|
||||
ah->ani[0].cckPhyErrBase);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
|
||||
ath9k_enable_mib_counters(ah);
|
||||
}
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
|
||||
"Setting OfdmErrBase = 0x%08x\n",
|
||||
ah->ani[0].ofdmPhyErrBase);
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
|
||||
ah->ani[0].cckPhyErrBase);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
|
||||
ath9k_enable_mib_counters(ah);
|
||||
|
||||
ah->aniperiod = ATH9K_ANI_PERIOD;
|
||||
if (ah->config.enable_ani)
|
||||
ah->proc_phyerr |= HAL_PROCESS_ANI;
|
||||
|
@ -826,9 +807,7 @@ void ath9k_hw_ani_disable(struct ath_hw *ah)
|
|||
{
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n");
|
||||
|
||||
if (ah->has_hw_phycounters) {
|
||||
ath9k_hw_disable_mib_counters(ah);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, 0);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, 0);
|
||||
}
|
||||
ath9k_hw_disable_mib_counters(ah);
|
||||
REG_WRITE(ah, AR_PHY_ERR_1, 0);
|
||||
REG_WRITE(ah, AR_PHY_ERR_2, 0);
|
||||
}
|
||||
|
|
|
@ -124,7 +124,6 @@ void ath9k_ani_reset(struct ath_hw *ah);
|
|||
void ath9k_hw_ani_monitor(struct ath_hw *ah,
|
||||
const struct ath9k_node_stats *stats,
|
||||
struct ath9k_channel *chan);
|
||||
bool ath9k_hw_phycounters(struct ath_hw *ah);
|
||||
void ath9k_enable_mib_counters(struct ath_hw *ah);
|
||||
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
|
||||
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "hw.h"
|
||||
#include "rc.h"
|
||||
#include "debug.h"
|
||||
#include "../ath.h"
|
||||
|
||||
struct ath_node;
|
||||
|
||||
|
@ -532,6 +533,8 @@ struct ath_softc {
|
|||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
|
||||
struct ath_common common;
|
||||
|
||||
spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
|
||||
struct ath_wiphy *pri_wiphy;
|
||||
struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
|
||||
|
@ -564,7 +567,6 @@ struct ath_softc {
|
|||
u32 sc_flags; /* SC_OP_* */
|
||||
u16 curtxpow;
|
||||
u16 curaid;
|
||||
u16 cachelsz;
|
||||
u8 nbcnvifs;
|
||||
u16 nvifs;
|
||||
u8 tx_chainmask;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -385,106 +385,124 @@ struct calDataPerFreqOpLoop {
|
|||
} __packed;
|
||||
|
||||
struct modal_eep_4k_header {
|
||||
u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
|
||||
u32 antCtrlCommon;
|
||||
u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 switchSettling;
|
||||
u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 adcDesiredSize;
|
||||
u8 pgaDesiredSize;
|
||||
u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 txEndToXpaOff;
|
||||
u8 txEndToRxOn;
|
||||
u8 txFrameToXpaOn;
|
||||
u8 thresh62;
|
||||
u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 xpdGain;
|
||||
u8 xpd;
|
||||
u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 pdGainOverlap;
|
||||
u8 ob_01;
|
||||
u8 db1_01;
|
||||
u8 xpaBiasLvl;
|
||||
u8 txFrameToDataStart;
|
||||
u8 txFrameToPaOn;
|
||||
u8 ht40PowerIncForPdadc;
|
||||
u8 bswAtten[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 bswMargin[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 swSettleHt40;
|
||||
u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 db2_01;
|
||||
u8 version;
|
||||
u16 ob_234;
|
||||
u16 db1_234;
|
||||
u16 db2_234;
|
||||
u8 futureModal[4];
|
||||
|
||||
u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
|
||||
u32 antCtrlCommon;
|
||||
u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 switchSettling;
|
||||
u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 adcDesiredSize;
|
||||
u8 pgaDesiredSize;
|
||||
u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 txEndToXpaOff;
|
||||
u8 txEndToRxOn;
|
||||
u8 txFrameToXpaOn;
|
||||
u8 thresh62;
|
||||
u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 xpdGain;
|
||||
u8 xpd;
|
||||
u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 pdGainOverlap;
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
u8 ob_1:4, ob_0:4;
|
||||
u8 db1_1:4, db1_0:4;
|
||||
#else
|
||||
u8 ob_0:4, ob_1:4;
|
||||
u8 db1_0:4, db1_1:4;
|
||||
#endif
|
||||
u8 xpaBiasLvl;
|
||||
u8 txFrameToDataStart;
|
||||
u8 txFrameToPaOn;
|
||||
u8 ht40PowerIncForPdadc;
|
||||
u8 bswAtten[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 bswMargin[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 swSettleHt40;
|
||||
u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
|
||||
u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
u8 db2_1:4, db2_0:4;
|
||||
#else
|
||||
u8 db2_0:4, db2_1:4;
|
||||
#endif
|
||||
u8 version;
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
u8 ob_3:4, ob_2:4;
|
||||
u8 antdiv_ctl1:4, ob_4:4;
|
||||
u8 db1_3:4, db1_2:4;
|
||||
u8 antdiv_ctl2:4, db1_4:4;
|
||||
u8 db2_2:4, db2_3:4;
|
||||
u8 reserved:4, db2_4:4;
|
||||
#else
|
||||
u8 ob_2:4, ob_3:4;
|
||||
u8 ob_4:4, antdiv_ctl1:4;
|
||||
u8 db1_2:4, db1_3:4;
|
||||
u8 db1_4:4, antdiv_ctl2:4;
|
||||
u8 db2_2:4, db2_3:4;
|
||||
u8 db2_4:4, reserved:4;
|
||||
#endif
|
||||
u8 futureModal[4];
|
||||
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
|
||||
} __packed;
|
||||
|
||||
struct base_eep_ar9287_header {
|
||||
u16 length;
|
||||
u16 checksum;
|
||||
u16 version;
|
||||
u8 opCapFlags;
|
||||
u8 eepMisc;
|
||||
u16 regDmn[2];
|
||||
u8 macAddr[6];
|
||||
u8 rxMask;
|
||||
u8 txMask;
|
||||
u16 rfSilent;
|
||||
u16 blueToothOptions;
|
||||
u16 deviceCap;
|
||||
u32 binBuildNumber;
|
||||
u8 deviceType;
|
||||
u8 openLoopPwrCntl;
|
||||
int8_t pwrTableOffset;
|
||||
int8_t tempSensSlope;
|
||||
int8_t tempSensSlopePalOn;
|
||||
u8 futureBase[29];
|
||||
u16 length;
|
||||
u16 checksum;
|
||||
u16 version;
|
||||
u8 opCapFlags;
|
||||
u8 eepMisc;
|
||||
u16 regDmn[2];
|
||||
u8 macAddr[6];
|
||||
u8 rxMask;
|
||||
u8 txMask;
|
||||
u16 rfSilent;
|
||||
u16 blueToothOptions;
|
||||
u16 deviceCap;
|
||||
u32 binBuildNumber;
|
||||
u8 deviceType;
|
||||
u8 openLoopPwrCntl;
|
||||
int8_t pwrTableOffset;
|
||||
int8_t tempSensSlope;
|
||||
int8_t tempSensSlopePalOn;
|
||||
u8 futureBase[29];
|
||||
} __packed;
|
||||
|
||||
struct modal_eep_ar9287_header {
|
||||
u32 antCtrlChain[AR9287_MAX_CHAINS];
|
||||
u32 antCtrlCommon;
|
||||
int8_t antennaGainCh[AR9287_MAX_CHAINS];
|
||||
u8 switchSettling;
|
||||
u8 txRxAttenCh[AR9287_MAX_CHAINS];
|
||||
u8 rxTxMarginCh[AR9287_MAX_CHAINS];
|
||||
int8_t adcDesiredSize;
|
||||
u8 txEndToXpaOff;
|
||||
u8 txEndToRxOn;
|
||||
u8 txFrameToXpaOn;
|
||||
u8 thresh62;
|
||||
int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS];
|
||||
u8 xpdGain;
|
||||
u8 xpd;
|
||||
int8_t iqCalICh[AR9287_MAX_CHAINS];
|
||||
int8_t iqCalQCh[AR9287_MAX_CHAINS];
|
||||
u8 pdGainOverlap;
|
||||
u8 xpaBiasLvl;
|
||||
u8 txFrameToDataStart;
|
||||
u8 txFrameToPaOn;
|
||||
u8 ht40PowerIncForPdadc;
|
||||
u8 bswAtten[AR9287_MAX_CHAINS];
|
||||
u8 bswMargin[AR9287_MAX_CHAINS];
|
||||
u8 swSettleHt40;
|
||||
u8 version;
|
||||
u8 db1;
|
||||
u8 db2;
|
||||
u8 ob_cck;
|
||||
u8 ob_psk;
|
||||
u8 ob_qam;
|
||||
u8 ob_pal_off;
|
||||
u8 futureModal[30];
|
||||
struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS];
|
||||
u32 antCtrlChain[AR9287_MAX_CHAINS];
|
||||
u32 antCtrlCommon;
|
||||
int8_t antennaGainCh[AR9287_MAX_CHAINS];
|
||||
u8 switchSettling;
|
||||
u8 txRxAttenCh[AR9287_MAX_CHAINS];
|
||||
u8 rxTxMarginCh[AR9287_MAX_CHAINS];
|
||||
int8_t adcDesiredSize;
|
||||
u8 txEndToXpaOff;
|
||||
u8 txEndToRxOn;
|
||||
u8 txFrameToXpaOn;
|
||||
u8 thresh62;
|
||||
int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS];
|
||||
u8 xpdGain;
|
||||
u8 xpd;
|
||||
int8_t iqCalICh[AR9287_MAX_CHAINS];
|
||||
int8_t iqCalQCh[AR9287_MAX_CHAINS];
|
||||
u8 pdGainOverlap;
|
||||
u8 xpaBiasLvl;
|
||||
u8 txFrameToDataStart;
|
||||
u8 txFrameToPaOn;
|
||||
u8 ht40PowerIncForPdadc;
|
||||
u8 bswAtten[AR9287_MAX_CHAINS];
|
||||
u8 bswMargin[AR9287_MAX_CHAINS];
|
||||
u8 swSettleHt40;
|
||||
u8 version;
|
||||
u8 db1;
|
||||
u8 db2;
|
||||
u8 ob_cck;
|
||||
u8 ob_psk;
|
||||
u8 ob_qam;
|
||||
u8 ob_pal_off;
|
||||
u8 futureModal[30];
|
||||
struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS];
|
||||
} __packed;
|
||||
|
||||
|
||||
|
||||
struct cal_data_per_freq {
|
||||
u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
|
||||
u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
|
||||
|
@ -525,7 +543,6 @@ struct cal_data_op_loop_ar9287 {
|
|||
u8 empty[2][5];
|
||||
} __packed;
|
||||
|
||||
|
||||
struct cal_data_per_freq_ar9287 {
|
||||
u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
|
||||
u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
|
||||
|
@ -601,26 +618,25 @@ struct ar5416_eeprom_4k {
|
|||
} __packed;
|
||||
|
||||
struct ar9287_eeprom {
|
||||
struct base_eep_ar9287_header baseEepHeader;
|
||||
struct base_eep_ar9287_header baseEepHeader;
|
||||
u8 custData[AR9287_DATA_SZ];
|
||||
struct modal_eep_ar9287_header modalHeader;
|
||||
u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS];
|
||||
union cal_data_per_freq_ar9287_u
|
||||
calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS];
|
||||
calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS];
|
||||
struct cal_target_power_leg
|
||||
calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS];
|
||||
calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS];
|
||||
struct cal_target_power_leg
|
||||
calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS];
|
||||
calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS];
|
||||
calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS];
|
||||
struct cal_target_power_ht
|
||||
calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS];
|
||||
calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS];
|
||||
u8 ctlIndex[AR9287_NUM_CTLS];
|
||||
struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS];
|
||||
u8 padding;
|
||||
} __packed;
|
||||
|
||||
|
||||
enum reg_ext_bitmap {
|
||||
REG_EXT_JAPAN_MIDBAND = 1,
|
||||
REG_EXT_FCC_DFS_HT40 = 2,
|
||||
|
@ -661,10 +677,39 @@ struct eeprom_ops {
|
|||
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
|
||||
};
|
||||
|
||||
void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
|
||||
u32 shift, u32 val);
|
||||
int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
|
||||
int16_t targetLeft,
|
||||
int16_t targetRight);
|
||||
bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
|
||||
u16 *indexL, u16 *indexR);
|
||||
bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data);
|
||||
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
|
||||
u8 *pVpdList, u16 numIntercepts,
|
||||
u8 *pRetVpdList);
|
||||
void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
struct cal_target_power_leg *powInfo,
|
||||
u16 numChannels,
|
||||
struct cal_target_power_leg *pNewPower,
|
||||
u16 numRates, bool isExtTarget);
|
||||
void ath9k_hw_get_target_powers(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
struct cal_target_power_ht *powInfo,
|
||||
u16 numChannels,
|
||||
struct cal_target_power_ht *pNewPower,
|
||||
u16 numRates, bool isHt40Target);
|
||||
u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
|
||||
bool is2GHz, int num_band_edges);
|
||||
int ath9k_hw_eeprom_init(struct ath_hw *ah);
|
||||
|
||||
#define ar5416_get_ntxchains(_txchainmask) \
|
||||
(((_txchainmask >> 2) & 1) + \
|
||||
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
|
||||
|
||||
int ath9k_hw_eeprom_init(struct ath_hw *ah);
|
||||
extern const struct eeprom_ops eep_def_ops;
|
||||
extern const struct eeprom_ops eep_4k_ops;
|
||||
extern const struct eeprom_ops eep_AR9287_ops;
|
||||
|
||||
#endif /* EEPROM_H */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -407,7 +407,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
|||
ah->config.cck_trig_high = 200;
|
||||
ah->config.cck_trig_low = 100;
|
||||
ah->config.enable_ani = 1;
|
||||
ah->config.diversity_control = 0;
|
||||
ah->config.diversity_control = ATH9K_ANT_VARIABLE;
|
||||
ah->config.antenna_switch_swap = 0;
|
||||
|
||||
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
|
||||
|
@ -452,9 +452,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
|
|||
ah->regulatory.power_limit = MAX_RATE_POWER;
|
||||
ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX;
|
||||
ah->atim_window = 0;
|
||||
ah->diversity_control = ah->config.diversity_control;
|
||||
ah->antenna_switch_swap =
|
||||
ah->config.antenna_switch_swap;
|
||||
ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
|
||||
ah->beacon_interval = 100;
|
||||
ah->enable_32kHz_clock = DONT_USE_32KHZ;
|
||||
|
@ -3891,7 +3888,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
ah->diversity_control = settings;
|
||||
ah->config.diversity_control = settings;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -4019,14 +4016,12 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah)
|
|||
ath9k_ps_restore(ah->ah_sc);
|
||||
}
|
||||
|
||||
bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
|
||||
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
|
||||
{
|
||||
if (setting)
|
||||
ah->misc_mode |= AR_PCU_TX_ADD_TSF;
|
||||
else
|
||||
ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
|
||||
|
|
|
@ -127,6 +127,12 @@ enum wireless_mode {
|
|||
ATH9K_MODE_MAX,
|
||||
};
|
||||
|
||||
enum ath9k_ant_setting {
|
||||
ATH9K_ANT_VARIABLE = 0,
|
||||
ATH9K_ANT_FIXED_A,
|
||||
ATH9K_ANT_FIXED_B
|
||||
};
|
||||
|
||||
enum ath9k_hw_caps {
|
||||
ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
|
||||
ATH9K_HW_CAP_MIC_CKIP = BIT(1),
|
||||
|
@ -191,7 +197,7 @@ struct ath9k_ops_config {
|
|||
u32 cck_trig_high;
|
||||
u32 cck_trig_low;
|
||||
u32 enable_ani;
|
||||
u16 diversity_control;
|
||||
enum ath9k_ant_setting diversity_control;
|
||||
u16 antenna_switch_swap;
|
||||
int serialize_regmode;
|
||||
bool intr_mitigation;
|
||||
|
@ -330,12 +336,6 @@ enum ath9k_power_mode {
|
|||
ATH9K_PM_UNDEFINED
|
||||
};
|
||||
|
||||
enum ath9k_ant_setting {
|
||||
ATH9K_ANT_VARIABLE = 0,
|
||||
ATH9K_ANT_FIXED_A,
|
||||
ATH9K_ANT_FIXED_B
|
||||
};
|
||||
|
||||
enum ath9k_tp_scale {
|
||||
ATH9K_TP_SCALE_MAX = 0,
|
||||
ATH9K_TP_SCALE_50,
|
||||
|
@ -437,8 +437,6 @@ struct ath_hw {
|
|||
u32 txurn_interrupt_mask;
|
||||
bool chip_fullsleep;
|
||||
u32 atim_window;
|
||||
u16 antenna_switch_swap;
|
||||
enum ath9k_ant_setting diversity_control;
|
||||
|
||||
/* Calibration */
|
||||
enum ath9k_cal_types supp_cals;
|
||||
|
@ -507,7 +505,6 @@ struct ath_hw {
|
|||
|
||||
/* ANI */
|
||||
u32 proc_phyerr;
|
||||
bool has_hw_phycounters;
|
||||
u32 aniperiod;
|
||||
struct ar5416AniState *curani;
|
||||
struct ar5416AniState ani[255];
|
||||
|
@ -601,7 +598,7 @@ void ath9k_hw_write_associd(struct ath_softc *sc);
|
|||
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
|
||||
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
|
||||
void ath9k_hw_reset_tsf(struct ath_hw *ah);
|
||||
bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
|
||||
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
|
||||
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
|
||||
void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode);
|
||||
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
|
||||
|
|
|
@ -40,20 +40,15 @@ u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
|
|||
return REG_READ(ah, AR_QTXDP(q));
|
||||
}
|
||||
|
||||
bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
|
||||
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
|
||||
{
|
||||
REG_WRITE(ah, AR_QTXDP(q), txdp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
|
||||
void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
|
||||
{
|
||||
DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q);
|
||||
|
||||
REG_WRITE(ah, AR_Q_TXE, 1 << q);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
|
||||
|
@ -178,7 +173,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
|
|||
#undef ATH9K_TIME_QUANTUM
|
||||
}
|
||||
|
||||
bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 segLen, bool firstSeg,
|
||||
bool lastSeg, const struct ath_desc *ds0)
|
||||
{
|
||||
|
@ -202,8 +197,6 @@ bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
|||
ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
|
||||
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
|
||||
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
|
||||
|
@ -888,7 +881,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 size, u32 flags)
|
||||
{
|
||||
struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
|
@ -901,8 +894,6 @@ bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
|||
ads->ds_rxstatus8 &= ~AR_RxDone;
|
||||
if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
|
||||
memset(&(ads->u), 0, sizeof(ads->u));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
|
||||
|
|
|
@ -628,12 +628,12 @@ struct ath9k_channel;
|
|||
struct ath_rate_table;
|
||||
|
||||
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
|
||||
bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
|
||||
bool ath9k_hw_txstart(struct ath_hw *ah, u32 q);
|
||||
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
|
||||
void ath9k_hw_txstart(struct ath_hw *ah, u32 q);
|
||||
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
|
||||
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
|
||||
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
|
||||
bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 segLen, bool firstSeg,
|
||||
bool lastSeg, const struct ath_desc *ds0);
|
||||
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds);
|
||||
|
@ -668,7 +668,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
|
|||
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
|
||||
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 pa, struct ath_desc *nds, u64 tsf);
|
||||
bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
|
||||
u32 size, u32 flags);
|
||||
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
|
||||
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
|
||||
|
|
|
@ -1327,7 +1327,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc)
|
|||
*/
|
||||
ath_read_cachesize(sc, &csz);
|
||||
/* XXX assert csz is non-zero */
|
||||
sc->cachelsz = csz << 2; /* convert to bytes */
|
||||
sc->common.cachelsz = csz << 2; /* convert to bytes */
|
||||
|
||||
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
|
||||
if (!ah) {
|
||||
|
@ -2140,6 +2140,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
|||
/* disable HAL and put h/w to sleep */
|
||||
ath9k_hw_disable(sc->sc_ah);
|
||||
ath9k_hw_configpcipowersave(sc->sc_ah, 1);
|
||||
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
|
||||
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
|
||||
|
@ -2214,8 +2215,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
|||
if ((conf->type == NL80211_IFTYPE_STATION) ||
|
||||
(conf->type == NL80211_IFTYPE_ADHOC) ||
|
||||
(conf->type == NL80211_IFTYPE_MESH_POINT)) {
|
||||
if (ath9k_hw_phycounters(sc->sc_ah))
|
||||
sc->imask |= ATH9K_INT_MIB;
|
||||
sc->imask |= ATH9K_INT_MIB;
|
||||
sc->imask |= ATH9K_INT_TSFOOR;
|
||||
}
|
||||
|
||||
|
@ -2380,6 +2380,7 @@ skip_chan_change:
|
|||
(FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
FIF_CONTROL | \
|
||||
FIF_PSPOLL | \
|
||||
FIF_OTHER_BSS | \
|
||||
FIF_BCN_PRBRESP_PROMISC | \
|
||||
FIF_FCSFAIL)
|
||||
|
|
|
@ -253,10 +253,12 @@ static int ath_pci_resume(struct pci_dev *pdev)
|
|||
u32 val;
|
||||
int err;
|
||||
|
||||
pci_restore_state(pdev);
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
pci_restore_state(pdev);
|
||||
|
||||
/*
|
||||
* Suspend/Resume resets the PCI configuration space, so we have to
|
||||
* re-disable the RETRY_TIMEOUT register (0x41) to keep
|
||||
|
|
|
@ -353,18 +353,16 @@ ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
u32 bank6SelMask;
|
||||
u32 *bank6Temp = ah->bank6Temp;
|
||||
|
||||
switch (ah->diversity_control) {
|
||||
switch (ah->config.diversity_control) {
|
||||
case ATH9K_ANT_FIXED_A:
|
||||
bank6SelMask =
|
||||
(ah->
|
||||
antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
|
||||
REDUCE_CHAIN_1;
|
||||
(ah->config.antenna_switch_swap & ANTSWAP_AB) ?
|
||||
REDUCE_CHAIN_0 : REDUCE_CHAIN_1;
|
||||
break;
|
||||
case ATH9K_ANT_FIXED_B:
|
||||
bank6SelMask =
|
||||
(ah->
|
||||
antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
|
||||
REDUCE_CHAIN_0;
|
||||
(ah->config.antenna_switch_swap & ANTSWAP_AB) ?
|
||||
REDUCE_CHAIN_1 : REDUCE_CHAIN_0;
|
||||
break;
|
||||
case ATH9K_ANT_VARIABLE:
|
||||
return;
|
||||
|
|
|
@ -312,7 +312,25 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
|
|||
#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12))
|
||||
#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
|
||||
#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
|
||||
#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
|
||||
|
||||
#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
|
||||
#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000
|
||||
#define AR_PHY_9285_ANT_DIV_CTL 0x01000000
|
||||
#define AR_PHY_9285_ANT_DIV_CTL_S 24
|
||||
#define AR_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000
|
||||
#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S 25
|
||||
#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000
|
||||
#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27
|
||||
#define AR_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000
|
||||
#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29
|
||||
#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000
|
||||
#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30
|
||||
#define AR_PHY_9285_ANT_DIV_LNA1 2
|
||||
#define AR_PHY_9285_ANT_DIV_LNA2 1
|
||||
#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3
|
||||
#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
|
||||
#define AR_PHY_9285_ANT_DIV_GAINTB_0 0
|
||||
#define AR_PHY_9285_ANT_DIV_GAINTB_1 1
|
||||
|
||||
#define AR_PHY_EXT_CCA0 0x99b8
|
||||
#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF
|
||||
|
@ -401,6 +419,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
|
|||
#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0
|
||||
#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6
|
||||
#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000
|
||||
#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13
|
||||
|
||||
#define AR_PHY_GAIN_2GHZ 0xA20C
|
||||
#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000
|
||||
|
|
|
@ -100,38 +100,6 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
|
|||
return (tsf & ~0x7fff) | rstamp;
|
||||
}
|
||||
|
||||
static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 off;
|
||||
|
||||
/*
|
||||
* Cache-line-align. This is important (for the
|
||||
* 5210 at least) as not doing so causes bogus data
|
||||
* in rx'd frames.
|
||||
*/
|
||||
|
||||
/* Note: the kernel can allocate a value greater than
|
||||
* what we ask it to give us. We really only need 4 KB as that
|
||||
* is this hardware supports and in fact we need at least 3849
|
||||
* as that is the MAX AMSDU size this hardware supports.
|
||||
* Unfortunately this means we may get 8 KB here from the
|
||||
* kernel... and that is actually what is observed on some
|
||||
* systems :( */
|
||||
skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask);
|
||||
if (skb != NULL) {
|
||||
off = ((unsigned long) skb->data) % sc->cachelsz;
|
||||
if (off != 0)
|
||||
skb_reserve(skb, sc->cachelsz - off);
|
||||
} else {
|
||||
DPRINTF(sc, ATH_DBG_FATAL,
|
||||
"skbuff alloc of size %u failed\n", len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* For Decrypt or Demic errors, we only mark packet status here and always push
|
||||
* up the frame up to let mac80211 handle the actual error case, be it no
|
||||
|
@ -252,6 +220,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
|
|||
else if (ds->ds_rxstat.rs_rssi > 127)
|
||||
ds->ds_rxstat.rs_rssi = 127;
|
||||
|
||||
/* Update Beacon RSSI, this is used by ANI. */
|
||||
if (ieee80211_is_beacon(fc))
|
||||
sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi;
|
||||
|
||||
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
|
||||
rx_status->band = hw->conf.channel->band;
|
||||
rx_status->freq = hw->conf.channel->center_freq;
|
||||
|
@ -332,10 +304,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
|
|||
spin_lock_init(&sc->rx.rxbuflock);
|
||||
|
||||
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
|
||||
min(sc->cachelsz, (u16)64));
|
||||
min(sc->common.cachelsz, (u16)64));
|
||||
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
|
||||
sc->cachelsz, sc->rx.bufsize);
|
||||
sc->common.cachelsz, sc->rx.bufsize);
|
||||
|
||||
/* Initialize rx descriptors */
|
||||
|
||||
|
@ -348,7 +320,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
|
|||
}
|
||||
|
||||
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
|
||||
skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
|
||||
skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL);
|
||||
if (skb == NULL) {
|
||||
error = -ENOMEM;
|
||||
goto err;
|
||||
|
@ -448,8 +420,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
|||
else
|
||||
rfilt |= ATH9K_RX_FILTER_BEACON;
|
||||
|
||||
/* If in HOSTAP mode, want to enable reception of PSPOLL frames */
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP)
|
||||
if (sc->rx.rxfilter & FIF_PSPOLL)
|
||||
rfilt |= ATH9K_RX_FILTER_PSPOLL;
|
||||
|
||||
if (sc->sec_wiphy) {
|
||||
|
@ -774,7 +745,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
|
|||
|
||||
/* Ensure we always have an skb to requeue once we are done
|
||||
* processing the current buffer's skb */
|
||||
requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC);
|
||||
requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC);
|
||||
|
||||
/* If there is no memory we ignore the current RX'd frame,
|
||||
* tell hardware it can give us a new frame using the old
|
||||
|
@ -789,7 +760,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
|
|||
DMA_FROM_DEVICE);
|
||||
|
||||
skb_put(skb, ds->ds_rxstat.rs_datalen);
|
||||
skb->protocol = cpu_to_be16(ETH_P_CONTROL);
|
||||
|
||||
/* see if any padding is done by the hw and remove it */
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
|
|
@ -17,6 +17,42 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "ath.h"
|
||||
|
||||
MODULE_AUTHOR("Atheros Communications");
|
||||
MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards.");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
||||
u32 len,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 off;
|
||||
|
||||
/*
|
||||
* Cache-line-align. This is important (for the
|
||||
* 5210 at least) as not doing so causes bogus data
|
||||
* in rx'd frames.
|
||||
*/
|
||||
|
||||
/* Note: the kernel can allocate a value greater than
|
||||
* what we ask it to give us. We really only need 4 KB as that
|
||||
* is this hardware supports and in fact we need at least 3849
|
||||
* as that is the MAX AMSDU size this hardware supports.
|
||||
* Unfortunately this means we may get 8 KB here from the
|
||||
* kernel... and that is actually what is observed on some
|
||||
* systems :( */
|
||||
skb = __dev_alloc_skb(len + common->cachelsz - 1, gfp_mask);
|
||||
if (skb != NULL) {
|
||||
off = ((unsigned long) skb->data) % common->cachelsz;
|
||||
if (off != 0)
|
||||
skb_reserve(skb, common->cachelsz - off);
|
||||
} else {
|
||||
printk(KERN_ERR "skbuff alloc of size %u failed\n", len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL(ath_rxbuf_alloc);
|
||||
|
|
|
@ -493,6 +493,10 @@ enum {
|
|||
|
||||
/* Max size of a security key */
|
||||
#define B43_SEC_KEYSIZE 16
|
||||
/* Max number of group keys */
|
||||
#define B43_NR_GROUP_KEYS 4
|
||||
/* Max number of pairwise keys */
|
||||
#define B43_NR_PAIRWISE_KEYS 50
|
||||
/* Security algorithms. */
|
||||
enum {
|
||||
B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
|
||||
|
@ -639,7 +643,7 @@ struct b43_wl {
|
|||
u8 mac_addr[ETH_ALEN];
|
||||
/* Current BSSID */
|
||||
u8 bssid[ETH_ALEN];
|
||||
/* Interface type. (IEEE80211_IF_TYPE_XXX) */
|
||||
/* Interface type. (NL80211_IFTYPE_XXX) */
|
||||
int if_type;
|
||||
/* Is the card operating in AP, STA or IBSS mode? */
|
||||
bool operating;
|
||||
|
@ -819,8 +823,7 @@ struct b43_wldev {
|
|||
|
||||
/* encryption/decryption */
|
||||
u16 ktp; /* Key table pointer */
|
||||
u8 max_nr_keys;
|
||||
struct b43_key key[58];
|
||||
struct b43_key key[B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS];
|
||||
|
||||
/* Firmware data */
|
||||
struct b43_firmware fw;
|
||||
|
@ -845,7 +848,7 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
|
|||
return ssb_get_drvdata(ssb_dev);
|
||||
}
|
||||
|
||||
/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
|
||||
/* Is the device operating in a specified mode (NL80211_IFTYPE_XXX). */
|
||||
static inline int b43_is_mode(struct b43_wl *wl, int type)
|
||||
{
|
||||
return (wl->operating && wl->if_type == type);
|
||||
|
|
|
@ -796,18 +796,19 @@ static void key_write(struct b43_wldev *dev,
|
|||
static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
|
||||
{
|
||||
u32 addrtmp[2] = { 0, 0, };
|
||||
u8 per_sta_keys_start = 8;
|
||||
u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
|
||||
|
||||
if (b43_new_kidx_api(dev))
|
||||
per_sta_keys_start = 4;
|
||||
pairwise_keys_start = B43_NR_GROUP_KEYS;
|
||||
|
||||
B43_WARN_ON(index < per_sta_keys_start);
|
||||
/* We have two default TX keys and possibly two default RX keys.
|
||||
B43_WARN_ON(index < pairwise_keys_start);
|
||||
/* We have four default TX keys and possibly four default RX keys.
|
||||
* Physical mac 0 is mapped to physical key 4 or 8, depending
|
||||
* on the firmware version.
|
||||
* So we must adjust the index here.
|
||||
*/
|
||||
index -= per_sta_keys_start;
|
||||
index -= pairwise_keys_start;
|
||||
B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
|
||||
|
||||
if (addr) {
|
||||
addrtmp[0] = addr[0];
|
||||
|
@ -818,27 +819,11 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
|
|||
addrtmp[1] |= ((u32) (addr[5]) << 8);
|
||||
}
|
||||
|
||||
if (dev->dev->id.revision >= 5) {
|
||||
/* Receive match transmitter address mechanism */
|
||||
b43_shm_write32(dev, B43_SHM_RCMTA,
|
||||
(index * 2) + 0, addrtmp[0]);
|
||||
b43_shm_write16(dev, B43_SHM_RCMTA,
|
||||
(index * 2) + 1, addrtmp[1]);
|
||||
} else {
|
||||
/* RXE (Receive Engine) and
|
||||
* PSM (Programmable State Machine) mechanism
|
||||
*/
|
||||
if (index < 8) {
|
||||
/* TODO write to RCM 16, 19, 22 and 25 */
|
||||
} else {
|
||||
b43_shm_write32(dev, B43_SHM_SHARED,
|
||||
B43_SHM_SH_PSM + (index * 6) + 0,
|
||||
addrtmp[0]);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED,
|
||||
B43_SHM_SH_PSM + (index * 6) + 4,
|
||||
addrtmp[1]);
|
||||
}
|
||||
}
|
||||
/* Receive match transmitter address (RCMTA) mechanism */
|
||||
b43_shm_write32(dev, B43_SHM_RCMTA,
|
||||
(index * 2) + 0, addrtmp[0]);
|
||||
b43_shm_write16(dev, B43_SHM_RCMTA,
|
||||
(index * 2) + 1, addrtmp[1]);
|
||||
}
|
||||
|
||||
static void do_key_write(struct b43_wldev *dev,
|
||||
|
@ -846,20 +831,20 @@ static void do_key_write(struct b43_wldev *dev,
|
|||
const u8 *key, size_t key_len, const u8 *mac_addr)
|
||||
{
|
||||
u8 buf[B43_SEC_KEYSIZE] = { 0, };
|
||||
u8 per_sta_keys_start = 8;
|
||||
u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
|
||||
|
||||
if (b43_new_kidx_api(dev))
|
||||
per_sta_keys_start = 4;
|
||||
pairwise_keys_start = B43_NR_GROUP_KEYS;
|
||||
|
||||
B43_WARN_ON(index >= dev->max_nr_keys);
|
||||
B43_WARN_ON(index >= ARRAY_SIZE(dev->key));
|
||||
B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
|
||||
|
||||
if (index >= per_sta_keys_start)
|
||||
if (index >= pairwise_keys_start)
|
||||
keymac_write(dev, index, NULL); /* First zero out mac. */
|
||||
if (key)
|
||||
memcpy(buf, key, key_len);
|
||||
key_write(dev, index, algorithm, buf);
|
||||
if (index >= per_sta_keys_start)
|
||||
if (index >= pairwise_keys_start)
|
||||
keymac_write(dev, index, mac_addr);
|
||||
|
||||
dev->key[index].algorithm = algorithm;
|
||||
|
@ -872,21 +857,24 @@ static int b43_key_write(struct b43_wldev *dev,
|
|||
struct ieee80211_key_conf *keyconf)
|
||||
{
|
||||
int i;
|
||||
int sta_keys_start;
|
||||
int pairwise_keys_start;
|
||||
|
||||
if (key_len > B43_SEC_KEYSIZE)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < dev->max_nr_keys; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
|
||||
/* Check that we don't already have this key. */
|
||||
B43_WARN_ON(dev->key[i].keyconf == keyconf);
|
||||
}
|
||||
if (index < 0) {
|
||||
/* Pairwise key. Get an empty slot for the key. */
|
||||
if (b43_new_kidx_api(dev))
|
||||
sta_keys_start = 4;
|
||||
pairwise_keys_start = B43_NR_GROUP_KEYS;
|
||||
else
|
||||
sta_keys_start = 8;
|
||||
for (i = sta_keys_start; i < dev->max_nr_keys; i++) {
|
||||
pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
|
||||
for (i = pairwise_keys_start;
|
||||
i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS;
|
||||
i++) {
|
||||
B43_WARN_ON(i >= ARRAY_SIZE(dev->key));
|
||||
if (!dev->key[i].keyconf) {
|
||||
/* found empty */
|
||||
index = i;
|
||||
|
@ -914,7 +902,7 @@ static int b43_key_write(struct b43_wldev *dev,
|
|||
|
||||
static int b43_key_clear(struct b43_wldev *dev, int index)
|
||||
{
|
||||
if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys)))
|
||||
if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key))))
|
||||
return -EINVAL;
|
||||
do_key_write(dev, index, B43_SEC_ALGO_NONE,
|
||||
NULL, B43_SEC_KEYSIZE, NULL);
|
||||
|
@ -929,15 +917,19 @@ static int b43_key_clear(struct b43_wldev *dev, int index)
|
|||
|
||||
static void b43_clear_keys(struct b43_wldev *dev)
|
||||
{
|
||||
int i;
|
||||
int i, count;
|
||||
|
||||
for (i = 0; i < dev->max_nr_keys; i++)
|
||||
if (b43_new_kidx_api(dev))
|
||||
count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
|
||||
else
|
||||
count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
|
||||
for (i = 0; i < count; i++)
|
||||
b43_key_clear(dev, i);
|
||||
}
|
||||
|
||||
static void b43_dump_keymemory(struct b43_wldev *dev)
|
||||
{
|
||||
unsigned int i, index, offset;
|
||||
unsigned int i, index, count, offset, pairwise_keys_start;
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 algo;
|
||||
u32 rcmta0;
|
||||
|
@ -951,7 +943,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
|
|||
hf = b43_hf_read(dev);
|
||||
b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
|
||||
!!(hf & B43_HF_USEDEFKEYS));
|
||||
for (index = 0; index < dev->max_nr_keys; index++) {
|
||||
if (b43_new_kidx_api(dev)) {
|
||||
pairwise_keys_start = B43_NR_GROUP_KEYS;
|
||||
count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
|
||||
} else {
|
||||
pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
|
||||
count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
|
||||
}
|
||||
for (index = 0; index < count; index++) {
|
||||
key = &(dev->key[index]);
|
||||
printk(KERN_DEBUG "Key slot %02u: %s",
|
||||
index, (key->keyconf == NULL) ? " " : "*");
|
||||
|
@ -965,11 +964,11 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
|
|||
B43_SHM_SH_KEYIDXBLOCK + (index * 2));
|
||||
printk(" Algo: %04X/%02X", algo, key->algorithm);
|
||||
|
||||
if (index >= 4) {
|
||||
if (index >= pairwise_keys_start) {
|
||||
rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
|
||||
((index - 4) * 2) + 0);
|
||||
((index - pairwise_keys_start) * 2) + 0);
|
||||
rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
|
||||
((index - 4) * 2) + 1);
|
||||
((index - pairwise_keys_start) * 2) + 1);
|
||||
*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
|
||||
*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
|
||||
printk(" MAC: %pM", mac);
|
||||
|
@ -1429,116 +1428,6 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
|
|||
b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
|
||||
}
|
||||
|
||||
static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
|
||||
u16 shm_offset, u16 size,
|
||||
struct ieee80211_rate *rate)
|
||||
{
|
||||
struct b43_plcp_hdr4 plcp;
|
||||
u32 tmp;
|
||||
__le16 dur;
|
||||
|
||||
plcp.data = 0;
|
||||
b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
|
||||
dur = ieee80211_generic_frame_duration(dev->wl->hw,
|
||||
dev->wl->vif, size,
|
||||
rate);
|
||||
/* Write PLCP in two parts and timing for packet transfer */
|
||||
tmp = le32_to_cpu(plcp.data);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur));
|
||||
}
|
||||
|
||||
/* Instead of using custom probe response template, this function
|
||||
* just patches custom beacon template by:
|
||||
* 1) Changing packet type
|
||||
* 2) Patching duration field
|
||||
* 3) Stripping TIM
|
||||
*/
|
||||
static const u8 *b43_generate_probe_resp(struct b43_wldev *dev,
|
||||
u16 *dest_size,
|
||||
struct ieee80211_rate *rate)
|
||||
{
|
||||
const u8 *src_data;
|
||||
u8 *dest_data;
|
||||
u16 src_size, elem_size, src_pos, dest_pos;
|
||||
__le16 dur;
|
||||
struct ieee80211_hdr *hdr;
|
||||
size_t ie_start;
|
||||
|
||||
src_size = dev->wl->current_beacon->len;
|
||||
src_data = (const u8 *)dev->wl->current_beacon->data;
|
||||
|
||||
/* Get the start offset of the variable IEs in the packet. */
|
||||
ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
||||
B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
|
||||
|
||||
if (B43_WARN_ON(src_size < ie_start))
|
||||
return NULL;
|
||||
|
||||
dest_data = kmalloc(src_size, GFP_ATOMIC);
|
||||
if (unlikely(!dest_data))
|
||||
return NULL;
|
||||
|
||||
/* Copy the static data and all Information Elements, except the TIM. */
|
||||
memcpy(dest_data, src_data, ie_start);
|
||||
src_pos = ie_start;
|
||||
dest_pos = ie_start;
|
||||
for ( ; src_pos < src_size - 2; src_pos += elem_size) {
|
||||
elem_size = src_data[src_pos + 1] + 2;
|
||||
if (src_data[src_pos] == 5) {
|
||||
/* This is the TIM. */
|
||||
continue;
|
||||
}
|
||||
memcpy(dest_data + dest_pos, src_data + src_pos,
|
||||
elem_size);
|
||||
dest_pos += elem_size;
|
||||
}
|
||||
*dest_size = dest_pos;
|
||||
hdr = (struct ieee80211_hdr *)dest_data;
|
||||
|
||||
/* Set the frame control. */
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
dur = ieee80211_generic_frame_duration(dev->wl->hw,
|
||||
dev->wl->vif, *dest_size,
|
||||
rate);
|
||||
hdr->duration_id = dur;
|
||||
|
||||
return dest_data;
|
||||
}
|
||||
|
||||
static void b43_write_probe_resp_template(struct b43_wldev *dev,
|
||||
u16 ram_offset,
|
||||
u16 shm_size_offset,
|
||||
struct ieee80211_rate *rate)
|
||||
{
|
||||
const u8 *probe_resp_data;
|
||||
u16 size;
|
||||
|
||||
size = dev->wl->current_beacon->len;
|
||||
probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
|
||||
if (unlikely(!probe_resp_data))
|
||||
return;
|
||||
|
||||
/* Looks like PLCP headers plus packet timings are stored for
|
||||
* all possible basic rates
|
||||
*/
|
||||
/* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */
|
||||
#if 0
|
||||
b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
|
||||
b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
|
||||
b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
|
||||
b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
|
||||
#endif
|
||||
|
||||
size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
|
||||
b43_write_template_common(dev, probe_resp_data,
|
||||
size, ram_offset, shm_size_offset,
|
||||
rate->hw_value);
|
||||
kfree(probe_resp_data);
|
||||
}
|
||||
|
||||
static void b43_upload_beacon0(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
|
@ -1546,10 +1435,6 @@ static void b43_upload_beacon0(struct b43_wldev *dev)
|
|||
if (wl->beacon0_uploaded)
|
||||
return;
|
||||
b43_write_beacon_template(dev, 0x68, 0x18);
|
||||
/* FIXME: Probe resp upload doesn't really belong here,
|
||||
* but we don't use that feature anyway. */
|
||||
b43_write_probe_resp_template(dev, 0x268, 0x4A,
|
||||
&__b43_ratetable[3]);
|
||||
wl->beacon0_uploaded = 1;
|
||||
}
|
||||
|
||||
|
@ -2990,17 +2875,14 @@ error:
|
|||
|
||||
static void b43_security_init(struct b43_wldev *dev)
|
||||
{
|
||||
dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
|
||||
B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
|
||||
dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
|
||||
/* KTP is a word address, but we address SHM bytewise.
|
||||
* So multiply by two.
|
||||
*/
|
||||
dev->ktp *= 2;
|
||||
if (dev->dev->id.revision >= 5) {
|
||||
/* Number of RCMTA address slots */
|
||||
b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8);
|
||||
}
|
||||
/* Number of RCMTA address slots */
|
||||
b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS);
|
||||
/* Clear the key memory. */
|
||||
b43_clear_keys(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,9 +59,126 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
|
|||
dev->phy.lp = NULL;
|
||||
}
|
||||
|
||||
static void lpphy_read_band_sprom(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
u16 cckpo, maxpwr;
|
||||
u32 ofdmpo;
|
||||
int i;
|
||||
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
lpphy->tx_isolation_med_band = bus->sprom.tri2g;
|
||||
lpphy->bx_arch = bus->sprom.bxa2g;
|
||||
lpphy->rx_pwr_offset = bus->sprom.rxpo2g;
|
||||
lpphy->rssi_vf = bus->sprom.rssismf2g;
|
||||
lpphy->rssi_vc = bus->sprom.rssismc2g;
|
||||
lpphy->rssi_gs = bus->sprom.rssisav2g;
|
||||
lpphy->txpa[0] = bus->sprom.pa0b0;
|
||||
lpphy->txpa[1] = bus->sprom.pa0b1;
|
||||
lpphy->txpa[2] = bus->sprom.pa0b2;
|
||||
maxpwr = bus->sprom.maxpwr_bg;
|
||||
lpphy->max_tx_pwr_med_band = maxpwr;
|
||||
cckpo = bus->sprom.cck2gpo;
|
||||
ofdmpo = bus->sprom.ofdm2gpo;
|
||||
if (cckpo) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
lpphy->tx_max_rate[i] =
|
||||
maxpwr - (ofdmpo & 0xF) * 2;
|
||||
ofdmpo >>= 4;
|
||||
}
|
||||
ofdmpo = bus->sprom.ofdm2gpo;
|
||||
for (i = 4; i < 15; i++) {
|
||||
lpphy->tx_max_rate[i] =
|
||||
maxpwr - (ofdmpo & 0xF) * 2;
|
||||
ofdmpo >>= 4;
|
||||
}
|
||||
} else {
|
||||
ofdmpo &= 0xFF;
|
||||
for (i = 0; i < 4; i++)
|
||||
lpphy->tx_max_rate[i] = maxpwr;
|
||||
for (i = 4; i < 15; i++)
|
||||
lpphy->tx_max_rate[i] = maxpwr - ofdmpo;
|
||||
}
|
||||
} else { /* 5GHz */
|
||||
lpphy->tx_isolation_low_band = bus->sprom.tri5gl;
|
||||
lpphy->tx_isolation_med_band = bus->sprom.tri5g;
|
||||
lpphy->tx_isolation_hi_band = bus->sprom.tri5gh;
|
||||
lpphy->bx_arch = bus->sprom.bxa5g;
|
||||
lpphy->rx_pwr_offset = bus->sprom.rxpo5g;
|
||||
lpphy->rssi_vf = bus->sprom.rssismf5g;
|
||||
lpphy->rssi_vc = bus->sprom.rssismc5g;
|
||||
lpphy->rssi_gs = bus->sprom.rssisav5g;
|
||||
lpphy->txpa[0] = bus->sprom.pa1b0;
|
||||
lpphy->txpa[1] = bus->sprom.pa1b1;
|
||||
lpphy->txpa[2] = bus->sprom.pa1b2;
|
||||
lpphy->txpal[0] = bus->sprom.pa1lob0;
|
||||
lpphy->txpal[1] = bus->sprom.pa1lob1;
|
||||
lpphy->txpal[2] = bus->sprom.pa1lob2;
|
||||
lpphy->txpah[0] = bus->sprom.pa1hib0;
|
||||
lpphy->txpah[1] = bus->sprom.pa1hib1;
|
||||
lpphy->txpah[2] = bus->sprom.pa1hib2;
|
||||
maxpwr = bus->sprom.maxpwr_al;
|
||||
ofdmpo = bus->sprom.ofdm5glpo;
|
||||
lpphy->max_tx_pwr_low_band = maxpwr;
|
||||
for (i = 4; i < 12; i++) {
|
||||
lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2;
|
||||
ofdmpo >>= 4;
|
||||
}
|
||||
maxpwr = bus->sprom.maxpwr_a;
|
||||
ofdmpo = bus->sprom.ofdm5gpo;
|
||||
lpphy->max_tx_pwr_med_band = maxpwr;
|
||||
for (i = 4; i < 12; i++) {
|
||||
lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2;
|
||||
ofdmpo >>= 4;
|
||||
}
|
||||
maxpwr = bus->sprom.maxpwr_ah;
|
||||
ofdmpo = bus->sprom.ofdm5ghpo;
|
||||
lpphy->max_tx_pwr_hi_band = maxpwr;
|
||||
for (i = 4; i < 12; i++) {
|
||||
lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2;
|
||||
ofdmpo >>= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lpphy_adjust_gain_table(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
u32 freq = dev->wl->hw->conf.channel->center_freq;
|
||||
u16 temp[3];
|
||||
u16 isolation;
|
||||
|
||||
B43_WARN_ON(dev->phy.rev >= 2);
|
||||
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
|
||||
isolation = lpphy->tx_isolation_med_band;
|
||||
else if (freq <= 5320)
|
||||
isolation = lpphy->tx_isolation_low_band;
|
||||
else if (freq <= 5700)
|
||||
isolation = lpphy->tx_isolation_med_band;
|
||||
else
|
||||
isolation = lpphy->tx_isolation_hi_band;
|
||||
|
||||
temp[0] = ((isolation - 26) / 12) << 12;
|
||||
temp[1] = temp[0] + 0x1000;
|
||||
temp[2] = temp[0] + 0x2000;
|
||||
|
||||
b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
|
||||
b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp);
|
||||
}
|
||||
|
||||
static void lpphy_table_init(struct b43_wldev *dev)
|
||||
{
|
||||
//TODO
|
||||
if (dev->phy.rev < 2)
|
||||
lpphy_rev0_1_table_init(dev);
|
||||
else
|
||||
lpphy_rev2plus_table_init(dev);
|
||||
|
||||
lpphy_init_tx_gain_table(dev);
|
||||
|
||||
if (dev->phy.rev < 2)
|
||||
lpphy_adjust_gain_table(dev);
|
||||
}
|
||||
|
||||
static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
|
||||
|
@ -130,7 +247,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
|
|||
b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
|
||||
b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
|
||||
b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
|
||||
b43_hf_write(dev, b43_hf_read(dev) | 0x0800ULL << 32);
|
||||
b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W);
|
||||
}
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
|
||||
|
@ -161,6 +278,56 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
|
||||
{
|
||||
static const u16 addr[] = {
|
||||
B43_PHY_OFDM(0xC1),
|
||||
B43_PHY_OFDM(0xC2),
|
||||
B43_PHY_OFDM(0xC3),
|
||||
B43_PHY_OFDM(0xC4),
|
||||
B43_PHY_OFDM(0xC5),
|
||||
B43_PHY_OFDM(0xC6),
|
||||
B43_PHY_OFDM(0xC7),
|
||||
B43_PHY_OFDM(0xC8),
|
||||
B43_PHY_OFDM(0xCF),
|
||||
};
|
||||
|
||||
static const u16 coefs[] = {
|
||||
0xDE5E, 0xE832, 0xE331, 0x4D26,
|
||||
0x0026, 0x1420, 0x0020, 0xFE08,
|
||||
0x0008,
|
||||
};
|
||||
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(addr); i++) {
|
||||
lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]);
|
||||
b43_phy_write(dev, addr[i], coefs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
|
||||
{
|
||||
static const u16 addr[] = {
|
||||
B43_PHY_OFDM(0xC1),
|
||||
B43_PHY_OFDM(0xC2),
|
||||
B43_PHY_OFDM(0xC3),
|
||||
B43_PHY_OFDM(0xC4),
|
||||
B43_PHY_OFDM(0xC5),
|
||||
B43_PHY_OFDM(0xC6),
|
||||
B43_PHY_OFDM(0xC7),
|
||||
B43_PHY_OFDM(0xC8),
|
||||
B43_PHY_OFDM(0xCF),
|
||||
};
|
||||
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(addr); i++)
|
||||
b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
|
||||
}
|
||||
|
||||
static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
|
||||
{
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
|
@ -175,7 +342,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
|
|||
b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0);
|
||||
b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0);
|
||||
b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10);
|
||||
b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x78);
|
||||
b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4);
|
||||
b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200);
|
||||
b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F);
|
||||
b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40);
|
||||
|
@ -183,7 +350,12 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
|
|||
b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000);
|
||||
b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000);
|
||||
b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1);
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
|
||||
if (bus->boardinfo.rev >= 0x18) {
|
||||
b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC);
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14);
|
||||
} else {
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
|
||||
}
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4);
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100);
|
||||
b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48);
|
||||
|
@ -213,8 +385,10 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
|
|||
b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
|
||||
b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
|
||||
|
||||
b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
|
||||
b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
|
||||
if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) {
|
||||
b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
|
||||
b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
|
||||
}
|
||||
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40);
|
||||
|
@ -234,6 +408,14 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
|
|||
b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1,
|
||||
0x2000 | ((u16)lpphy->rssi_gs << 10) |
|
||||
((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
|
||||
|
||||
if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
|
||||
b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400);
|
||||
}
|
||||
|
||||
lpphy_save_dig_flt_state(dev);
|
||||
}
|
||||
|
||||
static void lpphy_baseband_init(struct b43_wldev *dev)
|
||||
|
@ -333,12 +515,73 @@ static void lpphy_2062_init(struct b43_wldev *dev)
|
|||
/* Initialize the 2063 radio. */
|
||||
static void lpphy_2063_init(struct b43_wldev *dev)
|
||||
{
|
||||
//TODO
|
||||
b2063_upload_init_table(dev);
|
||||
b43_radio_write(dev, B2063_LOGEN_SP5, 0);
|
||||
b43_radio_set(dev, B2063_COMM8, 0x38);
|
||||
b43_radio_write(dev, B2063_REG_SP1, 0x56);
|
||||
b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2);
|
||||
b43_radio_write(dev, B2063_PA_SP7, 0);
|
||||
b43_radio_write(dev, B2063_TX_RF_SP6, 0x20);
|
||||
b43_radio_write(dev, B2063_TX_RF_SP9, 0x40);
|
||||
b43_radio_write(dev, B2063_PA_SP3, 0xa0);
|
||||
b43_radio_write(dev, B2063_PA_SP4, 0xa0);
|
||||
b43_radio_write(dev, B2063_PA_SP2, 0x18);
|
||||
}
|
||||
|
||||
struct lpphy_stx_table_entry {
|
||||
u16 phy_offset;
|
||||
u16 phy_shift;
|
||||
u16 rf_addr;
|
||||
u16 rf_shift;
|
||||
u16 mask;
|
||||
};
|
||||
|
||||
static const struct lpphy_stx_table_entry lpphy_stx_table[] = {
|
||||
{ .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, },
|
||||
{ .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, },
|
||||
{ .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, },
|
||||
{ .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, },
|
||||
{ .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, },
|
||||
{ .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, },
|
||||
{ .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, },
|
||||
{ .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, },
|
||||
{ .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, },
|
||||
{ .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, },
|
||||
{ .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, },
|
||||
{ .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, },
|
||||
{ .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, },
|
||||
{ .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, },
|
||||
{ .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, },
|
||||
{ .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, },
|
||||
{ .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, },
|
||||
{ .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, },
|
||||
{ .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, },
|
||||
{ .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, },
|
||||
{ .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, },
|
||||
{ .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, },
|
||||
{ .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, },
|
||||
{ .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, },
|
||||
{ .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, },
|
||||
{ .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, },
|
||||
{ .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, },
|
||||
{ .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, },
|
||||
{ .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, },
|
||||
};
|
||||
|
||||
static void lpphy_sync_stx(struct b43_wldev *dev)
|
||||
{
|
||||
//TODO
|
||||
const struct lpphy_stx_table_entry *e;
|
||||
unsigned int i;
|
||||
u16 tmp;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) {
|
||||
e = &lpphy_stx_table[i];
|
||||
tmp = b43_radio_read(dev, e->rf_addr);
|
||||
tmp >>= e->rf_shift;
|
||||
tmp <<= e->phy_shift;
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset),
|
||||
~(e->mask << e->phy_shift), tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpphy_radio_init(struct b43_wldev *dev)
|
||||
|
@ -356,10 +599,345 @@ static void lpphy_radio_init(struct b43_wldev *dev)
|
|||
lpphy_sync_stx(dev);
|
||||
b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
|
||||
b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
|
||||
//TODO Do something on the backplane
|
||||
if (dev->dev->bus->chip_id == 0x4325) {
|
||||
// TODO SSB PMU recalibration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
|
||||
|
||||
static void lpphy_set_rc_cap(struct b43_wldev *dev)
|
||||
{
|
||||
u8 rc_cap = dev->phy.lp->rc_cap;
|
||||
|
||||
b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80));
|
||||
b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80);
|
||||
b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80);
|
||||
}
|
||||
|
||||
static u8 lpphy_get_bb_mult(struct b43_wldev *dev)
|
||||
{
|
||||
return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8;
|
||||
}
|
||||
|
||||
static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
|
||||
{
|
||||
b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
|
||||
}
|
||||
|
||||
static void lpphy_disable_crs(struct b43_wldev *dev)
|
||||
{
|
||||
b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF);
|
||||
b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0);
|
||||
b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1);
|
||||
b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF);
|
||||
b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
|
||||
b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF);
|
||||
b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
|
||||
}
|
||||
|
||||
static void lpphy_restore_crs(struct b43_wldev *dev)
|
||||
{
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
|
||||
b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60);
|
||||
else
|
||||
b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
|
||||
}
|
||||
|
||||
struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
|
||||
|
||||
static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
|
||||
{
|
||||
struct lpphy_tx_gains gains;
|
||||
u16 tmp;
|
||||
|
||||
gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7;
|
||||
if (dev->phy.rev < 2) {
|
||||
tmp = b43_phy_read(dev,
|
||||
B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF;
|
||||
gains.gm = tmp & 0x0007;
|
||||
gains.pga = (tmp & 0x0078) >> 3;
|
||||
gains.pad = (tmp & 0x780) >> 7;
|
||||
} else {
|
||||
tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL);
|
||||
gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF;
|
||||
gains.gm = tmp & 0xFF;
|
||||
gains.pga = (tmp >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
return gains;
|
||||
}
|
||||
|
||||
static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
|
||||
{
|
||||
u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F;
|
||||
ctl |= dac << 7;
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
|
||||
}
|
||||
|
||||
static void lpphy_set_tx_gains(struct b43_wldev *dev,
|
||||
struct lpphy_tx_gains gains)
|
||||
{
|
||||
u16 rf_gain, pa_gain;
|
||||
|
||||
if (dev->phy.rev < 2) {
|
||||
rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm;
|
||||
b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
|
||||
0xF800, rf_gain);
|
||||
} else {
|
||||
pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00;
|
||||
b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
|
||||
(gains.pga << 8) | gains.gm);
|
||||
b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
|
||||
0x8000, gains.pad | pa_gain);
|
||||
b43_phy_write(dev, B43_PHY_OFDM(0xFC),
|
||||
(gains.pga << 8) | gains.gm);
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0xFD),
|
||||
0x8000, gains.pad | pa_gain);
|
||||
}
|
||||
lpphy_set_dac_gain(dev, gains.dac);
|
||||
if (dev->phy.rev < 2) {
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8);
|
||||
} else {
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14);
|
||||
}
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4);
|
||||
}
|
||||
|
||||
static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
|
||||
{
|
||||
u16 trsw = gain & 0x1;
|
||||
u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2);
|
||||
u16 ext_lna = (gain & 2) >> 1;
|
||||
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
|
||||
0xFBFF, ext_lna << 10);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
|
||||
0xF7FF, ext_lna << 11);
|
||||
b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
|
||||
}
|
||||
|
||||
static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
|
||||
{
|
||||
u16 low_gain = gain & 0xFFFF;
|
||||
u16 high_gain = (gain >> 16) & 0xF;
|
||||
u16 ext_lna = (gain >> 21) & 0x1;
|
||||
u16 trsw = ~(gain >> 20) & 0x1;
|
||||
u16 tmp;
|
||||
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
|
||||
0xFDFF, ext_lna << 9);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
|
||||
0xFBFF, ext_lna << 10);
|
||||
b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain);
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
tmp = (gain >> 2) & 0x3;
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
|
||||
0xE7FF, tmp<<11);
|
||||
b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
|
||||
{
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
|
||||
if (dev->phy.rev >= 2) {
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
|
||||
if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ)
|
||||
return;
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7);
|
||||
} else {
|
||||
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
|
||||
{
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
|
||||
if (dev->phy.rev >= 2) {
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
|
||||
if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ)
|
||||
return;
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8);
|
||||
} else {
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
|
||||
{
|
||||
if (dev->phy.rev < 2)
|
||||
lpphy_rev0_1_set_rx_gain(dev, gain);
|
||||
else
|
||||
lpphy_rev2plus_set_rx_gain(dev, gain);
|
||||
lpphy_enable_rx_gain_override(dev);
|
||||
}
|
||||
|
||||
static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx)
|
||||
{
|
||||
u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx));
|
||||
lpphy_set_rx_gain(dev, gain);
|
||||
}
|
||||
|
||||
static void lpphy_stop_ddfs(struct b43_wldev *dev)
|
||||
{
|
||||
b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD);
|
||||
b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF);
|
||||
}
|
||||
|
||||
static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
|
||||
int incr1, int incr2, int scale_idx)
|
||||
{
|
||||
lpphy_stop_ddfs(dev);
|
||||
b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80);
|
||||
b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4);
|
||||
b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
|
||||
b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
|
||||
b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
|
||||
b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20);
|
||||
}
|
||||
|
||||
static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
|
||||
struct lpphy_iq_est *iq_est)
|
||||
{
|
||||
int i;
|
||||
|
||||
b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7);
|
||||
b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
|
||||
b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
|
||||
b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
|
||||
b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF);
|
||||
|
||||
for (i = 0; i < 500; i++) {
|
||||
if (!(b43_phy_read(dev,
|
||||
B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
|
||||
b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
|
||||
return false;
|
||||
}
|
||||
|
||||
iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR);
|
||||
iq_est->iq_prod <<= 16;
|
||||
iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR);
|
||||
|
||||
iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR);
|
||||
iq_est->i_pwr <<= 16;
|
||||
iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR);
|
||||
|
||||
iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR);
|
||||
iq_est->q_pwr <<= 16;
|
||||
iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR);
|
||||
|
||||
b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lpphy_loopback(struct b43_wldev *dev)
|
||||
{
|
||||
struct lpphy_iq_est iq_est;
|
||||
int i, index = -1;
|
||||
u32 tmp;
|
||||
|
||||
memset(&iq_est, 0, sizeof(iq_est));
|
||||
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
|
||||
b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8);
|
||||
b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80);
|
||||
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80);
|
||||
for (i = 0; i < 32; i++) {
|
||||
lpphy_set_rx_gain_by_index(dev, i);
|
||||
lpphy_run_ddfs(dev, 1, 1, 5, 5, 0);
|
||||
if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
|
||||
continue;
|
||||
tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000;
|
||||
if ((tmp > 4000) && (tmp < 10000)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lpphy_stop_ddfs(dev);
|
||||
return index;
|
||||
}
|
||||
|
||||
static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
|
||||
{
|
||||
u32 quotient, remainder, rbit, roundup, tmp;
|
||||
|
||||
if (divisor == 0) {
|
||||
quotient = 0;
|
||||
remainder = 0;
|
||||
} else {
|
||||
quotient = dividend / divisor;
|
||||
remainder = dividend % divisor;
|
||||
}
|
||||
|
||||
rbit = divisor & 0x1;
|
||||
roundup = (divisor >> 1) + rbit;
|
||||
precision--;
|
||||
|
||||
while (precision != 0xFF) {
|
||||
tmp = remainder - roundup;
|
||||
quotient <<= 1;
|
||||
remainder <<= 1;
|
||||
if (remainder >= roundup) {
|
||||
remainder = (tmp << 1) + rbit;
|
||||
quotient--;
|
||||
}
|
||||
precision--;
|
||||
}
|
||||
|
||||
if (remainder >= roundup)
|
||||
quotient++;
|
||||
|
||||
return quotient;
|
||||
}
|
||||
|
||||
/* Read the TX power control mode from hardware. */
|
||||
static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
|
||||
{
|
||||
|
@ -444,6 +1022,170 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
|
|||
lpphy_write_tx_pctl_mode_to_hardware(dev);
|
||||
}
|
||||
|
||||
static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
struct lpphy_iq_est iq_est;
|
||||
struct lpphy_tx_gains tx_gains;
|
||||
static const u32 ideal_pwr_table[22] = {
|
||||
0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
|
||||
0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
|
||||
0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
|
||||
0x0004c, 0x0002c, 0x0001a, 0xc0006,
|
||||
};
|
||||
bool old_txg_ovr;
|
||||
u8 old_bbmult;
|
||||
u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
|
||||
old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl;
|
||||
u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
|
||||
int loopback, i, j, inner_sum;
|
||||
|
||||
memset(&iq_est, 0, sizeof(iq_est));
|
||||
|
||||
b43_switch_channel(dev, 7);
|
||||
old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1;
|
||||
old_bbmult = lpphy_get_bb_mult(dev);
|
||||
if (old_txg_ovr)
|
||||
tx_gains = lpphy_get_tx_gains(dev);
|
||||
old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0);
|
||||
old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0);
|
||||
old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR);
|
||||
old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL);
|
||||
old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
|
||||
old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
|
||||
old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
|
||||
old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) &
|
||||
B43_LPPHY_TX_PWR_CTL_CMD_MODE;
|
||||
|
||||
lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
|
||||
lpphy_disable_crs(dev);
|
||||
loopback = lpphy_loopback(dev);
|
||||
if (loopback == -1)
|
||||
goto finish;
|
||||
lpphy_set_rx_gain_by_index(dev, loopback);
|
||||
b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8);
|
||||
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0);
|
||||
for (i = 128; i <= 159; i++) {
|
||||
b43_radio_write(dev, B2062_N_RXBB_CALIB2, i);
|
||||
inner_sum = 0;
|
||||
for (j = 5; j <= 25; j++) {
|
||||
lpphy_run_ddfs(dev, 1, 1, j, j, 0);
|
||||
if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
|
||||
goto finish;
|
||||
mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr;
|
||||
if (j == 5)
|
||||
tmp = mean_sq_pwr;
|
||||
ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1;
|
||||
normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12);
|
||||
mean_sq_pwr = ideal_pwr - normal_pwr;
|
||||
mean_sq_pwr *= mean_sq_pwr;
|
||||
inner_sum += mean_sq_pwr;
|
||||
if ((i = 128) || (inner_sum < mean_sq_pwr_min)) {
|
||||
lpphy->rc_cap = i;
|
||||
mean_sq_pwr_min = inner_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
lpphy_stop_ddfs(dev);
|
||||
|
||||
finish:
|
||||
lpphy_restore_crs(dev);
|
||||
b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
|
||||
b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
|
||||
b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
|
||||
b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr);
|
||||
b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval);
|
||||
b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr);
|
||||
b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl);
|
||||
|
||||
lpphy_set_bb_mult(dev, old_bbmult);
|
||||
if (old_txg_ovr) {
|
||||
/*
|
||||
* SPEC FIXME: The specs say "get_tx_gains" here, which is
|
||||
* illogical. According to lwfinger, vendor driver v4.150.10.5
|
||||
* has a Set here, while v4.174.64.19 has a Get - regression in
|
||||
* the vendor driver? This should be tested this once the code
|
||||
* is testable.
|
||||
*/
|
||||
lpphy_set_tx_gains(dev, tx_gains);
|
||||
}
|
||||
lpphy_set_tx_power_control(dev, old_txpctl);
|
||||
if (lpphy->rc_cap)
|
||||
lpphy_set_rc_cap(dev);
|
||||
}
|
||||
|
||||
static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
|
||||
{
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
|
||||
u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
|
||||
int i;
|
||||
|
||||
b43_radio_write(dev, B2063_RX_BB_SP8, 0x0);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
|
||||
b43_radio_mask(dev, B2063_PLL_SP1, 0xF7);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D);
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
|
||||
b43_radio_write(dev, B2063_RX_BB_SP8, tmp);
|
||||
|
||||
tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF;
|
||||
|
||||
b43_radio_write(dev, B2063_TX_BB_SP3, 0x0);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76);
|
||||
|
||||
if (crystal_freq == 24000000) {
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0);
|
||||
} else {
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13);
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
|
||||
}
|
||||
|
||||
b43_radio_write(dev, B2063_PA_SP7, 0x7D);
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
|
||||
b43_radio_write(dev, B2063_TX_BB_SP3, tmp);
|
||||
|
||||
b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
|
||||
}
|
||||
|
||||
static void lpphy_calibrate_rc(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
|
||||
if (dev->phy.rev >= 2) {
|
||||
lpphy_rev2plus_rc_calib(dev);
|
||||
} else if (!lpphy->rc_cap) {
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
|
||||
lpphy_rev0_1_rc_calib(dev);
|
||||
} else {
|
||||
lpphy_set_rc_cap(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
|
@ -532,13 +1274,14 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev)
|
|||
|
||||
static int b43_lpphy_op_init(struct b43_wldev *dev)
|
||||
{
|
||||
/* TODO: band SPROM */
|
||||
lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
|
||||
lpphy_baseband_init(dev);
|
||||
lpphy_radio_init(dev);
|
||||
//TODO calibrate RC
|
||||
lpphy_calibrate_rc(dev);
|
||||
//TODO set channel
|
||||
lpphy_tx_pctl_init(dev);
|
||||
//TODO full calib
|
||||
lpphy_calibration(dev);
|
||||
//TODO ACI init
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -616,7 +1359,6 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
|
|||
return B43_TXPWR_RES_DONE;
|
||||
}
|
||||
|
||||
|
||||
const struct b43_phy_operations b43_phyops_lp = {
|
||||
.allocate = b43_lpphy_op_allocate,
|
||||
.free = b43_lpphy_op_free,
|
||||
|
|
|
@ -831,6 +831,22 @@ struct b43_phy_lp {
|
|||
/* Transmit isolation high band */
|
||||
u8 tx_isolation_hi_band; /* FIXME initial value? */
|
||||
|
||||
/* Max transmit power medium band */
|
||||
u16 max_tx_pwr_med_band;
|
||||
/* Max transmit power low band */
|
||||
u16 max_tx_pwr_low_band;
|
||||
/* Max transmit power high band */
|
||||
u16 max_tx_pwr_hi_band;
|
||||
|
||||
/* FIXME What are these used for? */
|
||||
/* FIXME Is 15 the correct array size? */
|
||||
u16 tx_max_rate[15];
|
||||
u16 tx_max_ratel[15];
|
||||
u16 tx_max_rateh[15];
|
||||
|
||||
/* Transmit power arrays */
|
||||
s16 txpa[3], txpal[3], txpah[3];
|
||||
|
||||
/* Receive power offset */
|
||||
u8 rx_pwr_offset; /* FIXME initial value? */
|
||||
|
||||
|
@ -865,6 +881,9 @@ struct b43_phy_lp {
|
|||
/* Transmit iqlocal best coeffs */
|
||||
bool tx_iqloc_best_coeffs_valid;
|
||||
u8 tx_iqloc_best_coeffs[11];
|
||||
|
||||
/* Used for "Save/Restore Dig Filt State" */
|
||||
u16 dig_flt_state[9];
|
||||
};
|
||||
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -26,6 +26,19 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset,
|
|||
unsigned int nr_elements, const void *data);
|
||||
|
||||
void b2062_upload_init_table(struct b43_wldev *dev);
|
||||
void b2063_upload_init_table(struct b43_wldev *dev);
|
||||
|
||||
struct lpphy_tx_gain_table_entry {
|
||||
u8 gm, pga, pad, dac, bb_mult;
|
||||
};
|
||||
|
||||
void lpphy_write_gain_table(struct b43_wldev *dev, int offset,
|
||||
struct lpphy_tx_gain_table_entry data);
|
||||
void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count,
|
||||
struct lpphy_tx_gain_table_entry *table);
|
||||
|
||||
void lpphy_rev0_1_table_init(struct b43_wldev *dev);
|
||||
void lpphy_rev2plus_table_init(struct b43_wldev *dev);
|
||||
void lpphy_init_tx_gain_table(struct b43_wldev *dev);
|
||||
|
||||
#endif /* B43_TABLES_LPPHY_H_ */
|
||||
|
|
|
@ -237,7 +237,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
int wlhdr_len;
|
||||
size_t iv_len;
|
||||
|
||||
B43_WARN_ON(key_idx >= dev->max_nr_keys);
|
||||
B43_WARN_ON(key_idx >= ARRAY_SIZE(dev->key));
|
||||
key = &(dev->key[key_idx]);
|
||||
|
||||
if (unlikely(!key->keyconf)) {
|
||||
|
@ -578,7 +578,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
* key index, but the ucode passed it slightly different.
|
||||
*/
|
||||
keyidx = b43_kidx_to_raw(dev, keyidx);
|
||||
B43_WARN_ON(keyidx >= dev->max_nr_keys);
|
||||
B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key));
|
||||
|
||||
if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
|
||||
wlhdr_len = ieee80211_hdrlen(fctl);
|
||||
|
|
|
@ -117,8 +117,8 @@ static struct iwl_lib_ops iwl1000_lib = {
|
|||
EEPROM_5000_REG_BAND_3_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_4_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_5_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_FAT_CHANNELS
|
||||
EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
|
||||
|
|
|
@ -176,7 +176,7 @@ struct iwl3945_eeprom {
|
|||
* in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
|
||||
* txpower (MSB).
|
||||
*
|
||||
* Entries immediately below are for 20 MHz channel width. FAT (40 MHz)
|
||||
* Entries immediately below are for 20 MHz channel width. HT40 (40 MHz)
|
||||
* channels (only for 4965, not supported by 3945) appear later in the EEPROM.
|
||||
*
|
||||
* 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
|
|
|
@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
|
|||
}
|
||||
}
|
||||
if (print_dump)
|
||||
iwl_print_hex_dump(IWL_DL_RX, data, length);
|
||||
iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
|
||||
}
|
||||
|
||||
static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt,
|
||||
struct ieee80211_hdr *header, int group100)
|
||||
{
|
||||
if (iwl_debug_level & IWL_DL_RX)
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_RX)
|
||||
_iwl3945_dbg_report_frame(priv, pkt, header, group100);
|
||||
}
|
||||
|
||||
|
@ -544,9 +544,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
|
|||
struct ieee80211_rx_status *stats)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
|
||||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
|
||||
#endif
|
||||
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
|
||||
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
|
||||
short len = le16_to_cpu(rx_hdr->len);
|
||||
|
@ -577,6 +575,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
|
|||
if (ieee80211_is_data(hdr->frame_control))
|
||||
priv->rxtxpackets += len;
|
||||
#endif
|
||||
iwl_update_stats(priv, false, hdr->frame_control, len);
|
||||
|
||||
memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
|
||||
ieee80211_rx_irqsafe(priv->hw, rxb->skb);
|
||||
rxb->skb = NULL;
|
||||
|
@ -679,6 +679,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
|
|||
|
||||
/* Set "1" to report good data frames in groups of 100 */
|
||||
iwl3945_dbg_report_frame(priv, pkt, header, 1);
|
||||
iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
|
||||
|
||||
if (network_packet) {
|
||||
priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
|
||||
|
@ -2851,8 +2852,8 @@ static struct iwl_lib_ops iwl3945_lib = {
|
|||
EEPROM_REGULATORY_BAND_3_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_4_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_5_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_FAT,
|
||||
EEPROM_REGULATORY_BAND_NO_FAT,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwl3945_eeprom_acquire_semaphore,
|
||||
|
|
|
@ -188,7 +188,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
|
|||
*
|
||||
* 1) Regulatory information (max txpower and channel usage flags) is provided
|
||||
* separately for each channel that can possibly supported by 4965.
|
||||
* 40 MHz wide (.11n fat) channels are listed separately from 20 MHz
|
||||
* 40 MHz wide (.11n HT40) channels are listed separately from 20 MHz
|
||||
* (legacy) channels.
|
||||
*
|
||||
* See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom
|
||||
|
@ -251,8 +251,8 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
|
|||
* no reduction (such as with regulatory txpower limits) is required.
|
||||
*
|
||||
* Saturation and Backoff values apply equally to 20 Mhz (legacy) channel
|
||||
* widths and 40 Mhz (.11n fat) channel widths; there is no separate
|
||||
* factory measurement for fat channels.
|
||||
* widths and 40 Mhz (.11n HT40) channel widths; there is no separate
|
||||
* factory measurement for ht40 channels.
|
||||
*
|
||||
* The result of this step is the final target txpower. The rest of
|
||||
* the steps figure out the proper settings for the device to achieve
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "iwl-sta.h"
|
||||
|
||||
static int iwl4965_send_tx_power(struct iwl_priv *priv);
|
||||
static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
|
||||
static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL4965_UCODE_API_MAX 2
|
||||
|
@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
|
|||
|
||||
IWL_DEBUG_INFO(priv, "Begin load bsm\n");
|
||||
|
||||
priv->ucode_type = UCODE_INIT;
|
||||
priv->ucode_type = UCODE_RT;
|
||||
|
||||
/* make sure bootstrap program is no larger than BSM's SRAM size */
|
||||
if (len > IWL49_MAX_BSM_SIZE)
|
||||
|
@ -256,8 +256,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
|
|||
*/
|
||||
static void iwl4965_init_alive_start(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check alive response for "valid" sign from uCode */
|
||||
if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
|
||||
/* We had an error bringing up the hardware, so take it
|
||||
|
@ -289,35 +287,13 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
|
|||
IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n");
|
||||
goto restart;
|
||||
}
|
||||
priv->ucode_type = UCODE_RT;
|
||||
if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
|
||||
IWL_WARN(priv, "Runtime uCode already alive? "
|
||||
"Waiting for alive anyway\n");
|
||||
clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
|
||||
}
|
||||
ret = wait_event_interruptible_timeout(
|
||||
priv->wait_command_queue,
|
||||
test_bit(STATUS_RT_UCODE_ALIVE, &priv->status),
|
||||
UCODE_ALIVE_TIMEOUT);
|
||||
if (!ret) {
|
||||
/* FIXME: if STATUS_RT_UCODE_ALIVE timeout
|
||||
* go back to restart the download Init uCode again
|
||||
* this might cause to trap in the restart loop
|
||||
*/
|
||||
priv->ucode_type = UCODE_NONE;
|
||||
if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
|
||||
IWL_ERR(priv, "Runtime timeout after %dms\n",
|
||||
jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
restart:
|
||||
queue_work(priv->workqueue, &priv->restart);
|
||||
}
|
||||
|
||||
static bool is_fat_channel(__le32 rxon_flags)
|
||||
static bool is_ht40_channel(__le32 rxon_flags)
|
||||
{
|
||||
int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK)
|
||||
>> RXON_FLG_CHANNEL_MODE_POS;
|
||||
|
@ -806,7 +782,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
|
|||
priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
|
||||
priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE;
|
||||
priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
|
||||
priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ);
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
|
||||
|
||||
|
@ -1266,7 +1242,7 @@ static const struct gain_entry gain_table[2][108] = {
|
|||
};
|
||||
|
||||
static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
|
||||
u8 is_fat, u8 ctrl_chan_high,
|
||||
u8 is_ht40, u8 ctrl_chan_high,
|
||||
struct iwl4965_tx_power_db *tx_power_tbl)
|
||||
{
|
||||
u8 saturation_power;
|
||||
|
@ -1298,8 +1274,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
|
|||
user_target_power = 2 * priv->tx_power_user_lmt;
|
||||
|
||||
/* Get current (RXON) channel, band, width */
|
||||
IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_fat %d\n", channel, band,
|
||||
is_fat);
|
||||
IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_ht40 %d\n", channel, band,
|
||||
is_ht40);
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, channel);
|
||||
|
||||
|
@ -1318,7 +1294,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
|
|||
IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n",
|
||||
channel, txatten_grp);
|
||||
|
||||
if (is_fat) {
|
||||
if (is_ht40) {
|
||||
if (ctrl_chan_high)
|
||||
channel -= 2;
|
||||
else
|
||||
|
@ -1342,8 +1318,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
|
|||
|
||||
/* regulatory txpower limits ... reg_limit values are in half-dBm,
|
||||
* max_power_avg values are in dBm, convert * 2 */
|
||||
if (is_fat)
|
||||
reg_limit = ch_info->fat_max_power_avg * 2;
|
||||
if (is_ht40)
|
||||
reg_limit = ch_info->ht40_max_power_avg * 2;
|
||||
else
|
||||
reg_limit = ch_info->max_power_avg * 2;
|
||||
|
||||
|
@ -1509,7 +1485,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
|
|||
/**
|
||||
* iwl4965_send_tx_power - Configure the TXPOWER level user limit
|
||||
*
|
||||
* Uses the active RXON for channel, band, and characteristics (fat, high)
|
||||
* Uses the active RXON for channel, band, and characteristics (ht40, high)
|
||||
* The power limit is taken from priv->tx_power_user_lmt.
|
||||
*/
|
||||
static int iwl4965_send_tx_power(struct iwl_priv *priv)
|
||||
|
@ -1517,7 +1493,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
|
|||
struct iwl4965_txpowertable_cmd cmd = { 0 };
|
||||
int ret;
|
||||
u8 band = 0;
|
||||
bool is_fat = false;
|
||||
bool is_ht40 = false;
|
||||
u8 ctrl_chan_high = 0;
|
||||
|
||||
if (test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
|
@ -1530,9 +1506,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
|
|||
|
||||
band = priv->band == IEEE80211_BAND_2GHZ;
|
||||
|
||||
is_fat = is_fat_channel(priv->active_rxon.flags);
|
||||
is_ht40 = is_ht40_channel(priv->active_rxon.flags);
|
||||
|
||||
if (is_fat &&
|
||||
if (is_ht40 &&
|
||||
(priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
|
||||
ctrl_chan_high = 1;
|
||||
|
||||
|
@ -1541,7 +1517,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
|
|||
|
||||
ret = iwl4965_fill_txpower_tbl(priv, band,
|
||||
le16_to_cpu(priv->active_rxon.channel),
|
||||
is_fat, ctrl_chan_high, &cmd.tx_power);
|
||||
is_ht40, ctrl_chan_high, &cmd.tx_power);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -1595,7 +1571,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
|
|||
{
|
||||
int rc;
|
||||
u8 band = 0;
|
||||
bool is_fat = false;
|
||||
bool is_ht40 = false;
|
||||
u8 ctrl_chan_high = 0;
|
||||
struct iwl4965_channel_switch_cmd cmd = { 0 };
|
||||
const struct iwl_channel_info *ch_info;
|
||||
|
@ -1604,9 +1580,9 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
|
|||
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, channel);
|
||||
|
||||
is_fat = is_fat_channel(priv->staging_rxon.flags);
|
||||
is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
|
||||
|
||||
if (is_fat &&
|
||||
if (is_ht40 &&
|
||||
(priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
|
||||
ctrl_chan_high = 1;
|
||||
|
||||
|
@ -1621,7 +1597,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
|
|||
else
|
||||
cmd.expect_beacon = 1;
|
||||
|
||||
rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat,
|
||||
rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
|
||||
ctrl_chan_high, &cmd.tx_power);
|
||||
if (rc) {
|
||||
IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc);
|
||||
|
@ -1680,7 +1656,7 @@ static s32 sign_extend(u32 oper, int index)
|
|||
*
|
||||
* A return of <0 indicates bogus data in the statistics
|
||||
*/
|
||||
static int iwl4965_hw_get_temperature(const struct iwl_priv *priv)
|
||||
static int iwl4965_hw_get_temperature(struct iwl_priv *priv)
|
||||
{
|
||||
s32 temperature;
|
||||
s32 vt;
|
||||
|
@ -1688,8 +1664,8 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv)
|
|||
u32 R4;
|
||||
|
||||
if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
|
||||
(priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) {
|
||||
IWL_DEBUG_TEMP(priv, "Running FAT temperature calibration\n");
|
||||
(priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
|
||||
IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n");
|
||||
R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
|
||||
R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
|
||||
R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
|
||||
|
@ -2330,8 +2306,8 @@ static struct iwl_lib_ops iwl4965_lib = {
|
|||
EEPROM_REGULATORY_BAND_3_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_4_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_5_CHANNELS,
|
||||
EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS,
|
||||
EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS
|
||||
EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
|
||||
|
|
|
@ -845,7 +845,7 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
|
|||
}
|
||||
|
||||
priv->hw_params.max_bsm_size = 0;
|
||||
priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
|
||||
|
||||
|
@ -1547,8 +1547,8 @@ struct iwl_lib_ops iwl5000_lib = {
|
|||
EEPROM_5000_REG_BAND_3_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_4_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_5_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_FAT_CHANNELS
|
||||
EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
|
||||
|
@ -1597,8 +1597,8 @@ static struct iwl_lib_ops iwl5150_lib = {
|
|||
EEPROM_5000_REG_BAND_3_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_4_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_5_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_FAT_CHANNELS
|
||||
EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
|
||||
|
|
|
@ -118,8 +118,8 @@ static struct iwl_lib_ops iwl6000_lib = {
|
|||
EEPROM_5000_REG_BAND_3_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_4_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_5_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_FAT_CHANNELS
|
||||
EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_5000_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
|
||||
|
|
|
@ -97,7 +97,7 @@ struct iwl_scale_tbl_info {
|
|||
enum iwl_table_type lq_type;
|
||||
u8 ant_type;
|
||||
u8 is_SGI; /* 1 = short guard interval */
|
||||
u8 is_fat; /* 1 = 40 MHz channel width */
|
||||
u8 is_ht40; /* 1 = 40 MHz channel width */
|
||||
u8 is_dup; /* 1 = duplicated data streams */
|
||||
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
|
||||
u8 max_search; /* maximun number of tables we can search */
|
||||
|
@ -539,11 +539,11 @@ static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
|
|||
RATE_MCS_ANT_ABC_MSK);
|
||||
|
||||
if (is_Ht(tbl->lq_type)) {
|
||||
if (tbl->is_fat) {
|
||||
if (tbl->is_ht40) {
|
||||
if (tbl->is_dup)
|
||||
rate_n_flags |= RATE_MCS_DUP_MSK;
|
||||
else
|
||||
rate_n_flags |= RATE_MCS_FAT_MSK;
|
||||
rate_n_flags |= RATE_MCS_HT40_MSK;
|
||||
}
|
||||
if (tbl->is_SGI)
|
||||
rate_n_flags |= RATE_MCS_SGI_MSK;
|
||||
|
@ -579,7 +579,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
|
|||
return -EINVAL;
|
||||
}
|
||||
tbl->is_SGI = 0; /* default legacy setup */
|
||||
tbl->is_fat = 0;
|
||||
tbl->is_ht40 = 0;
|
||||
tbl->is_dup = 0;
|
||||
tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
|
||||
tbl->lq_type = LQ_NONE;
|
||||
|
@ -598,9 +598,9 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
|
|||
if (rate_n_flags & RATE_MCS_SGI_MSK)
|
||||
tbl->is_SGI = 1;
|
||||
|
||||
if ((rate_n_flags & RATE_MCS_FAT_MSK) ||
|
||||
if ((rate_n_flags & RATE_MCS_HT40_MSK) ||
|
||||
(rate_n_flags & RATE_MCS_DUP_MSK))
|
||||
tbl->is_fat = 1;
|
||||
tbl->is_ht40 = 1;
|
||||
|
||||
if (rate_n_flags & RATE_MCS_DUP_MSK)
|
||||
tbl->is_dup = 1;
|
||||
|
@ -776,7 +776,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
|
|||
if (num_of_ant(tbl->ant_type) > 1)
|
||||
tbl->ant_type = ANT_A;/*FIXME:RS*/
|
||||
|
||||
tbl->is_fat = 0;
|
||||
tbl->is_ht40 = 0;
|
||||
tbl->is_SGI = 0;
|
||||
tbl->max_search = IWL_MAX_SEARCH;
|
||||
}
|
||||
|
@ -880,7 +880,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
|||
|
||||
if ((info->status.rates[0].idx < 0) ||
|
||||
(tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
|
||||
(tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
|
||||
(tbl_type.is_ht40 != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
|
||||
(tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
|
||||
(tbl_type.ant_type != info->antenna_sel_tx) ||
|
||||
(!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
|
||||
|
@ -1049,7 +1049,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
else
|
||||
tbl->expected_tpt = expected_tpt_A;
|
||||
} else if (is_siso(tbl->lq_type)) {
|
||||
if (tbl->is_fat && !lq_sta->is_dup)
|
||||
if (tbl->is_ht40 && !lq_sta->is_dup)
|
||||
if (tbl->is_SGI)
|
||||
tbl->expected_tpt = expected_tpt_siso40MHzSGI;
|
||||
else
|
||||
|
@ -1059,7 +1059,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
else
|
||||
tbl->expected_tpt = expected_tpt_siso20MHz;
|
||||
} else if (is_mimo2(tbl->lq_type)) {
|
||||
if (tbl->is_fat && !lq_sta->is_dup)
|
||||
if (tbl->is_ht40 && !lq_sta->is_dup)
|
||||
if (tbl->is_SGI)
|
||||
tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI;
|
||||
else
|
||||
|
@ -1069,7 +1069,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
else
|
||||
tbl->expected_tpt = expected_tpt_mimo2_20MHz;
|
||||
} else if (is_mimo3(tbl->lq_type)) {
|
||||
if (tbl->is_fat && !lq_sta->is_dup)
|
||||
if (tbl->is_ht40 && !lq_sta->is_dup)
|
||||
if (tbl->is_SGI)
|
||||
tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI;
|
||||
else
|
||||
|
@ -1217,13 +1217,13 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
|
|||
tbl->max_search = IWL_MAX_SEARCH;
|
||||
rate_mask = lq_sta->active_mimo2_rate;
|
||||
|
||||
if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
|
||||
tbl->is_fat = 1;
|
||||
if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
|
||||
tbl->is_ht40 = 1;
|
||||
else
|
||||
tbl->is_fat = 0;
|
||||
tbl->is_ht40 = 0;
|
||||
|
||||
/* FIXME: - don't toggle SGI here
|
||||
if (tbl->is_fat) {
|
||||
if (tbl->is_ht40) {
|
||||
if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
|
||||
tbl->is_SGI = 1;
|
||||
else
|
||||
|
@ -1283,13 +1283,13 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
|
|||
tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
|
||||
rate_mask = lq_sta->active_mimo3_rate;
|
||||
|
||||
if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
|
||||
tbl->is_fat = 1;
|
||||
if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
|
||||
tbl->is_ht40 = 1;
|
||||
else
|
||||
tbl->is_fat = 0;
|
||||
tbl->is_ht40 = 0;
|
||||
|
||||
/* FIXME: - don't toggle SGI here
|
||||
if (tbl->is_fat) {
|
||||
if (tbl->is_ht40) {
|
||||
if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
|
||||
tbl->is_SGI = 1;
|
||||
else
|
||||
|
@ -1342,13 +1342,13 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
|
|||
tbl->max_search = IWL_MAX_SEARCH;
|
||||
rate_mask = lq_sta->active_siso_rate;
|
||||
|
||||
if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
|
||||
tbl->is_fat = 1;
|
||||
if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
|
||||
tbl->is_ht40 = 1;
|
||||
else
|
||||
tbl->is_fat = 0;
|
||||
tbl->is_ht40 = 0;
|
||||
|
||||
/* FIXME: - don't toggle SGI here
|
||||
if (tbl->is_fat) {
|
||||
if (tbl->is_ht40) {
|
||||
if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
|
||||
tbl->is_SGI = 1;
|
||||
else
|
||||
|
@ -1401,7 +1401,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
|||
if (!iwl_ht_enabled(priv))
|
||||
/* stay in Legacy */
|
||||
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
|
||||
else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
|
||||
else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
|
||||
tbl->action > IWL_LEGACY_SWITCH_SISO)
|
||||
tbl->action = IWL_LEGACY_SWITCH_SISO;
|
||||
for (; ;) {
|
||||
|
@ -1535,7 +1535,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
||||
if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
|
||||
if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
|
||||
tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
|
||||
/* stay in SISO */
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
|
@ -1586,11 +1586,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
goto out;
|
||||
break;
|
||||
case IWL_SISO_SWITCH_GI:
|
||||
if (!tbl->is_fat &&
|
||||
if (!tbl->is_ht40 &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_20MHZ))
|
||||
break;
|
||||
if (tbl->is_fat &&
|
||||
if (tbl->is_ht40 &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_40MHZ))
|
||||
break;
|
||||
|
@ -1674,7 +1674,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
|||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
||||
if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
|
||||
if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
|
||||
(tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
|
||||
tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
|
||||
/* switch in SISO */
|
||||
|
@ -1726,11 +1726,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
|||
break;
|
||||
|
||||
case IWL_MIMO2_SWITCH_GI:
|
||||
if (!tbl->is_fat &&
|
||||
if (!tbl->is_ht40 &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_20MHZ))
|
||||
break;
|
||||
if (tbl->is_fat &&
|
||||
if (tbl->is_ht40 &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_40MHZ))
|
||||
break;
|
||||
|
@ -1816,7 +1816,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
|||
int ret;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
|
||||
if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
|
||||
if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
|
||||
(tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
|
||||
tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
|
||||
/* switch in SISO */
|
||||
|
@ -1890,11 +1890,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
|||
break;
|
||||
|
||||
case IWL_MIMO3_SWITCH_GI:
|
||||
if (!tbl->is_fat &&
|
||||
if (!tbl->is_ht40 &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_20MHZ))
|
||||
break;
|
||||
if (tbl->is_fat &&
|
||||
if (tbl->is_ht40 &&
|
||||
!(priv->current_ht_config.sgf &
|
||||
HT_SHORT_GI_40MHZ))
|
||||
break;
|
||||
|
@ -2202,7 +2202,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
|
||||
/* If we are searching for better modulation mode, check success. */
|
||||
if (lq_sta->search_better_tbl &&
|
||||
(iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) {
|
||||
(iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) {
|
||||
/* If good success, continue using the "search" mode;
|
||||
* no need to send new link quality command, since we're
|
||||
* continuing to use the setup that we've been trying. */
|
||||
|
@ -2332,7 +2332,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
scale_action = 0;
|
||||
if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
|
||||
scale_action = -1;
|
||||
if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI &&
|
||||
if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
|
||||
(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
|
||||
scale_action = -1;
|
||||
switch (scale_action) {
|
||||
|
@ -2368,7 +2368,7 @@ lq_update:
|
|||
rate = rs_update_rate_tbl(priv, lq_sta,
|
||||
tbl, index, is_green);
|
||||
|
||||
if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) {
|
||||
if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
|
||||
/* Should we stay with this modulation mode,
|
||||
* or search for a new one? */
|
||||
rs_stay_in_table(lq_sta);
|
||||
|
@ -2576,7 +2576,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
|
|||
info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
|
||||
if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
|
||||
info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
|
||||
if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK)
|
||||
if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK)
|
||||
info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
|
||||
if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
|
||||
info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
||||
|
@ -2963,7 +2963,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
|||
(is_siso(tbl->lq_type)) ? "SISO" :
|
||||
((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
|
||||
desc += sprintf(buff+desc, " %s",
|
||||
(tbl->is_fat) ? "40MHz" : "20MHz");
|
||||
(tbl->is_ht40) ? "40MHz" : "20MHz");
|
||||
desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "",
|
||||
(lq_sta->is_green) ? "GF enabled" : "");
|
||||
}
|
||||
|
@ -3028,12 +3028,13 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
|
|||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < LQ_SIZE; i++) {
|
||||
desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n"
|
||||
desc += sprintf(buff+desc,
|
||||
"%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n"
|
||||
"rate=0x%X\n",
|
||||
lq_sta->active_tbl == i ? "*" : "x",
|
||||
lq_sta->lq_info[i].lq_type,
|
||||
lq_sta->lq_info[i].is_SGI,
|
||||
lq_sta->lq_info[i].is_fat,
|
||||
lq_sta->lq_info[i].is_ht40,
|
||||
lq_sta->lq_info[i].is_dup,
|
||||
lq_sta->is_green,
|
||||
lq_sta->lq_info[i].current_rate);
|
||||
|
|
|
@ -533,16 +533,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
|
|||
|
||||
if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
|
||||
IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
|
||||
set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
memcpy(&priv->card_alive_init,
|
||||
&pkt->u.alive_frame,
|
||||
sizeof(struct iwl_init_alive_resp));
|
||||
pwork = &priv->init_alive_start;
|
||||
} else {
|
||||
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
|
||||
set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
memcpy(&priv->card_alive, &pkt->u.alive_frame,
|
||||
sizeof(struct iwl_alive_resp));
|
||||
pwork = &priv->alive_start;
|
||||
|
@ -896,7 +892,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
|
|||
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & IWL_DL_ISR) {
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
|
||||
/* just for debug */
|
||||
inta_mask = iwl_read32(priv, CSR_INT_MASK);
|
||||
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
|
||||
|
@ -931,7 +927,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & (IWL_DL_ISR)) {
|
||||
if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
|
||||
/* NIC fires this, but we don't use it, redundant with WAKEUP */
|
||||
if (inta & CSR_INT_BIT_SCD) {
|
||||
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
|
||||
|
@ -1045,7 +1041,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
|
|||
iwl_enable_interrupts(priv);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & (IWL_DL_ISR)) {
|
||||
if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
|
||||
inta = iwl_read32(priv, CSR_INT);
|
||||
inta_mask = iwl_read32(priv, CSR_INT_MASK);
|
||||
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
|
||||
|
@ -1076,7 +1072,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
|
|||
inta = priv->inta;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & IWL_DL_ISR) {
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
|
||||
/* just for debug */
|
||||
inta_mask = iwl_read32(priv, CSR_INT_MASK);
|
||||
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
|
||||
|
@ -1104,7 +1100,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & (IWL_DL_ISR)) {
|
||||
if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
|
||||
/* NIC fires this, but we don't use it, redundant with WAKEUP */
|
||||
if (inta & CSR_INT_BIT_SCD) {
|
||||
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
|
||||
|
@ -1610,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|||
set_bit(STATUS_READY, &priv->status);
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
|
||||
iwl_power_update_mode(priv, 1);
|
||||
iwl_power_update_mode(priv, true);
|
||||
|
||||
/* reassociate for ADHOC mode */
|
||||
if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
|
||||
|
@ -1784,7 +1780,6 @@ static int __iwl_up(struct iwl_priv *priv)
|
|||
{
|
||||
int i;
|
||||
int ret;
|
||||
unsigned long status;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
|
||||
|
@ -1862,51 +1857,6 @@ static int __iwl_up(struct iwl_priv *priv)
|
|||
/* start card; "initialize" will load runtime ucode */
|
||||
iwl_nic_start(priv);
|
||||
|
||||
/* Just finish download Init or Runtime uCode image to device
|
||||
* now we wait here for uCode send REPLY_ALIVE notification
|
||||
* to indicate uCode is ready.
|
||||
* 1) For Init uCode image, all iwlagn devices should wait here
|
||||
* on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
|
||||
* receive the REPLY_ALIVE notification, go back and try to
|
||||
* download the Init uCode image again.
|
||||
* 2) For Runtime uCode image, all iwlagn devices except 4965
|
||||
* wait here on STATUS_RT_UCODE_ALIVE status bit; if
|
||||
* timeout before receive the REPLY_ALIVE notification, go back
|
||||
* and download the Runtime uCode image again.
|
||||
* 3) For 4965 Runtime uCode, it will not go through this path,
|
||||
* need to wait for STATUS_RT_UCODE_ALIVE status bit in
|
||||
* iwl4965_init_alive_start() function; if timeout, need to
|
||||
* restart and download Init uCode image.
|
||||
*/
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
status = STATUS_INIT_UCODE_ALIVE;
|
||||
else
|
||||
status = STATUS_RT_UCODE_ALIVE;
|
||||
if (test_bit(status, &priv->status)) {
|
||||
IWL_WARN(priv,
|
||||
"%s uCode already alive? "
|
||||
"Waiting for alive anyway\n",
|
||||
(status == STATUS_INIT_UCODE_ALIVE)
|
||||
? "INIT" : "Runtime");
|
||||
clear_bit(status, &priv->status);
|
||||
}
|
||||
ret = wait_event_interruptible_timeout(
|
||||
priv->wait_command_queue,
|
||||
test_bit(status, &priv->status),
|
||||
UCODE_ALIVE_TIMEOUT);
|
||||
if (!ret) {
|
||||
if (!test_bit(status, &priv->status)) {
|
||||
priv->ucode_type =
|
||||
(status == STATUS_INIT_UCODE_ALIVE)
|
||||
? UCODE_NONE : UCODE_INIT;
|
||||
IWL_ERR(priv,
|
||||
"%s timeout after %dms\n",
|
||||
(status == STATUS_INIT_UCODE_ALIVE)
|
||||
? "INIT" : "Runtime",
|
||||
jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
|
||||
|
||||
return 0;
|
||||
|
@ -2125,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv)
|
|||
* If chain noise has already been run, then we need to enable
|
||||
* power management here */
|
||||
if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
|
||||
iwl_power_update_mode(priv, 0);
|
||||
iwl_power_update_mode(priv, false);
|
||||
|
||||
/* Enable Rx differential gain and sensitivity calibrations */
|
||||
iwl_chain_noise_reset(priv);
|
||||
|
@ -2455,15 +2405,15 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
|
|||
*
|
||||
* See the level definitions in iwl for details.
|
||||
*
|
||||
* FIXME This file can be deprecated as the module parameter is
|
||||
* writable and users can thus also change the debug level
|
||||
* using the /sys/module/iwl3945/parameters/debug file.
|
||||
* The debug_level being managed using sysfs below is a per device debug
|
||||
* level that is used instead of the global debug level if it (the per
|
||||
* device debug level) is set.
|
||||
*/
|
||||
|
||||
static ssize_t show_debug_level(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "0x%08X\n", iwl_debug_level);
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
|
||||
}
|
||||
static ssize_t store_debug_level(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
|
@ -2476,9 +2426,12 @@ static ssize_t store_debug_level(struct device *d,
|
|||
ret = strict_strtoul(buf, 0, &val);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
|
||||
else
|
||||
iwl_debug_level = val;
|
||||
|
||||
else {
|
||||
priv->debug_level = val;
|
||||
if (iwl_alloc_traffic_mem(priv))
|
||||
IWL_ERR(priv,
|
||||
"Not enough memory to generate traffic log\n");
|
||||
}
|
||||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
|
@ -2612,47 +2565,6 @@ static ssize_t store_filter_flags(struct device *d,
|
|||
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
|
||||
store_filter_flags);
|
||||
|
||||
static ssize_t store_power_level(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
int ret;
|
||||
unsigned long mode;
|
||||
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
ret = strict_strtoul(buf, 10, &mode);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = iwl_power_set_user_mode(priv, mode);
|
||||
if (ret) {
|
||||
IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n");
|
||||
goto out;
|
||||
}
|
||||
ret = count;
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_power_level(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
int level = priv->power_data.power_mode;
|
||||
char *p = buf;
|
||||
|
||||
p += sprintf(p, "%d\n", level);
|
||||
return p - buf + 1;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
|
||||
store_power_level);
|
||||
|
||||
|
||||
static ssize_t show_statistics(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -2745,7 +2657,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
|||
static struct attribute *iwl_sysfs_entries[] = {
|
||||
&dev_attr_flags.attr,
|
||||
&dev_attr_filter_flags.attr,
|
||||
&dev_attr_power_level.attr,
|
||||
&dev_attr_statistics.attr,
|
||||
&dev_attr_temperature.attr,
|
||||
&dev_attr_tx_power.attr,
|
||||
|
@ -2819,6 +2730,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
atomic_set(&priv->restrict_refcnt, 0);
|
||||
#endif
|
||||
if (iwl_alloc_traffic_mem(priv))
|
||||
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
|
||||
|
||||
/**************************
|
||||
* 2. Initializing PCI bus
|
||||
|
@ -3003,6 +2916,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
pci_disable_device(pdev);
|
||||
out_ieee80211_free_hw:
|
||||
ieee80211_free_hw(priv->hw);
|
||||
iwl_free_traffic_mem(priv);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
@ -3061,6 +2975,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
|
|||
* until now... */
|
||||
destroy_workqueue(priv->workqueue);
|
||||
priv->workqueue = NULL;
|
||||
iwl_free_traffic_mem(priv);
|
||||
|
||||
free_irq(priv->pci_dev->irq, priv);
|
||||
pci_disable_msi(priv->pci_dev);
|
||||
|
|
|
@ -852,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
|
|||
priv->cfg->ops->lib->update_chain_flags(priv);
|
||||
|
||||
data->state = IWL_CHAIN_NOISE_DONE;
|
||||
iwl_power_update_mode(priv, 0);
|
||||
iwl_power_update_mode(priv, false);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_chain_noise_calibration);
|
||||
|
||||
|
|
|
@ -283,7 +283,7 @@ struct iwl3945_power_per_rate {
|
|||
* 1) Dual stream (MIMO)
|
||||
* 2) Triple stream (MIMO)
|
||||
*
|
||||
* 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data
|
||||
* 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
|
||||
*
|
||||
* Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
|
||||
* 3-0: 0xD) 6 Mbps
|
||||
|
@ -320,11 +320,11 @@ struct iwl3945_power_per_rate {
|
|||
#define RATE_MCS_GF_POS 10
|
||||
#define RATE_MCS_GF_MSK 0x400
|
||||
|
||||
/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */
|
||||
#define RATE_MCS_FAT_POS 11
|
||||
#define RATE_MCS_FAT_MSK 0x800
|
||||
/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */
|
||||
#define RATE_MCS_HT40_POS 11
|
||||
#define RATE_MCS_HT40_MSK 0x800
|
||||
|
||||
/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */
|
||||
/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */
|
||||
#define RATE_MCS_DUP_POS 12
|
||||
#define RATE_MCS_DUP_MSK 0x1000
|
||||
|
||||
|
@ -459,7 +459,7 @@ struct iwl_init_alive_resp {
|
|||
|
||||
/* calibration values from "initialize" uCode */
|
||||
__le32 voltage; /* signed, higher value is lower voltage */
|
||||
__le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/
|
||||
__le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */
|
||||
__le32 therm_r2[2]; /* signed */
|
||||
__le32 therm_r3[2]; /* signed */
|
||||
__le32 therm_r4[2]; /* signed */
|
||||
|
@ -610,7 +610,7 @@ enum {
|
|||
#define RXON_FLG_HT_OPERATING_MODE_POS (23)
|
||||
|
||||
#define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23)
|
||||
#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23)
|
||||
#define RXON_FLG_HT40_PROT_MSK cpu_to_le32(0x2 << 23)
|
||||
|
||||
#define RXON_FLG_CHANNEL_MODE_POS (25)
|
||||
#define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25)
|
||||
|
@ -891,7 +891,7 @@ struct iwl_qosparam_cmd {
|
|||
#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18)
|
||||
#define STA_FLG_MAX_AGG_SIZE_POS (19)
|
||||
#define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19)
|
||||
#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21)
|
||||
#define STA_FLG_HT40_EN_MSK cpu_to_le32(1 << 21)
|
||||
#define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22)
|
||||
#define STA_FLG_AGG_MPDU_DENSITY_POS (23)
|
||||
#define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23)
|
||||
|
@ -1984,10 +1984,10 @@ struct iwl_link_qual_agg_params {
|
|||
* a) Use this same initial rate for first 3 entries.
|
||||
* b) Find next lower available rate using same mode (SISO or MIMO),
|
||||
* use for next 3 entries. If no lower rate available, switch to
|
||||
* legacy mode (no FAT channel, no MIMO, no short guard interval).
|
||||
* legacy mode (no HT40 channel, no MIMO, no short guard interval).
|
||||
* c) If using MIMO, set command's mimo_delimiter to number of entries
|
||||
* using MIMO (3 or 6).
|
||||
* d) After trying 2 HT rates, switch to legacy mode (no FAT channel,
|
||||
* d) After trying 2 HT rates, switch to legacy mode (no HT40 channel,
|
||||
* no MIMO, no short guard interval), at the next lower bit rate
|
||||
* (e.g. if second HT bit rate was 54, try 48 legacy), and follow
|
||||
* legacy procedure for remaining table entries.
|
||||
|
@ -2313,15 +2313,22 @@ struct iwl_spectrum_notification {
|
|||
* PM allow:
|
||||
* bit 0 - '0' Driver not allow power management
|
||||
* '1' Driver allow PM (use rest of parameters)
|
||||
*
|
||||
* uCode send sleep notifications:
|
||||
* bit 1 - '0' Don't send sleep notification
|
||||
* '1' send sleep notification (SEND_PM_NOTIFICATION)
|
||||
*
|
||||
* Sleep over DTIM
|
||||
* bit 2 - '0' PM have to walk up every DTIM
|
||||
* '1' PM could sleep over DTIM till listen Interval.
|
||||
*
|
||||
* PCI power managed
|
||||
* bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
|
||||
* '1' !(PCI_CFG_LINK_CTRL & 0x1)
|
||||
*
|
||||
* Fast PD
|
||||
* bit 4 - '1' Put radio to sleep when receiving frame for others
|
||||
*
|
||||
* Force sleep Modes
|
||||
* bit 31/30- '00' use both mac/xtal sleeps
|
||||
* '01' force Mac sleep
|
||||
|
@ -3017,7 +3024,7 @@ struct iwl_statistics_cmd {
|
|||
* one channel that has just been scanned.
|
||||
*/
|
||||
#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2)
|
||||
#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8)
|
||||
#define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8)
|
||||
|
||||
struct iwl3945_notif_statistics {
|
||||
__le32 flag;
|
||||
|
|
|
@ -105,7 +105,7 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
|
|||
r->flags |= IEEE80211_TX_RC_MCS;
|
||||
if (rate_n_flags & RATE_MCS_GF_MSK)
|
||||
r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
||||
if (rate_n_flags & RATE_MCS_FAT_MSK)
|
||||
if (rate_n_flags & RATE_MCS_HT40_MSK)
|
||||
r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
|
||||
if (rate_n_flags & RATE_MCS_DUP_MSK)
|
||||
r->flags |= IEEE80211_TX_RC_DUP_DATA;
|
||||
|
@ -400,7 +400,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
|
|||
(WLAN_HT_CAP_SM_PS_DISABLED << 2));
|
||||
|
||||
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
||||
if (priv->hw_params.fat_channel & BIT(band)) {
|
||||
if (priv->hw_params.ht40_channel & BIT(band)) {
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
|
||||
ht_info->mcs.rx_mask[4] = 0x01;
|
||||
|
@ -540,7 +540,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
|
|||
if (ch->flags & EEPROM_CHANNEL_RADAR)
|
||||
geo_ch->flags |= IEEE80211_CHAN_RADAR;
|
||||
|
||||
geo_ch->flags |= ch->fat_extension_channel;
|
||||
geo_ch->flags |= ch->ht40_extension_channel;
|
||||
|
||||
if (ch->max_power_avg > priv->tx_power_channel_lmt)
|
||||
priv->tx_power_channel_lmt = ch->max_power_avg;
|
||||
|
@ -604,16 +604,16 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
|
|||
return 0;
|
||||
|
||||
if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
|
||||
return !(ch_info->fat_extension_channel &
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40PLUS);
|
||||
else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
|
||||
return !(ch_info->fat_extension_channel &
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40MINUS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
|
||||
u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct ieee80211_sta_ht_cap *sta_ht_inf)
|
||||
{
|
||||
struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
|
||||
|
@ -637,7 +637,7 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
|
|||
le16_to_cpu(priv->staging_rxon.channel),
|
||||
iwl_ht_conf->extension_chan_offset);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
|
||||
EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
|
||||
|
||||
static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
|
||||
{
|
||||
|
@ -866,7 +866,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
|
|||
if (!ht_info->is_ht) {
|
||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
|
||||
RXON_FLG_FAT_PROT_MSK |
|
||||
RXON_FLG_HT40_PROT_MSK |
|
||||
RXON_FLG_HT_PROT_MSK);
|
||||
return;
|
||||
}
|
||||
|
@ -877,12 +877,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
|
|||
rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
|
||||
|
||||
/* Set up channel bandwidth:
|
||||
* 20 MHz only, 20/40 mixed or pure 40 if fat ok */
|
||||
* 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
|
||||
/* clear the HT channel mode before set the mode */
|
||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
|
||||
if (iwl_is_fat_tx_allowed(priv, NULL)) {
|
||||
/* pure 40 fat */
|
||||
if (iwl_is_ht40_tx_allowed(priv, NULL)) {
|
||||
/* pure ht40 */
|
||||
if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
|
||||
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
|
||||
/* Note: control channel is opposite of extension channel */
|
||||
|
@ -1278,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
|
|||
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
|
||||
|
||||
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
|
||||
iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
|
||||
iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
|
||||
IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
|
||||
IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
|
||||
IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
|
||||
|
@ -1343,17 +1343,10 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
|||
u32 desc, time, count, base, data1;
|
||||
u32 blink1, blink2, ilink1, ilink2;
|
||||
|
||||
switch (priv->ucode_type) {
|
||||
case UCODE_RT:
|
||||
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
|
||||
break;
|
||||
case UCODE_INIT:
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(priv, "uCode image not available\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
|
||||
|
||||
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
|
||||
IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
|
||||
|
@ -1405,17 +1398,10 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
|||
|
||||
if (num_events == 0)
|
||||
return;
|
||||
switch (priv->ucode_type) {
|
||||
case UCODE_RT:
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
break;
|
||||
case UCODE_INIT:
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(priv, "uCode image not available\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
|
||||
if (mode == 0)
|
||||
event_size = 2 * sizeof(u32);
|
||||
|
@ -1452,17 +1438,10 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
|
|||
u32 next_entry; /* index of next entry to be written by uCode */
|
||||
u32 size; /* # entries that we'll print */
|
||||
|
||||
switch (priv->ucode_type) {
|
||||
case UCODE_RT:
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
break;
|
||||
case UCODE_INIT:
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(priv, "uCode image not available\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
|
||||
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
|
||||
IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
|
||||
|
@ -1508,7 +1487,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
|
|||
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & IWL_DL_FW_ERRORS) {
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) {
|
||||
iwl_dump_nic_error_log(priv);
|
||||
iwl_dump_nic_event_log(priv);
|
||||
iwl_print_rx_config_cmd(priv);
|
||||
|
@ -1589,7 +1568,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
|
|||
IEEE80211_HW_NOISE_DBM |
|
||||
IEEE80211_HW_AMPDU_AGGREGATION |
|
||||
IEEE80211_HW_SPECTRUM_MGMT |
|
||||
IEEE80211_HW_SUPPORTS_PS;
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
@ -1684,8 +1664,6 @@ int iwl_init_drv(struct iwl_priv *priv)
|
|||
priv->qos_data.qos_cap.val = 0;
|
||||
|
||||
priv->rates_mask = IWL_RATES_MASK;
|
||||
/* If power management is turned on, default to CAM mode */
|
||||
priv->power_mode = IWL_POWER_MODE_CAM;
|
||||
priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX;
|
||||
|
||||
ret = iwl_init_channel_map(priv);
|
||||
|
@ -1985,7 +1963,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & (IWL_DL_ISR)) {
|
||||
if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
|
||||
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
|
||||
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
|
||||
"fh 0x%08x\n", inta, inta_mask, inta_fh);
|
||||
|
@ -2235,7 +2213,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
|||
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
|
||||
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
priv->power_data.ct_kill_toggle = false;
|
||||
priv->thermal_throttle.ct_kill_toggle = false;
|
||||
|
||||
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
|
||||
case CSR_HW_REV_TYPE_1000:
|
||||
|
@ -2248,6 +2226,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
|||
|
||||
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
|
||||
sizeof(adv_cmd), &adv_cmd);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
|
||||
else
|
||||
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
||||
"succeeded, "
|
||||
"critical temperature enter is %d,"
|
||||
"exit is %d\n",
|
||||
priv->hw_params.ct_kill_threshold,
|
||||
priv->hw_params.ct_kill_exit_threshold);
|
||||
break;
|
||||
default:
|
||||
cmd.critical_temperature_R =
|
||||
|
@ -2255,16 +2242,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
|||
|
||||
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
|
||||
sizeof(cmd), &cmd);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
|
||||
else
|
||||
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
||||
"succeeded, "
|
||||
"critical temperature is %d\n",
|
||||
priv->hw_params.ct_kill_threshold);
|
||||
break;
|
||||
}
|
||||
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
|
||||
sizeof(cmd), &cmd);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
|
||||
else
|
||||
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD succeeded, "
|
||||
"critical temperature is %d\n",
|
||||
cmd.critical_temperature_R);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
|
||||
|
||||
|
@ -2310,7 +2296,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
|
|||
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
|
||||
"notification for %s:\n",
|
||||
le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
|
||||
iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
|
||||
iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
|
||||
|
||||
|
@ -2428,7 +2414,7 @@ static void iwl_ht_conf(struct iwl_priv *priv,
|
|||
else if (conf_is_ht40_plus(&priv->hw->conf))
|
||||
iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
|
||||
|
||||
/* If no above or below channel supplied disable FAT channel */
|
||||
/* If no above or below channel supplied disable HT40 channel */
|
||||
if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
|
||||
iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
|
||||
iwl_conf->supported_chan_width = 0;
|
||||
|
@ -2564,7 +2550,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
|||
if (bss_conf->assoc) {
|
||||
priv->assoc_id = bss_conf->aid;
|
||||
priv->beacon_int = bss_conf->beacon_int;
|
||||
priv->power_data.dtim_period = bss_conf->dtim_period;
|
||||
priv->timestamp = bss_conf->timestamp;
|
||||
priv->assoc_capability = bss_conf->assoc_capability;
|
||||
|
||||
|
@ -2814,13 +2799,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
iwl_set_rate(priv);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_PS &&
|
||||
priv->iw_mode == NL80211_IFTYPE_STATION) {
|
||||
priv->power_data.power_disabled =
|
||||
!(conf->flags & IEEE80211_CONF_PS);
|
||||
ret = iwl_power_update_mode(priv, 0);
|
||||
if (changed & IEEE80211_CONF_CHANGE_PS) {
|
||||
ret = iwl_power_update_mode(priv, false);
|
||||
if (ret)
|
||||
IWL_DEBUG_MAC80211(priv, "Error setting power level\n");
|
||||
IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
||||
|
@ -2953,6 +2935,248 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_mac_reset_tsf);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
|
||||
#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
|
||||
|
||||
void iwl_reset_traffic_log(struct iwl_priv *priv)
|
||||
{
|
||||
priv->tx_traffic_idx = 0;
|
||||
priv->rx_traffic_idx = 0;
|
||||
if (priv->tx_traffic)
|
||||
memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
|
||||
if (priv->rx_traffic)
|
||||
memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
|
||||
}
|
||||
|
||||
int iwl_alloc_traffic_mem(struct iwl_priv *priv)
|
||||
{
|
||||
u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
|
||||
|
||||
if (iwl_debug_level & IWL_DL_TX) {
|
||||
if (!priv->tx_traffic) {
|
||||
priv->tx_traffic =
|
||||
kzalloc(traffic_size, GFP_KERNEL);
|
||||
if (!priv->tx_traffic)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
if (iwl_debug_level & IWL_DL_RX) {
|
||||
if (!priv->rx_traffic) {
|
||||
priv->rx_traffic =
|
||||
kzalloc(traffic_size, GFP_KERNEL);
|
||||
if (!priv->rx_traffic)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
iwl_reset_traffic_log(priv);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_alloc_traffic_mem);
|
||||
|
||||
void iwl_free_traffic_mem(struct iwl_priv *priv)
|
||||
{
|
||||
kfree(priv->tx_traffic);
|
||||
priv->tx_traffic = NULL;
|
||||
|
||||
kfree(priv->rx_traffic);
|
||||
priv->rx_traffic = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_free_traffic_mem);
|
||||
|
||||
void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header)
|
||||
{
|
||||
__le16 fc;
|
||||
u16 len;
|
||||
|
||||
if (likely(!(iwl_debug_level & IWL_DL_TX)))
|
||||
return;
|
||||
|
||||
if (!priv->tx_traffic)
|
||||
return;
|
||||
|
||||
fc = header->frame_control;
|
||||
if (ieee80211_is_data(fc)) {
|
||||
len = (length > IWL_TRAFFIC_ENTRY_SIZE)
|
||||
? IWL_TRAFFIC_ENTRY_SIZE : length;
|
||||
memcpy((priv->tx_traffic +
|
||||
(priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
|
||||
header, len);
|
||||
priv->tx_traffic_idx =
|
||||
(priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame);
|
||||
|
||||
void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header)
|
||||
{
|
||||
__le16 fc;
|
||||
u16 len;
|
||||
|
||||
if (likely(!(iwl_debug_level & IWL_DL_RX)))
|
||||
return;
|
||||
|
||||
if (!priv->rx_traffic)
|
||||
return;
|
||||
|
||||
fc = header->frame_control;
|
||||
if (ieee80211_is_data(fc)) {
|
||||
len = (length > IWL_TRAFFIC_ENTRY_SIZE)
|
||||
? IWL_TRAFFIC_ENTRY_SIZE : length;
|
||||
memcpy((priv->rx_traffic +
|
||||
(priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
|
||||
header, len);
|
||||
priv->rx_traffic_idx =
|
||||
(priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame);
|
||||
|
||||
const char *get_mgmt_string(int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
IWL_CMD(MANAGEMENT_ASSOC_REQ);
|
||||
IWL_CMD(MANAGEMENT_ASSOC_RESP);
|
||||
IWL_CMD(MANAGEMENT_REASSOC_REQ);
|
||||
IWL_CMD(MANAGEMENT_REASSOC_RESP);
|
||||
IWL_CMD(MANAGEMENT_PROBE_REQ);
|
||||
IWL_CMD(MANAGEMENT_PROBE_RESP);
|
||||
IWL_CMD(MANAGEMENT_BEACON);
|
||||
IWL_CMD(MANAGEMENT_ATIM);
|
||||
IWL_CMD(MANAGEMENT_DISASSOC);
|
||||
IWL_CMD(MANAGEMENT_AUTH);
|
||||
IWL_CMD(MANAGEMENT_DEAUTH);
|
||||
IWL_CMD(MANAGEMENT_ACTION);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const char *get_ctrl_string(int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
IWL_CMD(CONTROL_BACK_REQ);
|
||||
IWL_CMD(CONTROL_BACK);
|
||||
IWL_CMD(CONTROL_PSPOLL);
|
||||
IWL_CMD(CONTROL_RTS);
|
||||
IWL_CMD(CONTROL_CTS);
|
||||
IWL_CMD(CONTROL_ACK);
|
||||
IWL_CMD(CONTROL_CFEND);
|
||||
IWL_CMD(CONTROL_CFENDACK);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_clear_tx_stats(struct iwl_priv *priv)
|
||||
{
|
||||
memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
|
||||
|
||||
}
|
||||
|
||||
void iwl_clear_rx_stats(struct iwl_priv *priv)
|
||||
{
|
||||
memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
|
||||
}
|
||||
|
||||
/*
|
||||
* if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will
|
||||
* record all the MGMT, CTRL and DATA pkt for both TX and Rx pass.
|
||||
* Use debugFs to display the rx/rx_statistics
|
||||
* if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL
|
||||
* information will be recorded, but DATA pkt still will be recorded
|
||||
* for the reason of iwl_led.c need to control the led blinking based on
|
||||
* number of tx and rx data.
|
||||
*
|
||||
*/
|
||||
void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
|
||||
{
|
||||
struct traffic_stats *stats;
|
||||
|
||||
if (is_tx)
|
||||
stats = &priv->tx_stats;
|
||||
else
|
||||
stats = &priv->rx_stats;
|
||||
|
||||
if (ieee80211_is_mgmt(fc)) {
|
||||
switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
|
||||
case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
|
||||
stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
|
||||
stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
|
||||
stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
|
||||
stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
|
||||
stats->mgmt[MANAGEMENT_PROBE_REQ]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
|
||||
stats->mgmt[MANAGEMENT_PROBE_RESP]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_BEACON):
|
||||
stats->mgmt[MANAGEMENT_BEACON]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_ATIM):
|
||||
stats->mgmt[MANAGEMENT_ATIM]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
|
||||
stats->mgmt[MANAGEMENT_DISASSOC]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_AUTH):
|
||||
stats->mgmt[MANAGEMENT_AUTH]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
|
||||
stats->mgmt[MANAGEMENT_DEAUTH]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_ACTION):
|
||||
stats->mgmt[MANAGEMENT_ACTION]++;
|
||||
break;
|
||||
}
|
||||
} else if (ieee80211_is_ctl(fc)) {
|
||||
switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
|
||||
case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
|
||||
stats->ctrl[CONTROL_BACK_REQ]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_BACK):
|
||||
stats->ctrl[CONTROL_BACK]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
|
||||
stats->ctrl[CONTROL_PSPOLL]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_RTS):
|
||||
stats->ctrl[CONTROL_RTS]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_CTS):
|
||||
stats->ctrl[CONTROL_CTS]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_ACK):
|
||||
stats->ctrl[CONTROL_ACK]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_CFEND):
|
||||
stats->ctrl[CONTROL_CFEND]++;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
|
||||
stats->ctrl[CONTROL_CFENDACK]++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* data */
|
||||
stats->data_cnt++;
|
||||
stats->data_bytes += len;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_update_stats);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
|
|
@ -83,6 +83,8 @@ struct iwl_cmd;
|
|||
#define IWL_SKU_A 0x2
|
||||
#define IWL_SKU_N 0x8
|
||||
|
||||
#define IWL_CMD(x) case x: return #x
|
||||
|
||||
struct iwl_hcmd_ops {
|
||||
int (*rxon_assoc)(struct iwl_priv *priv);
|
||||
int (*commit_rxon)(struct iwl_priv *priv);
|
||||
|
@ -264,7 +266,7 @@ int iwl_full_rxon_required(struct iwl_priv *priv);
|
|||
void iwl_set_rxon_chain(struct iwl_priv *priv);
|
||||
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
|
||||
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
|
||||
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
|
||||
u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct ieee80211_sta_ht_cap *sta_ht_inf);
|
||||
void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band);
|
||||
void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode);
|
||||
|
@ -300,7 +302,55 @@ void iwl_config_ap(struct iwl_priv *priv);
|
|||
int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_queue_stats *stats);
|
||||
void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
|
||||
void iwl_free_traffic_mem(struct iwl_priv *priv);
|
||||
void iwl_reset_traffic_log(struct iwl_priv *priv);
|
||||
void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header);
|
||||
void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header);
|
||||
const char *get_mgmt_string(int cmd);
|
||||
const char *get_ctrl_string(int cmd);
|
||||
void iwl_clear_tx_stats(struct iwl_priv *priv);
|
||||
void iwl_clear_rx_stats(struct iwl_priv *priv);
|
||||
void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
|
||||
u16 len);
|
||||
#else
|
||||
static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void iwl_free_traffic_mem(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
static inline void iwl_reset_traffic_log(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header)
|
||||
{
|
||||
}
|
||||
static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header)
|
||||
{
|
||||
}
|
||||
static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
|
||||
__le16 fc, u16 len)
|
||||
{
|
||||
struct traffic_stats *stats;
|
||||
|
||||
if (is_tx)
|
||||
stats = &priv->tx_stats;
|
||||
else
|
||||
stats = &priv->rx_stats;
|
||||
|
||||
if (ieee80211_is_data(fc)) {
|
||||
/* data */
|
||||
stats->data_bytes += len;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*****************************************************
|
||||
* RX handlers.
|
||||
* **************************************************/
|
||||
|
@ -512,8 +562,6 @@ void iwlcore_free_geos(struct iwl_priv *priv);
|
|||
#define STATUS_POWER_PMI 16
|
||||
#define STATUS_FW_ERROR 17
|
||||
#define STATUS_MODE_PENDING 18
|
||||
#define STATUS_INIT_UCODE_ALIVE 19
|
||||
#define STATUS_RT_UCODE_ALIVE 20
|
||||
|
||||
|
||||
static inline int iwl_is_ready(struct iwl_priv *priv)
|
||||
|
|
|
@ -46,7 +46,7 @@ do { \
|
|||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
#define IWL_DEBUG(__priv, level, fmt, args...) \
|
||||
do { \
|
||||
if (iwl_debug_level & (level)) \
|
||||
if (iwl_get_debug_level(__priv) & (level)) \
|
||||
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
|
||||
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
|
||||
__func__ , ## args); \
|
||||
|
@ -54,15 +54,15 @@ do { \
|
|||
|
||||
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
|
||||
do { \
|
||||
if ((iwl_debug_level & (level)) && net_ratelimit()) \
|
||||
if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \
|
||||
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
|
||||
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
|
||||
__func__ , ## args); \
|
||||
} while (0)
|
||||
|
||||
#define iwl_print_hex_dump(level, p, len) \
|
||||
#define iwl_print_hex_dump(priv, level, p, len) \
|
||||
do { \
|
||||
if (iwl_debug_level & level) \
|
||||
if (iwl_get_debug_level(priv) & level) \
|
||||
print_hex_dump(KERN_DEBUG, "iwl data: ", \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
|
||||
} while (0)
|
||||
|
@ -72,13 +72,12 @@ struct iwl_debugfs {
|
|||
const char *name;
|
||||
struct dentry *dir_drv;
|
||||
struct dentry *dir_data;
|
||||
struct dentry *dir_debug;
|
||||
struct dentry *dir_rf;
|
||||
struct dir_data_files {
|
||||
struct dentry *file_sram;
|
||||
struct dentry *file_nvm;
|
||||
struct dentry *file_stations;
|
||||
struct dentry *file_rx_statistics;
|
||||
struct dentry *file_tx_statistics;
|
||||
struct dentry *file_log_event;
|
||||
struct dentry *file_channels;
|
||||
struct dentry *file_status;
|
||||
|
@ -89,12 +88,26 @@ struct iwl_debugfs {
|
|||
struct dentry *file_led;
|
||||
#endif
|
||||
struct dentry *file_disable_ht40;
|
||||
struct dentry *file_sleep_level_override;
|
||||
struct dentry *file_current_sleep_command;
|
||||
} dbgfs_data_files;
|
||||
struct dir_rf_files {
|
||||
struct dentry *file_disable_sensitivity;
|
||||
struct dentry *file_disable_chain_noise;
|
||||
struct dentry *file_disable_tx_power;
|
||||
} dbgfs_rf_files;
|
||||
struct dir_debug_files {
|
||||
struct dentry *file_rx_statistics;
|
||||
struct dentry *file_tx_statistics;
|
||||
struct dentry *file_traffic_log;
|
||||
struct dentry *file_rx_queue;
|
||||
struct dentry *file_tx_queue;
|
||||
struct dentry *file_ucode_rx_stats;
|
||||
struct dentry *file_ucode_tx_stats;
|
||||
struct dentry *file_ucode_general_stats;
|
||||
struct dentry *file_sensitivity;
|
||||
struct dentry *file_chain_noise;
|
||||
} dbgfs_debug_files;
|
||||
u32 sram_offset;
|
||||
u32 sram_len;
|
||||
};
|
||||
|
@ -106,7 +119,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
|
|||
#else
|
||||
#define IWL_DEBUG(__priv, level, fmt, args...)
|
||||
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
|
||||
static inline void iwl_print_hex_dump(int level, void *p, u32 len)
|
||||
static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
|
||||
void *p, u32 len)
|
||||
{}
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -277,8 +277,8 @@ struct iwl_channel_info {
|
|||
struct iwl4965_channel_tgd_info tgd;
|
||||
struct iwl4965_channel_tgh_info tgh;
|
||||
struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
|
||||
struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
|
||||
* FAT channel */
|
||||
struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for
|
||||
* HT40 channel */
|
||||
|
||||
u8 channel; /* channel number */
|
||||
u8 flags; /* flags copied from EEPROM */
|
||||
|
@ -291,13 +291,13 @@ struct iwl_channel_info {
|
|||
u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
|
||||
enum ieee80211_band band;
|
||||
|
||||
/* FAT channel info */
|
||||
s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
|
||||
s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
|
||||
s8 fat_min_power; /* always 0 */
|
||||
s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */
|
||||
u8 fat_flags; /* flags copied from EEPROM */
|
||||
u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
|
||||
/* HT40 channel info */
|
||||
s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
|
||||
s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
|
||||
s8 ht40_min_power; /* always 0 */
|
||||
s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */
|
||||
u8 ht40_flags; /* flags copied from EEPROM */
|
||||
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
|
||||
|
||||
/* Radio/DSP gain settings for each "normal" data Tx rate.
|
||||
* These include, in addition to RF and DSP gain, a few fields for
|
||||
|
@ -649,7 +649,7 @@ struct iwl_sensitivity_ranges {
|
|||
* @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
|
||||
* @max_stations:
|
||||
* @bcast_sta_id:
|
||||
* @fat_channel: is 40MHz width possible in band 2.4
|
||||
* @ht40_channel: is 40MHz width possible in band 2.4
|
||||
* BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
|
||||
* @sw_crypto: 0 for hw, 1 for sw
|
||||
* @max_xxx_size: for ucode uses
|
||||
|
@ -673,7 +673,7 @@ struct iwl_hw_params {
|
|||
u32 max_pkt_size;
|
||||
u8 max_stations;
|
||||
u8 bcast_sta_id;
|
||||
u8 fat_channel;
|
||||
u8 ht40_channel;
|
||||
u8 max_beacon_itrvl; /* in 1024 ms */
|
||||
u32 max_inst_size;
|
||||
u32 max_data_size;
|
||||
|
@ -823,8 +823,6 @@ struct iwl_calib_result {
|
|||
size_t buf_len;
|
||||
};
|
||||
|
||||
#define UCODE_ALIVE_TIMEOUT (5 * HZ)
|
||||
|
||||
enum ucode_type {
|
||||
UCODE_NONE = 0,
|
||||
UCODE_INIT,
|
||||
|
@ -877,6 +875,8 @@ struct iwl_chain_noise_data {
|
|||
#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */
|
||||
#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
|
||||
|
||||
#define IWL_TRAFFIC_ENTRIES (256)
|
||||
#define IWL_TRAFFIC_ENTRY_SIZE (64)
|
||||
|
||||
enum {
|
||||
MEASUREMENT_READY = (1 << 0),
|
||||
|
@ -917,6 +917,48 @@ struct isr_statistics {
|
|||
u32 unhandled;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/* management statistics */
|
||||
enum iwl_mgmt_stats {
|
||||
MANAGEMENT_ASSOC_REQ = 0,
|
||||
MANAGEMENT_ASSOC_RESP,
|
||||
MANAGEMENT_REASSOC_REQ,
|
||||
MANAGEMENT_REASSOC_RESP,
|
||||
MANAGEMENT_PROBE_REQ,
|
||||
MANAGEMENT_PROBE_RESP,
|
||||
MANAGEMENT_BEACON,
|
||||
MANAGEMENT_ATIM,
|
||||
MANAGEMENT_DISASSOC,
|
||||
MANAGEMENT_AUTH,
|
||||
MANAGEMENT_DEAUTH,
|
||||
MANAGEMENT_ACTION,
|
||||
MANAGEMENT_MAX,
|
||||
};
|
||||
/* control statistics */
|
||||
enum iwl_ctrl_stats {
|
||||
CONTROL_BACK_REQ = 0,
|
||||
CONTROL_BACK,
|
||||
CONTROL_PSPOLL,
|
||||
CONTROL_RTS,
|
||||
CONTROL_CTS,
|
||||
CONTROL_ACK,
|
||||
CONTROL_CFEND,
|
||||
CONTROL_CFENDACK,
|
||||
CONTROL_MAX,
|
||||
};
|
||||
|
||||
struct traffic_stats {
|
||||
u32 mgmt[MANAGEMENT_MAX];
|
||||
u32 ctrl[CONTROL_MAX];
|
||||
u32 data_cnt;
|
||||
u64 data_bytes;
|
||||
};
|
||||
#else
|
||||
struct traffic_stats {
|
||||
u64 data_bytes;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
|
||||
|
||||
struct iwl_priv {
|
||||
|
@ -1062,15 +1104,14 @@ struct iwl_priv {
|
|||
int last_rx_noise; /* From beacon statistics */
|
||||
|
||||
/* counts mgmt, ctl, and data packets */
|
||||
struct traffic_stats {
|
||||
u32 cnt;
|
||||
u64 bytes;
|
||||
} tx_stats[3], rx_stats[3];
|
||||
struct traffic_stats tx_stats;
|
||||
struct traffic_stats rx_stats;
|
||||
|
||||
/* counts interrupts */
|
||||
struct isr_statistics isr_stats;
|
||||
|
||||
struct iwl_power_mgr power_data;
|
||||
struct iwl_tt_mgmt thermal_throttle;
|
||||
|
||||
struct iwl_notif_statistics statistics;
|
||||
unsigned long last_statistics_time;
|
||||
|
@ -1078,7 +1119,6 @@ struct iwl_priv {
|
|||
/* context information */
|
||||
u16 rates_mask;
|
||||
|
||||
u32 power_mode;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u16 rts_threshold;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
@ -1157,6 +1197,9 @@ struct iwl_priv {
|
|||
struct work_struct report_work;
|
||||
struct work_struct request_scan;
|
||||
struct work_struct beacon_update;
|
||||
struct work_struct tt_work;
|
||||
struct work_struct ct_enter;
|
||||
struct work_struct ct_exit;
|
||||
|
||||
struct tasklet_struct irq_tasklet;
|
||||
|
||||
|
@ -1175,11 +1218,17 @@ struct iwl_priv {
|
|||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
/* debugging info */
|
||||
u32 debug_level; /* per device debugging will override global
|
||||
iwl_debug_level if set */
|
||||
u32 framecnt_to_us;
|
||||
atomic_t restrict_refcnt;
|
||||
bool disable_ht40;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/* debugfs */
|
||||
u16 tx_traffic_idx;
|
||||
u16 rx_traffic_idx;
|
||||
u8 *tx_traffic;
|
||||
u8 *rx_traffic;
|
||||
struct iwl_debugfs *dbgfs;
|
||||
#endif /* CONFIG_IWLWIFI_DEBUGFS */
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
@ -1211,8 +1260,27 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
|
|||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
const char *iwl_get_tx_fail_reason(u32 status);
|
||||
/*
|
||||
* iwl_get_debug_level: Return active debug level for device
|
||||
*
|
||||
* Using sysfs it is possible to set per device debug level. This debug
|
||||
* level will be used if set, otherwise the global debug level which can be
|
||||
* set via module parameter is used.
|
||||
*/
|
||||
static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
|
||||
{
|
||||
if (priv->debug_level)
|
||||
return priv->debug_level;
|
||||
else
|
||||
return iwl_debug_level;
|
||||
}
|
||||
#else
|
||||
static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
|
||||
|
||||
static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
|
||||
{
|
||||
return iwl_debug_level;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -127,11 +127,11 @@ static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */
|
|||
145, 149, 153, 157, 161, 165
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */
|
||||
static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */
|
||||
1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */
|
||||
static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
|
||||
36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
|
||||
};
|
||||
|
||||
|
@ -462,13 +462,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
|
|||
iwl_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwl_eeprom_band_5;
|
||||
break;
|
||||
case 6: /* 2.4GHz FAT channels */
|
||||
case 6: /* 2.4GHz ht40 channels */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwl_eeprom_band_6;
|
||||
break;
|
||||
case 7: /* 5 GHz FAT channels */
|
||||
case 7: /* 5 GHz ht40 channels */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_eeprom_query_addr(priv, offset);
|
||||
|
@ -484,14 +484,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
|
|||
? # x " " : "")
|
||||
|
||||
/**
|
||||
* iwl_set_fat_chan_info - Copy fat channel info into driver's priv.
|
||||
* iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv.
|
||||
*
|
||||
* Does not set up a command, or touch hardware.
|
||||
*/
|
||||
static int iwl_set_fat_chan_info(struct iwl_priv *priv,
|
||||
static int iwl_set_ht40_chan_info(struct iwl_priv *priv,
|
||||
enum ieee80211_band band, u16 channel,
|
||||
const struct iwl_eeprom_channel *eeprom_ch,
|
||||
u8 fat_extension_channel)
|
||||
u8 ht40_extension_channel)
|
||||
{
|
||||
struct iwl_channel_info *ch_info;
|
||||
|
||||
|
@ -501,7 +501,7 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv,
|
|||
if (!is_channel_valid(ch_info))
|
||||
return -1;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
|
||||
IWL_DEBUG_INFO(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
|
||||
" Ad-Hoc %ssupported\n",
|
||||
ch_info->channel,
|
||||
is_channel_a_band(ch_info) ?
|
||||
|
@ -517,13 +517,13 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv,
|
|||
&& !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
|
||||
"" : "not ");
|
||||
|
||||
ch_info->fat_eeprom = *eeprom_ch;
|
||||
ch_info->fat_max_power_avg = eeprom_ch->max_power_avg;
|
||||
ch_info->fat_curr_txpow = eeprom_ch->max_power_avg;
|
||||
ch_info->fat_min_power = 0;
|
||||
ch_info->fat_scan_power = eeprom_ch->max_power_avg;
|
||||
ch_info->fat_flags = eeprom_ch->flags;
|
||||
ch_info->fat_extension_channel = fat_extension_channel;
|
||||
ch_info->ht40_eeprom = *eeprom_ch;
|
||||
ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
|
||||
ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg;
|
||||
ch_info->ht40_min_power = 0;
|
||||
ch_info->ht40_scan_power = eeprom_ch->max_power_avg;
|
||||
ch_info->ht40_flags = eeprom_ch->flags;
|
||||
ch_info->ht40_extension_channel = ht40_extension_channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -589,9 +589,9 @@ int iwl_init_channel_map(struct iwl_priv *priv)
|
|||
/* Copy the run-time flags so they are there even on
|
||||
* invalid channels */
|
||||
ch_info->flags = eeprom_ch_info[ch].flags;
|
||||
/* First write that fat is not enabled, and then enable
|
||||
/* First write that ht40 is not enabled, and then enable
|
||||
* one by one */
|
||||
ch_info->fat_extension_channel =
|
||||
ch_info->ht40_extension_channel =
|
||||
(IEEE80211_CHAN_NO_HT40PLUS |
|
||||
IEEE80211_CHAN_NO_HT40MINUS);
|
||||
|
||||
|
@ -642,17 +642,17 @@ int iwl_init_channel_map(struct iwl_priv *priv)
|
|||
}
|
||||
}
|
||||
|
||||
/* Check if we do have FAT channels */
|
||||
/* Check if we do have HT40 channels */
|
||||
if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] ==
|
||||
EEPROM_REGULATORY_BAND_NO_FAT &&
|
||||
EEPROM_REGULATORY_BAND_NO_HT40 &&
|
||||
priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] ==
|
||||
EEPROM_REGULATORY_BAND_NO_FAT)
|
||||
EEPROM_REGULATORY_BAND_NO_HT40)
|
||||
return 0;
|
||||
|
||||
/* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
|
||||
/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
|
||||
for (band = 6; band <= 7; band++) {
|
||||
enum ieee80211_band ieeeband;
|
||||
u8 fat_extension_chan;
|
||||
u8 ht40_extension_chan;
|
||||
|
||||
iwl_init_band_reference(priv, band, &eeprom_ch_count,
|
||||
&eeprom_ch_info, &eeprom_ch_index);
|
||||
|
@ -669,19 +669,19 @@ int iwl_init_channel_map(struct iwl_priv *priv)
|
|||
(eeprom_ch_index[ch] == 6) ||
|
||||
(eeprom_ch_index[ch] == 7)))
|
||||
/* both are allowed: above and below */
|
||||
fat_extension_chan = 0;
|
||||
ht40_extension_chan = 0;
|
||||
else
|
||||
fat_extension_chan =
|
||||
ht40_extension_chan =
|
||||
IEEE80211_CHAN_NO_HT40MINUS;
|
||||
|
||||
/* Set up driver's info for lower half */
|
||||
iwl_set_fat_chan_info(priv, ieeeband,
|
||||
iwl_set_ht40_chan_info(priv, ieeeband,
|
||||
eeprom_ch_index[ch],
|
||||
&(eeprom_ch_info[ch]),
|
||||
fat_extension_chan);
|
||||
ht40_extension_chan);
|
||||
|
||||
/* Set up driver's info for upper half */
|
||||
iwl_set_fat_chan_info(priv, ieeeband,
|
||||
iwl_set_ht40_chan_info(priv, ieeeband,
|
||||
(eeprom_ch_index[ch] + 4),
|
||||
&(eeprom_ch_info[ch]),
|
||||
IEEE80211_CHAN_NO_HT40PLUS);
|
||||
|
|
|
@ -88,10 +88,10 @@ struct iwl_priv;
|
|||
* requirement for establishing a new network for legal operation on channels
|
||||
* requiring RADAR detection or restricting ACTIVE scanning.
|
||||
*
|
||||
* NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels.
|
||||
* It only indicates that 20 MHz channel use is supported; FAT channel
|
||||
* NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels.
|
||||
* It only indicates that 20 MHz channel use is supported; HT40 channel
|
||||
* usage is indicated by a separate set of regulatory flags for each
|
||||
* FAT channel pair.
|
||||
* HT40 channel pair.
|
||||
*
|
||||
* NOTE: Using a channel inappropriately will result in a uCode error!
|
||||
*/
|
||||
|
@ -112,7 +112,7 @@ enum {
|
|||
#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
|
||||
|
||||
/* *regulatory* channel data format in eeprom, one for each channel.
|
||||
* There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */
|
||||
* There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */
|
||||
struct iwl_eeprom_channel {
|
||||
u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
|
||||
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
|
||||
|
@ -170,9 +170,9 @@ struct iwl_eeprom_channel {
|
|||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
|
||||
#define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */
|
||||
#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\
|
||||
#define EEPROM_5000_REG_BAND_24_HT40_CHANNELS ((0x82)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */
|
||||
#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\
|
||||
#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
|
||||
|
||||
/* 5050 Specific */
|
||||
|
@ -313,7 +313,7 @@ struct iwl_eeprom_calib_info {
|
|||
* in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
|
||||
* txpower (MSB).
|
||||
*
|
||||
* Entries immediately below are for 20 MHz channel width. FAT (40 MHz)
|
||||
* Entries immediately below are for 20 MHz channel width. HT40 (40 MHz)
|
||||
* channels (only for 4965, not supported by 3945) appear later in the EEPROM.
|
||||
*
|
||||
* 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
|
@ -352,29 +352,29 @@ struct iwl_eeprom_calib_info {
|
|||
#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
|
||||
|
||||
/*
|
||||
* 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
|
||||
* 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
|
||||
*
|
||||
* The channel listed is the center of the lower 20 MHz half of the channel.
|
||||
* The overall center frequency is actually 2 channels (10 MHz) above that,
|
||||
* and the upper half of each FAT channel is centered 4 channels (20 MHz) away
|
||||
* from the lower half; e.g. the upper half of FAT channel 1 is channel 5,
|
||||
* and the overall FAT channel width centers on channel 3.
|
||||
* and the upper half of each HT40 channel is centered 4 channels (20 MHz) away
|
||||
* from the lower half; e.g. the upper half of HT40 channel 1 is channel 5,
|
||||
* and the overall HT40 channel width centers on channel 3.
|
||||
*
|
||||
* NOTE: The RXON command uses 20 MHz channel numbers to specify the
|
||||
* control channel to which to tune. RXON also specifies whether the
|
||||
* control channel is the upper or lower half of a FAT channel.
|
||||
* control channel is the upper or lower half of a HT40 channel.
|
||||
*
|
||||
* NOTE: 4965 does not support FAT channels on 2.4 GHz.
|
||||
* NOTE: 4965 does not support HT40 channels on 2.4 GHz.
|
||||
*/
|
||||
#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */
|
||||
#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */
|
||||
|
||||
/*
|
||||
* 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64),
|
||||
* 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64),
|
||||
* 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
|
||||
*/
|
||||
#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */
|
||||
#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */
|
||||
|
||||
#define EEPROM_REGULATORY_BAND_NO_FAT (0)
|
||||
#define EEPROM_REGULATORY_BAND_NO_HT40 (0)
|
||||
|
||||
struct iwl_eeprom_ops {
|
||||
const u32 regulatory_bands[7];
|
||||
|
|
|
@ -36,8 +36,6 @@
|
|||
#include "iwl-core.h"
|
||||
|
||||
|
||||
#define IWL_CMD(x) case x: return #x
|
||||
|
||||
const char *get_cmd_string(u8 cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
|
|
|
@ -272,7 +272,8 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
|
|||
/* count both tx and rx traffic to be able to
|
||||
* handle traffic in either direction
|
||||
*/
|
||||
u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
|
||||
u64 current_tpt = priv->tx_stats.data_bytes +
|
||||
priv->rx_stats.data_bytes;
|
||||
s64 tpt = current_tpt - priv->led_tpt;
|
||||
|
||||
if (tpt < 0) /* wraparound */
|
||||
|
|
|
@ -42,20 +42,35 @@
|
|||
#include "iwl-power.h"
|
||||
|
||||
/*
|
||||
* Setting power level allow the card to go to sleep when not busy.
|
||||
* Setting power level allows the card to go to sleep when not busy.
|
||||
*
|
||||
* The power level is set to INDEX_1 (the least deep state) by
|
||||
* default, and will, in the future, be the deepest state unless
|
||||
* otherwise required by pm_qos network latency requirements.
|
||||
*
|
||||
* Using INDEX_1 without pm_qos is ok because mac80211 will disable
|
||||
* PS when even checking every beacon for the TIM bit would exceed
|
||||
* the required latency.
|
||||
* We calculate a sleep command based on the required latency, which
|
||||
* we get from mac80211. In order to handle thermal throttling, we can
|
||||
* also use pre-defined power levels.
|
||||
*/
|
||||
|
||||
#define IWL_POWER_RANGE_0_MAX (2)
|
||||
#define IWL_POWER_RANGE_1_MAX (10)
|
||||
/*
|
||||
* For now, keep using power level 1 instead of automatically
|
||||
* adjusting ...
|
||||
*/
|
||||
bool no_sleep_autoadjust = true;
|
||||
module_param(no_sleep_autoadjust, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(no_sleep_autoadjust,
|
||||
"don't automatically adjust sleep level "
|
||||
"according to maximum network latency");
|
||||
|
||||
/*
|
||||
* This defines the old power levels. They are still used by default
|
||||
* (level 1) and for thermal throttle (levels 3 through 5)
|
||||
*/
|
||||
|
||||
struct iwl_power_vec_entry {
|
||||
struct iwl_powertable_cmd cmd;
|
||||
u8 no_dtim;
|
||||
};
|
||||
|
||||
#define IWL_DTIM_RANGE_0_MAX 2
|
||||
#define IWL_DTIM_RANGE_1_MAX 10
|
||||
|
||||
#define NOSLP cpu_to_le16(0), 0, 0
|
||||
#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
|
||||
|
@ -67,9 +82,8 @@
|
|||
cpu_to_le32(X3), \
|
||||
cpu_to_le32(X4)}
|
||||
/* default power management (not Tx power) table values */
|
||||
/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */
|
||||
/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
|
||||
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
|
||||
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
|
||||
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
|
||||
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
|
||||
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
|
||||
|
@ -78,9 +92,8 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
|
|||
};
|
||||
|
||||
|
||||
/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */
|
||||
/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
|
||||
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
|
||||
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
|
||||
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
|
||||
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
|
||||
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
|
||||
|
@ -88,9 +101,8 @@ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
|
|||
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
|
||||
};
|
||||
|
||||
/* for DTIM period > IWL_POWER_RANGE_1_MAX */
|
||||
/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
|
||||
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
|
||||
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
|
||||
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
|
||||
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
|
||||
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
|
||||
|
@ -98,6 +110,56 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
|
|||
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
|
||||
};
|
||||
|
||||
static void iwl_static_sleep_cmd(struct iwl_priv *priv,
|
||||
struct iwl_powertable_cmd *cmd,
|
||||
enum iwl_power_level lvl, int period)
|
||||
{
|
||||
const struct iwl_power_vec_entry *table;
|
||||
int max_sleep, i;
|
||||
bool skip;
|
||||
|
||||
table = range_2;
|
||||
if (period < IWL_DTIM_RANGE_1_MAX)
|
||||
table = range_1;
|
||||
if (period < IWL_DTIM_RANGE_0_MAX)
|
||||
table = range_0;
|
||||
|
||||
BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
|
||||
|
||||
*cmd = table[lvl].cmd;
|
||||
|
||||
if (period == 0) {
|
||||
skip = false;
|
||||
period = 1;
|
||||
} else {
|
||||
skip = !!table[lvl].no_dtim;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
|
||||
max_sleep = le32_to_cpu(slp_itrvl);
|
||||
if (max_sleep == 0xFF)
|
||||
max_sleep = period * (skip + 1);
|
||||
else if (max_sleep > period)
|
||||
max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
|
||||
cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
|
||||
} else {
|
||||
max_sleep = period;
|
||||
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
|
||||
}
|
||||
|
||||
for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
|
||||
if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
|
||||
cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
|
||||
|
||||
if (priv->power_data.pci_pm)
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
else
|
||||
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
|
||||
}
|
||||
|
||||
/* default Thermal Throttling transaction table
|
||||
* Current state | Throttling Down | Throttling Up
|
||||
*=============================================================================
|
||||
|
@ -132,104 +194,50 @@ static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
|
|||
|
||||
/* Advance Thermal Throttling default restriction table */
|
||||
static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
|
||||
{IWL_TX_MULTI, true, IWL_RX_MULTI},
|
||||
{IWL_TX_SINGLE, true, IWL_RX_MULTI},
|
||||
{IWL_TX_SINGLE, false, IWL_RX_SINGLE},
|
||||
{IWL_TX_NONE, false, IWL_RX_NONE}
|
||||
{IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
|
||||
{IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
|
||||
{IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
|
||||
{IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
|
||||
};
|
||||
|
||||
/* set card power command */
|
||||
static int iwl_set_power(struct iwl_priv *priv, void *cmd)
|
||||
|
||||
static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
|
||||
struct iwl_powertable_cmd *cmd)
|
||||
{
|
||||
return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
|
||||
sizeof(struct iwl_powertable_cmd), cmd);
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
|
||||
if (priv->power_data.pci_pm)
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
|
||||
}
|
||||
|
||||
/* initialize to default */
|
||||
static void iwl_power_init_handle(struct iwl_priv *priv)
|
||||
static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv,
|
||||
struct iwl_powertable_cmd *cmd,
|
||||
int dynps_ms, int wakeup_period)
|
||||
{
|
||||
struct iwl_power_mgr *pow_data;
|
||||
int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM;
|
||||
struct iwl_powertable_cmd *cmd;
|
||||
int i;
|
||||
u16 lctl;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Initialize power \n");
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
|
||||
pow_data = &priv->power_data;
|
||||
cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK |
|
||||
IWL_POWER_FAST_PD; /* no use seeing frames for others */
|
||||
|
||||
memset(pow_data, 0, sizeof(*pow_data));
|
||||
if (priv->power_data.pci_pm)
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
|
||||
memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
|
||||
memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
|
||||
memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
|
||||
|
||||
lctl = iwl_pcie_link_ctl(priv);
|
||||
|
||||
IWL_DEBUG_POWER(priv, "adjust power command flags\n");
|
||||
|
||||
for (i = 0; i < IWL_POWER_NUM; i++) {
|
||||
cmd = &pow_data->pwr_range_0[i].cmd;
|
||||
|
||||
if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
|
||||
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
|
||||
else
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
}
|
||||
}
|
||||
|
||||
/* adjust power command according to DTIM period and power level*/
|
||||
static int iwl_update_power_cmd(struct iwl_priv *priv,
|
||||
struct iwl_powertable_cmd *cmd, u16 mode)
|
||||
{
|
||||
struct iwl_power_vec_entry *range;
|
||||
struct iwl_power_mgr *pow_data;
|
||||
int i;
|
||||
u32 max_sleep = 0;
|
||||
u8 period;
|
||||
bool skip;
|
||||
|
||||
if (mode > IWL_POWER_INDEX_5) {
|
||||
IWL_DEBUG_POWER(priv, "Error invalid power mode \n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pow_data = &priv->power_data;
|
||||
|
||||
if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX)
|
||||
range = &pow_data->pwr_range_0[0];
|
||||
else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX)
|
||||
range = &pow_data->pwr_range_1[0];
|
||||
else
|
||||
range = &pow_data->pwr_range_2[0];
|
||||
|
||||
period = pow_data->dtim_period;
|
||||
memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
|
||||
|
||||
if (period == 0) {
|
||||
period = 1;
|
||||
skip = false;
|
||||
} else {
|
||||
skip = !!range[mode].no_dtim;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
|
||||
max_sleep = le32_to_cpu(slp_itrvl);
|
||||
if (max_sleep == 0xFF)
|
||||
max_sleep = period * (skip + 1);
|
||||
else if (max_sleep > period)
|
||||
max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
|
||||
cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
|
||||
} else {
|
||||
max_sleep = period;
|
||||
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
|
||||
}
|
||||
cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms);
|
||||
cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms);
|
||||
|
||||
for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
|
||||
if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
|
||||
cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
|
||||
cmd->sleep_interval[i] = cpu_to_le32(wakeup_period);
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Automatic sleep command\n");
|
||||
}
|
||||
|
||||
static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
|
||||
{
|
||||
IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
|
||||
IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
|
||||
IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
|
||||
IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
|
||||
|
@ -240,113 +248,107 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
|
|||
le32_to_cpu(cmd->sleep_interval[3]),
|
||||
le32_to_cpu(cmd->sleep_interval[4]));
|
||||
|
||||
return 0;
|
||||
return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
|
||||
sizeof(struct iwl_powertable_cmd), cmd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* compute the final power mode index
|
||||
*/
|
||||
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
||||
{
|
||||
struct iwl_power_mgr *setting = &(priv->power_data);
|
||||
int ret = 0;
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
u16 uninitialized_var(final_mode);
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) &&
|
||||
(priv->hw->conf.flags & IEEE80211_CONF_PS);
|
||||
bool update_chains;
|
||||
struct iwl_powertable_cmd cmd;
|
||||
int dtimper;
|
||||
|
||||
/* Don't update the RX chain when chain noise calibration is running */
|
||||
update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
|
||||
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
|
||||
|
||||
final_mode = priv->power_data.user_power_setting;
|
||||
if (priv->vif)
|
||||
dtimper = priv->vif->bss_conf.dtim_period;
|
||||
else
|
||||
dtimper = 1;
|
||||
|
||||
if (setting->power_disabled)
|
||||
final_mode = IWL_POWER_MODE_CAM;
|
||||
/* TT power setting overwrites everything */
|
||||
if (tt->state >= IWL_TI_1)
|
||||
iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
|
||||
else if (!enabled)
|
||||
iwl_power_sleep_cam_cmd(priv, &cmd);
|
||||
else if (priv->power_data.debug_sleep_level_override >= 0)
|
||||
iwl_static_sleep_cmd(priv, &cmd,
|
||||
priv->power_data.debug_sleep_level_override,
|
||||
dtimper);
|
||||
else if (no_sleep_autoadjust)
|
||||
iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper);
|
||||
else
|
||||
iwl_power_fill_sleep_cmd(priv, &cmd,
|
||||
priv->hw->conf.dynamic_ps_timeout,
|
||||
priv->hw->conf.max_sleep_period);
|
||||
|
||||
if (tt->state >= IWL_TI_1) {
|
||||
/* TT power setting overwrite user & system power setting */
|
||||
final_mode = tt->tt_power_mode;
|
||||
}
|
||||
if (iwl_is_ready_rf(priv) &&
|
||||
((setting->power_mode != final_mode) || force)) {
|
||||
struct iwl_powertable_cmd cmd;
|
||||
|
||||
if (final_mode != IWL_POWER_MODE_CAM)
|
||||
(memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) {
|
||||
if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
|
||||
set_bit(STATUS_POWER_PMI, &priv->status);
|
||||
|
||||
iwl_update_power_cmd(priv, &cmd, final_mode);
|
||||
cmd.keep_alive_beacons = 0;
|
||||
|
||||
if (final_mode == IWL_POWER_INDEX_5)
|
||||
cmd.flags |= IWL_POWER_FAST_PD;
|
||||
|
||||
ret = iwl_set_power(priv, &cmd);
|
||||
if (!ret) {
|
||||
if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
|
||||
clear_bit(STATUS_POWER_PMI, &priv->status);
|
||||
|
||||
if (final_mode == IWL_POWER_MODE_CAM)
|
||||
clear_bit(STATUS_POWER_PMI, &priv->status);
|
||||
|
||||
if (priv->cfg->ops->lib->update_chain_flags && update_chains)
|
||||
priv->cfg->ops->lib->update_chain_flags(priv);
|
||||
else
|
||||
IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise "
|
||||
if (priv->cfg->ops->lib->update_chain_flags &&
|
||||
update_chains)
|
||||
priv->cfg->ops->lib->update_chain_flags(priv);
|
||||
else
|
||||
IWL_DEBUG_POWER(priv,
|
||||
"Cannot update the power, chain noise "
|
||||
"calibration running: %d\n",
|
||||
priv->chain_noise_data.state);
|
||||
if (!ret)
|
||||
setting->power_mode = final_mode;
|
||||
memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd));
|
||||
} else
|
||||
IWL_ERR(priv, "set power fail, ret = %d", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_power_update_mode);
|
||||
|
||||
/* set user_power_setting */
|
||||
int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
|
||||
{
|
||||
if (mode >= IWL_POWER_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
priv->power_data.user_power_setting = mode;
|
||||
|
||||
return iwl_power_update_mode(priv, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_power_set_user_mode);
|
||||
|
||||
bool iwl_ht_enabled(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
struct iwl_tt_restriction *restriction;
|
||||
|
||||
if (!priv->power_data.adv_tt)
|
||||
if (!priv->thermal_throttle.advanced_tt)
|
||||
return true;
|
||||
restriction = tt->restriction + tt->state;
|
||||
return restriction->is_ht;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_ht_enabled);
|
||||
|
||||
u8 iwl_tx_ant_restriction(struct iwl_priv *priv)
|
||||
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
struct iwl_tt_restriction *restriction;
|
||||
|
||||
if (!priv->power_data.adv_tt)
|
||||
return IWL_TX_MULTI;
|
||||
if (!priv->thermal_throttle.advanced_tt)
|
||||
return IWL_ANT_OK_MULTI;
|
||||
restriction = tt->restriction + tt->state;
|
||||
return restriction->tx_stream;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_tx_ant_restriction);
|
||||
|
||||
u8 iwl_rx_ant_restriction(struct iwl_priv *priv)
|
||||
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
struct iwl_tt_restriction *restriction;
|
||||
|
||||
if (!priv->power_data.adv_tt)
|
||||
return IWL_RX_MULTI;
|
||||
if (!priv->thermal_throttle.advanced_tt)
|
||||
return IWL_ANT_OK_MULTI;
|
||||
restriction = tt->restriction + tt->state;
|
||||
return restriction->rx_stream;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_rx_ant_restriction);
|
||||
|
||||
#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
|
||||
|
||||
|
@ -361,21 +363,21 @@ EXPORT_SYMBOL(iwl_rx_ant_restriction);
|
|||
static void iwl_tt_check_exit_ct_kill(unsigned long data)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)data;
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
unsigned long flags;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (tt->state == IWL_TI_CT_KILL) {
|
||||
if (priv->power_data.ct_kill_toggle) {
|
||||
if (priv->thermal_throttle.ct_kill_toggle) {
|
||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
|
||||
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
||||
priv->power_data.ct_kill_toggle = false;
|
||||
priv->thermal_throttle.ct_kill_toggle = false;
|
||||
} else {
|
||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
|
||||
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
||||
priv->power_data.ct_kill_toggle = true;
|
||||
priv->thermal_throttle.ct_kill_toggle = true;
|
||||
}
|
||||
iwl_read32(priv, CSR_UCODE_DRV_GP1);
|
||||
spin_lock_irqsave(&priv->reg_lock, flags);
|
||||
|
@ -386,7 +388,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
|
|||
/* Reschedule the ct_kill timer to occur in
|
||||
* CT_KILL_EXIT_DURATION seconds to ensure we get a
|
||||
* thermal update */
|
||||
mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
|
||||
mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
|
||||
CT_KILL_EXIT_DURATION * HZ);
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +402,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
|
|||
ieee80211_stop_queues(priv->hw);
|
||||
IWL_DEBUG_POWER(priv,
|
||||
"Schedule 5 seconds CT_KILL Timer\n");
|
||||
mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
|
||||
mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
|
||||
CT_KILL_EXIT_DURATION * HZ);
|
||||
} else {
|
||||
IWL_DEBUG_POWER(priv, "Wake all queues\n");
|
||||
|
@ -424,9 +426,8 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
|
|||
*/
|
||||
static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
enum iwl_tt_state new_state;
|
||||
struct iwl_power_mgr *setting = &priv->power_data;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
enum iwl_tt_state old_state;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if ((tt->tt_previous_temp) &&
|
||||
|
@ -438,38 +439,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
|
|||
(temp - tt->tt_previous_temp));
|
||||
}
|
||||
#endif
|
||||
old_state = tt->state;
|
||||
/* in Celsius */
|
||||
if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
|
||||
new_state = IWL_TI_CT_KILL;
|
||||
tt->state = IWL_TI_CT_KILL;
|
||||
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
|
||||
new_state = IWL_TI_2;
|
||||
tt->state = IWL_TI_2;
|
||||
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
|
||||
new_state = IWL_TI_1;
|
||||
tt->state = IWL_TI_1;
|
||||
else
|
||||
new_state = IWL_TI_0;
|
||||
tt->state = IWL_TI_0;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
tt->tt_previous_temp = temp;
|
||||
#endif
|
||||
if (tt->state != new_state) {
|
||||
if (tt->state == IWL_TI_0) {
|
||||
tt->sys_power_mode = setting->power_mode;
|
||||
IWL_DEBUG_POWER(priv, "current power mode: %u\n",
|
||||
setting->power_mode);
|
||||
}
|
||||
switch (new_state) {
|
||||
if (tt->state != old_state) {
|
||||
switch (tt->state) {
|
||||
case IWL_TI_0:
|
||||
/* when system ready to go back to IWL_TI_0 state
|
||||
* using system power mode instead of TT power mode
|
||||
* revert back to the orginal power mode which was saved
|
||||
* before enter Thermal Throttling state
|
||||
* update priv->power_data.user_power_setting to the
|
||||
* required power mode to make sure
|
||||
* iwl_power_update_mode() will update power correctly.
|
||||
/*
|
||||
* When the system is ready to go back to IWL_TI_0
|
||||
* we only have to call iwl_power_update_mode() to
|
||||
* do so.
|
||||
*/
|
||||
priv->power_data.user_power_setting =
|
||||
tt->sys_power_mode;
|
||||
tt->tt_power_mode = tt->sys_power_mode;
|
||||
break;
|
||||
case IWL_TI_1:
|
||||
tt->tt_power_mode = IWL_POWER_INDEX_3;
|
||||
|
@ -481,24 +472,26 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
|
|||
tt->tt_power_mode = IWL_POWER_INDEX_5;
|
||||
break;
|
||||
}
|
||||
mutex_lock(&priv->mutex);
|
||||
if (iwl_power_update_mode(priv, true)) {
|
||||
/* TT state not updated
|
||||
* try again during next temperature read
|
||||
*/
|
||||
tt->state = old_state;
|
||||
IWL_ERR(priv, "Cannot update power mode, "
|
||||
"TT state not updated\n");
|
||||
} else {
|
||||
if (new_state == IWL_TI_CT_KILL)
|
||||
if (tt->state == IWL_TI_CT_KILL)
|
||||
iwl_perform_ct_kill_task(priv, true);
|
||||
else if (tt->state == IWL_TI_CT_KILL &&
|
||||
new_state != IWL_TI_CT_KILL)
|
||||
else if (old_state == IWL_TI_CT_KILL &&
|
||||
tt->state != IWL_TI_CT_KILL)
|
||||
iwl_perform_ct_kill_task(priv, false);
|
||||
tt->state = new_state;
|
||||
IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
|
||||
tt->state);
|
||||
IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
|
||||
tt->tt_power_mode);
|
||||
}
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,7 +518,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
|
|||
*/
|
||||
static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
int i;
|
||||
bool changed = false;
|
||||
enum iwl_tt_state old_state;
|
||||
|
@ -570,20 +563,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
|||
}
|
||||
if (changed) {
|
||||
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
|
||||
struct iwl_power_mgr *setting = &priv->power_data;
|
||||
|
||||
if (tt->state >= IWL_TI_1) {
|
||||
/* if switching from IWL_TI_0 to other TT state
|
||||
* save previous power setting in tt->sys_power_mode */
|
||||
if (old_state == IWL_TI_0)
|
||||
tt->sys_power_mode = setting->power_mode;
|
||||
/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
|
||||
tt->tt_power_mode = IWL_POWER_INDEX_5;
|
||||
if (!iwl_ht_enabled(priv))
|
||||
/* disable HT */
|
||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
|
||||
RXON_FLG_FAT_PROT_MSK |
|
||||
RXON_FLG_HT40_PROT_MSK |
|
||||
RXON_FLG_HT_PROT_MSK);
|
||||
else {
|
||||
/* check HT capability and set
|
||||
|
@ -593,22 +581,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
|||
}
|
||||
|
||||
} else {
|
||||
/* restore system power setting */
|
||||
/* the previous power mode was saved in
|
||||
* tt->sys_power_mode when system move into
|
||||
* Thermal Throttling state
|
||||
* set power_data.user_power_setting to the previous
|
||||
* system power mode to make sure power will get
|
||||
* updated correctly
|
||||
/*
|
||||
* restore system power setting -- it will be
|
||||
* recalculated automatically.
|
||||
*/
|
||||
priv->power_data.user_power_setting =
|
||||
tt->sys_power_mode;
|
||||
tt->tt_power_mode = tt->sys_power_mode;
|
||||
|
||||
/* check HT capability and set
|
||||
* according to the system HT capability
|
||||
* in case get disabled before */
|
||||
iwl_set_rxon_ht(priv, &priv->current_ht_config);
|
||||
}
|
||||
mutex_lock(&priv->mutex);
|
||||
if (iwl_power_update_mode(priv, true)) {
|
||||
/* TT state not updated
|
||||
* try again during next temperature read
|
||||
|
@ -631,6 +614,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
|||
iwl_perform_ct_kill_task(priv, false);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,17 +628,21 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
|||
* for advance mode
|
||||
* pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
|
||||
*/
|
||||
void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
|
||||
static void iwl_bg_ct_enter(struct work_struct *work)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (!iwl_is_ready(priv))
|
||||
return;
|
||||
|
||||
if (tt->state != IWL_TI_CT_KILL) {
|
||||
IWL_ERR(priv, "Device reached critical temperature "
|
||||
"- ucode going to sleep!\n");
|
||||
if (!priv->power_data.adv_tt)
|
||||
if (!priv->thermal_throttle.advanced_tt)
|
||||
iwl_legacy_tt_handler(priv,
|
||||
IWL_MINIMAL_POWER_THRESHOLD);
|
||||
else
|
||||
|
@ -662,38 +650,61 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
|
|||
CT_KILL_THRESHOLD + 1);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
|
||||
|
||||
/* Card State Notification indicated out of critical temperature
|
||||
* since Card State Notification will not provide any temperature reading
|
||||
* so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
|
||||
* to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
|
||||
*/
|
||||
void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
|
||||
static void iwl_bg_ct_exit(struct work_struct *work)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
if (!iwl_is_ready(priv))
|
||||
return;
|
||||
|
||||
/* stop ct_kill_exit_tm timer */
|
||||
del_timer_sync(&priv->power_data.ct_kill_exit_tm);
|
||||
del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
|
||||
|
||||
if (tt->state == IWL_TI_CT_KILL) {
|
||||
IWL_ERR(priv,
|
||||
"Device temperature below critical"
|
||||
"- ucode awake!\n");
|
||||
if (!priv->power_data.adv_tt)
|
||||
if (!priv->thermal_throttle.advanced_tt)
|
||||
iwl_legacy_tt_handler(priv,
|
||||
IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
|
||||
else
|
||||
iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
|
||||
{
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
|
||||
queue_work(priv->workqueue, &priv->ct_enter);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
|
||||
|
||||
void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
|
||||
{
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
|
||||
queue_work(priv->workqueue, &priv->ct_exit);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
|
||||
|
||||
void iwl_tt_handler(struct iwl_priv *priv)
|
||||
static void iwl_bg_tt_work(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
|
||||
s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
|
@ -702,11 +713,20 @@ void iwl_tt_handler(struct iwl_priv *priv)
|
|||
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
|
||||
temp = KELVIN_TO_CELSIUS(priv->temperature);
|
||||
|
||||
if (!priv->power_data.adv_tt)
|
||||
if (!priv->thermal_throttle.advanced_tt)
|
||||
iwl_legacy_tt_handler(priv, temp);
|
||||
else
|
||||
iwl_advance_tt_handler(priv, temp);
|
||||
}
|
||||
|
||||
void iwl_tt_handler(struct iwl_priv *priv)
|
||||
{
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
|
||||
queue_work(priv->workqueue, &priv->tt_work);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_tt_handler);
|
||||
|
||||
/* Thermal throttling initialization
|
||||
|
@ -716,8 +736,7 @@ EXPORT_SYMBOL(iwl_tt_handler);
|
|||
*/
|
||||
void iwl_tt_initialize(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_power_mgr *setting = &priv->power_data;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
|
||||
struct iwl_tt_trans *transaction;
|
||||
|
||||
|
@ -726,11 +745,15 @@ void iwl_tt_initialize(struct iwl_priv *priv)
|
|||
memset(tt, 0, sizeof(struct iwl_tt_mgmt));
|
||||
|
||||
tt->state = IWL_TI_0;
|
||||
tt->sys_power_mode = setting->power_mode;
|
||||
tt->tt_power_mode = tt->sys_power_mode;
|
||||
init_timer(&priv->power_data.ct_kill_exit_tm);
|
||||
priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv;
|
||||
priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
|
||||
init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
|
||||
priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
|
||||
priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
|
||||
|
||||
/* setup deferred ct kill work */
|
||||
INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
|
||||
INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
|
||||
INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
|
||||
|
||||
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
|
||||
case CSR_HW_REV_TYPE_6x00:
|
||||
case CSR_HW_REV_TYPE_6x50:
|
||||
|
@ -742,7 +765,7 @@ void iwl_tt_initialize(struct iwl_priv *priv)
|
|||
GFP_KERNEL);
|
||||
if (!tt->restriction || !tt->transaction) {
|
||||
IWL_ERR(priv, "Fallback to Legacy Throttling\n");
|
||||
priv->power_data.adv_tt = false;
|
||||
priv->thermal_throttle.advanced_tt = false;
|
||||
kfree(tt->restriction);
|
||||
tt->restriction = NULL;
|
||||
kfree(tt->transaction);
|
||||
|
@ -764,12 +787,12 @@ void iwl_tt_initialize(struct iwl_priv *priv)
|
|||
IWL_TI_STATE_MAX;
|
||||
memcpy(tt->restriction,
|
||||
&restriction_range[0], size);
|
||||
priv->power_data.adv_tt = true;
|
||||
priv->thermal_throttle.advanced_tt = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
|
||||
priv->power_data.adv_tt = false;
|
||||
priv->thermal_throttle.advanced_tt = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -778,12 +801,15 @@ EXPORT_SYMBOL(iwl_tt_initialize);
|
|||
/* cleanup thermal throttling management related memory and timer */
|
||||
void iwl_tt_exit(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
|
||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||
|
||||
/* stop ct_kill_exit_tm timer if activated */
|
||||
del_timer_sync(&priv->power_data.ct_kill_exit_tm);
|
||||
del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
|
||||
cancel_work_sync(&priv->tt_work);
|
||||
cancel_work_sync(&priv->ct_enter);
|
||||
cancel_work_sync(&priv->ct_exit);
|
||||
|
||||
if (priv->power_data.adv_tt) {
|
||||
if (priv->thermal_throttle.advanced_tt) {
|
||||
/* free advance thermal throttling memory */
|
||||
kfree(tt->restriction);
|
||||
tt->restriction = NULL;
|
||||
|
@ -796,9 +822,13 @@ EXPORT_SYMBOL(iwl_tt_exit);
|
|||
/* initialize to default */
|
||||
void iwl_power_initialize(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_power_init_handle(priv);
|
||||
priv->power_data.user_power_setting = IWL_POWER_INDEX_1;
|
||||
/* default to disabled until mac80211 says otherwise */
|
||||
priv->power_data.power_disabled = 1;
|
||||
u16 lctl = iwl_pcie_link_ctl(priv);
|
||||
|
||||
priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
|
||||
|
||||
priv->power_data.debug_sleep_level_override = -1;
|
||||
|
||||
memset(&priv->power_data.sleep_cmd, 0,
|
||||
sizeof(priv->power_data.sleep_cmd));
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_power_initialize);
|
||||
|
|
|
@ -28,22 +28,17 @@
|
|||
#ifndef __iwl_power_setting_h__
|
||||
#define __iwl_power_setting_h__
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "iwl-commands.h"
|
||||
|
||||
struct iwl_priv;
|
||||
|
||||
#define IWL_ABSOLUTE_ZERO 0
|
||||
#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
|
||||
#define IWL_TT_INCREASE_MARGIN 5
|
||||
|
||||
/* Tx/Rx restrictions */
|
||||
#define IWL_TX_MULTI 0x02
|
||||
#define IWL_TX_SINGLE 0x01
|
||||
#define IWL_TX_NONE 0x00
|
||||
#define IWL_RX_MULTI 0x02
|
||||
#define IWL_RX_SINGLE 0x01
|
||||
#define IWL_RX_NONE 0x00
|
||||
enum iwl_antenna_ok {
|
||||
IWL_ANT_OK_NONE,
|
||||
IWL_ANT_OK_SINGLE,
|
||||
IWL_ANT_OK_MULTI,
|
||||
};
|
||||
|
||||
/* Thermal Throttling State Machine states */
|
||||
enum iwl_tt_state {
|
||||
|
@ -55,27 +50,30 @@ enum iwl_tt_state {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct iwl_tt_restriction - Thermal Throttling restriction table used
|
||||
* by advance thermal throttling management
|
||||
* based on the current thermal throttling state, determine
|
||||
* number of tx/rx streams; and the status of HT operation
|
||||
* struct iwl_tt_restriction - Thermal Throttling restriction table
|
||||
* @tx_stream: number of tx stream allowed
|
||||
* @is_ht: ht enable/disable
|
||||
* @rx_stream: number of rx stream allowed
|
||||
*
|
||||
* This table is used by advance thermal throttling management
|
||||
* based on the current thermal throttling state, and determines
|
||||
* the number of tx/rx streams and the status of HT operation.
|
||||
*/
|
||||
struct iwl_tt_restriction {
|
||||
u8 tx_stream;
|
||||
enum iwl_antenna_ok tx_stream;
|
||||
enum iwl_antenna_ok rx_stream;
|
||||
bool is_ht;
|
||||
u8 rx_stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_tt_trans - Thermal Throttling transaction table; used by
|
||||
* advance thermal throttling algorithm to determine next
|
||||
* thermal state to go based on the current temperature
|
||||
* struct iwl_tt_trans - Thermal Throttling transaction table
|
||||
* @next_state: next thermal throttling mode
|
||||
* @tt_low: low temperature threshold to change state
|
||||
* @tt_high: high temperature threshold to change state
|
||||
*
|
||||
* This is used by the advanced thermal throttling algorithm
|
||||
* to determine the next thermal state to go based on the
|
||||
* current temperature.
|
||||
*/
|
||||
struct iwl_tt_trans {
|
||||
enum iwl_tt_state next_state;
|
||||
|
@ -85,34 +83,36 @@ struct iwl_tt_trans {
|
|||
|
||||
/**
|
||||
* struct iwl_tt_mgnt - Thermal Throttling Management structure
|
||||
* @advanced_tt: advanced thermal throttle required
|
||||
* @state: current Thermal Throttling state
|
||||
* @tt_power_mode: Thermal Throttling power mode index
|
||||
* being used to set power level when
|
||||
* when thermal throttling state != IWL_TI_0
|
||||
* the tt_power_mode should set to different
|
||||
* power mode based on the current tt state
|
||||
* @sys_power_mode: previous system power mode
|
||||
* before transition into TT state
|
||||
* @tt_previous_temperature: last measured temperature
|
||||
* @iwl_tt_restriction: ptr to restriction tbl, used by advance
|
||||
* thermal throttling to determine how many tx/rx streams
|
||||
* should be used in tt state; and can HT be enabled or not
|
||||
* @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
|
||||
* state transaction
|
||||
* @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
|
||||
* @ct_kill_exit_tm: timer to exit thermal kill
|
||||
*/
|
||||
struct iwl_tt_mgmt {
|
||||
enum iwl_tt_state state;
|
||||
bool advanced_tt;
|
||||
u8 tt_power_mode;
|
||||
u8 sys_power_mode;
|
||||
bool ct_kill_toggle;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
s32 tt_previous_temp;
|
||||
#endif
|
||||
struct iwl_tt_restriction *restriction;
|
||||
struct iwl_tt_trans *transaction;
|
||||
struct timer_list ct_kill_exit_tm;
|
||||
};
|
||||
|
||||
enum {
|
||||
IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */
|
||||
enum iwl_power_level {
|
||||
IWL_POWER_INDEX_1,
|
||||
IWL_POWER_INDEX_2,
|
||||
IWL_POWER_INDEX_3,
|
||||
|
@ -121,36 +121,16 @@ enum {
|
|||
IWL_POWER_NUM
|
||||
};
|
||||
|
||||
/* Power management (not Tx power) structures */
|
||||
|
||||
struct iwl_power_vec_entry {
|
||||
struct iwl_powertable_cmd cmd;
|
||||
u8 no_dtim;
|
||||
};
|
||||
|
||||
struct iwl_power_mgr {
|
||||
struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM];
|
||||
struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM];
|
||||
struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM];
|
||||
u32 dtim_period;
|
||||
/* final power level that used to calculate final power command */
|
||||
u8 power_mode;
|
||||
u8 user_power_setting; /* set by user through sysfs */
|
||||
u8 power_disabled; /* set by mac80211's CONF_PS */
|
||||
struct iwl_tt_mgmt tt; /* Thermal Throttling Management */
|
||||
bool adv_tt; /* false: legacy mode */
|
||||
/* true: advance mode */
|
||||
bool ct_kill_toggle; /* use to toggle the CSR bit when
|
||||
* checking uCode temperature
|
||||
*/
|
||||
struct timer_list ct_kill_exit_tm;
|
||||
struct iwl_powertable_cmd sleep_cmd;
|
||||
int debug_sleep_level_override;
|
||||
bool pci_pm;
|
||||
};
|
||||
|
||||
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
|
||||
int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
|
||||
bool iwl_ht_enabled(struct iwl_priv *priv);
|
||||
u8 iwl_tx_ant_restriction(struct iwl_priv *priv);
|
||||
u8 iwl_rx_ant_restriction(struct iwl_priv *priv);
|
||||
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
|
||||
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
|
||||
void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
|
||||
void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
|
||||
void iwl_tt_handler(struct iwl_priv *priv);
|
||||
|
@ -158,4 +138,6 @@ void iwl_tt_initialize(struct iwl_priv *priv);
|
|||
void iwl_tt_exit(struct iwl_priv *priv);
|
||||
void iwl_power_initialize(struct iwl_priv *priv);
|
||||
|
||||
extern bool no_sleep_autoadjust;
|
||||
|
||||
#endif /* __iwl_power_setting_h__ */
|
||||
|
|
|
@ -544,8 +544,8 @@ void iwl_rx_statistics(struct iwl_priv *priv,
|
|||
change = ((priv->statistics.general.temperature !=
|
||||
pkt->u.stats.general.temperature) ||
|
||||
((priv->statistics.flag &
|
||||
STATISTICS_REPLY_FLG_FAT_MODE_MSK) !=
|
||||
(pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)));
|
||||
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
|
||||
(pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
|
||||
|
||||
memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
|
||||
|
||||
|
@ -645,7 +645,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
|
|||
u32 tsf_low;
|
||||
int rssi;
|
||||
|
||||
if (likely(!(iwl_debug_level & IWL_DL_RX)))
|
||||
if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
|
||||
return;
|
||||
|
||||
/* MAC header */
|
||||
|
@ -741,18 +741,10 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
|
|||
}
|
||||
}
|
||||
if (print_dump)
|
||||
iwl_print_hex_dump(IWL_DL_RX, header, length);
|
||||
iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len)
|
||||
{
|
||||
/* 0 - mgmt, 1 - cnt, 2 - data */
|
||||
int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
|
||||
priv->rx_stats[idx].cnt++;
|
||||
priv->rx_stats[idx].bytes += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns non-zero if packet should be dropped
|
||||
*/
|
||||
|
@ -930,7 +922,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
|
|||
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
|
||||
return;
|
||||
|
||||
iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len);
|
||||
iwl_update_stats(priv, false, hdr->frame_control, len);
|
||||
memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
|
||||
ieee80211_rx_irqsafe(priv->hw, rxb->skb);
|
||||
priv->alloc_rxb_skb--;
|
||||
|
@ -1060,9 +1052,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
|
|||
|
||||
/* Set "1" to report good data frames in groups of 100 */
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (unlikely(iwl_debug_level & IWL_DL_RX))
|
||||
if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
|
||||
iwl_dbg_report_frame(priv, rx_start, 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,
|
||||
(unsigned long long)rx_status.mactime);
|
||||
|
|
|
@ -214,10 +214,10 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
|
|||
sta_flags |= cpu_to_le32(
|
||||
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
|
||||
|
||||
if (iwl_is_fat_tx_allowed(priv, sta_ht_inf))
|
||||
sta_flags |= STA_FLG_FAT_EN_MSK;
|
||||
if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf))
|
||||
sta_flags |= STA_FLG_HT40_EN_MSK;
|
||||
else
|
||||
sta_flags &= ~STA_FLG_FAT_EN_MSK;
|
||||
sta_flags &= ~STA_FLG_HT40_EN_MSK;
|
||||
|
||||
priv->stations[index].sta.station_flags = sta_flags;
|
||||
done:
|
||||
|
@ -1088,7 +1088,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
|
|||
IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
|
||||
"Defaulting to broadcast...\n",
|
||||
hdr->addr1);
|
||||
iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
|
||||
iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
||||
default:
|
||||
|
|
|
@ -668,14 +668,6 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
|
|||
}
|
||||
}
|
||||
|
||||
static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len)
|
||||
{
|
||||
/* 0 - mgmt, 1 - cnt, 2 - data */
|
||||
int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
|
||||
priv->tx_stats[idx].cnt++;
|
||||
priv->tx_stats[idx].bytes += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* start REPLY_TX command process
|
||||
*/
|
||||
|
@ -808,12 +800,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
|
||||
/* TODO need this for burst mode later on */
|
||||
iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
|
||||
iwl_dbg_log_tx_data_frame(priv, len, hdr);
|
||||
|
||||
/* set is_hcca to 0; it probably will never be implemented */
|
||||
iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
|
||||
|
||||
iwl_update_tx_stats(priv, le16_to_cpu(fc), len);
|
||||
|
||||
iwl_update_stats(priv, true, fc, len);
|
||||
/*
|
||||
* Use the first empty entry in this queue's command buffer array
|
||||
* to contain the Tx command and MAC header concatenated together
|
||||
|
@ -884,8 +876,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
|
||||
le16_to_cpu(out_cmd->hdr.sequence));
|
||||
IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
|
||||
iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
|
||||
iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
|
||||
iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
|
||||
iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
|
||||
|
||||
/* Set up entry for this TFD in Tx byte-count array */
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
|
|
|
@ -598,7 +598,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
len = (u16)skb->len;
|
||||
tx->len = cpu_to_le16(len);
|
||||
|
||||
|
||||
iwl_dbg_log_tx_data_frame(priv, len, hdr);
|
||||
iwl_update_stats(priv, true, fc, len);
|
||||
tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
|
||||
tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
|
||||
|
||||
|
@ -614,8 +615,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
|
||||
le16_to_cpu(out_cmd->hdr.sequence));
|
||||
IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags));
|
||||
iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx));
|
||||
iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr,
|
||||
iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
|
||||
iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
|
||||
ieee80211_hdrlen(fc));
|
||||
|
||||
/*
|
||||
|
@ -1646,7 +1647,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
|||
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & IWL_DL_ISR) {
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
|
||||
/* just for debug */
|
||||
inta_mask = iwl_read32(priv, CSR_INT_MASK);
|
||||
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
|
||||
|
@ -1681,7 +1682,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & (IWL_DL_ISR)) {
|
||||
if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
|
||||
/* NIC fires this, but we don't use it, redundant with WAKEUP */
|
||||
if (inta & CSR_INT_BIT_SCD) {
|
||||
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
|
||||
|
@ -1760,7 +1761,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
|||
iwl_enable_interrupts(priv);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_debug_level & (IWL_DL_ISR)) {
|
||||
if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
|
||||
inta = iwl_read32(priv, CSR_INT);
|
||||
inta_mask = iwl_read32(priv, CSR_INT_MASK);
|
||||
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
|
||||
|
@ -3311,14 +3312,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
*
|
||||
* See the level definitions in iwl for details.
|
||||
*
|
||||
* FIXME This file can be deprecated as the module parameter is
|
||||
* writable and users can thus also change the debug level
|
||||
* using the /sys/module/iwl3945/parameters/debug file.
|
||||
* The debug_level being managed using sysfs below is a per device debug
|
||||
* level that is used instead of the global debug level if it (the per
|
||||
* device debug level) is set.
|
||||
*/
|
||||
static ssize_t show_debug_level(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "0x%08X\n", iwl_debug_level);
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
|
||||
}
|
||||
static ssize_t store_debug_level(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
|
@ -3331,9 +3333,12 @@ static ssize_t store_debug_level(struct device *d,
|
|||
ret = strict_strtoul(buf, 0, &val);
|
||||
if (ret)
|
||||
IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf);
|
||||
else
|
||||
iwl_debug_level = val;
|
||||
|
||||
else {
|
||||
priv->debug_level = val;
|
||||
if (iwl_alloc_traffic_mem(priv))
|
||||
IWL_ERR(priv,
|
||||
"Not enough memory to generate traffic log\n");
|
||||
}
|
||||
return strnlen(buf, count);
|
||||
}
|
||||
|
||||
|
@ -3549,65 +3554,6 @@ static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
|
|||
store_retry_rate);
|
||||
|
||||
|
||||
static ssize_t store_power_level(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
int ret;
|
||||
unsigned long mode;
|
||||
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
ret = strict_strtoul(buf, 10, &mode);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = iwl_power_set_user_mode(priv, mode);
|
||||
if (ret) {
|
||||
IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n");
|
||||
goto out;
|
||||
}
|
||||
ret = count;
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_power_level(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
int level = priv->power_data.power_mode;
|
||||
char *p = buf;
|
||||
|
||||
p += sprintf(p, "%d\n", level);
|
||||
return p - buf + 1;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR,
|
||||
show_power_level, store_power_level);
|
||||
|
||||
#define MAX_WX_STRING 80
|
||||
|
||||
/* Values are in microsecond */
|
||||
static const s32 timeout_duration[] = {
|
||||
350000,
|
||||
250000,
|
||||
75000,
|
||||
37000,
|
||||
25000,
|
||||
};
|
||||
static const s32 period_duration[] = {
|
||||
400000,
|
||||
700000,
|
||||
1000000,
|
||||
1000000,
|
||||
1000000
|
||||
};
|
||||
|
||||
static ssize_t show_channels(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -3784,7 +3730,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
|
|||
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
|
||||
&dev_attr_measurement.attr,
|
||||
#endif
|
||||
&dev_attr_power_level.attr,
|
||||
&dev_attr_retry_rate.attr,
|
||||
&dev_attr_statistics.attr,
|
||||
&dev_attr_status.attr,
|
||||
|
@ -3849,8 +3794,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
|
|||
priv->qos_data.qos_cap.val = 0;
|
||||
|
||||
priv->rates_mask = IWL_RATES_MASK;
|
||||
/* If power management is turned on, default to CAM mode */
|
||||
priv->power_mode = IWL_POWER_MODE_CAM;
|
||||
priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
|
||||
|
||||
if (eeprom->version < EEPROM_3945_EEPROM_VERSION) {
|
||||
|
@ -3897,7 +3840,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
|
|||
/* Tell mac80211 our characteristics */
|
||||
hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM |
|
||||
IEEE80211_HW_SPECTRUM_MGMT;
|
||||
IEEE80211_HW_SPECTRUM_MGMT |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
|
@ -3975,6 +3920,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
atomic_set(&priv->restrict_refcnt, 0);
|
||||
#endif
|
||||
if (iwl_alloc_traffic_mem(priv))
|
||||
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
|
||||
|
||||
/***************************
|
||||
* 2. Initializing PCI bus
|
||||
|
@ -4137,6 +4084,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
pci_disable_device(pdev);
|
||||
out_ieee80211_free_hw:
|
||||
ieee80211_free_hw(priv->hw);
|
||||
iwl_free_traffic_mem(priv);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
@ -4192,6 +4140,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
|
|||
* until now... */
|
||||
destroy_workqueue(priv->workqueue);
|
||||
priv->workqueue = NULL;
|
||||
iwl_free_traffic_mem(priv);
|
||||
|
||||
free_irq(pdev->irq, priv);
|
||||
pci_disable_msi(pdev);
|
||||
|
|
|
@ -1176,7 +1176,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
|
|||
/* Allocate an Ethernet device and register it */
|
||||
dev = alloc_etherdev(sizeof(struct lbs_private));
|
||||
if (!dev) {
|
||||
lbs_pr_err("init ethX device failed\n");
|
||||
lbs_pr_err("init wlanX device failed\n");
|
||||
goto done;
|
||||
}
|
||||
priv = netdev_priv(dev);
|
||||
|
@ -1204,6 +1204,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
|
|||
SET_NETDEV_DEV(dev, dmdev);
|
||||
|
||||
priv->rtap_net_dev = NULL;
|
||||
strcpy(dev->name, "wlan%d");
|
||||
|
||||
lbs_deb_thread("Starting main thread...\n");
|
||||
init_waitqueue_head(&priv->waitq);
|
||||
|
|
|
@ -642,7 +642,7 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
|
|||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
|
||||
u8 tsc_arr[4][ORINOCO_SEQ_LEN];
|
||||
|
||||
if ((key < 0) || (key > 4))
|
||||
return -EINVAL;
|
||||
|
@ -768,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
|
|||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE:
|
||||
{
|
||||
struct orinoco_key keys[ORINOCO_MAX_KEYS];
|
||||
|
||||
memset(&keys, 0, sizeof(keys));
|
||||
for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
|
||||
int len = min(priv->keys[i].key_len,
|
||||
ORINOCO_MAX_KEY_SIZE);
|
||||
memcpy(&keys[i].data, priv->keys[i].key, len);
|
||||
if (len > SMALL_KEY_SIZE)
|
||||
keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
|
||||
else if (len > 0)
|
||||
keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
|
||||
else
|
||||
keys[i].len = cpu_to_le16(0);
|
||||
}
|
||||
|
||||
err = HERMES_WRITE_RECORD(hw, USER_BAP,
|
||||
HERMES_RID_CNFWEPKEYS_AGERE,
|
||||
&priv->keys);
|
||||
&keys);
|
||||
if (err)
|
||||
return err;
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
|
@ -782,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
|
|||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
case FIRMWARE_TYPE_INTERSIL:
|
||||
case FIRMWARE_TYPE_SYMBOL:
|
||||
{
|
||||
int keylen;
|
||||
int i;
|
||||
|
||||
/* Force uniform key length to work around
|
||||
* firmware bugs */
|
||||
keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
|
||||
keylen = priv->keys[priv->tx_key].key_len;
|
||||
|
||||
if (keylen > LARGE_KEY_SIZE) {
|
||||
printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
|
||||
priv->ndev->name, priv->tx_key, keylen);
|
||||
return -E2BIG;
|
||||
}
|
||||
} else if (keylen > SMALL_KEY_SIZE)
|
||||
keylen = LARGE_KEY_SIZE;
|
||||
else if (keylen > 0)
|
||||
keylen = SMALL_KEY_SIZE;
|
||||
else
|
||||
keylen = 0;
|
||||
|
||||
/* Write all 4 keys */
|
||||
for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
|
||||
u8 key[LARGE_KEY_SIZE] = { 0 };
|
||||
|
||||
memcpy(key, priv->keys[i].key,
|
||||
priv->keys[i].key_len);
|
||||
|
||||
err = hermes_write_ltv(hw, USER_BAP,
|
||||
HERMES_RID_CNFDEFAULTKEY0 + i,
|
||||
HERMES_BYTES_TO_RECLEN(keylen),
|
||||
priv->keys[i].data);
|
||||
key);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -829,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
|
|||
int auth_flag;
|
||||
int enc_flag;
|
||||
|
||||
/* Setup WEP keys for WEP and WPA */
|
||||
if (priv->encode_alg)
|
||||
/* Setup WEP keys */
|
||||
if (priv->encode_alg == ORINOCO_ALG_WEP)
|
||||
__orinoco_hw_setup_wepkeys(priv);
|
||||
|
||||
if (priv->wep_restrict)
|
||||
|
@ -840,14 +867,14 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
|
|||
|
||||
if (priv->wpa_enabled)
|
||||
enc_flag = 2;
|
||||
else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
|
||||
else if (priv->encode_alg == ORINOCO_ALG_WEP)
|
||||
enc_flag = 1;
|
||||
else
|
||||
enc_flag = 0;
|
||||
|
||||
switch (priv->firmware_type) {
|
||||
case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
|
||||
if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
|
||||
if (priv->encode_alg == ORINOCO_ALG_WEP) {
|
||||
/* Enable the shared-key authentication. */
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFAUTHENTICATION_AGERE,
|
||||
|
@ -872,7 +899,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
|
|||
|
||||
case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
|
||||
case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
|
||||
if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
|
||||
if (priv->encode_alg == ORINOCO_ALG_WEP) {
|
||||
if (priv->wep_restrict ||
|
||||
(priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
|
||||
master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
|
||||
|
@ -905,19 +932,20 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
|
|||
}
|
||||
|
||||
/* key must be 32 bytes, including the tx and rx MIC keys.
|
||||
* rsc must be 8 bytes
|
||||
* tsc must be 8 bytes or NULL
|
||||
* rsc must be NULL or up to 8 bytes
|
||||
* tsc must be NULL or up to 8 bytes
|
||||
*/
|
||||
int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
|
||||
int set_tx, u8 *key, u8 *rsc, u8 *tsc)
|
||||
int set_tx, u8 *key, u8 *rsc, size_t rsc_len,
|
||||
u8 *tsc, size_t tsc_len)
|
||||
{
|
||||
struct {
|
||||
__le16 idx;
|
||||
u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
|
||||
u8 rsc[ORINOCO_SEQ_LEN];
|
||||
u8 key[TKIP_KEYLEN];
|
||||
u8 tx_mic[MIC_KEYLEN];
|
||||
u8 rx_mic[MIC_KEYLEN];
|
||||
u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
|
||||
u8 tsc[ORINOCO_SEQ_LEN];
|
||||
} __attribute__ ((packed)) buf;
|
||||
hermes_t *hw = &priv->hw;
|
||||
int ret;
|
||||
|
@ -934,17 +962,22 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
|
|||
memcpy(buf.key, key,
|
||||
sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
|
||||
|
||||
if (rsc == NULL)
|
||||
memset(buf.rsc, 0, sizeof(buf.rsc));
|
||||
else
|
||||
memcpy(buf.rsc, rsc, sizeof(buf.rsc));
|
||||
if (rsc_len > sizeof(buf.rsc))
|
||||
rsc_len = sizeof(buf.rsc);
|
||||
|
||||
if (tsc == NULL) {
|
||||
memset(buf.tsc, 0, sizeof(buf.tsc));
|
||||
if (tsc_len > sizeof(buf.tsc))
|
||||
tsc_len = sizeof(buf.tsc);
|
||||
|
||||
memset(buf.rsc, 0, sizeof(buf.rsc));
|
||||
memset(buf.tsc, 0, sizeof(buf.tsc));
|
||||
|
||||
if (rsc != NULL)
|
||||
memcpy(buf.rsc, rsc, rsc_len);
|
||||
|
||||
if (tsc != NULL)
|
||||
memcpy(buf.tsc, tsc, tsc_len);
|
||||
else
|
||||
buf.tsc[4] = 0x10;
|
||||
} else {
|
||||
memcpy(buf.tsc, tsc, sizeof(buf.tsc));
|
||||
}
|
||||
|
||||
/* Wait upto 100ms for tx queue to empty */
|
||||
for (k = 100; k > 0; k--) {
|
||||
|
@ -970,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
|
|||
hermes_t *hw = &priv->hw;
|
||||
int err;
|
||||
|
||||
memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
|
||||
err = hermes_write_wordrec(hw, USER_BAP,
|
||||
HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
|
||||
key_idx);
|
||||
|
@ -1242,3 +1274,39 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv,
|
|||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Disassociate from node with BSSID addr */
|
||||
int orinoco_hw_disassociate(struct orinoco_private *priv,
|
||||
u8 *addr, u16 reason_code)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err;
|
||||
|
||||
struct {
|
||||
u8 addr[ETH_ALEN];
|
||||
__le16 reason_code;
|
||||
} __attribute__ ((packed)) buf;
|
||||
|
||||
/* Currently only supported by WPA enabled Agere fw */
|
||||
if (!priv->has_wpa)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memcpy(buf.addr, addr, ETH_ALEN);
|
||||
buf.reason_code = cpu_to_le16(reason_code);
|
||||
err = HERMES_WRITE_RECORD(hw, USER_BAP,
|
||||
HERMES_RID_CNFDISASSOCIATE,
|
||||
&buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
|
||||
u8 *addr)
|
||||
{
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err;
|
||||
|
||||
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
|
||||
ETH_ALEN, NULL, addr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ int __orinoco_hw_set_wap(struct orinoco_private *priv);
|
|||
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
|
||||
int __orinoco_hw_setup_enc(struct orinoco_private *priv);
|
||||
int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
|
||||
int set_tx, u8 *key, u8 *rsc, u8 *tsc);
|
||||
int set_tx, u8 *key, u8 *rsc, size_t rsc_len,
|
||||
u8 *tsc, size_t tsc_len);
|
||||
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
|
||||
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
|
||||
struct dev_addr_list *mc_list,
|
||||
|
@ -50,5 +51,9 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
|
|||
int *numrates, s32 *rates, int max);
|
||||
int orinoco_hw_trigger_scan(struct orinoco_private *priv,
|
||||
const struct cfg80211_ssid *ssid);
|
||||
int orinoco_hw_disassociate(struct orinoco_private *priv,
|
||||
u8 *addr, u16 reason_code);
|
||||
int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
|
||||
u8 *addr);
|
||||
|
||||
#endif /* _ORINOCO_HW_H_ */
|
||||
|
|
|
@ -341,12 +341,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
{
|
||||
struct orinoco_private *priv = ndev_priv(dev);
|
||||
struct net_device_stats *stats = &priv->stats;
|
||||
struct orinoco_tkip_key *key;
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
u16 txfid = priv->txfid;
|
||||
struct ethhdr *eh;
|
||||
int tx_control;
|
||||
unsigned long flags;
|
||||
int do_mic;
|
||||
|
||||
if (!netif_running(dev)) {
|
||||
printk(KERN_ERR "%s: Tx on stopped device!\n",
|
||||
|
@ -378,9 +380,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (skb->len < ETH_HLEN)
|
||||
goto drop;
|
||||
|
||||
key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
|
||||
|
||||
do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
|
||||
(key != NULL));
|
||||
|
||||
tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
|
||||
|
||||
if (priv->encode_alg == IW_ENCODE_ALG_TKIP)
|
||||
if (do_mic)
|
||||
tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
|
||||
HERMES_TXCTRL_MIC;
|
||||
|
||||
|
@ -462,7 +469,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
}
|
||||
|
||||
/* Calculate Michael MIC */
|
||||
if (priv->encode_alg == IW_ENCODE_ALG_TKIP) {
|
||||
if (do_mic) {
|
||||
u8 mic_buf[MICHAEL_MIC_LEN + 1];
|
||||
u8 *mic;
|
||||
size_t offset;
|
||||
|
@ -480,8 +487,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
len = MICHAEL_MIC_LEN;
|
||||
}
|
||||
|
||||
orinoco_mic(priv->tx_tfm_mic,
|
||||
priv->tkip_key[priv->tx_key].tx_mic,
|
||||
orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
|
||||
eh->h_dest, eh->h_source, 0 /* priority */,
|
||||
skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
|
||||
|
||||
|
@ -926,6 +932,7 @@ static void orinoco_rx(struct net_device *dev,
|
|||
|
||||
/* Calculate and check MIC */
|
||||
if (status & HERMES_RXSTAT_MIC) {
|
||||
struct orinoco_tkip_key *key;
|
||||
int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
|
||||
HERMES_MIC_KEY_ID_SHIFT);
|
||||
u8 mic[MICHAEL_MIC_LEN];
|
||||
|
@ -939,14 +946,18 @@ static void orinoco_rx(struct net_device *dev,
|
|||
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
|
||||
length -= MICHAEL_MIC_LEN;
|
||||
|
||||
orinoco_mic(priv->rx_tfm_mic,
|
||||
priv->tkip_key[key_id].rx_mic,
|
||||
desc->addr1,
|
||||
src,
|
||||
key = (struct orinoco_tkip_key *) priv->keys[key_id].key;
|
||||
|
||||
if (!key) {
|
||||
printk(KERN_WARNING "%s: Received encrypted frame from "
|
||||
"%pM using key %i, but key is not installed\n",
|
||||
dev->name, src, key_id);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src,
|
||||
0, /* priority or QoS? */
|
||||
skb->data,
|
||||
skb->len,
|
||||
&mic[0]);
|
||||
skb->data, skb->len, &mic[0]);
|
||||
|
||||
if (memcmp(mic, rxmic,
|
||||
MICHAEL_MIC_LEN)) {
|
||||
|
@ -2040,7 +2051,7 @@ int orinoco_init(struct orinoco_private *priv)
|
|||
priv->channel = 0; /* use firmware default */
|
||||
|
||||
priv->promiscuous = 0;
|
||||
priv->encode_alg = IW_ENCODE_ALG_NONE;
|
||||
priv->encode_alg = ORINOCO_ALG_NONE;
|
||||
priv->tx_key = 0;
|
||||
priv->wpa_enabled = 0;
|
||||
priv->tkip_cm_active = 0;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#define MAX_SCAN_LEN 4096
|
||||
|
||||
#define ORINOCO_SEQ_LEN 8
|
||||
#define ORINOCO_MAX_KEY_SIZE 14
|
||||
#define ORINOCO_MAX_KEYS 4
|
||||
|
||||
|
@ -42,6 +43,12 @@ struct orinoco_tkip_key {
|
|||
u8 rx_mic[MIC_KEYLEN];
|
||||
};
|
||||
|
||||
enum orinoco_alg {
|
||||
ORINOCO_ALG_NONE,
|
||||
ORINOCO_ALG_WEP,
|
||||
ORINOCO_ALG_TKIP
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
FIRMWARE_TYPE_AGERE,
|
||||
FIRMWARE_TYPE_INTERSIL,
|
||||
|
@ -107,12 +114,14 @@ struct orinoco_private {
|
|||
unsigned int do_fw_download:1;
|
||||
unsigned int broken_disableport:1;
|
||||
unsigned int broken_monitor:1;
|
||||
unsigned int prefer_port3:1;
|
||||
|
||||
/* Configuration paramaters */
|
||||
enum nl80211_iftype iw_mode;
|
||||
int prefer_port3;
|
||||
u16 encode_alg, wep_restrict, tx_key;
|
||||
struct orinoco_key keys[ORINOCO_MAX_KEYS];
|
||||
enum orinoco_alg encode_alg;
|
||||
u16 wep_restrict, tx_key;
|
||||
struct key_params keys[ORINOCO_MAX_KEYS];
|
||||
|
||||
int bitratemode;
|
||||
char nick[IW_ESSID_MAX_SIZE+1];
|
||||
char desired_essid[IW_ESSID_MAX_SIZE+1];
|
||||
|
@ -142,7 +151,6 @@ struct orinoco_private {
|
|||
u8 *wpa_ie;
|
||||
int wpa_ie_len;
|
||||
|
||||
struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS];
|
||||
struct crypto_hash *rx_tfm_mic;
|
||||
struct crypto_hash *tx_tfm_mic;
|
||||
|
||||
|
|
|
@ -22,6 +22,67 @@
|
|||
|
||||
#define MAX_RID_LEN 1024
|
||||
|
||||
/* Helper routine to record keys
|
||||
* Do not call from interrupt context */
|
||||
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)
|
||||
{
|
||||
kzfree(priv->keys[index].key);
|
||||
kzfree(priv->keys[index].seq);
|
||||
|
||||
if (key_len) {
|
||||
priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
|
||||
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);
|
||||
if (!priv->keys[index].seq)
|
||||
goto free_key;
|
||||
} else
|
||||
priv->keys[index].seq = NULL;
|
||||
|
||||
priv->keys[index].key_len = key_len;
|
||||
priv->keys[index].seq_len = seq_len;
|
||||
|
||||
if (key_len)
|
||||
memcpy(priv->keys[index].key, key, key_len);
|
||||
if (seq_len)
|
||||
memcpy(priv->keys[index].seq, seq, seq_len);
|
||||
|
||||
switch (alg) {
|
||||
case ORINOCO_ALG_TKIP:
|
||||
priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
|
||||
break;
|
||||
|
||||
case ORINOCO_ALG_WEP:
|
||||
priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
|
||||
WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
|
||||
break;
|
||||
|
||||
case ORINOCO_ALG_NONE:
|
||||
default:
|
||||
priv->keys[index].cipher = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_key:
|
||||
kfree(priv->keys[index].key);
|
||||
priv->keys[index].key = NULL;
|
||||
|
||||
nomem:
|
||||
priv->keys[index].key_len = 0;
|
||||
priv->keys[index].seq_len = 0;
|
||||
priv->keys[index].cipher = 0;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
|
||||
{
|
||||
struct orinoco_private *priv = ndev_priv(dev);
|
||||
|
@ -156,7 +217,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
|
|||
{
|
||||
struct orinoco_private *priv = ndev_priv(dev);
|
||||
|
||||
hermes_t *hw = &priv->hw;
|
||||
int err = 0;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -164,8 +224,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
|
|||
return -EBUSY;
|
||||
|
||||
ap_addr->sa_family = ARPHRD_ETHER;
|
||||
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
|
||||
ETH_ALEN, NULL, ap_addr->sa_data);
|
||||
err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
|
||||
|
||||
orinoco_unlock(priv, &flags);
|
||||
|
||||
|
@ -180,9 +239,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
|
|||
struct orinoco_private *priv = ndev_priv(dev);
|
||||
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
|
||||
int setindex = priv->tx_key;
|
||||
int encode_alg = priv->encode_alg;
|
||||
enum orinoco_alg encode_alg = priv->encode_alg;
|
||||
int restricted = priv->wep_restrict;
|
||||
u16 xlen = 0;
|
||||
int err = -EINPROGRESS; /* Call commit handler */
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -202,25 +260,17 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
|
|||
return -EBUSY;
|
||||
|
||||
/* Clear any TKIP key we have */
|
||||
if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
|
||||
if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
|
||||
(void) orinoco_clear_tkip_key(priv, setindex);
|
||||
|
||||
if (erq->length > 0) {
|
||||
if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
|
||||
index = priv->tx_key;
|
||||
|
||||
/* Adjust key length to a supported value */
|
||||
if (erq->length > SMALL_KEY_SIZE)
|
||||
xlen = LARGE_KEY_SIZE;
|
||||
else if (erq->length > 0)
|
||||
xlen = SMALL_KEY_SIZE;
|
||||
else
|
||||
xlen = 0;
|
||||
|
||||
/* Switch on WEP if off */
|
||||
if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) {
|
||||
if (encode_alg != ORINOCO_ALG_WEP) {
|
||||
setindex = index;
|
||||
encode_alg = IW_ENCODE_ALG_WEP;
|
||||
encode_alg = ORINOCO_ALG_WEP;
|
||||
}
|
||||
} else {
|
||||
/* Important note : if the user do "iwconfig eth0 enc off",
|
||||
|
@ -233,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
|
|||
}
|
||||
} else {
|
||||
/* Set the index : Check that the key is valid */
|
||||
if (priv->keys[index].len == 0) {
|
||||
if (priv->keys[index].key_len == 0) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -242,17 +292,15 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
|
|||
}
|
||||
|
||||
if (erq->flags & IW_ENCODE_DISABLED)
|
||||
encode_alg = IW_ENCODE_ALG_NONE;
|
||||
encode_alg = ORINOCO_ALG_NONE;
|
||||
if (erq->flags & IW_ENCODE_OPEN)
|
||||
restricted = 0;
|
||||
if (erq->flags & IW_ENCODE_RESTRICTED)
|
||||
restricted = 1;
|
||||
|
||||
if (erq->pointer && erq->length > 0) {
|
||||
priv->keys[index].len = cpu_to_le16(xlen);
|
||||
memset(priv->keys[index].data, 0,
|
||||
sizeof(priv->keys[index].data));
|
||||
memcpy(priv->keys[index].data, keybuf, erq->length);
|
||||
err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
|
||||
erq->length, NULL, 0);
|
||||
}
|
||||
priv->tx_key = setindex;
|
||||
|
||||
|
@ -281,7 +329,6 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
|
|||
{
|
||||
struct orinoco_private *priv = ndev_priv(dev);
|
||||
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
|
||||
u16 xlen = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!priv->has_wep)
|
||||
|
@ -303,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
|
|||
else
|
||||
erq->flags |= IW_ENCODE_OPEN;
|
||||
|
||||
xlen = le16_to_cpu(priv->keys[index].len);
|
||||
erq->length = priv->keys[index].key_len;
|
||||
|
||||
erq->length = xlen;
|
||||
|
||||
memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
|
||||
memcpy(keybuf, priv->keys[index].key, erq->length);
|
||||
|
||||
orinoco_unlock(priv, &flags);
|
||||
return 0;
|
||||
|
@ -793,7 +838,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
|
|||
int idx, alg = ext->alg, set_key = 1;
|
||||
unsigned long flags;
|
||||
int err = -EINVAL;
|
||||
u16 key_len;
|
||||
|
||||
if (orinoco_lock(priv, &flags) != 0)
|
||||
return -EBUSY;
|
||||
|
@ -825,25 +869,18 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
|
|||
/* Set the requested key first */
|
||||
switch (alg) {
|
||||
case IW_ENCODE_ALG_NONE:
|
||||
priv->encode_alg = alg;
|
||||
priv->keys[idx].len = 0;
|
||||
priv->encode_alg = ORINOCO_ALG_NONE;
|
||||
err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
|
||||
NULL, 0, NULL, 0);
|
||||
break;
|
||||
|
||||
case IW_ENCODE_ALG_WEP:
|
||||
if (ext->key_len > SMALL_KEY_SIZE)
|
||||
key_len = LARGE_KEY_SIZE;
|
||||
else if (ext->key_len > 0)
|
||||
key_len = SMALL_KEY_SIZE;
|
||||
else
|
||||
if (ext->key_len <= 0)
|
||||
goto out;
|
||||
|
||||
priv->encode_alg = alg;
|
||||
priv->keys[idx].len = cpu_to_le16(key_len);
|
||||
|
||||
key_len = min(ext->key_len, key_len);
|
||||
|
||||
memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
|
||||
memcpy(priv->keys[idx].data, ext->key, key_len);
|
||||
priv->encode_alg = ORINOCO_ALG_WEP;
|
||||
err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
|
||||
ext->key, ext->key_len, NULL, 0);
|
||||
break;
|
||||
|
||||
case IW_ENCODE_ALG_TKIP:
|
||||
|
@ -851,21 +888,22 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
|
|||
u8 *tkip_iv = NULL;
|
||||
|
||||
if (!priv->has_wpa ||
|
||||
(ext->key_len > sizeof(priv->tkip_key[0])))
|
||||
(ext->key_len > sizeof(struct orinoco_tkip_key)))
|
||||
goto out;
|
||||
|
||||
priv->encode_alg = alg;
|
||||
memset(&priv->tkip_key[idx], 0,
|
||||
sizeof(priv->tkip_key[idx]));
|
||||
memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
|
||||
priv->encode_alg = ORINOCO_ALG_TKIP;
|
||||
|
||||
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
|
||||
tkip_iv = &ext->rx_seq[0];
|
||||
|
||||
err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
|
||||
ext->key, ext->key_len, tkip_iv,
|
||||
ORINOCO_SEQ_LEN);
|
||||
|
||||
err = __orinoco_hw_set_tkip_key(priv, idx,
|
||||
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
|
||||
(u8 *) &priv->tkip_key[idx],
|
||||
tkip_iv, NULL);
|
||||
priv->keys[idx].key,
|
||||
tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
|
||||
if (err)
|
||||
printk(KERN_ERR "%s: Error %d setting TKIP key"
|
||||
"\n", dev->name, err);
|
||||
|
@ -914,22 +952,22 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
|
|||
encoding->flags = idx + 1;
|
||||
memset(ext, 0, sizeof(*ext));
|
||||
|
||||
ext->alg = priv->encode_alg;
|
||||
switch (priv->encode_alg) {
|
||||
case IW_ENCODE_ALG_NONE:
|
||||
case ORINOCO_ALG_NONE:
|
||||
ext->alg = IW_ENCODE_ALG_NONE;
|
||||
ext->key_len = 0;
|
||||
encoding->flags |= IW_ENCODE_DISABLED;
|
||||
break;
|
||||
case IW_ENCODE_ALG_WEP:
|
||||
ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
|
||||
max_key_len);
|
||||
memcpy(ext->key, priv->keys[idx].data, ext->key_len);
|
||||
case ORINOCO_ALG_WEP:
|
||||
ext->alg = IW_ENCODE_ALG_WEP;
|
||||
ext->key_len = min(priv->keys[idx].key_len, max_key_len);
|
||||
memcpy(ext->key, priv->keys[idx].key, ext->key_len);
|
||||
encoding->flags |= IW_ENCODE_ENABLED;
|
||||
break;
|
||||
case IW_ENCODE_ALG_TKIP:
|
||||
ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
|
||||
max_key_len);
|
||||
memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
|
||||
case ORINOCO_ALG_TKIP:
|
||||
ext->alg = IW_ENCODE_ALG_TKIP;
|
||||
ext->key_len = min(priv->keys[idx].key_len, max_key_len);
|
||||
memcpy(ext->key, priv->keys[idx].key, ext->key_len);
|
||||
encoding->flags |= IW_ENCODE_ENABLED;
|
||||
break;
|
||||
}
|
||||
|
@ -1136,7 +1174,6 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
|
|||
union iwreq_data *wrqu, char *extra)
|
||||
{
|
||||
struct orinoco_private *priv = ndev_priv(dev);
|
||||
hermes_t *hw = &priv->hw;
|
||||
struct iw_mlme *mlme = (struct iw_mlme *)extra;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
@ -1150,19 +1187,11 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
|
|||
break;
|
||||
|
||||
case IW_MLME_DISASSOC:
|
||||
{
|
||||
struct {
|
||||
u8 addr[ETH_ALEN];
|
||||
__le16 reason_code;
|
||||
} __attribute__ ((packed)) buf;
|
||||
|
||||
memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
|
||||
buf.reason_code = cpu_to_le16(mlme->reason_code);
|
||||
ret = HERMES_WRITE_RECORD(hw, USER_BAP,
|
||||
HERMES_RID_CNFDISASSOCIATE,
|
||||
&buf);
|
||||
ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
|
||||
mlme->reason_code);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
@ -320,7 +320,7 @@ int p54_setup_mac(struct p54_common *priv)
|
|||
return -ENOMEM;
|
||||
|
||||
setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
|
||||
if (priv->hw->conf.radio_enabled) {
|
||||
if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
|
||||
switch (priv->mode) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
mode = P54_FILTER_TYPE_STATION;
|
||||
|
@ -348,8 +348,9 @@ int p54_setup_mac(struct p54_common *priv)
|
|||
(priv->filter_flags & FIF_OTHER_BSS)) &&
|
||||
(mode != P54_FILTER_TYPE_PROMISCUOUS))
|
||||
mode |= P54_FILTER_TYPE_TRANSPARENT;
|
||||
} else
|
||||
} else {
|
||||
mode = P54_FILTER_TYPE_HIBERNATE;
|
||||
}
|
||||
|
||||
setup->mac_mode = cpu_to_le16(mode);
|
||||
memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
|
||||
|
|
|
@ -288,6 +288,11 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
|
|||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
|
||||
ret = p54_setup_mac(priv);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->conf_mutex);
|
||||
|
@ -317,7 +322,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
|
|||
int ret;
|
||||
|
||||
mutex_lock(&priv->conf_mutex);
|
||||
if ((params) && !(queue > 4)) {
|
||||
if (queue < dev->queues) {
|
||||
P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
|
||||
params->cw_min, params->cw_max, params->txop);
|
||||
ret = p54_set_edcf(priv);
|
||||
|
|
|
@ -552,6 +552,12 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
|
|||
break;
|
||||
case P54_TRAP_TIMER:
|
||||
break;
|
||||
case P54_TRAP_FAA_RADIO_OFF:
|
||||
wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
|
||||
break;
|
||||
case P54_TRAP_FAA_RADIO_ON:
|
||||
wiphy_rfkill_set_hw_state(priv->hw->wiphy, false);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "%s: received event:%x freq:%d\n",
|
||||
wiphy_name(priv->hw->wiphy), event, freq);
|
||||
|
|
|
@ -1764,8 +1764,15 @@ static int rndis_iw_set_essid(struct net_device *dev,
|
|||
|
||||
if (!wrqu->essid.flags || length == 0)
|
||||
return disassociate(usbdev, 1);
|
||||
else
|
||||
else {
|
||||
/* Pause and purge rx queue, so we don't pass packets before
|
||||
* 'media connect'-indication.
|
||||
*/
|
||||
usbnet_pause_rx(usbdev);
|
||||
usbnet_purge_paused_rxq(usbdev);
|
||||
|
||||
return set_essid(usbdev, &ssid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2328,6 +2335,8 @@ get_bssid:
|
|||
memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
|
||||
wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
|
||||
}
|
||||
|
||||
usbnet_resume_rx(usbdev);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) {
|
||||
|
@ -2541,6 +2550,8 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
|
|||
|
||||
switch (msg->status) {
|
||||
case RNDIS_STATUS_MEDIA_CONNECT:
|
||||
usbnet_pause_rx(usbdev);
|
||||
|
||||
devinfo(usbdev, "media connect");
|
||||
|
||||
/* queue work to avoid recursive calls into rndis_command */
|
||||
|
|
|
@ -1069,8 +1069,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry)
|
|||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
|
|
|
@ -1227,8 +1227,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry)
|
|||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, CSR14, ®);
|
||||
rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
|
||||
rt2x00_set_field32(®, CSR14_TBCN, 0);
|
||||
rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
|
||||
|
||||
|
|
|
@ -1238,8 +1238,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
|
|||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
|
||||
|
||||
|
@ -1287,7 +1285,7 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
|
|||
static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
||||
const enum data_queue_qid queue)
|
||||
{
|
||||
u16 reg;
|
||||
u16 reg, reg0;
|
||||
|
||||
if (queue != QID_BEACON) {
|
||||
rt2x00usb_kick_tx_queue(rt2x00dev, queue);
|
||||
|
@ -1298,16 +1296,19 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
|
|||
if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
|
||||
rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
|
||||
reg0 = reg;
|
||||
rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1);
|
||||
/*
|
||||
* Beacon generation will fail initially.
|
||||
* To prevent this we need to register the TXRX_CSR19
|
||||
* register several times.
|
||||
* To prevent this we need to change the TXRX_CSR19
|
||||
* register several times (reg0 is the same as reg
|
||||
* except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
|
||||
* and 1 in reg).
|
||||
*/
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
|
||||
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -518,7 +518,7 @@ static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev,
|
|||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
!(filter_flags & FIF_PSPOLL));
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL,
|
||||
|
@ -2050,8 +2050,6 @@ static void rt2800usb_write_beacon(struct queue_entry *entry)
|
|||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0);
|
||||
rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
|
||||
|
||||
|
@ -2623,6 +2621,13 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* This device has multiple filters for control frames
|
||||
* and has a separate filter for PS Poll frames.
|
||||
*/
|
||||
__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
|
||||
__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
|
||||
|
||||
/*
|
||||
* This device requires firmware.
|
||||
*/
|
||||
|
|
|
@ -133,6 +133,17 @@
|
|||
#define SHORT_EIFS ( SIFS + SHORT_DIFS + \
|
||||
GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
|
||||
|
||||
/*
|
||||
* Structure for average calculation
|
||||
* The avg field contains the actual average value,
|
||||
* but avg_weight is internally used during calculations
|
||||
* to prevent rounding errors.
|
||||
*/
|
||||
struct avg_val {
|
||||
int avg;
|
||||
int avg_weight;
|
||||
};
|
||||
|
||||
/*
|
||||
* Chipset identification
|
||||
* The chipset on the device is composed of a RT and RF chip.
|
||||
|
@ -245,21 +256,18 @@ struct link_ant {
|
|||
struct antenna_setup active;
|
||||
|
||||
/*
|
||||
* RSSI information for the different antennas.
|
||||
* These statistics are used to determine when
|
||||
* to switch antenna when using software diversity.
|
||||
*
|
||||
* rssi[0] -> Antenna A RSSI
|
||||
* rssi[1] -> Antenna B RSSI
|
||||
* RSSI history information for the antenna.
|
||||
* Used to determine when to switch antenna
|
||||
* when using software diversity.
|
||||
*/
|
||||
int rssi_history[2];
|
||||
int rssi_history;
|
||||
|
||||
/*
|
||||
* Current RSSI average of the currently active antenna.
|
||||
* Similar to the avg_rssi in the link_qual structure
|
||||
* this value is updated by using the walking average.
|
||||
*/
|
||||
int rssi_ant;
|
||||
struct avg_val rssi_ant;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -288,7 +296,7 @@ struct link {
|
|||
/*
|
||||
* Currently active average RSSI value
|
||||
*/
|
||||
int avg_rssi;
|
||||
struct avg_val avg_rssi;
|
||||
|
||||
/*
|
||||
* Currently precalculated percentages of successful
|
||||
|
@ -325,6 +333,11 @@ struct rt2x00_intf {
|
|||
*/
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
/*
|
||||
* beacon->skb must be protected with the mutex.
|
||||
*/
|
||||
struct mutex beacon_skb_mutex;
|
||||
|
||||
/*
|
||||
* Entry in the beacon queue which belongs to
|
||||
* this interface. Each interface has its own
|
||||
|
@ -611,6 +624,8 @@ enum rt2x00_flags {
|
|||
*/
|
||||
CONFIG_SUPPORT_HW_BUTTON,
|
||||
CONFIG_SUPPORT_HW_CRYPTO,
|
||||
DRIVER_SUPPORT_CONTROL_FILTERS,
|
||||
DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
|
||||
|
||||
/*
|
||||
* Driver configuration
|
||||
|
|
|
@ -124,8 +124,9 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
|
|||
}
|
||||
|
||||
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
||||
struct antenna_setup ant)
|
||||
struct antenna_setup config)
|
||||
{
|
||||
struct link_ant *ant = &rt2x00dev->link.ant;
|
||||
struct antenna_setup *def = &rt2x00dev->default_ant;
|
||||
struct antenna_setup *active = &rt2x00dev->link.ant.active;
|
||||
|
||||
|
@ -134,14 +135,23 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
|||
* ANTENNA_SW_DIVERSITY state to the driver.
|
||||
* If that happens, fallback to hardware defaults,
|
||||
* or our own default.
|
||||
* If diversity handling is active for a particular antenna,
|
||||
* we shouldn't overwrite that antenna.
|
||||
* The calls to rt2x00lib_config_antenna_check()
|
||||
* might have caused that we restore back to the already
|
||||
* active setting. If that has happened we can quit.
|
||||
*/
|
||||
ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx);
|
||||
ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx);
|
||||
if (!(ant->flags & ANTENNA_RX_DIVERSITY))
|
||||
config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
|
||||
else
|
||||
config.rx = active->rx;
|
||||
|
||||
if (ant.rx == active->rx && ant.tx == active->tx)
|
||||
if (!(ant->flags & ANTENNA_TX_DIVERSITY))
|
||||
config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx);
|
||||
else
|
||||
config.tx = active->tx;
|
||||
|
||||
if (config.rx == active->rx && config.tx == active->tx)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -156,11 +166,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
|||
* The latter is required since we need to recalibrate the
|
||||
* noise-sensitivity ratio for the new setup.
|
||||
*/
|
||||
rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant);
|
||||
rt2x00dev->ops->lib->config_ant(rt2x00dev, &config);
|
||||
|
||||
rt2x00link_reset_tuner(rt2x00dev, true);
|
||||
|
||||
memcpy(active, &ant, sizeof(ant));
|
||||
memcpy(active, &config, sizeof(config));
|
||||
|
||||
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
||||
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
|
||||
|
|
|
@ -186,7 +186,6 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
|
|||
static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = data;
|
||||
struct rt2x00_intf *intf = vif_to_intf(vif);
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_AP &&
|
||||
|
@ -195,12 +194,6 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
|
|||
vif->type != NL80211_IFTYPE_WDS)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Clean up the beacon skb.
|
||||
*/
|
||||
rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
|
||||
intf->beacon->skb = NULL;
|
||||
|
||||
spin_lock(&intf->lock);
|
||||
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
|
||||
spin_unlock(&intf->lock);
|
||||
|
@ -785,6 +778,13 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00dev->intf_sta_count = 0;
|
||||
rt2x00dev->intf_associated = 0;
|
||||
|
||||
/* Enable the radio */
|
||||
retval = rt2x00lib_enable_radio(rt2x00dev);
|
||||
if (retval) {
|
||||
rt2x00queue_uninitialize(rt2x00dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -46,7 +46,15 @@
|
|||
#define DEFAULT_PERCENTAGE 50
|
||||
|
||||
/*
|
||||
* Small helper macro to work with moving/walking averages.
|
||||
* Small helper macro for percentage calculation
|
||||
* This is a very simple macro with the only catch that it will
|
||||
* produce a default value in case no total value was provided.
|
||||
*/
|
||||
#define PERCENTAGE(__value, __total) \
|
||||
( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
|
||||
|
||||
/*
|
||||
* Helper struct and macro to work with moving/walking averages.
|
||||
* When adding a value to the average value the following calculation
|
||||
* is needed:
|
||||
*
|
||||
|
@ -60,18 +68,28 @@
|
|||
* for a few minutes but when the device is moved away from the AP
|
||||
* the average will not decrease fast enough to compensate.
|
||||
* The walking average compensates this and will move towards
|
||||
* the new values correctly allowing a effective link tuning.
|
||||
* the new values correctly allowing a effective link tuning,
|
||||
* the speed of the average moving towards other values depends
|
||||
* on the value for the number of samples. The higher the number
|
||||
* of samples, the slower the average will move.
|
||||
* We use two variables to keep track of the average value to
|
||||
* compensate for the rounding errors. This can be a significant
|
||||
* error (>5dBm) if the factor is too low.
|
||||
*/
|
||||
#define MOVING_AVERAGE(__avg, __val, __samples) \
|
||||
( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
|
||||
|
||||
/*
|
||||
* Small helper macro for percentage calculation
|
||||
* This is a very simple macro with the only catch that it will
|
||||
* produce a default value in case no total value was provided.
|
||||
*/
|
||||
#define PERCENTAGE(__value, __total) \
|
||||
( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
|
||||
#define AVG_SAMPLES 8
|
||||
#define AVG_FACTOR 1000
|
||||
#define MOVING_AVERAGE(__avg, __val) \
|
||||
({ \
|
||||
struct avg_val __new; \
|
||||
__new.avg_weight = \
|
||||
(__avg).avg_weight ? \
|
||||
((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \
|
||||
((__val) * (AVG_FACTOR))) / \
|
||||
(AVG_SAMPLES) ) : \
|
||||
((__val) * (AVG_FACTOR)); \
|
||||
__new.avg = __new.avg_weight / (AVG_FACTOR); \
|
||||
__new; \
|
||||
})
|
||||
|
||||
/*
|
||||
* For calculating the Signal quality we have determined
|
||||
|
@ -98,56 +116,41 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
|
|||
{
|
||||
struct link_ant *ant = &rt2x00dev->link.ant;
|
||||
|
||||
if (ant->rssi_ant && rt2x00dev->link.qual.rx_success)
|
||||
return ant->rssi_ant;
|
||||
if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success)
|
||||
return ant->rssi_ant.avg;
|
||||
return DEFAULT_RSSI;
|
||||
}
|
||||
|
||||
static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev,
|
||||
enum antenna antenna)
|
||||
static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct link_ant *ant = &rt2x00dev->link.ant;
|
||||
|
||||
if (ant->rssi_history[antenna - ANTENNA_A])
|
||||
return ant->rssi_history[antenna - ANTENNA_A];
|
||||
if (ant->rssi_history)
|
||||
return ant->rssi_history;
|
||||
return DEFAULT_RSSI;
|
||||
}
|
||||
/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
|
||||
#define rt2x00link_antenna_get_rssi_rx_history(__dev) \
|
||||
rt2x00link_antenna_get_rssi_history((__dev), \
|
||||
(__dev)->link.ant.active.rx)
|
||||
#define rt2x00link_antenna_get_rssi_tx_history(__dev) \
|
||||
rt2x00link_antenna_get_rssi_history((__dev), \
|
||||
(__dev)->link.ant.active.tx)
|
||||
|
||||
static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
|
||||
enum antenna antenna,
|
||||
int rssi)
|
||||
{
|
||||
struct link_ant *ant = &rt2x00dev->link.ant;
|
||||
ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi;
|
||||
ant->rssi_history = rssi;
|
||||
}
|
||||
/* Small wrapper for rt2x00link_antenna_get_rssi_history() */
|
||||
#define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \
|
||||
rt2x00link_antenna_update_rssi_history((__dev), \
|
||||
(__dev)->link.ant.active.rx, \
|
||||
(__rssi))
|
||||
#define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \
|
||||
rt2x00link_antenna_update_rssi_history((__dev), \
|
||||
(__dev)->link.ant.active.tx, \
|
||||
(__rssi))
|
||||
|
||||
static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
rt2x00dev->link.ant.rssi_ant = 0;
|
||||
rt2x00dev->link.ant.rssi_ant.avg = 0;
|
||||
rt2x00dev->link.ant.rssi_ant.avg_weight = 0;
|
||||
}
|
||||
|
||||
static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct link_ant *ant = &rt2x00dev->link.ant;
|
||||
struct antenna_setup new_ant;
|
||||
int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A);
|
||||
int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B);
|
||||
int other_antenna;
|
||||
|
||||
int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
|
||||
int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
|
||||
|
||||
memcpy(&new_ant, &ant->active, sizeof(new_ant));
|
||||
|
||||
|
@ -161,17 +164,22 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
|
|||
* from both antennas. It now is time to determine
|
||||
* which antenna demonstrated the best performance.
|
||||
* When we are already on the antenna with the best
|
||||
* performance, then there really is nothing for us
|
||||
* left to do.
|
||||
* performance, just create a good starting point
|
||||
* for the history and we are done.
|
||||
*/
|
||||
if (sample_a == sample_b)
|
||||
if (sample_current >= sample_other) {
|
||||
rt2x00link_antenna_update_rssi_history(rt2x00dev,
|
||||
sample_current);
|
||||
return;
|
||||
}
|
||||
|
||||
other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
|
||||
|
||||
if (ant->flags & ANTENNA_RX_DIVERSITY)
|
||||
new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
|
||||
new_ant.rx = other_antenna;
|
||||
|
||||
if (ant->flags & ANTENNA_TX_DIVERSITY)
|
||||
new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
|
||||
new_ant.tx = other_antenna;
|
||||
|
||||
rt2x00lib_config_antenna(rt2x00dev, new_ant);
|
||||
}
|
||||
|
@ -190,8 +198,8 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
|
|||
* after that update the history with the current value.
|
||||
*/
|
||||
rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
|
||||
rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev);
|
||||
rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr);
|
||||
rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
|
||||
rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
|
||||
|
||||
/*
|
||||
* Legacy driver indicates that we should swap antenna's
|
||||
|
@ -216,9 +224,10 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00lib_config_antenna(rt2x00dev, new_ant);
|
||||
}
|
||||
|
||||
static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
|
||||
static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct link_ant *ant = &rt2x00dev->link.ant;
|
||||
unsigned int flags = ant->flags;
|
||||
|
||||
/*
|
||||
* Determine if software diversity is enabled for
|
||||
|
@ -226,30 +235,38 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
|
|||
* Always perform this check since within the link
|
||||
* tuner interval the configuration might have changed.
|
||||
*/
|
||||
ant->flags &= ~ANTENNA_RX_DIVERSITY;
|
||||
ant->flags &= ~ANTENNA_TX_DIVERSITY;
|
||||
flags &= ~ANTENNA_RX_DIVERSITY;
|
||||
flags &= ~ANTENNA_TX_DIVERSITY;
|
||||
|
||||
if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
|
||||
ant->flags |= ANTENNA_RX_DIVERSITY;
|
||||
flags |= ANTENNA_RX_DIVERSITY;
|
||||
if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
|
||||
ant->flags |= ANTENNA_TX_DIVERSITY;
|
||||
flags |= ANTENNA_TX_DIVERSITY;
|
||||
|
||||
if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
|
||||
!(ant->flags & ANTENNA_TX_DIVERSITY)) {
|
||||
ant->flags = 0;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Update flags */
|
||||
ant->flags = flags;
|
||||
|
||||
/*
|
||||
* If we have only sampled the data over the last period
|
||||
* we should now harvest the data. Otherwise just evaluate
|
||||
* the data. The latter should only be performed once
|
||||
* every 2 seconds.
|
||||
*/
|
||||
if (ant->flags & ANTENNA_MODE_SAMPLE)
|
||||
if (ant->flags & ANTENNA_MODE_SAMPLE) {
|
||||
rt2x00lib_antenna_diversity_sample(rt2x00dev);
|
||||
else if (rt2x00dev->link.count & 1)
|
||||
return true;
|
||||
} else if (rt2x00dev->link.count & 1) {
|
||||
rt2x00lib_antenna_diversity_eval(rt2x00dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
|
||||
|
@ -260,8 +277,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
|
|||
struct link_qual *qual = &rt2x00dev->link.qual;
|
||||
struct link_ant *ant = &rt2x00dev->link.ant;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
int avg_rssi = rxdesc->rssi;
|
||||
int ant_rssi = rxdesc->rssi;
|
||||
|
||||
/*
|
||||
* Frame was received successfully since non-succesfull
|
||||
|
@ -281,16 +296,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
|
|||
/*
|
||||
* Update global RSSI
|
||||
*/
|
||||
if (link->avg_rssi)
|
||||
avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8);
|
||||
link->avg_rssi = avg_rssi;
|
||||
link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi);
|
||||
|
||||
/*
|
||||
* Update antenna RSSI
|
||||
*/
|
||||
if (ant->rssi_ant)
|
||||
ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8);
|
||||
ant->rssi_ant = ant_rssi;
|
||||
ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi);
|
||||
}
|
||||
|
||||
static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
|
||||
|
@ -423,10 +434,10 @@ static void rt2x00link_tuner(struct work_struct *work)
|
|||
* collect the RSSI data we could use this. Otherwise we
|
||||
* must fallback to the default RSSI value.
|
||||
*/
|
||||
if (!link->avg_rssi || !qual->rx_success)
|
||||
if (!link->avg_rssi.avg || !qual->rx_success)
|
||||
qual->rssi = DEFAULT_RSSI;
|
||||
else
|
||||
qual->rssi = link->avg_rssi;
|
||||
qual->rssi = link->avg_rssi.avg;
|
||||
|
||||
/*
|
||||
* Only perform the link tuning when Link tuning
|
||||
|
@ -444,18 +455,15 @@ static void rt2x00link_tuner(struct work_struct *work)
|
|||
/*
|
||||
* Send a signal to the led to update the led signal strength.
|
||||
*/
|
||||
rt2x00leds_led_quality(rt2x00dev, link->avg_rssi);
|
||||
rt2x00leds_led_quality(rt2x00dev, qual->rssi);
|
||||
|
||||
/*
|
||||
* Evaluate antenna setup, make this the last step since this could
|
||||
* possibly reset some statistics.
|
||||
* Evaluate antenna setup, make this the last step when
|
||||
* rt2x00lib_antenna_diversity made changes the quality
|
||||
* statistics will be reset.
|
||||
*/
|
||||
rt2x00lib_antenna_diversity(rt2x00dev);
|
||||
|
||||
/*
|
||||
* Reset the quality counters which recounted during each period.
|
||||
*/
|
||||
rt2x00link_reset_qual(rt2x00dev);
|
||||
if (rt2x00lib_antenna_diversity(rt2x00dev))
|
||||
rt2x00link_reset_qual(rt2x00dev);
|
||||
|
||||
/*
|
||||
* Increase tuner counter, and reschedule the next link tuner run.
|
||||
|
|
|
@ -274,6 +274,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
|
|||
|
||||
spin_lock_init(&intf->lock);
|
||||
spin_lock_init(&intf->seqlock);
|
||||
mutex_init(&intf->beacon_skb_mutex);
|
||||
intf->beacon = entry;
|
||||
|
||||
if (conf->type == NL80211_IFTYPE_AP)
|
||||
|
@ -338,7 +339,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* mac80211 might be calling this function while we are trying
|
||||
|
@ -348,44 +348,29 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
return 0;
|
||||
|
||||
/*
|
||||
* Only change device state when the radio is enabled. It does not
|
||||
* matter what parameters we have configured when the radio is disabled
|
||||
* because we won't be able to send or receive anyway. Also note that
|
||||
* some configuration parameters (e.g. channel and antenna values) can
|
||||
* only be set when the radio is enabled.
|
||||
* Some configuration parameters (e.g. channel and antenna values) can
|
||||
* only be set when the radio is enabled, but do require the RX to
|
||||
* be off.
|
||||
*/
|
||||
if (conf->radio_enabled) {
|
||||
/* For programming the values, we have to turn RX off */
|
||||
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
|
||||
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
|
||||
|
||||
/* Enable the radio */
|
||||
status = rt2x00lib_enable_radio(rt2x00dev);
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
/*
|
||||
* When we've just turned on the radio, we want to reprogram
|
||||
* everything to ensure a consistent state
|
||||
*/
|
||||
rt2x00lib_config(rt2x00dev, conf, changed);
|
||||
|
||||
/*
|
||||
* When we've just turned on the radio, we want to reprogram
|
||||
* everything to ensure a consistent state
|
||||
*/
|
||||
rt2x00lib_config(rt2x00dev, conf, changed);
|
||||
/*
|
||||
* After the radio has been enabled we need to configure
|
||||
* the antenna to the default settings. rt2x00lib_config_antenna()
|
||||
* should determine if any action should be taken based on
|
||||
* checking if diversity has been enabled or no antenna changes
|
||||
* have been made since the last configuration change.
|
||||
*/
|
||||
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
|
||||
|
||||
/*
|
||||
* The radio was enabled, configure the antenna to the
|
||||
* default settings, the link tuner will later start
|
||||
* continue configuring the antenna based on the software
|
||||
* diversity. But for non-diversity configurations, we need
|
||||
* to have configured the correct state now.
|
||||
*/
|
||||
if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
|
||||
rt2x00lib_config_antenna(rt2x00dev,
|
||||
rt2x00dev->default_ant);
|
||||
|
||||
/* Turn RX back on */
|
||||
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
|
||||
} else {
|
||||
/* Disable the radio */
|
||||
rt2x00lib_disable_radio(rt2x00dev);
|
||||
}
|
||||
/* Turn RX back on */
|
||||
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -407,6 +392,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
|||
FIF_FCSFAIL |
|
||||
FIF_PLCPFAIL |
|
||||
FIF_CONTROL |
|
||||
FIF_PSPOLL |
|
||||
FIF_OTHER_BSS |
|
||||
FIF_PROMISC_IN_BSS;
|
||||
|
||||
|
@ -421,6 +407,22 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
|||
*total_flags & FIF_PROMISC_IN_BSS)
|
||||
*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
|
||||
|
||||
/*
|
||||
* If the device has a single filter for all control frames,
|
||||
* FIF_CONTROL and FIF_PSPOLL flags imply each other.
|
||||
* And if the device has more than one filter for control frames
|
||||
* of different types, but has no a separate filter for PS Poll frames,
|
||||
* FIF_CONTROL flag implies FIF_PSPOLL.
|
||||
*/
|
||||
if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) {
|
||||
if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
|
||||
*total_flags |= FIF_CONTROL | FIF_PSPOLL;
|
||||
}
|
||||
if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) {
|
||||
if (*total_flags & FIF_CONTROL)
|
||||
*total_flags |= FIF_PSPOLL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there is any work left for us.
|
||||
*/
|
||||
|
|
|
@ -324,7 +324,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
|
|||
/*
|
||||
* Check if more fragments are pending
|
||||
*/
|
||||
if (ieee80211_has_morefrags(hdr->frame_control)) {
|
||||
if (ieee80211_has_morefrags(hdr->frame_control) ||
|
||||
(tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) {
|
||||
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
|
||||
__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
|
||||
}
|
||||
|
@ -452,9 +453,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
|
|||
rt2x00crypto_tx_remove_iv(skb, &txdesc);
|
||||
}
|
||||
|
||||
/*
|
||||
* When DMA allocation is required we should guarentee to the
|
||||
* driver that the DMA is aligned to a 4-byte boundary.
|
||||
* Aligning the header to this boundary can be done by calling
|
||||
* rt2x00queue_payload_align with the header length of 0.
|
||||
* However some drivers require L2 padding to pad the payload
|
||||
* rather then the header. This could be a requirement for
|
||||
* PCI and USB devices, while header alignment only is valid
|
||||
* for PCI devices.
|
||||
*/
|
||||
if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags))
|
||||
rt2x00queue_payload_align(entry->skb, true,
|
||||
txdesc.header_length);
|
||||
else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
|
||||
rt2x00queue_payload_align(entry->skb, false, 0);
|
||||
|
||||
/*
|
||||
* It could be possible that the queue was corrupted and this
|
||||
|
@ -490,14 +503,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
|||
if (unlikely(!intf->beacon))
|
||||
return -ENOBUFS;
|
||||
|
||||
mutex_lock(&intf->beacon_skb_mutex);
|
||||
|
||||
/*
|
||||
* Clean up the beacon skb.
|
||||
*/
|
||||
rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
|
||||
intf->beacon->skb = NULL;
|
||||
|
||||
if (!enable_beacon) {
|
||||
rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON);
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
|
||||
if (!intf->beacon->skb)
|
||||
if (!intf->beacon->skb) {
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all TX descriptor information into txdesc,
|
||||
|
@ -535,6 +559,8 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
|
|||
rt2x00dev->ops->lib->write_beacon(intf->beacon);
|
||||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
|
||||
|
||||
mutex_unlock(&intf->beacon_skb_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -530,7 +530,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
|
|||
rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
|
||||
|
@ -1855,8 +1855,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry)
|
|||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
|
@ -2623,6 +2621,12 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* This device has multiple filters for control frames,
|
||||
* but has no a separate filter for PS Poll frames.
|
||||
*/
|
||||
__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
|
||||
|
||||
/*
|
||||
* This device requires firmware and DMA mapped skbs.
|
||||
*/
|
||||
|
|
|
@ -493,7 +493,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
|
|||
rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
|
||||
|
@ -1527,8 +1527,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
|
|||
* otherwise we might be sending out invalid data.
|
||||
*/
|
||||
rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
|
||||
rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
|
||||
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
|
||||
|
||||
|
@ -2143,6 +2141,12 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* This device has multiple filters for control frames,
|
||||
* but has no a separate filter for PS Poll frames.
|
||||
*/
|
||||
__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
|
||||
|
||||
/*
|
||||
* This device requires firmware.
|
||||
*/
|
||||
|
|
|
@ -194,8 +194,18 @@ struct rtl818x_rf_ops {
|
|||
void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
|
||||
};
|
||||
|
||||
/* Tx/Rx flags are common between RTL818X chips */
|
||||
|
||||
/**
|
||||
* enum rtl818x_tx_desc_flags - Tx/Rx flags are common between RTL818X chips
|
||||
*
|
||||
* @RTL818X_TX_DESC_FLAG_NO_ENC: Disable hardware based encryption.
|
||||
* @RTL818X_TX_DESC_FLAG_TX_OK: TX frame was ACKed.
|
||||
* @RTL818X_TX_DESC_FLAG_SPLCP: Use short preamble.
|
||||
* @RTL818X_TX_DESC_FLAG_MOREFRAG: More fragments follow.
|
||||
* @RTL818X_TX_DESC_FLAG_CTS: Use CTS-to-self protection.
|
||||
* @RTL818X_TX_DESC_FLAG_RTS: Use RTS/CTS protection.
|
||||
* @RTL818X_TX_DESC_FLAG_LS: Last segment of the frame.
|
||||
* @RTL818X_TX_DESC_FLAG_FS: First segment of the frame.
|
||||
*/
|
||||
enum rtl818x_tx_desc_flags {
|
||||
RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15),
|
||||
RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15),
|
||||
|
|
|
@ -7,12 +7,46 @@ menuconfig WL12XX
|
|||
|
||||
config WL1251
|
||||
tristate "TI wl1251 support"
|
||||
depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
|
||||
depends on WL12XX && GENERIC_HARDIRQS
|
||||
select FW_LOADER
|
||||
select CRC7
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
TI wl1251 chipset.
|
||||
|
||||
If you choose to build a module, it'll be called wl1251. Say N if
|
||||
If you choose to build a module, it'll be called wl1251. Say
|
||||
N if unsure.
|
||||
|
||||
config WL1251_SPI
|
||||
tristate "TI wl1251 SPI support"
|
||||
depends on WL1251 && SPI_MASTER
|
||||
---help---
|
||||
This module adds support for the SPI interface of adapters using
|
||||
TI wl1251 chipset. Select this if your platform is using
|
||||
the SPI bus.
|
||||
|
||||
If you choose to build a module, it'll be called wl1251_spi.
|
||||
Say N if unsure.
|
||||
|
||||
config WL1251_SDIO
|
||||
tristate "TI wl1251 SDIO support"
|
||||
depends on WL1251 && MMC
|
||||
---help---
|
||||
This module adds support for the SDIO interface of adapters using
|
||||
TI wl1251 chipset. Select this if your platform is using
|
||||
the SDIO bus.
|
||||
|
||||
If you choose to build a module, it'll be called
|
||||
wl1251_sdio. Say N if unsure.
|
||||
|
||||
config WL1271
|
||||
tristate "TI wl1271 support"
|
||||
depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
|
||||
select FW_LOADER
|
||||
select CRC7
|
||||
---help---
|
||||
This module adds support for wireless adapters based on the
|
||||
TI wl1271 chipset.
|
||||
|
||||
If you choose to build a module, it'll be called wl1271. Say N if
|
||||
unsure.
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \
|
||||
wl1251-objs = wl1251_main.o wl1251_event.o \
|
||||
wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
|
||||
wl1251_acx.o wl1251_boot.o wl1251_init.o \
|
||||
wl1251_ops.o wl1251_debugfs.o
|
||||
wl1251_debugfs.o wl1251_io.o
|
||||
|
||||
obj-$(CONFIG_WL1251) += wl1251.o
|
||||
obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o
|
||||
obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
|
||||
|
||||
wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \
|
||||
wl1271_event.o wl1271_tx.o wl1271_rx.o \
|
||||
wl1271_ps.o wl1271_acx.o wl1271_boot.o \
|
||||
wl1271_init.o wl1271_debugfs.o
|
||||
obj-$(CONFIG_WL1271) += wl1271.o
|
||||
|
|
|
@ -143,35 +143,6 @@ struct wl1251_partition_set {
|
|||
|
||||
struct wl1251;
|
||||
|
||||
/* FIXME: I'm not sure about this structure name */
|
||||
struct wl1251_chip {
|
||||
u32 id;
|
||||
|
||||
const char *fw_filename;
|
||||
const char *nvs_filename;
|
||||
|
||||
char fw_ver[21];
|
||||
|
||||
unsigned int power_on_sleep;
|
||||
int intr_cmd_complete;
|
||||
int intr_init_complete;
|
||||
|
||||
int (*op_upload_fw)(struct wl1251 *wl);
|
||||
int (*op_upload_nvs)(struct wl1251 *wl);
|
||||
int (*op_boot)(struct wl1251 *wl);
|
||||
void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag);
|
||||
void (*op_target_enable_interrupts)(struct wl1251 *wl);
|
||||
int (*op_hw_init)(struct wl1251 *wl);
|
||||
int (*op_plt_init)(struct wl1251 *wl);
|
||||
void (*op_tx_flush)(struct wl1251 *wl);
|
||||
void (*op_fw_version)(struct wl1251 *wl);
|
||||
int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
|
||||
u16 beacon_interval, u8 wait);
|
||||
|
||||
struct wl1251_partition_set *p_table;
|
||||
enum wl12xx_acx_int_reg *acx_reg_table;
|
||||
};
|
||||
|
||||
struct wl1251_stats {
|
||||
struct acx_statistics *fw_stats;
|
||||
unsigned long fw_stats_update;
|
||||
|
@ -281,11 +252,20 @@ struct wl1251_debugfs {
|
|||
struct dentry *excessive_retries;
|
||||
};
|
||||
|
||||
struct wl1251_if_operations {
|
||||
void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len);
|
||||
void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len);
|
||||
void (*reset)(struct wl1251 *wl);
|
||||
void (*enable_irq)(struct wl1251 *wl);
|
||||
void (*disable_irq)(struct wl1251 *wl);
|
||||
};
|
||||
|
||||
struct wl1251 {
|
||||
struct ieee80211_hw *hw;
|
||||
bool mac80211_registered;
|
||||
|
||||
struct spi_device *spi;
|
||||
void *if_priv;
|
||||
const struct wl1251_if_operations *if_ops;
|
||||
|
||||
void (*set_power)(bool enable);
|
||||
int irq;
|
||||
|
@ -298,8 +278,6 @@ struct wl1251 {
|
|||
int virtual_mem_addr;
|
||||
int virtual_reg_addr;
|
||||
|
||||
struct wl1251_chip chip;
|
||||
|
||||
int cmd_box_addr;
|
||||
int event_box_addr;
|
||||
struct boot_attr boot_attr;
|
||||
|
@ -382,6 +360,9 @@ struct wl1251 {
|
|||
/* PSM mode requested */
|
||||
bool psm_requested;
|
||||
|
||||
u16 beacon_int;
|
||||
u8 dtim_period;
|
||||
|
||||
/* in dBm */
|
||||
int power_level;
|
||||
|
||||
|
@ -392,11 +373,20 @@ struct wl1251 {
|
|||
u32 buffer_cmd;
|
||||
u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
|
||||
struct wl1251_rx_descriptor *rx_descriptor;
|
||||
|
||||
u32 chip_id;
|
||||
char fw_ver[21];
|
||||
};
|
||||
|
||||
int wl1251_plt_start(struct wl1251 *wl);
|
||||
int wl1251_plt_stop(struct wl1251 *wl);
|
||||
|
||||
struct ieee80211_hw *wl1251_alloc_hw(void);
|
||||
int wl1251_free_hw(struct wl1251 *wl);
|
||||
int wl1251_init_ieee80211(struct wl1251 *wl);
|
||||
void wl1251_enable_interrupts(struct wl1251 *wl);
|
||||
void wl1251_disable_interrupts(struct wl1251 *wl);
|
||||
|
||||
#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
|
||||
#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
|
||||
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
|
||||
|
@ -405,11 +395,10 @@ int wl1251_plt_stop(struct wl1251 *wl);
|
|||
|
||||
#define WL1251_TX_QUEUE_MAX_LENGTH 20
|
||||
|
||||
/* Different chips need different sleep times after power on. WL1271 needs
|
||||
* 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
|
||||
* know the chip ID, we change the sleep value in the wl1251 chip structure,
|
||||
* so in subsequent power ons, we don't waste more time then needed. */
|
||||
#define WL1251_DEFAULT_POWER_ON_SLEEP 200
|
||||
#define WL1251_DEFAULT_BEACON_INT 100
|
||||
#define WL1251_DEFAULT_DTIM_PERIOD 1
|
||||
|
||||
#define WL1251_DEFAULT_CHANNEL 0
|
||||
|
||||
#define CHIP_ID_1251_PG10 (0x7010101)
|
||||
#define CHIP_ID_1251_PG11 (0x7020101)
|
||||
|
@ -417,4 +406,19 @@ int wl1251_plt_stop(struct wl1251 *wl);
|
|||
#define CHIP_ID_1271_PG10 (0x4030101)
|
||||
#define CHIP_ID_1271_PG20 (0x4030111)
|
||||
|
||||
#define WL1251_FW_NAME "wl1251-fw.bin"
|
||||
#define WL1251_NVS_NAME "wl1251-nvs.bin"
|
||||
|
||||
#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
|
||||
|
||||
#define WL1251_PART_DOWN_MEM_START 0x0
|
||||
#define WL1251_PART_DOWN_MEM_SIZE 0x16800
|
||||
#define WL1251_PART_DOWN_REG_START REGISTERS_BASE
|
||||
#define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE
|
||||
|
||||
#define WL1251_PART_WORK_MEM_START 0x28000
|
||||
#define WL1251_PART_WORK_MEM_SIZE 0x14000
|
||||
#define WL1251_PART_WORK_REG_START REGISTERS_BASE
|
||||
#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/crc7.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "wl1251.h"
|
||||
#include "reg.h"
|
||||
#include "wl1251_spi.h"
|
||||
#include "wl1251_reg.h"
|
||||
#include "wl1251_cmd.h"
|
||||
#include "wl1251_ps.h"
|
||||
|
||||
int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
|
||||
|
@ -838,3 +837,82 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1251_acx_rate_policies(struct wl1251 *wl)
|
||||
{
|
||||
struct acx_rate_policy *acx;
|
||||
int ret = 0;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx rate policies");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* configure one default (one-size-fits-all) rate class */
|
||||
acx->rate_class_cnt = 1;
|
||||
acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
|
||||
acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
|
||||
acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
|
||||
acx->rate_class[0].aflags = 0;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1251_warning("Setting of rate policies failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_acx_mem_cfg(struct wl1251 *wl)
|
||||
{
|
||||
struct wl1251_acx_config_memory *mem_conf;
|
||||
int ret, i;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx mem cfg");
|
||||
|
||||
mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
|
||||
if (!mem_conf) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* memory config */
|
||||
mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
|
||||
mem_conf->mem_config.rx_mem_block_num = 35;
|
||||
mem_conf->mem_config.tx_min_mem_block_num = 64;
|
||||
mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES;
|
||||
mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING;
|
||||
mem_conf->mem_config.num_ssid_profiles = 1;
|
||||
mem_conf->mem_config.debug_buffer_size =
|
||||
cpu_to_le16(TRACE_BUFFER_MAX_SIZE);
|
||||
|
||||
/* RX queue config */
|
||||
mem_conf->rx_queue_config.dma_address = 0;
|
||||
mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF;
|
||||
mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
|
||||
mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE;
|
||||
|
||||
/* TX queue config */
|
||||
for (i = 0; i < MAX_TX_QUEUES; i++) {
|
||||
mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
|
||||
mem_conf->tx_queue_config[i].attributes = i;
|
||||
}
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
|
||||
sizeof(*mem_conf));
|
||||
if (ret < 0) {
|
||||
wl1251_warning("wl1251 mem config failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(mem_conf);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1031,6 +1031,150 @@ struct acx_statistics {
|
|||
struct acx_rxpipe_statistics rxpipe;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define ACX_MAX_RATE_CLASSES 8
|
||||
#define ACX_RATE_MASK_UNSPECIFIED 0
|
||||
#define ACX_RATE_RETRY_LIMIT 10
|
||||
|
||||
struct acx_rate_class {
|
||||
u32 enabled_rates;
|
||||
u8 short_retry_limit;
|
||||
u8 long_retry_limit;
|
||||
u8 aflags;
|
||||
u8 reserved;
|
||||
};
|
||||
|
||||
struct acx_rate_policy {
|
||||
struct acx_header header;
|
||||
|
||||
u32 rate_class_cnt;
|
||||
struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct wl1251_acx_memory {
|
||||
__le16 num_stations; /* number of STAs to be supported. */
|
||||
u16 reserved_1;
|
||||
|
||||
/*
|
||||
* Nmber of memory buffers for the RX mem pool.
|
||||
* The actual number may be less if there are
|
||||
* not enough blocks left for the minimum num
|
||||
* of TX ones.
|
||||
*/
|
||||
u8 rx_mem_block_num;
|
||||
u8 reserved_2;
|
||||
u8 num_tx_queues; /* From 1 to 16 */
|
||||
u8 host_if_options; /* HOST_IF* */
|
||||
u8 tx_min_mem_block_num;
|
||||
u8 num_ssid_profiles;
|
||||
__le16 debug_buffer_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
#define ACX_RX_DESC_MIN 1
|
||||
#define ACX_RX_DESC_MAX 127
|
||||
#define ACX_RX_DESC_DEF 32
|
||||
struct wl1251_acx_rx_queue_config {
|
||||
u8 num_descs;
|
||||
u8 pad;
|
||||
u8 type;
|
||||
u8 priority;
|
||||
__le32 dma_address;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define ACX_TX_DESC_MIN 1
|
||||
#define ACX_TX_DESC_MAX 127
|
||||
#define ACX_TX_DESC_DEF 16
|
||||
struct wl1251_acx_tx_queue_config {
|
||||
u8 num_descs;
|
||||
u8 pad[2];
|
||||
u8 attributes;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define MAX_TX_QUEUE_CONFIGS 5
|
||||
#define MAX_TX_QUEUES 4
|
||||
struct wl1251_acx_config_memory {
|
||||
struct acx_header header;
|
||||
|
||||
struct wl1251_acx_memory mem_config;
|
||||
struct wl1251_acx_rx_queue_config rx_queue_config;
|
||||
struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct wl1251_acx_mem_map {
|
||||
struct acx_header header;
|
||||
|
||||
void *code_start;
|
||||
void *code_end;
|
||||
|
||||
void *wep_defkey_start;
|
||||
void *wep_defkey_end;
|
||||
|
||||
void *sta_table_start;
|
||||
void *sta_table_end;
|
||||
|
||||
void *packet_template_start;
|
||||
void *packet_template_end;
|
||||
|
||||
void *queue_memory_start;
|
||||
void *queue_memory_end;
|
||||
|
||||
void *packet_memory_pool_start;
|
||||
void *packet_memory_pool_end;
|
||||
|
||||
void *debug_buffer1_start;
|
||||
void *debug_buffer1_end;
|
||||
|
||||
void *debug_buffer2_start;
|
||||
void *debug_buffer2_end;
|
||||
|
||||
/* Number of blocks FW allocated for TX packets */
|
||||
u32 num_tx_mem_blocks;
|
||||
|
||||
/* Number of blocks FW allocated for RX packets */
|
||||
u32 num_rx_mem_blocks;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*************************************************************************
|
||||
|
||||
Host Interrupt Register (WiLink -> Host)
|
||||
|
||||
**************************************************************************/
|
||||
|
||||
/* RX packet is ready in Xfer buffer #0 */
|
||||
#define WL1251_ACX_INTR_RX0_DATA BIT(0)
|
||||
|
||||
/* TX result(s) are in the TX complete buffer */
|
||||
#define WL1251_ACX_INTR_TX_RESULT BIT(1)
|
||||
|
||||
/* OBSOLETE */
|
||||
#define WL1251_ACX_INTR_TX_XFR BIT(2)
|
||||
|
||||
/* RX packet is ready in Xfer buffer #1 */
|
||||
#define WL1251_ACX_INTR_RX1_DATA BIT(3)
|
||||
|
||||
/* Event was entered to Event MBOX #A */
|
||||
#define WL1251_ACX_INTR_EVENT_A BIT(4)
|
||||
|
||||
/* Event was entered to Event MBOX #B */
|
||||
#define WL1251_ACX_INTR_EVENT_B BIT(5)
|
||||
|
||||
/* OBSOLETE */
|
||||
#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
|
||||
|
||||
/* Trace meassge on MBOX #A */
|
||||
#define WL1251_ACX_INTR_TRACE_A BIT(7)
|
||||
|
||||
/* Trace meassge on MBOX #B */
|
||||
#define WL1251_ACX_INTR_TRACE_B BIT(8)
|
||||
|
||||
/* Command processing completion */
|
||||
#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
|
||||
|
||||
/* Init sequence is done */
|
||||
#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
|
||||
|
||||
#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
|
||||
|
||||
enum {
|
||||
ACX_WAKE_UP_CONDITIONS = 0x0002,
|
||||
ACX_MEM_CFG = 0x0003,
|
||||
|
@ -1142,5 +1286,7 @@ int wl1251_acx_cts_protect(struct wl1251 *wl,
|
|||
enum acx_ctsprotect_type ctsprotect);
|
||||
int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
|
||||
int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
|
||||
int wl1251_acx_rate_policies(struct wl1251 *wl);
|
||||
int wl1251_acx_mem_cfg(struct wl1251 *wl);
|
||||
|
||||
#endif /* __WL1251_ACX_H__ */
|
||||
|
|
|
@ -23,15 +23,12 @@
|
|||
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "reg.h"
|
||||
#include "wl1251_reg.h"
|
||||
#include "wl1251_boot.h"
|
||||
#include "wl1251_io.h"
|
||||
#include "wl1251_spi.h"
|
||||
#include "wl1251_event.h"
|
||||
|
||||
static void wl1251_boot_enable_interrupts(struct wl1251 *wl)
|
||||
{
|
||||
enable_irq(wl->irq);
|
||||
}
|
||||
#include "wl1251_acx.h"
|
||||
|
||||
void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
|
||||
{
|
||||
|
@ -212,18 +209,30 @@ int wl1251_boot_init_seq(struct wl1251 *wl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
|
||||
{
|
||||
u32 cpu_ctrl;
|
||||
|
||||
/* 10.5.0 run the firmware (I) */
|
||||
cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
|
||||
|
||||
/* 10.5.1 run the firmware (II) */
|
||||
cpu_ctrl &= ~flag;
|
||||
wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
|
||||
}
|
||||
|
||||
int wl1251_boot_run_firmware(struct wl1251 *wl)
|
||||
{
|
||||
int loop, ret;
|
||||
u32 chip_id, interrupt;
|
||||
|
||||
wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
|
||||
wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
|
||||
|
||||
chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
|
||||
|
||||
wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
|
||||
|
||||
if (chip_id != wl->chip.id) {
|
||||
if (chip_id != wl->chip_id) {
|
||||
wl1251_error("chip id doesn't match after firmware boot");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -240,9 +249,9 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
|||
return -EIO;
|
||||
}
|
||||
/* check that ACX_INTR_INIT_COMPLETE is enabled */
|
||||
else if (interrupt & wl->chip.intr_init_complete) {
|
||||
else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) {
|
||||
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
|
||||
wl->chip.intr_init_complete);
|
||||
WL1251_ACX_INTR_INIT_COMPLETE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -260,16 +269,15 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
|||
wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
|
||||
|
||||
/* set the working partition to its "running" mode offset */
|
||||
wl1251_set_partition(wl,
|
||||
wl->chip.p_table[PART_WORK].mem.start,
|
||||
wl->chip.p_table[PART_WORK].mem.size,
|
||||
wl->chip.p_table[PART_WORK].reg.start,
|
||||
wl->chip.p_table[PART_WORK].reg.size);
|
||||
wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START,
|
||||
WL1251_PART_WORK_MEM_SIZE,
|
||||
WL1251_PART_WORK_REG_START,
|
||||
WL1251_PART_WORK_REG_SIZE);
|
||||
|
||||
wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
|
||||
wl->cmd_box_addr, wl->event_box_addr);
|
||||
|
||||
wl->chip.op_fw_version(wl);
|
||||
wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver));
|
||||
|
||||
/*
|
||||
* in case of full asynchronous mode the firmware event must be
|
||||
|
@ -277,9 +285,16 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
|||
*/
|
||||
|
||||
/* enable gpio interrupts */
|
||||
wl1251_boot_enable_interrupts(wl);
|
||||
wl1251_enable_interrupts(wl);
|
||||
|
||||
wl->chip.op_target_enable_interrupts(wl);
|
||||
/* Enable target's interrupts */
|
||||
wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
|
||||
WL1251_ACX_INTR_RX1_DATA |
|
||||
WL1251_ACX_INTR_TX_RESULT |
|
||||
WL1251_ACX_INTR_EVENT_A |
|
||||
WL1251_ACX_INTR_EVENT_B |
|
||||
WL1251_ACX_INTR_INIT_COMPLETE;
|
||||
wl1251_boot_target_enable_interrupts(wl);
|
||||
|
||||
/* unmask all mbox events */
|
||||
wl->event_mask = 0xffffffff;
|
||||
|
@ -295,3 +310,218 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
|||
/* firmware startup completed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
||||
{
|
||||
int addr, chunk_num, partition_limit;
|
||||
size_t fw_data_len;
|
||||
u8 *p;
|
||||
|
||||
/* whal_FwCtrl_LoadFwImageSm() */
|
||||
|
||||
wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
|
||||
wl1251_reg_read32(wl, CHIP_ID_B));
|
||||
|
||||
/* 10.0 check firmware length and set partition */
|
||||
fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) |
|
||||
(wl->fw[6] << 8) | (wl->fw[7]);
|
||||
|
||||
wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
|
||||
CHUNK_SIZE);
|
||||
|
||||
if ((fw_data_len % 4) != 0) {
|
||||
wl1251_error("firmware length not multiple of four");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START,
|
||||
WL1251_PART_DOWN_MEM_SIZE,
|
||||
WL1251_PART_DOWN_REG_START,
|
||||
WL1251_PART_DOWN_REG_SIZE);
|
||||
|
||||
/* 10.1 set partition limit and chunk num */
|
||||
chunk_num = 0;
|
||||
partition_limit = WL1251_PART_DOWN_MEM_SIZE;
|
||||
|
||||
while (chunk_num < fw_data_len / CHUNK_SIZE) {
|
||||
/* 10.2 update partition, if needed */
|
||||
addr = WL1251_PART_DOWN_MEM_START +
|
||||
(chunk_num + 2) * CHUNK_SIZE;
|
||||
if (addr > partition_limit) {
|
||||
addr = WL1251_PART_DOWN_MEM_START +
|
||||
chunk_num * CHUNK_SIZE;
|
||||
partition_limit = chunk_num * CHUNK_SIZE +
|
||||
WL1251_PART_DOWN_MEM_SIZE;
|
||||
wl1251_set_partition(wl,
|
||||
addr,
|
||||
WL1251_PART_DOWN_MEM_SIZE,
|
||||
WL1251_PART_DOWN_REG_START,
|
||||
WL1251_PART_DOWN_REG_SIZE);
|
||||
}
|
||||
|
||||
/* 10.3 upload the chunk */
|
||||
addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
|
||||
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
|
||||
wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
|
||||
p, addr);
|
||||
wl1251_mem_write(wl, addr, p, CHUNK_SIZE);
|
||||
|
||||
chunk_num++;
|
||||
}
|
||||
|
||||
/* 10.4 upload the last chunk */
|
||||
addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
|
||||
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
|
||||
wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
|
||||
fw_data_len % CHUNK_SIZE, p, addr);
|
||||
wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1251_boot_upload_nvs(struct wl1251 *wl)
|
||||
{
|
||||
size_t nvs_len, nvs_bytes_written, burst_len;
|
||||
int nvs_start, i;
|
||||
u32 dest_addr, val;
|
||||
u8 *nvs_ptr, *nvs;
|
||||
|
||||
nvs = wl->nvs;
|
||||
if (nvs == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
nvs_ptr = nvs;
|
||||
|
||||
nvs_len = wl->nvs_len;
|
||||
nvs_start = wl->fw_len;
|
||||
|
||||
/*
|
||||
* Layout before the actual NVS tables:
|
||||
* 1 byte : burst length.
|
||||
* 2 bytes: destination address.
|
||||
* n bytes: data to burst copy.
|
||||
*
|
||||
* This is ended by a 0 length, then the NVS tables.
|
||||
*/
|
||||
|
||||
while (nvs_ptr[0]) {
|
||||
burst_len = nvs_ptr[0];
|
||||
dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
|
||||
|
||||
/* We move our pointer to the data */
|
||||
nvs_ptr += 3;
|
||||
|
||||
for (i = 0; i < burst_len; i++) {
|
||||
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
|
||||
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
|
||||
|
||||
wl1251_debug(DEBUG_BOOT,
|
||||
"nvs burst write 0x%x: 0x%x",
|
||||
dest_addr, val);
|
||||
wl1251_mem_write32(wl, dest_addr, val);
|
||||
|
||||
nvs_ptr += 4;
|
||||
dest_addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We've reached the first zero length, the first NVS table
|
||||
* is 7 bytes further.
|
||||
*/
|
||||
nvs_ptr += 7;
|
||||
nvs_len -= nvs_ptr - nvs;
|
||||
nvs_len = ALIGN(nvs_len, 4);
|
||||
|
||||
/* Now we must set the partition correctly */
|
||||
wl1251_set_partition(wl, nvs_start,
|
||||
WL1251_PART_DOWN_MEM_SIZE,
|
||||
WL1251_PART_DOWN_REG_START,
|
||||
WL1251_PART_DOWN_REG_SIZE);
|
||||
|
||||
/* And finally we upload the NVS tables */
|
||||
nvs_bytes_written = 0;
|
||||
while (nvs_bytes_written < nvs_len) {
|
||||
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
|
||||
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
|
||||
|
||||
val = cpu_to_le32(val);
|
||||
|
||||
wl1251_debug(DEBUG_BOOT,
|
||||
"nvs write table 0x%x: 0x%x",
|
||||
nvs_start, val);
|
||||
wl1251_mem_write32(wl, nvs_start, val);
|
||||
|
||||
nvs_ptr += 4;
|
||||
nvs_bytes_written += 4;
|
||||
nvs_start += 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1251_boot(struct wl1251 *wl)
|
||||
{
|
||||
int ret = 0, minor_minor_e2_ver;
|
||||
u32 tmp, boot_data;
|
||||
|
||||
ret = wl1251_boot_soft_reset(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* 2. start processing NVS file */
|
||||
ret = wl1251_boot_upload_nvs(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* write firmware's last address (ie. it's length) to
|
||||
* ACX_EEPROMLESS_IND_REG */
|
||||
wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
|
||||
|
||||
/* 6. read the EEPROM parameters */
|
||||
tmp = wl1251_reg_read32(wl, SCR_PAD2);
|
||||
|
||||
/* 7. read bootdata */
|
||||
wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
|
||||
wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
|
||||
tmp = wl1251_reg_read32(wl, SCR_PAD3);
|
||||
|
||||
/* 8. check bootdata and call restart sequence */
|
||||
wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
|
||||
minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
|
||||
|
||||
wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
|
||||
"minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
|
||||
wl->boot_attr.radio_type, wl->boot_attr.major,
|
||||
wl->boot_attr.minor, minor_minor_e2_ver);
|
||||
|
||||
ret = wl1251_boot_init_seq(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* 9. NVS processing done */
|
||||
boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
|
||||
|
||||
wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
|
||||
|
||||
/* 10. check that ECPU_CONTROL_HALT bits are set in
|
||||
* pWhalBus->uBootData and start uploading firmware
|
||||
*/
|
||||
if ((boot_data & ECPU_CONTROL_HALT) == 0) {
|
||||
wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1251_boot_upload_firmware(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* 10.5 start firmware */
|
||||
ret = wl1251_boot_run_firmware(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ int wl1251_boot_soft_reset(struct wl1251 *wl);
|
|||
int wl1251_boot_init_seq(struct wl1251 *wl);
|
||||
int wl1251_boot_run_firmware(struct wl1251 *wl);
|
||||
void wl1251_boot_target_enable_interrupts(struct wl1251 *wl);
|
||||
int wl1251_boot(struct wl1251 *wl);
|
||||
|
||||
/* number of times we try to read the INIT interrupt */
|
||||
#define INIT_LOOP 20000
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/crc7.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "wl1251.h"
|
||||
#include "reg.h"
|
||||
#include "wl1251_spi.h"
|
||||
#include "wl1251_reg.h"
|
||||
#include "wl1251_io.h"
|
||||
#include "wl1251_ps.h"
|
||||
#include "wl1251_acx.h"
|
||||
|
||||
|
@ -31,14 +30,14 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len)
|
|||
|
||||
WARN_ON(len % 4 != 0);
|
||||
|
||||
wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
|
||||
wl1251_mem_write(wl, wl->cmd_box_addr, buf, len);
|
||||
|
||||
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT);
|
||||
|
||||
intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
|
||||
while (!(intr & wl->chip.intr_cmd_complete)) {
|
||||
while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
wl1251_error("command complete timeout");
|
||||
ret = -ETIMEDOUT;
|
||||
|
@ -51,7 +50,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len)
|
|||
}
|
||||
|
||||
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
|
||||
wl->chip.intr_cmd_complete);
|
||||
WL1251_ACX_INTR_CMD_COMPLETE);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -86,7 +85,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
|
|||
* The answer would be a wl1251_command, where the
|
||||
* parameter array contains the actual answer.
|
||||
*/
|
||||
wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
|
||||
wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
|
||||
|
||||
cmd_answer = buf;
|
||||
|
||||
|
@ -125,7 +124,7 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len)
|
|||
}
|
||||
|
||||
/* the interrogate command got in, we can read the answer */
|
||||
wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
|
||||
wl1251_mem_read(wl, wl->cmd_box_addr, buf, len);
|
||||
|
||||
acx = buf;
|
||||
if (acx->cmd.status != CMD_STATUS_SUCCESS)
|
||||
|
@ -252,10 +251,9 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
|
||||
u16 beacon_interval, u8 wait)
|
||||
int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
|
||||
u16 beacon_interval, u8 dtim_interval)
|
||||
{
|
||||
unsigned long timeout;
|
||||
struct cmd_join *join;
|
||||
int ret, i;
|
||||
u8 *bssid;
|
||||
|
@ -266,15 +264,9 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME: this should be in main.c */
|
||||
ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
|
||||
DEFAULT_HW_GEN_MODULATION_TYPE,
|
||||
wl->tx_mgmt_frm_rate,
|
||||
wl->tx_mgmt_frm_mod);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1251_debug(DEBUG_CMD, "cmd join");
|
||||
wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d",
|
||||
bss_type == BSS_TYPE_IBSS ? " ibss" : "",
|
||||
channel, beacon_interval, dtim_interval);
|
||||
|
||||
/* Reverse order BSSID */
|
||||
bssid = (u8 *) &join->bssid_lsb;
|
||||
|
@ -284,13 +276,22 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
|
|||
join->rx_config_options = wl->rx_config;
|
||||
join->rx_filter_options = wl->rx_filter;
|
||||
|
||||
/*
|
||||
* FIXME: disable temporarily all filters because after commit
|
||||
* 9cef8737 "mac80211: fix managed mode BSSID handling" broke
|
||||
* association. The filter logic needs to be implemented properly
|
||||
* and once that is done, this hack can be removed.
|
||||
*/
|
||||
join->rx_config_options = 0;
|
||||
join->rx_filter_options = WL1251_DEFAULT_RX_FILTER;
|
||||
|
||||
join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
|
||||
RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
|
||||
|
||||
join->beacon_interval = beacon_interval;
|
||||
join->dtim_interval = dtim_interval;
|
||||
join->bss_type = bss_type;
|
||||
join->channel = wl->channel;
|
||||
join->channel = channel;
|
||||
join->ctrl = JOIN_CMD_CTRL_TX_FLUSH;
|
||||
|
||||
ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
|
||||
|
@ -299,15 +300,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
|
|||
goto out;
|
||||
}
|
||||
|
||||
timeout = msecs_to_jiffies(JOIN_TIMEOUT);
|
||||
|
||||
/*
|
||||
* ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
|
||||
* simplify locking we just sleep instead, for now
|
||||
*/
|
||||
if (wait)
|
||||
msleep(10);
|
||||
|
||||
out:
|
||||
kfree(join);
|
||||
return ret;
|
||||
|
@ -318,14 +310,6 @@ int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode)
|
|||
struct wl1251_cmd_ps_params *ps_params = NULL;
|
||||
int ret = 0;
|
||||
|
||||
/* FIXME: this should be in ps.c */
|
||||
ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
|
||||
wl->listen_int);
|
||||
if (ret < 0) {
|
||||
wl1251_error("couldn't set wake up conditions");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1251_debug(DEBUG_CMD, "cmd set ps mode");
|
||||
|
||||
ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
|
||||
|
@ -379,7 +363,7 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
|
|||
}
|
||||
|
||||
/* the read command got in, we can now read the answer */
|
||||
wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
|
||||
wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
|
||||
|
||||
if (cmd->header.status != CMD_STATUS_SUCCESS)
|
||||
wl1251_error("error in read command result: %d",
|
||||
|
|
|
@ -36,8 +36,8 @@ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
|
|||
int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
|
||||
void *bitmap, u16 bitmap_len, u8 bitmap_control);
|
||||
int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
|
||||
int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
|
||||
u16 beacon_interval, u8 wait);
|
||||
int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
|
||||
u16 beacon_interval, u8 dtim_interval);
|
||||
int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
|
||||
int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
|
||||
size_t len);
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
*/
|
||||
|
||||
#include "wl1251.h"
|
||||
#include "reg.h"
|
||||
#include "wl1251_spi.h"
|
||||
#include "wl1251_reg.h"
|
||||
#include "wl1251_io.h"
|
||||
#include "wl1251_event.h"
|
||||
#include "wl1251_ps.h"
|
||||
|
||||
|
@ -39,6 +39,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
|
|||
mutex_unlock(&wl->mutex);
|
||||
ieee80211_scan_completed(wl->hw, false);
|
||||
mutex_lock(&wl->mutex);
|
||||
wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
|
||||
wl->scanning = false;
|
||||
}
|
||||
|
||||
|
@ -112,7 +113,7 @@ int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num)
|
|||
return -EINVAL;
|
||||
|
||||
/* first we read the mbox descriptor */
|
||||
wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
|
||||
wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
|
||||
sizeof(struct event_mailbox));
|
||||
|
||||
/* process the descriptor */
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "wl12xx_80211.h"
|
||||
#include "wl1251_acx.h"
|
||||
#include "wl1251_cmd.h"
|
||||
#include "wl1251_reg.h"
|
||||
|
||||
int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
|
||||
{
|
||||
|
@ -198,3 +199,215 @@ int wl1251_hw_init_power_auth(struct wl1251 *wl)
|
|||
{
|
||||
return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
|
||||
}
|
||||
|
||||
int wl1251_hw_init_mem_config(struct wl1251 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1251_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
|
||||
GFP_KERNEL);
|
||||
if (!wl->target_mem_map) {
|
||||
wl1251_error("couldn't allocate target memory map");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* we now ask for the firmware built memory map */
|
||||
ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
|
||||
sizeof(struct wl1251_acx_mem_map));
|
||||
if (ret < 0) {
|
||||
wl1251_error("couldn't retrieve firmware memory map");
|
||||
kfree(wl->target_mem_map);
|
||||
wl->target_mem_map = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1251_hw_init_txq_fill(u8 qid,
|
||||
struct acx_tx_queue_qos_config *config,
|
||||
u32 num_blocks)
|
||||
{
|
||||
config->qid = qid;
|
||||
|
||||
switch (qid) {
|
||||
case QOS_AC_BE:
|
||||
config->high_threshold =
|
||||
(QOS_TX_HIGH_BE_DEF * num_blocks) / 100;
|
||||
config->low_threshold =
|
||||
(QOS_TX_LOW_BE_DEF * num_blocks) / 100;
|
||||
break;
|
||||
case QOS_AC_BK:
|
||||
config->high_threshold =
|
||||
(QOS_TX_HIGH_BK_DEF * num_blocks) / 100;
|
||||
config->low_threshold =
|
||||
(QOS_TX_LOW_BK_DEF * num_blocks) / 100;
|
||||
break;
|
||||
case QOS_AC_VI:
|
||||
config->high_threshold =
|
||||
(QOS_TX_HIGH_VI_DEF * num_blocks) / 100;
|
||||
config->low_threshold =
|
||||
(QOS_TX_LOW_VI_DEF * num_blocks) / 100;
|
||||
break;
|
||||
case QOS_AC_VO:
|
||||
config->high_threshold =
|
||||
(QOS_TX_HIGH_VO_DEF * num_blocks) / 100;
|
||||
config->low_threshold =
|
||||
(QOS_TX_LOW_VO_DEF * num_blocks) / 100;
|
||||
break;
|
||||
default:
|
||||
wl1251_error("Invalid TX queue id: %d", qid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
|
||||
{
|
||||
struct acx_tx_queue_qos_config *config;
|
||||
struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
|
||||
int ret, i;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx tx queue config");
|
||||
|
||||
config = kzalloc(sizeof(*config), GFP_KERNEL);
|
||||
if (!config) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NUM_OF_AC; i++) {
|
||||
ret = wl1251_hw_init_txq_fill(i, config,
|
||||
wl_mem_map->num_tx_mem_blocks);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
|
||||
config, sizeof(*config));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(config);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* asking for the data path parameters */
|
||||
wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
|
||||
GFP_KERNEL);
|
||||
if (!wl->data_path) {
|
||||
wl1251_error("Couldnt allocate data path parameters");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = wl1251_acx_data_path_params(wl, wl->data_path);
|
||||
if (ret < 0) {
|
||||
kfree(wl->data_path);
|
||||
wl->data_path = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wl1251_hw_init(struct wl1251 *wl)
|
||||
{
|
||||
struct wl1251_acx_mem_map *wl_mem_map;
|
||||
int ret;
|
||||
|
||||
ret = wl1251_hw_init_hwenc_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Template settings */
|
||||
ret = wl1251_hw_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Default memory configuration */
|
||||
ret = wl1251_hw_init_mem_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Default data path configuration */
|
||||
ret = wl1251_hw_init_data_path_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* RX config */
|
||||
ret = wl1251_hw_init_rx_config(wl,
|
||||
RX_CFG_PROMISCUOUS | RX_CFG_TSF,
|
||||
RX_FILTER_OPTION_DEF);
|
||||
/* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
|
||||
RX_FILTER_OPTION_FILTER_ALL); */
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* TX queues config */
|
||||
ret = wl1251_hw_init_tx_queue_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* PHY layer config */
|
||||
ret = wl1251_hw_init_phy_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1251_hw_init_beacon_filter(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Bluetooth WLAN coexistence */
|
||||
ret = wl1251_hw_init_pta(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Energy detection */
|
||||
ret = wl1251_hw_init_energy_detection(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Beacons and boradcast settings */
|
||||
ret = wl1251_hw_init_beacon_broadcast(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Enable data path */
|
||||
ret = wl1251_cmd_data_path(wl, wl->channel, 1);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Default power state */
|
||||
ret = wl1251_hw_init_power_auth(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
wl_mem_map = wl->target_mem_map;
|
||||
wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
|
||||
wl_mem_map->num_tx_mem_blocks,
|
||||
wl->data_path->tx_control_addr,
|
||||
wl_mem_map->num_rx_mem_blocks,
|
||||
wl->data_path->rx_control_addr);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_data_path:
|
||||
kfree(wl->data_path);
|
||||
|
||||
out_free_memmap:
|
||||
kfree(wl->target_mem_map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче