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

This commit is contained in:
David S. Miller 2009-08-14 12:29:17 -07:00
Родитель 5c16807d3d 560ad81b6c
Коммит a8519de4a0
175 изменённых файлов: 22009 добавлений и 7641 удалений

Просмотреть файл

@ -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,9 +1083,6 @@ 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
@ -1094,9 +1090,6 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
* the relevant bits of the h/w.
*/
return ath5k_reset(sc, chan);
}
return 0;
}
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 {
* 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 full sleep\n");
ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
}
"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);
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 */
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,
ee->ee_x_gain[ee_mode],
pdg_curve_to_idx[0],
AR5K_RF_PD_GAIN_LO, true);
ath5k_hw_rfb_op(ah, rf_regs,
ee->ee_x_gain[ee_mode],
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,9 +236,8 @@ 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,
@ -265,7 +264,7 @@ static void ath9k_ani_restart(struct ath_hw *ah)
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);
}
}
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,10 +561,6 @@ 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);
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
@ -609,7 +600,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
ah->stats.ast_ani_cckerrs +=
cckPhyErrCnt - aniState->cckPhyErrCount;
aniState->cckPhyErrCount = cckPhyErrCnt;
}
if (aniState->listenTime > 5 * ah->aniperiod) {
if (aniState->ofdmPhyErrCount <= aniState->listenTime *
@ -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,14 +782,12 @@ 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;
}
}
if (ah->has_hw_phycounters) {
DPRINTF(ah->ah_sc, ATH_DBG_ANI,
"Setting OfdmErrBase = 0x%08x\n",
ah->ani[0].ofdmPhyErrBase);
@ -816,7 +797,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
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);
}
}

Просмотреть файл

@ -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;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -404,8 +404,13 @@ struct modal_eep_4k_header {
u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
u8 pdGainOverlap;
u8 ob_01;
u8 db1_01;
#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;
@ -415,13 +420,28 @@ struct modal_eep_4k_header {
u8 swSettleHt40;
u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
u8 db2_01;
#ifdef __BIG_ENDIAN_BITFIELD
u8 db2_1:4, db2_0:4;
#else
u8 db2_0:4, db2_1:4;
#endif
u8 version;
u16 ob_234;
u16 db1_234;
u16 db2_234;
#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;
@ -483,8 +503,6 @@ struct modal_eep_ar9287_header {
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];
@ -620,7 +637,6 @@ struct ar9287_eeprom {
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,7 +2215,6 @@ 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_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_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 */
/* 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]);
} 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]);
}
}
}
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);
}
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);
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);
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,8 +599,343 @@ 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. */
@ -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,23 +2226,31 @@ 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 =
cpu_to_le32(priv->hw_params.ct_kill_threshold);
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
sizeof(cmd), &cmd);
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, "
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
"succeeded, "
"critical temperature is %d\n",
cmd.critical_temperature_R);
priv->hw_params.ct_kill_threshold);
break;
}
}
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));
/* initialize to default */
static void iwl_power_init_handle(struct iwl_priv *priv)
{
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");
pow_data = &priv->power_data;
memset(pow_data, 0, sizeof(*pow_data));
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
if (priv->power_data.pci_pm)
cmd->flags |= IWL_POWER_PCI_PM_MSK;
}
IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
}
/* 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)
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_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;
}
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 */
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];
if (priv->power_data.pci_pm)
cmd->flags |= IWL_POWER_PCI_PM_MSK;
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 (final_mode == IWL_POWER_MODE_CAM)
if (!ret) {
if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
clear_bit(STATUS_POWER_PMI, &priv->status);
if (priv->cfg->ops->lib->update_chain_flags && update_chains)
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 "
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) {
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, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
rt2x00_set_field32(&reg, CSR14_TBCN, 0);
rt2x00_set_field32(&reg, 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, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
rt2x00_set_field32(&reg, CSR14_TBCN, 0);
rt2x00_set_field32(&reg, 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, &reg);
rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
rt2x00_set_field16(&reg, 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(&reg, TXRX_CSR19_TSF_COUNT, 1);
rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
reg0 = reg;
rt2x00_set_field16(&reg, 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(&reg, RX_FILTER_CFG_DROP_RTS,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
!(filter_flags & FIF_CONTROL));
!(filter_flags & FIF_PSPOLL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0);
rt2x00_set_field32(&reg, 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, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, 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,17 +455,14 @@ 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.
*/
rt2x00lib_antenna_diversity(rt2x00dev);
/*
* Reset the quality counters which recounted during each period.
* Evaluate antenna setup, make this the last step when
* rt2x00lib_antenna_diversity made changes the quality
* statistics will be reset.
*/
if (rt2x00lib_antenna_diversity(rt2x00dev))
rt2x00link_reset_qual(rt2x00dev);
/*

Просмотреть файл

@ -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,21 +348,12 @@ 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);
/* 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
@ -370,22 +361,16 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
rt2x00lib_config(rt2x00dev, conf, changed);
/*
* 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.
* 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.
*/
if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
rt2x00lib_config_antenna(rt2x00dev,
rt2x00dev->default_ant);
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);
}
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(&reg, TXRX_CSR0_DROP_PHYSICAL,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
!(filter_flags & FIF_PROMISC_IN_BSS));
rt2x00_set_field32(&reg, 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, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, 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(&reg, TXRX_CSR0_DROP_PHYSICAL,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
!(filter_flags & FIF_PROMISC_IN_BSS));
rt2x00_set_field32(&reg, 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, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, 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;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше