diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-06-08 19:44:21 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-06-08 19:44:21 +0200 |
commit | c0c33addcba2ce753b4e2746db99feaae2f82a85 (patch) | |
tree | dab480183ac0e64bfe9250e1f294705d1a424c78 | |
parent | net: add needed interrupt.h (diff) | |
parent | ath9k: make use of a helper to get paprd scale factor (diff) | |
download | linux-c0c33addcba2ce753b4e2746db99feaae2f82a85.tar.xz linux-c0c33addcba2ce753b4e2746db99feaae2f82a85.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
133 files changed, 3173 insertions, 1293 deletions
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 353781b5b78b..83e9adf46441 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -13,6 +13,11 @@ config BCMA Bus driver for Broadcom specific Advanced Microcontroller Bus Architecture. +# Support for Block-I/O. SELECT this from the driver that needs it. +config BCMA_BLOCKIO + bool + depends on BCMA + config BCMA_HOST_PCI_POSSIBLE bool depends on BCMA && PCI = y diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index 0d56245bcb79..cde0182bd1dc 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -1,4 +1,4 @@ -bcma-y += main.o scan.o core.o +bcma-y += main.o scan.o core.o sprom.o bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o bcma-y += driver_pci.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 2f72e9c585fd..12a75ab3dd23 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -19,6 +19,9 @@ extern void bcma_bus_unregister(struct bcma_bus *bus); /* scan.c */ int bcma_bus_scan(struct bcma_bus *bus); +/* sprom.c */ +int bcma_sprom_get(struct bcma_bus *bus); + #ifdef CONFIG_BCMA_HOST_PCI /* host_pci.c */ extern int __init bcma_host_pci_init(void); diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index e757e4e3c7e2..789d68b4858b 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -161,3 +161,26 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc) { bcma_pcicore_serdes_workaround(pc); } + +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, + bool enable) +{ + struct pci_dev *pdev = pc->core->bus->host_pci; + u32 coremask, tmp; + int err; + + err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); + if (err) + goto out; + + coremask = BIT(core->core_index) << 8; + if (enable) + tmp |= coremask; + else + tmp &= ~coremask; + + err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); + +out: + return err; +} diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 471a04013fe0..2a526bc3342f 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -65,6 +65,54 @@ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset, iowrite32(value, core->bus->mmio + offset); } +#ifdef CONFIG_BCMA_BLOCKIO +void bcma_host_pci_block_read(struct bcma_device *core, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + void __iomem *addr = core->bus->mmio + offset; + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + switch (reg_width) { + case sizeof(u8): + ioread8_rep(addr, buffer, count); + break; + case sizeof(u16): + WARN_ON(count & 1); + ioread16_rep(addr, buffer, count >> 1); + break; + case sizeof(u32): + WARN_ON(count & 3); + ioread32_rep(addr, buffer, count >> 2); + break; + default: + WARN_ON(1); + } +} + +void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + void __iomem *addr = core->bus->mmio + offset; + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + switch (reg_width) { + case sizeof(u8): + iowrite8_rep(addr, buffer, count); + break; + case sizeof(u16): + WARN_ON(count & 1); + iowrite16_rep(addr, buffer, count >> 1); + break; + case sizeof(u32): + WARN_ON(count & 3); + iowrite32_rep(addr, buffer, count >> 2); + break; + default: + WARN_ON(1); + } +} +#endif + static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset) { if (core->bus->mapped_core != core) @@ -87,6 +135,10 @@ const struct bcma_host_ops bcma_host_pci_ops = { .write8 = bcma_host_pci_write8, .write16 = bcma_host_pci_write16, .write32 = bcma_host_pci_write32, +#ifdef CONFIG_BCMA_BLOCKIO + .block_read = bcma_host_pci_block_read, + .block_write = bcma_host_pci_block_write, +#endif .aread32 = bcma_host_pci_aread32, .awrite32 = bcma_host_pci_awrite32, }; diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index be52344ed19d..11e96dc6011a 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -89,6 +89,8 @@ static int bcma_register_cores(struct bcma_bus *bus) switch (bus->hosttype) { case BCMA_HOSTTYPE_PCI: core->dev.parent = &bus->host_pci->dev; + core->dma_dev = &bus->host_pci->dev; + core->irq = bus->host_pci->irq; break; case BCMA_HOSTTYPE_NONE: case BCMA_HOSTTYPE_SDIO: @@ -144,6 +146,13 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_init(&bus->drv_pci); } + /* Try to get SPROM */ + err = bcma_sprom_get(bus); + if (err) { + pr_err("Failed to get SPROM: %d\n", err); + return -ENOENT; + } + /* Register found cores */ bcma_register_cores(bus); diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c new file mode 100644 index 000000000000..ffbb0e32e921 --- /dev/null +++ b/drivers/bcma/sprom.c @@ -0,0 +1,162 @@ +/* + * Broadcom specific AMBA + * SPROM reading + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" + +#include <linux/bcma/bcma.h> +#include <linux/bcma/bcma_regs.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> + +#define SPOFF(offset) ((offset) / sizeof(u16)) + +/************************************************** + * R/W ops. + **************************************************/ + +static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom) +{ + int i; + for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++) + sprom[i] = bcma_read16(bus->drv_cc.core, + BCMA_CC_SPROM + (i * 2)); +} + +/************************************************** + * Validation. + **************************************************/ + +static inline u8 bcma_crc8(u8 crc, u8 data) +{ + /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */ + static const u8 t[] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, + }; + return t[crc ^ data]; +} + +static u8 bcma_sprom_crc(const u16 *sprom) +{ + int word; + u8 crc = 0xFF; + + for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) { + crc = bcma_crc8(crc, sprom[word] & 0x00FF); + crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8); + } + crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF); + crc ^= 0xFF; + + return crc; +} + +static int bcma_sprom_check_crc(const u16 *sprom) +{ + u8 crc; + u8 expected_crc; + u16 tmp; + + crc = bcma_sprom_crc(sprom); + tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC; + expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; + if (crc != expected_crc) + return -EPROTO; + + return 0; +} + +static int bcma_sprom_valid(const u16 *sprom) +{ + u16 revision; + int err; + + err = bcma_sprom_check_crc(sprom); + if (err) + return err; + + revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV; + if (revision != 8) { + pr_err("Unsupported SPROM revision: %d\n", revision); + return -ENOENT; + } + + return 0; +} + +/************************************************** + * SPROM extraction. + **************************************************/ + +static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) +{ + u16 v; + int i; + + for (i = 0; i < 3; i++) { + v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; + *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); + } +} + +int bcma_sprom_get(struct bcma_bus *bus) +{ + u16 *sprom; + int err = 0; + + if (!bus->drv_cc.core) + return -EOPNOTSUPP; + + sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), + GFP_KERNEL); + if (!sprom) + return -ENOMEM; + + bcma_sprom_read(bus, sprom); + + err = bcma_sprom_valid(sprom); + if (err) + goto out; + + bcma_sprom_extract_r8(bus, sprom); + +out: + kfree(sprom); + return err; +} diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 7cf4317a2a84..17c4b56c3874 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -161,6 +161,7 @@ struct ath_common { const struct ath_bus_ops *bus_ops; bool btcoex_enabled; + bool disable_ani; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 22047628ccfa..b6c5d3715b96 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -72,6 +72,11 @@ static int modparam_all_channels; module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); +static int modparam_fastchanswitch; +module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); +MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); + + /* Module info */ MODULE_AUTHOR("Jiri Slaby"); MODULE_AUTHOR("Nick Kossifidis"); @@ -2686,6 +2691,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, struct ath5k_hw *ah = sc->ah; struct ath_common *common = ath5k_hw_common(ah); int ret, ani_mode; + bool fast; ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); @@ -2705,7 +2711,10 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, ath5k_drain_tx_buffs(sc); if (chan) sc->curchan = chan; - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL, + + fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0; + + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast, skip_pcu); if (ret) { ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 3510de2cf622..126a4eab35f3 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1124,8 +1124,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Non fatal, can happen eg. * on mode change */ ret = 0; - } else + } else { + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET, + "fast chan change successful\n"); return 0; + } } /* diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 077e8a6983fa..45b262fe2c25 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -28,11 +28,6 @@ static void ar9002_hw_set_desc_link(void *ds, u32 ds_link) ((struct ath_desc*) ds)->ds_link = ds_link; } -static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link) -{ - *ds_link = &((struct ath_desc *)ds)->ds_link; -} - static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) { u32 isr = 0; @@ -437,7 +432,6 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->rx_enable = ar9002_hw_rx_enable; ops->set_desc_link = ar9002_hw_set_desc_link; - ops->get_desc_link = ar9002_hw_get_desc_link; ops->get_isr = ar9002_hw_get_isr; ops->fill_txdesc = ar9002_hw_fill_txdesc; ops->proc_txdesc = ar9002_hw_proc_txdesc; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 10d71f7d3fc2..04e6be04acf9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -43,13 +43,6 @@ static void ar9003_hw_set_desc_link(void *ds, u32 ds_link) ads->ctl10 |= ar9003_calc_ptr_chksum(ads); } -static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link) -{ - struct ar9003_txc *ads = ds; - - *ds_link = &ads->link; -} - static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) { u32 isr = 0; @@ -498,7 +491,6 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->rx_enable = ar9003_hw_rx_enable; ops->set_desc_link = ar9003_hw_set_desc_link; - ops->get_desc_link = ar9003_hw_get_desc_link; ops->get_isr = ar9003_hw_get_isr; ops->fill_txdesc = ar9003_hw_fill_txdesc; ops->proc_txdesc = ar9003_hw_proc_txdesc; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index e4d6a87ec538..2e7f0f2567eb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -46,11 +46,10 @@ EXPORT_SYMBOL(ar9003_paprd_enable); static int ar9003_get_training_power_2g(struct ath_hw *ah) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G; + struct ath9k_channel *chan = ah->curchan; unsigned int power, scale, delta; - scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), AR9300_PAPRD_SCALE_1); + scale = ar9003_get_paprd_scale_factor(ah, chan); power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, AR_PHY_POWERTX_RATE5_POWERTXHT20_0); @@ -67,20 +66,10 @@ static int ar9003_get_training_power_2g(struct ath_hw *ah) static int ar9003_get_training_power_5g(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G; struct ath9k_channel *chan = ah->curchan; unsigned int power, scale, delta; - if (chan->channel >= 5700) - scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), - AR9300_PAPRD_SCALE_1); - else if (chan->channel >= 5400) - scale = MS(le32_to_cpu(hdr->papdRateMaskHt40), - AR9300_PAPRD_SCALE_2); - else - scale = MS(le32_to_cpu(hdr->papdRateMaskHt40), - AR9300_PAPRD_SCALE_1); + scale = ar9003_get_paprd_scale_factor(ah, chan); if (IS_CHAN_HT40(chan)) power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8, @@ -119,15 +108,16 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) else training_power = ar9003_get_training_power_5g(ah); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Training power: %d, Target power: %d\n", + training_power, ah->paprd_target_power); + if (training_power < 0) { ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD target power delta out of range"); return -ERANGE; } ah->paprd_training_power = training_power; - ath_dbg(common, ATH_DBG_CALIBRATE, - "Training power: %d, Target power: %d\n", - ah->paprd_training_power, ah->paprd_target_power); REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, ah->paprd_ratemask); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e99dfe6065bf..57933db57633 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -180,7 +180,7 @@ enum ATH_AGGR_STATUS { struct ath_txq { int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ u32 axq_qnum; /* ath9k hardware queue number */ - u32 *axq_link; + void *axq_link; struct list_head axq_q; spinlock_t axq_lock; u32 axq_depth; @@ -189,7 +189,6 @@ struct ath_txq { bool axq_tx_inprogress; struct list_head axq_acq; struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; - struct list_head txq_fifo_pending; u8 txq_headidx; u8 txq_tailidx; int pending_frames; @@ -429,6 +428,7 @@ void ath_hw_check(struct work_struct *work); void ath_hw_pll_work(struct work_struct *work); void ath_paprd_calibrate(struct work_struct *work); void ath_ani_calibrate(unsigned long data); +void ath_start_ani(struct ath_common *common); /**********/ /* BTCOEX */ @@ -670,12 +670,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops); void ath9k_deinit_device(struct ath_softc *sc); void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); -int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *hchan); -void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); -bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); bool ath9k_uses_beacons(int type); #ifdef CONFIG_ATH9K_PCI diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index d4d8ceced89b..0174cdb65a83 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -496,7 +496,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, u32 nexttbtt, intval; /* NB: the beacon interval is kept internally in TU's */ - intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); + intval = TU_TO_USEC(conf->beacon_interval); intval /= ATH_BCBUF; /* for staggered beacons */ nexttbtt = intval; @@ -543,7 +543,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, } memset(&bs, 0, sizeof(bs)); - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval = conf->beacon_interval; /* * Setup dtim and cfp parameters according to @@ -652,22 +652,13 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 tsf, delta, intval, nexttbtt; + u32 tsf, intval, nexttbtt; ath9k_reset_beacon_status(sc); - tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); - intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); - - if (!sc->beacon.bc_tstamp) - nexttbtt = tsf + intval; - else { - if (tsf > sc->beacon.bc_tstamp) - delta = (tsf - sc->beacon.bc_tstamp); - else - delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); - nexttbtt = tsf + intval - (delta % intval); - } + intval = TU_TO_USEC(conf->beacon_interval); + tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval); + nexttbtt = tsf + intval; ath_dbg(common, ATH_DBG_BEACON, "IBSS nexttbtt %u intval %u (%u)\n", diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index d55ffd7d4bd2..22d3a26e684d 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -176,6 +176,56 @@ static const struct file_operations fops_rx_chainmask = { .llseek = default_llseek, }; +static ssize_t read_file_disable_ani(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d\n", common->disable_ani); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_disable_ani(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + unsigned long disable_ani; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &disable_ani)) + return -EINVAL; + + common->disable_ani = !!disable_ani; + + if (disable_ani) { + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); + } else { + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); + } + + return count; +} + +static const struct file_operations fops_disable_ani = { + .read = read_file_disable_ani, + .write = write_file_disable_ani, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -550,6 +600,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("MPDUs Queued: ", queued); PR("MPDUs Completed: ", completed); + PR("MPDUs XRetried: ", xretries); PR("Aggregates: ", a_aggr); PR("AMPDUs Queued HW:", a_queued_hw); PR("AMPDUs Queued SW:", a_queued_sw); @@ -587,7 +638,6 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PRQLE("axq_q empty: ", axq_q); PRQLE("axq_acq empty: ", axq_acq); - PRQLE("txq_fifo_pending: ", txq_fifo_pending); for (i = 0; i < ATH_TXFIFO_DEPTH; i++) { snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i); PRQLE(tmp, txq_fifo[i]); @@ -807,7 +857,10 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, else TX_STAT_INC(qnum, a_completed); } else { - TX_STAT_INC(qnum, completed); + if (bf_isxretried(bf)) + TX_STAT_INC(qnum, xretries); + else + TX_STAT_INC(qnum, completed); } if (ts->ts_status & ATH9K_TXERR_FIFO) @@ -1160,6 +1213,8 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, sc, &fops_rx_chainmask); debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_tx_chainmask); + debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_disable_ani); debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_regidx); debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 8ce6ad80f4e2..4a04510e1111 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -116,6 +116,7 @@ struct ath_tx_stats { u32 tx_bytes_all; u32 queued; u32 completed; + u32 xretries; u32 a_aggr; u32 a_queued_hw; u32 a_queued_sw; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index aa6a73118706..57fe22b24247 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -79,7 +79,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, memset(&bs, 0, sizeof(bs)); - intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval = bss_conf->beacon_interval; bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); /* @@ -194,7 +194,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, u8 cmd_rsp; u64 tsf; - intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval = bss_conf->beacon_interval; intval /= ATH9K_HTC_MAX_BCN_VIF; nexttbtt = intval; @@ -250,7 +250,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, u8 cmd_rsp; u64 tsf; - intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval = bss_conf->beacon_interval; nexttbtt = intval; /* @@ -427,7 +427,7 @@ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, u16 intval; int slot; - intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD; + intval = priv->cur_beacon_conf.beacon_interval; tsf = be64_to_cpu(swba->tsf); tsftu = TSF_TO_TU(tsf >> 32, tsf); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 2f3e07263fcb..cb29e8875386 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -39,11 +39,6 @@ static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set_desc_link(ds, link); } -static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds, - u32 **link) -{ - ath9k_hw_ops(ah)->get_desc_link(ds, link); -} static inline bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, u8 rxchainmask, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1be7c8bbef84..6de2655e07dd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1785,16 +1785,16 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); REG_WRITE(ah, AR_BEACON_PERIOD, - TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); + TU_TO_USEC(bs->bs_intval)); REG_WRITE(ah, AR_DMA_BEACON_PERIOD, - TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); + TU_TO_USEC(bs->bs_intval)); REGWRITE_BUFFER_FLUSH(ah); REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); - beaconintval = bs->bs_intval & ATH9K_BEACON_PERIOD; + beaconintval = bs->bs_intval; if (bs->bs_sleepduration > beaconintval) beaconintval = bs->bs_sleepduration; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4b157c53d1a8..6a6fb5439831 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -403,7 +403,6 @@ struct ath9k_beacon_state { u32 bs_nexttbtt; u32 bs_nextdtim; u32 bs_intval; -#define ATH9K_BEACON_PERIOD 0x0000ffff #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ u32 bs_dtimperiod; u16 bs_cfpperiod; @@ -603,7 +602,6 @@ struct ath_hw_ops { int power_off); void (*rx_enable)(struct ath_hw *ah); void (*set_desc_link)(void *ds, u32 link); - void (*get_desc_link)(void *ds, u32 **link); bool (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan, u8 rxchainmask, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 45c585a337e9..d4b166cfdf60 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -519,7 +519,6 @@ static void ath9k_init_misc(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; - setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); sc->config.txpowlimit = ATH_TXPOWER_MAX; @@ -585,6 +584,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, common->priv = sc; common->debug_mask = ath9k_debug; common->btcoex_enabled = ath9k_btcoex_enable == 1; + common->disable_ani = false; spin_lock_init(&common->cc_lock); spin_lock_init(&sc->sc_serial_rw); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2ca351fe6d3c..7f945333e2d8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -62,14 +62,12 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) if (txq->axq_depth || !list_empty(&txq->axq_acq)) pending = true; - else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) - pending = !list_empty(&txq->txq_fifo_pending); spin_unlock_bh(&txq->axq_lock); return pending; } -bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) +static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) { unsigned long flags; bool ret; @@ -136,7 +134,7 @@ void ath9k_ps_restore(struct ath_softc *sc) spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } -static void ath_start_ani(struct ath_common *common) +void ath_start_ani(struct ath_common *common) { struct ath_hw *ah = common->ah; unsigned long timestamp = jiffies_to_msecs(jiffies); @@ -219,7 +217,7 @@ static int ath_update_survey_stats(struct ath_softc *sc) * by reseting the chip. To accomplish this we must first cleanup any pending * DMA, then restart stuff. */ -int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, +static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { struct ath_hw *ah = sc->sc_ah; @@ -302,7 +300,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_set_beacon(sc); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); - ath_start_ani(common); + if (!common->disable_ani) + ath_start_ani(common); } ps_restore: @@ -394,12 +393,14 @@ void ath_paprd_calibrate(struct work_struct *work) if (!caldata) return; + ath9k_ps_wakeup(sc); + if (ar9003_paprd_init_table(ah) < 0) - return; + goto fail_paprd; skb = alloc_skb(len, GFP_KERNEL); if (!skb) - return; + goto fail_paprd; skb_put(skb, len); memset(skb->data, 0, len); @@ -411,7 +412,6 @@ void ath_paprd_calibrate(struct work_struct *work) memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); - ath9k_ps_wakeup(sc); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { if (!(common->tx_chainmask & BIT(chain))) continue; @@ -515,24 +515,19 @@ void ath_ani_calibrate(unsigned long data) common->ani.checkani_timer = timestamp; } - /* Skip all processing if there's nothing to do. */ - if (longcal || shortcal || aniflag) { - /* Call ANI routine if necessary */ - if (aniflag) { - spin_lock_irqsave(&common->cc_lock, flags); - ath9k_hw_ani_monitor(ah, ah->curchan); - ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); - } + /* Call ANI routine if necessary */ + if (aniflag) { + spin_lock_irqsave(&common->cc_lock, flags); + ath9k_hw_ani_monitor(ah, ah->curchan); + ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + } - /* Perform calibration if necessary */ - if (longcal || shortcal) { - common->ani.caldone = - ath9k_hw_calibrate(ah, - ah->curchan, - common->rx_chainmask, - longcal); - } + /* Perform calibration if necessary */ + if (longcal || shortcal) { + common->ani.caldone = + ath9k_hw_calibrate(ah, ah->curchan, + common->rx_chainmask, longcal); } ath9k_ps_restore(sc); @@ -868,7 +863,7 @@ chip_reset: #undef SCHED_INTR } -void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) +static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -974,6 +969,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->hw_busy_count = 0; /* Stop ANI */ + del_timer_sync(&common->ani.timer); ath9k_ps_wakeup(sc); @@ -1023,7 +1019,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) spin_unlock_bh(&sc->sc_pcu_lock); /* Start ANI */ - ath_start_ani(common); + if (!common->disable_ani) + ath_start_ani(common); + ath9k_ps_restore(sc); return r; @@ -1412,10 +1410,14 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(ah, ah->imask); /* Set up ANI */ - if ((iter_data.naps + iter_data.nadhocs) > 0) { + if (iter_data.naps > 0) { sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_flags |= SC_OP_ANI_RUN; - ath_start_ani(common); + + if (!common->disable_ani) { + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); + } + } else { sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); @@ -1952,50 +1954,38 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_vif *avp = (void *)vif->drv_priv; - switch (sc->sc_ah->opmode) { - case NL80211_IFTYPE_ADHOC: - /* There can be only one vif available */ + /* + * Skip iteration if primary station vif's bss info + * was not changed + */ + if (sc->sc_flags & SC_OP_PRIM_STA_VIF) + return; + + if (bss_conf->assoc) { + sc->sc_flags |= SC_OP_PRIM_STA_VIF; + avp->primary_sta_vif = true; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); - /* configure beacon */ - if (bss_conf->enable_beacon) - ath_beacon_config(sc, vif); - break; - case NL80211_IFTYPE_STATION: - /* - * Skip iteration if primary station vif's bss info - * was not changed - */ - if (sc->sc_flags & SC_OP_PRIM_STA_VIF) - break; - - if (bss_conf->assoc) { - sc->sc_flags |= SC_OP_PRIM_STA_VIF; - avp->primary_sta_vif = true; - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah); - ath_dbg(common, ATH_DBG_CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, common->curbssid); - ath_beacon_config(sc, vif); - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; - /* Reset rssi stats */ - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + ath_beacon_config(sc, vif); + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; + /* Reset rssi stats */ + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + if (!common->disable_ani) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); } - break; - default: - break; + } } @@ -2005,6 +1995,9 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_vif *avp = (void *)vif->drv_priv; + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + return; + /* Reconfigure bss info */ if (avp->primary_sta_vif && !bss_conf->assoc) { ath_dbg(common, ATH_DBG_CONFIG, @@ -2023,8 +2016,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) * None of station vifs are associated. * Clear bssid & aid */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && - !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { + if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { ath9k_hw_write_associd(sc->sc_ah); /* Stop ANI */ sc->sc_flags &= ~SC_OP_ANI_RUN; @@ -2054,6 +2046,26 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, common->curbssid, common->curaid); } + if (changed & BSS_CHANGED_IBSS) { + /* There can be only one vif available */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + + if (bss_conf->ibss_joined) { + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + + if (!common->disable_ani) { + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); + } + + } else { + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); + } + } + /* Enable transmission of beacons (AP, IBSS, MESH) */ if ((changed & BSS_CHANGED_BEACON) || ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { @@ -2334,7 +2346,7 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) return false; } -int ath9k_tx_last_beacon(struct ieee80211_hw *hw) +static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3779b8977d47..ec012b4317af 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -53,7 +53,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, struct ath_tx_status *ts, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, - struct list_head *head); + struct list_head *head, bool internal); static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len); static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int nframes, int nbad, @@ -377,8 +377,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, bf_next = bf->bf_next; bf->bf_state.bf_type |= BUF_XRETRY; - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) || - !bf->bf_stale || bf_next != NULL) + if (!bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false); @@ -463,20 +462,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } } - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && - bf_next == NULL) { - /* - * Make sure the last desc is reclaimed if it - * not a holding desc. - */ - if (!bf_last->bf_stale) - list_move_tail(&bf->list, &bf_head); - else - INIT_LIST_HEAD(&bf_head); - } else { - BUG_ON(list_empty(bf_q)); + /* + * Make sure the last desc is reclaimed if it + * not a holding desc. + */ + if (!bf_last->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - } + else + INIT_LIST_HEAD(&bf_head); if (!txpending || (tid->state & AGGR_CLEANUP)) { /* @@ -837,7 +830,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type &= ~BUF_AGGR; ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); ath_buf_set_rate(sc, bf, fi->framelen); - ath_tx_txqaddbuf(sc, txq, &bf_q); + ath_tx_txqaddbuf(sc, txq, &bf_q, false); continue; } @@ -849,7 +842,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, /* anchor last desc of aggregate */ ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); - ath_tx_txqaddbuf(sc, txq, &bf_q); + ath_tx_txqaddbuf(sc, txq, &bf_q, false); TX_STAT_INC(txq->axq_qnum, a_aggr); } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH && @@ -1085,7 +1078,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->txq_headidx = txq->txq_tailidx = 0; for (i = 0; i < ATH_TXFIFO_DEPTH; i++) INIT_LIST_HEAD(&txq->txq_fifo[i]); - INIT_LIST_HEAD(&txq->txq_fifo_pending); } return &sc->tx.txq[axq_qnum]; } @@ -1155,13 +1147,8 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf) return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); } -/* - * Drain a given TX queue (could be Beacon or Data) - * - * This assumes output has been stopped and - * we do not need to block ath_tx_tasklet. - */ -void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) +static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *list, bool retry_tx) { struct ath_buf *bf, *lastbf; struct list_head bf_head; @@ -1170,93 +1157,63 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); - for (;;) { - spin_lock_bh(&txq->axq_lock); + while (!list_empty(list)) { + bf = list_first_entry(list, struct ath_buf, list); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { - txq->txq_headidx = txq->txq_tailidx = 0; - spin_unlock_bh(&txq->axq_lock); - break; - } else { - bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx], - struct ath_buf, list); - } - } else { - if (list_empty(&txq->axq_q)) { - txq->axq_link = NULL; - spin_unlock_bh(&txq->axq_lock); - break; - } - bf = list_first_entry(&txq->axq_q, struct ath_buf, - list); - - if (bf->bf_stale) { - list_del(&bf->list); - spin_unlock_bh(&txq->axq_lock); + if (bf->bf_stale) { + list_del(&bf->list); - ath_tx_return_buffer(sc, bf); - continue; - } + ath_tx_return_buffer(sc, bf); + continue; } lastbf = bf->bf_lastbf; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - list_cut_position(&bf_head, - &txq->txq_fifo[txq->txq_tailidx], - &lastbf->list); - INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); - } else { - /* remove ath_buf's of the same mpdu from txq */ - list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); - } + list_cut_position(&bf_head, list, &lastbf->list); txq->axq_depth--; if (bf_is_ampdu_not_probing(bf)) txq->axq_ampdu_depth--; - spin_unlock_bh(&txq->axq_lock); + spin_unlock_bh(&txq->axq_lock); if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0, retry_tx); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); + spin_lock_bh(&txq->axq_lock); } +} +/* + * Drain a given TX queue (could be Beacon or Data) + * + * This assumes output has been stopped and + * we do not need to block ath_tx_tasklet. + */ +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) +{ spin_lock_bh(&txq->axq_lock); - txq->axq_tx_inprogress = false; - spin_unlock_bh(&txq->axq_lock); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - spin_lock_bh(&txq->axq_lock); - while (!list_empty(&txq->txq_fifo_pending)) { - bf = list_first_entry(&txq->txq_fifo_pending, - struct ath_buf, list); - list_cut_position(&bf_head, - &txq->txq_fifo_pending, - &bf->bf_lastbf->list); - spin_unlock_bh(&txq->axq_lock); + int idx = txq->txq_tailidx; - if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, - &ts, 0, retry_tx); - else - ath_tx_complete_buf(sc, bf, txq, &bf_head, - &ts, 0, 0); - spin_lock_bh(&txq->axq_lock); + while (!list_empty(&txq->txq_fifo[idx])) { + ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx], + retry_tx); + + INCR(idx, ATH_TXFIFO_DEPTH); } - spin_unlock_bh(&txq->axq_lock); + txq->txq_tailidx = idx; } + txq->axq_link = NULL; + txq->axq_tx_inprogress = false; + ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx); + /* flush any pending frames if aggregation is enabled */ - if (sc->sc_flags & SC_OP_TXAGGR) { - if (!retry_tx) { - spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq); - spin_unlock_bh(&txq->axq_lock); - } - } + if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx) + ath_txq_drain_pending_buffers(sc, txq); + + spin_unlock_bh(&txq->axq_lock); } bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) @@ -1370,11 +1327,13 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) * assume the descriptors are already chained together by caller. */ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, - struct list_head *head) + struct list_head *head, bool internal) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath_buf *bf; + struct ath_buf *bf, *bf_last; + bool puttxbuf = false; + bool edma; /* * Insert the frame on the outbound list and @@ -1384,51 +1343,49 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, if (list_empty(head)) return; + edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); bf = list_first_entry(head, struct ath_buf, list); + bf_last = list_entry(head->prev, struct ath_buf, list); ath_dbg(common, ATH_DBG_QUEUE, "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - if (txq->axq_depth >= ATH_TXFIFO_DEPTH) { - list_splice_tail_init(head, &txq->txq_fifo_pending); - return; - } - if (!list_empty(&txq->txq_fifo[txq->txq_headidx])) - ath_dbg(common, ATH_DBG_XMIT, - "Initializing tx fifo %d which is non-empty\n", - txq->txq_headidx); - INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]); - list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]); + if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) { + list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]); INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH); - TX_STAT_INC(txq->axq_qnum, puttxbuf); - ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", - txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); + puttxbuf = true; } else { list_splice_tail_init(head, &txq->axq_q); - if (txq->axq_link == NULL) { - TX_STAT_INC(txq->axq_qnum, puttxbuf); - ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", - txq->axq_qnum, ito64(bf->bf_daddr), - bf->bf_desc); - } else { - *txq->axq_link = bf->bf_daddr; + if (txq->axq_link) { + ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr); ath_dbg(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", txq->axq_qnum, txq->axq_link, ito64(bf->bf_daddr), bf->bf_desc); - } - ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc, - &txq->axq_link); + } else if (!edma) + puttxbuf = true; + + txq->axq_link = bf_last->bf_desc; + } + + if (puttxbuf) { + TX_STAT_INC(txq->axq_qnum, puttxbuf); + ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); + ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); + } + + if (!edma) { TX_STAT_INC(txq->axq_qnum, txstart); ath9k_hw_txstart(ah, txq->axq_qnum); } - txq->axq_depth++; - if (bf_is_ampdu_not_probing(bf)) - txq->axq_ampdu_depth++; + + if (!internal) { + txq->axq_depth++; + if (bf_is_ampdu_not_probing(bf)) + txq->axq_ampdu_depth++; + } } static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, @@ -1470,7 +1427,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw); bf->bf_lastbf = bf; ath_buf_set_rate(sc, bf, fi->framelen); - ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); + ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false); } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, @@ -1490,7 +1447,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_lastbf = bf; fi = get_frame_info(bf->bf_mpdu); ath_buf_set_rate(sc, bf, fi->framelen); - ath_tx_txqaddbuf(sc, txq, bf_head); + ath_tx_txqaddbuf(sc, txq, bf_head, false); TX_STAT_INC(txq->axq_qnum, queued); } @@ -2077,6 +2034,38 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; } +static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, + struct ath_tx_status *ts, struct ath_buf *bf, + struct list_head *bf_head) +{ + int txok; + + txq->axq_depth--; + txok = !(ts->ts_status & ATH9K_TXERR_MASK); + txq->axq_tx_inprogress = false; + if (bf_is_ampdu_not_probing(bf)) + txq->axq_ampdu_depth--; + + spin_unlock_bh(&txq->axq_lock); + + if (!bf_isampdu(bf)) { + /* + * This frame is sent out as a single frame. + * Use hardware retry status for this frame. + */ + if (ts->ts_status & ATH9K_TXERR_XRETRY) + bf->bf_state.bf_type |= BUF_XRETRY; + ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true); + ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0); + } else + ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true); + + spin_lock_bh(&txq->axq_lock); + + if (sc->sc_flags & SC_OP_TXAGGR) + ath_txq_schedule(sc, txq); +} + static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hw *ah = sc->sc_ah; @@ -2085,20 +2074,18 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct list_head bf_head; struct ath_desc *ds; struct ath_tx_status ts; - int txok; int status; ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); + spin_lock_bh(&txq->axq_lock); for (;;) { - spin_lock_bh(&txq->axq_lock); if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); - spin_unlock_bh(&txq->axq_lock); break; } bf = list_first_entry(&txq->axq_q, struct ath_buf, list); @@ -2114,13 +2101,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) bf_held = NULL; if (bf->bf_stale) { bf_held = bf; - if (list_is_last(&bf_held->list, &txq->axq_q)) { - spin_unlock_bh(&txq->axq_lock); + if (list_is_last(&bf_held->list, &txq->axq_q)) break; - } else { - bf = list_entry(bf_held->list.next, - struct ath_buf, list); - } + + bf = list_entry(bf_held->list.next, struct ath_buf, + list); } lastbf = bf->bf_lastbf; @@ -2128,10 +2113,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) memset(&ts, 0, sizeof(ts)); status = ath9k_hw_txprocdesc(ah, ds, &ts); - if (status == -EINPROGRESS) { - spin_unlock_bh(&txq->axq_lock); + if (status == -EINPROGRESS) break; - } + TX_STAT_INC(txq->axq_qnum, txprocdesc); /* @@ -2145,42 +2129,14 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) list_cut_position(&bf_head, &txq->axq_q, lastbf->list.prev); - txq->axq_depth--; - txok = !(ts.ts_status & ATH9K_TXERR_MASK); - txq->axq_tx_inprogress = false; - if (bf_held) + if (bf_held) { list_del(&bf_held->list); - - if (bf_is_ampdu_not_probing(bf)) - txq->axq_ampdu_depth--; - - spin_unlock_bh(&txq->axq_lock); - - if (bf_held) ath_tx_return_buffer(sc, bf_held); - - if (!bf_isampdu(bf)) { - /* - * This frame is sent out as a single frame. - * Use hardware retry status for this frame. - */ - if (ts.ts_status & ATH9K_TXERR_XRETRY) - bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true); } - if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok, - true); - else - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0); - - spin_lock_bh(&txq->axq_lock); - - if (sc->sc_flags & SC_OP_TXAGGR) - ath_txq_schedule(sc, txq); - spin_unlock_bh(&txq->axq_lock); + ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); } + spin_unlock_bh(&txq->axq_lock); } static void ath_tx_complete_poll_work(struct work_struct *work) @@ -2237,17 +2193,16 @@ void ath_tx_tasklet(struct ath_softc *sc) void ath_tx_edma_tasklet(struct ath_softc *sc) { - struct ath_tx_status txs; + struct ath_tx_status ts; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; struct ath_txq *txq; struct ath_buf *bf, *lastbf; struct list_head bf_head; int status; - int txok; for (;;) { - status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs); + status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); if (status == -EINPROGRESS) break; if (status == -EIO) { @@ -2257,12 +2212,13 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) } /* Skip beacon completions */ - if (txs.qid == sc->beacon.beaconq) + if (ts.qid == sc->beacon.beaconq) continue; - txq = &sc->tx.txq[txs.qid]; + txq = &sc->tx.txq[ts.qid]; spin_lock_bh(&txq->axq_lock); + if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { spin_unlock_bh(&txq->axq_lock); return; @@ -2275,41 +2231,21 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) INIT_LIST_HEAD(&bf_head); list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx], &lastbf->list); - INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); - txq->axq_depth--; - txq->axq_tx_inprogress = false; - if (bf_is_ampdu_not_probing(bf)) - txq->axq_ampdu_depth--; - spin_unlock_bh(&txq->axq_lock); - txok = !(txs.ts_status & ATH9K_TXERR_MASK); - - if (!bf_isampdu(bf)) { - if (txs.ts_status & ATH9K_TXERR_XRETRY) - bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true); - } - - if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, - txok, true); - else - ath_tx_complete_buf(sc, bf, txq, &bf_head, - &txs, txok, 0); + if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { + INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); - spin_lock_bh(&txq->axq_lock); + if (!list_empty(&txq->axq_q)) { + struct list_head bf_q; - if (!list_empty(&txq->txq_fifo_pending)) { - INIT_LIST_HEAD(&bf_head); - bf = list_first_entry(&txq->txq_fifo_pending, - struct ath_buf, list); - list_cut_position(&bf_head, - &txq->txq_fifo_pending, - &bf->bf_lastbf->list); - ath_tx_txqaddbuf(sc, txq, &bf_head); - } else if (sc->sc_flags & SC_OP_TXAGGR) - ath_txq_schedule(sc, txq); + INIT_LIST_HEAD(&bf_q); + txq->axq_link = NULL; + list_splice_tail_init(&txq->axq_q, &bf_q); + ath_tx_txqaddbuf(sc, txq, &bf_q, true); + } + } + ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); spin_unlock_bh(&txq->axq_lock); } } diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 480595f04411..fe26bf448fdb 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -26,6 +26,11 @@ config B43 This driver can be built as a module (recommended) that will be called "b43". If unsure, say M. +config B43_BCMA + bool "Support for BCMA bus" + depends on B43 && BCMA && BROKEN + default y + # Auto-select SSB PCI-HOST support, if possible config B43_PCI_AUTOSELECT bool diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index cef334a8c669..95f7c001fda1 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,4 +1,5 @@ b43-y += main.o +b43-y += bus.o b43-y += tables.o b43-$(CONFIG_B43_PHY_N) += tables_nphy.o b43-$(CONFIG_B43_PHY_N) += radio_2055.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 25a78cfb7d15..1cb2ddee9dcf 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -5,12 +5,14 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/hw_random.h> +#include <linux/bcma/bcma.h> #include <linux/ssb/ssb.h> #include <net/mac80211.h> #include "debugfs.h" #include "leds.h" #include "rfkill.h" +#include "bus.h" #include "lo.h" #include "phy_common.h" @@ -414,6 +416,17 @@ enum { #define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */ #define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */ +/* BCMA 802.11 core specific IO Control (BCMA_IOCTL) flags */ +#define B43_BCMA_IOCTL_PHY_CLKEN 0x00000004 /* PHY Clock Enable */ +#define B43_BCMA_IOCTL_PHY_RESET 0x00000008 /* PHY Reset */ +#define B43_BCMA_IOCTL_MACPHYCLKEN 0x00000010 /* MAC PHY Clock Control Enable */ +#define B43_BCMA_IOCTL_PLLREFSEL 0x00000020 /* PLL Frequency Reference Select */ +#define B43_BCMA_IOCTL_PHY_BW 0x000000C0 /* PHY band width and clock speed mask (N-PHY+ only?) */ +#define B43_BCMA_IOCTL_PHY_BW_10MHZ 0x00000000 /* 10 MHz bandwidth, 40 MHz PHY */ +#define B43_BCMA_IOCTL_PHY_BW_20MHZ 0x00000040 /* 20 MHz bandwidth, 80 MHz PHY */ +#define B43_BCMA_IOCTL_PHY_BW_40MHZ 0x00000080 /* 40 MHz bandwidth, 160 MHz PHY */ +#define B43_BCMA_IOCTL_GMODE 0x00002000 /* G Mode Enable */ + /* 802.11 core specific TM State Low (SSB_TMSLOW) flags */ #define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ #define B43_TMSLOW_PHY_BANDWIDTH 0x00C00000 /* PHY band width and clock speed mask (N-PHY only) */ @@ -707,7 +720,8 @@ enum { /* Data structure for one wireless device (802.11 core) */ struct b43_wldev { - struct ssb_device *sdev; + struct ssb_device *sdev; /* TODO: remove when b43_bus_dev is ready */ + struct b43_bus_dev *dev; struct b43_wl *wl; /* The device initialization status. @@ -879,36 +893,59 @@ static inline enum ieee80211_band b43_current_band(struct b43_wl *wl) return wl->hw->conf.channel->band; } +static inline int b43_bus_may_powerdown(struct b43_wldev *wldev) +{ + return wldev->dev->bus_may_powerdown(wldev->dev); +} +static inline int b43_bus_powerup(struct b43_wldev *wldev, bool dynamic_pctl) +{ + return wldev->dev->bus_powerup(wldev->dev, dynamic_pctl); +} +static inline int b43_device_is_enabled(struct b43_wldev *wldev) +{ + return wldev->dev->device_is_enabled(wldev->dev); +} +static inline void b43_device_enable(struct b43_wldev *wldev, + u32 core_specific_flags) +{ + wldev->dev->device_enable(wldev->dev, core_specific_flags); +} +static inline void b43_device_disable(struct b43_wldev *wldev, + u32 core_specific_flags) +{ + wldev->dev->device_disable(wldev->dev, core_specific_flags); +} + static inline u16 b43_read16(struct b43_wldev *dev, u16 offset) { - return ssb_read16(dev->sdev, offset); + return dev->dev->read16(dev->dev, offset); } static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value) { - ssb_write16(dev->sdev, offset, value); + dev->dev->write16(dev->dev, offset, value); } static inline u32 b43_read32(struct b43_wldev *dev, u16 offset) { - return ssb_read32(dev->sdev, offset); + return dev->dev->read32(dev->dev, offset); } static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value) { - ssb_write32(dev->sdev, offset, value); + dev->dev->write32(dev->dev, offset, value); } static inline void b43_block_read(struct b43_wldev *dev, void *buffer, size_t count, u16 offset, u8 reg_width) { - ssb_block_read(dev->sdev, buffer, count, offset, reg_width); + dev->dev->block_read(dev->dev, buffer, count, offset, reg_width); } static inline void b43_block_write(struct b43_wldev *dev, const void *buffer, size_t count, u16 offset, u8 reg_width) { - ssb_block_write(dev->sdev, buffer, count, offset, reg_width); + dev->dev->block_write(dev->dev, buffer, count, offset, reg_width); } static inline bool b43_using_pio_transfers(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c new file mode 100644 index 000000000000..6c63aecd6ab4 --- /dev/null +++ b/drivers/net/wireless/b43/bus.c @@ -0,0 +1,122 @@ +/* + + Broadcom B43 wireless driver + Bus abstraction layer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "bus.h" + + +/* SSB */ + +static inline int b43_bus_ssb_bus_may_powerdown(struct b43_bus_dev *dev) +{ + return ssb_bus_may_powerdown(dev->sdev->bus); +} +static inline int b43_bus_ssb_bus_powerup(struct b43_bus_dev *dev, + bool dynamic_pctl) +{ + return ssb_bus_powerup(dev->sdev->bus, dynamic_pctl); +} +static inline int b43_bus_ssb_device_is_enabled(struct b43_bus_dev *dev) +{ + return ssb_device_is_enabled(dev->sdev); +} +static inline void b43_bus_ssb_device_enable(struct b43_bus_dev *dev, + u32 core_specific_flags) +{ + ssb_device_enable(dev->sdev, core_specific_flags); +} +static inline void b43_bus_ssb_device_disable(struct b43_bus_dev *dev, + u32 core_specific_flags) +{ + ssb_device_disable(dev->sdev, core_specific_flags); +} + +static inline u16 b43_bus_ssb_read16(struct b43_bus_dev *dev, u16 offset) +{ + return ssb_read16(dev->sdev, offset); +} +static inline u32 b43_bus_ssb_read32(struct b43_bus_dev *dev, u16 offset) +{ + return ssb_read32(dev->sdev, offset); +} +static inline +void b43_bus_ssb_write16(struct b43_bus_dev *dev, u16 offset, u16 value) +{ + ssb_write16(dev->sdev, offset, value); +} +static inline +void b43_bus_ssb_write32(struct b43_bus_dev *dev, u16 offset, u32 value) +{ + ssb_write32(dev->sdev, offset, value); +} +static inline +void b43_bus_ssb_block_read(struct b43_bus_dev *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + ssb_block_read(dev->sdev, buffer, count, offset, reg_width); +} +static inline +void b43_bus_ssb_block_write(struct b43_bus_dev *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + ssb_block_write(dev->sdev, buffer, count, offset, reg_width); +} + +struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev) +{ + struct b43_bus_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); + + dev->bus_type = B43_BUS_SSB; + dev->sdev = sdev; + + dev->bus_may_powerdown = b43_bus_ssb_bus_may_powerdown; + dev->bus_powerup = b43_bus_ssb_bus_powerup; + dev->device_is_enabled = b43_bus_ssb_device_is_enabled; + dev->device_enable = b43_bus_ssb_device_enable; + dev->device_disable = b43_bus_ssb_device_disable; + + dev->read16 = b43_bus_ssb_read16; + dev->read32 = b43_bus_ssb_read32; + dev->write16 = b43_bus_ssb_write16; + dev->write32 = b43_bus_ssb_write32; + dev->block_read = b43_bus_ssb_block_read; + dev->block_write = b43_bus_ssb_block_write; + + dev->dev = sdev->dev; + dev->dma_dev = sdev->dma_dev; + dev->irq = sdev->irq; + + dev->board_vendor = sdev->bus->boardinfo.vendor; + dev->board_type = sdev->bus->boardinfo.type; + dev->board_rev = sdev->bus->boardinfo.rev; + + dev->chip_id = sdev->bus->chip_id; + dev->chip_rev = sdev->bus->chip_rev; + dev->chip_pkg = sdev->bus->chip_package; + + dev->bus_sprom = &sdev->bus->sprom; + + dev->core_id = sdev->id.coreid; + dev->core_rev = sdev->id.revision; + + return dev; +} diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h new file mode 100644 index 000000000000..79a5ab4270c3 --- /dev/null +++ b/drivers/net/wireless/b43/bus.h @@ -0,0 +1,62 @@ +#ifndef B43_BUS_H_ +#define B43_BUS_H_ + +enum b43_bus_type { + B43_BUS_SSB, +}; + +struct b43_bus_dev { + enum b43_bus_type bus_type; + union { + struct ssb_device *sdev; + }; + + int (*bus_may_powerdown)(struct b43_bus_dev *dev); + int (*bus_powerup)(struct b43_bus_dev *dev, bool dynamic_pctl); + int (*device_is_enabled)(struct b43_bus_dev *dev); + void (*device_enable)(struct b43_bus_dev *dev, + u32 core_specific_flags); + void (*device_disable)(struct b43_bus_dev *dev, + u32 core_specific_flags); + + u16 (*read16)(struct b43_bus_dev *dev, u16 offset); + u32 (*read32)(struct b43_bus_dev *dev, u16 offset); + void (*write16)(struct b43_bus_dev *dev, u16 offset, u16 value); + void (*write32)(struct b43_bus_dev *dev, u16 offset, u32 value); + void (*block_read)(struct b43_bus_dev *dev, void *buffer, + size_t count, u16 offset, u8 reg_width); + void (*block_write)(struct b43_bus_dev *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width); + + struct device *dev; + struct device *dma_dev; + unsigned int irq; + + u16 board_vendor; + u16 board_type; + u16 board_rev; + + u16 chip_id; + u8 chip_rev; + u8 chip_pkg; + + struct ssb_sprom *bus_sprom; + + u16 core_id; + u8 core_rev; +}; + +static inline bool b43_bus_host_is_pcmcia(struct b43_bus_dev *dev) +{ + return (dev->bus_type == B43_BUS_SSB && + dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA); +} +static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev) +{ + return (dev->bus_type == B43_BUS_SSB && + dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO); +} + +struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev); + +#endif /* B43_BUS_H_ */ diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 47d44bcff37d..d02cf8300e3e 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -333,10 +333,10 @@ static inline dma_addr_t dmaaddr; if (tx) { - dmaaddr = dma_map_single(ring->dev->sdev->dma_dev, + dmaaddr = dma_map_single(ring->dev->dev->dma_dev, buf, len, DMA_TO_DEVICE); } else { - dmaaddr = dma_map_single(ring->dev->sdev->dma_dev, + dmaaddr = dma_map_single(ring->dev->dev->dma_dev, buf, len, DMA_FROM_DEVICE); } @@ -348,10 +348,10 @@ static inline dma_addr_t addr, size_t len, int tx) { if (tx) { - dma_unmap_single(ring->dev->sdev->dma_dev, + dma_unmap_single(ring->dev->dev->dma_dev, addr, len, DMA_TO_DEVICE); } else { - dma_unmap_single(ring->dev->sdev->dma_dev, + dma_unmap_single(ring->dev->dev->dma_dev, addr, len, DMA_FROM_DEVICE); } } @@ -361,7 +361,7 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_cpu(ring->dev->sdev->dma_dev, + dma_sync_single_for_cpu(ring->dev->dev->dma_dev, addr, len, DMA_FROM_DEVICE); } @@ -370,7 +370,7 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_device(ring->dev->sdev->dma_dev, + dma_sync_single_for_device(ring->dev->dev->dma_dev, addr, len, DMA_FROM_DEVICE); } @@ -401,7 +401,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring) */ if (ring->type == B43_DMA_64BIT) flags |= GFP_DMA; - ring->descbase = dma_alloc_coherent(ring->dev->sdev->dma_dev, + ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE, &(ring->dmabase), flags); if (!ring->descbase) { @@ -415,7 +415,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring) static void free_ringmemory(struct b43_dmaring *ring) { - dma_free_coherent(ring->dev->sdev->dma_dev, B43_DMA_RINGMEMSIZE, + dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE, ring->descbase, ring->dmabase); } @@ -523,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, dma_addr_t addr, size_t buffersize, bool dma_to_device) { - if (unlikely(dma_mapping_error(ring->dev->sdev->dma_dev, addr))) + if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr))) return 1; switch (ring->type) { @@ -757,14 +757,14 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring) static void free_all_descbuffers(struct b43_dmaring *ring) { - struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; int i; if (!ring->used_slots) return; for (i = 0; i < ring->nr_slots; i++) { - desc = ring->ops->idx2desc(ring, i, &meta); + /* get meta - ignore returned value */ + ring->ops->idx2desc(ring, i, &meta); if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) { B43_WARN_ON(!ring->tx); @@ -869,7 +869,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, goto err_kfree_meta; /* test for ability to dma to txhdr_cache */ - dma_test = dma_map_single(dev->sdev->dma_dev, + dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, b43_txhdr_size(dev), DMA_TO_DEVICE); @@ -884,7 +884,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = dma_map_single(dev->sdev->dma_dev, + dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, b43_txhdr_size(dev), DMA_TO_DEVICE); @@ -898,7 +898,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } } - dma_unmap_single(dev->sdev->dma_dev, + dma_unmap_single(dev->dev->dma_dev, dma_test, b43_txhdr_size(dev), DMA_TO_DEVICE); } @@ -1013,9 +1013,9 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) /* Try to set the DMA mask. If it fails, try falling back to a * lower mask, as we can always also support a lower one. */ while (1) { - err = dma_set_mask(dev->sdev->dma_dev, mask); + err = dma_set_mask(dev->dev->dma_dev, mask); if (!err) { - err = dma_set_coherent_mask(dev->sdev->dma_dev, mask); + err = dma_set_coherent_mask(dev->dev->dma_dev, mask); if (!err) break; } @@ -1085,7 +1085,7 @@ int b43_dma_init(struct b43_wldev *dev) goto err_destroy_mcast; /* No support for the TX status DMA ring. */ - B43_WARN_ON(dev->sdev->id.revision < 5); + B43_WARN_ON(dev->dev->core_rev < 5); b43dbg(dev->wl, "%u-bit DMA initialized\n", (unsigned int)type); @@ -1388,7 +1388,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, { const struct b43_dma_ops *ops; struct b43_dmaring *ring; - struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; int slot, firstused; bool frame_succeed; @@ -1416,7 +1415,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ops = ring->ops; while (1) { B43_WARN_ON(slot < 0 || slot >= ring->nr_slots); - desc = ops->idx2desc(ring, slot, &meta); + /* get meta - ignore returned value */ + ops->idx2desc(ring, slot, &meta); if (b43_dma_ptr_is_poisoned(meta->skb)) { b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) " diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 0cafafe368af..b56ed41fc1bd 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -138,7 +138,7 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, led->led_dev.default_trigger = default_trigger; led->led_dev.brightness_set = b43_led_brightness_set; - err = led_classdev_register(dev->sdev->dev, &led->led_dev); + err = led_classdev_register(dev->dev->dev, &led->led_dev); if (err) { b43warn(dev->wl, "LEDs: Failed to register %s\n", name); led->wl = NULL; @@ -215,13 +215,12 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev, enum b43_led_behaviour *behaviour, bool *activelow) { - struct ssb_bus *bus = dev->sdev->bus; u8 sprom[4]; - sprom[0] = bus->sprom.gpio0; - sprom[1] = bus->sprom.gpio1; - sprom[2] = bus->sprom.gpio2; - sprom[3] = bus->sprom.gpio3; + sprom[0] = dev->dev->bus_sprom->gpio0; + sprom[1] = dev->dev->bus_sprom->gpio1; + sprom[2] = dev->dev->bus_sprom->gpio2; + sprom[3] = dev->dev->bus_sprom->gpio3; if (sprom[led_index] == 0xFF) { /* There is no LED information in the SPROM @@ -231,12 +230,12 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev, case 0: *behaviour = B43_LED_ACTIVITY; *activelow = 1; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + if (dev->dev->board_vendor == PCI_VENDOR_ID_COMPAQ) *behaviour = B43_LED_RADIO_ALL; break; case 1: *behaviour = B43_LED_RADIO_B; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + if (dev->dev->board_vendor == PCI_VENDOR_ID_ASUSTEK) *behaviour = B43_LED_ASSOC; break; case 2: diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 2ef7d4b38540..a3dc8bb8ca95 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -98,7 +98,7 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev, rfover |= pga; rfover |= lna; rfover |= trsw_rx; - if ((dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) + if ((dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA) && phy->rev > 6) rfover |= B43_PHY_RFOVERVAL_EXTLNA; @@ -301,14 +301,12 @@ static void lo_measure_gain_values(struct b43_wldev *dev, max_rx_gain = 0; if (has_loopback_gain(phy)) { - int trsw_rx = 0; int trsw_rx_gain; if (use_trsw_rx) { trsw_rx_gain = gphy->trsw_rx_gain / 2; if (max_rx_gain >= trsw_rx_gain) { trsw_rx_gain = max_rx_gain - trsw_rx_gain; - trsw_rx = 0x20; } } else trsw_rx_gain = max_rx_gain; @@ -387,7 +385,7 @@ struct lo_g_saved_values { static void lo_measure_setup(struct b43_wldev *dev, struct lo_g_saved_values *sav) { - struct ssb_sprom *sprom = &dev->sdev->bus->sprom; + struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; struct b43_txpower_lo_control *lo = gphy->lo_control; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d74bc5ff8e13..cae31463ead9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -113,6 +113,16 @@ static int b43_modparam_pio = B43_PIO_DEFAULT; module_param_named(pio, b43_modparam_pio, int, 0644); MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO"); +#ifdef CONFIG_B43_BCMA +static const struct bcma_device_id b43_bcma_tbl[] = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS), + BCMA_CORETABLE_END +}; +MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl); +#endif + static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), @@ -548,7 +558,7 @@ void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) { u32 low, high; - B43_WARN_ON(dev->sdev->id.revision < 3); + B43_WARN_ON(dev->dev->core_rev < 3); /* The hardware guarantees us an atomic read, if we * read the low register first. */ @@ -586,7 +596,7 @@ static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf) { u32 low, high; - B43_WARN_ON(dev->sdev->id.revision < 3); + B43_WARN_ON(dev->dev->core_rev < 3); low = tsf; high = (tsf >> 32); @@ -714,7 +724,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) b43_ram_write(dev, i * 4, buffer[i]); b43_write16(dev, 0x0568, 0x0000); - if (dev->sdev->id.revision < 11) + if (dev->dev->core_rev < 11) b43_write16(dev, 0x07C0, 0x0000); else b43_write16(dev, 0x07C0, 0x0100); @@ -1132,7 +1142,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) b43_write32(dev, B43_MMIO_MACCTL, macctl); /* Commit write */ b43_read32(dev, B43_MMIO_MACCTL); - if (awake && dev->sdev->id.revision >= 5) { + if (awake && dev->dev->core_rev >= 5) { /* Wait for the microcode to wake up. */ for (i = 0; i < 100; i++) { ucstat = b43_shm_read16(dev, B43_SHM_SHARED, @@ -1144,35 +1154,39 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } -static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, u32 flags) +static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode) { + struct ssb_device *sdev = dev->dev->sdev; u32 tmslow; + u32 flags = 0; + if (gmode) + flags |= B43_TMSLOW_GMODE; flags |= B43_TMSLOW_PHYCLKEN; flags |= B43_TMSLOW_PHYRESET; if (dev->phy.type == B43_PHYTYPE_N) flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */ - ssb_device_enable(dev->sdev, flags); + b43_device_enable(dev, flags); msleep(2); /* Wait for the PLL to turn on. */ /* Now take the PHY out of Reset again */ - tmslow = ssb_read32(dev->sdev, SSB_TMSLOW); + tmslow = ssb_read32(sdev, SSB_TMSLOW); tmslow |= SSB_TMSLOW_FGC; tmslow &= ~B43_TMSLOW_PHYRESET; - ssb_write32(dev->sdev, SSB_TMSLOW, tmslow); - ssb_read32(dev->sdev, SSB_TMSLOW); /* flush */ + ssb_write32(sdev, SSB_TMSLOW, tmslow); + ssb_read32(sdev, SSB_TMSLOW); /* flush */ msleep(1); tmslow &= ~SSB_TMSLOW_FGC; - ssb_write32(dev->sdev, SSB_TMSLOW, tmslow); - ssb_read32(dev->sdev, SSB_TMSLOW); /* flush */ + ssb_write32(sdev, SSB_TMSLOW, tmslow); + ssb_read32(sdev, SSB_TMSLOW); /* flush */ msleep(1); } -void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) +void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode) { u32 macctl; - b43_ssb_wireless_core_reset(dev, flags); + b43_ssb_wireless_core_reset(dev, gmode); /* Turn Analog ON, but only if we already know the PHY-type. * This protects against very early setup where we don't know the @@ -1183,7 +1197,7 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) macctl = b43_read32(dev, B43_MMIO_MACCTL); macctl &= ~B43_MACCTL_GMODE; - if (flags & B43_TMSLOW_GMODE) + if (gmode) macctl |= B43_MACCTL_GMODE; macctl |= B43_MACCTL_IHR_ENABLED; b43_write32(dev, B43_MMIO_MACCTL, macctl); @@ -1221,7 +1235,7 @@ static void drain_txstatus_queue(struct b43_wldev *dev) { u32 dummy; - if (dev->sdev->id.revision < 5) + if (dev->dev->core_rev < 5) return; /* Read all entries from the microcode TXstatus FIFO * and throw them away. @@ -1427,9 +1441,9 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, /* Get the mask of available antennas. */ if (dev->phy.gmode) - antenna_mask = dev->sdev->bus->sprom.ant_available_bg; + antenna_mask = dev->dev->bus_sprom->ant_available_bg; else - antenna_mask = dev->sdev->bus->sprom.ant_available_a; + antenna_mask = dev->dev->bus_sprom->ant_available_a; if (!(antenna_mask & (1 << (antenna_nr - 1)))) { /* This antenna is not available. Fall back to default. */ @@ -1644,7 +1658,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) mutex_lock(&wl->mutex); dev = wl->current_dev; if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { - if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) { + if (b43_bus_host_is_sdio(dev->dev)) { /* wl->mutex is enough. */ b43_do_beacon_update_trigger_work(dev); mmiowb(); @@ -1689,7 +1703,7 @@ static void b43_update_templates(struct b43_wl *wl) static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) { b43_time_lock(dev); - if (dev->sdev->id.revision >= 3) { + if (dev->dev->core_rev >= 3) { b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16)); b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10)); } else { @@ -2063,7 +2077,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, B43_WARN_ON(1); return -ENOSYS; } - err = request_firmware(&blob, ctx->fwname, ctx->dev->sdev->dev); + err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); if (err == -ENOENT) { snprintf(ctx->errors[ctx->req_type], sizeof(ctx->errors[ctx->req_type]), @@ -2113,7 +2127,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) { struct b43_wldev *dev = ctx->dev; struct b43_firmware *fw = &ctx->dev->fw; - const u8 rev = ctx->dev->sdev->id.revision; + const u8 rev = ctx->dev->dev->core_rev; const char *filename; u32 tmshigh; int err; @@ -2157,7 +2171,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) switch (dev->phy.type) { case B43_PHYTYPE_A: if ((rev >= 5) && (rev <= 10)) { - tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH); + tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH); if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) filename = "a0g1initvals5"; else @@ -2202,7 +2216,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) switch (dev->phy.type) { case B43_PHYTYPE_A: if ((rev >= 5) && (rev <= 10)) { - tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH); + tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH); if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) filename = "a0g1bsinitvals5"; else @@ -2448,7 +2462,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u", dev->fw.rev, dev->fw.patch); - wiphy->hw_version = dev->sdev->id.coreid; + wiphy->hw_version = dev->dev->core_id; if (b43_is_old_txhdr_format(dev)) { /* We're over the deadline, but we keep support for old fw @@ -2566,7 +2580,7 @@ out: */ static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; #ifdef CONFIG_SSB_DRIVER_PCICORE return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev); @@ -2588,7 +2602,7 @@ static int b43_gpio_init(struct b43_wldev *dev) mask = 0x0000001F; set = 0x0000000F; - if (dev->sdev->bus->chip_id == 0x4301) { + if (dev->dev->chip_id == 0x4301) { mask |= 0x0060; set |= 0x0060; } @@ -2599,14 +2613,14 @@ static int b43_gpio_init(struct b43_wldev *dev) mask |= 0x0180; set |= 0x0180; } - if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) { + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) { b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x0200); mask |= 0x0200; set |= 0x0200; } - if (dev->sdev->id.revision >= 2) + if (dev->dev->core_rev >= 2) mask |= 0x0010; /* FIXME: This is redundant. */ gpiodev = b43_ssb_gpio_dev(dev); @@ -2741,15 +2755,15 @@ static void b43_adjust_opmode(struct b43_wldev *dev) /* Workaround: On old hardware the HW-MAC-address-filter * doesn't work properly, so always run promisc in filter * it in software. */ - if (dev->sdev->id.revision <= 4) + if (dev->dev->core_rev <= 4) ctl |= B43_MACCTL_PROMISC; b43_write32(dev, B43_MMIO_MACCTL, ctl); cfp_pretbtt = 2; if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) { - if (dev->sdev->bus->chip_id == 0x4306 && - dev->sdev->bus->chip_rev == 3) + if (dev->dev->chip_id == 0x4306 && + dev->dev->chip_rev == 3) cfp_pretbtt = 100; else cfp_pretbtt = 50; @@ -2907,7 +2921,7 @@ static int b43_chip_init(struct b43_wldev *dev) b43_write16(dev, 0x005E, value16); } b43_write32(dev, 0x0100, 0x01000000); - if (dev->sdev->id.revision < 5) + if (dev->dev->core_rev < 5) b43_write32(dev, 0x010C, 0x01000000); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) @@ -2922,7 +2936,7 @@ static int b43_chip_init(struct b43_wldev *dev) /* Initially set the wireless operation mode. */ b43_adjust_opmode(dev); - if (dev->sdev->id.revision < 3) { + if (dev->dev->core_rev < 3) { b43_write16(dev, 0x060E, 0x0000); b43_write16(dev, 0x0610, 0x8000); b43_write16(dev, 0x0604, 0x0000); @@ -3105,7 +3119,7 @@ static int b43_validate_chipaccess(struct b43_wldev *dev) b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0); b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4); - if ((dev->sdev->id.revision >= 3) && (dev->sdev->id.revision <= 10)) { + if ((dev->dev->core_rev >= 3) && (dev->dev->core_rev <= 10)) { /* The 32bit register shadows the two 16bit registers * with update sideeffects. Validate this. */ b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA); @@ -3954,7 +3968,7 @@ redo: /* Disable interrupts on the device. */ b43_set_status(dev, B43_STAT_INITIALIZED); - if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) { + if (b43_bus_host_is_sdio(dev->dev)) { /* wl->mutex is locked. That is enough. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ @@ -3967,11 +3981,11 @@ redo: /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */ orig_dev = dev; mutex_unlock(&wl->mutex); - if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) { + if (b43_bus_host_is_sdio(dev->dev)) { b43_sdio_free_irq(dev); } else { - synchronize_irq(dev->sdev->irq); - free_irq(dev->sdev->irq, dev); + synchronize_irq(dev->dev->irq); + free_irq(dev->dev->irq, dev); } mutex_lock(&wl->mutex); dev = wl->current_dev; @@ -4004,19 +4018,19 @@ static int b43_wireless_core_start(struct b43_wldev *dev) B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); drain_txstatus_queue(dev); - if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) { + if (b43_bus_host_is_sdio(dev->dev)) { err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler); if (err) { b43err(dev->wl, "Cannot request SDIO IRQ\n"); goto out; } } else { - err = request_threaded_irq(dev->sdev->irq, b43_interrupt_handler, + err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, b43_interrupt_thread_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (err) { b43err(dev->wl, "Cannot request IRQ-%d\n", - dev->sdev->irq); + dev->dev->irq); goto out; } } @@ -4096,10 +4110,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) analog_type, phy_type, phy_rev); /* Get RADIO versioning */ - if (dev->sdev->bus->chip_id == 0x4317) { - if (dev->sdev->bus->chip_rev == 0) + if (dev->dev->chip_id == 0x4317) { + if (dev->dev->chip_rev == 0) tmp = 0x3205017F; - else if (dev->sdev->bus->chip_rev == 1) + else if (dev->dev->chip_rev == 1) tmp = 0x4205017F; else tmp = 0x5205017F; @@ -4204,7 +4218,7 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev) static void b43_bluetooth_coext_enable(struct b43_wldev *dev) { - struct ssb_sprom *sprom = &dev->sdev->bus->sprom; + struct ssb_sprom *sprom = dev->dev->bus_sprom; u64 hf; if (!modparam_btcoex) @@ -4231,16 +4245,21 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev) static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus; u32 tmp; + if (dev->dev->bus_type != B43_BUS_SSB) + return; + + bus = dev->dev->sdev->bus; + if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) || (bus->chip_id == 0x4312)) { - tmp = ssb_read32(dev->sdev, SSB_IMCFGLO); + tmp = ssb_read32(dev->dev->sdev, SSB_IMCFGLO); tmp &= ~SSB_IMCFGLO_REQTO; tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x3; - ssb_write32(dev->sdev, SSB_IMCFGLO, tmp); + ssb_write32(dev->dev->sdev, SSB_IMCFGLO, tmp); ssb_commit_settings(bus); } } @@ -4310,29 +4329,26 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) dev->wl->current_beacon = NULL; } - ssb_device_disable(dev->sdev, 0); - ssb_bus_may_powerdown(dev->sdev->bus); + b43_device_disable(dev, 0); + b43_bus_may_powerdown(dev); } /* Initialize a wireless core */ static int b43_wireless_core_init(struct b43_wldev *dev) { struct ssb_bus *bus = dev->sdev->bus; - struct ssb_sprom *sprom = &bus->sprom; + struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy *phy = &dev->phy; int err; u64 hf; - u32 tmp; B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); - err = ssb_bus_powerup(bus, 0); + err = b43_bus_powerup(dev, 0); if (err) goto out; - if (!ssb_device_is_enabled(dev->sdev)) { - tmp = phy->gmode ? B43_TMSLOW_GMODE : 0; - b43_wireless_core_reset(dev, tmp); - } + if (!b43_device_is_enabled(dev)) + b43_wireless_core_reset(dev, phy->gmode); /* Reset all data structures. */ setup_struct_wldev_for_init(dev); @@ -4352,7 +4368,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) if (err) goto err_busdown; b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_WLCOREREV, dev->sdev->id.revision); + B43_SHM_SH_WLCOREREV, dev->dev->core_rev); hf = b43_hf_read(dev); if (phy->type == B43_PHYTYPE_G) { hf |= B43_HF_SYMW; @@ -4399,8 +4415,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); - if ((dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA) || - (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) || + if (b43_bus_host_is_pcmcia(dev->dev) || + b43_bus_host_is_sdio(dev->dev) || dev->use_pio) { dev->__using_pio_transfers = 1; err = b43_pio_init(dev); @@ -4414,7 +4430,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_set_synth_pu_delay(dev, 1); b43_bluetooth_coext_enable(dev); - ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)); + b43_bus_powerup(dev, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)); b43_upload_card_macaddress(dev); b43_security_init(dev); @@ -4431,7 +4447,7 @@ out: err_chip_exit: b43_chip_exit(dev); err_busdown: - ssb_bus_may_powerdown(bus); + b43_bus_may_powerdown(dev); B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); return err; } @@ -4741,7 +4757,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL; int err; bool have_2ghz_phy = 0, have_5ghz_phy = 0; - u32 tmp; /* Do NOT do any device initialization here. * Do it in wireless_core_init() instead. @@ -4750,13 +4765,13 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) * that in core_init(), too. */ - err = ssb_bus_powerup(bus, 0); + err = b43_bus_powerup(dev, 0); if (err) { b43err(wl, "Bus powerup failed\n"); goto out; } /* Get the PHY type. */ - if (dev->sdev->id.revision >= 5) { + if (dev->dev->core_rev >= 5) { u32 tmshigh; tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH); @@ -4767,8 +4782,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) dev->phy.gmode = have_2ghz_phy; dev->phy.radio_on = 1; - tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; - b43_wireless_core_reset(dev, tmp); + b43_wireless_core_reset(dev, dev->phy.gmode); err = b43_phy_versioning(dev); if (err) @@ -4816,8 +4830,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) goto err_powerdown; dev->phy.gmode = have_2ghz_phy; - tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; - b43_wireless_core_reset(dev, tmp); + b43_wireless_core_reset(dev, dev->phy.gmode); err = b43_validate_chipaccess(dev); if (err) @@ -4832,8 +4845,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) INIT_WORK(&dev->restart_work, b43_chip_reset); dev->phy.ops->switch_analog(dev, 0); - ssb_device_disable(dev->sdev, 0); - ssb_bus_may_powerdown(bus); + b43_device_disable(dev, 0); + b43_bus_may_powerdown(dev); out: return err; @@ -4841,11 +4854,11 @@ out: err_phy_free: b43_phy_free(dev); err_powerdown: - ssb_bus_may_powerdown(bus); + b43_bus_may_powerdown(dev); return err; } -static void b43_one_core_detach(struct ssb_device *dev) +static void b43_one_core_detach(struct b43_bus_dev *dev) { struct b43_wldev *wldev; struct b43_wl *wl; @@ -4853,17 +4866,17 @@ static void b43_one_core_detach(struct ssb_device *dev) /* Do not cancel ieee80211-workqueue based work here. * See comment in b43_remove(). */ - wldev = ssb_get_drvdata(dev); + wldev = ssb_get_drvdata(dev->sdev); wl = wldev->wl; b43_debugfs_remove_device(wldev); b43_wireless_core_detach(wldev); list_del(&wldev->list); wl->nr_devs--; - ssb_set_drvdata(dev, NULL); + ssb_set_drvdata(dev->sdev, NULL); kfree(wldev); } -static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) +static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl) { struct b43_wldev *wldev; int err = -ENOMEM; @@ -4873,7 +4886,8 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) goto out; wldev->use_pio = b43_modparam_pio; - wldev->sdev = dev; + wldev->dev = dev; + wldev->sdev = dev->sdev; /* TODO: Remove when not needed */ wldev->wl = wl; b43_set_status(wldev, B43_STAT_UNINIT); wldev->bad_frames_preempt = modparam_bad_frames_preempt; @@ -4885,7 +4899,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) list_add(&wldev->list, &wl->devlist); wl->nr_devs++; - ssb_set_drvdata(dev, wldev); + ssb_set_drvdata(dev->sdev, wldev); b43_debugfs_add_device(wldev); out: @@ -4926,11 +4940,11 @@ static void b43_sprom_fixup(struct ssb_bus *bus) } } -static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl) +static void b43_wireless_exit(struct b43_bus_dev *dev, struct b43_wl *wl) { struct ieee80211_hw *hw = wl->hw; - ssb_set_devtypedata(dev, NULL); + ssb_set_devtypedata(dev->sdev, NULL); ieee80211_free_hw(hw); } @@ -4982,24 +4996,48 @@ static struct b43_wl *b43_wireless_init(struct ssb_device *dev) return wl; } -static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id) +#ifdef CONFIG_B43_BCMA +static int b43_bcma_probe(struct bcma_device *core) +{ + b43err(NULL, "BCMA is not supported yet!"); + return -EOPNOTSUPP; +} + +static void b43_bcma_remove(struct bcma_device *core) +{ + /* TODO */ +} + +static struct bcma_driver b43_bcma_driver = { + .name = KBUILD_MODNAME, + .id_table = b43_bcma_tbl, + .probe = b43_bcma_probe, + .remove = b43_bcma_remove, +}; +#endif + +static +int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id) { + struct b43_bus_dev *dev; struct b43_wl *wl; int err; int first = 0; - wl = ssb_get_devtypedata(dev); + dev = b43_bus_dev_ssb_init(sdev); + + wl = ssb_get_devtypedata(sdev); if (!wl) { /* Probing the first core. Must setup common struct b43_wl */ first = 1; - b43_sprom_fixup(dev->bus); - wl = b43_wireless_init(dev); + b43_sprom_fixup(sdev->bus); + wl = b43_wireless_init(sdev); if (IS_ERR(wl)) { err = PTR_ERR(wl); goto out; } - ssb_set_devtypedata(dev, wl); - B43_WARN_ON(ssb_get_devtypedata(dev) != wl); + ssb_set_devtypedata(sdev, wl); + B43_WARN_ON(ssb_get_devtypedata(sdev) != wl); } err = b43_one_core_attach(dev, wl); if (err) @@ -5023,10 +5061,10 @@ static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id) return err; } -static void b43_ssb_remove(struct ssb_device *dev) +static void b43_ssb_remove(struct ssb_device *sdev) { - struct b43_wl *wl = ssb_get_devtypedata(dev); - struct b43_wldev *wldev = ssb_get_drvdata(dev); + struct b43_wl *wl = ssb_get_devtypedata(sdev); + struct b43_wldev *wldev = ssb_get_drvdata(sdev); /* We must cancel any work here before unregistering from ieee80211, * as the ieee80211 unreg will destroy the workqueue. */ @@ -5042,14 +5080,14 @@ static void b43_ssb_remove(struct ssb_device *dev) ieee80211_unregister_hw(wl->hw); } - b43_one_core_detach(dev); + b43_one_core_detach(wldev->dev); if (list_empty(&wl->devlist)) { b43_leds_unregister(wl); /* Last core on the chip unregistered. * We can destroy common struct b43_wl. */ - b43_wireless_exit(dev, wl); + b43_wireless_exit(wldev->dev, wl); } } @@ -5108,14 +5146,23 @@ static int __init b43_init(void) err = b43_sdio_init(); if (err) goto err_pcmcia_exit; - err = ssb_driver_register(&b43_ssb_driver); +#ifdef CONFIG_B43_BCMA + err = bcma_driver_register(&b43_bcma_driver); if (err) goto err_sdio_exit; +#endif + err = ssb_driver_register(&b43_ssb_driver); + if (err) + goto err_bcma_driver_exit; b43_print_driverinfo(); return err; +err_bcma_driver_exit: +#ifdef CONFIG_B43_BCMA + bcma_driver_unregister(&b43_bcma_driver); err_sdio_exit: +#endif b43_sdio_exit(); err_pcmcia_exit: b43_pcmcia_exit(); @@ -5127,6 +5174,9 @@ err_dfs_exit: static void __exit b43_exit(void) { ssb_driver_unregister(&b43_ssb_driver); +#ifdef CONFIG_B43_BCMA + bcma_driver_unregister(&b43_bcma_driver); +#endif b43_sdio_exit(); b43_pcmcia_exit(); b43_debugfs_exit(); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index a0d327f13183..e4ebce9be592 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -121,7 +121,7 @@ void b43_hf_write(struct b43_wldev *dev, u64 value); void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on); -void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); +void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode); void b43_controller_restart(struct b43_wldev *dev, const char *reason); diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index b01c8ced57c3..73ace5552bad 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -265,7 +265,6 @@ static void hardware_pctl_init_aphy(struct b43_wldev *dev) void b43_phy_inita(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; struct b43_phy *phy = &dev->phy; /* This lowlevel A-PHY init is also called from G-PHY init. @@ -296,9 +295,9 @@ void b43_phy_inita(struct b43_wldev *dev) b43_radio_init2060(dev); - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - ((bus->boardinfo.type == SSB_BOARD_BU4306) || - (bus->boardinfo.type == SSB_BOARD_BU4309))) { + if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) && + ((dev->dev->board_type == SSB_BOARD_BU4306) || + (dev->dev->board_type == SSB_BOARD_BU4309))) { ; //TODO: A PHY LO } @@ -311,7 +310,7 @@ void b43_phy_inita(struct b43_wldev *dev) } if ((phy->type == B43_PHYTYPE_G) && - (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { + (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)) { b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF); } } @@ -323,17 +322,17 @@ static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev) struct b43_phy_a *aphy = phy->a; s16 pab0, pab1, pab2; - pab0 = (s16) (dev->sdev->bus->sprom.pa1b0); - pab1 = (s16) (dev->sdev->bus->sprom.pa1b1); - pab2 = (s16) (dev->sdev->bus->sprom.pa1b2); + pab0 = (s16) (dev->dev->bus_sprom->pa1b0); + pab1 = (s16) (dev->dev->bus_sprom->pa1b1); + pab2 = (s16) (dev->dev->bus_sprom->pa1b2); if (pab0 != 0 && pab1 != 0 && pab2 != 0 && pab0 != -1 && pab1 != -1 && pab2 != -1) { /* The pabX values are set in SPROM. Use them. */ - if ((s8) dev->sdev->bus->sprom.itssi_a != 0 && - (s8) dev->sdev->bus->sprom.itssi_a != -1) + if ((s8) dev->dev->bus_sprom->itssi_a != 0 && + (s8) dev->dev->bus_sprom->itssi_a != -1) aphy->tgt_idle_tssi = - (s8) (dev->sdev->bus->sprom.itssi_a); + (s8) (dev->dev->bus_sprom->itssi_a); else aphy->tgt_idle_tssi = 62; aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e46b2f4f0920..425af28ea4e5 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -168,7 +168,7 @@ void b43_phy_lock(struct b43_wldev *dev) B43_WARN_ON(dev->phy.phy_locked); dev->phy.phy_locked = 1; #endif - B43_WARN_ON(dev->sdev->id.revision < 3); + B43_WARN_ON(dev->dev->core_rev < 3); if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); @@ -180,7 +180,7 @@ void b43_phy_unlock(struct b43_wldev *dev) B43_WARN_ON(!dev->phy.phy_locked); dev->phy.phy_locked = 0; #endif - B43_WARN_ON(dev->sdev->id.revision < 3); + B43_WARN_ON(dev->dev->core_rev < 3); if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43_power_saving_ctl_bits(dev, 0); @@ -368,8 +368,8 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) /* The next check will be needed in two seconds, or later. */ phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2)); - if ((dev->sdev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (dev->sdev->bus->boardinfo.type == SSB_BOARD_BU4306)) + if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) && + (dev->dev->board_type == SSB_BOARD_BU4306)) return; /* No software txpower adjustment needed */ result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI)); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 1758a282f913..83532d19347f 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -718,7 +718,7 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev) B43_WARN_ON(phy->type != B43_PHYTYPE_G); if (!phy->gmode || - !(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + !(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) { tmp16 = b43_nrssi_hw_read(dev, 0x20); if (tmp16 >= 0x20) tmp16 -= 0x40; @@ -1114,7 +1114,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev, { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; - struct ssb_sprom *sprom = &(dev->sdev->bus->sprom); + struct ssb_sprom *sprom = dev->dev->bus_sprom; if (!phy->gmode) return 0; @@ -1491,7 +1491,6 @@ static u16 b43_radio_init2050(struct b43_wldev *dev) static void b43_phy_initb5(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; u16 offset, value; @@ -1500,8 +1499,8 @@ static void b43_phy_initb5(struct b43_wldev *dev) if (phy->analog == 1) { b43_radio_set(dev, 0x007A, 0x0050); } - if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type != SSB_BOARD_BU4306)) { + if ((dev->dev->board_vendor != SSB_BOARDVENDOR_BCM) && + (dev->dev->board_type != SSB_BOARD_BU4306)) { value = 0x2120; for (offset = 0x00A8; offset < 0x00C7; offset++) { b43_phy_write(dev, offset, value); @@ -1620,7 +1619,7 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_radio_write16(dev, 0x5A, 0x88); b43_radio_write16(dev, 0x5B, 0x6B); b43_radio_write16(dev, 0x5C, 0x0F); - if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_ALTIQ) { b43_radio_write16(dev, 0x5D, 0xFA); b43_radio_write16(dev, 0x5E, 0xD8); } else { @@ -1787,7 +1786,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_set(dev, B43_PHY_RFOVER, 0x0100); b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF); - if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA) { if (phy->rev >= 7) { b43_phy_set(dev, B43_PHY_RFOVER, 0x0800); b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000); @@ -1922,7 +1921,6 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev) /* Initialize B/G PHY power control */ static void b43_phy_init_pctl(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; struct b43_rfatt old_rfatt; @@ -1931,8 +1929,8 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) B43_WARN_ON(phy->type != B43_PHYTYPE_G); - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) + if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) && + (dev->dev->board_type == SSB_BOARD_BU4306)) return; b43_phy_write(dev, 0x0028, 0x8018); @@ -2053,7 +2051,7 @@ static void b43_phy_initg(struct b43_wldev *dev) if (phy->rev >= 6) { b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12)); } - if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); else b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); @@ -2066,7 +2064,7 @@ static void b43_phy_initg(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); } - if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) { /* The specs state to update the NRSSI LT with * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. @@ -2088,8 +2086,8 @@ static void b43_phy_initg(struct b43_wldev *dev) /* FIXME: The spec says in the following if, the 0 should be replaced 'if OFDM may not be used in the current locale' but OFDM is legal everywhere */ - if ((dev->sdev->bus->chip_id == 0x4306 - && dev->sdev->bus->chip_package == 2) || 0) { + if ((dev->dev->chip_id == 0x4306 + && dev->dev->chip_pkg == 2) || 0) { b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF); b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF); } @@ -2105,7 +2103,7 @@ void b43_gphy_channel_switch(struct b43_wldev *dev, b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); if (channel == 14) { - if (dev->sdev->bus->sprom.country_code == + if (dev->dev->bus_sprom->country_code == SSB_SPROM1CCODE_JAPAN) b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACPR); @@ -2136,17 +2134,17 @@ static void default_baseband_attenuation(struct b43_wldev *dev, static void default_radio_attenuation(struct b43_wldev *dev, struct b43_rfatt *rf) { - struct ssb_bus *bus = dev->sdev->bus; + struct b43_bus_dev *bdev = dev->dev; struct b43_phy *phy = &dev->phy; rf->with_padmix = 0; - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && - bus->boardinfo.type == SSB_BOARD_BCM4309G) { - if (bus->boardinfo.rev < 0x43) { + if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM && + dev->dev->board_type == SSB_BOARD_BCM4309G) { + if (dev->dev->board_rev < 0x43) { rf->att = 2; return; - } else if (bus->boardinfo.rev < 0x51) { + } else if (dev->dev->board_rev < 0x51) { rf->att = 3; return; } @@ -2172,21 +2170,21 @@ static void default_radio_attenuation(struct b43_wldev *dev, return; case 1: if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) + if (bdev->board_vendor == SSB_BOARDVENDOR_BCM + && bdev->board_type == SSB_BOARD_BCM4309G + && bdev->board_rev >= 30) rf->att = 3; - else if (bus->boardinfo.vendor == + else if (bdev->board_vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == + && bdev->board_type == SSB_BOARD_BU4306) rf->att = 3; else rf->att = 1; } else { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) + if (bdev->board_vendor == SSB_BOARDVENDOR_BCM + && bdev->board_type == SSB_BOARD_BCM4309G + && bdev->board_rev >= 30) rf->att = 7; else rf->att = 6; @@ -2194,16 +2192,16 @@ static void default_radio_attenuation(struct b43_wldev *dev, return; case 2: if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) + if (bdev->board_vendor == SSB_BOARDVENDOR_BCM + && bdev->board_type == SSB_BOARD_BCM4309G + && bdev->board_rev >= 30) rf->att = 3; - else if (bus->boardinfo.vendor == + else if (bdev->board_vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == + && bdev->board_type == SSB_BOARD_BU4306) rf->att = 5; - else if (bus->chip_id == 0x4320) + else if (bdev->chip_id == 0x4320) rf->att = 4; else rf->att = 3; @@ -2384,11 +2382,11 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev) struct b43_phy_g *gphy = phy->g; s16 pab0, pab1, pab2; - pab0 = (s16) (dev->sdev->bus->sprom.pa0b0); - pab1 = (s16) (dev->sdev->bus->sprom.pa0b1); - pab2 = (s16) (dev->sdev->bus->sprom.pa0b2); + pab0 = (s16) (dev->dev->bus_sprom->pa0b0); + pab1 = (s16) (dev->dev->bus_sprom->pa0b1); + pab2 = (s16) (dev->dev->bus_sprom->pa0b2); - B43_WARN_ON((dev->sdev->bus->chip_id == 0x4301) && + B43_WARN_ON((dev->dev->chip_id == 0x4301) && (phy->radio_ver != 0x2050)); /* Not supported anymore */ gphy->dyn_tssi_tbl = 0; @@ -2396,10 +2394,10 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev) if (pab0 != 0 && pab1 != 0 && pab2 != 0 && pab0 != -1 && pab1 != -1 && pab2 != -1) { /* The pabX values are set in SPROM. Use them. */ - if ((s8) dev->sdev->bus->sprom.itssi_bg != 0 && - (s8) dev->sdev->bus->sprom.itssi_bg != -1) { + if ((s8) dev->dev->bus_sprom->itssi_bg != 0 && + (s8) dev->dev->bus_sprom->itssi_bg != -1) { gphy->tgt_idle_tssi = - (s8) (dev->sdev->bus->sprom.itssi_bg); + (s8) (dev->dev->bus_sprom->itssi_bg); } else gphy->tgt_idle_tssi = 62; gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, @@ -2537,7 +2535,7 @@ static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev) b43_wireless_core_reset(dev, 0); b43_phy_initg(dev); phy->gmode = 1; - b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); + b43_wireless_core_reset(dev, 1); } return 0; @@ -2840,7 +2838,7 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) B43_TXCTL_TXMIX; rfatt += 2; bbatt += 2; - } else if (dev->sdev->bus->sprom. + } else if (dev->dev->bus_sprom-> boardflags_lo & B43_BFL_PACTRL) { bbatt += 4 * (rfatt - 2); @@ -2914,14 +2912,14 @@ static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi); B43_WARN_ON(phy->type != B43_PHYTYPE_G); - max_pwr = dev->sdev->bus->sprom.maxpwr_bg; - if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + max_pwr = dev->dev->bus_sprom->maxpwr_bg; + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) max_pwr -= 3; /* minus 0.75 */ if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) { b43warn(dev->wl, "Invalid max-TX-power value in SPROM.\n"); max_pwr = INT_TO_Q52(20); /* fake it */ - dev->sdev->bus->sprom.maxpwr_bg = max_pwr; + dev->dev->bus_sprom->maxpwr_bg = max_pwr; } /* Get desired power (in Q5.2) */ @@ -3014,7 +3012,7 @@ static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) + if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) return; b43_mac_suspend(dev); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 012c8da2f944..daec1d9e4a18 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -85,39 +85,39 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ static void lpphy_read_band_sprom(struct b43_wldev *dev) { + struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy_lp *lpphy = dev->phy.lp; - struct ssb_bus *bus = dev->sdev->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->tx_isolation_med_band = sprom->tri2g; + lpphy->bx_arch = sprom->bxa2g; + lpphy->rx_pwr_offset = sprom->rxpo2g; + lpphy->rssi_vf = sprom->rssismf2g; + lpphy->rssi_vc = sprom->rssismc2g; + lpphy->rssi_gs = sprom->rssisav2g; + lpphy->txpa[0] = sprom->pa0b0; + lpphy->txpa[1] = sprom->pa0b1; + lpphy->txpa[2] = sprom->pa0b2; + maxpwr = sprom->maxpwr_bg; lpphy->max_tx_pwr_med_band = maxpwr; - cckpo = bus->sprom.cck2gpo; + cckpo = sprom->cck2gpo; /* * We don't read SPROM's opo as specs say. On rev8 SPROMs * opo == ofdm2gpo and we don't know any SSB with LP-PHY * and SPROM rev below 8. */ - B43_WARN_ON(bus->sprom.revision < 8); - ofdmpo = bus->sprom.ofdm2gpo; + B43_WARN_ON(sprom->revision < 8); + ofdmpo = 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; + ofdmpo = sprom->ofdm2gpo; for (i = 4; i < 15; i++) { lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2; @@ -131,39 +131,39 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) 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->tx_isolation_low_band = sprom->tri5gl; + lpphy->tx_isolation_med_band = sprom->tri5g; + lpphy->tx_isolation_hi_band = sprom->tri5gh; + lpphy->bx_arch = sprom->bxa5g; + lpphy->rx_pwr_offset = sprom->rxpo5g; + lpphy->rssi_vf = sprom->rssismf5g; + lpphy->rssi_vc = sprom->rssismc5g; + lpphy->rssi_gs = sprom->rssisav5g; + lpphy->txpa[0] = sprom->pa1b0; + lpphy->txpa[1] = sprom->pa1b1; + lpphy->txpa[2] = sprom->pa1b2; + lpphy->txpal[0] = sprom->pa1lob0; + lpphy->txpal[1] = sprom->pa1lob1; + lpphy->txpal[2] = sprom->pa1lob2; + lpphy->txpah[0] = sprom->pa1hib0; + lpphy->txpah[1] = sprom->pa1hib1; + lpphy->txpah[2] = sprom->pa1hib2; + maxpwr = sprom->maxpwr_al; + ofdmpo = 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; + maxpwr = sprom->maxpwr_a; + ofdmpo = 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; + maxpwr = sprom->maxpwr_ah; + ofdmpo = sprom->ofdm5ghpo; lpphy->max_tx_pwr_hi_band = maxpwr; for (i = 4; i < 12; i++) { lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2; @@ -214,7 +214,8 @@ static void lpphy_table_init(struct b43_wldev *dev) static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; + struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy_lp *lpphy = dev->phy.lp; u16 tmp, tmp2; @@ -242,9 +243,9 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00); b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, 0xFF00, lpphy->rx_pwr_offset); - if ((bus->sprom.boardflags_lo & B43_BFL_FEM) && + if ((sprom->boardflags_lo & B43_BFL_FEM) && ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || - (bus->sprom.boardflags_hi & B43_BFH_PAREF))) { + (sprom->boardflags_hi & B43_BFH_PAREF))) { ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28); ssb_pmu_set_ldo_paref(&bus->chipco, true); if (dev->phy.rev == 0) { @@ -260,7 +261,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) } tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000; b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp); - if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV) + if (sprom->boardflags_hi & B43_BFH_RSSIINV) b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA); else b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA); @@ -268,7 +269,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFF9, (lpphy->bx_arch << 1)); if (dev->phy.rev == 1 && - (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) { + (sprom->boardflags_hi & B43_BFH_FEM_BT)) { b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A); @@ -286,8 +287,8 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00); } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ || - (bus->boardinfo.type == 0x048A) || ((dev->phy.rev == 0) && - (bus->sprom.boardflags_lo & B43_BFL_FEM))) { + (dev->dev->board_type == 0x048A) || ((dev->phy.rev == 0) && + (sprom->boardflags_lo & B43_BFL_FEM))) { b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001); @@ -297,7 +298,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00); } else if (dev->phy.rev == 1 || - (bus->sprom.boardflags_lo & B43_BFL_FEM)) { + (sprom->boardflags_lo & B43_BFL_FEM)) { b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004); @@ -316,15 +317,15 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700); } - if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) { + if (dev->phy.rev == 1 && (sprom->boardflags_hi & B43_BFH_PAREF)) { b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4); } - if ((bus->sprom.boardflags_hi & B43_BFH_FEM_BT) && - (bus->chip_id == 0x5354) && - (bus->chip_package == SSB_CHIPPACK_BCM4712S)) { + if ((sprom->boardflags_hi & B43_BFH_FEM_BT) && + (dev->dev->chip_id == 0x5354) && + (dev->dev->chip_pkg == SSB_CHIPPACK_BCM4712S)) { 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); @@ -412,7 +413,6 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; struct b43_phy_lp *lpphy = dev->phy.lp; b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50); @@ -432,7 +432,7 @@ 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) { + if (dev->dev->board_rev >= 0x18) { b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC); b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14); } else { @@ -449,7 +449,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300); b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00); - if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { + if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) { b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100); b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xA); } else { @@ -467,7 +467,7 @@ 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 == 0)) { + if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) { b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); } @@ -492,7 +492,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) 0x2000 | ((u16)lpphy->rssi_gs << 10) | ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf); - if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { + if ((dev->dev->chip_id == 0x4325) && (dev->dev->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); @@ -519,7 +519,7 @@ struct b2062_freqdata { static void lpphy_2062_init(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; u32 crystalfreq, tmp, ref; unsigned int i; const struct b2062_freqdata *fd = NULL; @@ -697,7 +697,7 @@ 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); - if (dev->sdev->bus->chip_id == 0x4325) { + if (dev->dev->chip_id == 0x4325) { // TODO SSB PMU recalibration } } @@ -1289,7 +1289,7 @@ finish: static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; int i; @@ -1840,7 +1840,6 @@ static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains, static void lpphy_papd_cal_txpwr(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; - struct ssb_bus *bus = dev->sdev->bus; struct lpphy_tx_gains gains, oldgains; int old_txpctl, old_afe_ovr, old_rf, old_bbmult; @@ -1854,7 +1853,7 @@ static void lpphy_papd_cal_txpwr(struct b43_wldev *dev) lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); - if (bus->chip_id == 0x4325 && bus->chip_rev == 0) + if (dev->dev->chip_id == 0x4325 && dev->dev->chip_rev == 0) lpphy_papd_cal(dev, gains, 0, 1, 30); else lpphy_papd_cal(dev, gains, 0, 1, 65); @@ -1870,7 +1869,6 @@ static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx, bool rx, bool pa, struct lpphy_tx_gains *gains) { struct b43_phy_lp *lpphy = dev->phy.lp; - struct ssb_bus *bus = dev->sdev->bus; const struct lpphy_rx_iq_comp *iqcomp = NULL; struct lpphy_tx_gains nogains, oldgains; u16 tmp; @@ -1879,7 +1877,7 @@ static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx, memset(&nogains, 0, sizeof(nogains)); memset(&oldgains, 0, sizeof(oldgains)); - if (bus->chip_id == 0x5354) { + if (dev->dev->chip_id == 0x5354) { for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) { if (lpphy_5354_iq_table[i].chan == lpphy->channel) { iqcomp = &lpphy_5354_iq_table[i]; @@ -2408,11 +2406,9 @@ static const struct b206x_channel b2063_chantbl[] = { static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; - b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF); udelay(20); - if (bus->chip_id == 0x5354) { + if (dev->dev->chip_id == 0x5354) { b43_radio_write(dev, B2062_N_COMM1, 4); b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4); } else { @@ -2432,7 +2428,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, unsigned int channel) { struct b43_phy_lp *lpphy = dev->phy.lp; - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; const struct b206x_channel *chandata = NULL; u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; @@ -2522,7 +2518,7 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev) static int lpphy_b2063_tune(struct b43_wldev *dev, unsigned int channel) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; static const struct b206x_channel *chandata = NULL; u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; @@ -2670,6 +2666,11 @@ static int b43_lpphy_op_init(struct b43_wldev *dev) { int err; + if (dev->dev->bus_type != B43_BUS_SSB) { + b43err(dev->wl, "LP-PHY is supported only on SSB!\n"); + return -EOPNOTSUPP; + } + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? lpphy_baseband_init(dev); lpphy_radio_init(dev); diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 05960ddde24e..ad14f3b428c5 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -299,7 +299,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) static void b43_nphy_tx_power_fix(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; - struct ssb_sprom *sprom = &(dev->sdev->bus->sprom); + struct ssb_sprom *sprom = dev->dev->bus_sprom; u8 txpi[2], bbmult, i; u16 tmp, radio_gain, dac_gain; @@ -423,16 +423,15 @@ static void b43_radio_init2055_pre(struct b43_wldev *dev) static void b43_radio_init2055_post(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; - struct ssb_sprom *sprom = &(dev->sdev->bus->sprom); - struct ssb_boardinfo *binfo = &(dev->sdev->bus->boardinfo); + struct ssb_sprom *sprom = dev->dev->bus_sprom; int i; u16 val; bool workaround = false; if (sprom->revision < 4) - workaround = (binfo->vendor != PCI_VENDOR_ID_BROADCOM && - binfo->type == 0x46D && - binfo->rev >= 0x41); + workaround = (dev->dev->board_vendor != PCI_VENDOR_ID_BROADCOM + && dev->dev->board_type == 0x46D + && dev->dev->board_rev >= 0x41); else workaround = !(sprom->boardflags2_lo & B43_BFL2_RXBB_INT_REG_DIS); @@ -983,7 +982,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) { u16 tmp; - if (dev->sdev->id.revision == 16) + if (dev->dev->core_rev == 16) b43_mac_suspend(dev); tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL); @@ -993,7 +992,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) tmp |= (val & mask); b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp); - if (dev->sdev->id.revision == 16) + if (dev->dev->core_rev == 16) b43_mac_enable(dev); return tmp; @@ -1168,7 +1167,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; - struct ssb_sprom *sprom = &(dev->sdev->bus->sprom); + struct ssb_sprom *sprom = dev->dev->bus_sprom; /* PHY rev 0, 1, 2 */ u8 i, j; @@ -1373,7 +1372,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ static void b43_nphy_workarounds(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = phy->n; @@ -1443,9 +1442,9 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) /* N PHY WAR TX Chain Update with hw_phytxchain as argument */ - if ((bus->sprom.boardflags2_lo & B43_BFL2_APLL_WAR && + if ((sprom->boardflags2_lo & B43_BFL2_APLL_WAR && b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || - (bus->sprom.boardflags2_lo & B43_BFL2_GPLL_WAR && + (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR && b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) tmp32 = 0x00088888; else @@ -1503,8 +1502,8 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); - if (bus->sprom.boardflags2_lo & 0x100 && - bus->boardinfo.type == 0x8B) { + if (sprom->boardflags2_lo & 0x100 && + dev->dev->board_type == 0x8B) { delays1[0] = 0x1; delays1[5] = 0x14; } @@ -3586,7 +3585,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask) */ int b43_phy_initn(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = phy->n; u8 tx_pwr_state; @@ -3599,7 +3598,7 @@ int b43_phy_initn(struct b43_wldev *dev) bool do_cal = false; if ((dev->phy.rev >= 3) && - (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && + (sprom->boardflags_lo & B43_BFL_EXTLNA) && (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) { chipco_set32(&dev->sdev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40); } @@ -3639,9 +3638,9 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); - if (bus->sprom.boardflags2_lo & 0x100 || - (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && - bus->boardinfo.type == 0x8B)) + if (sprom->boardflags2_lo & 0x100 || + (dev->dev->board_vendor == PCI_VENDOR_ID_APPLE && + dev->dev->board_type == 0x8B)) b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0); else b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 72ab94df7569..44da620d9cc2 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -111,7 +111,7 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev, B43_MMIO_PIO11_BASE5, }; - if (dev->sdev->id.revision >= 11) { + if (dev->dev->core_rev >= 11) { B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11)); return bases_rev11[index]; } @@ -121,14 +121,14 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev, static u16 pio_txqueue_offset(struct b43_wldev *dev) { - if (dev->sdev->id.revision >= 11) + if (dev->dev->core_rev >= 11) return 0x18; return 0; } static u16 pio_rxqueue_offset(struct b43_wldev *dev) { - if (dev->sdev->id.revision >= 11) + if (dev->dev->core_rev >= 11) return 0x38; return 8; } @@ -144,7 +144,7 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev, if (!q) return NULL; q->dev = dev; - q->rev = dev->sdev->id.revision; + q->rev = dev->dev->core_rev; q->mmio_base = index_to_pioqueue_base(dev, index) + pio_txqueue_offset(dev); q->index = index; @@ -178,7 +178,7 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, if (!q) return NULL; q->dev = dev; - q->rev = dev->sdev->id.revision; + q->rev = dev->dev->core_rev; q->mmio_base = index_to_pioqueue_base(dev, index) + pio_rxqueue_offset(dev); diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index a617efe38289..59c3afe047af 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -37,17 +37,16 @@ void b43_rfkill_poll(struct ieee80211_hw *hw) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - struct ssb_bus *bus = dev->sdev->bus; bool enabled; bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { - if (ssb_bus_powerup(bus, 0)) { + if (b43_bus_powerup(dev, 0)) { mutex_unlock(&wl->mutex); return; } - ssb_device_enable(dev->sdev, 0); + b43_device_enable(dev, 0); brought_up = true; } @@ -63,8 +62,8 @@ void b43_rfkill_poll(struct ieee80211_hw *hw) } if (brought_up) { - ssb_device_disable(dev->sdev, 0); - ssb_bus_may_powerdown(bus); + b43_device_disable(dev, 0); + b43_bus_may_powerdown(dev); } mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 808e25b79703..e6c733d37c94 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -66,7 +66,7 @@ static void b43_sdio_interrupt_dispatcher(struct sdio_func *func) int b43_sdio_request_irq(struct b43_wldev *dev, void (*handler)(struct b43_wldev *dev)) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; struct sdio_func *func = bus->host_sdio; struct b43_sdio *sdio = sdio_get_drvdata(func); int err; @@ -82,7 +82,7 @@ int b43_sdio_request_irq(struct b43_wldev *dev, void b43_sdio_free_irq(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_bus *bus = dev->dev->sdev->bus; struct sdio_func *func = bus->host_sdio; struct b43_sdio *sdio = sdio_get_drvdata(func); diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 57af619725c3..f1ae4e05a32c 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -140,7 +140,7 @@ static DEVICE_ATTR(interference, 0644, int b43_sysfs_register(struct b43_wldev *wldev) { - struct device *dev = wldev->sdev->dev; + struct device *dev = wldev->dev->dev; B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED); @@ -149,7 +149,7 @@ int b43_sysfs_register(struct b43_wldev *wldev) void b43_sysfs_unregister(struct b43_wldev *wldev) { - struct device *dev = wldev->sdev->dev; + struct device *dev = wldev->dev->dev; device_remove_file(dev, &dev_attr_interference); } diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 59df3c64af63..6748c5a196e9 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -2304,7 +2304,6 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev) void lpphy_rev2plus_table_init(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; int i; B43_WARN_ON(dev->phy.rev < 2); @@ -2341,7 +2340,7 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev) b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), ARRAY_SIZE(lpphy_papd_mult_table), lpphy_papd_mult_table); - if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { + if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) { b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0), ARRAY_SIZE(lpphy_a0_gain_idx_table), lpphy_a0_gain_idx_table); b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), @@ -2416,12 +2415,12 @@ void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count, void lpphy_init_tx_gain_table(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_sprom *sprom = dev->dev->bus_sprom; switch (dev->phy.rev) { case 0: - if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || - (bus->sprom.boardflags_lo & B43_BFL_HGPA)) + if ((sprom->boardflags_hi & B43_BFH_NOPA) || + (sprom->boardflags_lo & B43_BFL_HGPA)) lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev0_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) @@ -2432,8 +2431,8 @@ void lpphy_init_tx_gain_table(struct b43_wldev *dev) lpphy_rev0_5ghz_tx_gain_table); break; case 1: - if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || - (bus->sprom.boardflags_lo & B43_BFL_HGPA)) + if ((sprom->boardflags_hi & B43_BFH_NOPA) || + (sprom->boardflags_lo & B43_BFL_HGPA)) lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev1_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) @@ -2444,7 +2443,7 @@ void lpphy_init_tx_gain_table(struct b43_wldev *dev) lpphy_rev1_5ghz_tx_gain_table); break; default: - if (bus->sprom.boardflags_hi & B43_BFH_NOPA) + if (sprom->boardflags_hi & B43_BFH_NOPA) lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev2_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index 8f4db448ec33..5d00d0eaf2e7 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -458,17 +458,15 @@ static void b43_wa_rssi_adc(struct b43_wldev *dev) static void b43_wa_boards_a(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; - - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && - bus->boardinfo.type == SSB_BOARD_BU4306 && - bus->boardinfo.rev < 0x30) { + if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM && + dev->dev->board_type == SSB_BOARD_BU4306 && + dev->dev->board_rev < 0x30) { b43_phy_write(dev, 0x0010, 0xE000); b43_phy_write(dev, 0x0013, 0x0140); b43_phy_write(dev, 0x0014, 0x0280); } else { - if (bus->boardinfo.type == SSB_BOARD_MP4318 && - bus->boardinfo.rev < 0x20) { + if (dev->dev->board_type == SSB_BOARD_MP4318 && + dev->dev->board_rev < 0x20) { b43_phy_write(dev, 0x0013, 0x0210); b43_phy_write(dev, 0x0014, 0x0840); } else { @@ -486,19 +484,19 @@ static void b43_wa_boards_a(struct b43_wldev *dev) static void b43_wa_boards_g(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; + struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy *phy = &dev->phy; - if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM || - bus->boardinfo.type != SSB_BOARD_BU4306 || - bus->boardinfo.rev != 0x17) { + if (dev->dev->board_vendor != SSB_BOARDVENDOR_BCM || + dev->dev->board_type != SSB_BOARD_BU4306 || + dev->dev->board_rev != 0x17) { if (phy->rev < 2) { b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002); b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001); } else { b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002); b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001); - if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && + if ((sprom->boardflags_lo & B43_BFL_EXTLNA) && (phy->rev >= 7)) { b43_phy_mask(dev, B43_PHY_EXTG(0x11), 0xF7FF); b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001); @@ -510,7 +508,7 @@ static void b43_wa_boards_g(struct b43_wldev *dev) } } } - if (bus->sprom.boardflags_lo & B43_BFL_FEM) { + if (sprom->boardflags_lo & B43_BFL_FEM) { b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120); b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index c8f99aebe01f..488b898418a3 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -547,7 +547,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, else tmp -= 3; } else { - if (dev->sdev->bus->sprom. + if (dev->dev->bus_sprom-> boardflags_lo & B43_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index e03e01d0bc35..c33934ad6cd2 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -817,14 +817,13 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring) static void free_all_descbuffers(struct b43legacy_dmaring *ring) { - struct b43legacy_dmadesc_generic *desc; struct b43legacy_dmadesc_meta *meta; int i; if (!ring->used_slots) return; for (i = 0; i < ring->nr_slots; i++) { - desc = ring->ops->idx2desc(ring, i, &meta); + ring->ops->idx2desc(ring, i, &meta); if (!meta->skb) { B43legacy_WARN_ON(!ring->tx); @@ -1371,10 +1370,8 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb) { struct b43legacy_dmaring *ring; - struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); @@ -1401,8 +1398,6 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing * into the skb data or cb now. */ - hdr = NULL; - info = NULL; err = dma_tx_fragment(ring, &skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key @@ -1435,7 +1430,6 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, { const struct b43legacy_dma_ops *ops; struct b43legacy_dmaring *ring; - struct b43legacy_dmadesc_generic *desc; struct b43legacy_dmadesc_meta *meta; int retry_limit; int slot; @@ -1450,7 +1444,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, ops = ring->ops; while (1) { B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); - desc = ops->idx2desc(ring, slot, &meta); + ops->idx2desc(ring, slot, &meta); if (meta->skb) unmap_descbuffer(ring, meta->dmaaddr, diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 60107b8e4c93..d6db6c17da4f 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1564,10 +1564,10 @@ static int b43legacy_request_firmware(struct b43legacy_wldev *dev) struct b43legacy_firmware *fw = &dev->fw; const u8 rev = dev->dev->id.revision; const char *filename; - u32 tmshigh; int err; - tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + /* do dummy read */ + ssb_read32(dev->dev, SSB_TMSHIGH); if (!fw->ucode) { if (rev == 2) filename = "ucode2"; @@ -2634,11 +2634,9 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, unsigned long flags; unsigned int new_phymode = 0xFFFF; int antenna_tx; - int antenna_rx; int err = 0; antenna_tx = B43legacy_ANTENNA_DEFAULT; - antenna_rx = B43legacy_ANTENNA_DEFAULT; mutex_lock(&wl->mutex); dev = wl->current_dev; @@ -2775,14 +2773,12 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; - struct b43legacy_phy *phy; unsigned long flags; mutex_lock(&wl->mutex); B43legacy_WARN_ON(wl->vif != vif); dev = wl->current_dev; - phy = &dev->phy; /* Disable IRQs while reconfiguring the device. * This makes it possible to drop the spinlock throughout diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 3a95541708a6..6c174f38ca3c 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -321,11 +321,9 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct ieee80211_hdr *hdr; int rts_rate; int rts_rate_fb; - int rts_rate_ofdm; int rts_rate_fb_ofdm; rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value; - rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); if (rts_rate_fb_ofdm) diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c index 24d149909ba3..9b65153bdd01 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c @@ -2275,6 +2275,9 @@ iwl4965_rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if (rate_control_send_low(sta, priv_sta, txrc)) return; + if (!lq_sta) + return; + rate_idx = lq_sta->last_txrate_idx; if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c index f9db25bb35c3..3a022bcf615c 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965.c @@ -496,7 +496,7 @@ static s32 iwl4965_get_tx_atten_grp(u16 channel) channel <= CALIB_IWL_TX_ATTEN_GR4_LCH) return CALIB_CH_GROUP_4; - return -1; + return -EINVAL; } static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) @@ -915,7 +915,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, if (txatten_grp < 0) { IWL_ERR(priv, "Can't find txatten group for channel %d.\n", channel); - return -EINVAL; + return txatten_grp; } IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n", @@ -1185,8 +1185,6 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv, ret = iwl_legacy_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC, sizeof(rxon_assoc), &rxon_assoc, NULL); - if (ret) - return ret; return ret; } @@ -1237,7 +1235,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); iwl_legacy_print_rx_config_cmd(priv, ctx); - return 0; + goto set_tx_power; } /* If we are currently associated and the new config requires @@ -1317,6 +1315,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c iwl4965_init_sensitivity(priv); +set_tx_power: /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ ret = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true); diff --git a/drivers/net/wireless/iwlegacy/iwl-eeprom.c b/drivers/net/wireless/iwlegacy/iwl-eeprom.c index cb346d1a9ffa..5bf3f49b74ab 100644 --- a/drivers/net/wireless/iwlegacy/iwl-eeprom.c +++ b/drivers/net/wireless/iwlegacy/iwl-eeprom.c @@ -316,7 +316,6 @@ static void iwl_legacy_init_band_reference(const struct iwl_priv *priv, break; default: BUG(); - return; } } diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 61d4a11f566b..7aa240e6ba1c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -174,7 +174,6 @@ static struct iwl_lib_ops iwl1000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl_apm_init, @@ -223,6 +222,7 @@ static struct iwl_base_params iwl1000_base_params = { static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, .use_rts_for_aggregation = true, /* use rts/cts protection */ + .smps_mode = IEEE80211_SMPS_STATIC, }; #define IWL_DEVICE_1000 \ diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 86feec86d130..5484ab712da8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -177,88 +177,13 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) return 0; } -static int iwl2030_hw_channel_switch(struct iwl_priv *priv, - struct ieee80211_channel_switch *ch_switch) -{ - /* - * MULTI-FIXME - * See iwl_mac_channel_switch. - */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl6000_channel_switch_cmd cmd; - const struct iwl_channel_info *ch_info; - u32 switch_time_in_usec, ucode_switch_time; - u16 ch; - u32 tsf_low; - u8 switch_count; - u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); - struct ieee80211_vif *vif = ctx->vif; - struct iwl_host_cmd hcmd = { - .id = REPLY_CHANNEL_SWITCH, - .len = { sizeof(cmd), }, - .flags = CMD_SYNC, - .data = { &cmd, }, - }; - - cmd.band = priv->band == IEEE80211_BAND_2GHZ; - ch = ch_switch->channel->hw_value; - IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", - ctx->active.channel, ch); - cmd.channel = cpu_to_le16(ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; - switch_count = ch_switch->count; - tsf_low = ch_switch->timestamp & 0x0ffffffff; - /* - * calculate the ucode channel switch time - * adding TSF as one of the factor for when to switch - */ - if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { - if (switch_count > ((priv->ucode_beacon_time - tsf_low) / - beacon_interval)) { - switch_count -= (priv->ucode_beacon_time - - tsf_low) / beacon_interval; - } else - switch_count = 0; - } - if (switch_count <= 1) - cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); - else { - switch_time_in_usec = - vif->bss_conf.beacon_int * switch_count * TIME_UNIT; - ucode_switch_time = iwl_usecs_to_beacons(priv, - switch_time_in_usec, - beacon_interval); - cmd.switch_time = iwl_add_beacon_time(priv, - priv->ucode_beacon_time, - ucode_switch_time, - beacon_interval); - } - IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", - cmd.switch_time); - ch_info = iwl_get_channel_info(priv, priv->band, ch); - if (ch_info) - cmd.expect_beacon = is_channel_radar(ch_info); - else { - IWL_ERR(priv, "invalid channel switch from %u to %u\n", - ctx->active.channel, ch); - return -EFAULT; - } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; - - return iwl_send_cmd_sync(priv, &hcmd); -} - static struct iwl_lib_ops iwl2000_lib = { .set_hw_params = iwl2000_hw_set_hw_params, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, - .set_channel_switch = iwl2030_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .config = iwl2000_nic_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a70b8cfafda1..4353a658de25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -331,8 +331,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch); return -EFAULT; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } @@ -342,7 +340,6 @@ static struct iwl_lib_ops iwl5000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { @@ -373,7 +370,6 @@ static struct iwl_lib_ops iwl5150_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { @@ -425,7 +421,6 @@ static struct iwl_base_params iwl5000_base_params = { }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, - .use_rts_for_aggregation = true, /* use rts/cts protection */ }; #define IWL_DEVICE_5000 \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index fda6fe08cf91..6e5ce4478490 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -270,8 +270,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch); return -EFAULT; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } @@ -281,7 +279,6 @@ static struct iwl_lib_ops iwl6000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, .apm_ops = { @@ -314,7 +311,6 @@ static struct iwl_lib_ops iwl6030_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, .apm_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index b12c72d63ccb..23eee0ca5b35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -163,17 +163,9 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, __le16 fc, __le32 *tx_flags) { if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS || - info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT || + info->flags & IEEE80211_TX_CTL_AMPDU) *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK; - return; - } - - if (priv->cfg->ht_params && - priv->cfg->ht_params->use_rts_for_aggregation && - info->flags & IEEE80211_TX_CTL_AMPDU) { - *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK; - return; - } } /* Calc max signal level (dBm) among 3 possible receivers */ @@ -310,7 +302,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) } struct iwl_hcmd_ops iwlagn_hcmd = { - .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, .send_bt_config = iwl_send_bt_config, @@ -318,7 +309,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = { }; struct iwl_hcmd_ops iwlagn_bt_hcmd = { - .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, .send_bt_config = iwlagn_send_advance_bt_config, @@ -332,5 +322,4 @@ struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = { .tx_cmd_protection = iwlagn_tx_cmd_protection, .calc_rssi = iwlagn_calc_rssi, .request_scan = iwlagn_request_scan, - .post_scan = iwlagn_post_scan, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index f803fb62f8bc..677f73c4c1e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -408,9 +408,9 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, unsigned long flags; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { - IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d " - "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.write_ptr, + IWL_ERR(priv, "%s: Read index for DMA queue txq_id (%d) " + "index %d is out of range [0-%d] %d %d\n", __func__, + txq_id, index, txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr); return; } @@ -1797,6 +1797,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) priv->cfg->ops->lib->update_chain_flags(priv); if (smps_request != -1) { + priv->current_ht_config.smps = smps_request; for_each_context(priv, ctx) { if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) ieee80211_request_smps(ctx->vif, smps_request); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 592b0cfcf717..85e082830c1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -426,7 +426,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, ieee80211_stop_tx_ba_session(sta, tid); } } else { - IWL_ERR(priv, "Aggregation not enabled for tid %d " + IWL_DEBUG_HT(priv, "Aggregation not enabled for tid %d " "because load = %u\n", tid, load); } return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index a95ad84c5377..a7c66c4e5f2a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -81,6 +81,21 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, return ret; } +static int iwlagn_disconn_pan(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct iwl_rxon_cmd *send) +{ + __le32 old_filter = send->filter_flags; + int ret; + + send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send); + + send->filter_flags = old_filter; + + return ret; +} + static void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -163,9 +178,6 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, sizeof(rxon_assoc), &rxon_assoc, NULL); - if (ret) - return ret; - return ret; } @@ -175,10 +187,21 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv, int ret; struct iwl_rxon_cmd *active = (void *)&ctx->active; - if (ctx->ctxid == IWL_RXON_CTX_BSS) + if (ctx->ctxid == IWL_RXON_CTX_BSS) { ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); - else + } else { ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + if (ret) + return ret; + if (ctx->vif) { + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); + return ret; + } + ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging); + } + } if (ret) return ret; @@ -205,10 +228,12 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv, struct iwl_rxon_cmd *active = (void *)&ctx->active; /* RXON timing must be before associated RXON */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); - return ret; + if (ctx->ctxid == IWL_RXON_CTX_BSS) { + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); + return ret; + } } /* QoS info may be cleared by previous un-assoc RXON */ iwlagn_update_qos(priv, ctx); @@ -263,6 +288,12 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv, IWL_ERR(priv, "Error sending TX power (%d)\n", ret); return ret; } + + if ((ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) && + priv->cfg->ht_params->smps_mode) + ieee80211_request_smps(ctx->vif, + priv->cfg->ht_params->smps_mode); + return 0; } @@ -325,6 +356,14 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } + /* + * force CTS-to-self frames protection if RTS-CTS is not preferred + * one aggregation protection method + */ + if (!(priv->cfg->ht_params && + priv->cfg->ht_params->use_rts_for_aggregation)) + ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; + if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK)) ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; @@ -342,10 +381,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * receive commit_rxon request * abort any previous channel switch if still in process */ - if (priv->switch_rxon.switch_in_progress && - (priv->switch_rxon.channel != ctx->staging.channel)) { + if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) && + (priv->switch_channel != ctx->staging.channel)) { IWL_DEBUG_11H(priv, "abort channel switch on %d\n", - le16_to_cpu(priv->switch_rxon.channel)); + le16_to_cpu(priv->switch_channel)); iwl_chswitch_done(priv, false); } @@ -362,13 +401,16 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } memcpy(active, &ctx->staging, sizeof(*active)); - return 0; - } + /* + * We do not commit tx power settings while channel changing, + * do it now if after settings changed. + */ + iwl_set_tx_power(priv, priv->tx_power_next, false); - if (priv->cfg->ops->hcmd->set_pan_params) { - ret = priv->cfg->ops->hcmd->set_pan_params(priv); - if (ret) - return ret; + /* make sure we are in the right PS state */ + iwl_power_update_mode(priv, true); + + return 0; } iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); @@ -392,6 +434,12 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) if (ret) return ret; + if (priv->cfg->ops->hcmd->set_pan_params) { + ret = priv->cfg->ops->hcmd->set_pan_params(priv); + if (ret) + return ret; + } + if (new_assoc) return iwlagn_rxon_connect(priv, ctx); @@ -757,6 +805,13 @@ void iwlagn_post_scan(struct iwl_priv *priv) struct iwl_rxon_context *ctx; /* + * We do not commit power settings while scan is pending, + * do it now if the settings changed. + */ + iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false); + iwl_set_tx_power(priv, priv->tx_power_next, false); + + /* * Since setting the RXON may have been deferred while * performing the scan, fire one off if needed */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 4974cd7837cb..8bd48f61a9f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1033,8 +1033,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, if (unlikely(tx_fifo < 0)) return tx_fifo; - IWL_WARN(priv, "%s on ra = %pM tid = %d\n", - __func__, sta->addr, tid); + IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n", + sta->addr, tid); sta_id = iwl_sta_id(sta); if (sta_id == IWL_INVALID_STATION) { @@ -1236,9 +1236,9 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) struct ieee80211_hdr *hdr; if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { - IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, " - "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->write_ptr, q->read_ptr); + IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), " + "index %d is out of range [0-%d] %d %d.\n", __func__, + txq_id, index, q->n_bd, q->write_ptr, q->read_ptr); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a662adcb2adb..099c2795ec0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -97,7 +97,7 @@ void iwl_update_chain_flags(struct iwl_priv *priv) for_each_context(priv, ctx) { priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); if (ctx->active.rx_chain != ctx->staging.rx_chain) - iwlcore_commit_rxon(priv, ctx); + iwlagn_commit_rxon(priv, ctx); } } } @@ -274,7 +274,7 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) for_each_context(priv, ctx) { if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - iwlcore_commit_rxon(priv, ctx); + iwlagn_commit_rxon(priv, ctx); } priv->cfg->ops->hcmd->send_bt_config(priv); @@ -2056,7 +2056,7 @@ int iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); /* Configure the adapter for unassociated operation */ - ret = iwlcore_commit_rxon(priv, ctx); + ret = iwlagn_commit_rxon(priv, ctx); if (ret) return ret; @@ -2420,6 +2420,77 @@ unlock: * *****************************************************************************/ +static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, +}; + +static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +static const struct ieee80211_iface_combination +iwlagn_iface_combinations_dualmode[] = { + { .num_different_channels = 1, + .max_interfaces = 2, + .beacon_int_infra_match = true, + .limits = iwlagn_sta_ap_limits, + .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits), + }, + { .num_different_channels = 1, + .max_interfaces = 2, + .limits = iwlagn_2sta_limits, + .n_limits = ARRAY_SIZE(iwlagn_2sta_limits), + }, +}; + +static const struct ieee80211_iface_combination +iwlagn_iface_combinations_p2p[] = { + { .num_different_channels = 1, + .max_interfaces = 2, + .beacon_int_infra_match = true, + .limits = iwlagn_p2p_sta_go_limits, + .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits), + }, + { .num_different_channels = 1, + .max_interfaces = 2, + .limits = iwlagn_p2p_2sta_limits, + .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits), + }, +}; + /* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. @@ -2460,6 +2531,18 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->wiphy->interface_modes |= ctx->exclusive_interface_modes; } + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + + if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) { + hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(iwlagn_iface_combinations_p2p); + } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { + hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(iwlagn_iface_combinations_dualmode); + } + hw->wiphy->max_remain_on_channel_duration = 1000; hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | @@ -2711,12 +2794,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, ret = 0; if (priv->cfg->ht_params && priv->cfg->ht_params->use_rts_for_aggregation) { - struct iwl_station_priv *sta_priv = - (void *) sta->drv_priv; /* * switch off RTS/CTS if it was previously enabled */ - sta_priv->lq_sta.lq.general_params.flags &= ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), @@ -2764,6 +2844,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), &sta_priv->lq_sta.lq, CMD_ASYNC, false); + + IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n", + sta->addr, tid); ret = 0; break; } @@ -2833,7 +2916,6 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; u16 ch; - unsigned long flags = 0; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -2843,73 +2925,73 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status)) + test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) goto out; if (!iwl_is_associated_ctx(ctx)) goto out; - /* channel switch in progress */ - if (priv->switch_rxon.switch_in_progress == true) + if (!priv->cfg->ops->lib->set_channel_switch) goto out; - if (priv->cfg->ops->lib->set_channel_switch) { + ch = channel->hw_value; + if (le16_to_cpu(ctx->active.channel) == ch) + goto out; - ch = channel->hw_value; - if (le16_to_cpu(ctx->active.channel) != ch) { - ch_info = iwl_get_channel_info(priv, - channel->band, - ch); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_MAC80211(priv, "invalid channel\n"); - goto out; - } - spin_lock_irqsave(&priv->lock, flags); - - priv->current_ht_config.smps = conf->smps_mode; - - /* Configure HT40 channels */ - ctx->ht.enabled = conf_is_ht(conf); - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else - ctx->ht.is_40mhz = false; + ch_info = iwl_get_channel_info(priv, channel->band, ch); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_MAC80211(priv, "invalid channel\n"); + goto out; + } - if ((le16_to_cpu(ctx->staging.channel) != ch)) - ctx->staging.flags = 0; + spin_lock_irq(&priv->lock); - iwl_set_rxon_channel(priv, channel, ctx); - iwl_set_rxon_ht(priv, ht_conf); - iwl_set_flags_for_band(priv, ctx, channel->band, - ctx->vif); - spin_unlock_irqrestore(&priv->lock, flags); + priv->current_ht_config.smps = conf->smps_mode; - iwl_set_rate(priv); - /* - * at this point, staging_rxon has the - * configuration for channel switch - */ - if (priv->cfg->ops->lib->set_channel_switch(priv, - ch_switch)) - priv->switch_rxon.switch_in_progress = false; + /* Configure HT40 channels */ + ctx->ht.enabled = conf_is_ht(conf); + if (ctx->ht.enabled) { + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; } + } else + ctx->ht.is_40mhz = false; + + if ((le16_to_cpu(ctx->staging.channel) != ch)) + ctx->staging.flags = 0; + + iwl_set_rxon_channel(priv, channel, ctx); + iwl_set_rxon_ht(priv, ht_conf); + iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); + + spin_unlock_irq(&priv->lock); + + iwl_set_rate(priv); + /* + * at this point, staging_rxon has the + * configuration for channel switch + */ + set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); + priv->switch_channel = cpu_to_le16(ch); + if (priv->cfg->ops->lib->set_channel_switch(priv, ch_switch)) { + clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); + priv->switch_channel = 0; + ieee80211_chswitch_done(ctx->vif, false); } + out: mutex_unlock(&priv->mutex); - if (!priv->switch_rxon.switch_in_progress) - ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); } @@ -3018,7 +3100,7 @@ static void iwlagn_disable_roc(struct iwl_priv *priv) priv->_agn.hw_roc_channel = NULL; - iwlcore_commit_rxon(priv, ctx); + iwlagn_commit_rxon(priv, ctx); ctx->is_active = false; } @@ -3061,7 +3143,7 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw, priv->_agn.hw_roc_channel = channel; priv->_agn.hw_roc_chantype = channel_type; priv->_agn.hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024); - iwlcore_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); + iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); queue_delayed_work(priv->workqueue, &priv->_agn.hw_roc_work, msecs_to_jiffies(duration + 20)); @@ -3618,8 +3700,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; free_irq(priv->pci_dev->irq, priv); - iwl_free_isr_ict(priv); out_disable_msi: + iwl_free_isr_ict(priv); pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); out_free_eeprom: diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4653deada05b..5416b12cd931 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -843,12 +843,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (priv->switch_rxon.switch_in_progress) { + if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) ieee80211_chswitch_done(ctx->vif, is_success); - mutex_lock(&priv->mutex); - priv->switch_rxon.switch_in_progress = false; - mutex_unlock(&priv->mutex); - } } #ifdef CONFIG_IWLWIFI_DEBUG @@ -1131,9 +1127,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (priv->tx_power_user_lmt == tx_power && !force) return 0; - if (!priv->cfg->ops->lib->send_tx_power) - return -EOPNOTSUPP; - if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) { IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n", @@ -1167,7 +1160,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) prev_tx_power = priv->tx_power_user_lmt; priv->tx_power_user_lmt = tx_power; - ret = priv->cfg->ops->lib->send_tx_power(priv); + ret = iwlagn_send_tx_power(priv); /* if fail to set tx_power, restore the orig. tx power */ if (ret) { @@ -1282,7 +1275,7 @@ static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - return iwlcore_commit_rxon(priv, ctx); + return iwlagn_commit_rxon(priv, ctx); } static int iwl_setup_interface(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3bb76f6ea410..05ea88aa76e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -90,7 +90,6 @@ struct iwl_cmd; #define IWL_CMD(x) case x: return #x struct iwl_hcmd_ops { - int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void (*set_rxon_chain)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant); @@ -112,7 +111,6 @@ struct iwl_hcmd_utils_ops { int (*calc_rssi)(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); int (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif); - void (*post_scan)(struct iwl_priv *priv); }; struct iwl_apm_ops { @@ -141,7 +139,6 @@ struct iwl_lib_ops { struct iwl_apm_ops apm_ops; /* power */ - int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); /* eeprom operations (as defined in iwl-eeprom.h) */ @@ -225,7 +222,7 @@ struct iwl_base_params { * @ampdu_factor: Maximum A-MPDU length factor * @ampdu_density: Minimum A-MPDU spacing * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode -*/ + */ struct iwl_bt_params { bool advanced_bt_coexist; u8 bt_init_traffic_load; @@ -238,10 +235,11 @@ struct iwl_bt_params { }; /* * @use_rts_for_aggregation: use rts/cts protection for HT traffic -*/ + */ struct iwl_ht_params { const bool ht_greenfield_support; /* if used set to true */ bool use_rts_for_aggregation; + enum ieee80211_smps_mode smps_mode; }; /** @@ -560,6 +558,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_DEVICE_ENABLED 18 +#define STATUS_CHANNEL_SWITCH_PENDING 19 static inline int iwl_is_ready(struct iwl_priv *priv) @@ -612,11 +611,7 @@ void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_init(struct iwl_priv *priv); int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -static inline int iwlcore_commit_rxon(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - return priv->cfg->ops->hcmd->commit_rxon(priv, ctx); -} + static inline const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1f4797d9848d..7ad98d868954 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -983,17 +983,6 @@ struct traffic_stats { }; /* - * iwl_switch_rxon: "channel switch" structure - * - * @ switch_in_progress: channel switch in progress - * @ channel: new channel - */ -struct iwl_switch_rxon { - bool switch_in_progress; - __le16 channel; -}; - -/* * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds * to perform continuous uCode event logging operation if enabled */ @@ -1288,7 +1277,7 @@ struct iwl_priv { struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX]; - struct iwl_switch_rxon switch_rxon; + __le16 switch_channel; struct { u32 error_event_table; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 0053e9ea9021..b774517aa9fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -250,19 +250,19 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_cmd *rxon = (void *)&ctx->active; - if (priv->switch_rxon.switch_in_progress) { - if (!le32_to_cpu(csa->status) && - (csa->channel == priv->switch_rxon.channel)) { - rxon->channel = csa->channel; - ctx->staging.channel = csa->channel; - IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", - le16_to_cpu(csa->channel)); - iwl_chswitch_done(priv, true); - } else { - IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + return; + + if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) { + rxon->channel = csa->channel; + ctx->staging.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", le16_to_cpu(csa->channel)); - iwl_chswitch_done(priv, false); - } + iwl_chswitch_done(priv, true); + } else { + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); + iwl_chswitch_done(priv, false); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index d60d630cb93a..438eecd87335 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -36,6 +36,7 @@ #include "iwl-sta.h" #include "iwl-io.h" #include "iwl-helpers.h" +#include "iwl-agn.h" /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses @@ -600,14 +601,7 @@ out_settings: if (!iwl_is_ready_rf(priv)) goto out; - /* - * We do not commit power settings while scan is pending, - * do it now if the settings changed. - */ - iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false); - iwl_set_tx_power(priv, priv->tx_power_next, false); - - priv->cfg->ops->utils->post_scan(priv); + iwlagn_post_scan(priv); out: mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 686e176b5ebd..1084fe0e8a86 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -753,9 +753,9 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx) int nfreed = 0; if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) { - IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, " - "is out of range [0-%d] %d %d.\n", txq_id, - idx, q->n_bd, q->write_ptr, q->read_ptr); + IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), " + "index %d is out of range [0-%d] %d %d.\n", __func__, + txq_id, idx, q->n_bd, q->write_ptr, q->read_ptr); return; } diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index a7b5cb0c2753..224e9853c480 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -907,7 +907,7 @@ static void if_sdio_interrupt(struct sdio_func *func) card = sdio_get_drvdata(func); cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret); - if (ret) + if (ret || !cause) goto out; lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause); @@ -1008,10 +1008,6 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto release; - ret = sdio_claim_irq(func, if_sdio_interrupt); - if (ret) - goto disable; - /* For 1-bit transfers to the 8686 model, we need to enable the * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 * bit to allow access to non-vendor registers. */ @@ -1083,6 +1079,21 @@ static int if_sdio_probe(struct sdio_func *func, card->rx_unit = 0; /* + * Set up the interrupt handler late. + * + * If we set it up earlier, the (buggy) hardware generates a spurious + * interrupt, even before the interrupt has been enabled, with + * CCCR_INTx = 0. + * + * We register the interrupt handler late so that we can handle any + * spurious interrupts, and also to avoid generation of that known + * spurious interrupt in the first place. + */ + ret = sdio_claim_irq(func, if_sdio_interrupt); + if (ret) + goto disable; + + /* * Enable interrupts now that everything is set up */ sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9d4a40ee16c4..7e1fa9671277 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1,6 +1,7 @@ /* * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -25,11 +26,17 @@ #include <linux/rtnetlink.h> #include <linux/etherdevice.h> #include <linux/debugfs.h> +#include <net/genetlink.h> +#include "mac80211_hwsim.h" + +#define WARN_QUEUE 100 +#define MAX_QUEUE 200 MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); MODULE_LICENSE("GPL"); +int wmediumd_pid; static int radios = 2; module_param(radios, int, 0444); MODULE_PARM_DESC(radios, "Number of simulated radios"); @@ -302,6 +309,7 @@ struct mac80211_hwsim_data { struct dentry *debugfs; struct dentry *debugfs_ps; + struct sk_buff_head pending; /* packets pending */ /* * Only radios in the same group can communicate together (the * channel has to match too). Each bit represents a group. A @@ -322,6 +330,32 @@ struct hwsim_radiotap_hdr { __le16 rt_chbitmask; } __packed; +/* MAC80211_HWSIM netlinf family */ +static struct genl_family hwsim_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = "MAC80211_HWSIM", + .version = 1, + .maxattr = HWSIM_ATTR_MAX, +}; + +/* MAC80211_HWSIM netlink policy */ + +static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { + [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, + .len = 6*sizeof(u8) }, + [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, + .len = 6*sizeof(u8) }, + [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, + [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, + [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, + [HWSIM_ATTR_TX_INFO] = { .type = NLA_UNSPEC, + .len = IEEE80211_TX_MAX_RATES*sizeof( + struct hwsim_tx_rate)}, + [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, +}; static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) @@ -478,9 +512,89 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, return md.ret; } +static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, + struct sk_buff *my_skb, + int dst_pid) +{ + struct sk_buff *skb; + struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb); + void *msg_head; + unsigned int hwsim_flags = 0; + int i; + struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; + + if (data->idle) { + wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); + dev_kfree_skb(my_skb); + return; + } + + if (data->ps != PS_DISABLED) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + /* If the queue contains MAX_QUEUE skb's drop some */ + if (skb_queue_len(&data->pending) >= MAX_QUEUE) { + /* Droping until WARN_QUEUE level */ + while (skb_queue_len(&data->pending) >= WARN_QUEUE) + skb_dequeue(&data->pending); + } + + skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + if (skb == NULL) + goto nla_put_failure; + + msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, + HWSIM_CMD_FRAME); + if (msg_head == NULL) { + printk(KERN_DEBUG "mac80211_hwsim: problem with msg_head\n"); + goto nla_put_failure; + } + + NLA_PUT(skb, HWSIM_ATTR_ADDR_TRANSMITTER, + sizeof(struct mac_address), data->addresses[1].addr); -static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, - struct sk_buff *skb) + /* We get the skb->data */ + NLA_PUT(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data); + + /* We get the flags for this transmission, and we translate them to + wmediumd flags */ + + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) + hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS; + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + hwsim_flags |= HWSIM_TX_CTL_NO_ACK; + + NLA_PUT_U32(skb, HWSIM_ATTR_FLAGS, hwsim_flags); + + /* We get the tx control (rate and retries) info*/ + + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + tx_attempts[i].idx = info->status.rates[i].idx; + tx_attempts[i].count = info->status.rates[i].count; + } + + NLA_PUT(skb, HWSIM_ATTR_TX_INFO, + sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, + tx_attempts); + + /* We create a cookie to identify this skb */ + NLA_PUT_U64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb); + + genlmsg_end(skb, msg_head); + genlmsg_unicast(&init_net, skb, dst_pid); + + /* Enqueue the packet */ + skb_queue_tail(&data->pending, my_skb); + return; + +nla_put_failure: + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); +} + +static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, + struct sk_buff *skb) { struct mac80211_hwsim_data *data = hw->priv, *data2; bool ack = false; @@ -540,11 +654,11 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, return ack; } - static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { bool ack; struct ieee80211_tx_info *txi; + int _pid; mac80211_hwsim_monitor_rx(hw, skb); @@ -554,7 +668,15 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return; } - ack = mac80211_hwsim_tx_frame(hw, skb); + /* wmediumd mode check */ + _pid = wmediumd_pid; + + if (_pid) + return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); + + /* NO wmediumd detected, perfect medium simulation */ + ack = mac80211_hwsim_tx_frame_no_nl(hw, skb); + if (ack && skb->len >= 16) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; mac80211_hwsim_monitor_ack(hw, hdr->addr2); @@ -635,6 +757,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct ieee80211_hw *hw = arg; struct sk_buff *skb; struct ieee80211_tx_info *info; + int _pid; hwsim_check_magic(vif); @@ -649,7 +772,14 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, info = IEEE80211_SKB_CB(skb); mac80211_hwsim_monitor_rx(hw, skb); - mac80211_hwsim_tx_frame(hw, skb); + + /* wmediumd mode check */ + _pid = wmediumd_pid; + + if (_pid) + return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); + + mac80211_hwsim_tx_frame_no_nl(hw, skb); dev_kfree_skb(skb); } @@ -966,12 +1096,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) { - /* - * In this special case, there's nothing we need to - * do because hwsim does transmission synchronously. - * In the future, when it does transmissions via - * userspace, we may need to do something. - */ + /* Not implemented, queues only on kernel side */ } struct hw_scan_done { @@ -1119,6 +1244,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct sk_buff *skb; struct ieee80211_pspoll *pspoll; + int _pid; if (!vp->assoc) return; @@ -1137,8 +1263,15 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) pspoll->aid = cpu_to_le16(0xc000 | vp->aid); memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); memcpy(pspoll->ta, mac, ETH_ALEN); - if (!mac80211_hwsim_tx_frame(data->hw, skb)) - printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); + + /* wmediumd mode check */ + _pid = wmediumd_pid; + + if (_pid) + return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); + + if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) + printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__); dev_kfree_skb(skb); } @@ -1149,6 +1282,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct sk_buff *skb; struct ieee80211_hdr *hdr; + int _pid; if (!vp->assoc) return; @@ -1168,7 +1302,14 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, memcpy(hdr->addr1, vp->bssid, ETH_ALEN); memcpy(hdr->addr2, mac, ETH_ALEN); memcpy(hdr->addr3, vp->bssid, ETH_ALEN); - if (!mac80211_hwsim_tx_frame(data->hw, skb)) + + /* wmediumd mode check */ + _pid = wmediumd_pid; + + if (_pid) + return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); + + if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); dev_kfree_skb(skb); } @@ -1248,6 +1389,273 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, hwsim_fops_group_read, hwsim_fops_group_write, "%llx\n"); +struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr( + struct mac_address *addr) +{ + struct mac80211_hwsim_data *data; + bool _found = false; + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_entry(data, &hwsim_radios, list) { + if (memcmp(data->addresses[1].addr, addr, + sizeof(struct mac_address)) == 0) { + _found = true; + break; + } + } + spin_unlock_bh(&hwsim_radio_lock); + + if (!_found) + return NULL; + + return data; +} + +static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, + struct genl_info *info) +{ + + struct ieee80211_hdr *hdr; + struct mac80211_hwsim_data *data2; + struct ieee80211_tx_info *txi; + struct hwsim_tx_rate *tx_attempts; + struct sk_buff __user *ret_skb; + struct sk_buff *skb, *tmp; + struct mac_address *src; + unsigned int hwsim_flags; + + int i; + bool found = false; + + if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || + !info->attrs[HWSIM_ATTR_FLAGS] || + !info->attrs[HWSIM_ATTR_COOKIE] || + !info->attrs[HWSIM_ATTR_TX_INFO]) + goto out; + + src = (struct mac_address *)nla_data( + info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); + hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); + + ret_skb = (struct sk_buff __user *) + (unsigned long) nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); + + data2 = get_hwsim_data_ref_from_addr(src); + + if (data2 == NULL) + goto out; + + /* look for the skb matching the cookie passed back from user */ + skb_queue_walk_safe(&data2->pending, skb, tmp) { + if (skb == ret_skb) { + skb_unlink(skb, &data2->pending); + found = true; + break; + } + } + + /* not found */ + if (!found) + goto out; + + /* Tx info received because the frame was broadcasted on user space, + so we get all the necessary info: tx attempts and skb control buff */ + + tx_attempts = (struct hwsim_tx_rate *)nla_data( + info->attrs[HWSIM_ATTR_TX_INFO]); + + /* now send back TX status */ + txi = IEEE80211_SKB_CB(skb); + + if (txi->control.vif) + hwsim_check_magic(txi->control.vif); + if (txi->control.sta) + hwsim_check_sta_magic(txi->control.sta); + + ieee80211_tx_info_clear_status(txi); + + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + txi->status.rates[i].idx = tx_attempts[i].idx; + txi->status.rates[i].count = tx_attempts[i].count; + /*txi->status.rates[i].flags = 0;*/ + } + + txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); + + if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) && + (hwsim_flags & HWSIM_TX_STAT_ACK)) { + if (skb->len >= 16) { + hdr = (struct ieee80211_hdr *) skb->data; + mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); + } + } + ieee80211_tx_status_irqsafe(data2->hw, skb); + return 0; +out: + return -EINVAL; + +} + +static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, + struct genl_info *info) +{ + + struct mac80211_hwsim_data *data2; + struct ieee80211_rx_status rx_status; + struct mac_address *dst; + int frame_data_len; + char *frame_data; + struct sk_buff *skb = NULL; + + if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || + !info->attrs[HWSIM_ATTR_FRAME] || + !info->attrs[HWSIM_ATTR_RX_RATE] || + !info->attrs[HWSIM_ATTR_SIGNAL]) + goto out; + + dst = (struct mac_address *)nla_data( + info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); + + frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); + frame_data = (char *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); + + /* Allocate new skb here */ + skb = alloc_skb(frame_data_len, GFP_KERNEL); + if (skb == NULL) + goto err; + + if (frame_data_len <= IEEE80211_MAX_DATA_LEN) { + /* Copy the data */ + memcpy(skb_put(skb, frame_data_len), frame_data, + frame_data_len); + } else + goto err; + + data2 = get_hwsim_data_ref_from_addr(dst); + + if (data2 == NULL) + goto out; + + /* check if radio is configured properly */ + + if (data2->idle || !data2->started || !data2->channel) + goto out; + + /*A frame is received from user space*/ + memset(&rx_status, 0, sizeof(rx_status)); + rx_status.freq = data2->channel->center_freq; + rx_status.band = data2->channel->band; + rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); + rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); + + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(data2->hw, skb); + + return 0; +err: + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); + goto out; +out: + dev_kfree_skb(skb); + return -EINVAL; +} + +static int hwsim_register_received_nl(struct sk_buff *skb_2, + struct genl_info *info) +{ + if (info == NULL) + goto out; + + wmediumd_pid = info->snd_pid; + + printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, " + "switching to wmediumd mode with pid %d\n", info->snd_pid); + + return 0; +out: + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); + return -EINVAL; +} + +/* Generic Netlink operations array */ +static struct genl_ops hwsim_ops[] = { + { + .cmd = HWSIM_CMD_REGISTER, + .policy = hwsim_genl_policy, + .doit = hwsim_register_received_nl, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = HWSIM_CMD_FRAME, + .policy = hwsim_genl_policy, + .doit = hwsim_cloned_frame_received_nl, + }, + { + .cmd = HWSIM_CMD_TX_INFO_FRAME, + .policy = hwsim_genl_policy, + .doit = hwsim_tx_info_frame_received_nl, + }, +}; + +static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, + unsigned long state, + void *_notify) +{ + struct netlink_notify *notify = _notify; + + if (state != NETLINK_URELEASE) + return NOTIFY_DONE; + + if (notify->pid == wmediumd_pid) { + printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" + " socket, switching to perfect channel medium\n"); + wmediumd_pid = 0; + } + return NOTIFY_DONE; + +} + +static struct notifier_block hwsim_netlink_notifier = { + .notifier_call = mac80211_hwsim_netlink_notify, +}; + +static int hwsim_init_netlink(void) +{ + int rc; + printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); + + wmediumd_pid = 0; + + rc = genl_register_family_with_ops(&hwsim_genl_family, + hwsim_ops, ARRAY_SIZE(hwsim_ops)); + if (rc) + goto failure; + + rc = netlink_register_notifier(&hwsim_netlink_notifier); + if (rc) + goto failure; + + return 0; + +failure: + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); + return -EINVAL; +} + +static void hwsim_exit_netlink(void) +{ + int ret; + + printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); + /* unregister the notifier */ + netlink_unregister_notifier(&hwsim_netlink_notifier); + /* unregister the family */ + ret = genl_unregister_family(&hwsim_genl_family); + if (ret) + printk(KERN_DEBUG "mac80211_hwsim: " + "unregister family %i\n", ret); +} + static int __init init_mac80211_hwsim(void) { int i, err = 0; @@ -1298,6 +1706,7 @@ static int __init init_mac80211_hwsim(void) goto failed_drvdata; } data->dev->driver = &mac80211_hwsim_driver; + skb_queue_head_init(&data->pending); SET_IEEE80211_DEV(hw, data->dev); addr[3] = i >> 8; @@ -1379,6 +1788,10 @@ static int __init init_mac80211_hwsim(void) data->group = 1; mutex_init(&data->mutex); + /* Enable frame retransmissions for lossy channels */ + hw->max_rates = 4; + hw->max_rate_tries = 11; + /* Work to be done prior to ieee80211_register_hw() */ switch (regtest) { case HWSIM_REGTEST_DISABLED: @@ -1515,12 +1928,29 @@ static int __init init_mac80211_hwsim(void) if (hwsim_mon == NULL) goto failed; - err = register_netdev(hwsim_mon); + rtnl_lock(); + + err = dev_alloc_name(hwsim_mon, hwsim_mon->name); if (err < 0) goto failed_mon; + + err = register_netdevice(hwsim_mon); + if (err < 0) + goto failed_mon; + + rtnl_unlock(); + + err = hwsim_init_netlink(); + if (err < 0) + goto failed_nl; + return 0; +failed_nl: + printk(KERN_DEBUG "mac_80211_hwsim: failed initializing netlink\n"); + return err; + failed_mon: rtnl_unlock(); free_netdev(hwsim_mon); @@ -1541,6 +1971,8 @@ static void __exit exit_mac80211_hwsim(void) { printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); + hwsim_exit_netlink(); + mac80211_hwsim_free(); unregister_netdev(hwsim_mon); } diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h new file mode 100644 index 000000000000..afaad5a443b6 --- /dev/null +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -0,0 +1,133 @@ +/* + * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 + * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __MAC80211_HWSIM_H +#define __MAC80211_HWSIM_H + +/** + * enum hwsim_tx_control_flags - flags to describe transmission info/status + * + * These flags are used to give the wmediumd extra information in order to + * modify its behavior for each frame + * + * @HWSIM_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. + * @HWSIM_TX_CTL_NO_ACK: tell the wmediumd not to wait for an ack + * @HWSIM_TX_STAT_ACK: Frame was acknowledged + * + */ +enum hwsim_tx_control_flags { + HWSIM_TX_CTL_REQ_TX_STATUS = BIT(0), + HWSIM_TX_CTL_NO_ACK = BIT(1), + HWSIM_TX_STAT_ACK = BIT(2), +}; + +/** + * DOC: Frame transmission/registration support + * + * Frame transmission and registration support exists to allow userspace + * entities such as wmediumd to receive and process all broadcasted + * frames from a mac80211_hwsim radio device. + * + * This allow user space applications to decide if the frame should be + * dropped or not and implement a wireless medium simulator at user space. + * + * Registration is done by sending a register message to the driver and + * will be automatically unregistered if the user application doesn't + * responds to sent frames. + * Once registered the user application has to take responsibility of + * broadcasting the frames to all listening mac80211_hwsim radio + * interfaces. + * + * For more technical details, see the corresponding command descriptions + * below. + */ + +/** + * enum hwsim_commands - supported hwsim commands + * + * @HWSIM_CMD_UNSPEC: unspecified command to catch errors + * + * @HWSIM_CMD_REGISTER: request to register and received all broadcasted + * frames by any mac80211_hwsim radio device. + * @HWSIM_CMD_FRAME: send/receive a broadcasted frame from/to kernel/user + * space, uses: + * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER, + * %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE, + * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE + * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to + * kernel, uses: + * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, + * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE + * @__HWSIM_CMD_MAX: enum limit + */ +enum { + HWSIM_CMD_UNSPEC, + HWSIM_CMD_REGISTER, + HWSIM_CMD_FRAME, + HWSIM_CMD_TX_INFO_FRAME, + __HWSIM_CMD_MAX, +}; +#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) + +/** + * enum hwsim_attrs - hwsim netlink attributes + * + * @HWSIM_ATTR_UNSPEC: unspecified attribute to catch errors + * + * @HWSIM_ATTR_ADDR_RECEIVER: MAC address of the radio device that + * the frame is broadcasted to + * @HWSIM_ATTR_ADDR_TRANSMITTER: MAC address of the radio device that + * the frame was broadcasted from + * @HWSIM_ATTR_FRAME: Data array + * @HWSIM_ATTR_FLAGS: mac80211 transmission flags, used to process + properly the frame at user space + * @HWSIM_ATTR_RX_RATE: estimated rx rate index for this frame at user + space + * @HWSIM_ATTR_SIGNAL: estimated RX signal for this frame at user + space + * @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array + * @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame + * @__HWSIM_ATTR_MAX: enum limit + */ + + +enum { + HWSIM_ATTR_UNSPEC, + HWSIM_ATTR_ADDR_RECEIVER, + HWSIM_ATTR_ADDR_TRANSMITTER, + HWSIM_ATTR_FRAME, + HWSIM_ATTR_FLAGS, + HWSIM_ATTR_RX_RATE, + HWSIM_ATTR_SIGNAL, + HWSIM_ATTR_TX_INFO, + HWSIM_ATTR_COOKIE, + __HWSIM_ATTR_MAX, +}; +#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) + +/** + * struct hwsim_tx_rate - rate selection/status + * + * @idx: rate index to attempt to send with + * @count: number of tries in this rate before going to the next rate + * + * A value of -1 for @idx indicates an invalid rate and, if used + * in an array of retry rates, that no more rates should be tried. + * + * When used for transmit status reporting, the driver should + * always report the rate and number of retries used. + * + */ +struct hwsim_tx_rate { + s8 idx; + u8 count; +} __packed; + +#endif /* __MAC80211_HWSIM_H */ diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index f807447e4d99..1a453a605b3f 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -164,12 +164,13 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; - if (skb_queue_empty(&pra_list->skb_head)) { + skb_src = skb_peek(&pra_list->skb_head); + if (!skb_src) { spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); return 0; } - skb_src = skb_peek(&pra_list->skb_head); + tx_info_src = MWIFIEX_SKB_TXCB(skb_src); skb_aggr = dev_alloc_skb(adapter->tx_buf_size); if (!skb_aggr) { @@ -184,17 +185,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, tx_info_aggr->bss_index = tx_info_src->bss_index; skb_aggr->priority = skb_src->priority; - while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len - + LLC_SNAP_LEN) - <= adapter->tx_buf_size)) { + do { + /* Check if AMSDU can accommodate this MSDU */ + if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN)) + break; - if (!skb_queue_empty(&pra_list->skb_head)) - skb_src = skb_dequeue(&pra_list->skb_head); - else - skb_src = NULL; + skb_src = skb_dequeue(&pra_list->skb_head); - if (skb_src) - pra_list->total_pkts_size -= skb_src->len; + pra_list->total_pkts_size -= skb_src->len; + pra_list->total_pkts--; atomic_dec(&priv->wmm.tx_pkts_queued); @@ -212,11 +211,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, return -1; } - if (!skb_queue_empty(&pra_list->skb_head)) - skb_src = skb_peek(&pra_list->skb_head); - else - skb_src = NULL; - } + if (skb_tailroom(skb_aggr) < pad) { + pad = 0; + break; + } + skb_put(skb_aggr, pad); + + skb_src = skb_peek(&pra_list->skb_head); + + } while (skb_src); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -230,11 +233,19 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_push(skb_aggr, headroom); - tx_param.next_pkt_len = ((pra_list->total_pkts_size) ? - (((pra_list->total_pkts_size) > - adapter->tx_buf_size) ? adapter-> - tx_buf_size : pra_list->total_pkts_size + - LLC_SNAP_LEN + sizeof(struct txpd)) : 0); + /* + * Padding per MSDU will affect the length of next + * packet and hence the exact length of next packet + * is uncertain here. + * + * Also, aggregation of transmission buffer, while + * downloading the data to the card, wont gain much + * on the AMSDU packets as the AMSDU packets utilizes + * the transmission buffer space to the maximum + * (adapter->tx_buf_size). + */ + tx_param.next_pkt_len = 0; + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb_aggr->data, skb_aggr->len, &tx_param); @@ -258,6 +269,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_queue_tail(&pra_list->skb_head, skb_aggr); pra_list->total_pkts_size += skb_aggr->len; + pra_list->total_pkts++; atomic_inc(&priv->wmm.tx_pkts_queued); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index f0582259c935..4f43443036f4 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -35,8 +35,6 @@ static struct mwifiex_bss_attr mwifiex_bss_sta[] = { static int drv_mode = DRV_MODE_STA; -static char fw_name[32] = DEFAULT_FW_NAME; - /* Supported drv_mode table */ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { { @@ -384,20 +382,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) memset(&fw, 0, sizeof(struct mwifiex_fw_image)); - switch (adapter->revision_id) { - case SD8787_W0: - case SD8787_W1: - strcpy(fw_name, SD8787_W1_FW_NAME); - break; - case SD8787_A0: - case SD8787_A1: - strcpy(fw_name, SD8787_AX_FW_NAME); - break; - default: - break; - } - - err = request_firmware(&adapter->firmware, fw_name, adapter->dev); + err = request_firmware(&adapter->firmware, adapter->fw_name, + adapter->dev); if (err < 0) { dev_err(adapter->dev, "request_firmware() returned" " error code %#x\n", err); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 8316b3cd92cd..57b183af72d7 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -48,15 +48,6 @@ enum { #define DRV_MODE_STA 0x1 -#define SD8787_W0 0x30 -#define SD8787_W1 0x31 -#define SD8787_A0 0x40 -#define SD8787_A1 0x41 - -#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" -#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin" -#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin" - struct mwifiex_drv_mode { u16 drv_mode; u16 intf_num; @@ -190,6 +181,7 @@ struct mwifiex_ra_list_tbl { struct sk_buff_head skb_head; u8 ra[ETH_ALEN]; u32 total_pkts_size; + u32 total_pkts; u32 is_11n_enabled; }; @@ -576,10 +568,10 @@ struct mwifiex_adapter { u8 priv_num; struct mwifiex_drv_mode *drv_mode; const struct firmware *firmware; + char fw_name[32]; struct device *dev; bool surprise_removed; u32 fw_release_number; - u32 revision_id; u16 init_wait_q_woken; wait_queue_head_t init_wait_q; void *card; diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index d425dbd91d19..4327b6d099c8 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1531,6 +1531,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) sdio_set_drvdata(func, card); adapter->dev = &func->dev; + strcpy(adapter->fw_name, SD8787_DEFAULT_FW_NAME); return 0; @@ -1552,7 +1553,6 @@ disable_func: * the first interrupt got from bootloader * - Disable host interrupt mask register * - Get SDIO port - * - Get revision ID * - Initialize SDIO variables in card * - Allocate MP registers * - Allocate MPA Tx and Rx buffers @@ -1576,10 +1576,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) /* Get SDIO ioport */ mwifiex_init_sdio_ioport(adapter); - /* Get revision ID */ -#define REV_ID_REG 0x5c - mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); - /* Initialize SDIO variables in card */ card->mp_rd_bitmap = 0; card->mp_wr_bitmap = 0; @@ -1751,4 +1747,4 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); MODULE_VERSION(SDIO_VERSION); MODULE_LICENSE("GPL v2"); -MODULE_FIRMWARE("sd8787.bin"); +MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 4e97e90aa399..c925376fcaae 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -28,6 +28,8 @@ #include "main.h" +#define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" + #define BLOCK_MODE 1 #define BYTE_MODE 0 diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 91634daec306..67b2d0b78c71 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -121,6 +121,7 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) memcpy(ra_list->ra, ra, ETH_ALEN); ra_list->total_pkts_size = 0; + ra_list->total_pkts = 0; dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); @@ -645,6 +646,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, skb_queue_tail(&ra_list->skb_head, skb); ra_list->total_pkts_size += skb->len; + ra_list->total_pkts++; atomic_inc(&priv->wmm.tx_pkts_queued); @@ -971,28 +973,6 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, } /* - * This function gets the number of packets in the Tx queue of a - * particular RA list. - */ -static int -mwifiex_num_pkts_in_txq(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int max_buf_size) -{ - int count = 0, total_size = 0; - struct sk_buff *skb, *tmp; - - skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { - total_size += skb->len; - if (total_size < max_buf_size) - ++count; - else - break; - } - - return count; -} - -/* * This function sends a single packet to firmware for transmission. */ static void @@ -1019,6 +999,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); ptr->total_pkts_size -= skb->len; + ptr->total_pkts--; if (!skb_queue_empty(&ptr->skb_head)) skb_next = skb_peek(&ptr->skb_head); @@ -1044,6 +1025,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, skb_queue_tail(&ptr->skb_head, skb); ptr->total_pkts_size += skb->len; + ptr->total_pkts++; tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -1231,9 +1213,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) } /* Minimum number of AMSDU */ #define MIN_NUM_AMSDU 2 + if (mwifiex_is_amsdu_allowed(priv, tid) && - (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= - MIN_NUM_AMSDU)) + (ptr->total_pkts >= MIN_NUM_AMSDU)) mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptr_index, flags); /* ra_list_spinlock has been freed in diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index b2f8b8fd4d2d..a0a7854facc0 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -83,14 +83,12 @@ config RT2800PCI_RT33XX config RT2800PCI_RT35XX bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL - default n + default y ---help--- This adds support for rt35xx wireless chipset family to the rt2800pci driver. Supported chips: RT3060, RT3062, RT3562, RT3592 - Support for these devices is non-functional at the moment and is - intended for testers and developers. config RT2800PCI_RT53XX bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)" @@ -154,15 +152,12 @@ config RT2800USB_RT33XX config RT2800USB_RT35XX bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL - default n + default y ---help--- This adds support for rt35xx wireless chipset family to the rt2800usb driver. Supported chips: RT3572 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - config RT2800USB_RT53XX bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index f67bc9b31b28..c69a7d71f4ca 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1740,6 +1740,7 @@ struct mac_iveiv_entry { /* * BBP 3: RX Antenna */ +#define BBP3_RX_ADC FIELD8(0x03) #define BBP3_RX_ANTENNA FIELD8(0x18) #define BBP3_HT40_MINUS FIELD8(0x20) @@ -1783,6 +1784,8 @@ struct mac_iveiv_entry { #define RFCSR1_TX0_PD FIELD8(0x08) #define RFCSR1_RX1_PD FIELD8(0x10) #define RFCSR1_TX1_PD FIELD8(0x20) +#define RFCSR1_RX2_PD FIELD8(0x40) +#define RFCSR1_TX2_PD FIELD8(0x80) /* * RFCSR 2: @@ -1790,15 +1793,25 @@ struct mac_iveiv_entry { #define RFCSR2_RESCAL_EN FIELD8(0x80) /* + * FRCSR 5: + */ +#define RFCSR5_R1 FIELD8(0x0c) + +/* * RFCSR 6: */ #define RFCSR6_R1 FIELD8(0x03) #define RFCSR6_R2 FIELD8(0x40) +#define RFCSR6_TXDIV FIELD8(0x0c) /* * RFCSR 7: */ #define RFCSR7_RF_TUNING FIELD8(0x01) +#define RFCSR7_R02 FIELD8(0x07) +#define RFCSR7_R3 FIELD8(0x08) +#define RFCSR7_R45 FIELD8(0x30) +#define RFCSR7_R67 FIELD8(0xc0) /* * RFCSR 11: @@ -1809,11 +1822,13 @@ struct mac_iveiv_entry { * RFCSR 12: */ #define RFCSR12_TX_POWER FIELD8(0x1f) +#define RFCSR12_DR0 FIELD8(0xe0) /* * RFCSR 13: */ #define RFCSR13_TX_POWER FIELD8(0x1f) +#define RFCSR13_DR0 FIELD8(0xe0) /* * RFCSR 15: @@ -2256,6 +2271,7 @@ struct mac_iveiv_entry { #define MCU_ANT_SELECT 0X73 #define MCU_BBP_SIGNAL 0x80 #define MCU_POWER_SAVE 0x83 +#define MCU_BAND_SELECT 0x91 /* * MCU mailbox tokens diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 8f92dfcb08df..84ab7d1acb6a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -401,7 +401,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, return -EBUSY; if (rt2x00_is_pci(rt2x00dev)) { - if (rt2x00_rt(rt2x00dev, RT5390)) { + if (rt2x00_rt(rt2x00dev, RT3572) || + rt2x00_rt(rt2x00dev, RT5390)) { rt2800_register_read(rt2x00dev, AUX_CTRL, ®); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); @@ -600,49 +601,6 @@ void rt2800_process_rxwi(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_process_rxwi); -static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) -{ - __le32 *txwi; - u32 word; - int wcid, ack, pid; - int tx_wcid, tx_ack, tx_pid; - - wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); - ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); - pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); - - /* - * This frames has returned with an IO error, - * so the status report is not intended for this - * frame. - */ - if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { - rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); - return false; - } - - /* - * Validate if this TX status report is intended for - * this entry by comparing the WCID/ACK/PID fields. - */ - txwi = rt2800_drv_get_txwi(entry); - - rt2x00_desc_read(txwi, 1, &word); - tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); - tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); - tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); - - if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { - WARNING(entry->queue->rt2x00dev, - "TX status report missed for queue %d entry %d\n", - entry->queue->qid, entry->entry_idx); - rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); - return false; - } - - return true; -} - void rt2800_txdone_entry(struct queue_entry *entry, u32 status) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; @@ -725,45 +683,6 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) } EXPORT_SYMBOL_GPL(rt2800_txdone_entry); -void rt2800_txdone(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue; - struct queue_entry *entry; - u32 reg; - u8 qid; - - while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { - - /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus - * qid is guaranteed to be one of the TX QIDs - */ - qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); - queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); - if (unlikely(!queue)) { - WARNING(rt2x00dev, "Got TX status for an unavailable " - "queue %u, dropping\n", qid); - continue; - } - - /* - * Inside each queue, we process each entry in a chronological - * order. We first check that the queue is not empty. - */ - entry = NULL; - while (!rt2x00queue_empty(queue)) { - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - if (rt2800_txdone_entry_check(entry, reg)) - break; - } - - if (!entry || rt2x00queue_empty(queue)) - break; - - rt2800_txdone_entry(entry, reg); - } -} -EXPORT_SYMBOL_GPL(rt2800_txdone); - void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; @@ -1433,6 +1352,40 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, } EXPORT_SYMBOL_GPL(rt2800_config_erp); +static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 eeprom; + u8 led_ctrl, led_g_mode, led_r_mode; + + rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { + rt2x00_set_field32(®, GPIO_SWITCH_0, 1); + rt2x00_set_field32(®, GPIO_SWITCH_1, 1); + } else { + rt2x00_set_field32(®, GPIO_SWITCH_0, 0); + rt2x00_set_field32(®, GPIO_SWITCH_1, 0); + } + rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); + + rt2800_register_read(rt2x00dev, LED_CFG, ®); + led_g_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 3 : 0; + led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3; + if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) || + led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE); + if (led_ctrl == 0 || led_ctrl > 0x40) { + rt2x00_set_field32(®, LED_CFG_G_LED_MODE, led_g_mode); + rt2x00_set_field32(®, LED_CFG_R_LED_MODE, led_r_mode); + rt2800_register_write(rt2x00dev, LED_CFG, reg); + } else { + rt2800_mcu_request(rt2x00dev, MCU_BAND_SELECT, 0xff, + (led_g_mode << 2) | led_r_mode, 1); + } + } +} + static void rt2800_set_ant_diversity(struct rt2x00_dev *rt2x00dev, enum antenna ant) { @@ -1463,6 +1416,10 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2800_bbp_read(rt2x00dev, 1, &r1); rt2800_bbp_read(rt2x00dev, 3, &r3); + if (rt2x00_rt(rt2x00dev, RT3572) && + test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) + rt2800_config_3572bt_ant(rt2x00dev); + /* * Configure the TX antenna. */ @@ -1471,7 +1428,11 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); break; case 2: - rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); + if (rt2x00_rt(rt2x00dev, RT3572) && + test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 1); + else + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); break; case 3: rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); @@ -1496,7 +1457,15 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); break; case 2: - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); + if (rt2x00_rt(rt2x00dev, RT3572) && + test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { + rt2x00_set_field8(&r3, BBP3_RX_ADC, 1); + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, + rt2x00dev->curr_band == IEEE80211_BAND_5GHZ); + rt2800_set_ant_diversity(rt2x00dev, ANTENNA_B); + } else { + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); + } break; case 3: rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); @@ -1630,6 +1599,161 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); } +static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u8 rfcsr; + u32 reg; + + if (rf->channel <= 14) { + rt2800_bbp_write(rt2x00dev, 25, 0x15); + rt2800_bbp_write(rt2x00dev, 26, 0x85); + } else { + rt2800_bbp_write(rt2x00dev, 25, 0x09); + rt2800_bbp_write(rt2x00dev, 26, 0xff); + } + + rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); + rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3); + + rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2); + if (rf->channel <= 14) + rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 2); + else + rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 1); + rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 5, &rfcsr); + if (rf->channel <= 14) + rt2x00_set_field8(&rfcsr, RFCSR5_R1, 1); + else + rt2x00_set_field8(&rfcsr, RFCSR5_R1, 2); + rt2800_rfcsr_write(rt2x00dev, 5, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + if (rf->channel <= 14) { + rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 3); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, + (info->default_power1 & 0x3) | + ((info->default_power1 & 0xC) << 1)); + } else { + rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 7); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, + (info->default_power1 & 0x3) | + ((info->default_power1 & 0xC) << 1)); + } + rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); + if (rf->channel <= 14) { + rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 3); + rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, + (info->default_power2 & 0x3) | + ((info->default_power2 & 0xC) << 1)); + } else { + rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 7); + rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, + (info->default_power2 & 0x3) | + ((info->default_power2 & 0xC) << 1)); + } + rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); + rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); + rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { + if (rf->channel <= 14) { + rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); + rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); + } + rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); + rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); + } else { + switch (rt2x00dev->default_ant.tx_chain_num) { + case 1: + rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); + case 2: + rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); + break; + } + + switch (rt2x00dev->default_ant.rx_chain_num) { + case 1: + rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); + case 2: + rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); + break; + } + } + rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); + rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 24, + rt2x00dev->calibration[conf_is_ht40(conf)]); + rt2800_rfcsr_write(rt2x00dev, 31, + rt2x00dev->calibration[conf_is_ht40(conf)]); + + if (rf->channel <= 14) { + rt2800_rfcsr_write(rt2x00dev, 7, 0xd8); + rt2800_rfcsr_write(rt2x00dev, 9, 0xc3); + rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 11, 0xb9); + rt2800_rfcsr_write(rt2x00dev, 15, 0x53); + rt2800_rfcsr_write(rt2x00dev, 16, 0x4c); + rt2800_rfcsr_write(rt2x00dev, 17, 0x23); + rt2800_rfcsr_write(rt2x00dev, 19, 0x93); + rt2800_rfcsr_write(rt2x00dev, 20, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 25, 0x15); + rt2800_rfcsr_write(rt2x00dev, 26, 0x85); + rt2800_rfcsr_write(rt2x00dev, 27, 0x00); + rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); + } else { + rt2800_rfcsr_write(rt2x00dev, 7, 0x14); + rt2800_rfcsr_write(rt2x00dev, 9, 0xc0); + rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 11, 0x00); + rt2800_rfcsr_write(rt2x00dev, 15, 0x43); + rt2800_rfcsr_write(rt2x00dev, 16, 0x7a); + rt2800_rfcsr_write(rt2x00dev, 17, 0x23); + if (rf->channel <= 64) { + rt2800_rfcsr_write(rt2x00dev, 19, 0xb7); + rt2800_rfcsr_write(rt2x00dev, 20, 0xf6); + rt2800_rfcsr_write(rt2x00dev, 25, 0x3d); + } else if (rf->channel <= 128) { + rt2800_rfcsr_write(rt2x00dev, 19, 0x74); + rt2800_rfcsr_write(rt2x00dev, 20, 0xf4); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + } else { + rt2800_rfcsr_write(rt2x00dev, 19, 0x72); + rt2800_rfcsr_write(rt2x00dev, 20, 0xf3); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + } + rt2800_rfcsr_write(rt2x00dev, 26, 0x87); + rt2800_rfcsr_write(rt2x00dev, 27, 0x01); + rt2800_rfcsr_write(rt2x00dev, 29, 0x9f); + } + + rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + rt2x00_set_field32(®, GPIO_CTRL_CFG_GPIOD_BIT7, 0); + if (rf->channel <= 14) + rt2x00_set_field32(®, GPIO_CTRL_CFG_BIT7, 1); + else + rt2x00_set_field32(®, GPIO_CTRL_CFG_BIT7, 0); + rt2800_register_write(rt2x00dev, GPIO_CTRL_CFG, reg); + + rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); + rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); +} #define RT5390_POWER_BOUND 0x27 #define RT5390_FREQ_OFFSET_BOUND 0x5f @@ -1748,9 +1872,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_rf(rt2x00dev, RF3020) || rt2x00_rf(rt2x00dev, RF3021) || rt2x00_rf(rt2x00dev, RF3022) || - rt2x00_rf(rt2x00dev, RF3052) || rt2x00_rf(rt2x00dev, RF3320)) rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); + else if (rt2x00_rf(rt2x00dev, RF3052)) + rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info); else if (rt2x00_rf(rt2x00dev, RF5370) || rt2x00_rf(rt2x00dev, RF5390)) rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info); @@ -1777,7 +1902,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } } } else { - rt2800_bbp_write(rt2x00dev, 82, 0xf2); + if (rt2x00_rt(rt2x00dev, RT3572)) + rt2800_bbp_write(rt2x00dev, 82, 0x94); + else + rt2800_bbp_write(rt2x00dev, 82, 0xf2); if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) rt2800_bbp_write(rt2x00dev, 75, 0x46); @@ -1791,12 +1919,17 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg); + if (rt2x00_rt(rt2x00dev, RT3572)) + rt2800_rfcsr_write(rt2x00dev, 8, 0); + tx_pin = 0; /* Turn on unused PA or LNA when not using 1T or 1R */ if (rt2x00dev->default_ant.tx_chain_num == 2) { - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, + rf->channel > 14); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, + rf->channel <= 14); } /* Turn on unused PA or LNA when not using 1T or 1R */ @@ -1809,11 +1942,18 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1); + else + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, + rf->channel <= 14); rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + if (rt2x00_rt(rt2x00dev, RT3572)) + rt2800_rfcsr_write(rt2x00dev, 8, 0x80); + rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); rt2800_bbp_write(rt2x00dev, 4, bbp); @@ -2413,6 +2553,9 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030); + } else if (rt2x00_rt(rt2x00dev, RT3572)) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); } else if (rt2x00_rt(rt2x00dev, RT5390)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); @@ -2799,6 +2942,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } if (rt2800_is_305x_soc(rt2x00dev) || + rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390)) rt2800_bbp_write(rt2x00dev, 31, 0x08); @@ -2828,6 +2972,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3390) || + rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390)) { rt2800_bbp_write(rt2x00dev, 79, 0x13); rt2800_bbp_write(rt2x00dev, 80, 0x05); @@ -2868,6 +3013,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) || + rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390) || rt2800_is_305x_soc(rt2x00dev)) rt2800_bbp_write(rt2x00dev, 103, 0xc0); @@ -2895,6 +3041,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3390) || + rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390)) { rt2800_bbp_read(rt2x00dev, 138, &value); @@ -3031,6 +3178,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) !rt2x00_rt(rt2x00dev, RT3071) && !rt2x00_rt(rt2x00dev, RT3090) && !rt2x00_rt(rt2x00dev, RT3390) && + !rt2x00_rt(rt2x00dev, RT3572) && !rt2x00_rt(rt2x00dev, RT5390) && !rt2800_is_305x_soc(rt2x00dev)) return 0; @@ -3109,6 +3257,38 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 29, 0x8f); rt2800_rfcsr_write(rt2x00dev, 30, 0x20); rt2800_rfcsr_write(rt2x00dev, 31, 0x0f); + } else if (rt2x00_rt(rt2x00dev, RT3572)) { + rt2800_rfcsr_write(rt2x00dev, 0, 0x70); + rt2800_rfcsr_write(rt2x00dev, 1, 0x81); + rt2800_rfcsr_write(rt2x00dev, 2, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 3, 0x02); + rt2800_rfcsr_write(rt2x00dev, 4, 0x4c); + rt2800_rfcsr_write(rt2x00dev, 5, 0x05); + rt2800_rfcsr_write(rt2x00dev, 6, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 7, 0xd8); + rt2800_rfcsr_write(rt2x00dev, 9, 0xc3); + rt2800_rfcsr_write(rt2x00dev, 10, 0xf1); + rt2800_rfcsr_write(rt2x00dev, 11, 0xb9); + rt2800_rfcsr_write(rt2x00dev, 12, 0x70); + rt2800_rfcsr_write(rt2x00dev, 13, 0x65); + rt2800_rfcsr_write(rt2x00dev, 14, 0xa0); + rt2800_rfcsr_write(rt2x00dev, 15, 0x53); + rt2800_rfcsr_write(rt2x00dev, 16, 0x4c); + rt2800_rfcsr_write(rt2x00dev, 17, 0x23); + rt2800_rfcsr_write(rt2x00dev, 18, 0xac); + rt2800_rfcsr_write(rt2x00dev, 19, 0x93); + rt2800_rfcsr_write(rt2x00dev, 20, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 21, 0xd0); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x3c); + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800_rfcsr_write(rt2x00dev, 25, 0x15); + rt2800_rfcsr_write(rt2x00dev, 26, 0x85); + rt2800_rfcsr_write(rt2x00dev, 27, 0x00); + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); + rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); + rt2800_rfcsr_write(rt2x00dev, 30, 0x09); + rt2800_rfcsr_write(rt2x00dev, 31, 0x10); } else if (rt2800_is_305x_soc(rt2x00dev)) { rt2800_rfcsr_write(rt2x00dev, 0, 0x50); rt2800_rfcsr_write(rt2x00dev, 1, 0x01); @@ -3258,6 +3438,19 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); rt2x00_set_field32(®, GPIO_SWITCH_5, 0); rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); + } else if (rt2x00_rt(rt2x00dev, RT3572)) { + rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); + rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); + + rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); + rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); + rt2800_register_write(rt2x00dev, LDO_CFG0, reg); + msleep(1); + rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); + rt2800_register_write(rt2x00dev, LDO_CFG0, reg); } /* @@ -3270,7 +3463,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19); } else if (rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090) || - rt2x00_rt(rt2x00dev, RT3390)) { + rt2x00_rt(rt2x00dev, RT3390) || + rt2x00_rt(rt2x00dev, RT3572)) { rt2x00dev->calibration[0] = rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x13); rt2x00dev->calibration[1] = diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index f2d15941c71a..69deb3148ae7 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -152,7 +152,6 @@ void rt2800_write_tx_data(struct queue_entry *entry, struct txentry_desc *txdesc); void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); -void rt2800_txdone(struct rt2x00_dev *rt2x00dev); void rt2800_txdone_entry(struct queue_entry *entry, u32 status); void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 3ac0943b9789..9ccc53733bae 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -501,7 +501,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); - if (rt2x00_rt(rt2x00dev, RT5390)) { + if (rt2x00_is_pcie(rt2x00dev) && + (rt2x00_rt(rt2x00dev, RT3572) || + rt2x00_rt(rt2x00dev, RT5390))) { rt2x00pci_register_read(rt2x00dev, AUX_CTRL, ®); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index ba82c972703a..6e9229830a29 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -457,6 +457,87 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry) /* * TX control handlers */ +static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) +{ + __le32 *txwi; + u32 word; + int wcid, ack, pid; + int tx_wcid, tx_ack, tx_pid; + + wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); + ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); + + /* + * This frames has returned with an IO error, + * so the status report is not intended for this + * frame. + */ + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + return false; + } + + /* + * Validate if this TX status report is intended for + * this entry by comparing the WCID/ACK/PID fields. + */ + txwi = rt2800usb_get_txwi(entry); + + rt2x00_desc_read(txwi, 1, &word); + tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); + tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); + tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); + + if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { + WARNING(entry->queue->rt2x00dev, + "TX status report missed for queue %d entry %d\n", + entry->queue->qid, entry->entry_idx); + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); + return false; + } + + return true; +} + +static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + u32 reg; + u8 qid; + + while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { + + /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus + * qid is guaranteed to be one of the TX QIDs + */ + qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); + if (unlikely(!queue)) { + WARNING(rt2x00dev, "Got TX status for an unavailable " + "queue %u, dropping\n", qid); + continue; + } + + /* + * Inside each queue, we process each entry in a chronological + * order. We first check that the queue is not empty. + */ + entry = NULL; + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + if (rt2800usb_txdone_entry_check(entry, reg)) + break; + } + + if (!entry || rt2x00queue_empty(queue)) + break; + + rt2800_txdone_entry(entry, reg); + } +} + static void rt2800usb_work_txdone(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = @@ -464,7 +545,7 @@ static void rt2800usb_work_txdone(struct work_struct *work) struct data_queue *queue; struct queue_entry *entry; - rt2800_txdone(rt2x00dev); + rt2800usb_txdone(rt2x00dev); /* * Process any trailing TX status reports for IO failures, diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 555180d8f4aa..b704e5b183d0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -250,7 +250,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00link_reset_tuner(rt2x00dev, false); - if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && (conf->flags & IEEE80211_CONF_PS)) { beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index c018d67aab8e..939821b4af2f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -146,6 +146,9 @@ static void rt2x00lib_autowakeup(struct work_struct *work) struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, autowakeup_work.work); + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return; + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) ERROR(rt2x00dev, "Device failed to wakeup.\n"); clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); @@ -1160,6 +1163,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Stop all work. */ cancel_work_sync(&rt2x00dev->intf_work); + cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); if (rt2x00_is_usb(rt2x00dev)) { del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->rxdone_work); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index ab8c16f8bcaf..c7fc9def6bcf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -206,7 +206,6 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); - unsigned long irqflags; if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) return; @@ -227,14 +226,14 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, * sequence counting per-frame, since those will override the * sequence counter given by mac80211. */ - spin_lock_irqsave(&intf->seqlock, irqflags); + spin_lock(&intf->seqlock); if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) intf->seqno += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl |= cpu_to_le16(intf->seqno); - spin_unlock_irqrestore(&intf->seqlock, irqflags); + spin_unlock(&intf->seqlock); } diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index ccb6da38fe22..fb5e43bd7c3c 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -888,7 +888,6 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl_tid_data *tid_data; struct rtl_sta_info *sta_entry = NULL; if (sta == NULL) @@ -906,7 +905,6 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw, return -EINVAL; sta_entry = (struct rtl_sta_info *)sta->drv_priv; - tid_data = &sta_entry->tids[tid]; sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); @@ -918,7 +916,6 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_tid_data *tid_data; struct rtl_sta_info *sta_entry = NULL; if (sta == NULL) @@ -936,7 +933,6 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw, return -EINVAL; sta_entry = (struct rtl_sta_info *)sta->drv_priv; - tid_data = &sta_entry->tids[tid]; sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; return 0; diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 50de6f5d8a56..0b562322f138 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -925,7 +925,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct target_pkt; u8 write_state = PG_STATE_HEADER; - int continual = true, dataempty = true, result = true; + int continual = true, result = true; u16 efuse_addr = 0; u8 efuse_data; u8 target_word_cnts = 0; @@ -953,7 +953,6 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { if (write_state == PG_STATE_HEADER) { - dataempty = true; badworden = 0x0F; RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER\n")); @@ -1176,13 +1175,12 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw) { int continual = true; u16 efuse_addr = 0; - u8 hoffset, hworden; + u8 hworden; u8 efuse_data, word_cnts; while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_addr < EFUSE_MAX_SIZE)) { if (efuse_data != 0xFF) { - hoffset = (efuse_data >> 4) & 0x0F; hworden = efuse_data & 0x0F; word_cnts = efuse_calculate_word_cnts(hworden); efuse_addr = efuse_addr + (word_cnts * 2) + 1; diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 89100e7c553b..fc44005b0d53 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -622,7 +622,7 @@ tx_status_ok: if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) { - rtl_lps_leave(hw); + tasklet_schedule(&rtlpriv->works.ips_leave_tasklet); } } @@ -644,22 +644,23 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) .noise = -98, .rate = 0, }; + int index = rtlpci->rx_ring[rx_queue_idx].idx; /*RX NORMAL PKT */ while (count--) { /*rx descriptor */ struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[ - rtlpci->rx_ring[rx_queue_idx].idx]; + index]; /*rx pkt */ struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[ - rtlpci->rx_ring[rx_queue_idx].idx]; + index]; own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false, HW_DESC_OWN); if (own) { /*wait data to be filled by hardware */ - return; + break; } else { struct ieee80211_hdr *hdr; __le16 fc; @@ -700,7 +701,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); - if (!stats.crc || !stats.hwerror) { + if (!stats.crc && !stats.hwerror) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); @@ -765,15 +766,12 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) { - rtl_lps_leave(hw); + tasklet_schedule(&rtlpriv->works.ips_leave_tasklet); } skb = new_skb; - rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci-> - rx_ring - [rx_queue_idx]. - idx] = skb; + rtlpci->rx_ring[rx_queue_idx].rx_buf[index] = skb; *((dma_addr_t *) skb->cb) = pci_map_single(rtlpci->pdev, skb_tail_pointer(skb), rtlpci->rxbuffersize, @@ -786,23 +784,22 @@ done: rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, - (u8 *)&tmp_one); rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXPKT_LEN, (u8 *)&rtlpci->rxbuffersize); - if (rtlpci->rx_ring[rx_queue_idx].idx == - rtlpci->rxringcount - 1) + if (index == rtlpci->rxringcount - 1) rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXERO, (u8 *)&tmp_one); - rtlpci->rx_ring[rx_queue_idx].idx = - (rtlpci->rx_ring[rx_queue_idx].idx + 1) % - rtlpci->rxringcount; + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, + (u8 *)&tmp_one); + + index = (index + 1) % rtlpci->rxringcount; } + rtlpci->rx_ring[rx_queue_idx].idx = index; } static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) @@ -940,6 +937,11 @@ static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) _rtl_pci_tx_chk_waitq(hw); } +static void _rtl_pci_ips_leave_tasklet(struct ieee80211_hw *hw) +{ + rtl_lps_leave(hw); +} + static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1038,6 +1040,9 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, (unsigned long)hw); + tasklet_init(&rtlpriv->works.ips_leave_tasklet, + (void (*)(unsigned long))_rtl_pci_ips_leave_tasklet, + (unsigned long)hw); } static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, @@ -1507,6 +1512,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) synchronize_irq(rtlpci->pdev->irq); tasklet_kill(&rtlpriv->works.irq_tasklet); + tasklet_kill(&rtlpriv->works.ips_leave_tasklet); flush_workqueue(rtlpriv->works.rtl_wq); destroy_workqueue(rtlpriv->works.rtl_wq); @@ -1581,6 +1587,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw) set_hal_stop(rtlhal); rtlpriv->cfg->ops->disable_interrupt(hw); + tasklet_kill(&rtlpriv->works.ips_leave_tasklet); spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); while (ppsc->rfchange_inprogress) { diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 39b0297ce925..d14c13d02177 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -68,6 +68,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) /*<2> Disable Interrupt */ rtlpriv->cfg->ops->disable_interrupt(hw); + tasklet_kill(&rtlpriv->works.irq_tasklet); /*<3> Disable Adapter */ rtlpriv->cfg->ops->hw_disable(hw); @@ -82,10 +83,8 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - enum rf_pwrstate rtstate; bool actionallowed = false; u16 rfwait_cnt = 0; - unsigned long flag; /*protect_or_not = true; */ @@ -98,10 +97,9 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, *should wait to be executed. */ while (true) { - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + spin_lock(&rtlpriv->locks.rf_ps_lock); if (ppsc->rfchange_inprogress) { - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, - flag); + spin_unlock(&rtlpriv->locks.rf_ps_lock); RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("RF Change in progress!" @@ -122,15 +120,12 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, } } else { ppsc->rfchange_inprogress = true; - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, - flag); + spin_unlock(&rtlpriv->locks.rf_ps_lock); break; } } no_protect: - rtstate = ppsc->rfpwr_state; - switch (state_toset) { case ERFON: ppsc->rfoff_reason &= (~changesource); @@ -173,9 +168,9 @@ no_protect: rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); if (!protect_or_not) { - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + spin_lock(&rtlpriv->locks.rf_ps_lock); ppsc->rfchange_inprogress = false; - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + spin_unlock(&rtlpriv->locks.rf_ps_lock); } return actionallowed; @@ -289,12 +284,11 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); enum rf_pwrstate rtstate; - unsigned long flags; if (mac->opmode != NL80211_IFTYPE_STATION) return; - spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); + spin_lock(&rtlpriv->locks.ips_lock); if (ppsc->inactiveps) { rtstate = ppsc->rfpwr_state; @@ -310,7 +304,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) } } - spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags); + spin_unlock(&rtlpriv->locks.ips_lock); } /*for FW LPS*/ @@ -428,7 +422,6 @@ void rtl_lps_enter(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); - unsigned long flag; if (!ppsc->fwctrl_lps) return; @@ -449,7 +442,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) if (mac->link_state != MAC80211_LINKED) return; - spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + spin_lock(&rtlpriv->locks.lps_lock); /* Idle for a while if we connect to AP a while ago. */ if (mac->cnt_after_linked >= 2) { @@ -461,7 +454,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) } } - spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + spin_unlock(&rtlpriv->locks.lps_lock); } /*Leave the leisure power save mode.*/ @@ -470,9 +463,8 @@ void rtl_lps_leave(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - unsigned long flag; - spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + spin_lock(&rtlpriv->locks.lps_lock); if (ppsc->fwctrl_lps) { if (ppsc->dot11_psmode != EACTIVE) { @@ -493,7 +485,7 @@ void rtl_lps_leave(struct ieee80211_hw *hw) rtl_lps_set_psmode(hw, EACTIVE); } } - spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + spin_unlock(&rtlpriv->locks.lps_lock); } /* For sw LPS*/ @@ -582,7 +574,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - unsigned long flag; if (!rtlpriv->psc.swctrl_lps) return; @@ -595,9 +586,9 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } - spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + spin_lock(&rtlpriv->locks.lps_lock); rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); - spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + spin_unlock(&rtlpriv->locks.lps_lock); } void rtl_swlps_rfon_wq_callback(void *data) @@ -614,7 +605,6 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - unsigned long flag; u8 sleep_intv; if (!rtlpriv->psc.sw_ps_enabled) @@ -631,16 +621,16 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) if (rtlpriv->link_info.busytraffic) return; - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + spin_lock(&rtlpriv->locks.rf_ps_lock); if (rtlpriv->psc.rfchange_inprogress) { - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + spin_unlock(&rtlpriv->locks.rf_ps_lock); return; } - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + spin_unlock(&rtlpriv->locks.rf_ps_lock); - spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + spin_lock(&rtlpriv->locks.lps_lock); rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false); - spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + spin_unlock(&rtlpriv->locks.lps_lock); if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index 8f6718f163e5..9fedb1f70919 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -303,22 +303,6 @@ static void _rtl_reg_apply_world_flags(struct wiphy *wiphy, return; } -static void _rtl_dump_channel_map(struct wiphy *wiphy) -{ - enum ieee80211_band band; - struct ieee80211_supported_band *sband; - struct ieee80211_channel *ch; - unsigned int i; - - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - if (!wiphy->bands[band]) - continue; - sband = wiphy->bands[band]; - for (i = 0; i < sband->n_channels; i++) - ch = &sband->channels[i]; - } -} - static int _rtl_reg_notifier_apply(struct wiphy *wiphy, struct regulatory_request *request, struct rtl_regulatory *reg) @@ -336,8 +320,6 @@ static int _rtl_reg_notifier_apply(struct wiphy *wiphy, break; } - _rtl_dump_channel_map(wiphy); - return 0; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 50303e1adff1..f9f2370e9256 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -546,7 +546,6 @@ static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; - u8 own; unsigned long flags; struct sk_buff *pskb = NULL; @@ -559,7 +558,6 @@ static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); pdesc = &ring->desc[0]; - own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index d2cc81586a6a..3b11642d3f7d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -1253,10 +1253,9 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, const u32 retrycount = 2; - u32 bbvalue; - if (t == 0) { - bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD); + /* dummy read */ + rtl_get_bbreg(hw, 0x800, MASKDWORD); _rtl92c_phy_save_adda_registers(hw, adda_reg, rtlphy->adda_backup, 16); @@ -1762,8 +1761,7 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) long result[4][8]; u8 i, final_candidate; bool patha_ok, pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, - reg_ecc, reg_tmp = 0; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4, reg_tmp = 0; bool is12simular, is13simular, is23simular; bool start_conttx = false, singletone = false; u32 iqk_bb_reg[10] = { @@ -1841,21 +1839,17 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; patha_ok = pathb_ok = true; } else { rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index defb4370cf74..944f55e9d316 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -763,11 +763,9 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); u8 reg_bw_opmode; - u32 reg_ratr, reg_prsr; + u32 reg_prsr; reg_bw_opmode = BW_OPMODE_20MHZ; - reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | - RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); @@ -1196,6 +1194,7 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); rtlpci->irq_enabled = false; + synchronize_irq(rtlpci->pdev->irq); } static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) @@ -1969,7 +1968,7 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; + enum rf_pwrstate e_rfpowerstate_toset; u8 u1tmp; bool actuallyset = false; unsigned long flag; @@ -1989,8 +1988,6 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); } - cur_rfstate = ppsc->rfpwr_state; - rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG)&~(BIT(3))); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index abe0fcc75368..592a10ac5929 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -46,13 +46,12 @@ u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; struct rtl_phy *rtlphy = &(rtlpriv->phy); - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " "rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, bitmask)); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (rtlphy->rf_mode != RF_OP_BY_FW) { original_value = _rtl92c_phy_rf_serial_read(hw, @@ -65,7 +64,7 @@ u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " @@ -120,13 +119,12 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); u32 original_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (rtlphy->rf_mode != RF_OP_BY_FW) { if (bitmask != RFREG_OFFSET_MASK) { @@ -153,7 +151,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, _rtl92c_phy_fw_rf_serial_write(hw, rfpath, regaddr, data); } - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " "bitmask(%#x), data(%#x), " @@ -281,7 +279,6 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, { int i; - bool rtstatus = true; u32 *radioa_array_table; u32 *radiob_array_table; u16 radioa_arraylen, radiob_arraylen; @@ -308,7 +305,6 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, ("Radio_B:RTL8192CE_RADIOB_1TARRAY\n")); } RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Radio No %x\n", rfpath)); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { @@ -521,7 +517,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, u8 i, queue_id; struct rtl8192_tx_ring *ring = NULL; - ppsc->set_rfpowerstate_inprogress = true; switch (rfpwr_state) { case ERFON:{ if ((ppsc->rfpwr_state == ERFOFF) && @@ -617,7 +612,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, } if (bresult) ppsc->rfpwr_state = rfpwr_state; - ppsc->set_rfpowerstate_inprogress = false; return bresult; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 54b2bd53d36a..2492cc234c03 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -592,7 +592,6 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr; u8 *tmp_buf; u8 *praddr; - u8 *psaddr; __le16 fc; u16 type, c_fc; bool packet_matchbssid, packet_toself, packet_beacon; @@ -604,7 +603,6 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, c_fc = le16_to_cpu(fc); type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; - psaddr = hdr->addr2; packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && @@ -932,6 +930,7 @@ void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) if (istx == true) { switch (desc_name) { case HW_DESC_OWN: + wmb(); SET_TX_DESC_OWN(pdesc, 1); break; case HW_DESC_TX_NEXTDESC_ADDR: @@ -945,6 +944,7 @@ void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) } else { switch (desc_name) { case HW_DESC_RXOWN: + wmb(); SET_RX_DESC_OWN(pdesc, 1); break; case HW_DESC_RXBUFF_ADDR: diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index f8514cba17b6..4e057df6f488 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -1113,7 +1113,6 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr; u8 *tmp_buf; u8 *praddr; - u8 *psaddr; __le16 fc; u16 type, cpu_fc; bool packet_matchbssid, packet_toself, packet_beacon; @@ -1124,7 +1123,6 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, cpu_fc = le16_to_cpu(fc); type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; - psaddr = hdr->addr2; packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && (!compare_ether_addr(mac->bssid, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 9a3d0239e27e..72852900df84 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -470,7 +470,6 @@ static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, u8 i, queue_id; struct rtl8192_tx_ring *ring = NULL; - ppsc->set_rfpowerstate_inprogress = true; switch (rfpwr_state) { case ERFON: if ((ppsc->rfpwr_state == ERFOFF) && @@ -590,7 +589,6 @@ static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, } if (bresult) ppsc->rfpwr_state = rfpwr_state; - ppsc->set_rfpowerstate_inprogress = false; return bresult; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index da86db86fa4a..609c7ec7e66a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -222,7 +222,6 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw) u32 low_rssi_thresh = 0; u32 middle_rssi_thresh = 0; u32 high_rssi_thresh = 0; - u8 rssi_level; struct ieee80211_sta *sta = NULL; if (is_hal_stop(rtlhal)) @@ -272,18 +271,14 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw) if (rtlpriv->dm.undecorated_smoothed_pwdb > (long)high_rssi_thresh) { ra->ratr_state = DM_RATR_STA_HIGH; - rssi_level = 1; } else if (rtlpriv->dm.undecorated_smoothed_pwdb > (long)middle_rssi_thresh) { ra->ratr_state = DM_RATR_STA_LOW; - rssi_level = 3; } else if (rtlpriv->dm.undecorated_smoothed_pwdb > (long)low_rssi_thresh) { ra->ratr_state = DM_RATR_STA_LOW; - rssi_level = 5; } else { ra->ratr_state = DM_RATR_STA_ULTRALOW; - rssi_level = 6; } if (ra->pre_ratr_state != ra->ratr_state) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c index 3b5af0113d7f..6f91a148c222 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -358,7 +358,6 @@ int rtl92s_download_fw(struct ieee80211_hw *hw) struct fw_priv *pfw_priv = NULL; u8 *puc_mappedfile = NULL; u32 ul_filelength = 0; - u32 file_length = 0; u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE; u8 fwstatus = FW_STATUS_INIT; bool rtstatus = true; @@ -370,7 +369,6 @@ int rtl92s_download_fw(struct ieee80211_hw *hw) firmware->fwstatus = FW_STATUS_INIT; puc_mappedfile = firmware->sz_fw_tmpbuffer; - file_length = firmware->sz_fw_tmpbufferlen; /* 1. Retrieve FW header. */ firmware->pfwheader = (struct fw_hdr *) puc_mappedfile; diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 2e9005d0454b..35dd12d0dcf3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -884,12 +884,10 @@ static void _rtl92se_hw_configure(struct ieee80211_hw *hw) struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 reg_bw_opmode = 0; - u32 reg_ratr = 0, reg_rrsr = 0; + u32 reg_rrsr = 0; u8 regtmp = 0; reg_bw_opmode = BW_OPMODE_20MHZ; - reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | - RATE_ALL_OFDM_2SS; reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL); @@ -1122,14 +1120,12 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 bt_msr = rtl_read_byte(rtlpriv, MSR); - enum led_ctl_mode ledaction = LED_CTL_NO_LINK; u32 temp; bt_msr &= ~MSR_LINK_MASK; switch (type) { case NL80211_IFTYPE_UNSPECIFIED: bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); - ledaction = LED_CTL_LINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Set Network type to NO LINK!\n")); break; @@ -1140,7 +1136,6 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw, break; case NL80211_IFTYPE_STATION: bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT); - ledaction = LED_CTL_LINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Set Network type to STA!\n")); break; @@ -1231,6 +1226,7 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); rtlpci->irq_enabled = false; + synchronize_irq(rtlpci->pdev->irq); } @@ -2271,7 +2267,7 @@ bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - enum rf_pwrstate rfpwr_toset, cur_rfstate; + enum rf_pwrstate rfpwr_toset /*, cur_rfstate */; unsigned long flag = 0; bool actuallyset = false; bool turnonbypowerdomain = false; @@ -2292,7 +2288,7 @@ bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); } - cur_rfstate = ppsc->rfpwr_state; + /* cur_rfstate = ppsc->rfpwr_state;*/ /* because after _rtl92s_phy_set_rfhalt, all power * closed, so we must open some power for GPIO check, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index 63b45e60a95e..7ee2daccd7d5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -180,19 +180,18 @@ u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " "bitmask(%#x)\n", regaddr, rfpath, bitmask)); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr); bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " "bitmask(%#x), original_value(%#x)\n", regaddr, rfpath, @@ -207,7 +206,6 @@ void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); u32 original_value, bitshift; - unsigned long flags; if (!((rtlphy->rf_pathmap >> rfpath) & 0x1)) return; @@ -215,7 +213,7 @@ void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," " data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (bitmask != RFREG_OFFSET_MASK) { original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, @@ -226,7 +224,7 @@ void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data); - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), " "data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); @@ -263,7 +261,6 @@ void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); u8 reg_bw_opmode; - u8 reg_prsr_rsc; RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("Switch to %s bandwidth\n", rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? @@ -277,7 +274,8 @@ void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, rtlphy->set_bwmode_inprogress = true; reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE); - reg_prsr_rsc = rtl_read_byte(rtlpriv, RRSR + 2); + /* dummy read */ + rtl_read_byte(rtlpriv, RRSR + 2); switch (rtlphy->current_chan_bw) { case HT_CHANNEL_WIDTH_20: @@ -546,8 +544,6 @@ bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, if (rfpwr_state == ppsc->rfpwr_state) return false; - ppsc->set_rfpowerstate_inprogress = true; - switch (rfpwr_state) { case ERFON:{ if ((ppsc->rfpwr_state == ERFOFF) && @@ -659,8 +655,6 @@ bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, if (bresult) ppsc->rfpwr_state = rfpwr_state; - ppsc->set_rfpowerstate_inprogress = false; - return bresult; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 5cf442373d46..d509cf6a1e4d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -581,7 +581,6 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr; u8 *tmp_buf; u8 *praddr; - u8 *psaddr; __le16 fc; u16 type, cfc; bool packet_matchbssid, packet_toself, packet_beacon; @@ -593,7 +592,6 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, cfc = le16_to_cpu(fc); type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; - psaddr = hdr->addr2; packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? @@ -875,6 +873,7 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + wmb(); SET_TX_DESC_OWN(pdesc, 1); } else { /* H2C Command Desc format (Host TXCMD) */ /* 92SE must set as 1 for firmware download HW DMA error */ @@ -893,6 +892,7 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + wmb(); SET_TX_DESC_OWN(pdesc, 1); } @@ -903,6 +903,7 @@ void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) if (istx == true) { switch (desc_name) { case HW_DESC_OWN: + wmb(); SET_TX_DESC_OWN(pdesc, 1); break; case HW_DESC_TX_NEXTDESC_ADDR: @@ -916,6 +917,7 @@ void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) } else { switch (desc_name) { case HW_DESC_RXOWN: + wmb(); SET_RX_STATUS_DESC_OWN(pdesc, 1); break; case HW_DESC_RXBUFF_ADDR: diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 693395ee98f9..9d003e0864f5 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1188,7 +1188,6 @@ struct rtl_efuse { struct rtl_ps_ctl { bool pwrdomain_protect; - bool set_rfpowerstate_inprogress; bool in_powersavemode; bool rfchange_inprogress; bool swrf_processing; @@ -1536,6 +1535,7 @@ struct rtl_works { /* For SW LPS */ struct delayed_work ps_work; struct delayed_work ps_rfon_wq; + struct tasklet_struct ips_leave_tasklet; }; struct rtl_debug { diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index b07f8b7e5f11..7ccec07a600c 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -485,7 +485,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; else - wl->event_mask |= DUMMY_PACKET_EVENT_ID; + wl->event_mask |= DUMMY_PACKET_EVENT_ID | + BA_SESSION_RX_CONSTRAINT_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index c3c554cd6580..94bbd00ec31b 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -168,6 +168,21 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl, wl->last_rssi_event = event; } +static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed) +{ + /* Convert the value to bool */ + wl->ba_allowed = !!ba_allowed; + + /* + * Return in case: + * there are not BA open or the event indication is to allowed BA + */ + if ((!wl->ba_rx_bitmap) || (wl->ba_allowed)) + return; + + ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid); +} + static void wl1271_event_mbox_dump(struct event_mailbox *mbox) { wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); @@ -252,6 +267,14 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_rssi_trigger(wl, mbox); } + if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) { + wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " + "ba_allowed = 0x%x", mbox->ba_allowed); + + if (wl->vif) + wl1271_stop_ba_event(wl, mbox->ba_allowed); + } + if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index b6cf06e565a4..ce99adf4256e 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -71,7 +71,7 @@ enum { HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), - BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30), + BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, }; @@ -122,7 +122,20 @@ struct event_mailbox { __le16 sta_aging_status; __le16 sta_tx_retry_exceeded; - u8 reserved_5[24]; + /* + * Bitmap, Each bit set represents the Role ID for which this constraint + * is set. Range: 0 - FF, FF means ANY role + */ + u8 ba_role_id; + /* + * Bitmap, Each bit set represents the Link ID for which this constraint + * is set. Not applicable if ba_role_id is set to ANY role (FF). + * Range: 0 - FFFF, FFFF means ANY link in that role + */ + u8 ba_link_id; + u8 ba_allowed; + + u8 reserved_5[21]; } __packed; int wl1271_event_unmask(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index a8f4f156c055..f5c2c9e6f84b 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -541,6 +541,7 @@ static int wl1271_set_ba_policies(struct wl1271 *wl) /* Reset the BA RX indicators */ wl->ba_rx_bitmap = 0; + wl->ba_allowed = true; /* validate that FW support BA */ wl1271_check_ba_support(wl); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e6497dc669df..f37f0b873c73 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3354,9 +3354,12 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, if (ret < 0) goto out; + wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d", + tid, action); + switch (action) { case IEEE80211_AMPDU_RX_START: - if (wl->ba_support) { + if ((wl->ba_support) && (wl->ba_allowed)) { ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn, true); if (!ret) diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index fbe8f46d1232..3bc794a1ee75 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -564,6 +564,7 @@ struct wl1271 { /* RX BA constraint value */ bool ba_support; u8 ba_rx_bitmap; + bool ba_allowed; int tcxo_clock; diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 82feb348c8bb..2a20dabec76d 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -539,10 +539,12 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); - /* Additional always once-executed workarounds */ - ssb_pcicore_serdes_workaround(pc); - /* TODO: ASPM */ - /* TODO: Clock Request Update */ + /* Additional PCIe always once-executed workarounds */ + if (dev->id.coreid == SSB_DEV_PCIE) { + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ + } } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 08763e4e848f..6ff080eac0b2 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -6,6 +6,7 @@ #include <linux/bcma/bcma_driver_chipcommon.h> #include <linux/bcma/bcma_driver_pci.h> +#include <linux/ssb/ssb.h> /* SPROM sharing */ #include "bcma_regs.h" @@ -31,6 +32,12 @@ struct bcma_host_ops { void (*write8)(struct bcma_device *core, u16 offset, u8 value); void (*write16)(struct bcma_device *core, u16 offset, u16 value); void (*write32)(struct bcma_device *core, u16 offset, u32 value); +#ifdef CONFIG_BCMA_BLOCKIO + void (*block_read)(struct bcma_device *core, void *buffer, + size_t count, u16 offset, u8 reg_width); + void (*block_write)(struct bcma_device *core, const void *buffer, + size_t count, u16 offset, u8 reg_width); +#endif /* Agent ops */ u32 (*aread32)(struct bcma_device *core, u16 offset); void (*awrite32)(struct bcma_device *core, u16 offset, u32 value); @@ -117,6 +124,8 @@ struct bcma_device { struct bcma_device_id id; struct device dev; + struct device *dma_dev; + unsigned int irq; bool dev_registered; u8 core_index; @@ -179,6 +188,10 @@ struct bcma_bus { struct bcma_drv_cc drv_cc; struct bcma_drv_pci drv_pci; + + /* We decided to share SPROM struct with SSB as long as we do not need + * any hacks for BCMA. This simplifies drivers code. */ + struct ssb_sprom sprom; }; extern inline u32 bcma_read8(struct bcma_device *core, u16 offset) @@ -208,6 +221,18 @@ void bcma_write32(struct bcma_device *core, u16 offset, u32 value) { core->bus->ops->write32(core, offset, value); } +#ifdef CONFIG_BCMA_BLOCKIO +extern inline void bcma_block_read(struct bcma_device *core, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + core->bus->ops->block_read(core, buffer, count, offset, reg_width); +} +extern inline void bcma_block_write(struct bcma_device *core, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + core->bus->ops->block_write(core, buffer, count, offset, reg_width); +} +#endif extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset) { return core->bus->ops->aread32(core, offset); diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 083c3b6cd5ce..9c5b69fc985a 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -244,6 +244,7 @@ #define BCMA_CC_REGCTL_DATA 0x065C #define BCMA_CC_PLLCTL_ADDR 0x0660 #define BCMA_CC_PLLCTL_DATA 0x0664 +#define BCMA_CC_SPROM 0x0830 /* SPROM beginning */ /* Data for the PMU, if available. * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) diff --git a/include/linux/cordic.h b/include/linux/cordic.h new file mode 100644 index 000000000000..f932093e20c2 --- /dev/null +++ b/include/linux/cordic.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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 __CORDIC_H_ +#define __CORDIC_H_ + +#include <linux/types.h> + +/** + * struct cordic_iq - i/q coordinate. + * + * @i: real part of coordinate (in phase). + * @q: imaginary part of coordinate (quadrature). + */ +struct cordic_iq { + s32 i; + s32 q; +}; + +/** + * cordic_calc_iq() - calculates the i/q coordinate for given angle. + * + * @theta: angle in degrees for which i/q coordinate is to be calculated. + * @coord: function output parameter holding the i/q coordinate. + * + * The function calculates the i/q coordinate for a given angle using + * cordic algorithm. The coordinate consists of a real (i) and an + * imaginary (q) part. The real part is essentially the cosine of the + * angle and the imaginary part is the sine of the angle. The returned + * values are scaled by 2^16 for precision. The range for theta is + * for -180 degrees to +180 degrees. Passed values outside this range are + * converted before doing the actual calculation. + */ +struct cordic_iq cordic_calc_iq(s32 theta); + +#endif /* __CORDIC_H_ */ diff --git a/include/linux/crc8.h b/include/linux/crc8.h new file mode 100644 index 000000000000..13c8dabb0441 --- /dev/null +++ b/include/linux/crc8.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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 __CRC8_H_ +#define __CRC8_H_ + +#include <linux/types.h> + +/* see usage of this value in crc8() description */ +#define CRC8_INIT_VALUE 0xFF + +/* + * Return value of crc8() indicating valid message+crc. This is true + * if a CRC is inverted before transmission. The CRC computed over the + * whole received bitstream is _table[x], where x is the bit pattern + * of the modification (almost always 0xff). + */ +#define CRC8_GOOD_VALUE(_table) (_table[0xFF]) + +/* required table size for crc8 algorithm */ +#define CRC8_TABLE_SIZE 256 + +/* helper macro assuring right table size is used */ +#define DECLARE_CRC8_TABLE(_table) \ + static u8 _table[CRC8_TABLE_SIZE] + +/** + * crc8_populate_lsb - fill crc table for given polynomial in regular bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + * + * This function fills the provided table according the polynomial provided for + * regular bit order (lsb first). Polynomials in CRC algorithms are typically + * represented as shown below. + * + * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1 + * + * For lsb first direction x^7 maps to the lsb. So the polynomial is as below. + * + * - lsb first: poly = 10101011(1) = 0xAB + */ +void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial); + +/** + * crc8_populate_msb - fill crc table for given polynomial in reverse bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + * + * This function fills the provided table according the polynomial provided for + * reverse bit order (msb first). Polynomials in CRC algorithms are typically + * represented as shown below. + * + * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1 + * + * For msb first direction x^7 maps to the msb. So the polynomial is as below. + * + * - msb first: poly = (1)11010101 = 0xD5 + */ +void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial); + +/** + * crc8() - calculate a crc8 over the given input data. + * + * @table: crc table used for calculation. + * @pdata: pointer to data buffer. + * @nbytes: number of bytes in data buffer. + * @crc: previous returned crc8 value. + * + * The CRC8 is calculated using the polynomial given in crc8_populate_msb() + * or crc8_populate_lsb(). + * + * The caller provides the initial value (either %CRC8_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When validating a byte + * stream (including CRC8), a final return value of %CRC8_GOOD_VALUE + * indicates the byte stream data can be considered valid. + * + * Reference: + * "A Painless Guide to CRC Error Detection Algorithms", ver 3, Aug 1993 + * Williams, Ross N., ross<at>ross.net + * (see URL http://www.ross.net/crc/download/crc_v3.txt). + */ +u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc); + +#endif /* __CRC8_H_ */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0589f554788a..6cb2543a2ee1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1284,6 +1284,12 @@ struct cfg80211_wowlan { * frame on another channel * * @testmode_cmd: run a test mode command + * @testmode_dump: Implement a test mode dump. The cb->args[2] and up may be + * used by the function, but 0 and 1 must not be touched. Additionally, + * return error codes other than -ENOBUFS and -ENOENT will terminate the + * dump and return to userspace with an error, so be careful. If any data + * was passed in from userspace then the data/len arguments will be present + * and point to the data contained in %NL80211_ATTR_TESTDATA. * * @set_bitrate_mask: set the bitrate mask configuration * @@ -1433,6 +1439,9 @@ struct cfg80211_ops { #ifdef CONFIG_NL80211_TESTMODE int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); + int (*testmode_dump)(struct wiphy *wiphy, struct sk_buff *skb, + struct netlink_callback *cb, + void *data, int len); #endif int (*set_bitrate_mask)(struct wiphy *wiphy, @@ -2849,8 +2858,10 @@ struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp); #define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd), +#define CFG80211_TESTMODE_DUMP(cmd) .testmode_dump = (cmd), #else #define CFG80211_TESTMODE_CMD(cmd) +#define CFG80211_TESTMODE_DUMP(cmd) #endif /** diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e6d6a66a8f71..3b31ec95dd8e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1816,6 +1816,7 @@ enum ieee80211_ampdu_mlme_action { * * @testmode_cmd: Implement a cfg80211 test mode command. * The callback can sleep. + * @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep. * * @flush: Flush all pending frames from the hardware queue, making sure * that the hardware queues are empty. If the parameter @drop is set @@ -1936,6 +1937,9 @@ struct ieee80211_ops { void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); #ifdef CONFIG_NL80211_TESTMODE int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); + int (*testmode_dump)(struct ieee80211_hw *hw, struct sk_buff *skb, + struct netlink_callback *cb, + void *data, int len); #endif void (*flush)(struct ieee80211_hw *hw, bool drop); void (*channel_switch)(struct ieee80211_hw *hw, @@ -2965,6 +2969,23 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw); */ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw); +/** + * ieee80211_stop_rx_ba_session - callback to stop existing BA sessions + * + * in order not to harm the system performance and user experience, the device + * may request not to allow any rx ba session and tear down existing rx ba + * sessions based on system constraints such as periodic BT activity that needs + * to limit wlan activity (eg.sco or a2dp)." + * in such cases, the intention is to limit the duration of the rx ppdu and + * therefore prevent the peer device to use a-mpdu aggregation. + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @ba_rx_bitmap: Bit map of open rx ba per tid + * @addr: & to bssid mac address + */ +void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, + const u8 *addr); + /* Rate control API */ /** diff --git a/lib/Kconfig b/lib/Kconfig index 830181cc7a83..32f3e5ae2be5 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -79,6 +79,13 @@ config LIBCRC32C require M here. See Castagnoli93. Module will be libcrc32c. +config CRC8 + tristate "CRC8 function" + help + This option provides CRC8 function. Drivers may select this + when they need to do cyclic redundancy check according CRC8 + algorithm. Module will be called crc8. + config AUDIT_GENERIC bool depends on AUDIT && !AUDIT_ARCH @@ -262,4 +269,11 @@ config AVERAGE If unsure, say N. +config CORDIC + tristate "Cordic function" + help + The option provides arithmetic function using cordic algorithm + so its calculations are in fixed point. Modules can select this + when they require this function. Module will be called cordic. + endmenu diff --git a/lib/Makefile b/lib/Makefile index 6b597fdb1898..892f4e282ea1 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_CRC7) += crc7.o obj-$(CONFIG_LIBCRC32C) += libcrc32c.o +obj-$(CONFIG_CRC8) += crc8.o obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ @@ -112,6 +113,8 @@ obj-$(CONFIG_AVERAGE) += average.o obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o +obj-$(CONFIG_CORDIC) += cordic.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/cordic.c b/lib/cordic.c new file mode 100644 index 000000000000..aa27a88d7e04 --- /dev/null +++ b/lib/cordic.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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. + */ +#include <linux/module.h> +#include <linux/cordic.h> + +#define CORDIC_ANGLE_GEN 39797 +#define CORDIC_PRECISION_SHIFT 16 +#define CORDIC_NUM_ITER (CORDIC_PRECISION_SHIFT + 2) + +#define FIXED(X) ((s32)((X) << CORDIC_PRECISION_SHIFT)) +#define FLOAT(X) (((X) >= 0) \ + ? ((((X) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1) \ + : -((((-(X)) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1)) + +static const s32 arctan_table[] = { + 2949120, + 1740967, + 919879, + 466945, + 234379, + 117304, + 58666, + 29335, + 14668, + 7334, + 3667, + 1833, + 917, + 458, + 229, + 115, + 57, + 29 +}; + +/* + * cordic_calc_iq() - calculates the i/q coordinate for given angle + * + * theta: angle in degrees for which i/q coordinate is to be calculated + * coord: function output parameter holding the i/q coordinate + */ +struct cordic_iq cordic_calc_iq(s32 theta) +{ + struct cordic_iq coord; + s32 angle, valtmp; + unsigned iter; + int signx = 1; + int signtheta; + + coord.i = CORDIC_ANGLE_GEN; + coord.q = 0; + angle = 0; + + theta = FIXED(theta); + signtheta = (theta < 0) ? -1 : 1; + theta = ((theta + FIXED(180) * signtheta) % FIXED(360)) - + FIXED(180) * signtheta; + + if (FLOAT(theta) > 90) { + theta -= FIXED(180); + signx = -1; + } else if (FLOAT(theta) < -90) { + theta += FIXED(180); + signx = -1; + } + + for (iter = 0; iter < CORDIC_NUM_ITER; iter++) { + if (theta > angle) { + valtmp = coord.i - (coord.q >> iter); + coord.q += (coord.i >> iter); + angle += arctan_table[iter]; + } else { + valtmp = coord.i + (coord.q >> iter); + coord.q -= (coord.i >> iter); + angle -= arctan_table[iter]; + } + coord.i = valtmp; + } + + coord.i *= signx; + coord.q *= signx; + return coord; +} +EXPORT_SYMBOL(cordic_calc_iq); + +MODULE_DESCRIPTION("Cordic functions"); +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/lib/crc8.c b/lib/crc8.c new file mode 100644 index 000000000000..87b59cafdb83 --- /dev/null +++ b/lib/crc8.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/crc8.h> +#include <linux/printk.h> + +/* + * crc8_populate_msb - fill crc table for given polynomial in reverse bit order. + * + * table: table to be filled. + * polynomial: polynomial for which table is to be filled. + */ +void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial) +{ + int i, j; + const u8 msbit = 0x80; + u8 t = msbit; + + table[0] = 0; + + for (i = 1; i < CRC8_TABLE_SIZE; i *= 2) { + t = (t << 1) ^ (t & msbit ? polynomial : 0); + for (j = 0; j < i; j++) + table[i+j] = table[j] ^ t; + } +} +EXPORT_SYMBOL(crc8_populate_msb); + +/* + * crc8_populate_lsb - fill crc table for given polynomial in regular bit order. + * + * table: table to be filled. + * polynomial: polynomial for which table is to be filled. + */ +void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial) +{ + int i, j; + u8 t = 1; + + table[0] = 0; + + for (i = (CRC8_TABLE_SIZE >> 1); i; i >>= 1) { + t = (t >> 1) ^ (t & 1 ? polynomial : 0); + for (j = 0; j < CRC8_TABLE_SIZE; j += 2*i) + table[i+j] = table[j] ^ t; + } +} +EXPORT_SYMBOL(crc8_populate_lsb); + +/* + * crc8 - calculate a crc8 over the given input data. + * + * table: crc table used for calculation. + * pdata: pointer to data buffer. + * nbytes: number of bytes in data buffer. + * crc: previous returned crc8 value. + */ +u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc) +{ + /* loop over the buffer data */ + while (nbytes-- > 0) + crc = table[(crc ^ *pdata++) & 0xff]; + + return crc; +} +EXPORT_SYMBOL(crc8); + +MODULE_DESCRIPTION("CRC8 (by Williams, Ross N.) function"); +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 9c0d76cdca92..89b0b2ca6db6 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -100,6 +100,21 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, mutex_unlock(&sta->ampdu_mlme.mtx); } +void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, + const u8 *addr) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct sta_info *sta = sta_info_get(sdata, addr); + int i; + + for (i = 0; i < STA_TID_NUM; i++) + if (ba_rx_bitmap & BIT(i)) + set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); + + ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); +} +EXPORT_SYMBOL(ieee80211_stop_rx_ba_session); + /* * After accepting the AddBA Request we activated a timer, * resetting it after each frame that arrives from the originator. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index be70c70d3f5b..6e56c6ee7ccd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1554,6 +1554,19 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) return local->ops->testmode_cmd(&local->hw, data, len); } + +static int ieee80211_testmode_dump(struct wiphy *wiphy, + struct sk_buff *skb, + struct netlink_callback *cb, + void *data, int len) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + if (!local->ops->testmode_dump) + return -EOPNOTSUPP; + + return local->ops->testmode_dump(&local->hw, skb, cb, data, len); +} #endif int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, @@ -2134,6 +2147,7 @@ struct cfg80211_ops mac80211_config_ops = { .set_wds_peer = ieee80211_set_wds_peer, .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) + CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump) .set_power_mgmt = ieee80211_set_power_mgmt, .set_bitrate_mask = ieee80211_set_bitrate_mask, .remain_on_channel = ieee80211_remain_on_channel, diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 591add22bcc0..7cfc286946c0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -140,6 +140,12 @@ void ieee80211_ba_session_work(struct work_struct *work) sta, tid, WLAN_BACK_RECIPIENT, WLAN_REASON_QSTA_TIMEOUT, true); + if (test_and_clear_bit(tid, + sta->ampdu_mlme.tid_rx_stop_requested)) + ___ieee80211_stop_rx_ba_session( + sta, tid, WLAN_BACK_RECIPIENT, + WLAN_REASON_UNSPECIFIED, true); + tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; if (tid_tx) { /* diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2025af52b195..090b0ec1e056 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -775,9 +775,6 @@ struct ieee80211_local { int tx_headroom; /* required headroom for hardware/radiotap */ - /* count for keys needing tailroom space allocation */ - int crypto_tx_tailroom_needed_cnt; - /* Tasklet and skb queue to process calls from IRQ mode. All frames * added to skb_queue will be processed, but frames in * skb_queue_unreliable may be dropped if the total length of these diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 49d4f869e0bc..dee30aea9ab3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1145,6 +1145,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, + IEEE80211_ENCRYPT_HEADROOM; ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; + ret = dev_alloc_name(ndev, ndev->name); + if (ret < 0) + goto fail; + ieee80211_assign_perm_addr(local, ndev, type); memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 31afd712930d..f825e2f0a57e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -101,11 +101,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; - - if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || - (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) - key->local->crypto_tx_tailroom_needed_cnt--; - return 0; } @@ -161,10 +156,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - - if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || - (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) - key->local->crypto_tx_tailroom_needed_cnt++; } void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) @@ -403,10 +394,8 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) ieee80211_aes_key_free(key->u.ccmp.tfm); if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); - if (key->local) { + if (key->local) ieee80211_debugfs_key_remove(key); - key->local->crypto_tx_tailroom_needed_cnt--; - } kfree(key); } @@ -468,8 +457,6 @@ int ieee80211_key_link(struct ieee80211_key *key, ieee80211_debugfs_key_add(key); - key->local->crypto_tx_tailroom_needed_cnt++; - ret = ieee80211_key_enable_hw_accel(key); mutex_unlock(&sdata->local->key_mtx); @@ -511,12 +498,8 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->local->key_mtx); - sdata->local->crypto_tx_tailroom_needed_cnt = 0; - - list_for_each_entry(key, &sdata->key_list, list) { - sdata->local->crypto_tx_tailroom_needed_cnt++; + list_for_each_entry(key, &sdata->key_list, list) ieee80211_key_enable_hw_accel(key); - } mutex_unlock(&sdata->local->key_mtx); } diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 8adac67395f7..58a89554b788 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -532,12 +532,21 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) mp->hw = hw; mp->update_interval = 100; +#ifdef CONFIG_MAC80211_DEBUGFS + mp->fixed_rate_idx = (u32) -1; + mp->dbg_fixed_rate = debugfs_create_u32("fixed_rate_idx", + S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); +#endif + return mp; } static void minstrel_free(void *priv) { +#ifdef CONFIG_MAC80211_DEBUGFS + debugfs_remove(((struct minstrel_priv *)priv)->dbg_fixed_rate); +#endif kfree(priv); } diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 0f5a83370aa6..5d278eccaef0 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -78,6 +78,18 @@ struct minstrel_priv { unsigned int update_interval; unsigned int lookaround_rate; unsigned int lookaround_rate_mrr; + +#ifdef CONFIG_MAC80211_DEBUGFS + /* + * enable fixed rate processing per RC + * - write static index to debugfs:ieee80211/phyX/rc/fixed_rate_idx + * - write -1 to enable RC processing again + * - setting will be applied on next update + */ + u32 fixed_rate_idx; + struct dentry *dbg_fixed_rate; +#endif + }; struct minstrel_debugfs_info { diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 333b5118be6d..66a1eeb279c6 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -609,6 +609,13 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, info->flags |= mi->tx_flags; sample_idx = minstrel_get_sample_rate(mp, mi); + +#ifdef CONFIG_MAC80211_DEBUGFS + /* use fixed index if set */ + if (mp->fixed_rate_idx != -1) + sample_idx = mp->fixed_rate_idx; +#endif + if (sample_idx >= 0) { sample = true; minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c6ae8718bd57..a06d64ebc177 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -158,6 +158,8 @@ struct tid_ampdu_rx { * @work: work struct for starting/stopping aggregation * @tid_rx_timer_expired: bitmap indicating on which TIDs the * RX timer expired until the work for it runs + * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the + * driver requested to close until the work for it runs * @mtx: mutex to protect all TX data (except non-NULL assignments * to tid_tx[idx], which are protected by the sta spinlock) */ @@ -166,6 +168,7 @@ struct sta_ampdu_mlme { /* rx */ struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; + unsigned long tid_rx_stop_requested[BITS_TO_LONGS(STA_TID_NUM)]; /* tx */ struct work_struct work; struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 64e0f7587e6d..3104c844b544 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1480,7 +1480,12 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, { int tail_need = 0; - if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) { + /* + * This could be optimised, devices that do full hardware + * crypto (including TKIP MMIC) need no tailroom... But we + * have no drivers for such devices currently. + */ + if (may_encrypt) { tail_need = IEEE80211_ENCRYPT_TAILROOM; tail_need -= skb_tailroom(skb); tail_need = max_t(int, tail_need, 0); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 88a565f130a5..70cbc8ca371e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3754,10 +3754,6 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, void *hdr; struct nlattr *infoattr; - /* Survey without a channel doesn't make sense */ - if (!survey->channel) - return -EINVAL; - hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_SURVEY_RESULTS); if (!hdr) @@ -3820,6 +3816,8 @@ static int nl80211_dump_survey(struct sk_buff *skb, } while (1) { + struct ieee80211_channel *chan; + res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, &survey); if (res == -ENOENT) @@ -3827,6 +3825,19 @@ static int nl80211_dump_survey(struct sk_buff *skb, if (res) goto out_err; + /* Survey without a channel doesn't make sense */ + if (!survey.channel) { + res = -EINVAL; + goto out; + } + + chan = ieee80211_get_channel(&dev->wiphy, + survey.channel->center_freq); + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { + survey_idx++; + continue; + } + if (nl80211_send_survey(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, @@ -4361,6 +4372,93 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_testmode_dump(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct cfg80211_registered_device *dev; + int err; + long phy_idx; + void *data = NULL; + int data_len = 0; + + if (cb->args[0]) { + /* + * 0 is a valid index, but not valid for args[0], + * so we need to offset by 1. + */ + phy_idx = cb->args[0] - 1; + } else { + err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, + nl80211_fam.attrbuf, nl80211_fam.maxattr, + nl80211_policy); + if (err) + return err; + if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) + return -EINVAL; + phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); + if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) + cb->args[1] = + (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; + } + + if (cb->args[1]) { + data = nla_data((void *)cb->args[1]); + data_len = nla_len((void *)cb->args[1]); + } + + mutex_lock(&cfg80211_mutex); + dev = cfg80211_rdev_by_wiphy_idx(phy_idx); + if (!dev) { + mutex_unlock(&cfg80211_mutex); + return -ENOENT; + } + cfg80211_lock_rdev(dev); + mutex_unlock(&cfg80211_mutex); + + if (!dev->ops->testmode_dump) { + err = -EOPNOTSUPP; + goto out_err; + } + + while (1) { + void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + NL80211_CMD_TESTMODE); + struct nlattr *tmdata; + + if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) { + genlmsg_cancel(skb, hdr); + break; + } + + tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA); + if (!tmdata) { + genlmsg_cancel(skb, hdr); + break; + } + err = dev->ops->testmode_dump(&dev->wiphy, skb, cb, + data, data_len); + nla_nest_end(skb, tmdata); + + if (err == -ENOBUFS || err == -ENOENT) { + genlmsg_cancel(skb, hdr); + break; + } else if (err) { + genlmsg_cancel(skb, hdr); + goto out_err; + } + + genlmsg_end(skb, hdr); + } + + err = skb->len; + /* see above */ + cb->args[0] = phy_idx + 1; + out_err: + cfg80211_unlock_rdev(dev); + return err; +} + static struct sk_buff * __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, int approxlen, u32 pid, u32 seq, gfp_t gfp) @@ -5658,6 +5756,7 @@ static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_TESTMODE, .doit = nl80211_testmode_do, + .dumpit = nl80211_testmode_dump, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .internal_flags = NL80211_FLAG_NEED_WIPHY | |