1
0
Fork 0

Merge tag 'master-2014-09-16' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next

John W. Linville says:

====================
pull request: wireless-next 2014-09-22

Please pull this batch of updates intended for the 3.18 stream...

For the mac80211 bits, Johannes says:

"This time, I have some rate minstrel improvements, support for a very
small feature from CCX that Steinar reverse-engineered, dynamic ACK
timeout support, a number of changes for TDLS, early support for radio
resource measurement and many fixes. Also, I'm changing a number of
places to clear key memory when it's freed and Intel claims copyright
for code they developed."

For the bluetooth bits, Johan says:

"Here are some more patches intended for 3.18. Most of them are cleanups
or fixes for SMP. The only exception is a fix for BR/EDR L2CAP fixed
channels which should now work better together with the L2CAP
information request procedure."

For the iwlwifi bits, Emmanuel says:

"I fix here dvm which was broken by my last pull request. Arik
continues to work on TDLS and Luca solved a few issues in CT-Kill. Eyal
keeps digging into rate scaling code, more to come soon. Besides this,
nothing really special here."

Beyond that, there are the usual big batches of updates to ath9k, b43,
mwifiex, and wil6210 as well as a handful of other bits here and there.
Also, rtlwifi gets some btcoexist attention from Larry.

Please let me know if there are problems!
====================

Had to adjust the wil6210 code to comply with Joe Perches's recent
change in net-next to make the netdev_*() routines return void instead
of 'int'.

Signed-off-by: David S. Miller <davem@davemloft.net>
wifi-calibration
David S. Miller 2014-09-26 15:19:05 -04:00
commit 57219dc7bf
208 changed files with 20673 additions and 2385 deletions

View File

@ -210,6 +210,10 @@ static void __init bcm47xx_register_bcma(void)
pr_warn("bcm47xx: someone else already registered a bcma SPROM callback handler (err %d)\n", err);
err = bcma_host_soc_register(&bcm47xx_bus.bcma);
if (err)
panic("Failed to register BCMA bus (err %d)", err);
err = bcma_host_soc_init(&bcm47xx_bus.bcma);
if (err)
panic("Failed to initialize BCMA bus (err %d)", err);

View File

@ -1,5 +1,6 @@
bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_chipcommon_b.o
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
bcma-y += driver_pci.o

View File

@ -50,6 +50,10 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
extern struct platform_device bcma_pflash_dev;
#endif /* CONFIG_BCMA_DRIVER_MIPS */
/* driver_chipcommon_b.c */
int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
/* driver_chipcommon_pmu.c */
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);

View File

@ -0,0 +1,61 @@
/*
* Broadcom specific AMBA
* ChipCommon B Unit driver
*
* Copyright 2014, Hauke Mehrtens <hauke@hauke-m.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include "bcma_private.h"
#include <linux/export.h>
#include <linux/bcma/bcma.h>
static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask,
u32 value, int timeout)
{
unsigned long deadline = jiffies + timeout;
u32 val;
do {
val = readl(addr);
if ((val & mask) == value)
return true;
cpu_relax();
udelay(10);
} while (!time_after_eq(jiffies, deadline));
bcma_err(bus, "Timeout waiting for register %p\n", addr);
return false;
}
void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
{
struct bcma_bus *bus = ccb->core->bus;
writel(offset, ccb->mii + 0x00);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
writel(value, ccb->mii + 0x04);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
}
EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);
int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb)
{
if (ccb->setup_done)
return 0;
ccb->setup_done = 1;
ccb->mii = ioremap_nocache(ccb->core->addr_s[1], BCMA_CORE_SIZE);
if (!ccb->mii)
return -ENOMEM;
return 0;
}
void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb)
{
if (ccb->mii)
iounmap(ccb->mii);
}

View File

@ -208,6 +208,9 @@ static int bcma_host_pci_probe(struct pci_dev *dev,
bus->boardinfo.vendor = bus->host_pci->subsystem_vendor;
bus->boardinfo.type = bus->host_pci->subsystem_device;
/* Initialize struct, detect chip */
bcma_init_bus(bus);
/* Register */
err = bcma_bus_register(bus);
if (err)

View File

@ -165,7 +165,6 @@ static const struct bcma_host_ops bcma_host_soc_ops = {
int __init bcma_host_soc_register(struct bcma_soc *soc)
{
struct bcma_bus *bus = &soc->bus;
int err;
/* iomap only first core. We have to read some register on this core
* to scan the bus.
@ -178,7 +177,18 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
bus->hosttype = BCMA_HOSTTYPE_SOC;
bus->ops = &bcma_host_soc_ops;
/* Register */
/* Initialize struct, detect chip */
bcma_init_bus(bus);
return 0;
}
int __init bcma_host_soc_init(struct bcma_soc *soc)
{
struct bcma_bus *bus = &soc->bus;
int err;
/* Scan bus and initialize it */
err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
if (err)
iounmap(bus->mmio);

View File

@ -120,16 +120,60 @@ static void bcma_release_core_dev(struct device *dev)
kfree(core);
}
static int bcma_register_cores(struct bcma_bus *bus)
static bool bcma_is_core_needed_early(u16 core_id)
{
switch (core_id) {
case BCMA_CORE_NS_NAND:
case BCMA_CORE_NS_QSPI:
return true;
}
return false;
}
static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
{
int err;
core->dev.release = bcma_release_core_dev;
core->dev.bus = &bcma_bus_type;
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
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_SOC:
core->dev.dma_mask = &core->dev.coherent_dma_mask;
core->dma_dev = &core->dev;
break;
case BCMA_HOSTTYPE_SDIO:
break;
}
err = device_register(&core->dev);
if (err) {
bcma_err(bus, "Could not register dev for core 0x%03X\n",
core->id.id);
put_device(&core->dev);
return;
}
core->dev_registered = true;
}
static int bcma_register_devices(struct bcma_bus *bus)
{
struct bcma_device *core;
int err, dev_id = 0;
int err;
list_for_each_entry(core, &bus->cores, list) {
/* We support that cores ourself */
switch (core->id.id) {
case BCMA_CORE_4706_CHIPCOMMON:
case BCMA_CORE_CHIPCOMMON:
case BCMA_CORE_NS_CHIPCOMMON_B:
case BCMA_CORE_PCI:
case BCMA_CORE_PCIE:
case BCMA_CORE_PCIE2:
@ -138,39 +182,16 @@ static int bcma_register_cores(struct bcma_bus *bus)
continue;
}
/* Early cores were already registered */
if (bcma_is_core_needed_early(core->id.id))
continue;
/* Only first GMAC core on BCM4706 is connected and working */
if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
core->core_unit > 0)
continue;
core->dev.release = bcma_release_core_dev;
core->dev.bus = &bcma_bus_type;
dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
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_SOC:
core->dev.dma_mask = &core->dev.coherent_dma_mask;
core->dma_dev = &core->dev;
break;
case BCMA_HOSTTYPE_SDIO:
break;
}
err = device_register(&core->dev);
if (err) {
bcma_err(bus,
"Could not register dev for core 0x%03X\n",
core->id.id);
put_device(&core->dev);
continue;
}
core->dev_registered = true;
dev_id++;
bcma_register_core(bus, core);
}
#ifdef CONFIG_BCMA_DRIVER_MIPS
@ -247,6 +268,12 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_early_init(&bus->drv_cc);
}
/* Cores providing flash access go before SPROM init */
list_for_each_entry(core, &bus->cores, list) {
if (bcma_is_core_needed_early(core->id.id))
bcma_register_core(bus, core);
}
/* Try to get SPROM */
err = bcma_sprom_get(bus);
if (err == -ENOENT) {
@ -261,6 +288,13 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_init(&bus->drv_cc);
}
/* Init CC core */
core = bcma_find_core(bus, BCMA_CORE_NS_CHIPCOMMON_B);
if (core) {
bus->drv_cc_b.core = core;
bcma_core_chipcommon_b_init(&bus->drv_cc_b);
}
/* Init MIPS core */
core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
if (core) {
@ -297,7 +331,7 @@ int bcma_bus_register(struct bcma_bus *bus)
}
/* Register found cores */
bcma_register_cores(bus);
bcma_register_devices(bus);
bcma_info(bus, "Bus registered\n");
@ -315,6 +349,8 @@ void bcma_bus_unregister(struct bcma_bus *bus)
else if (err)
bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
bcma_core_chipcommon_b_free(&bus->drv_cc_b);
cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
@ -334,8 +370,6 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
struct bcma_device *core;
struct bcma_device_id match;
bcma_init_bus(bus);
match.manuf = BCMA_MANUF_BCM;
match.id = bcma_cc_core_id(bus);
match.class = BCMA_CL_SIM;

View File

@ -276,7 +276,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
struct bcma_device *core)
{
u32 tmp;
u8 i, j;
u8 i, j, k;
s32 cia, cib;
u8 ports[2], wrappers[2];
@ -314,6 +314,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
/* Some specific cores don't need wrappers */
switch (core->id.id) {
case BCMA_CORE_4706_MAC_GBIT_COMMON:
case BCMA_CORE_NS_CHIPCOMMON_B:
/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
break;
default:
@ -367,6 +368,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
core->addr = tmp;
/* get & parse slave ports */
k = 0;
for (i = 0; i < ports[1]; i++) {
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr,
@ -376,9 +378,9 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
/* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */
break;
} else {
if (i == 0 && j == 0)
core->addr1 = tmp;
} else if (k < ARRAY_SIZE(core->addr_s)) {
core->addr_s[k] = tmp;
k++;
}
}
}
@ -438,9 +440,6 @@ void bcma_init_bus(struct bcma_bus *bus)
s32 tmp;
struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
if (bus->init_done)
return;
INIT_LIST_HEAD(&bus->cores);
bus->nr_cores = 0;
@ -452,8 +451,6 @@ void bcma_init_bus(struct bcma_bus *bus)
chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
chipinfo->id, chipinfo->rev, chipinfo->pkg);
bus->init_done = true;
}
int bcma_bus_scan(struct bcma_bus *bus)
@ -463,8 +460,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
int err, core_num = 0;
bcma_init_bus(bus);
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);

View File

@ -331,6 +331,9 @@ static void btusb_intr_complete(struct urb *urb)
BT_ERR("%s corrupted event packet", hdev->name);
hdev->stat.err_rx++;
}
} else if (urb->status == -ENOENT) {
/* Avoid suspend failed when usb_kill_urb */
return;
}
if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
@ -419,6 +422,9 @@ static void btusb_bulk_complete(struct urb *urb)
BT_ERR("%s corrupted ACL packet", hdev->name);
hdev->stat.err_rx++;
}
} else if (urb->status == -ENOENT) {
/* Avoid suspend failed when usb_kill_urb */
return;
}
if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
@ -513,6 +519,9 @@ static void btusb_isoc_complete(struct urb *urb)
hdev->stat.err_rx++;
}
}
} else if (urb->status == -ENOENT) {
/* Avoid suspend failed when usb_kill_urb */
return;
}
if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))

View File

@ -234,6 +234,7 @@ void ath_printk(const char *level, const struct ath_common *common,
* AR9462.
* @ATH_DBG_DFS: radar datection
* @ATH_DBG_WOW: Wake on Wireless
* @ATH_DBG_DYNACK: dynack handling
* @ATH_DBG_ANY: enable all debugging
*
* The debug level is used to control the amount and type of debugging output
@ -262,6 +263,7 @@ enum ATH_DEBUG {
ATH_DBG_DFS = 0x00010000,
ATH_DBG_WOW = 0x00020000,
ATH_DBG_CHAN_CTX = 0x00040000,
ATH_DBG_DYNACK = 0x00080000,
ATH_DBG_ANY = 0xffffffff
};

View File

@ -4838,7 +4838,6 @@ int ath10k_mac_register(struct ath10k *ar)
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_SUPPORTS_STATIC_SMPS |
IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_SPECTRUM_MGMT;
@ -4846,8 +4845,10 @@ int ath10k_mac_register(struct ath10k *ar)
* bytes is used for padding/alignment if necessary. */
ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) {
ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;

View File

@ -704,7 +704,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
* reset.
*/
static void
ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
{
struct ath5k_hw *ah = hw->priv;

View File

@ -92,6 +92,15 @@ config ATH9K_DFS_CERTIFIED
developed. At this point enabling this option won't do anything
except increase code size.
config ATH9K_DYNACK
bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)"
depends on ATH9K
default n
---help---
This option enables ath9k dynamic ACK timeout estimation algorithm
based on ACK frame RX timestamp, TX frame timestamp and frame
duration
config ATH9K_TX99
bool "Atheros ath9k TX99 testing support"
depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS

View File

@ -49,6 +49,9 @@ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o
ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
ar9003_mci.o
ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o

View File

@ -381,6 +381,13 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
ts->evm1 = ads->AR_TxEVM1;
ts->evm2 = ads->AR_TxEVM2;
status = ACCESS_ONCE(ads->ds_ctl4);
ts->duration[0] = MS(status, AR_PacketDur0);
ts->duration[1] = MS(status, AR_PacketDur1);
status = ACCESS_ONCE(ads->ds_ctl5);
ts->duration[2] = MS(status, AR_PacketDur2);
ts->duration[3] = MS(status, AR_PacketDur3);
return 0;
}

View File

@ -355,9 +355,11 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
struct ath_tx_status *ts)
{
struct ar9003_txs *ads;
struct ar9003_txc *adc;
u32 status;
ads = &ah->ts_ring[ah->ts_tail];
adc = (struct ar9003_txc *)ads;
status = ACCESS_ONCE(ads->status8);
if ((status & AR_TxDone) == 0)
@ -426,6 +428,13 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
status = ACCESS_ONCE(adc->ctl15);
ts->duration[0] = MS(status, AR_PacketDur0);
ts->duration[1] = MS(status, AR_PacketDur1);
status = ACCESS_ONCE(adc->ctl16);
ts->duration[2] = MS(status, AR_PacketDur2);
ts->duration[3] = MS(status, AR_PacketDur3);
memset(ads, 0, sizeof(*ads));
return 0;

View File

@ -274,6 +274,9 @@ struct ath_node {
struct ath_rx_rate_stats rx_rate_stats;
#endif
u8 key_idx[4];
u32 ackto;
struct list_head list;
};
struct ath_tx_control {
@ -314,7 +317,6 @@ struct ath_rx {
bool discard_next;
u32 *rxlink;
u32 num_pkts;
unsigned int rxfilter;
struct list_head rxbuf;
struct ath_descdma rxdma;
struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
@ -350,6 +352,9 @@ struct ath_chanctx {
bool active;
bool assigned;
bool switch_after_beacon;
short nvifs;
unsigned int rxfilter;
};
enum ath_chanctx_event {
@ -376,6 +381,9 @@ enum ath_chanctx_state {
struct ath_chanctx_sched {
bool beacon_pending;
bool offchannel_pending;
bool wait_switch;
bool force_noa_update;
bool extend_absence;
enum ath_chanctx_state state;
u8 beacon_miss;
@ -449,7 +457,7 @@ void ath9k_p2p_ps_timer(void *priv);
void ath9k_chanctx_wake_queues(struct ath_softc *sc);
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx);
void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
enum ath_chanctx_event ev);
void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
enum ath_chanctx_event ev);
@ -478,7 +486,7 @@ static inline void ath9k_offchannel_init(struct ath_softc *sc)
static inline void ath9k_deinit_channel_context(struct ath_softc *sc)
{
}
static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
enum ath_chanctx_event ev)
{
}
@ -527,7 +535,7 @@ static inline void ath_chanctx_check_active(struct ath_softc *sc,
#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
int ath_startrecv(struct ath_softc *sc);
void ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
int ath_rx_init(struct ath_softc *sc, int nbufs);
@ -572,6 +580,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
/* VIFs */
/********/
#define P2P_DEFAULT_CTWIN 10
struct ath_vif {
struct list_head list;
@ -590,8 +600,10 @@ struct ath_vif {
u32 offchannel_start;
u32 offchannel_duration;
u32 periodic_noa_start;
u32 periodic_noa_duration;
/* These are used for both periodic and one-shot */
u32 noa_start;
u32 noa_duration;
bool periodic_noa;
};
struct ath9k_vif_iter_data {
@ -960,7 +972,6 @@ struct ath_softc {
bool ps_enabled;
bool ps_idle;
short nbcnvifs;
short nvifs;
unsigned long ps_usecount;
struct ath_rx rx;

View File

@ -183,7 +183,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
spin_unlock_bh(&cabq->axq_lock);
if (skb && cabq_depth) {
if (sc->nvifs > 1) {
if (sc->cur_chan->nvifs > 1) {
ath_dbg(common, BEACON,
"Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq);
@ -514,6 +514,18 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
if (ath9k_is_chanctx_enabled()) {
/*
* If the VIF is not present in the current channel context,
* then we can't do the usual opmode checks. Allow the
* beacon config for the VIF to be updated in this case and
* return immediately.
*/
if (sc->cur_chan != avp->chanctx)
return true;
}
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
if ((vif->type != NL80211_IFTYPE_AP) ||

View File

@ -83,8 +83,6 @@ static int ath_set_channel(struct ath_softc *sc)
if (hw->conf.radar_enabled) {
u32 rxfilter;
/* set HW specific DFS configuration */
ath9k_hw_set_radar_params(ah);
rxfilter = ath9k_hw_getrxfilter(ah);
rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
ATH9K_RX_FILTER_PHYERR;
@ -262,6 +260,9 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
cur = sc->cur_chan;
prev = ath_chanctx_get_next(sc, cur);
if (!prev->switch_after_beacon)
return;
getrawmonotonic(&ts);
cur_tsf = (u32) cur->tsf_val +
ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
@ -310,7 +311,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
struct ath_chanctx *ctx;
u32 tsf_time;
u32 beacon_int;
bool noa_changed = false;
if (vif)
avp = (struct ath_vif *) vif->drv_priv;
@ -333,7 +333,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
break;
}
if (sc->sched.offchannel_pending) {
if (sc->sched.offchannel_pending && !sc->sched.wait_switch) {
sc->sched.offchannel_pending = false;
sc->next_chan = &sc->offchannel.chan;
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
@ -372,44 +372,91 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.switch_start_time = tsf_time;
sc->cur_chan->last_beacon = sc->sched.next_tbtt;
/* Prevent wrap-around issues */
if (avp->periodic_noa_duration &&
tsf_time - avp->periodic_noa_start > BIT(30))
avp->periodic_noa_duration = 0;
/*
* If an offchannel switch is scheduled to happen after
* a beacon transmission, update the NoA with one-shot
* values and increment the index.
*/
if (sc->next_chan == &sc->offchannel.chan) {
avp->noa_index++;
avp->offchannel_start = tsf_time;
avp->offchannel_duration = sc->sched.offchannel_duration;
if (ctx->active && !avp->periodic_noa_duration) {
avp->periodic_noa_start = tsf_time;
avp->periodic_noa_duration =
TU_TO_USEC(cur_conf->beacon_interval) / 2 -
sc->sched.channel_switch_time;
noa_changed = true;
} else if (!ctx->active && avp->periodic_noa_duration) {
avp->periodic_noa_duration = 0;
noa_changed = true;
ath_dbg(common, CHAN_CTX,
"offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
avp->offchannel_duration,
avp->offchannel_start,
avp->noa_index);
/*
* When multiple contexts are active, the NoA
* has to be recalculated and advertised after
* an offchannel operation.
*/
if (ctx->active && avp->noa_duration)
avp->noa_duration = 0;
break;
}
/*
* Clear the extend_absence flag if it had been
* set during the previous beacon transmission,
* since we need to revert to the normal NoA
* schedule.
*/
if (ctx->active && sc->sched.extend_absence) {
avp->noa_duration = 0;
sc->sched.extend_absence = false;
}
/* If at least two consecutive beacons were missed on the STA
* chanctx, stay on the STA channel for one extra beacon period,
* to resync the timer properly.
*/
if (ctx->active && sc->sched.beacon_miss >= 2)
sc->sched.offchannel_duration = 3 * beacon_int / 2;
if (sc->sched.offchannel_duration) {
noa_changed = true;
avp->offchannel_start = tsf_time;
avp->offchannel_duration =
sc->sched.offchannel_duration;
if (ctx->active && sc->sched.beacon_miss >= 2) {
avp->noa_duration = 0;
sc->sched.extend_absence = true;
}
if (noa_changed)
avp->noa_index++;
/* Prevent wrap-around issues */
if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30))
avp->noa_duration = 0;
ath_dbg(common, CHAN_CTX,
"periodic_noa_duration: %d, periodic_noa_start: %d, noa_index: %d\n",
avp->periodic_noa_duration,
avp->periodic_noa_start,
avp->noa_index);
/*
* If multiple contexts are active, start periodic
* NoA and increment the index for the first
* announcement.
*/
if (ctx->active &&
(!avp->noa_duration || sc->sched.force_noa_update)) {
avp->noa_index++;
avp->noa_start = tsf_time;
if (sc->sched.extend_absence)
avp->noa_duration = (3 * beacon_int / 2) +
sc->sched.channel_switch_time;
else
avp->noa_duration =
TU_TO_USEC(cur_conf->beacon_interval) / 2 +
sc->sched.channel_switch_time;
if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
sc->sched.extend_absence)
avp->periodic_noa = false;
else
avp->periodic_noa = true;
ath_dbg(common, CHAN_CTX,
"noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
avp->noa_duration,
avp->noa_start,
avp->noa_index,
avp->periodic_noa);
}
if (ctx->active && sc->sched.force_noa_update)
sc->sched.force_noa_update = false;
break;
case ATH_CHANCTX_EVENT_BEACON_SENT:
@ -490,9 +537,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
"Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n");
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
sc->sched.wait_switch = false;
tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
if (sc->sched.beacon_miss >= 2) {
if (sc->sched.extend_absence) {
sc->sched.beacon_miss = 0;
tsf_time *= 3;
}
@ -560,10 +609,9 @@ void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
ath_chanctx_event(sc, NULL, ev);
}
void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
enum ath_chanctx_event ev)
{
sc->sched.next_tbtt = ts;
ath_chanctx_event(sc, NULL, ev);
}
@ -587,8 +635,18 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
(sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
if (chandef)
ctx->chandef = *chandef;
sc->sched.offchannel_pending = true;
sc->sched.wait_switch = true;
sc->sched.offchannel_duration =
jiffies_to_usecs(sc->offchannel.duration) +
sc->sched.channel_switch_time;
spin_unlock_bh(&sc->chan_lock);
ath_dbg(common, CHAN_CTX,
"Set offchannel_pending to true\n");
return;
}
@ -601,7 +659,7 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
if (sc->next_chan == &sc->offchannel.chan) {
sc->sched.offchannel_duration =
TU_TO_USEC(sc->offchannel.duration) +
jiffies_to_usecs(sc->offchannel.duration) +
sc->sched.channel_switch_time;
if (chandef) {
@ -688,7 +746,8 @@ void ath_offchannel_next(struct ath_softc *sc)
} else if (sc->offchannel.roc_vif) {
vif = sc->offchannel.roc_vif;
sc->offchannel.chan.txpower = vif->bss_conf.txpower;
sc->offchannel.duration = sc->offchannel.roc_duration;
sc->offchannel.duration =
msecs_to_jiffies(sc->offchannel.roc_duration);
sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
} else {
@ -724,6 +783,10 @@ void ath_scan_complete(struct ath_softc *sc, bool abort)
sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
ieee80211_scan_completed(sc->hw, abort);
clear_bit(ATH_OP_SCANNING, &common->op_flags);
spin_lock_bh(&sc->chan_lock);
if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
sc->sched.force_noa_update = true;
spin_unlock_bh(&sc->chan_lock);
ath_offchannel_next(sc);
ath9k_ps_restore(sc);
}
@ -959,8 +1022,8 @@ static void ath_offchannel_channel_change(struct ath_softc *sc)
break;
sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
mod_timer(&sc->offchannel.timer, jiffies +
msecs_to_jiffies(sc->offchannel.duration));
mod_timer(&sc->offchannel.timer,
jiffies + sc->offchannel.duration);
ieee80211_ready_on_channel(sc->hw);
break;
case ATH_OFFCHANNEL_ROC_DONE:
@ -1022,7 +1085,10 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force)
sc->cur_chan = sc->next_chan;
sc->cur_chan->stopped = false;
sc->next_chan = NULL;
sc->sched.offchannel_duration = 0;
if (!sc->sched.offchannel_pending)
sc->sched.offchannel_duration = 0;
if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
sc->sched.state = ATH_CHANCTX_STATE_IDLE;
@ -1165,6 +1231,30 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
ath9k_update_p2p_ps_timer(sc, avp);
}
static u8 ath9k_get_ctwin(struct ath_softc *sc, struct ath_vif *avp)
{
struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
u8 switch_time, ctwin;
/*
* Channel switch in multi-channel mode is deferred
* by a quarter beacon interval when handling
* ATH_CHANCTX_EVENT_BEACON_PREPARE, so the P2P-GO
* interface is guaranteed to be discoverable
* for that duration after a TBTT.
*/
switch_time = cur_conf->beacon_interval / 4;
ctwin = avp->vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
if (ctwin && (ctwin < switch_time))
return ctwin;
if (switch_time < P2P_DEFAULT_CTWIN)
return 0;
return P2P_DEFAULT_CTWIN;
}
void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
struct sk_buff *skb)
{
@ -1182,10 +1272,10 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
int noa_len, noa_desc, i = 0;
u8 *hdr;
if (!avp->offchannel_duration && !avp->periodic_noa_duration)
if (!avp->offchannel_duration && !avp->noa_duration)
return;
noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
noa_desc = !!avp->offchannel_duration + !!avp->noa_duration;
noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
hdr = skb_put(skb, sizeof(noa_ie_hdr));
@ -1197,13 +1287,19 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
memset(noa, 0, noa_len);
noa->index = avp->noa_index;
if (avp->periodic_noa_duration) {
u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
noa->desc[i].count = 255;
noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
noa->desc[i].interval = cpu_to_le32(interval);
if (avp->noa_duration) {
if (avp->periodic_noa) {
u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
noa->desc[i].count = 255;
noa->desc[i].interval = cpu_to_le32(interval);
} else {
noa->desc[i].count = 1;
}
noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
i++;
}

View File

@ -838,7 +838,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
iter_data.nmeshes, iter_data.nwds);
len += scnprintf(buf + len, sizeof(buf) - len,
" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
iter_data.nadhocs, sc->nvifs, sc->nbcnvifs);
iter_data.nadhocs, sc->cur_chan->nvifs, sc->nbcnvifs);
}
if (len > sizeof(buf))
@ -1169,6 +1169,29 @@ static const struct file_operations fops_btcoex = {
};
#endif
#ifdef CONFIG_ATH9K_DYNACK
static ssize_t read_file_ackto(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_hw *ah = sc->sc_ah;
char buf[32];
unsigned int len;
len = sprintf(buf, "%u %c\n", ah->dynack.ackto,
(ah->dynack.enabled) ? 'A' : 'S');
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_ackto = {
.read = read_file_ackto,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
#endif
/* Ethtool support for get-stats */
#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
@ -1374,5 +1397,10 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_btcoex);
#endif
#ifdef CONFIG_ATH9K_DYNACK
debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
sc, &fops_ackto);
#endif
return 0;
}

View File

@ -0,0 +1,351 @@
/*
* Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* 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 "ath9k.h"
#include "hw.h"
#include "dynack.h"
#define COMPUTE_TO (5 * HZ)
#define LATEACK_DELAY (10 * HZ)
#define LATEACK_TO 256
#define MAX_DELAY 300
#define EWMA_LEVEL 96
#define EWMA_DIV 128
/**
* ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
*
*/
static inline u32 ath_dynack_ewma(u32 old, u32 new)
{
return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV;
}
/**
* ath_dynack_get_sifs - get sifs time based on phy used
* @ah: ath hw
* @phy: phy used
*
*/
static inline u32 ath_dynack_get_sifs(struct ath_hw *ah, int phy)
{
u32 sifs = CCK_SIFS_TIME;
if (phy == WLAN_RC_PHY_OFDM) {
if (IS_CHAN_QUARTER_RATE(ah->curchan))
sifs = OFDM_SIFS_TIME_QUARTER;
else if (IS_CHAN_HALF_RATE(ah->curchan))
sifs = OFDM_SIFS_TIME_HALF;
else
sifs = OFDM_SIFS_TIME;
}
return sifs;
}
/**
* ath_dynack_bssidmask - filter out ACK frames based on BSSID mask
* @ah: ath hw
* @mac: receiver address
*/
static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac)
{
int i;
struct ath_common *common = ath9k_hw_common(ah);
for (i = 0; i < ETH_ALEN; i++) {
if ((common->macaddr[i] & common->bssidmask[i]) !=
(mac[i] & common->bssidmask[i]))
return false;
}
return true;
}
/**
* ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout
* @ah: ath hw
*
* should be called while holding qlock
*/
static void ath_dynack_compute_ackto(struct ath_hw *ah)
{
struct ath_node *an;
u32 to = 0;
struct ath_dynack *da = &ah->dynack;
struct ath_common *common = ath9k_hw_common(ah);
list_for_each_entry(an, &da->nodes, list)
if (an->ackto > to)
to = an->ackto;
if (to && da->ackto != to) {
u32 slottime;
slottime = (to - 3) / 2;
da->ackto = to;
ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n",
da->ackto, slottime);
ath9k_hw_setslottime(ah, slottime);
ath9k_hw_set_ack_timeout(ah, da->ackto);
ath9k_hw_set_cts_timeout(ah, da->ackto);
}
}
/**
* ath_dynack_compute_to - compute STA ACK timeout
* @ah: ath hw
*
* should be called while holding qlock
*/
static void ath_dynack_compute_to(struct ath_hw *ah)
{
u32 ackto, ack_ts;
u8 *dst, *src;
struct ieee80211_sta *sta;
struct ath_node *an;
struct ts_info *st_ts;
struct ath_dynack *da = &ah->dynack;
rcu_read_lock();
while (da->st_rbf.h_rb != da->st_rbf.t_rb &&
da->ack_rbf.h_rb != da->ack_rbf.t_rb) {
ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb];
st_ts = &da->st_rbf.ts[da->st_rbf.h_rb];
dst = da->st_rbf.addr[da->st_rbf.h_rb].h_dest;
src = da->st_rbf.addr[da->st_rbf.h_rb].h_src;
ath_dbg(ath9k_hw_common(ah), DYNACK,
"ack_ts %u st_ts %u st_dur %u [%u-%u]\n",
ack_ts, st_ts->tstamp, st_ts->dur,
da->ack_rbf.h_rb, da->st_rbf.h_rb);
if (ack_ts > st_ts->tstamp + st_ts->dur) {
ackto = ack_ts - st_ts->tstamp - st_ts->dur;
if (ackto < MAX_DELAY) {
sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst,
src);
if (sta) {
an = (struct ath_node *)sta->drv_priv;
an->ackto = ath_dynack_ewma(an->ackto,
ackto);
ath_dbg(ath9k_hw_common(ah), DYNACK,
"%pM to %u\n", dst, an->ackto);
if (time_is_before_jiffies(da->lto)) {
ath_dynack_compute_ackto(ah);
da->lto = jiffies + COMPUTE_TO;
}
}
INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
}
INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
} else {
INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
}
}
rcu_read_unlock();
}
/**
* ath_dynack_sample_tx_ts - status timestamp sampling method
* @ah: ath hw
* @skb: socket buffer
* @ts: tx status info
*
*/
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
struct ath_tx_status *ts)
{
u8 ridx;
struct ieee80211_hdr *hdr;
struct ath_dynack *da = &ah->dynack;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled)
return;
spin_lock_bh(&da->qlock);
hdr = (struct ieee80211_hdr *)skb->data;
/* late ACK */
if (ts->ts_status & ATH9K_TXERR_XRETRY) {
if (ieee80211_is_assoc_req(hdr->frame_control) ||
ieee80211_is_assoc_resp(hdr->frame_control)) {
ath_dbg(common, DYNACK, "late ack\n");
ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
da->lto = jiffies + LATEACK_DELAY;
}
spin_unlock_bh(&da->qlock);
return;
}
ridx = ts->ts_rateindex;
da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp;
da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration[ts->ts_rateindex];
ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1);
ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2);
if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) {
u32 phy, sifs;
const struct ieee80211_rate *rate;
struct ieee80211_tx_rate *rates = info->status.rates;
rate = &common->sbands[info->band].bitrates[rates[ridx].idx];
if (info->band == IEEE80211_BAND_2GHZ &&
!(rate->flags & IEEE80211_RATE_ERP_G))
phy = WLAN_RC_PHY_CCK;
else
phy = WLAN_RC_PHY_OFDM;
sifs = ath_dynack_get_sifs(ah, phy);
da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs;
}
ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n",
hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp,
da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb,
(da->st_rbf.t_rb + 1) % ATH_DYN_BUF);
INCR(da->st_rbf.t_rb, ATH_DYN_BUF);
if (da->st_rbf.t_rb == da->st_rbf.h_rb)
INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
ath_dynack_compute_to(ah);
spin_unlock_bh(&da->qlock);
}
EXPORT_SYMBOL(ath_dynack_sample_tx_ts);
/**
* ath_dynack_sample_ack_ts - ACK timestamp sampling method
* @ah: ath hw
* @skb: socket buffer
* @ts: rx timestamp
*
*/
void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb,
u32 ts)
{
struct ath_dynack *da = &ah->dynack;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled)
return;
spin_lock_bh(&da->qlock);
da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts;
ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n",
da->ack_rbf.tstamp[da->ack_rbf.t_rb],
da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF);
INCR(da->ack_rbf.t_rb, ATH_DYN_BUF);
if (da->ack_rbf.t_rb == da->ack_rbf.h_rb)
INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
ath_dynack_compute_to(ah);
spin_unlock_bh(&da->qlock);
}
EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
/**
* ath_dynack_node_init - init ath_node related info
* @ah: ath hw
* @an: ath node
*
*/
void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
{
/* ackto = slottime + sifs + air delay */
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
struct ath_dynack *da = &ah->dynack;
an->ackto = ackto;
spin_lock(&da->qlock);
list_add_tail(&an->list, &da->nodes);
spin_unlock(&da->qlock);
}
EXPORT_SYMBOL(ath_dynack_node_init);
/**
* ath_dynack_node_deinit - deinit ath_node related info
* @ah: ath hw
* @an: ath node
*
*/
void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an)
{
struct ath_dynack *da = &ah->dynack;
spin_lock(&da->qlock);
list_del(&an->list);
spin_unlock(&da->qlock);
}
EXPORT_SYMBOL(ath_dynack_node_deinit);
/**
* ath_dynack_reset - reset dynack processing
* @ah: ath hw
*
*/
void ath_dynack_reset(struct ath_hw *ah)
{
/* ackto = slottime + sifs + air delay */
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
struct ath_dynack *da = &ah->dynack;
da->lto = jiffies;
da->ackto = ackto;
da->st_rbf.t_rb = 0;
da->st_rbf.h_rb = 0;
da->ack_rbf.t_rb = 0;
da->ack_rbf.h_rb = 0;
/* init acktimeout */
ath9k_hw_setslottime(ah, (ackto - 3) / 2);
ath9k_hw_set_ack_timeout(ah, ackto);
ath9k_hw_set_cts_timeout(ah, ackto);
}
EXPORT_SYMBOL(ath_dynack_reset);
/**
* ath_dynack_init - init dynack data structure
* @ah: ath hw
*
*/
void ath_dynack_init(struct ath_hw *ah)
{
struct ath_dynack *da = &ah->dynack;
memset(da, 0, sizeof(struct ath_dynack));
spin_lock_init(&da->qlock);
INIT_LIST_HEAD(&da->nodes);
ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION;
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* 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 DYNACK_H
#define DYNACK_H
#define ATH_DYN_BUF 64
struct ath_hw;
struct ath_node;
/**
* struct ath_dyn_rxbuf - ACK frame ring buffer
* @h_rb: ring buffer head
* @t_rb: ring buffer tail
* @tstamp: ACK RX timestamp buffer
*/
struct ath_dyn_rxbuf {
u16 h_rb, t_rb;
u32 tstamp[ATH_DYN_BUF];
};
struct ts_info {
u32 tstamp;
u32 dur;
};
struct haddr_pair {
u8 h_dest[ETH_ALEN];
u8 h_src[ETH_ALEN];
};
/**
* struct ath_dyn_txbuf - tx frame ring buffer
* @h_rb: ring buffer head
* @t_rb: ring buffer tail
* @addr: dest/src address pair for a given TX frame
* @ts: TX frame timestamp buffer
*/
struct ath_dyn_txbuf {
u16 h_rb, t_rb;
struct haddr_pair addr[ATH_DYN_BUF];
struct ts_info ts[ATH_DYN_BUF];
};
/**
* struct ath_dynack - dynack processing info
* @enabled: enable dyn ack processing
* @ackto: current ACK timeout
* @lto: last ACK timeout computation
* @nodes: ath_node linked list
* @qlock: ts queue spinlock
* @ack_rbf: ACK ts ring buffer
* @st_rbf: status ts ring buffer
*/
struct ath_dynack {
bool enabled;
int ackto;
unsigned long lto;
struct list_head nodes;
/* protect timestamp queue access */
spinlock_t qlock;
struct ath_dyn_rxbuf ack_rbf;
struct ath_dyn_txbuf st_rbf;
};
#if defined(CONFIG_ATH9K_DYNACK)
void ath_dynack_reset(struct ath_hw *ah);
void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an);
void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an);
void ath_dynack_init(struct ath_hw *ah);
void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts);
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
struct ath_tx_status *ts);
#else
static inline void ath_dynack_init(struct ath_hw *ah) {}
static inline void ath_dynack_node_init(struct ath_hw *ah,
struct ath_node *an) {}
static inline void ath_dynack_node_deinit(struct ath_hw *ah,
struct ath_node *an) {}
static inline void ath_dynack_sample_ack_ts(struct ath_hw *ah,
struct sk_buff *skb, u32 ts) {}
static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah,
struct sk_buff *skb,
struct ath_tx_status *ts) {}
#endif
#endif /* DYNACK_H */

View File

@ -1722,7 +1722,7 @@ static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
}
static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
u8 coverage_class)
s16 coverage_class)
{
struct ath9k_htc_priv *priv = hw->priv;

View File

@ -647,6 +647,8 @@ int ath9k_hw_init(struct ath_hw *ah)
return ret;
}
ath_dynack_init(ah);
return 0;
}
EXPORT_SYMBOL(ath9k_hw_init);
@ -935,21 +937,21 @@ static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us)
REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val);
}
static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
val = min(val, (u32) 0xFFFF);
REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
}
static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
}
static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
@ -1053,6 +1055,14 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
ctstimeout += 48 - sifstime - ah->slottime;
}
if (ah->dynack.enabled) {
acktimeout = ah->dynack.ackto;
ctstimeout = acktimeout;
slottime = (acktimeout - 3) / 2;
} else {
ah->dynack.ackto = acktimeout;
}
ath9k_hw_set_sifs_time(ah, sifstime);
ath9k_hw_setslottime(ah, slottime);
ath9k_hw_set_ack_timeout(ah, acktimeout);
@ -1954,6 +1964,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9565(ah) && common->bt_ant_diversity)
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
if (ah->hw->conf.radar_enabled) {
/* set HW specific DFS configuration */
ah->radar_conf.ext_channel = IS_CHAN_HT40(chan);
ath9k_hw_set_radar_params(ah);
}
return 0;
}
EXPORT_SYMBOL(ath9k_hw_reset);

View File

@ -29,6 +29,7 @@
#include "reg.h"
#include "phy.h"
#include "btcoex.h"
#include "dynack.h"
#include "../regd.h"
@ -924,6 +925,8 @@ struct ath_hw {
int (*external_reset)(void);
const struct firmware *eeprom_blob;
struct ath_dynack dynack;
};
struct ath_bus_ops {
@ -1080,6 +1083,10 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us);
void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us);
void ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
{

View File

@ -763,8 +763,9 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR |
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE);
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
NL80211_FEATURE_P2P_GO_CTWIN;
if (!config_enabled(CONFIG_ATH9K_TX99)) {
hw->wiphy->interface_modes =
@ -810,7 +811,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
/* allow 4 queues per channel context +
* 1 cab queue + 1 offchannel tx queue
*/
hw->queues = 10;
hw->queues = ATH9K_NUM_TX_QUEUES;
/* last queue for offchannel */
hw->offchannel_tx_hw_queue = hw->queues - 1;
hw->max_rates = 4;

View File

@ -121,6 +121,7 @@ struct ath_tx_status {
u32 evm0;
u32 evm1;
u32 evm2;
u32 duration[4];
};
struct ath_rx_status {

View File

@ -224,16 +224,11 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
struct ath_common *common = ath9k_hw_common(ah);
unsigned long flags;
if (ath_startrecv(sc) != 0) {
ath_err(common, "Unable to restart recv logic\n");
return false;
}
ath9k_calculate_summary_state(sc, sc->cur_chan);
ath_startrecv(sc);
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->cur_chan->txpower, &sc->curtxpow);
clear_bit(ATH_OP_HW_RESET, &common->op_flags);
ath9k_calculate_summary_state(sc, sc->cur_chan);
if (!sc->cur_chan->offchannel && start) {
/* restore per chanctx TSF timer */
@ -350,12 +345,16 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
memset(&an->key_idx, 0, sizeof(an->key_idx));
ath_tx_node_init(sc, an);
ath_dynack_node_init(sc->sc_ah, an);
}
static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
ath_tx_node_cleanup(sc, an);
ath_dynack_node_deinit(sc->sc_ah, an);
}
void ath9k_tasklet(unsigned long data)
@ -916,8 +915,6 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
switch (vif->type) {
case NL80211_IFTYPE_AP:
iter_data->naps++;
if (vif->bss_conf.enable_beacon)
iter_data->beacons = true;
break;
case NL80211_IFTYPE_STATION:
iter_data->nstations++;
@ -960,21 +957,6 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
list_for_each_entry(avp, &ctx->vifs, list)
ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
if (ctx == &sc->offchannel.chan) {
struct ieee80211_vif *vif;
if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
vif = sc->offchannel.scan_vif;
else
vif = sc->offchannel.roc_vif;
if (vif)
ath9k_vif_iter(iter_data, vif->addr, vif);
iter_data->beacons = false;
}
#endif
}
static void ath9k_set_assoc_state(struct ath_softc *sc,
@ -985,13 +967,6 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
unsigned long flags;
set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
/* Set the AID, BSSID and do beacon-sync only when
* the HW opmode is STATION.
*
* But the primary bit is set above in any case.
*/
if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
return;
ether_addr_copy(common->curbssid, bss_conf->bssid);
common->curaid = bss_conf->aid;
@ -1014,6 +989,43 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
vif->addr, common->curbssid);
}
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
static void ath9k_set_offchannel_state(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_vif *vif = NULL;
ath9k_ps_wakeup(sc);
if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
vif = sc->offchannel.scan_vif;
else
vif = sc->offchannel.roc_vif;
if (WARN_ON(!vif))
goto exit;
eth_zero_addr(common->curbssid);
eth_broadcast_addr(common->bssidmask);
ether_addr_copy(common->macaddr, vif->addr);
common->curaid = 0;
ah->opmode = vif->type;
ah->imask &= ~ATH9K_INT_SWBA;
ah->imask &= ~ATH9K_INT_TSFOOR;
ah->slottime = ATH9K_SLOT_TIME_9;
ath_hw_setbssidmask(common);
ath9k_hw_setopmode(ah);
ath9k_hw_write_associd(sc->sc_ah);
ath9k_hw_set_interrupts(ah);
ath9k_hw_init_global_settings(ah);
exit:
ath9k_ps_restore(sc);
}
#endif
/* Called with sc->mutex held. */
void ath9k_calculate_summary_state(struct ath_softc *sc,
struct ath_chanctx *ctx)
@ -1021,12 +1033,18 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_vif_iter_data iter_data;
struct ath_beacon_config *cur_conf;
ath_chanctx_check_active(sc, ctx);
if (ctx != sc->cur_chan)
return;
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
if (ctx == &sc->offchannel.chan)
return ath9k_set_offchannel_state(sc);
#endif
ath9k_ps_wakeup(sc);
ath9k_calculate_iter_data(sc, ctx, &iter_data);
@ -1037,8 +1055,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ath_hw_setbssidmask(common);
if (iter_data.naps > 0) {
cur_conf = &ctx->beacon;
ath9k_hw_set_tsfadjust(ah, true);
ah->opmode = NL80211_IFTYPE_AP;
if (cur_conf->enable_beacon)
iter_data.beacons = true;
} else {
ath9k_hw_set_tsfadjust(ah, false);
@ -1067,13 +1088,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
if (ah->opmode == NL80211_IFTYPE_STATION) {
bool changed = (iter_data.primary_sta != ctx->primary_sta);
iter_data.beacons = true;
if (iter_data.primary_sta) {
iter_data.beacons = true;
ath9k_set_assoc_state(sc, iter_data.primary_sta,
changed);
if (!ctx->primary_sta ||
!ctx->primary_sta->bss_conf.assoc)
ctx->primary_sta = iter_data.primary_sta;
ctx->primary_sta = iter_data.primary_sta;
} else {
ctx->primary_sta = NULL;
memset(common->curbssid, 0, ETH_ALEN);
@ -1102,11 +1121,23 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
else
clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
ctx->primary_sta = iter_data.primary_sta;
ath9k_ps_restore(sc);
}
static void ath9k_assign_hw_queues(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
int i;
for (i = 0; i < IEEE80211_NUM_ACS; i++)
vif->hw_queue[i] = i;
if (vif->type == NL80211_IFTYPE_AP)
vif->cab_queue = hw->queues - 2;
else
vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
}
static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@ -1115,12 +1146,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_node *an = &avp->mcast_node;
int i;
mutex_lock(&sc->mutex);
if (config_enabled(CONFIG_ATH9K_TX99)) {
if (sc->nvifs >= 1) {
if (sc->cur_chan->nvifs >= 1) {
mutex_unlock(&sc->mutex);
return -EOPNOTSUPP;
}
@ -1128,7 +1158,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
}
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
sc->nvifs++;
sc->cur_chan->nvifs++;
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);
@ -1138,12 +1168,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
avp->chanctx = sc->cur_chan;
list_add_tail(&avp->list, &avp->chanctx->vifs);
}
for (i = 0; i < IEEE80211_NUM_ACS; i++)
vif->hw_queue[i] = i;
if (vif->type == NL80211_IFTYPE_AP)
vif->cab_queue = hw->queues - 2;
else
vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
ath9k_assign_hw_queues(hw, vif);
an->sc = sc;
an->sta = NULL;
@ -1163,7 +1189,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
int i;
mutex_lock(&sc->mutex);
@ -1183,14 +1208,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);
for (i = 0; i < IEEE80211_NUM_ACS; i++)
vif->hw_queue[i] = i;
if (vif->type == NL80211_IFTYPE_AP)
vif->cab_queue = hw->queues - 2;
else
vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
ath9k_assign_hw_queues(hw, vif);
ath9k_calculate_summary_state(sc, avp->chanctx);
mutex_unlock(&sc->mutex);
@ -1210,7 +1228,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
ath9k_p2p_remove_vif(sc, vif);
sc->nvifs--;
sc->cur_chan->nvifs--;
sc->tx99_vif = NULL;
if (!ath9k_is_chanctx_enabled())
list_del(&avp->list);
@ -1430,7 +1448,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
sc->rx.rxfilter = *total_flags;
spin_lock_bh(&sc->chan_lock);
sc->cur_chan->rxfilter = *total_flags;
spin_unlock_bh(&sc->chan_lock);
ath9k_ps_wakeup(sc);
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
@ -1695,9 +1716,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
(changed & BSS_CHANGED_BEACON_INT) ||
(changed & BSS_CHANGED_BEACON_INFO)) {
ath9k_beacon_config(sc, vif, changed);
if (changed & BSS_CHANGED_BEACON_ENABLED)
ath9k_calculate_summary_state(sc, avp->chanctx);
ath9k_beacon_config(sc, vif, changed);
}
if ((avp->chanctx == sc->cur_chan) &&
@ -1859,7 +1880,22 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
return 0;
}
static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
static void ath9k_enable_dynack(struct ath_softc *sc)
{
#ifdef CONFIG_ATH9K_DYNACK
u32 rfilt;
struct ath_hw *ah = sc->sc_ah;
ath_dynack_reset(ah);
ah->dynack.enabled = true;
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(ah, rfilt);
#endif
}
static void ath9k_set_coverage_class(struct ieee80211_hw *hw,
s16 coverage_class)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
@ -1868,11 +1904,22 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
return;
mutex_lock(&sc->mutex);
ah->coverage_class = coverage_class;
ath9k_ps_wakeup(sc);
ath9k_hw_init_global_settings(ah);
ath9k_ps_restore(sc);
if (coverage_class >= 0) {
ah->coverage_class = coverage_class;
if (ah->dynack.enabled) {
u32 rfilt;
ah->dynack.enabled = false;
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(ah, rfilt);
}
ath9k_ps_wakeup(sc);
ath9k_hw_init_global_settings(ah);
ath9k_ps_restore(sc);
} else if (!ah->dynack.enabled) {
ath9k_enable_dynack(sc);
}
mutex_unlock(&sc->mutex);
}

View File

@ -387,7 +387,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->hw->conf.radar_enabled)
rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR;
if (sc->rx.rxfilter & FIF_PROBE_REQ)
spin_lock_bh(&sc->chan_lock);
if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
/*
@ -398,24 +400,25 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->sc_ah->is_monitoring)
rfilt |= ATH9K_RX_FILTER_PROM;
if (sc->rx.rxfilter & FIF_CONTROL)
if ((sc->cur_chan->rxfilter & FIF_CONTROL) ||
sc->sc_ah->dynack.enabled)
rfilt |= ATH9K_RX_FILTER_CONTROL;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
(sc->nvifs <= 1) &&
!(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
(sc->cur_chan->nvifs <= 1) &&
!(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
else
rfilt |= ATH9K_RX_FILTER_BEACON;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
(sc->rx.rxfilter & FIF_PSPOLL))
(sc->cur_chan->rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
if (conf_is_ht(&sc->hw->conf))
if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
if (sc->cur_chan->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) {
/* This is needed for older chips */
if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
rfilt |= ATH9K_RX_FILTER_PROM;
@ -429,18 +432,20 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
test_bit(ATH_OP_SCANNING, &common->op_flags))
rfilt |= ATH9K_RX_FILTER_BEACON;
spin_unlock_bh(&sc->chan_lock);
return rfilt;
}
int ath_startrecv(struct ath_softc *sc)
void ath_startrecv(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_rxbuf *bf, *tbf;
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
ath_edma_start_recv(sc);
return 0;
return;
}
if (list_empty(&sc->rx.rxbuf))
@ -463,8 +468,6 @@ int ath_startrecv(struct ath_softc *sc)
start_recv:
ath_opmode_init(sc);
ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel);
return 0;
}
static void ath_flushrecv(struct ath_softc *sc)
@ -535,6 +538,7 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
bool skip_beacon = false;
if (skb->len < 24 + 8 + 2 + 2)
return;
@ -545,7 +549,16 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
sc->ps_flags &= ~PS_BEACON_SYNC;
ath_dbg(common, PS,
"Reconfigure beacon timers based on synchronized timestamp\n");
if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
if (ath9k_is_chanctx_enabled()) {
if (sc->cur_chan == &sc->offchannel.chan)
skip_beacon = true;
}
#endif
if (!skip_beacon &&
!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
ath9k_set_beacon(sc);
ath9k_p2p_beacon_sync(sc);
@ -867,8 +880,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame.
*/
if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter))
spin_lock_bh(&sc->chan_lock);
if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error,
sc->cur_chan->rxfilter)) {
spin_unlock_bh(&sc->chan_lock);
return -EINVAL;
}
spin_unlock_bh(&sc->chan_lock);
if (ath_is_mybeacon(common, hdr)) {
RX_STAT_INC(rx_beacons);
@ -894,7 +912,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
if (ath9k_is_chanctx_enabled()) {
if (rx_stats->is_mybeacon)
ath_chanctx_beacon_recv_ev(sc, rx_stats->rs_tstamp,
ath_chanctx_beacon_recv_ev(sc,
ATH_CHANCTX_EVENT_BEACON_RECEIVED);
}
@ -992,6 +1010,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
unsigned long flags;
dma_addr_t new_buf_addr;
unsigned int budget = 512;
struct ieee80211_hdr *hdr;
if (edma)
dma_type = DMA_BIDIRECTIONAL;
@ -1121,6 +1140,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
ath9k_apply_ampdu_details(sc, &rs, rxs);
ath_debug_rate_stats(sc, &rs, skb);
hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_ack(hdr->frame_control))
ath_dynack_sample_ack_ts(sc->sc_ah, skb, rs.rs_tstamp);
ieee80211_rx(hw, skb);
requeue_drop_frag:

View File

@ -174,7 +174,7 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
ssize_t len;
int r;
if (sc->nvifs > 1)
if (sc->cur_chan->nvifs > 1)
return -EOPNOTSUPP;
len = min(count, sizeof(buf) - 1);

View File

@ -232,7 +232,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
goto fail_wow;
}
if (sc->nvifs > 1) {
if (sc->cur_chan->nvifs > 1) {
ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
ret = 1;
goto fail_wow;

View File

@ -587,6 +587,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
memcpy(tx_info->control.rates, rates, sizeof(rates));
ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok);
rc_update = false;
if (bf == bf->bf_lastbf)
ath_dynack_sample_tx_ts(sc->sc_ah,
bf->bf_mpdu,
ts);
}
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
@ -687,6 +691,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
memcpy(info->control.rates, bf->rates,
sizeof(info->control.rates));
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts);
}
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
} else

View File

@ -39,3 +39,12 @@ config WIL6210_TRACING
option if you are interested in debugging the driver.
If unsure, say Y to make it easier to debug problems.
config WIL6210_PLATFORM_MSM
bool "wil6210 MSM platform specific support"
depends on WIL6210
depends on ARCH_MSM
default y
---help---
Say Y here to enable wil6210 driver support for MSM
platform specific features

View File

@ -10,7 +10,10 @@ wil6210-y += interrupt.o
wil6210-y += txrx.o
wil6210-y += debug.o
wil6210-y += rx_reorder.o
wil6210-y += fw.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
wil6210-y += wil_platform.o
wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)

View File

@ -296,6 +296,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
n = min(request->n_channels, 4U);
for (i = 0; i < n; i++) {
int ch = request->channels[i]->hw_value;
if (ch == 0) {
wil_err(wil,
"Scan requested for unknown frequency %dMhz\n",
@ -308,9 +309,23 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
request->channels[i]->center_freq);
}
if (request->ie_len)
print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET,
request->ie, request->ie_len);
else
wil_dbg_misc(wil, "Scan has no IE's\n");
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len,
request->ie);
if (rc) {
wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc);
goto out;
}
rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
out:
if (rc) {
del_timer_sync(&wil->scan_timer);
wil->scan_request = NULL;
@ -319,6 +334,22 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
return rc;
}
static void wil_print_connect_params(struct wil6210_priv *wil,
struct cfg80211_connect_params *sme)
{
wil_info(wil, "Connecting to:\n");
if (sme->channel) {
wil_info(wil, " Channel: %d freq %d\n",
sme->channel->hw_value, sme->channel->center_freq);
}
if (sme->bssid)
wil_info(wil, " BSSID: %pM\n", sme->bssid);
if (sme->ssid)
print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
16, 1, sme->ssid, sme->ssid_len, true);
wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
}
static int wil_cfg80211_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
@ -335,6 +366,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
test_bit(wil_status_fwconnected, &wil->status))
return -EALREADY;
wil_print_connect_params(wil, sme);
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
sme->ssid, sme->ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@ -360,22 +393,22 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
sme->ie_len);
goto out;
}
/*
* For secure assoc, send:
* (1) WMI_DELETE_CIPHER_KEY_CMD
* (2) WMI_SET_APPIE_CMD
*/
/* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
rc = wmi_del_cipher_key(wil, 0, bss->bssid);
if (rc) {
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
goto out;
}
/* WMI_SET_APPIE_CMD */
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
if (rc) {
wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
goto out;
}
}
/* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
* elements. Send it also in case it's empty, to erase previously set
* ies in FW.
*/
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
if (rc) {
wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
goto out;
}
/* WMI_CONNECT_CMD */
@ -621,6 +654,45 @@ static int wil_fix_bcon(struct wil6210_priv *wil,
return rc;
}
static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_beacon_data *bcon)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
if (wil_fix_bcon(wil, bcon)) {
wil_dbg_misc(wil, "Fixed bcon\n");
wil_print_bcon_data(bcon);
}
/* FW do not form regular beacon, so bcon IE's are not set
* For the DMG bcon, when it will be supported, bcon IE's will
* be reused; add something like:
* wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
* bcon->beacon_ies);
*/
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
bcon->proberesp_ies_len,
bcon->proberesp_ies);
if (rc) {
wil_err(wil, "set_ie(PROBE_RESP) failed\n");
return rc;
}
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
bcon->assocresp_ies_len,
bcon->assocresp_ies);
if (rc) {
wil_err(wil, "set_ie(ASSOC_RESP) failed\n");
return rc;
}
return 0;
}
static int wil_cfg80211_start_ap(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_ap_settings *info)
@ -658,12 +730,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
rc = wil_reset(wil);
if (rc)
goto out;
/* Rx VRING. */
rc = wil_rx_init(wil);
__wil_down(wil);
rc = __wil_up(wil);
if (rc)
goto out;
@ -671,9 +739,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
goto out;
/* MAC address - pre-requisite for other commands */
wmi_set_mac_address(wil, ndev->dev_addr);
/* IE's */
/* bcon 'head IE's are not relevant for 60g band */
/*
@ -695,7 +760,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
goto out;
netif_carrier_on(ndev);
out:
@ -706,7 +770,7 @@ out:
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
struct net_device *ndev)
{
int rc = 0;
int rc, rc1;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "%s()\n", __func__);
@ -715,8 +779,12 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
rc = wmi_pcp_stop(wil);
__wil_down(wil);
rc1 = __wil_up(wil);
mutex_unlock(&wil->mutex);
return rc;
return min(rc, rc1);
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
@ -746,6 +814,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.del_key = wil_cfg80211_del_key,
.set_default_key = wil_cfg80211_set_default_key,
/* AP mode */
.change_beacon = wil_cfg80211_change_beacon,
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station,
@ -755,6 +824,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
{
/* TODO: set real value */
wiphy->max_scan_ssids = 10;
wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
wiphy->max_num_pmkids = 0 /* TODO: */;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
@ -764,8 +834,8 @@ static void wil_wiphy_init(struct wiphy *wiphy)
*/
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
__func__, wiphy->flags);
dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
__func__, wiphy->flags);
wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
@ -786,7 +856,9 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev)
int rc = 0;
struct wireless_dev *wdev;
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
dev_dbg(dev, "%s()\n", __func__);
wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
if (!wdev)
return ERR_PTR(-ENOMEM);
@ -818,6 +890,8 @@ void wil_wdev_free(struct wil6210_priv *wil)
{
struct wireless_dev *wdev = wil_to_wdev(wil);
dev_dbg(wil_to_dev(wil), "%s()\n", __func__);
if (!wdev)
return;

View File

@ -17,43 +17,37 @@
#include "wil6210.h"
#include "trace.h"
int wil_err(struct wil6210_priv *wil, const char *fmt, ...)
void wil_err(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = netdev_err(ndev, "%pV", &vaf);
netdev_err(ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf);
va_end(args);
return ret;
}
int wil_info(struct wil6210_priv *wil, const char *fmt, ...)
void wil_info(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = netdev_info(ndev, "%pV", &vaf);
netdev_info(ndev, "%pV", &vaf);
trace_wil6210_log_info(&vaf);
va_end(args);
return ret;
}
int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@ -64,6 +58,4 @@ int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
vaf.va = &args;
trace_wil6210_log_dbg(&vaf);
va_end(args);
return 0;
}

View File

@ -61,20 +61,22 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
if (x)
seq_printf(s, "0x%08x\n", ioread32(x));
else
seq_printf(s, "???\n");
seq_puts(s, "???\n");
if (vring->va && (vring->size < 1025)) {
uint i;
for (i = 0; i < vring->size; i++) {
volatile struct vring_tx_desc *d = &vring->va[i].tx;
if ((i % 64) == 0 && (i != 0))
seq_printf(s, "\n");
seq_puts(s, "\n");
seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
_s : (vring->ctx[i].skb ? _h : 'h'));
}
seq_printf(s, "\n");
seq_puts(s, "\n");
}
seq_printf(s, "}\n");
seq_puts(s, "}\n");
}
static int wil_vring_debugfs_show(struct seq_file *s, void *data)
@ -85,7 +87,7 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
struct vring *vring = &(wil->vring_tx[i]);
struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
if (vring->va) {
@ -163,7 +165,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
if (!wmi_addr(wil, r.base) ||
!wmi_addr(wil, r.tail) ||
!wmi_addr(wil, r.head)) {
seq_printf(s, " ??? pointers are garbage?\n");
seq_puts(s, " ??? pointers are garbage?\n");
goto out;
}
@ -182,6 +184,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
le32_to_cpu(d.addr));
if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
u16 len = le16_to_cpu(hdr.len);
seq_printf(s, " -> %04x %04x %04x %02x\n",
le16_to_cpu(hdr.seq), len,
le16_to_cpu(hdr.type), hdr.flags);
@ -199,6 +202,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
wil_memcpy_fromio_32(databuf, src, len);
while (n < len) {
int l = min(len - n, 16);
hex_dump_to_buffer(databuf + n, l,
16, 1, printbuf,
sizeof(printbuf),
@ -208,11 +212,11 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
}
}
} else {
seq_printf(s, "\n");
seq_puts(s, "\n");
}
}
out:
seq_printf(s, "}\n");
seq_puts(s, "}\n");
}
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
@ -271,11 +275,13 @@ static int wil_debugfs_ulong_set(void *data, u64 val)
*(ulong *)data = val;
return 0;
}
static int wil_debugfs_ulong_get(void *data, u64 *val)
{
*val = *(ulong *)data;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
wil_debugfs_ulong_set, "%llu\n");
@ -302,7 +308,7 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
int i;
for (i = 0; tbl[i].name; i++) {
struct dentry *f = NULL;
struct dentry *f;
switch (tbl[i].type) {
case doff_u32:
@ -322,6 +328,8 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
tbl[i].mode, dbg,
base + tbl[i].off);
break;
default:
f = ERR_PTR(-EINVAL);
}
if (IS_ERR_OR_NULL(f))
wil_err(wil, "Create file \"%s\": err %ld\n",
@ -339,6 +347,7 @@ static const struct dbg_off isr_off[] = {
{"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
{},
};
static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
const char *name,
struct dentry *parent, u32 off)
@ -422,7 +431,7 @@ static const struct file_operations fops_memread = {
};
static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{
enum { max_count = 4096 };
struct debugfs_blob_wrapper *blob = file->private_data;
@ -474,6 +483,7 @@ struct dentry *wil_debugfs_create_ioblob(const char *name,
{
return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
}
/*---reset---*/
static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@ -499,6 +509,7 @@ static const struct file_operations fops_reset = {
.write = wil_write_file_reset,
.open = simple_open,
};
/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@ -509,6 +520,7 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
bool on;
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
if (copy_from_user(kbuf, buf, len)) {
@ -545,6 +557,7 @@ static const struct file_operations fops_rxon = {
.write = wil_write_file_rxon,
.open = simple_open,
};
/*---tx_mgmt---*/
/* Write mgmt frame to this file to send it */
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@ -555,8 +568,8 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
struct wireless_dev *wdev = wil_to_wdev(wil);
struct cfg80211_mgmt_tx_params params;
int rc;
void *frame = kmalloc(len, GFP_KERNEL);
if (!frame)
return -ENOMEM;
@ -625,8 +638,10 @@ static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
{
char printbuf[16 * 3 + 2];
int i = 0;
while (i < len) {
int l = min(len - i, 16);
hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
sizeof(printbuf), false);
seq_printf(s, "%s%s\n", prefix, printbuf);
@ -664,10 +679,8 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
struct wil6210_priv *wil = s->private;
struct vring *vring;
bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
if (tx)
vring = &(wil->vring_tx[dbg_vring_index]);
else
vring = &wil->vring_rx;
vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
if (!vring->va) {
if (tx)
@ -682,7 +695,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
* only field used, .dma.length, is the same
*/
volatile struct vring_tx_desc *d =
&(vring->va[dbg_txdesc_index].tx);
&vring->va[dbg_txdesc_index].tx;
volatile u32 *u = (volatile u32 *)d;
struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
@ -702,7 +715,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
wil_seq_print_skb(s, skb);
kfree_skb(skb);
}
seq_printf(s, "}\n");
seq_puts(s, "}\n");
} else {
if (tx)
seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
@ -816,6 +829,7 @@ static const struct file_operations fops_bf = {
.read = seq_read,
.llseek = seq_lseek,
};
/*---------SSID------------*/
static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@ -878,10 +892,10 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
u32 t_m, t_r;
int rc = wmi_get_temperature(wil, &t_m, &t_r);
if (rc) {
seq_printf(s, "Failed\n");
seq_puts(s, "Failed\n");
return 0;
}
@ -937,6 +951,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
switch (p->status) {
case wil_sta_unused:
status = "unused ";
@ -997,7 +1012,6 @@ static int wil_info_debugfs_show(struct seq_file *s, void *data)
rxf_old = rxf;
txf_old = txf;
#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
" " __stringify(x) : ""
@ -1032,6 +1046,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
{
int i;
u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
seq_printf(s, "0x%03x [", r->head_seq_num);
for (i = 0; i < r->buf_size; i++) {
if (i == index)
@ -1046,10 +1061,12 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
int i, tid;
unsigned long flags;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
switch (p->status) {
case wil_sta_unused:
status = "unused ";
@ -1065,13 +1082,16 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
(p->data_port_open ? " data_port_open" : ""));
if (p->status == wil_sta_connected) {
spin_lock_irqsave(&p->tid_rx_lock, flags);
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
if (r) {
seq_printf(s, "[%2d] ", tid);
wil_print_rxtid(s, r);
}
}
spin_unlock_irqrestore(&p->tid_rx_lock, flags);
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/crc32.h>
#include "wil6210.h"
#include "fw.h"
MODULE_FIRMWARE(WIL_FW_NAME);
/* target operations */
/* register read */
#define R(a) ioread32(wil->csr + HOSTADDR(a))
/* register write. wmb() to make sure it is completed */
#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
/* register set = read, OR, write */
#define S(a, v) W(a, R(a) | v)
/* register clear = read, AND with inverted, write */
#define C(a, v) W(a, R(a) & ~v)
static
void wil_memset_toio_32(volatile void __iomem *dst, u32 val,
size_t count)
{
volatile u32 __iomem *d = dst;
for (count += 4; count > 4; count -= 4)
__raw_writel(val, d++);
}
#include "fw_inc.c"

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
#define WIL_FW_FMT_VERSION (1) /* format version driver supports */
enum wil_fw_record_type {
wil_fw_type_comment = 1,
wil_fw_type_data = 2,
wil_fw_type_fill = 3,
wil_fw_type_action = 4,
wil_fw_type_verify = 5,
wil_fw_type_file_header = 6,
wil_fw_type_direct_write = 7,
wil_fw_type_gateway_data = 8,
wil_fw_type_gateway_data4 = 9,
};
struct wil_fw_record_head {
__le16 type; /* enum wil_fw_record_type */
__le16 flags; /* to be defined */
__le32 size; /* whole record, bytes after head */
} __packed;
/* data block. write starting from @addr
* data_size inferred from the @head.size. For this case,
* data_size = @head.size - offsetof(struct wil_fw_record_data, data)
*/
struct wil_fw_record_data { /* type == wil_fw_type_data */
__le32 addr;
__le32 data[0]; /* [data_size], see above */
} __packed;
/* fill with constant @value, @size bytes starting from @addr */
struct wil_fw_record_fill { /* type == wil_fw_type_fill */
__le32 addr;
__le32 value;
__le32 size;
} __packed;
/* free-form comment
* for informational purpose, data_size is @head.size from record header
*/
struct wil_fw_record_comment { /* type == wil_fw_type_comment */
u8 data[0]; /* free-form data [data_size], see above */
} __packed;
/* perform action
* data_size = @head.size - offsetof(struct wil_fw_record_action, data)
*/
struct wil_fw_record_action { /* type == wil_fw_type_action */
__le32 action; /* action to perform: reset, wait for fw ready etc. */
__le32 data[0]; /* action specific, [data_size], see above */
} __packed;
/* data block for struct wil_fw_record_direct_write */
struct wil_fw_data_dwrite {
__le32 addr;
__le32 value;
__le32 mask;
} __packed;
/* write @value to the @addr,
* preserve original bits accordingly to the @mask
* data_size is @head.size where @head is record header
*/
struct wil_fw_record_direct_write { /* type == wil_fw_type_direct_write */
struct wil_fw_data_dwrite data[0];
} __packed;
/* verify condition: [@addr] & @mask == @value
* if condition not met, firmware download fails
*/
struct wil_fw_record_verify { /* type == wil_fw_verify */
__le32 addr; /* read from this address */
__le32 value; /* reference value */
__le32 mask; /* mask for verification */
} __packed;
/* file header
* First record of every file
*/
struct wil_fw_record_file_header {
__le32 signature ; /* Wilocity signature */
__le32 reserved;
__le32 crc; /* crc32 of the following data */
__le32 version; /* format version */
__le32 data_len; /* total data in file, including this record */
u8 comment[32]; /* short description */
} __packed;
/* 1-dword gateway */
/* data block for the struct wil_fw_record_gateway_data */
struct wil_fw_data_gw {
__le32 addr;
__le32 value;
} __packed;
/* gateway write block.
* write starting address and values from the data buffer
* through the gateway
* data_size inferred from the @head.size. For this case,
* data_size = @head.size - offsetof(struct wil_fw_record_gateway_data, data)
*/
struct wil_fw_record_gateway_data { /* type == wil_fw_type_gateway_data */
__le32 gateway_addr_addr;
__le32 gateway_value_addr;
__le32 gateway_cmd_addr;
__le32 gateway_ctrl_address;
#define WIL_FW_GW_CTL_BUSY BIT(29) /* gateway busy performing operation */
#define WIL_FW_GW_CTL_RUN BIT(30) /* start gateway operation */
__le32 command;
struct wil_fw_data_gw data[0]; /* total size [data_size], see above */
} __packed;
/* 4-dword gateway */
/* data block for the struct wil_fw_record_gateway_data4 */
struct wil_fw_data_gw4 {
__le32 addr;
__le32 value[4];
} __packed;
/* gateway write block.
* write starting address and values from the data buffer
* through the gateway
* data_size inferred from the @head.size. For this case,
* data_size = @head.size - offsetof(struct wil_fw_record_gateway_data4, data)
*/
struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
__le32 gateway_addr_addr;
__le32 gateway_value_addr[4];
__le32 gateway_cmd_addr;
__le32 gateway_ctrl_address; /* same logic as for 1-dword gw */
__le32 command;
struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
} __packed;

View File

@ -0,0 +1,495 @@
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Algorithmic part of the firmware download.
* To be included in the container file providing framework
*/
#define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg)
#define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg)
#define wil_hex_dump_fw(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
print_hex_dump_debug("DBG[ FW ]" prefix_str, \
prefix_type, rowsize, \
groupsize, buf, len, ascii)
#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
ioaddr = wmi_buffer(wil, val); \
if (!ioaddr) { \
wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
le32_to_cpu(val)); \
return -EINVAL; \
} \
} while (0)
/**
* wil_fw_verify - verify firmware file validity
*
* perform various checks for the firmware file header.
* records are not validated.
*
* Return file size or negative error
*/
static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size)
{
const struct wil_fw_record_head *hdr = (const void *)data;
struct wil_fw_record_file_header fh;
const struct wil_fw_record_file_header *fh_;
u32 crc;
u32 dlen;
if (size % 4) {
wil_err_fw(wil, "image size not aligned: %zu\n", size);
return -EINVAL;
}
/* have enough data for the file header? */
if (size < sizeof(*hdr) + sizeof(fh)) {
wil_err_fw(wil, "file too short: %zu bytes\n", size);
return -EINVAL;
}
/* start with the file header? */
if (le16_to_cpu(hdr->type) != wil_fw_type_file_header) {
wil_err_fw(wil, "no file header\n");
return -EINVAL;
}
/* data_len */
fh_ = (struct wil_fw_record_file_header *)&hdr[1];
dlen = le32_to_cpu(fh_->data_len);
if (dlen % 4) {
wil_err_fw(wil, "data length not aligned: %lu\n", (ulong)dlen);
return -EINVAL;
}
if (size < dlen) {
wil_err_fw(wil, "file truncated at %zu/%lu\n",
size, (ulong)dlen);
return -EINVAL;
}
if (dlen < sizeof(*hdr) + sizeof(fh)) {
wil_err_fw(wil, "data length too short: %lu\n", (ulong)dlen);
return -EINVAL;
}
/* signature */
if (le32_to_cpu(fh_->signature) != WIL_FW_SIGNATURE) {
wil_err_fw(wil, "bad header signature: 0x%08x\n",
le32_to_cpu(fh_->signature));
return -EINVAL;
}
/* version */
if (le32_to_cpu(fh_->version) > WIL_FW_FMT_VERSION) {
wil_err_fw(wil, "unsupported header version: %d\n",
le32_to_cpu(fh_->version));
return -EINVAL;
}
/* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/
fh = *fh_;
fh.crc = 0;
crc = crc32_le(~0, (unsigned char const *)hdr, sizeof(*hdr));
crc = crc32_le(crc, (unsigned char const *)&fh, sizeof(fh));
crc = crc32_le(crc, (unsigned char const *)&fh_[1],
dlen - sizeof(*hdr) - sizeof(fh));
crc = ~crc;
if (crc != le32_to_cpu(fh_->crc)) {
wil_err_fw(wil, "checksum mismatch:"
" calculated for %lu bytes 0x%08x != 0x%08x\n",
(ulong)dlen, crc, le32_to_cpu(fh_->crc));
return -EINVAL;
}
return (int)dlen;
}
static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
size_t size)
{
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
return 0;
}
static int fw_handle_data(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_data *d = data;
void __iomem *dst;
size_t s = size - sizeof(*d);
if (size < sizeof(*d) + sizeof(u32)) {
wil_err_fw(wil, "data record too short: %zu\n", size);
return -EINVAL;
}
FW_ADDR_CHECK(dst, d->addr, "address");
wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
s);
wil_memcpy_toio_32(dst, d->data, s);
wmb(); /* finish before processing next record */
return 0;
}
static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_fill *d = data;
void __iomem *dst;
u32 v;
size_t s = (size_t)le32_to_cpu(d->size);
if (size != sizeof(*d)) {
wil_err_fw(wil, "bad size for fill record: %zu\n", size);
return -EINVAL;
}
if (s < sizeof(u32)) {
wil_err_fw(wil, "fill size too short: %zu\n", s);
return -EINVAL;
}
if (s % sizeof(u32)) {
wil_err_fw(wil, "fill size not aligned: %zu\n", s);
return -EINVAL;
}
FW_ADDR_CHECK(dst, d->addr, "address");
v = le32_to_cpu(d->value);
wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
le32_to_cpu(d->addr), v, s);
wil_memset_toio_32(dst, v, s);
wmb(); /* finish before processing next record */
return 0;
}
static int fw_handle_file_header(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_file_header *d = data;
if (size != sizeof(*d)) {
wil_err_fw(wil, "file header length incorrect: %zu\n", size);
return -EINVAL;
}
wil_dbg_fw(wil, "new file, ver. %d, %i bytes\n",
d->version, d->data_len);
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, d->comment,
sizeof(d->comment), true);
return 0;
}
static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_direct_write *d = data;
const struct wil_fw_data_dwrite *block = d->data;
int n, i;
if (size % sizeof(*block)) {
wil_err_fw(wil, "record size not aligned on %zu: %zu\n",
sizeof(*block), size);
return -EINVAL;
}
n = size / sizeof(*block);
for (i = 0; i < n; i++) {
void __iomem *dst;
u32 m = le32_to_cpu(block[i].mask);
u32 v = le32_to_cpu(block[i].value);
u32 x, y;
FW_ADDR_CHECK(dst, block[i].addr, "address");
x = ioread32(dst);
y = (x & m) | (v & ~m);
wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x "
"(old 0x%08x val 0x%08x mask 0x%08x)\n",
le32_to_cpu(block[i].addr), y, x, v, m);
iowrite32(y, dst);
wmb(); /* finish before processing next record */
}
return 0;
}
static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr,
void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd,
u32 a)
{
unsigned delay = 0;
iowrite32(a, gwa_addr);
iowrite32(gw_cmd, gwa_cmd);
wmb(); /* finish before activate gw */
iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */
do {
udelay(1); /* typical time is few usec */
if (delay++ > 100) {
wil_err_fw(wil, "gw timeout\n");
return -EINVAL;
}
} while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */
return 0;
}
static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_gateway_data *d = data;
const struct wil_fw_data_gw *block = d->data;
void __iomem *gwa_addr;
void __iomem *gwa_val;
void __iomem *gwa_cmd;
void __iomem *gwa_ctl;
u32 gw_cmd;
int n, i;
if (size < sizeof(*d) + sizeof(*block)) {
wil_err_fw(wil, "gateway record too short: %zu\n", size);
return -EINVAL;
}
if ((size - sizeof(*d)) % sizeof(*block)) {
wil_err_fw(wil, "gateway record data size"
" not aligned on %zu: %zu\n",
sizeof(*block), size - sizeof(*d));
return -EINVAL;
}
n = (size - sizeof(*d)) / sizeof(*block);
gw_cmd = le32_to_cpu(d->command);
wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
n, gw_cmd);
FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
" cmd 0x%08x ctl 0x%08x\n",
le32_to_cpu(d->gateway_addr_addr),
le32_to_cpu(d->gateway_value_addr),
le32_to_cpu(d->gateway_cmd_addr),
le32_to_cpu(d->gateway_ctrl_address));
for (i = 0; i < n; i++) {
int rc;
u32 a = le32_to_cpu(block[i].addr);
u32 v = le32_to_cpu(block[i].value);
wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n",
i, a, v);
iowrite32(v, gwa_val);
rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
if (rc)
return rc;
}
return 0;
}
static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_gateway_data4 *d = data;
const struct wil_fw_data_gw4 *block = d->data;
void __iomem *gwa_addr;
void __iomem *gwa_val[ARRAY_SIZE(block->value)];
void __iomem *gwa_cmd;
void __iomem *gwa_ctl;
u32 gw_cmd;
int n, i, k;
if (size < sizeof(*d) + sizeof(*block)) {
wil_err_fw(wil, "gateway4 record too short: %zu\n", size);
return -EINVAL;
}
if ((size - sizeof(*d)) % sizeof(*block)) {
wil_err_fw(wil, "gateway4 record data size"
" not aligned on %zu: %zu\n",
sizeof(*block), size - sizeof(*d));
return -EINVAL;
}
n = (size - sizeof(*d)) / sizeof(*block);
gw_cmd = le32_to_cpu(d->command);
wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
n, gw_cmd);
FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
for (k = 0; k < ARRAY_SIZE(block->value); k++)
FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
"gateway_value_addr");
FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
le32_to_cpu(d->gateway_addr_addr),
le32_to_cpu(d->gateway_cmd_addr),
le32_to_cpu(d->gateway_ctrl_address));
wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE, 16, 4,
d->gateway_value_addr, sizeof(d->gateway_value_addr),
false);
for (i = 0; i < n; i++) {
int rc;
u32 a = le32_to_cpu(block[i].addr);
u32 v[ARRAY_SIZE(block->value)];
for (k = 0; k < ARRAY_SIZE(block->value); k++)
v[k] = le32_to_cpu(block[i].value[k]);
wil_dbg_fw(wil, " gw4 write[%3d] [0x%08x] <==\n", i, a);
wil_hex_dump_fw(" val ", DUMP_PREFIX_NONE, 16, 4, v,
sizeof(v), false);
for (k = 0; k < ARRAY_SIZE(block->value); k++)
iowrite32(v[k], gwa_val[k]);
rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
if (rc)
return rc;
}
return 0;
}
static const struct {
int type;
int (*handler)(struct wil6210_priv *wil, const void *data, size_t size);
} wil_fw_handlers[] = {
{wil_fw_type_comment, fw_handle_comment},
{wil_fw_type_data, fw_handle_data},
{wil_fw_type_fill, fw_handle_fill},
/* wil_fw_type_action */
/* wil_fw_type_verify */
{wil_fw_type_file_header, fw_handle_file_header},
{wil_fw_type_direct_write, fw_handle_direct_write},
{wil_fw_type_gateway_data, fw_handle_gateway_data},
{wil_fw_type_gateway_data4, fw_handle_gateway_data4},
};
static int wil_fw_handle_record(struct wil6210_priv *wil, int type,
const void *data, size_t size)
{
int i;
for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) {
if (wil_fw_handlers[i].type == type)
return wil_fw_handlers[i].handler(wil, data, size);
}
wil_err_fw(wil, "unknown record type: %d\n", type);
return -EINVAL;
}
/**
* wil_fw_load - load FW into device
*
* Load the FW and uCode code and data to the corresponding device
* memory regions
*
* Return error code
*/
static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
{
int rc = 0;
const struct wil_fw_record_head *hdr;
size_t s, hdr_sz;
for (hdr = data;; hdr = (const void *)hdr + s, size -= s) {
if (size < sizeof(*hdr))
break;
hdr_sz = le32_to_cpu(hdr->size);
s = sizeof(*hdr) + hdr_sz;
if (s > size)
break;
if (hdr_sz % 4) {
wil_err_fw(wil, "unaligned record size: %zu\n",
hdr_sz);
return -EINVAL;
}
rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type),
&hdr[1], hdr_sz);
if (rc)
return rc;
}
if (size) {
wil_err_fw(wil, "unprocessed bytes: %zu\n", size);
if (size >= sizeof(*hdr)) {
wil_err_fw(wil, "Stop at offset %ld"
" record type %d [%zd bytes]\n",
(const void *)hdr - data,
le16_to_cpu(hdr->type), hdr_sz);
}
return -EINVAL;
}
/* Mark FW as loaded from host */
S(RGF_USER_USAGE_6, 1);
return rc;
}
/**
* wil_request_firmware - Request firmware and load to device
*
* Request firmware image from the file and load it to device
*
* Return error code
*/
int wil_request_firmware(struct wil6210_priv *wil, const char *name)
{
int rc, rc1;
const struct firmware *fw;
size_t sz;
const void *d;
rc = request_firmware(&fw, name, wil_to_pcie_dev(wil));
if (rc) {
wil_err_fw(wil, "Failed to load firmware %s\n", name);
return rc;
}
wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) {
rc1 = wil_fw_verify(wil, d, sz);
if (rc1 < 0) {
rc = rc1;
goto out;
}
rc = wil_fw_load(wil, d, rc1);
if (rc < 0)
goto out;
}
out:
release_firmware(fw);
return rc;
}

View File

@ -135,7 +135,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
}
void wil6210_disable_irq(struct wil6210_priv *wil)
void wil_mask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@ -145,7 +145,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil)
wil6210_mask_irq_pseudo(wil);
}
void wil6210_enable_irq(struct wil6210_priv *wil)
void wil_unmask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@ -196,8 +196,13 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
if (test_bit(wil_status_reset_done, &wil->status)) {
wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
napi_schedule(&wil->napi_rx);
if (test_bit(wil_status_napi_en, &wil->status)) {
wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
napi_schedule(&wil->napi_rx);
} else {
wil_err(wil, "Got Rx interrupt while "
"stopping interface\n");
}
} else {
wil_err(wil, "Got Rx interrupt while in reset\n");
}
@ -506,7 +511,8 @@ free0:
return rc;
}
/* can't use wil_ioread32_and_clear because ICC value is not ser yet */
/* can't use wil_ioread32_and_clear because ICC value is not set yet */
static inline void wil_clear32(void __iomem *addr)
{
u32 x = ioread32(addr);
@ -522,11 +528,15 @@ void wil6210_clear_irq(struct wil6210_priv *wil)
offsetof(struct RGF_ICR, ICR));
wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR));
wmb(); /* make sure write completed */
}
int wil6210_init_irq(struct wil6210_priv *wil, int irq)
{
int rc;
wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi);
if (wil->n_msi == 3)
rc = wil6210_request_3msi(wil, irq);
else
@ -534,17 +544,14 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq)
wil6210_thread_irq,
wil->n_msi ? 0 : IRQF_SHARED,
WIL_NAME, wil);
if (rc)
return rc;
wil6210_enable_irq(wil);
return 0;
return rc;
}
void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
{
wil6210_disable_irq(wil);
wil_dbg_misc(wil, "%s()\n", __func__);
wil_mask_irq(wil);
free_irq(irq, wil);
if (wil->n_msi == 3) {
free_irq(irq + 1, wil);

View File

@ -20,11 +20,19 @@
#include "wil6210.h"
#include "txrx.h"
#include "wmi.h"
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
static bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
static bool no_fw_load = true;
module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
@ -67,6 +75,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wil_sta_info *sta = &wil->sta[cid];
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
sta->status);
@ -86,9 +95,16 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
}
for (i = 0; i < WIL_STA_TID_NUM; i++) {
struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
struct wil_tid_ampdu_rx *r;
unsigned long flags;
spin_lock_irqsave(&sta->tid_rx_lock, flags);
r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
}
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
if (wil->vring2cid_tid[i][0] == cid)
@ -205,10 +221,8 @@ static void wil_fw_error_worker(struct work_struct *work)
case NL80211_IFTYPE_MONITOR:
wil_info(wil, "fw error recovery started (try %d)...\n",
wil->recovery_count);
wil_reset(wil);
/* need to re-allocate Rx ring after reset */
wil_rx_init(wil);
__wil_down(wil);
__wil_up(wil);
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
@ -223,6 +237,7 @@ static void wil_fw_error_worker(struct work_struct *work)
static int wil_find_free_vring(struct wil6210_priv *wil)
{
int i;
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
if (!wil->vring_tx[i].va)
return i;
@ -257,14 +272,19 @@ static void wil_connect_worker(struct work_struct *work)
int wil_priv_init(struct wil6210_priv *wil)
{
uint i;
wil_dbg_misc(wil, "%s()\n", __func__);
memset(wil->sta, 0, sizeof(wil->sta));
for (i = 0; i < WIL6210_MAX_CID; i++)
spin_lock_init(&wil->sta[i].tid_rx_lock);
mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex);
init_completion(&wil->wmi_ready);
init_completion(&wil->wmi_call);
wil->pending_connect_cid = -1;
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
@ -295,12 +315,16 @@ int wil_priv_init(struct wil6210_priv *wil)
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
{
wil_dbg_misc(wil, "%s()\n", __func__);
del_timer_sync(&wil->connect_timer);
_wil6210_disconnect(wil, bssid);
}
void wil_priv_deinit(struct wil6210_priv *wil)
{
wil_dbg_misc(wil, "%s()\n", __func__);
del_timer_sync(&wil->scan_timer);
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
@ -312,6 +336,28 @@ void wil_priv_deinit(struct wil6210_priv *wil)
destroy_workqueue(wil->wmi_wq);
}
/* target operations */
/* register read */
#define R(a) ioread32(wil->csr + HOSTADDR(a))
/* register write. wmb() to make sure it is completed */
#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
/* register set = read, OR, write */
#define S(a, v) W(a, R(a) | v)
/* register clear = read, AND with inverted, write */
#define C(a, v) W(a, R(a) & ~v)
static inline void wil_halt_cpu(struct wil6210_priv *wil)
{
W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
}
static inline void wil_release_cpu(struct wil6210_priv *wil)
{
/* Start CPU */
W(RGF_USER_USER_CPU_0, 1);
}
static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
@ -321,60 +367,41 @@ static int wil_target_reset(struct wil6210_priv *wil)
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
/* register read */
#define R(a) ioread32(wil->csr + HOSTADDR(a))
/* register write */
#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
/* register set = read, OR, write */
#define S(a, v) W(a, R(a) | v)
/* register clear = read, AND with inverted, write */
#define C(a, v) W(a, R(a) & ~v)
wmb(); /* If host reorder writes here -> race in NIC */
W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
wil->hw_version = R(RGF_USER_FW_REV_ID);
rev_id = wil->hw_version & 0xff;
/* Clear MAC link up */
S(RGF_HP_CTRL, BIT(15));
/* hpal_perst_from_pad_src_n_mask */
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
/* car_perst_rst_src_n_mask */
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
wmb(); /* order is important here */
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
wil_halt_cpu(wil);
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
}
W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
wmb(); /* If host reorder writes here -> race in NIC */
W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
}
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
wmb(); /* order is important here */
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
/* reset A2 PCIE AHB */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
} else {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
if (rev_id == 1) {
@ -384,12 +411,10 @@ static int wil_target_reset(struct wil6210_priv *wil)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
}
}
/* TODO: check order here!!! Erez code is different */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
wmb(); /* order is important here */
/* wait until device ready. typical time is 200..250 msec */
do {
@ -407,16 +432,15 @@ static int wil_target_reset(struct wil6210_priv *wil)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
wmb(); /* order is important here */
wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
return 0;
}
#undef R
#undef W
#undef S
#undef C
}
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
{
@ -431,6 +455,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
{
ulong to = msecs_to_jiffies(1000);
ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
if (0 == left) {
wil_err(wil, "Firmware not ready\n");
return -ETIME;
@ -450,15 +475,15 @@ int wil_reset(struct wil6210_priv *wil)
{
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
WARN_ON(!mutex_is_locked(&wil->mutex));
WARN_ON(test_bit(wil_status_napi_en, &wil->status));
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL);
wil->status = 0; /* prevent NAPI from being scheduled */
if (test_bit(wil_status_napi_en, &wil->status)) {
napi_synchronize(&wil->napi_rx);
}
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@ -468,7 +493,7 @@ int wil_reset(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
wil6210_disable_irq(wil);
wil_mask_irq(wil);
wmi_event_flush(wil);
@ -480,13 +505,38 @@ int wil_reset(struct wil6210_priv *wil)
if (rc)
return rc;
if (!no_fw_load) {
wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
wil_halt_cpu(wil);
/* Loading f/w from the file */
rc = wil_request_firmware(wil, WIL_FW_NAME);
if (rc)
return rc;
/* clear any interrupts which on-card-firmware may have set */
wil6210_clear_irq(wil);
{ /* CAF_ICR - clear and mask */
u32 a = HOSTADDR(RGF_CAF_ICR) +
offsetof(struct RGF_ICR, ICR);
u32 m = HOSTADDR(RGF_CAF_ICR) +
offsetof(struct RGF_ICR, IMV);
u32 icr = ioread32(wil->csr + a);
iowrite32(icr, wil->csr + a); /* W1C */
iowrite32(~0, wil->csr + m);
wmb(); /* wait for completion */
}
wil_release_cpu(wil);
} else {
wil_info(wil, "Use firmware from on-card flash\n");
}
/* init after reset */
wil->pending_connect_cid = -1;
reinit_completion(&wil->wmi_ready);
reinit_completion(&wil->wmi_call);
/* TODO: release MAC reset */
wil6210_enable_irq(wil);
wil_unmask_irq(wil);
/* we just started MAC, wait for FW ready */
rc = wil_wait_for_fw_ready(wil);
@ -522,7 +572,7 @@ void wil_link_off(struct wil6210_priv *wil)
netif_carrier_off(ndev);
}
static int __wil_up(struct wil6210_priv *wil)
int __wil_up(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
@ -568,11 +618,15 @@ static int __wil_up(struct wil6210_priv *wil)
/* MAC address - pre-requisite for other commands */
wmi_set_mac_address(wil, ndev->dev_addr);
wil_dbg_misc(wil, "NAPI enable\n");
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
set_bit(wil_status_napi_en, &wil->status);
if (wil->platform_ops.bus_request)
wil->platform_ops.bus_request(wil->platform_handle,
WIL_MAX_BUS_REQUEST_KBPS);
return 0;
}
@ -580,6 +634,8 @@ int wil_up(struct wil6210_priv *wil)
{
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
mutex_lock(&wil->mutex);
rc = __wil_up(wil);
mutex_unlock(&wil->mutex);
@ -587,13 +643,23 @@ int wil_up(struct wil6210_priv *wil)
return rc;
}
static int __wil_down(struct wil6210_priv *wil)
int __wil_down(struct wil6210_priv *wil)
{
int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
WAIT_FOR_DISCONNECT_INTERVAL_MS;
WARN_ON(!mutex_is_locked(&wil->mutex));
clear_bit(wil_status_napi_en, &wil->status);
napi_disable(&wil->napi_rx);
napi_disable(&wil->napi_tx);
if (wil->platform_ops.bus_request)
wil->platform_ops.bus_request(wil->platform_handle, 0);
wil_disable_irq(wil);
if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
napi_disable(&wil->napi_rx);
napi_disable(&wil->napi_tx);
wil_dbg_misc(wil, "NAPI disable\n");
}
wil_enable_irq(wil);
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@ -603,7 +669,24 @@ static int __wil_down(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
wil6210_disconnect(wil, NULL);
if (test_bit(wil_status_fwconnected, &wil->status) ||
test_bit(wil_status_fwconnecting, &wil->status))
wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
/* make sure wil is idle (not connected) */
mutex_unlock(&wil->mutex);
while (iter--) {
int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
!test_bit(wil_status_fwconnecting, &wil->status);
if (idle)
break;
msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
}
mutex_lock(&wil->mutex);
if (!iter)
wil_err(wil, "timeout waiting for idle FW/HW\n");
wil_rx_fini(wil);
return 0;
@ -613,6 +696,8 @@ int wil_down(struct wil6210_priv *wil)
{
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
mutex_lock(&wil->mutex);
rc = __wil_down(wil);
mutex_unlock(&wil->mutex);

View File

@ -17,11 +17,14 @@
#include <linux/etherdevice.h>
#include "wil6210.h"
#include "txrx.h"
static int wil_open(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
wil_dbg_misc(wil, "%s()\n", __func__);
return wil_up(wil);
}
@ -29,6 +32,8 @@ static int wil_stop(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
wil_dbg_misc(wil, "%s()\n", __func__);
return wil_down(wil);
}
@ -36,8 +41,10 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG)
if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) {
wil_err(wil, "invalid MTU %d\n", new_mtu);
return -EINVAL;
}
wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu);
ndev->mtu = new_mtu;
@ -121,6 +128,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
wil->csr = csr;
wil->wdev = wdev;
wil_dbg_misc(wil, "%s()\n", __func__);
rc = wil_priv_init(wil);
if (rc) {
dev_err(dev, "wil_priv_init failed\n");
@ -169,6 +178,8 @@ void wil_if_free(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
wil_dbg_misc(wil, "%s()\n", __func__);
if (!ndev)
return;
@ -185,6 +196,8 @@ int wil_if_add(struct wil6210_priv *wil)
struct net_device *ndev = wil_to_ndev(wil);
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
rc = register_netdev(ndev);
if (rc < 0) {
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
@ -200,5 +213,7 @@ void wil_if_remove(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
wil_dbg_misc(wil, "%s()\n", __func__);
unregister_netdev(ndev);
}

View File

@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include "wil6210.h"
@ -30,6 +31,28 @@ static bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
void wil_disable_irq(struct wil6210_priv *wil)
{
int irq = wil->pdev->irq;
disable_irq(irq);
if (wil->n_msi == 3) {
disable_irq(irq + 1);
disable_irq(irq + 2);
}
}
void wil_enable_irq(struct wil6210_priv *wil)
{
int irq = wil->pdev->irq;
enable_irq(irq);
if (wil->n_msi == 3) {
enable_irq(irq + 1);
enable_irq(irq + 2);
}
}
/* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil)
{
@ -41,6 +64,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
*/
int msi_only = pdev->msi_enabled;
wil_dbg_misc(wil, "%s()\n", __func__);
pdev->msi_enabled = 0;
pci_set_master(pdev);
@ -107,6 +132,8 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil)
{
struct pci_dev *pdev = wil->pdev;
wil_dbg_misc(wil, "%s()\n", __func__);
pci_clear_master(pdev);
/* disable and release IRQ */
wil6210_fini_irq(wil, pdev->irq);
@ -180,6 +207,10 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
wil->board = board;
wil6210_clear_irq(wil);
wil->platform_handle =
wil_platform_init(&pdev->dev, &wil->platform_ops);
/* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil);
if (rc) {
@ -204,6 +235,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
bus_disable:
wil_if_pcie_disable(wil);
if_free:
if (wil->platform_ops.uninit)
wil->platform_ops.uninit(wil->platform_handle);
wil_if_free(wil);
err_iounmap:
pci_iounmap(pdev, csr);
@ -220,9 +253,13 @@ static void wil_pcie_remove(struct pci_dev *pdev)
struct wil6210_priv *wil = pci_get_drvdata(pdev);
void __iomem *csr = wil->csr;
wil_dbg_misc(wil, "%s()\n", __func__);
wil6210_debugfs_remove(wil);
wil_if_pcie_disable(wil);
wil_if_remove(wil);
wil_if_pcie_disable(wil);
if (wil->platform_ops.uninit)
wil->platform_ops.uninit(wil->platform_handle);
wil_if_free(wil);
pci_iounmap(pdev, csr);
pci_release_region(pdev, 0);

View File

@ -98,22 +98,25 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
int mid = wil_rxdesc_mid(d);
u16 seq = wil_rxdesc_seq(d);
struct wil_sta_info *sta = &wil->sta[cid];
struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
struct wil_tid_ampdu_rx *r;
u16 hseq;
int index;
unsigned long flags;
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
mid, cid, tid, seq);
spin_lock_irqsave(&sta->tid_rx_lock, flags);
r = sta->tid_rx[tid];
if (!r) {
spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
wil_netif_rx_any(skb, ndev);
return;
}
hseq = r->head_seq_num;
spin_lock(&r->reorder_lock);
/** Due to the race between WMI events, where BACK establishment
* reported, and data Rx, few packets may be pass up before reorder
* buffer get allocated. Catch up by pretending SSN is what we
@ -176,13 +179,14 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
wil_reorder_release(wil, r);
out:
spin_unlock(&r->reorder_lock);
spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
}
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
int size, u16 ssn)
{
struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
if (!r)
return NULL;
@ -197,7 +201,6 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
return NULL;
}
spin_lock_init(&r->reorder_lock);
r->ssn = ssn;
r->head_seq_num = ssn;
r->buf_size = size;

View File

@ -52,6 +52,7 @@ static inline int wil_vring_is_full(struct vring *vring)
{
return wil_vring_next_tail(vring) == vring->swhead;
}
/*
* Available space in Tx Vring
*/
@ -86,6 +87,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
size_t sz = vring->size * sizeof(vring->va[0]);
uint i;
wil_dbg_misc(wil, "%s()\n", __func__);
BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
vring->swhead = 0;
@ -110,7 +113,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
* we can use any
*/
for (i = 0; i < vring->size; i++) {
volatile struct vring_tx_desc *_d = &(vring->va[i].tx);
volatile struct vring_tx_desc *_d = &vring->va[i].tx;
_d->dma.status = TX_DMA_STATUS_DU;
}
@ -125,6 +129,7 @@ static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d,
{
dma_addr_t pa = wil_desc_addr(&d->dma.addr);
u16 dmalen = le16_to_cpu(d->dma.length);
switch (ctx->mapped_as) {
case wil_mapped_as_single:
dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
@ -143,6 +148,18 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil);
size_t sz = vring->size * sizeof(vring->va[0]);
if (tx) {
int vring_index = vring - wil->vring_tx;
wil_dbg_misc(wil, "free Tx vring %d [%d] 0x%p:%pad 0x%p\n",
vring_index, vring->size, vring->va,
&vring->pa, vring->ctx);
} else {
wil_dbg_misc(wil, "free Rx vring [%d] 0x%p:%pad 0x%p\n",
vring->size, vring->va,
&vring->pa, vring->ctx);
}
while (!wil_vring_is_empty(vring)) {
dma_addr_t pa;
u16 dmalen;
@ -191,11 +208,12 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil);
unsigned int sz = RX_BUF_LEN;
struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d = &(vring->va[i].rx);
volatile struct vring_rx_desc *_d = &vring->va[i].rx;
dma_addr_t pa;
/* TODO align */
struct sk_buff *skb = dev_alloc_skb(sz + headroom);
if (unlikely(!skb))
return -ENOMEM;
@ -274,9 +292,11 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
*/
int len = min_t(int, 8 + sizeof(phy_data),
wil_rxdesc_phy_length(d));
if (len > 8) {
void *p = skb_tail_pointer(skb);
void *pa = PTR_ALIGN(p, 8);
if (skb_tailroom(skb) >= len + (pa - p)) {
phy_length = len - 8;
memcpy(phy_data, pa, phy_length);
@ -372,13 +392,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
int cid;
struct wil_net_stats *stats;
BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
if (wil_vring_is_empty(vring))
return NULL;
_d = &(vring->va[vring->swhead].rx);
_d = &vring->va[vring->swhead].rx;
if (!(_d->dma.status & RX_DMA_STATUS_DU)) {
/* it is not error, we just reached end of Rx done area */
return NULL;
@ -532,7 +551,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
[GRO_NORMAL] = "GRO_NORMAL",
[GRO_DROP] = "GRO_DROP",
};
wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n",
wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
len, gro_res_str[rc]);
}
}
@ -573,7 +592,6 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
else
wil_netif_rx_any(skb, ndev);
}
}
wil_rx_refill(wil, v->size);
}
@ -583,6 +601,8 @@ int wil_rx_init(struct wil6210_priv *wil)
struct vring *vring = &wil->vring_rx;
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
if (vring->va) {
wil_err(wil, "Rx ring already allocated\n");
return -EINVAL;
@ -612,6 +632,8 @@ void wil_rx_fini(struct wil6210_priv *wil)
{
struct vring *vring = &wil->vring_rx;
wil_dbg_misc(wil, "%s()\n", __func__);
if (vring->va)
wil_vring_free(wil, vring, 0);
}
@ -646,6 +668,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
struct vring *vring = &wil->vring_tx[id];
struct vring_tx_data *txdata = &wil->vring_tx_data[id];
wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id);
rc = -EINVAL;
@ -695,6 +720,8 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
if (!vring->va)
return;
wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
/* make sure NAPI won't touch this vring */
wil->vring_tx_data[id].enabled = 0;
if (test_bit(wil_status_napi_en, &wil->status))
@ -721,6 +748,7 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
if (wil->vring2cid_tid[i][0] == cid) {
struct vring *v = &wil->vring_tx[i];
wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
__func__, eth->h_dest, i);
if (v->va) {
@ -740,6 +768,7 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
{
struct ethhdr *eth = (void *)skb->data;
int cid = wil->vring2cid_tid[vring_index][0];
memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
}
@ -750,7 +779,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
* duplicate skb and send it to other active vrings
*/
static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
struct sk_buff *skb)
struct sk_buff *skb)
{
struct vring *v, *v2;
struct sk_buff *skb2;
@ -833,8 +862,8 @@ void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
}
static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
struct vring_tx_desc *d,
struct sk_buff *skb)
struct vring_tx_desc *d,
struct sk_buff *skb)
{
int protocol;
@ -902,10 +931,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
1 + nr_frags);
return -ENOMEM;
}
_d = &(vring->va[i].tx);
_d = &vring->va[i].tx;
pa = dma_map_single(dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb),
skb->data, &pa);
@ -934,10 +962,11 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
const struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[f];
int len = skb_frag_size(frag);
i = (swhead + f + 1) % vring->size;
_d = &(vring->va[i].tx);
_d = &vring->va[i].tx;
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
DMA_TO_DEVICE);
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, pa)))
goto dma_error;
vring->ctx[i].mapped_as = wil_mapped_as_page;
@ -982,7 +1011,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
i = (swhead + f) % vring->size;
ctx = &vring->ctx[i];
_d = &(vring->va[i].tx);
_d = &vring->va[i].tx;
*d = *_d;
_d->dma.status = TX_DMA_STATUS_DU;
wil_txdesc_unmap(dev, d, ctx);
@ -996,7 +1025,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
return -EINVAL;
}
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
@ -1024,15 +1052,15 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
pr_once_fw = false;
/* find vring */
if (is_unicast_ether_addr(eth->h_dest)) {
if (is_unicast_ether_addr(eth->h_dest))
vring = wil_find_tx_vring(wil, skb);
} else {
else
vring = wil_tx_bcast(wil, skb);
}
if (!vring) {
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop;
}
/* set up vring entry */
rc = wil_tx_vring(wil, vring, skb);

View File

@ -20,9 +20,9 @@
#define BUF_SW_OWNED (1)
#define BUF_HW_OWNED (0)
/* size of max. Rx packet */
#define RX_BUF_LEN (2048)
#define TX_BUF_LEN (2048)
/* size of max. Tx/Rx buffers, as supported by FW */
#define RX_BUF_LEN (2242)
#define TX_BUF_LEN (2242)
/* how many bytes to reserve for rtap header? */
#define WIL6210_RTAP_SIZE (128)
@ -237,7 +237,6 @@ struct vring_tx_mac {
#define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 /* L4 type: 0-UDP, 2-TCP */
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_POS 0
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_LEN 7
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_MSK 0x7F /* MAC hdr len */
@ -246,7 +245,6 @@ struct vring_tx_mac {
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_LEN 1
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_MSK 0x80 /* 1-IPv4, 0-IPv6 */
#define TX_DMA_STATUS_DU BIT(0)
struct vring_tx_dma {
@ -347,7 +345,6 @@ struct vring_rx_mac {
#define RX_DMA_ERROR_L3_ERR BIT(4)
#define RX_DMA_ERROR_L4_ERR BIT(5)
/* Status field */
#define RX_DMA_STATUS_DU BIT(0)
#define RX_DMA_STATUS_ERROR BIT(2)

View File

@ -21,8 +21,13 @@
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/timex.h>
#include "wil_platform.h"
#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw"
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
struct wil_board {
int board;
@ -86,22 +91,29 @@ struct RGF_ICR {
/* registers - FW addresses */
#define RGF_USER_USAGE_1 (0x880004)
#define RGF_USER_USAGE_6 (0x880018)
#define RGF_USER_HW_MACHINE_STATE (0x8801dc)
#define HW_MACHINE_BOOT_DONE (0x3fffffd)
#define RGF_USER_USER_CPU_0 (0x8801e0)
#define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */
#define RGF_USER_MAC_CPU_0 (0x8801fc)
#define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */
#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */
#define RGF_USER_CLKS_CTL_0 (0x880abc)
#define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */
#define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */
#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10)
#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
#define BIT_HPAL_PERST_FROM_PAD BIT(6)
#define BIT_CAR_PERST_RST BIT(7)
#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
#define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c)
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
@ -136,6 +148,8 @@ struct RGF_ICR {
/* MAC timer, usec, for packet lifetime */
#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
#define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@ -154,6 +168,7 @@ struct fw_map {
u32 host; /* PCI/Host address - BAR0 + 0x880000 */
const char *name; /* for debugfs */
};
/* array size should be in sync with actual definition in the wmi.c */
extern const struct fw_map fw_mapping[7];
@ -303,18 +318,12 @@ struct pci_dev;
* @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
* @rcu_head: RCU head used for freeing this struct
* @reorder_lock: serializes access to reorder buffer, see below.
*
* This structure's lifetime is managed by RCU, assignments to
* the array holding it must hold the aggregation mutex.
*
* The @reorder_lock is used to protect the members of this
* struct, except for @timeout, @buf_size and @dialog_token,
* which are constant across the lifetime of the struct (the
* dialog token being used only for debugging).
*/
struct wil_tid_ampdu_rx {
spinlock_t reorder_lock; /* see above */
struct sk_buff **reorder_buf;
unsigned long *reorder_time;
struct timer_list session_timer;
@ -363,6 +372,7 @@ struct wil_sta_info {
bool data_port_open; /* can send any data, not only EAPOL */
/* Rx BACK */
struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
spinlock_t tid_rx_lock; /* guarding tid_rx array */
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
};
@ -389,6 +399,7 @@ struct wil6210_priv {
struct mutex wmi_mutex;
struct wil6210_mbox_ctl mbox_ctl;
struct completion wmi_ready;
struct completion wmi_call;
u16 wmi_seq;
u16 reply_id; /**< wait for this WMI event */
void *reply_buf;
@ -426,6 +437,9 @@ struct wil6210_priv {
/* debugfs */
struct dentry *debug;
struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
void *platform_handle;
struct wil_platform_ops platform_ops;
};
#define wil_to_wiphy(i) (i->wdev->wiphy)
@ -435,10 +449,11 @@ struct wil6210_priv {
#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
#define wil_to_pcie_dev(i) (&i->pdev->dev)
int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
int wil_err(struct wil6210_priv *wil, const char *fmt, ...);
int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
wil_dbg_trace(wil, fmt, ##arg); \
@ -449,6 +464,7 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
#if defined(CONFIG_DYNAMIC_DEBUG)
#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
print_hex_dump_debug("DBG[TXRX]" prefix_str,\
@ -460,6 +476,19 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
print_hex_dump_debug("DBG[ WMI]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
#else /* defined(CONFIG_DYNAMIC_DEBUG) */
static inline
void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize,
int groupsize, const void *buf, size_t len, bool ascii)
{
}
static inline
void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize,
int groupsize, const void *buf, size_t len, bool ascii)
{
}
#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count);
@ -477,7 +506,9 @@ void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_link_on(struct wil6210_priv *wil);
void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
int __wil_down(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
@ -510,8 +541,10 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
void wil6210_clear_irq(struct wil6210_priv *wil);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
void wil6210_disable_irq(struct wil6210_priv *wil);
void wil6210_enable_irq(struct wil6210_priv *wil);
void wil_mask_irq(struct wil6210_priv *wil);
void wil_unmask_irq(struct wil6210_priv *wil);
void wil_disable_irq(struct wil6210_priv *wil);
void wil_enable_irq(struct wil6210_priv *wil);
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
u64 *cookie);
@ -547,4 +580,5 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
int wil_iftype_nl2wmi(enum nl80211_iftype type);
int wil_request_firmware(struct wil6210_priv *wil, const char *name);
#endif /* __WIL6210_H__ */

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "linux/device.h"
#include "wil_platform.h"
#ifdef CONFIG_WIL6210_PLATFORM_MSM
#include "wil_platform_msm.h"
#endif
/**
* wil_platform_init() - wil6210 platform module init
*
* The function must be called before all other functions in this module.
* It returns a handle which is used with the rest of the API
*
*/
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
{
void *handle = NULL;
if (!ops) {
dev_err(dev, "Invalid parameter. Cannot init platform module\n");
return NULL;
}
#ifdef CONFIG_WIL6210_PLATFORM_MSM
handle = wil_platform_msm_init(dev, ops);
if (handle)
return handle;
#endif
/* other platform specific init functions should be called here */
return handle;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __WIL_PLATFORM_H__
#define __WIL_PLATFORM_H__
struct device;
/**
* struct wil_platform_ops - wil platform module callbacks
*/
struct wil_platform_ops {
int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */);
int (*suspend)(void *handle);
int (*resume)(void *handle);
void (*uninit)(void *handle);
};
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
#endif /* __WIL_PLATFORM_H__ */

View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/msm-bus.h>
#include "wil_platform.h"
#include "wil_platform_msm.h"
/**
* struct wil_platform_msm - wil6210 msm platform module info
*
* @dev: device object
* @msm_bus_handle: handle for using msm_bus API
* @pdata: bus scale info retrieved from DT
*/
struct wil_platform_msm {
struct device *dev;
uint32_t msm_bus_handle;
struct msm_bus_scale_pdata *pdata;
};
#define KBTOB(a) (a * 1000ULL)
/**
* wil_platform_get_pdata() - Generate bus client data from device tree
* provided by clients.
*
* dev: device object
* of_node: Device tree node to extract information from
*
* The function returns a valid pointer to the allocated bus-scale-pdata
* if the vectors were correctly read from the client's device node.
* Any error in reading or parsing the device node will return NULL
* to the caller.
*/
static struct msm_bus_scale_pdata *wil_platform_get_pdata(
struct device *dev,
struct device_node *of_node)
{
struct msm_bus_scale_pdata *pdata;
struct msm_bus_paths *usecase;
int i, j, ret, len;
unsigned int num_usecases, num_paths, mem_size;
const uint32_t *vec_arr;
struct msm_bus_vectors *vectors;
/* first read num_usecases and num_paths so we can calculate
* amount of memory to allocate
*/
ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
&num_usecases);
if (ret) {
dev_err(dev, "Error: num-usecases not found\n");
return NULL;
}
ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
&num_paths);
if (ret) {
dev_err(dev, "Error: num_paths not found\n");
return NULL;
}
/* pdata memory layout:
* msm_bus_scale_pdata
* msm_bus_paths[num_usecases]
* msm_bus_vectors[num_usecases][num_paths]
*/
mem_size = sizeof(struct msm_bus_scale_pdata) +
sizeof(struct msm_bus_paths) * num_usecases +
sizeof(struct msm_bus_vectors) * num_usecases * num_paths;
pdata = kzalloc(mem_size, GFP_KERNEL);
if (!pdata)
return NULL;
ret = of_property_read_string(of_node, "qcom,msm-bus,name",
&pdata->name);
if (ret) {
dev_err(dev, "Error: Client name not found\n");
goto err;
}
if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) {
pdata->active_only = 1;
} else {
dev_info(dev, "active_only flag absent.\n");
dev_info(dev, "Using dual context by default\n");
}
pdata->num_usecases = num_usecases;
pdata->usecase = (struct msm_bus_paths *)(pdata + 1);
vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
if (vec_arr == NULL) {
dev_err(dev, "Error: Vector array not found\n");
goto err;
}
if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
dev_err(dev, "Error: Length-error on getting vectors\n");
goto err;
}
vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases);
for (i = 0; i < num_usecases; i++) {
usecase = &pdata->usecase[i];
usecase->num_paths = num_paths;
usecase->vectors = &vectors[i];
for (j = 0; j < num_paths; j++) {
int index = ((i * num_paths) + j) * 4;
usecase->vectors[j].src = be32_to_cpu(vec_arr[index]);
usecase->vectors[j].dst =
be32_to_cpu(vec_arr[index + 1]);
usecase->vectors[j].ab = (uint64_t)
KBTOB(be32_to_cpu(vec_arr[index + 2]));
usecase->vectors[j].ib = (uint64_t)
KBTOB(be32_to_cpu(vec_arr[index + 3]));
}
}
return pdata;
err:
kfree(pdata);
return NULL;
}
/* wil_platform API (callbacks) */
static int wil_platform_bus_request(void *handle,
uint32_t kbps /* KBytes/Sec */)
{
int rc, i;
struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
struct msm_bus_paths *usecase;
uint32_t usecase_kbps;
uint32_t min_kbps = ~0;
/* find the lowest usecase that is bigger than requested kbps */
for (i = 0; i < msm->pdata->num_usecases; i++) {
usecase = &msm->pdata->usecase[i];
/* assume we have single path (vectors[0]). If we ever
* have multiple paths, need to define the behavior */
usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
min_kbps = usecase_kbps;
vote = i;
}
}
rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote);
if (rc)
dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
kbps, vote, rc);
else
/* TOOD: remove */
dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
kbps, vote);
return rc;
}
static void wil_platform_uninit(void *handle)
{
struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
dev_info(msm->dev, "wil_platform_uninit\n");
if (msm->msm_bus_handle)
msm_bus_scale_unregister_client(msm->msm_bus_handle);
kfree(msm->pdata);
kfree(msm);
}
static int wil_platform_msm_bus_register(struct wil_platform_msm *msm,
struct device_node *node)
{
msm->pdata = wil_platform_get_pdata(msm->dev, node);
if (!msm->pdata) {
dev_err(msm->dev, "Failed getting DT info\n");
return -EINVAL;
}
msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata);
if (!msm->msm_bus_handle) {
dev_err(msm->dev, "Failed msm_bus registration\n");
return -EINVAL;
}
dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n",
msm->msm_bus_handle);
return 0;
}
/**
* wil_platform_msm_init() - wil6210 msm platform module init
*
* The function must be called before all other functions in this module.
* It returns a handle which is used with the rest of the API
*
*/
void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops)
{
struct device_node *of_node;
struct wil_platform_msm *msm;
int rc;
of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210");
if (!of_node) {
/* this could mean non-msm platform */
dev_err(dev, "DT node not found\n");
return NULL;
}
msm = kzalloc(sizeof(*msm), GFP_KERNEL);
if (!msm)
return NULL;
msm->dev = dev;
/* register with msm_bus module for scaling requests */
rc = wil_platform_msm_bus_register(msm, of_node);
if (rc)
goto cleanup;
memset(ops, 0, sizeof(*ops));
ops->bus_request = wil_platform_bus_request;
ops->uninit = wil_platform_uninit;
return (void *)msm;
cleanup:
kfree(msm);
return NULL;
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __WIL_PLATFORM__MSM_H__
#define __WIL_PLATFORM_MSM_H__
#include "wil_platform.h"
void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops);
#endif /* __WIL_PLATFORM__MSM_H__ */

View File

@ -157,6 +157,7 @@ int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
struct wil6210_mbox_hdr *hdr)
{
void __iomem *src = wmi_buffer(wil, ptr);
if (!src)
return -EINVAL;
@ -278,6 +279,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wmi_ready_event *evt = d;
wil->fw_version = le32_to_cpu(evt->sw_version);
wil->n_mids = evt->numof_additional_mids;
@ -298,7 +300,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
wil_dbg_wmi(wil, "WMI: got FW ready event\n");
set_bit(wil_status_fwready, &wil->status);
/* reuse wmi_ready for the firmware ready indication */
/* let the reset sequence continue */
complete(&wil->wmi_ready);
}
@ -595,27 +597,40 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
return;
}
mutex_lock(&wil->mutex);
cid = wil->vring2cid_tid[evt->ringid][0];
if (cid >= WIL6210_MAX_CID) {
wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
return;
goto out;
}
sta = &wil->sta[cid];
if (sta->status == wil_sta_unused) {
wil_err(wil, "CID %d unused\n", cid);
return;
goto out;
}
wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
for (i = 0; i < WIL_STA_TID_NUM; i++) {
struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
struct wil_tid_ampdu_rx *r;
unsigned long flags;
spin_lock_irqsave(&sta->tid_rx_lock, flags);
r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
evt->agg_wsize, 0);
}
out:
mutex_unlock(&wil->mutex);
}
static const struct {
@ -653,7 +668,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
unsigned n;
if (!test_bit(wil_status_reset_done, &wil->status)) {
wil_err(wil, "Reset not completed\n");
wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
return;
}
@ -708,6 +723,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
u16 id = le16_to_cpu(wmi->id);
u32 tstamp = le32_to_cpu(wmi->timestamp);
wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
id, wmi->mid, tstamp);
trace_wil6210_wmi_event(wmi, &wmi[1],
@ -748,8 +764,8 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
wil->reply_id = reply_id;
wil->reply_buf = reply;
wil->reply_size = reply_size;
remain = wait_for_completion_timeout(&wil->wmi_ready,
msecs_to_jiffies(to_msec));
remain = wait_for_completion_timeout(&wil->wmi_call,
msecs_to_jiffies(to_msec));
if (0 == remain) {
wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
cmdid, reply_id, to_msec);
@ -953,8 +969,11 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
int rc;
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
if (!cmd)
return -ENOMEM;
if (!ie)
ie_len = 0;
cmd->mgmt_frm_type = type;
/* BUG: FW API define ieLen as u8. Will fix FW */
@ -1128,6 +1147,9 @@ static void wmi_event_handle(struct wil6210_priv *wil,
struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
void *evt_data = (void *)(&wmi[1]);
u16 id = le16_to_cpu(wmi->id);
wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
id, wil->reply_id);
/* check if someone waits for this event */
if (wil->reply_id && wil->reply_id == id) {
if (wil->reply_buf) {
@ -1138,7 +1160,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
len - sizeof(*wmi));
}
wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
complete(&wil->wmi_ready);
complete(&wil->wmi_call);
return;
}
/* unsolicited event */
@ -1184,9 +1206,11 @@ void wmi_event_worker(struct work_struct *work)
struct pending_wmi_event *evt;
struct list_head *lh;
wil_dbg_wmi(wil, "Start %s\n", __func__);
while ((lh = next_wmi_ev(wil)) != NULL) {
evt = list_entry(lh, struct pending_wmi_event, list);
wmi_event_handle(wil, &evt->event.hdr);
kfree(evt);
}
wil_dbg_wmi(wil, "Finished %s\n", __func__);
}

View File

@ -179,7 +179,6 @@ enum wmi_crypto_type {
WMI_CRYPT_AES_GCMP = 0x20,
};
enum wmi_connect_ctrl_flag_bits {
WMI_CONNECT_ASSOC_POLICY_USER = 0x0001,
WMI_CONNECT_SEND_REASSOC = 0x0002,
@ -219,7 +218,6 @@ struct wmi_disconnect_sta_cmd {
__le16 disconnect_reason;
} __packed;
/*
* WMI_SET_PMK_CMDID
*/
@ -234,7 +232,6 @@ struct wmi_set_pmk_cmd {
u8 pmk[WMI_PMK_LEN];
} __packed;
/*
* WMI_SET_PASSPHRASE_CMDID
*/
@ -273,7 +270,6 @@ struct wmi_delete_cipher_key_cmd {
u8 mac[WMI_MAC_LEN];
} __packed;
/*
* WMI_START_SCAN_CMDID
*
@ -325,7 +321,6 @@ struct wmi_probed_ssid_cmd {
u8 ssid[WMI_MAX_SSID_LEN];
} __packed;
/*
* WMI_SET_APPIE_CMDID
* Add Application specified IE to a management frame
@ -351,7 +346,6 @@ struct wmi_set_appie_cmd {
u8 ie_info[0];
} __packed;
/*
* WMI_PXMT_RANGE_CFG_CMDID
*/
@ -380,7 +374,6 @@ struct wmi_rf_mgmt_cmd {
__le32 rf_mgmt_type;
} __packed;
/*
* WMI_RF_RX_TEST_CMDID
*/
@ -426,7 +419,6 @@ struct wmi_bcon_ctrl_cmd {
u8 disable_sec;
} __packed;
/******* P2P ***********/
/*
@ -797,7 +789,6 @@ struct wmi_temp_sense_cmd {
__le32 measure_marlon_r_en;
} __packed;
/*
* WMI Events
*/
@ -887,7 +878,6 @@ enum wmi_event_id {
* Events data structures
*/
enum wmi_fw_status {
WMI_FW_STATUS_SUCCESS,
WMI_FW_STATUS_FAILURE,
@ -1038,8 +1028,8 @@ struct wmi_disconnect_event {
__le16 protocol_reason_status; /* reason code, see 802.11 spec. */
u8 bssid[WMI_MAC_LEN]; /* set if known */
u8 disconnect_reason; /* see wmi_disconnect_reason */
u8 assoc_resp_len; /* not in use */
u8 assoc_info[0]; /* not in use */
u8 assoc_resp_len; /* not used */
u8 assoc_info[0]; /* not used */
} __packed;
/*
@ -1081,7 +1071,6 @@ struct wmi_delba_event {
__le16 reason;
} __packed;
/*
* WMI_VRING_CFG_DONE_EVENTID
*/
@ -1147,7 +1136,6 @@ struct wmi_data_port_open_event {
u8 reserved[3];
} __packed;
/*
* WMI_GET_PCP_CHANNEL_EVENTID
*/
@ -1156,7 +1144,6 @@ struct wmi_get_pcp_channel_event {
u8 reserved[3];
} __packed;
/*
* WMI_PORT_ALLOCATED_EVENTID
*/
@ -1260,7 +1247,6 @@ struct wmi_rx_mgmt_info {
u8 channel; /* From Radio MNGR */
} __packed;
/*
* WMI_TX_MGMT_PACKET_EVENTID
*/

View File

@ -45,6 +45,7 @@
#define B43_MMIO_RAM_DATA 0x134
#define B43_MMIO_PS_STATUS 0x140
#define B43_MMIO_RADIO_HWENABLED_HI 0x158
#define B43_MMIO_MAC_HW_CAP 0x15C /* MAC capabilities (corerev >= 13) */
#define B43_MMIO_SHM_CONTROL 0x160
#define B43_MMIO_SHM_DATA 0x164
#define B43_MMIO_SHM_DATA_UNALIGNED 0x166
@ -253,6 +254,8 @@ enum {
#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */
#define B43_SHM_SH_CHAN_40MHZ 0x0200 /* Bit set, if 40 Mhz channel width */
#define B43_SHM_SH_MACHW_L 0x00C0 /* Location where the ucode expects the MAC capabilities */
#define B43_SHM_SH_MACHW_H 0x00C2 /* Location where the ucode expects the MAC capabilities */
#define B43_SHM_SH_HOSTF5 0x00D4 /* Hostflags 5 for ucode options */
#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* TSSI information */
@ -297,6 +300,7 @@ enum {
#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */
#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */
#define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */
#define B43_SHM_SH_BCN_LI 0x00B6 /* beacon listen interval */
/* SHM_SHARED ACK/CTS control */
#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */
/* SHM_SHARED probe response variables */
@ -476,6 +480,11 @@ enum {
#define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */
#define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */
/* B43_MMIO_PSM_PHY_HDR bits */
#define B43_PSM_HDR_MAC_PHY_RESET 0x00000001
#define B43_PSM_HDR_MAC_PHY_CLOCK_EN 0x00000002
#define B43_PSM_HDR_MAC_PHY_FORCE_CLK 0x00000004
/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
#define B43_BCMA_CLKCTLST_80211_PLL_REQ 0x00000100
#define B43_BCMA_CLKCTLST_PHY_PLL_REQ 0x00000200

View File

@ -1204,6 +1204,36 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
}
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */
void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
{
struct bcma_drv_cc *bcma_cc __maybe_unused;
struct ssb_chipcommon *ssb_cc __maybe_unused;
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
bcma_cc = &dev->dev->bdev->bus->drv_cc;
bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
break;
#endif
#ifdef CONFIG_B43_SSB
case B43_BUS_SSB:
ssb_cc = &dev->dev->sdev->bus->chipco;
chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0);
chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4);
chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
break;
#endif
}
}
#ifdef CONFIG_B43_BCMA
static void b43_bcma_phy_reset(struct b43_wldev *dev)
{
@ -2985,7 +3015,22 @@ void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode)
{
u16 chip_id = dev->dev->chip_id;
if (chip_id == BCMA_CHIP_ID_BCM43131 ||
if (chip_id == BCMA_CHIP_ID_BCM4331) {
switch (spurmode) {
case 2: /* 168 Mhz: 2^26/168 = 0x61862 */
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x1862);
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
break;
case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x3e70);
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
break;
default: /* 160 Mhz: 2^26/160 = 0x66666 */
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x6666);
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
break;
}
} else if (chip_id == BCMA_CHIP_ID_BCM43131 ||
chip_id == BCMA_CHIP_ID_BCM43217 ||
chip_id == BCMA_CHIP_ID_BCM43222 ||
chip_id == BCMA_CHIP_ID_BCM43224 ||
@ -3106,6 +3151,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
case B43_PHYTYPE_HT:
case B43_PHYTYPE_LCN:
b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_9MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
@ -3884,6 +3930,12 @@ static int b43_switch_band(struct b43_wldev *dev,
return 0;
}
static void b43_set_beacon_listen_interval(struct b43_wldev *dev, u16 interval)
{
interval = min_t(u16, interval, (u16)0xFF);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BCN_LI, interval);
}
/* Write the short and long frame retry limit values. */
static void b43_set_retry_limits(struct b43_wldev *dev,
unsigned int short_retry,
@ -3912,6 +3964,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&wl->mutex);
b43_mac_suspend(dev);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL)
b43_set_beacon_listen_interval(dev, conf->listen_interval);
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
phy->chandef = &conf->chandef;
phy->channel = conf->chandef.chan->hw_value;
@ -4812,6 +4867,16 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
hf &= ~B43_HF_SKCFPUP;
b43_hf_write(dev, hf);
/* tell the ucode MAC capabilities */
if (dev->dev->core_rev >= 13) {
u32 mac_hw_cap = b43_read32(dev, B43_MMIO_MAC_HW_CAP);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_L,
mac_hw_cap & 0xffff);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_H,
(mac_hw_cap >> 16) & 0xffff);
}
b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
B43_DEFAULT_LONG_RETRY_LIMIT);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
@ -4834,6 +4899,10 @@ 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);
/* write phytype and phyvers */
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYTYPE, phy->type);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYVER, phy->rev);
if (b43_bus_host_is_pcmcia(dev->dev) ||
b43_bus_host_is_sdio(dev->dev)) {
dev->__using_pio_transfers = true;

View File

@ -96,6 +96,8 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason);
#define B43_PS_ASLEEP (1 << 3) /* Force device asleep */
void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev);
void b43_mac_suspend(struct b43_wldev *dev);
void b43_mac_enable(struct b43_wldev *dev);
void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);

View File

@ -81,80 +81,104 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
udelay(50);
/* Calibration */
b43_radio_mask(dev, 0x2b, ~0x1);
b43_radio_mask(dev, 0x2e, ~0x4);
b43_radio_set(dev, 0x2e, 0x4);
b43_radio_set(dev, 0x2b, 0x1);
b43_radio_mask(dev, R2059_RFPLL_MISC_EN, ~0x1);
b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x4);
b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x4);
b43_radio_set(dev, R2059_RFPLL_MISC_EN, 0x1);
udelay(300);
}
/* Calibrate resistors in LPF of PLL? */
static void b43_radio_2059_rcal(struct b43_wldev *dev)
{
/* Enable */
b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x1);
usleep_range(10, 20);
b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
/* Start */
b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x2);
usleep_range(100, 200);
/* Stop */
b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x2);
if (!b43_radio_wait_value(dev, R2059_C3 | R2059_RCAL_STATUS, 1, 1, 100,
1000000))
b43err(dev->wl, "Radio 0x2059 rcal timeout\n");
/* Disable */
b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x1);
b43_radio_set(dev, 0xa, 0x60);
}
/* Calibrate the internal RC oscillator? */
static void b43_radio_2057_rccal(struct b43_wldev *dev)
{
const u16 radio_values[3][2] = {
{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
};
int i;
for (i = 0; i < 3; i++) {
b43_radio_write(dev, R2059_RCCAL_MASTER, radio_values[i][0]);
b43_radio_write(dev, R2059_RCCAL_X1, 0x6E);
b43_radio_write(dev, R2059_RCCAL_TRC0, radio_values[i][1]);
/* Start */
b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x55);
/* Wait */
if (!b43_radio_wait_value(dev, R2059_RCCAL_DONE_OSCCAP, 2, 2,
500, 5000000))
b43err(dev->wl, "Radio 0x2059 rccal timeout\n");
/* Stop */
b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x15);
}
b43_radio_mask(dev, R2059_RCCAL_MASTER, ~0x1);
}
static void b43_radio_2059_init_pre(struct b43_wldev *dev)
{
b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_FORCE);
b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_FORCE);
b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
}
static void b43_radio_2059_init(struct b43_wldev *dev)
{
const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 };
const u16 radio_values[3][2] = {
{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
};
u16 i, j;
int i;
b43_radio_write(dev, R2059_ALL | 0x51, 0x0070);
b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003);
/* Prepare (reset?) radio */
b43_radio_2059_init_pre(dev);
r2059_upload_inittabs(dev);
for (i = 0; i < ARRAY_SIZE(routing); i++)
b43_radio_set(dev, routing[i] | 0x146, 0x3);
b43_radio_set(dev, 0x2e, 0x0078);
b43_radio_set(dev, 0xc0, 0x0080);
/* Post init starts below */
b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x0078);
b43_radio_set(dev, R2059_XTAL_CONFIG2, 0x0080);
msleep(2);
b43_radio_mask(dev, 0x2e, ~0x0078);
b43_radio_mask(dev, 0xc0, ~0x0080);
b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x0078);
b43_radio_mask(dev, R2059_XTAL_CONFIG2, ~0x0080);
if (1) { /* FIXME */
b43_radio_set(dev, R2059_C3 | 0x4, 0x1);
udelay(10);
b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
b43_radio_set(dev, R2059_C3 | 0x4, 0x2);
udelay(100);
b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2);
for (i = 0; i < 10000; i++) {
if (b43_radio_read(dev, R2059_C3 | 0x145) & 1) {
i = 0;
break;
}
udelay(100);
}
if (i)
b43err(dev->wl, "radio 0x945 timeout\n");
b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1);
b43_radio_set(dev, 0xa, 0x60);
for (i = 0; i < 3; i++) {
b43_radio_write(dev, 0x17F, radio_values[i][0]);
b43_radio_write(dev, 0x13D, 0x6E);
b43_radio_write(dev, 0x13E, radio_values[i][1]);
b43_radio_write(dev, 0x13C, 0x55);
for (j = 0; j < 10000; j++) {
if (b43_radio_read(dev, 0x140) & 2) {
j = 0;
break;
}
udelay(500);
}
if (j)
b43err(dev->wl, "radio 0x140 timeout\n");
b43_radio_write(dev, 0x13C, 0x15);
}
b43_radio_mask(dev, 0x17F, ~0x1);
b43_radio_2059_rcal(dev);
b43_radio_2057_rccal(dev);
}
b43_radio_mask(dev, 0x11, ~0x0008);
b43_radio_mask(dev, R2059_RFPLL_MASTER, ~0x0008);
}
/**************************************************
@ -297,6 +321,26 @@ static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
}
static void b43_phy_ht_bphy_reset(struct b43_wldev *dev, bool reset)
{
u16 tmp;
tmp = b43_read16(dev, B43_MMIO_PSM_PHY_HDR);
b43_write16(dev, B43_MMIO_PSM_PHY_HDR,
tmp | B43_PSM_HDR_MAC_PHY_FORCE_CLK);
/* Put BPHY in or take it out of the reset */
if (reset)
b43_phy_set(dev, B43_PHY_B_BBCFG,
B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX);
else
b43_phy_mask(dev, B43_PHY_B_BBCFG,
(u16)~(B43_PHY_B_BBCFG_RSTCCA |
B43_PHY_B_BBCFG_RSTRX));
b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp);
}
/**************************************************
* Samples
**************************************************/
@ -704,7 +748,6 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
{
struct bcma_device *core = dev->dev->bdev;
int spuravoid = 0;
u16 tmp;
/* Check for 13 and 14 is just a guess, we don't have enough logs. */
if (new_channel->hw_value == 13 || new_channel->hw_value == 14)
@ -717,22 +760,9 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
B43_BCMA_CLKCTLST_80211_PLL_ST |
B43_BCMA_CLKCTLST_PHY_PLL_ST, false);
/* Values has been taken from wlc_bmac_switch_macfreq comments */
switch (spuravoid) {
case 2: /* 126MHz */
tmp = 0x2082;
break;
case 1: /* 123MHz */
tmp = 0x5341;
break;
default: /* 120MHz */
tmp = 0x8889;
}
b43_mac_switch_freq(dev, spuravoid);
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp);
b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
/* TODO: reset PLL */
b43_wireless_core_phy_pll_reset(dev);
if (spuravoid)
b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX);
@ -747,13 +777,19 @@ static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
const struct b43_phy_ht_channeltab_e_phy *e,
struct ieee80211_channel *new_channel)
{
bool old_band_5ghz;
if (new_channel->band == IEEE80211_BAND_5GHZ) {
/* Switch to 2 GHz for a moment to access B-PHY regs */
b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ);
old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
/* TODO */
} else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
/* TODO */
b43_phy_ht_bphy_reset(dev, true);
/* Switch to 5 GHz */
b43_phy_set(dev, B43_PHY_HT_BANDCTL, B43_PHY_HT_BANDCTL_5GHZ);
} else {
/* Switch to 2 GHz */
b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ);
b43_phy_ht_bphy_reset(dev, false);
}
b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1);
@ -1002,19 +1038,10 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
b43err(dev->wl, "MAC not suspended\n");
/* In the following PHY ops we copy wl's dummy behaviour.
* TODO: Find out if reads (currently hidden in masks/masksets) are
* needed and replace following ops with just writes or w&r.
* Note: B43_PHY_HT_RF_CTL1 register is tricky, wrong operation can
* cause delayed (!) machine lock up. */
if (blocked) {
b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD,
~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
} else {
b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x1);
b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x2);
if (dev->phy.radio_ver == 0x2059)
b43_radio_2059_init(dev);
else

View File

@ -81,7 +81,9 @@
#define B43_PHY_HT_RF_SEQ_STATUS B43_PHY_EXTG(0x004)
/* Values for the status are the same as for the trigger */
#define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010)
#define B43_PHY_HT_RF_CTL_CMD 0x810
#define B43_PHY_HT_RF_CTL_CMD_FORCE 0x0001
#define B43_PHY_HT_RF_CTL_CMD_CHIP0_PU 0x0002
#define B43_PHY_HT_RF_CTL_INT_C1 B43_PHY_EXTG(0x04c)
#define B43_PHY_HT_RF_CTL_INT_C2 B43_PHY_EXTG(0x06c)
@ -104,6 +106,9 @@
#define B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT 0
#define B43_PHY_HT_TX_PCTL_STATUS_C3 B43_PHY_EXTG(0x169)
#define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001)
#define B43_PHY_B_BBCFG_RSTCCA 0x4000 /* Reset CCA */
#define B43_PHY_B_BBCFG_RSTRX 0x8000 /* Reset RX */
#define B43_PHY_HT_TEST B43_PHY_N_BMODE(0x00A)

View File

@ -6369,7 +6369,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
b43_mac_switch_freq(dev, spuravoid);
if (dev->phy.rev == 3 || dev->phy.rev == 4)
; /* TODO: reset PLL */
b43_wireless_core_phy_pll_reset(dev);
if (spuravoid)
b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX);

View File

@ -25,6 +25,13 @@
#include "b43.h"
#include "radio_2059.h"
/* Extracted from MMIO dump of 6.30.223.141 */
static u16 r2059_phy_rev1_init[][2] = {
{ 0x051, 0x70 }, { 0x05a, 0x03 }, { 0x079, 0x01 }, { 0x082, 0x70 },
{ 0x083, 0x00 }, { 0x084, 0x70 }, { 0x09a, 0x7f }, { 0x0b6, 0x10 },
{ 0x188, 0x05 },
};
#define RADIOREGS(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
r20) \
@ -58,73 +65,87 @@
.phy_regs.bw5 = r4, \
.phy_regs.bw6 = r5
/* Extracted from MMIO dump of 6.30.223.141
* TODO: Values for channels 12 & 13 are outdated (from some old 5.x driver)!
*/
static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radio2059[] = {
{ .freq = 2412,
RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
},
{ .freq = 2417,
RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
},
{ .freq = 2422,
RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
},
{ .freq = 2427,
RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
},
{ .freq = 2432,
RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
},
{ .freq = 2437,
RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
},
{ .freq = 2442,
RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
},
{ .freq = 2447,
RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
},
{ .freq = 2452,
RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
},
{ .freq = 2457,
RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
},
{ .freq = 2462,
RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
},
{
.freq = 2412,
RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0xd0, 0x00),
PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
},
{
.freq = 2417,
RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0xd0, 0x00),
PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
},
{
.freq = 2422,
RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0xd0, 0x00),
PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
},
{
.freq = 2427,
RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0xa0, 0x00),
PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
},
{
.freq = 2432,
RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0xa0, 0x00),
PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
},
{
.freq = 2437,
RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0xa0, 0x00),
PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
},
{
.freq = 2442,
RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0x80, 0x00),
PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
},
{
.freq = 2447,
RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0x80, 0x00),
PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
},
{
.freq = 2452,
RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0x80, 0x00),
PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
},
{
.freq = 2457,
RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0x60, 0x00),
PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
},
{
.freq = 2462,
RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73,
0x00, 0x00, 0x00, 0x60, 0x00),
PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
},
{ .freq = 2467,
RADIOREGS(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3,
0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03,
@ -137,8 +158,196 @@ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radi
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
},
{
.freq = 5180,
RADIOREGS(0xbe, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x06,
0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
0x0f, 0x4f, 0xa3, 0x00, 0xfc),
PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
},
{
.freq = 5200,
RADIOREGS(0xc5, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x08,
0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
0x0f, 0x4f, 0x93, 0x00, 0xfb),
PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
},
{
.freq = 5220,
RADIOREGS(0xcc, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0a,
0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
0x0f, 0x4f, 0x93, 0x00, 0xea),
PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
},
{
.freq = 5240,
RADIOREGS(0xd2, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0c,
0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
0x0f, 0x4f, 0x93, 0x00, 0xda),
PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
},
{
.freq = 5260,
RADIOREGS(0xd9, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0e,
0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
0x0f, 0x4f, 0x93, 0x00, 0xca),
PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
},
{
.freq = 5280,
RADIOREGS(0xe0, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x10,
0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
0x0f, 0x4f, 0x93, 0x00, 0xb9),
PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
},
{
.freq = 5300,
RADIOREGS(0xe6, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x12,
0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
0x0f, 0x4c, 0x83, 0x00, 0xb8),
PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
},
{
.freq = 5320,
RADIOREGS(0xed, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x14,
0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
0x0f, 0x4c, 0x83, 0x00, 0xa8),
PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
},
{
.freq = 5500,
RADIOREGS(0x29, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x26,
0x02, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00,
0x0a, 0x46, 0x43, 0x00, 0x75),
PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
},
{
.freq = 5520,
RADIOREGS(0x30, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x28,
0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
0x0a, 0x46, 0x43, 0x00, 0x75),
PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
},
{
.freq = 5540,
RADIOREGS(0x36, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2a,
0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
0x0a, 0x46, 0x43, 0x00, 0x75),
PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
},
{
.freq = 5560,
RADIOREGS(0x3d, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2c,
0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
0x0a, 0x46, 0x43, 0x00, 0x75),
PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
},
{
.freq = 5580,
RADIOREGS(0x44, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2e,
0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
0x0a, 0x46, 0x43, 0x00, 0x74),
PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
},
{
.freq = 5600,
RADIOREGS(0x4a, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x30,
0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
0x09, 0x44, 0x23, 0x00, 0x54),
PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
},
{
.freq = 5620,
RADIOREGS(0x51, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x32,
0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
0x09, 0x44, 0x23, 0x00, 0x54),
PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
},
{
.freq = 5640,
RADIOREGS(0x58, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x34,
0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
0x09, 0x44, 0x23, 0x00, 0x43),
PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
},
{
.freq = 5660,
RADIOREGS(0x5e, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x36,
0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
0x09, 0x43, 0x23, 0x00, 0x43),
PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
},
{
.freq = 5680,
RADIOREGS(0x65, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x38,
0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
0x09, 0x42, 0x23, 0x00, 0x43),
PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
},
{
.freq = 5700,
RADIOREGS(0x6c, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x3a,
0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
0x08, 0x42, 0x13, 0x00, 0x32),
PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
},
{
.freq = 5745,
RADIOREGS(0x7b, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x7d,
0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
0x08, 0x42, 0x13, 0x00, 0x21),
PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
},
{
.freq = 5765,
RADIOREGS(0x81, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x81,
0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
0x08, 0x42, 0x13, 0x00, 0x11),
PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
},
{
.freq = 5785,
RADIOREGS(0x88, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x85,
0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
0x08, 0x42, 0x13, 0x00, 0x00),
PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
},
{
.freq = 5805,
RADIOREGS(0x8f, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x89,
0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
0x06, 0x41, 0x03, 0x00, 0x00),
PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
},
{
.freq = 5825,
RADIOREGS(0x95, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x8d,
0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
0x06, 0x41, 0x03, 0x00, 0x00),
PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
},
};
void r2059_upload_inittabs(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u16 *table = NULL;
u16 size, i;
switch (phy->rev) {
case 1:
table = r2059_phy_rev1_init[0];
size = ARRAY_SIZE(r2059_phy_rev1_init);
break;
default:
B43_WARN_ON(1);
return;
}
for (i = 0; i < size; i++, table += 2)
b43_radio_write(dev, R2059_ALL | table[0], table[1]);
}
const struct b43_phy_ht_channeltab_e_radio2059
*b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq)
{

View File

@ -10,6 +10,18 @@
#define R2059_C3 0x800
#define R2059_ALL 0xC00
#define R2059_RCAL_CONFIG 0x004
#define R2059_RFPLL_MASTER 0x011
#define R2059_RFPLL_MISC_EN 0x02b
#define R2059_RFPLL_MISC_CAL_RESETN 0x02e
#define R2059_XTAL_CONFIG2 0x0c0
#define R2059_RCCAL_START_R1_Q1_P1 0x13c
#define R2059_RCCAL_X1 0x13d
#define R2059_RCCAL_TRC0 0x13e
#define R2059_RCCAL_DONE_OSCCAP 0x140
#define R2059_RCAL_STATUS 0x145
#define R2059_RCCAL_MASTER 0x17f
/* Values for various registers uploaded on channel switching */
struct b43_phy_ht_channeltab_e_radio2059 {
/* The channel frequency in MHz */
@ -40,6 +52,8 @@ struct b43_phy_ht_channeltab_e_radio2059 {
struct b43_phy_ht_channeltab_e_phy phy_regs;
};
void r2059_upload_inittabs(struct b43_wldev *dev);
const struct b43_phy_ht_channeltab_e_radio2059
*b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq);

View File

@ -97,9 +97,13 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
};
/* MAC TX control */
#define B43_TXH_MAC_RTS_FB_SHORTPRMBL 0x80000000 /* RTS fallback preamble */
#define B43_TXH_MAC_RTS_SHORTPRMBL 0x40000000 /* RTS main rate preamble */
#define B43_TXH_MAC_FB_SHORTPRMBL 0x20000000 /* Main fallback preamble */
#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */
#define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */
#define B43_TXH_MAC_KEYIDX_SHIFT 20
#define B43_TXH_MAC_ALT_TXPWR 0x00080000 /* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */
#define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */
#define B43_TXH_MAC_KEYALG_SHIFT 16
#define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */
@ -126,25 +130,25 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
#define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */
#define B43_TXH_EFT_FB_CCK 0x00 /* CCK */
#define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */
#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */
#define B43_TXH_EFT_FB_N 0x03 /* N */
#define B43_TXH_EFT_FB_HT 0x02 /* HT */
#define B43_TXH_EFT_FB_VHT 0x03 /* VHT */
#define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */
#define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */
#define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */
#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */
#define B43_TXH_EFT_RTS_N 0x0C /* N */
#define B43_TXH_EFT_RTS_HT 0x08 /* HT */
#define B43_TXH_EFT_RTS_VHT 0x0C /* VHT */
#define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */
#define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */
#define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */
#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */
#define B43_TXH_EFT_RTSFB_N 0x30 /* N */
#define B43_TXH_EFT_RTSFB_HT 0x20 /* HT */
#define B43_TXH_EFT_RTSFB_VHT 0x30 /* VHT */
/* PHY TX control word */
#define B43_TXH_PHY_ENC 0x0003 /* Data frame encoding */
#define B43_TXH_PHY_ENC_CCK 0x0000 /* CCK */
#define B43_TXH_PHY_ENC_OFDM 0x0001 /* OFDM */
#define B43_TXH_PHY_ENC_EWC 0x0002 /* EWC */
#define B43_TXH_PHY_ENC_N 0x0003 /* N */
#define B43_TXH_PHY_ENC_HT 0x0002 /* HT */
#define B43_TXH_PHY_ENC_VHT 0x0003 /* VHT */
#define B43_TXH_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
#define B43_TXH_PHY_ANT 0x03C0 /* Antenna selection */
#define B43_TXH_PHY_ANT0 0x0000 /* Use antenna 0 */
@ -162,7 +166,7 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
#define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */
#define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */
#define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */
#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */
#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 40 MHz duplicate */
#define B43_TXH_PHY1_MODE 0x0038 /* Mode */
#define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */
#define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */

View File

@ -746,7 +746,7 @@ dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring,
/* !! may be called with core in reset */
void dma_detach(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@ -842,7 +842,7 @@ static void _dma_rxenable(struct dma_info *di)
void dma_rxinit(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@ -924,7 +924,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
*/
int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff_head dma_frames;
struct sk_buff *p, *next;
uint len;
@ -1022,7 +1022,7 @@ static bool dma64_txidle(struct dma_info *di)
*/
bool dma_rxfill(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff *p;
u16 rxin, rxout;
u32 flags = 0;
@ -1106,7 +1106,7 @@ bool dma_rxfill(struct dma_pub *pub)
void dma_rxreclaim(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff *p;
brcms_dbg_dma(di->core, "%s:\n", di->name);
@ -1126,7 +1126,7 @@ void dma_counterreset(struct dma_pub *pub)
/* get the address of the var in order to change later */
unsigned long dma_getvar(struct dma_pub *pub, const char *name)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
if (!strcmp(name, "&txavail"))
return (unsigned long)&(di->dma.txavail);
@ -1137,7 +1137,7 @@ unsigned long dma_getvar(struct dma_pub *pub, const char *name)
void dma_txinit(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
u32 control = D64_XC_XE;
brcms_dbg_dma(di->core, "%s:\n", di->name);
@ -1170,7 +1170,7 @@ void dma_txinit(struct dma_pub *pub)
void dma_txsuspend(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@ -1182,7 +1182,7 @@ void dma_txsuspend(struct dma_pub *pub)
void dma_txresume(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@ -1194,7 +1194,7 @@ void dma_txresume(struct dma_pub *pub)
bool dma_txsuspended(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
return (di->ntxd == 0) ||
((bcma_read32(di->core,
@ -1204,7 +1204,7 @@ bool dma_txsuspended(struct dma_pub *pub)
void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff *p;
brcms_dbg_dma(di->core, "%s: %s\n",
@ -1225,7 +1225,7 @@ void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
bool dma_txreset(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
u32 status;
if (di->ntxd == 0)
@ -1252,7 +1252,7 @@ bool dma_txreset(struct dma_pub *pub)
bool dma_rxreset(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
u32 status;
if (di->nrxd == 0)
@ -1377,7 +1377,7 @@ static void dma_update_txavail(struct dma_info *di)
int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
struct sk_buff *p)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
struct brcms_ampdu_session *session = &di->ampdu_session;
struct ieee80211_tx_info *tx_info;
bool is_ampdu;
@ -1427,7 +1427,7 @@ int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
void dma_txflush(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
struct brcms_ampdu_session *session = &di->ampdu_session;
if (!skb_queue_empty(&session->skb_list))
@ -1436,7 +1436,7 @@ void dma_txflush(struct dma_pub *pub)
int dma_txpending(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
return ntxdactive(di, di->txin, di->txout);
}
@ -1446,7 +1446,7 @@ int dma_txpending(struct dma_pub *pub)
*/
void dma_kick_tx(struct dma_pub *pub)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
struct brcms_ampdu_session *session = &di->ampdu_session;
if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di))
@ -1465,7 +1465,7 @@ void dma_kick_tx(struct dma_pub *pub)
*/
struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
{
struct dma_info *di = (struct dma_info *)pub;
struct dma_info *di = container_of(pub, struct dma_info, dma);
u16 start, end, i;
u16 active_desc;
struct sk_buff *txp;
@ -1547,7 +1547,7 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
(void *pkt, void *arg_a), void *arg_a)
{
struct dma_info *di = (struct dma_info *) dmah;
struct dma_info *di = container_of(dmah, struct dma_info, dma);
uint i = di->txin;
uint end = di->txout;
struct sk_buff *skb;

View File

@ -128,19 +128,19 @@ static const u8 ofdm_rate_lookup[] = {
void wlc_phyreg_enter(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
}
void wlc_phyreg_exit(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
}
void wlc_radioreg_enter(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
udelay(10);
@ -148,7 +148,7 @@ void wlc_radioreg_enter(struct brcms_phy_pub *pih)
void wlc_radioreg_exit(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
pi->phy_wreg = 0;
@ -586,7 +586,7 @@ err:
void wlc_phy_detach(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (pih) {
if (--pi->refcnt)
@ -613,7 +613,7 @@ bool
wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
u16 *radioid, u16 *radiover)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
*phytype = (u16) pi->pubpi.phy_type;
*phyrev = (u16) pi->pubpi.phy_rev;
*radioid = pi->pubpi.radioid;
@ -624,19 +624,19 @@ wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
bool wlc_phy_get_encore(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
return pi->pubpi.abgphy_encore;
}
u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
return pi->pubpi.coreflags;
}
void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi)) {
if (on) {
@ -673,7 +673,7 @@ void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u32 phy_bw_clkbits = 0;
@ -698,14 +698,14 @@ u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
void wlc_phy_por_inform(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->phy_init_por = true;
}
void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->edcrs_threshold_lock = lock;
@ -717,14 +717,14 @@ void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->do_initcal = initcal;
}
void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (!pi || !pi->sh)
return;
@ -734,7 +734,7 @@ void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (!pi || !pi->sh)
return;
@ -746,7 +746,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
{
u32 mc;
void (*phy_init)(struct brcms_phy *) = NULL;
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (pi->init_in_progress)
return;
@ -798,7 +798,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
void wlc_phy_cal_init(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
void (*cal_init)(struct brcms_phy *) = NULL;
if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
@ -816,7 +816,7 @@ void wlc_phy_cal_init(struct brcms_phy_pub *pih)
int wlc_phy_down(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
int callbacks = 0;
if (pi->phycal_timer
@ -1070,7 +1070,7 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (set)
mboolset(pi->measure_hold, id);
@ -1082,7 +1082,7 @@ void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (mute)
mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
@ -1096,7 +1096,7 @@ void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
void wlc_phy_clear_tssi(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi)) {
return;
@ -1115,7 +1115,7 @@ static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
if (ISNPHY(pi)) {
@ -1149,35 +1149,35 @@ void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->bw;
}
void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->bw = bw;
}
void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->radio_chanspec = newch;
}
u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->radio_chanspec;
}
void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 m_cur_channel;
void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
m_cur_channel = CHSPEC_CHANNEL(chanspec);
@ -1226,7 +1226,7 @@ int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec)
void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
bool wide_filter)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->channel_14_wide_filter = wide_filter;
@ -1246,7 +1246,7 @@ void
wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
struct brcms_chanvec *channels)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint i;
uint channel;
@ -1267,7 +1267,7 @@ wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint i;
uint channel;
u16 chspec;
@ -1311,7 +1311,7 @@ u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
*qdbm = pi->tx_user_target[0];
if (override != NULL)
@ -1323,7 +1323,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
struct txpwr_limits *txpwr)
{
bool mac_enabled = false;
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
&txpwr->cck[0], BRCMS_NUM_RATES_CCK);
@ -1371,7 +1371,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
int i;
if (qdbm > 127)
@ -1407,7 +1407,7 @@ void
wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
u8 *max_pwr, int txp_rate_idx)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint i;
*min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;
@ -1456,7 +1456,7 @@ void
wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
u8 *max_txpwr, u8 *min_txpwr)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u8 tx_pwr_max = 0;
u8 tx_pwr_min = 255;
u8 max_num_rate;
@ -1493,14 +1493,14 @@ wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit,
u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->tx_power_min;
}
u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->tx_power_max;
}
@ -1812,21 +1812,21 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->txpwr_percent = txpwr_percent;
}
void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->sh->machwcap = machwcap;
}
void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 rxc;
rxc = 0;
@ -1857,7 +1857,7 @@ void
wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
u16 chanspec)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
@ -1881,14 +1881,14 @@ wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->ofdm_rateset_war = war;
}
void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->bf_preempt_4306 = bf_preempt;
}
@ -1945,7 +1945,7 @@ void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi))
return pi->nphy_txpwrctrl;
@ -1955,7 +1955,7 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
bool suspend;
if (!pi->hwpwrctrl_capable)
@ -2038,7 +2038,7 @@ void
wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
uint channel)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint rate, num_rates;
u8 min_pwr, max_pwr;
@ -2136,21 +2136,21 @@ wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->antsel_type = antsel_type;
}
bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->phytest_on;
}
void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
bool suspend;
pi->sh->rx_antdiv = val;
@ -2283,7 +2283,7 @@ static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u16 jssi_aux;
u8 channel = 0;
s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
@ -2339,7 +2339,7 @@ void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
static void
wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
bool sampling_in_progress = (pi->phynoise_state != 0);
bool wait_for_intr = true;
@ -2531,7 +2531,7 @@ int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
{
int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
uint radioid = pih->radioid;
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if ((pi->sh->corerev >= 11)
&& !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
@ -2591,7 +2591,7 @@ void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag)
void wlc_phy_watchdog(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
bool delay_phy_cal = false;
pi->sh->now++;
@ -2651,7 +2651,7 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih)
void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
uint i;
uint k;
@ -2711,7 +2711,7 @@ void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
s16 nphy_currtemp = 0;
s16 delta_temp = 0;
bool do_periodic_cal = true;
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (!ISNPHY(pi))
return;
@ -2804,7 +2804,7 @@ u8 wlc_phy_nbits(s32 value)
void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->sh->hw_phytxchain = txchain;
pi->sh->hw_phyrxchain = rxchain;
@ -2815,7 +2815,7 @@ void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->sh->phytxchain = txchain;
@ -2827,7 +2827,7 @@ void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
*txchain = pi->sh->phytxchain;
*rxchain = pi->sh->phyrxchain;
@ -2837,7 +2837,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
{
s16 nphy_currtemp;
u8 active_bitmap;
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
@ -2867,7 +2867,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u8 siso_mcs_id, cdd_mcs_id;
siso_mcs_id =
@ -2944,7 +2944,7 @@ s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi))
return wlc_phy_n_txpower_ipa_ison(pi);

View File

@ -2865,7 +2865,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
{
bool suspend, tx_gain_override_old;
struct lcnphy_txgains old_gains;
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
idleTssi0_regvalue_2C;
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
@ -3084,7 +3084,7 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
s32 a1, b0, b1;
s32 tssi, pwr, maxtargetpwr, mintargetpwr;
bool suspend;
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
MCTL_EN_MAC));
@ -4348,7 +4348,7 @@ void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
{
s8 index;
u16 index2;
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&

View File

@ -14121,7 +14121,7 @@ static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = {
bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u32 phybist0, phybist1, phybist2, phybist3, phybist4;
if (NREV_GE(pi->pubpi.phy_rev, 16))
@ -19734,7 +19734,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask)
u16 regval;
u16 tbl_buf[16];
uint i;
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u16 tbl_opcode;
bool suspend;
@ -19812,7 +19812,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask)
u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih)
{
u16 regval, rxen_bits;
struct brcms_phy *pi = (struct brcms_phy *) pih;
struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
regval = read_phy_reg(pi, 0xa2);
rxen_bits = (regval >> 4) & 0xf;
@ -21342,7 +21342,7 @@ void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec)
void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 mask = 0xfc00;
u32 mc = 0;

View File

@ -186,11 +186,9 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
bss->ssid[i] : '_');
seq_putc(m, '\t');
for (i = 0; i < bss->ssid_len; i++)
seq_printf(m, "%02x", bss->ssid[i]);
seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
seq_putc(m, '\t');
for (i = 0; i < bss->wpa_ie_len; i++)
seq_printf(m, "%02x", bss->wpa_ie[i]);
seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie);
seq_putc(m, '\n');
return 0;
}

View File

@ -4633,7 +4633,7 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr,
else {
ret = il_set_tx_power(il, val, false);
if (ret)
IL_ERR("failed setting tx power (0x%d).\n", ret);
IL_ERR("failed setting tx power (0x%08x).\n", ret);
else
ret = count;
}
@ -5757,9 +5757,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (il->cfg->sku & IL_SKU_N)
hw->flags |=
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_SUPPORTS_STATIC_SMPS;
hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
NL80211_FEATURE_STATIC_SMPS;
hw->sta_data_size = sizeof(struct il_station_priv);
hw->vif_data_size = sizeof(struct il_vif_priv);

View File

@ -125,8 +125,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
*/
if (priv->nvm_data->sku_cap_11n_enable)
hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_SUPPORTS_STATIC_SMPS;
hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
NL80211_FEATURE_STATIC_SMPS;
/*
* Enable 11w if advertised by firmware and software crypto

View File

@ -131,7 +131,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl7000_base_params, \
.led_mode = IWL_LED_RF_STATE, \
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \
.non_shared_ant = ANT_A
const struct iwl_cfg iwl7260_2ac_cfg = {
@ -220,6 +221,12 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = {
{0},
};
static const struct iwl_ht_params iwl7265_ht_params = {
.stbc = true,
.ldpc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
const struct iwl_cfg iwl3165_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 3165",
.fw_name_pre = IWL3165_FW_PRE,
@ -234,7 +241,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7265",
.fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
@ -244,7 +251,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
@ -254,7 +261,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
.name = "Intel(R) Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,

View File

@ -103,6 +103,7 @@ static const struct iwl_base_params iwl8000_base_params = {
};
static const struct iwl_ht_params iwl8000_ht_params = {
.ldpc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
@ -115,7 +116,17 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl8000_base_params, \
.led_mode = IWL_LED_RF_STATE, \
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \
.non_shared_ant = ANT_A
const struct iwl_cfg iwl8260_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 8260",
.fw_name_pre = IWL8000_FW_PRE,
IWL_DEVICE_8000,
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
};
const struct iwl_cfg iwl8260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 8260",
@ -135,6 +146,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.disable_dummy_notification = true,
};
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));

View File

@ -171,6 +171,7 @@ struct iwl_base_params {
/*
* @stbc: support Tx STBC and 1*SS Rx STBC
* @ldpc: support Tx/Rx with LDPC
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
*/
@ -178,6 +179,7 @@ struct iwl_ht_params {
enum ieee80211_smps_mode smps_mode;
const bool ht_greenfield_support; /* if used set to true */
const bool stbc;
const bool ldpc;
bool use_rts_for_aggregation;
u8 ht40_bands;
};
@ -228,6 +230,7 @@ struct iwl_pwr_tx_backoff {
* @max_data_size: The maximal length of the fw data section
* @valid_tx_ant: valid transmit antenna
* @valid_rx_ant: valid receive antenna
* @non_shared_ant: the antenna that is for WiFi only
* @nvm_ver: NVM version
* @nvm_calib_ver: NVM calibration version
* @lib: pointer to the lib ops
@ -260,6 +263,7 @@ struct iwl_cfg {
const u32 max_inst_size;
u8 valid_tx_ant;
u8 valid_rx_ant;
u8 non_shared_ant;
bool bt_shared_single_ant;
u16 nvm_ver;
u16 nvm_calib_ver;
@ -280,6 +284,7 @@ struct iwl_cfg {
bool no_power_up_nic_in_init;
const char *default_nvm_file;
unsigned int max_rx_agg_size;
bool disable_dummy_notification;
};
/*
@ -341,6 +346,7 @@ extern const struct iwl_cfg iwl3165_2ac_cfg;
extern const struct iwl_cfg iwl7265_2ac_cfg;
extern const struct iwl_cfg iwl7265_2n_cfg;
extern const struct iwl_cfg iwl7265_n_cfg;
extern const struct iwl_cfg iwl8260_2n_cfg;
extern const struct iwl_cfg iwl8260_2ac_cfg;
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
#endif /* CONFIG_IWLMVM */

View File

@ -295,6 +295,16 @@
#define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0)
#define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2)
/**
* hw_rev values
*/
enum {
SILICON_A_STEP = 0,
SILICON_B_STEP,
};
#define CSR_HW_REV_TYPE_MSK (0x000FFF0)
#define CSR_HW_REV_TYPE_5300 (0x0000020)
#define CSR_HW_REV_TYPE_5350 (0x0000030)

View File

@ -1363,7 +1363,7 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)")
module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
int, S_IRUGO);
MODULE_PARM_DESC(antenna_coupling,
"specify antenna coupling in dB (defualt: 0 dB)");
"specify antenna coupling in dB (default: 0 dB)");
module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
MODULE_PARM_DESC(wd_disable,

View File

@ -758,6 +758,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
}
if (cfg->ht_params->ldpc)
ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;

View File

@ -127,6 +127,7 @@ enum iwl_ucode_tlv_flag {
* @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
* @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
* @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
* @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
* @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
* longer than the passive one, which is essential for fragmented scan.
*/
@ -137,6 +138,7 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_CSA_FLOW = BIT(4),
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6),
IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7),
IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
};

View File

@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans)
* DEVICE_SET_NMI_8000B_REG - is used.
*/
if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) ||
((trans->hw_rev & 0xc) == 0x0))
(CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL);
else
iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG,

View File

@ -334,6 +334,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
if (cfg->ht_params->ldpc)
vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
if (num_tx_ants > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
else

View File

@ -377,6 +377,7 @@ enum iwl_trans_status {
* if unset 4k will be the RX buffer size
* @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
* @queue_watchdog_timeout: time (in ms) after which queues
* are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries
@ -392,6 +393,7 @@ struct iwl_trans_config {
bool rx_buf_size_8k;
bool bc_table_dword;
bool scd_set_active;
unsigned int queue_watchdog_timeout;
const char *const *command_names;
};
@ -826,12 +828,6 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg);
}
static inline void
iwl_trans_txq_enable_no_scd(struct iwl_trans *trans, int queue, u16 ssn)
{
iwl_trans_txq_enable_cfg(trans, queue, ssn, NULL);
}
static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
u32 txq_bm)
{

View File

@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o coex.o coex_legacy.o
iwlmvm-y += tt.o offloading.o
iwlmvm-y += tt.o offloading.o tdls.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o

View File

@ -1146,6 +1146,10 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
{
/* there is no other antenna, shared antenna is always available */
if (mvm->cfg->bt_shared_single_ant)
return true;
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);

View File

@ -65,12 +65,18 @@
#ifndef __MVM_CONSTANTS_H
#define __MVM_CONSTANTS_H
#include <linux/ieee80211.h>
#define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
#define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
#define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
#define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
#define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20
#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8
#define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30
@ -86,5 +92,7 @@
#define IWL_MVM_BT_COEX_SYNC2SCO 1
#define IWL_MVM_BT_COEX_CORUNNING 1
#define IWL_MVM_BT_COEX_MPLUT 1
#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
#define IWL_MVM_QUOTA_THRESHOLD 8
#endif /* __MVM_CONSTANTS_H */

View File

@ -288,6 +288,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
{
int temperature;
if (!mvm->ucode_loaded && !mvm->temperature_test)
return -EIO;
if (kstrtoint(buf, 10, &temperature))
return -EINVAL;
/* not a legal temperature */
@ -1256,6 +1259,18 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
PRINT_MVM_REF(IWL_MVM_REF_USER);
PRINT_MVM_REF(IWL_MVM_REF_TX);
PRINT_MVM_REF(IWL_MVM_REF_TX_AGG);
PRINT_MVM_REF(IWL_MVM_REF_ADD_IF);
PRINT_MVM_REF(IWL_MVM_REF_START_AP);
PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED);
PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX);
PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS);
PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL);
PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ);
PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE);
PRINT_MVM_REF(IWL_MVM_REF_NMI);
PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);

View File

@ -205,6 +205,10 @@ enum {
REPLY_SF_CFG_CMD = 0xd1,
REPLY_BEACON_FILTERING_CMD = 0xd2,
/* DTS measurements */
CMD_DTS_MEASUREMENT_TRIGGER = 0xdc,
DTS_MEASUREMENT_NOTIFICATION = 0xdd,
REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7,
@ -550,7 +554,7 @@ enum iwl_time_event_type {
TE_WIDI_TX_SYNC,
/* Channel Switch NoA */
TE_P2P_GO_CSA_NOA,
TE_CHANNEL_SWITCH_PERIOD,
TE_MAX
}; /* MAC_EVENT_TYPE_API_E_VER_1 */
@ -1601,6 +1605,8 @@ enum iwl_sf_scenario {
#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */
#define SF_CFG_DUMMY_NOTIF_OFF BIT(16)
/**
* Smart Fifo configuration command.
* @state: smart fifo state, types listed in enum %iwl_sf_sate.
@ -1616,4 +1622,32 @@ struct iwl_sf_cfg_cmd {
__le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
} __packed; /* SF_CFG_API_S_VER_2 */
/* DTS measurements */
enum iwl_dts_measurement_flags {
DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0),
DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1),
};
/**
* iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements
*
* @flags: indicates which measurements we want as specified in &enum
* iwl_dts_measurement_flags
*/
struct iwl_dts_measurement_cmd {
__le32 flags;
} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */
/**
* iwl_dts_measurement_notif - notification received with the measurements
*
* @temp: the measured temperature
* @voltage: the measured voltage
*/
struct iwl_dts_measurement_notif {
__le32 temp;
__le32 voltage;
} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
#endif /* __fw_api_h__ */

View File

@ -454,6 +454,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
/* reset quota debouncing buffer - 0xff will yield invalid data */
memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
/* Add auxiliary station for scanning */
ret = iwl_mvm_add_aux_sta(mvm);
if (ret)

View File

@ -1234,13 +1234,13 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,
!iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) {
u32 rel_time = (c + 1) *
csa_vif->bss_conf.beacon_int -
IWL_MVM_CHANNEL_SWITCH_TIME;
IWL_MVM_CHANNEL_SWITCH_TIME_GO;
u32 apply_time = gp2 + rel_time * 1024;
iwl_mvm_schedule_csa_noa(mvm, csa_vif,
IWL_MVM_CHANNEL_SWITCH_TIME -
IWL_MVM_CHANNEL_SWITCH_MARGIN,
apply_time);
iwl_mvm_schedule_csa_period(mvm, csa_vif,
IWL_MVM_CHANNEL_SWITCH_TIME_GO -
IWL_MVM_CHANNEL_SWITCH_MARGIN,
apply_time);
}
} else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) {
/* we don't have CSA NoA scheduled yet, switch now */

View File

@ -303,9 +303,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TIMING_BEACON_ONLY |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_CHANCTX_STA_CSA |
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_SUPPORTS_STATIC_SMPS;
IEEE80211_HW_CHANCTX_STA_CSA;
hw->queues = mvm->first_agg_queue;
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
@ -327,7 +325,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 &&
!iwlwifi_mod_params.uapsd_disable) {
hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
hw->uapsd_queues = IWL_UAPSD_AC_INFO;
hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
}
@ -409,7 +407,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN |
NL80211_FEATURE_P2P_GO_OPPPS;
NL80211_FEATURE_P2P_GO_OPPPS |
NL80211_FEATURE_DYNAMIC_SMPS |
NL80211_FEATURE_STATIC_SMPS;
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
@ -670,8 +670,9 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
{
static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
@ -763,20 +764,16 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
file_len += fw_error_dump->trans_ptr->len;
dump_file->file_len = cpu_to_le32(file_len);
mvm->fw_error_dump = fw_error_dump;
/* notify the userspace about the error we had */
kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
}
#endif
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
#ifdef CONFIG_IWLWIFI_DEBUGFS
static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
iwl_mvm_fw_error_dump(mvm);
/* notify the userspace about the error we had */
kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
#endif
iwl_trans_stop_device(mvm->trans);
mvm->scan_status = IWL_MVM_SCAN_NONE;
@ -815,12 +812,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
mvm->rx_ba_sessions = 0;
}
static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
mutex_lock(&mvm->mutex);
lockdep_assert_held(&mvm->mutex);
/* Clean up some internal and mac80211 state on restart */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
@ -837,6 +833,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
iwl_mvm_d0i3_enable_tx(mvm, NULL);
}
return ret;
}
static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
mutex_lock(&mvm->mutex);
ret = __iwl_mvm_mac_start(mvm);
mutex_unlock(&mvm->mutex);
return ret;
@ -862,14 +868,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
mutex_unlock(&mvm->mutex);
}
static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
flush_work(&mvm->d0i3_exit_work);
flush_work(&mvm->async_handlers_wk);
mutex_lock(&mvm->mutex);
lockdep_assert_held(&mvm->mutex);
/* disallow low power states when the FW is down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
@ -890,6 +891,19 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
/* the fw is stopped, the aux sta is dead: clean up driver state */
iwl_mvm_del_aux_sta(mvm);
mvm->ucode_loaded = false;
}
static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
flush_work(&mvm->d0i3_exit_work);
flush_work(&mvm->async_handlers_wk);
flush_work(&mvm->fw_error_dump_wk);
mutex_lock(&mvm->mutex);
__iwl_mvm_mac_stop(mvm);
mutex_unlock(&mvm->mutex);
/*
@ -1198,14 +1212,15 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mcast_filter_cmd *cmd;
struct netdev_hw_addr *addr;
int addr_count = netdev_hw_addr_list_count(mc_list);
bool pass_all = false;
int addr_count;
bool pass_all;
int len;
if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) {
pass_all = true;
addr_count = netdev_hw_addr_list_count(mc_list);
pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES ||
IWL_MVM_FW_MCAST_FILTER_PASS_ALL;
if (pass_all)
addr_count = 0;
}
len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
cmd = kzalloc(len, GFP_ATOMIC);
@ -1405,28 +1420,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
}
#endif
static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
{
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
int i;
lockdep_assert_held(&mvm->mutex);
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
lockdep_is_held(&mvm->mutex));
if (!sta || IS_ERR(sta) || !sta->tdls)
continue;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
NL80211_TDLS_TEARDOWN,
WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
GFP_KERNEL);
}
}
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@ -1724,7 +1717,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
return;
if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
BSS_CHANGED_BANDWIDTH) &&
BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) &&
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL))
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
@ -1955,48 +1948,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex);
}
int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
int count = 0;
int i;
lockdep_assert_held(&mvm->mutex);
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
lockdep_is_held(&mvm->mutex));
if (!sta || IS_ERR(sta) || !sta->tdls)
continue;
if (vif) {
mvmsta = iwl_mvm_sta_from_mac80211(sta);
if (mvmsta->vif != vif)
continue;
}
count++;
}
return count;
}
static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool sta_added)
{
int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);
/*
* Disable ps when the first TDLS sta is added and re-enable it
* when the last TDLS sta is removed
*/
if ((tdls_sta_cnt == 1 && sta_added) ||
(tdls_sta_cnt == 0 && !sta_added))
iwl_mvm_power_update_mac(mvm);
}
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@ -2170,27 +2121,6 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
}
static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
/*
* iwl_mvm_protect_session() reads directly from the device
* (the system time), so make sure it is available.
*/
if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
return;
mutex_lock(&mvm->mutex);
/* Protect the session to hear the TDLS setup response on the channel */
iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true);
mutex_unlock(&mvm->mutex);
iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
}
static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,

View File

@ -87,11 +87,11 @@
/* A TimeUnit is 1024 microsecond */
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
/*
* The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0"
* TBTT. This value should be big enough to ensure that we switch in time.
/* This value represents the number of TUs before CSA "beacon 0" TBTT
* when the CSA time-event needs to be scheduled to start. It must be
* big enough to ensure that we switch in time.
*/
#define IWL_MVM_CHANNEL_SWITCH_TIME 40
#define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40
/*
* This value (in TUs) is used to fine tune the CSA NoA end time which should
@ -180,10 +180,6 @@ enum iwl_power_scheme {
};
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
#define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2
#ifdef CONFIG_IWLWIFI_DEBUGFS
@ -274,6 +270,8 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_TM_CMD,
IWL_MVM_REF_EXIT_WORK,
/* update debugfs.c when changing this */
IWL_MVM_REF_COUNT,
};
@ -649,6 +647,7 @@ struct iwl_mvm {
/* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw;
struct work_struct fw_error_dump_wk;
struct iwl_mvm_dump_ptrs *fw_error_dump;
#ifdef CONFIG_IWLWIFI_LEDS
@ -709,6 +708,8 @@ struct iwl_mvm {
*/
bool temperature_test; /* Debug test temperature is enabled */
struct iwl_time_quota_cmd last_quota_cmd;
#ifdef CONFIG_NL80211_TESTMODE
u32 noa_duration;
struct ieee80211_vif *noa_vif;
@ -788,6 +789,9 @@ struct iwl_rate_info {
u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
};
void __iwl_mvm_mac_stop(struct iwl_mvm *mvm);
int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
/******************
* MVM Methods
******************/
@ -1153,7 +1157,17 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* TDLS */
int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm);
void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool sta_added);
void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
#ifdef CONFIG_IWLWIFI_DEBUGFS
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
#else
static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
#endif
#endif /* __IWL_MVM_H__ */

View File

@ -64,6 +64,7 @@
*****************************************************************************/
#include <linux/firmware.h>
#include "iwl-trans.h"
#include "iwl-csr.h"
#include "mvm.h"
#include "iwl-eeprom-parse.h"
#include "iwl-eeprom-read.h"
@ -349,7 +350,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
/* Maximal size depends on HW family and step */
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
max_section_size = IWL_MAX_NVM_SECTION_SIZE;
else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */
else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE;
else /* Family 8000 B-step */
max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE;

View File

@ -332,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BCAST_FILTER_CMD),
CMD(REPLY_SF_CFG_CMD),
CMD(REPLY_BEACON_FILTERING_CMD),
CMD(CMD_DTS_MEASUREMENT_TRIGGER),
CMD(DTS_MEASUREMENT_NOTIFICATION),
CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE),
CMD(BT_COEX_CI),
@ -364,6 +366,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
return 0;
}
static void iwl_mvm_fw_error_dump_wk(struct work_struct *work);
static struct iwl_op_mode *
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@ -431,6 +435,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk);
spin_lock_init(&mvm->d0i3_tx_lock);
spin_lock_init(&mvm->refs_lock);
@ -460,6 +465,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
trans_cfg.scd_set_active = true;
snprintf(mvm->hw->wiphy->fw_version,
sizeof(mvm->hw->wiphy->fw_version),
@ -781,6 +787,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk)
module_put(THIS_MODULE);
}
static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
{
struct iwl_mvm *mvm =
container_of(work, struct iwl_mvm, fw_error_dump_wk);
mutex_lock(&mvm->mutex);
iwl_mvm_fw_error_dump(mvm);
mutex_unlock(&mvm->mutex);
}
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
{
iwl_abort_notification_waits(&mvm->notif_wait);
@ -846,6 +862,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
if (fw_error && mvm->restart_fw > 0)
mvm->restart_fw--;
ieee80211_restart_hw(mvm->hw);
} else if (fw_error) {
schedule_work(&mvm->fw_error_dump_wk);
}
}

View File

@ -286,12 +286,28 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
return true;
}
static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
{
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
bool radar_detect = false;
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
WARN_ON(!chanctx_conf);
if (chanctx_conf) {
chan = chanctx_conf->def.chan;
radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
}
rcu_read_unlock();
return radar_detect;
}
static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd)
{
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
int dtimper, dtimper_msec;
int keep_alive;
bool radar_detect = false;
@ -320,7 +336,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
!mvmvif->pm_enabled)
!mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif))
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@ -333,14 +349,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
}
/* Check if radar detection is required on current channel */
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
WARN_ON(!chanctx_conf);
if (chanctx_conf) {
chan = chanctx_conf->def.chan;
radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
}
rcu_read_unlock();
radar_detect = iwl_mvm_power_is_radar(vif);
/* Check skip over DTIM conditions */
if (!radar_detect && (dtimper <= 10) &&
@ -501,8 +510,6 @@ struct iwl_power_vifs {
bool bss_active;
bool ap_active;
bool monitor_active;
bool bss_tdls;
bool p2p_tdls;
};
static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,
@ -557,8 +564,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
/* only a single MAC of the same type */
WARN_ON(power_iterator->p2p_vif);
power_iterator->p2p_vif = vif;
power_iterator->p2p_tdls =
!!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif);
if (mvmvif->phy_ctxt)
if (mvmvif->phy_ctxt->id < MAX_PHYS)
power_iterator->p2p_active = true;
@ -568,8 +573,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
/* only a single MAC of the same type */
WARN_ON(power_iterator->bss_vif);
power_iterator->bss_vif = vif;
power_iterator->bss_tdls =
!!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif);
if (mvmvif->phy_ctxt)
if (mvmvif->phy_ctxt->id < MAX_PHYS)
power_iterator->bss_active = true;
@ -612,15 +615,13 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
/* enable PM on bss if bss stand alone */
if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active &&
!vifs->bss_tdls) {
if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
bss_mvmvif->pm_enabled = true;
return;
}
/* enable PM on p2p if p2p stand alone */
if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active &&
!vifs->p2p_tdls) {
if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
p2p_mvmvif->pm_enabled = true;
return;
@ -961,17 +962,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
if (enable) {
/* configure skip over dtim up to 300 msec */
/* configure skip over dtim up to 306TU - 314 msec */
int dtimper = vif->bss_conf.dtim_period ?: 1;
int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
bool radar_detect = iwl_mvm_power_is_radar(vif);
if (WARN_ON(!dtimper_msec))
if (WARN_ON(!dtimper_tu))
return 0;
cmd.skip_dtim_periods = 300 / dtimper_msec;
if (cmd.skip_dtim_periods)
cmd.flags |=
cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
/* Check skip over DTIM conditions */
/* TODO: check that multicast wake lock is off */
if (!radar_detect && (dtimper < 10)) {
cmd.skip_dtim_periods = 306 / dtimper_tu;
if (cmd.skip_dtim_periods)
cmd.flags |= cpu_to_le16(
POWER_FLAGS_SKIP_OVER_DTIM_MSK);
}
}
iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS

View File

@ -175,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
struct ieee80211_vif *disabled_vif)
{
struct iwl_time_quota_cmd cmd = {};
int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat;
int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat;
struct iwl_mvm_quota_iterator_data data = {
.n_interfaces = {},
.colors = { -1, -1, -1, -1 },
.disabled_vif = disabled_vif,
};
struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
bool send = false;
lockdep_assert_held(&mvm->mutex);
@ -293,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
/* check that we have non-zero quota for all valid bindings */
for (i = 0; i < MAX_BINDINGS; i++) {
if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color)
send = true;
if (cmd.quotas[i].max_duration != last->quotas[i].max_duration)
send = true;
if (abs((int)le32_to_cpu(cmd.quotas[i].quota) -
(int)le32_to_cpu(last->quotas[i].quota))
> IWL_MVM_QUOTA_THRESHOLD)
send = true;
if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID))
continue;
WARN_ONCE(cmd.quotas[i].quota == 0,
"zero quota on binding %d\n", i);
}
ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
sizeof(cmd), &cmd);
if (ret)
IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
return ret;
if (!send) {
/* don't send a practically unchanged command, the firmware has
* to re-initialize a lot of state and that can have an adverse
* impact on it
*/
return 0;
}
err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd);
if (err)
IWL_ERR(mvm, "Failed to send quota: %d\n", err);
else
mvm->last_quota_cmd = cmd;
return err;
}

View File

@ -505,10 +505,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
const char *prefix)
{
IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n",
IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n",
prefix, rs_pretty_lq_type(rate->type),
rate->index, rs_pretty_ant(rate->ant),
rate->bw, rate->sgi);
rate->bw, rate->sgi, rate->ldpc);
}
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
@ -672,8 +672,10 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
return -EINVAL;
if (tbl->column != RS_COLUMN_INVALID) {
lq_sta->tx_stats[tbl->column][scale_index].total += attempts;
lq_sta->tx_stats[tbl->column][scale_index].success += successes;
struct lq_sta_pers *pers = &lq_sta->pers;
pers->tx_stats[tbl->column][scale_index].total += attempts;
pers->tx_stats[tbl->column][scale_index].success += successes;
}
/* Select window for current tx bit rate */
@ -742,6 +744,8 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
ucode_rate |= rate->bw;
if (rate->sgi)
ucode_rate |= RATE_MCS_SGI_MSK;
if (rate->ldpc)
ucode_rate |= RATE_MCS_LDPC_MSK;
return ucode_rate;
}
@ -779,6 +783,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
/* HT or VHT */
if (ucode_rate & RATE_MCS_SGI_MSK)
rate->sgi = true;
if (ucode_rate & RATE_MCS_LDPC_MSK)
rate->ldpc = true;
rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
@ -965,13 +971,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rate->index > IWL_RATE_MCS_9_INDEX);
rate->index = rs_ht_to_legacy[rate->index];
rate->ldpc = false;
} else {
/* Downgrade to SISO with same MCS if in MIMO */
rate->type = is_vht_mimo2(rate) ?
LQ_VHT_SISO : LQ_HT_SISO;
}
if (num_of_ant(rate->ant) > 1)
rate->ant = first_antenna(mvm->fw->valid_tx_ant);
@ -1621,6 +1627,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
}
rate->bw = rs_bw_from_sta_bw(sta);
rate->ldpc = lq_sta->ldpc;
search_tbl->column = col_id;
rs_set_expected_tpt_table(lq_sta, search_tbl);
@ -2031,18 +2038,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
return;
}
/* force user max rate if set by user */
if ((lq_sta->max_rate_idx != -1) &&
(lq_sta->max_rate_idx < index)) {
index = lq_sta->max_rate_idx;
update_lq = 1;
window = &(tbl->win[index]);
IWL_DEBUG_RATE(mvm,
"Forcing user max rate %d\n",
index);
goto lq_update;
}
/* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
window = &(tbl->win[index]);
/*
@ -2130,10 +2126,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
low = high_low & 0xff;
high = (high_low >> 8) & 0xff;
/* If user set max rate, dont allow higher than user constrain */
if ((lq_sta->max_rate_idx != -1) &&
(lq_sta->max_rate_idx < high))
high = IWL_RATE_INVALID;
/* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
sr = window->success_ratio;
@ -2342,6 +2335,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rate->index = i;
rate->ant = first_antenna(valid_tx_ant);
rate->sgi = false;
rate->ldpc = false;
rate->bw = RATE_MCS_CHAN_WIDTH_20;
if (band == IEEE80211_BAND_5GHZ)
rate->type = LQ_LEGACY_A;
@ -2364,23 +2358,13 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
struct ieee80211_tx_rate_control *txrc)
{
struct sk_buff *skb = txrc->skb;
struct ieee80211_supported_band *sband = txrc->sband;
struct iwl_op_mode *op_mode __maybe_unused =
(struct iwl_op_mode *)mvm_r;
struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = mvm_sta;
/* Get max rate if user set max rate */
if (lq_sta) {
lq_sta->max_rate_idx = txrc->max_rate_idx;
if ((sband->band == IEEE80211_BAND_5GHZ) &&
(lq_sta->max_rate_idx != -1))
lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
if ((lq_sta->max_rate_idx < 0) ||
(lq_sta->max_rate_idx >= IWL_RATE_COUNT))
lq_sta->max_rate_idx = -1;
}
/* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
/* Treat uninitialized rate scaling data same as non-existing. */
if (lq_sta && !lq_sta->pers.drv) {
@ -2581,7 +2565,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
* previous packets? Need to have IEEE 802.1X auth succeed immediately
* after assoc.. */
lq_sta->max_rate_idx = -1;
lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
lq_sta->band = sband->band;
/*
@ -2610,9 +2593,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
lq_sta->is_vht = false;
if (mvm->cfg->ht_params->ldpc &&
(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
lq_sta->ldpc = true;
} else {
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
lq_sta->is_vht = true;
if (mvm->cfg->ht_params->ldpc &&
(vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
lq_sta->ldpc = true;
}
lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
@ -2622,11 +2612,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate,
BITS_PER_LONG);
IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n",
IWL_DEBUG_RATE(mvm,
"RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n",
lq_sta->active_legacy_rate,
lq_sta->active_siso_rate,
lq_sta->active_mimo2_rate,
lq_sta->is_vht);
lq_sta->is_vht, lq_sta->ldpc);
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
lq_sta->max_legacy_rate_idx,
lq_sta->max_siso_rate_idx,
@ -3032,8 +3023,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(is_ht20(rate)) ? "20MHz" :
(is_ht40(rate)) ? "40MHz" :
(is_ht80(rate)) ? "80Mhz" : "BAD BW");
desc += sprintf(buff+desc, " %s %s\n",
desc += sprintf(buff+desc, " %s %s %s\n",
(rate->sgi) ? "SGI" : "NGI",
(rate->ldpc) ? "LDPC" : "BCC",
(lq_sta->is_agg) ? "AGG on" : "");
}
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
@ -3181,7 +3173,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file,
"%s,", column_name[col]);
for (rate = 0; rate < IWL_RATE_COUNT; rate++) {
stats = &(lq_sta->tx_stats[col][rate]);
stats = &(lq_sta->pers.tx_stats[col][rate]);
pos += scnprintf(pos, endpos - pos,
"%llu/%llu,",
stats->success,
@ -3200,7 +3192,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_lq_sta *lq_sta = file->private_data;
memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats));
memset(lq_sta->pers.tx_stats, 0, sizeof(lq_sta->pers.tx_stats));
return count;
}

View File

@ -207,6 +207,7 @@ struct rs_rate {
u8 ant;
u32 bw;
bool sgi;
bool ldpc;
};
@ -329,10 +330,9 @@ struct iwl_lq_sta {
*/
u64 last_tx;
bool is_vht;
bool ldpc; /* LDPC Rx is supported by the STA */
enum ieee80211_band band;
struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
unsigned long active_legacy_rate;
unsigned long active_siso_rate;
@ -343,7 +343,6 @@ struct iwl_lq_sta {
u8 max_siso_rate_idx;
u8 max_mimo2_rate_idx;
s8 max_rate_idx; /* Max rate set by user */
u8 missed_rate_counter;
struct iwl_lq_cmd lq;
@ -361,11 +360,14 @@ struct iwl_lq_sta {
int tpc_reduce;
/* persistent fields - initialized only once - keep last! */
struct {
struct lq_sta_pers {
#ifdef CONFIG_MAC80211_DEBUGFS
u32 dbg_fixed_rate;
u8 dbg_fixed_txp_reduction;
#endif
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
struct iwl_mvm *drv;
} pers;
};

View File

@ -160,8 +160,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
{
if (band == IEEE80211_BAND_2GHZ)
return 30 + 3 * (n_ssids + 1);
return 20 + 2 * (n_ssids + 1);
return 20 + 3 * (n_ssids + 1);
return 10 + 2 * (n_ssids + 1);
}
static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)

View File

@ -179,6 +179,10 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
struct ieee80211_sta *sta;
int ret = 0;
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF &&
mvm->cfg->disable_dummy_notification)
sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
/*
* If an associated AP sta changed its antenna configuration, the state
* will remain FULL_ON but SF parameters need to be reconsidered.

View File

@ -948,8 +948,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
tid_data->ssn = 0xffff;
tid_data->state = IWL_AGG_OFF;
mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE;
spin_unlock_bh(&mvmsta->lock);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
iwl_trans_txq_disable(mvm->trans, txq_id, true);
/* fall through */
return 0;
case IWL_AGG_STARTING:
case IWL_EMPTYING_HW_QUEUE_ADDBA:
/*
@ -1003,6 +1011,8 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true);
}

View File

@ -0,0 +1,149 @@
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "mvm.h"
#include "time-event.h"
void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
{
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
int i;
lockdep_assert_held(&mvm->mutex);
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
lockdep_is_held(&mvm->mutex));
if (!sta || IS_ERR(sta) || !sta->tdls)
continue;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
NL80211_TDLS_TEARDOWN,
WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
GFP_KERNEL);
}
}
int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
int count = 0;
int i;
lockdep_assert_held(&mvm->mutex);
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
lockdep_is_held(&mvm->mutex));
if (!sta || IS_ERR(sta) || !sta->tdls)
continue;
if (vif) {
mvmsta = iwl_mvm_sta_from_mac80211(sta);
if (mvmsta->vif != vif)
continue;
}
count++;
}
return count;
}
void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool sta_added)
{
int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);
/*
* Disable ps when the first TDLS sta is added and re-enable it
* when the last TDLS sta is removed
*/
if ((tdls_sta_cnt == 1 && sta_added) ||
(tdls_sta_cnt == 0 && !sta_added))
iwl_mvm_power_update_mac(mvm);
}
void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
/*
* iwl_mvm_protect_session() reads directly from the device
* (the system time), so make sure it is available.
*/
if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
return;
mutex_lock(&mvm->mutex);
/* Protect the session to hear the TDLS setup response on the channel */
iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true);
mutex_unlock(&mvm->mutex);
iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
}

View File

@ -700,9 +700,9 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)
iwl_mvm_roc_finished(mvm);
}
int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 duration, u32 apply_time)
int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 duration, u32 apply_time)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
@ -711,14 +711,14 @@ int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
if (te_data->running) {
IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n");
IWL_DEBUG_TE(mvm, "CS period is already scheduled\n");
return -EBUSY;
}
time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
time_cmd.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA);
time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD);
time_cmd.apply_time = cpu_to_le32(apply_time);
time_cmd.max_frags = TE_V2_FRAG_NONE;
time_cmd.duration = cpu_to_le32(duration);

Some files were not shown because too many files have changed in this diff Show More