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

This commit is contained in:
David S. Miller 2012-05-14 18:00:48 -04:00
commit c597f6653d
43 changed files with 902 additions and 253 deletions

View file

@ -1122,12 +1122,12 @@ exit:
static void at76_dump_mib_local(struct at76_priv *priv)
{
int ret;
struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
struct mib_local *m = kmalloc(sizeof(*m), GFP_KERNEL);
if (!m)
return;
ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local));
ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(*m));
if (ret < 0) {
wiphy_err(priv->hw->wiphy,
"at76_get_mib (LOCAL) failed: %d\n", ret);

View file

@ -36,6 +36,15 @@ config BRCMFMAC_SDIO
IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
use the driver for a SDIO wireless card.
config BRCMFMAC_SDIO_OOB
bool "Out of band interrupt support for SDIO interface chipset"
depends on BRCMFMAC_SDIO
---help---
This option enables out-of-band interrupt support for Broadcom
SDIO Wifi chipset using fullmac in order to gain better
performance and deep sleep wake up capability on certain
platforms. Say N if you are unsure.
config BRCMFMAC_USB
bool "USB bus interface support for FullMAC driver"
depends on USB

View file

@ -39,37 +39,113 @@
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
static void brcmf_sdioh_irqhandler(struct sdio_func *func)
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
{
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id);
brcmf_dbg(TRACE, "***IRQHandler\n");
brcmf_dbg(INTR, "oob intr triggered\n");
sdio_release_host(func);
/*
* out-of-band interrupt is level-triggered which won't
* be cleared until dpc
*/
if (sdiodev->irq_en) {
disable_irq_nosync(irq);
sdiodev->irq_en = false;
}
brcmf_sdbrcm_isr(sdiodev->bus);
sdio_claim_host(func);
return IRQ_HANDLED;
}
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
u8 data;
unsigned long flags;
brcmf_dbg(TRACE, "Entering\n");
brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq);
ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
sdiodev->irq_flags, "brcmf_oob_intr",
&sdiodev->func[1]->card->dev);
if (ret != 0)
return ret;
spin_lock_init(&sdiodev->irq_en_lock);
spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
sdiodev->irq_en = true;
spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
ret = enable_irq_wake(sdiodev->irq);
if (ret != 0)
return ret;
sdiodev->irq_wake = true;
/* must configure SDIO_CCCR_IENx to enable irq */
data = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_0,
SDIO_CCCR_IENx, &ret);
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx,
data, &ret);
/* redirect, configure ane enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
data, &ret);
return 0;
}
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(TRACE, "Entering\n");
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
0, NULL);
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, 0, NULL);
if (sdiodev->irq_wake) {
disable_irq_wake(sdiodev->irq);
sdiodev->irq_wake = false;
}
free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev);
sdiodev->irq_en = false;
return 0;
}
#else /* CONFIG_BRCMFMAC_SDIO_OOB */
static void brcmf_sdio_irqhandler(struct sdio_func *func)
{
struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
brcmf_dbg(INTR, "ib intr triggered\n");
brcmf_sdbrcm_isr(sdiodev->bus);
}
/* dummy handler for SDIO function 2 interrupt */
static void brcmf_sdioh_dummy_irq_handler(struct sdio_func *func)
static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
{
}
int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(TRACE, "Entering\n");
sdio_claim_host(sdiodev->func[1]);
sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler);
sdio_claim_irq(sdiodev->func[2], brcmf_sdioh_dummy_irq_handler);
sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler);
sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
sdio_release_host(sdiodev->func[1]);
return 0;
}
int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(TRACE, "Entering\n");
@ -80,6 +156,7 @@ int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev)
return 0;
}
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
int *err)

View file

@ -27,6 +27,7 @@
#include <linux/errno.h>
#include <linux/sched.h> /* request_irq() */
#include <linux/module.h>
#include <linux/platform_device.h>
#include <net/cfg80211.h>
#include <defs.h>
@ -55,6 +56,15 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static struct list_head oobirq_lh;
struct brcmf_sdio_oobirq {
unsigned int irq;
unsigned long flags;
struct list_head list;
};
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
static bool
brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
{
@ -107,7 +117,8 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
}
sdio_release_host(sdfunc);
}
} else if (regaddr == SDIO_CCCR_ABORT) {
} else if ((regaddr == SDIO_CCCR_ABORT) ||
(regaddr == SDIO_CCCR_IENx)) {
sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func),
GFP_KERNEL);
if (!sdfunc)
@ -467,12 +478,40 @@ void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
}
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
{
struct brcmf_sdio_oobirq *oobirq_entry;
if (list_empty(&oobirq_lh)) {
brcmf_dbg(ERROR, "no valid oob irq resource\n");
return -ENXIO;
}
oobirq_entry = list_first_entry(&oobirq_lh, struct brcmf_sdio_oobirq,
list);
sdiodev->irq = oobirq_entry->irq;
sdiodev->irq_flags = oobirq_entry->flags;
list_del(&oobirq_entry->list);
kfree(oobirq_entry);
return 0;
}
#else
static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
{
return 0;
}
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int ret = 0;
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(TRACE, "func->class=%x\n", func->class);
brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
@ -511,6 +550,10 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
sdiodev = dev_get_drvdata(&func->card->dev);
if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
return -ENODEV;
ret = brcmf_sdio_getintrcfg(sdiodev);
if (ret)
return ret;
sdiodev->func[2] = func;
bus_if = sdiodev->bus_if;
@ -603,6 +646,65 @@ static struct sdio_driver brcmf_sdmmc_driver = {
#endif /* CONFIG_PM_SLEEP */
};
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static int brcmf_sdio_pd_probe(struct platform_device *pdev)
{
struct resource *res;
struct brcmf_sdio_oobirq *oobirq_entry;
int i, ret;
INIT_LIST_HEAD(&oobirq_lh);
for (i = 0; ; i++) {
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
if (!res)
break;
oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq),
GFP_KERNEL);
oobirq_entry->irq = res->start;
oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK;
list_add_tail(&oobirq_entry->list, &oobirq_lh);
}
if (i == 0)
return -ENXIO;
ret = sdio_register_driver(&brcmf_sdmmc_driver);
if (ret)
brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret);
return ret;
}
static struct platform_driver brcmf_sdio_pd = {
.probe = brcmf_sdio_pd_probe,
.driver = {
.name = "brcmf_sdio_pd"
}
};
void brcmf_sdio_exit(void)
{
brcmf_dbg(TRACE, "Enter\n");
sdio_unregister_driver(&brcmf_sdmmc_driver);
platform_driver_unregister(&brcmf_sdio_pd);
}
void brcmf_sdio_init(void)
{
int ret;
brcmf_dbg(TRACE, "Enter\n");
ret = platform_driver_register(&brcmf_sdio_pd);
if (ret)
brcmf_dbg(ERROR, "platform_driver_register failed: %d\n", ret);
}
#else
void brcmf_sdio_exit(void)
{
brcmf_dbg(TRACE, "Enter\n");
@ -621,3 +723,4 @@ void brcmf_sdio_init(void)
if (ret)
brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret);
}
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */

View file

@ -2352,6 +2352,24 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
up(&bus->sdsem);
}
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
{
unsigned long flags;
spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
if (!bus->sdiodev->irq_en && !bus->ipend) {
enable_irq(bus->sdiodev->irq);
bus->sdiodev->irq_en = true;
}
spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
}
#else
static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
{
}
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
{
u32 intstatus, newstatus = 0;
@ -2509,6 +2527,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
bus->intstatus = intstatus;
clkwait:
brcmf_sdbrcm_clrintr(bus);
if (data_ok(bus) && bus->ctrl_frame_stat &&
(bus->clkstate == CLK_AVAIL)) {
int ret, i;
@ -3508,8 +3528,14 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
if (ret == 0) {
ret = brcmf_sdio_intr_register(bus->sdiodev);
if (ret != 0)
brcmf_dbg(ERROR, "intr register failed:%d\n", ret);
}
/* If we didn't come up, turn off backplane clock */
if (!ret)
if (bus_if->state != BRCMF_BUS_DATA)
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
exit:
@ -3867,7 +3893,7 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
if (bus) {
/* De-register interrupt handler */
brcmf_sdcard_intr_dereg(bus->sdiodev);
brcmf_sdio_intr_unregister(bus->sdiodev);
if (bus->sdiodev->bus_if->drvr) {
brcmf_detach(bus->sdiodev->dev);
@ -3968,15 +3994,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
goto fail;
}
/* Register interrupt callback, but mask it (not operational yet). */
brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n");
ret = brcmf_sdcard_intr_reg(bus->sdiodev);
if (ret != 0) {
brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret);
goto fail;
}
brcmf_dbg(INTR, "registered SDIO interrupt function ok\n");
brcmf_dbg(INFO, "completed!!\n");
/* if firmware path present try to download and bring up bus */

View file

@ -43,6 +43,13 @@
/* as of sdiod rev 0, supports 3 functions */
#define SBSDIO_NUM_FUNCTION 3
/* function 0 vendor specific CCCR registers */
#define SDIO_CCCR_BRCM_SEPINT 0xf2
#define SDIO_SEPINT_MASK 0x01
#define SDIO_SEPINT_OE 0x02
#define SDIO_SEPINT_ACT_HI 0x04
/* function 1 miscellaneous registers */
/* sprom command and status */
@ -144,13 +151,18 @@ struct brcmf_sdio_dev {
wait_queue_head_t request_buffer_wait;
struct device *dev;
struct brcmf_bus *bus_if;
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
unsigned int irq; /* oob interrupt number */
unsigned long irq_flags; /* board specific oob flags */
bool irq_en; /* irq enable flags */
spinlock_t irq_en_lock;
bool irq_wake; /* irq wake enable flags */
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
};
/* Register/deregister device interrupt handler. */
extern int
brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev);
extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev);
/* Register/deregister interrupt handler. */
extern int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev);
extern int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev);
/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface).
* fn: function number

View file

@ -1963,10 +1963,8 @@ static int ipw2100_wdev_init(struct net_device *dev)
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
if (wiphy_register(wdev->wiphy)) {
ipw2100_down(priv);
if (wiphy_register(wdev->wiphy))
return -EIO;
}
return 0;
}
@ -6331,6 +6329,11 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
printk(KERN_INFO DRV_NAME
": Detected Intel PRO/Wireless 2100 Network Connection\n");
err = ipw2100_wdev_init(dev);
if (err)
goto fail;
registered = 1;
/* Bring up the interface. Pre 0.46, after we registered the
* network device we would call ipw2100_up. This introduced a race
* condition with newer hotplug configurations (network was coming
@ -6347,11 +6350,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
"Error calling register_netdev.\n");
goto fail;
}
registered = 1;
err = ipw2100_wdev_init(dev);
if (err)
goto fail;
registered = 2;
mutex_lock(&priv->action_mutex);
@ -6390,13 +6389,16 @@ out:
fail_unlock:
mutex_unlock(&priv->action_mutex);
wiphy_unregister(priv->ieee->wdev.wiphy);
kfree(priv->ieee->bg_band.channels);
fail:
if (dev) {
if (registered)
if (registered >= 2)
unregister_netdev(dev);
if (registered) {
wiphy_unregister(priv->ieee->wdev.wiphy);
kfree(priv->ieee->bg_band.channels);
}
ipw2100_hw_stop_adapter(priv);
ipw2100_disable_interrupts(priv);

View file

@ -11443,20 +11443,6 @@ static void ipw_bg_down(struct work_struct *work)
mutex_unlock(&priv->mutex);
}
/* Called by register_netdev() */
static int ipw_net_init(struct net_device *dev)
{
int rc = 0;
struct ipw_priv *priv = libipw_priv(dev);
mutex_lock(&priv->mutex);
if (ipw_up(priv))
rc = -EIO;
mutex_unlock(&priv->mutex);
return rc;
}
static int ipw_wdev_init(struct net_device *dev)
{
int i, rc = 0;
@ -11725,7 +11711,6 @@ static void ipw_prom_free(struct ipw_priv *priv)
#endif
static const struct net_device_ops ipw_netdev_ops = {
.ndo_init = ipw_net_init,
.ndo_open = ipw_net_open,
.ndo_stop = ipw_net_stop,
.ndo_set_rx_mode = ipw_net_set_multicast_list,
@ -11848,17 +11833,24 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
goto out_release_irq;
}
mutex_unlock(&priv->mutex);
err = register_netdev(net_dev);
if (err) {
IPW_ERROR("failed to register network device\n");
if (ipw_up(priv)) {
mutex_unlock(&priv->mutex);
err = -EIO;
goto out_remove_sysfs;
}
mutex_unlock(&priv->mutex);
err = ipw_wdev_init(net_dev);
if (err) {
IPW_ERROR("failed to register wireless device\n");
goto out_unregister_netdev;
goto out_remove_sysfs;
}
err = register_netdev(net_dev);
if (err) {
IPW_ERROR("failed to register network device\n");
goto out_unregister_wiphy;
}
#ifdef CONFIG_IPW2200_PROMISCUOUS
@ -11867,10 +11859,8 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
if (err) {
IPW_ERROR("Failed to register promiscuous network "
"device (error %d).\n", err);
wiphy_unregister(priv->ieee->wdev.wiphy);
kfree(priv->ieee->a_band.channels);
kfree(priv->ieee->bg_band.channels);
goto out_unregister_netdev;
unregister_netdev(priv->net_dev);
goto out_unregister_wiphy;
}
}
#endif
@ -11882,8 +11872,10 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
return 0;
out_unregister_netdev:
unregister_netdev(priv->net_dev);
out_unregister_wiphy:
wiphy_unregister(priv->ieee->wdev.wiphy);
kfree(priv->ieee->a_band.channels);
kfree(priv->ieee->bg_band.channels);
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
out_release_irq:

View file

@ -186,76 +186,8 @@ done:
/*
* BT coex
*/
/*
* Macros to access the lookup table.
*
* The lookup table has 7 inputs: bt3_prio, bt3_txrx, bt_rf_act, wifi_req,
* wifi_prio, wifi_txrx and wifi_sh_ant_req.
*
* It has three outputs: WLAN_ACTIVE, WLAN_KILL and ANT_SWITCH
*
* The format is that "registers" 8 through 11 contain the WLAN_ACTIVE bits
* one after another in 32-bit registers, and "registers" 0 through 7 contain
* the WLAN_KILL and ANT_SWITCH bits interleaved (in that order).
*
* These macros encode that format.
*/
#define LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, wifi_req, wifi_prio, \
wifi_txrx, wifi_sh_ant_req) \
(bt3_prio | (bt3_txrx << 1) | (bt_rf_act << 2) | (wifi_req << 3) | \
(wifi_prio << 4) | (wifi_txrx << 5) | (wifi_sh_ant_req << 6))
#define LUT_PTA_WLAN_ACTIVE_OP(lut, op, val) \
lut[8 + ((val) >> 5)] op (cpu_to_le32(BIT((val) & 0x1f)))
#define LUT_TEST_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
(!!(LUT_PTA_WLAN_ACTIVE_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, \
bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
wifi_sh_ant_req))))
#define LUT_SET_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
LUT_PTA_WLAN_ACTIVE_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, \
bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
wifi_sh_ant_req))
#define LUT_CLEAR_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, \
wifi_req, wifi_prio, wifi_txrx, \
wifi_sh_ant_req) \
LUT_PTA_WLAN_ACTIVE_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, \
bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
wifi_sh_ant_req))
#define LUT_WLAN_KILL_OP(lut, op, val) \
lut[(val) >> 4] op (cpu_to_le32(BIT(((val) << 1) & 0x1e)))
#define LUT_TEST_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
(!!(LUT_WLAN_KILL_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))))
#define LUT_SET_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
LUT_WLAN_KILL_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
#define LUT_CLEAR_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
LUT_WLAN_KILL_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
#define LUT_ANT_SWITCH_OP(lut, op, val) \
lut[(val) >> 4] op (cpu_to_le32(BIT((((val) << 1) & 0x1e) + 1)))
#define LUT_TEST_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
(!!(LUT_ANT_SWITCH_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
wifi_req, wifi_prio, wifi_txrx, \
wifi_sh_ant_req))))
#define LUT_SET_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
LUT_ANT_SWITCH_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
#define LUT_CLEAR_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
wifi_prio, wifi_txrx, wifi_sh_ant_req) \
LUT_ANT_SWITCH_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
static const __le32 iwlagn_def_3w_lookup[12] = {
/* Notmal TDM */
static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaeaaaaaa),
@ -270,7 +202,25 @@ static const __le32 iwlagn_def_3w_lookup[12] = {
cpu_to_le32(0xf0005000),
};
static const __le32 iwlagn_concurrent_lookup[12] = {
/* Loose Coex */
static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaeaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xcc00ff28),
cpu_to_le32(0x0000aaaa),
cpu_to_le32(0xcc00aaaa),
cpu_to_le32(0x0000aaaa),
cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000),
cpu_to_le32(0xf0005000),
cpu_to_le32(0xf0005000),
};
/* Full concurrency */
static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
@ -325,6 +275,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
basic.kill_ack_mask = priv->kill_ack_mask;
basic.kill_cts_mask = priv->kill_cts_mask;
basic.reduce_txpower = priv->reduced_txpower;
basic.valid = priv->bt_valid;
/*
@ -610,29 +561,62 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv,
BT_UART_MSG_FRAME7CONNECTABLE_POS);
}
static void iwlagn_set_kill_msk(struct iwl_priv *priv,
static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
struct iwl_bt_uart_msg *uart_msg)
{
u8 kill_msk;
static const __le32 bt_kill_ack_msg[2] = {
bool need_update = false;
u8 kill_msk = IWL_BT_KILL_REDUCE;
static const __le32 bt_kill_ack_msg[3] = {
IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
IWLAGN_BT_KILL_ACK_CTS_MASK_SCO };
static const __le32 bt_kill_cts_msg[2] = {
IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
static const __le32 bt_kill_cts_msg[3] = {
IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
IWLAGN_BT_KILL_ACK_CTS_MASK_SCO };
IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
? 1 : 0;
if (!priv->reduced_txpower)
kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
? IWL_BT_KILL_OVERRIDE : IWL_BT_KILL_DEFAULT;
if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
/* schedule to send runtime bt_config */
queue_work(priv->workqueue, &priv->bt_runtime_config);
need_update = true;
}
return need_update;
}
static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
struct iwl_bt_uart_msg *uart_msg)
{
bool need_update = false;
if (!priv->reduced_txpower &&
!iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)) &&
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK))) {
/* enabling reduced tx power */
priv->reduced_txpower = true;
priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
need_update = true;
} else if (priv->reduced_txpower &&
(iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)))) {
/* disable reduced tx power */
priv->reduced_txpower = false;
priv->bt_valid &= ~IWLAGN_BT_VALID_REDUCED_TX_PWR;
need_update = true;
}
return need_update;
}
int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
@ -680,7 +664,12 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
}
}
iwlagn_set_kill_msk(priv, uart_msg);
/* schedule to send runtime bt_config */
/* check reduce power before change ack/cts kill mask */
if (iwlagn_fill_txpower_mode(priv, uart_msg) ||
iwlagn_set_kill_msk(priv, uart_msg))
queue_work(priv->workqueue, &priv->bt_runtime_config);
/* FIXME: based on notification, adjust the prio_boost */

View file

@ -764,7 +764,8 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
fraglen = len - hdrlen;
if (fraglen) {
int offset = (void *)hdr - rxb_addr(rxb) + rxb_offset(rxb);
int offset = (void *)hdr + hdrlen -
rxb_addr(rxb) + rxb_offset(rxb);
skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
fraglen, rxb->truesize);

View file

@ -1307,6 +1307,9 @@ static int iwl_init_geos(struct iwl_priv *priv)
priv->hw_params.sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
}
if (iwlwifi_mod_params.disable_5ghz)
priv->bands[IEEE80211_BAND_5GHZ].n_channels = 0;
IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
priv->bands[IEEE80211_BAND_2GHZ].n_channels,
priv->bands[IEEE80211_BAND_5GHZ].n_channels);
@ -1417,38 +1420,37 @@ void iwl_set_hw_params(struct iwl_priv *priv)
void iwl_debug_config(struct iwl_priv *priv)
/* show what optional capabilities we have */
void iwl_option_config(struct iwl_priv *priv)
{
dev_printk(KERN_INFO, priv->trans->dev, "CONFIG_IWLWIFI_DEBUG "
#ifdef CONFIG_IWLWIFI_DEBUG
"enabled\n");
IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n");
#else
"disabled\n");
#endif
dev_printk(KERN_INFO, priv->trans->dev, "CONFIG_IWLWIFI_DEBUGFS "
#ifdef CONFIG_IWLWIFI_DEBUGFS
"enabled\n");
#else
"disabled\n");
#endif
dev_printk(KERN_INFO, priv->trans->dev, "CONFIG_IWLWIFI_DEVICE_TRACING "
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
"enabled\n");
#else
"disabled\n");
IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n");
#endif
dev_printk(KERN_INFO, priv->trans->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE "
#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
"enabled\n");
#ifdef CONFIG_IWLWIFI_DEBUGFS
IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n");
#else
"disabled\n");
IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n");
#endif
dev_printk(KERN_INFO, priv->trans->dev, "CONFIG_IWLWIFI_P2P "
#ifdef CONFIG_IWLWIFI_P2P
"enabled\n");
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n");
#else
"disabled\n");
IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n");
#endif
#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE enabled\n");
#else
IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE disabled\n");
#endif
#ifdef CONFIG_IWLWIFI_P2P
IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n");
#else
IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n");
#endif
}
@ -1567,8 +1569,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
/* show what debugging capabilities we have */
iwl_debug_config(priv);
iwl_option_config(priv);
IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
@ -1586,7 +1587,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
/* these spin locks will be used in apm_ops.init and EEPROM access
* we should init now
*/
spin_lock_init(&priv->trans->reg_lock);
spin_lock_init(&priv->statistics.lock);
/***********************

View file

@ -523,7 +523,7 @@ static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
void iwl_setup_deferred_work(struct iwl_priv *priv);
int iwl_send_wimax_coex(struct iwl_priv *priv);
int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
void iwl_debug_config(struct iwl_priv *priv);
void iwl_option_config(struct iwl_priv *priv);
void iwl_set_hw_params(struct iwl_priv *priv);
void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags);
int iwl_init_drv(struct iwl_priv *priv);

View file

@ -1877,9 +1877,16 @@ struct iwl_bt_cmd {
#define IWLAGN_BT3_T7_DEFAULT 1
enum iwl_bt_kill_idx {
IWL_BT_KILL_DEFAULT = 0,
IWL_BT_KILL_OVERRIDE = 1,
IWL_BT_KILL_REDUCE = 2,
};
#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT cpu_to_le32(0xffff0000)
#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT cpu_to_le32(0xffff0000)
#define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO cpu_to_le32(0xffffffff)
#define IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE cpu_to_le32(0)
#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
@ -1891,7 +1898,7 @@ struct iwl_bt_cmd {
#define IWLAGN_BT_VALID_3W_TIMERS cpu_to_le16(BIT(3))
#define IWLAGN_BT_VALID_KILL_ACK_MASK cpu_to_le16(BIT(4))
#define IWLAGN_BT_VALID_KILL_CTS_MASK cpu_to_le16(BIT(5))
#define IWLAGN_BT_VALID_BT4_TIMES cpu_to_le16(BIT(6))
#define IWLAGN_BT_VALID_REDUCED_TX_PWR cpu_to_le16(BIT(6))
#define IWLAGN_BT_VALID_3W_LUT cpu_to_le16(BIT(7))
#define IWLAGN_BT_ALL_VALID_MSK (IWLAGN_BT_VALID_ENABLE_FLAGS | \
@ -1900,9 +1907,11 @@ struct iwl_bt_cmd {
IWLAGN_BT_VALID_3W_TIMERS | \
IWLAGN_BT_VALID_KILL_ACK_MASK | \
IWLAGN_BT_VALID_KILL_CTS_MASK | \
IWLAGN_BT_VALID_BT4_TIMES | \
IWLAGN_BT_VALID_REDUCED_TX_PWR | \
IWLAGN_BT_VALID_3W_LUT)
#define IWLAGN_BT_DECISION_LUT_SIZE 12
struct iwl_basic_bt_cmd {
u8 flags;
u8 ledtime; /* unused */
@ -1913,8 +1922,9 @@ struct iwl_basic_bt_cmd {
u8 bt3_prio_sample_time;
u8 bt3_timer_t2_value;
__le16 bt4_reaction_time; /* unused */
__le32 bt3_lookup_table[12];
__le16 bt4_decision_time; /* unused */
__le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
u8 reduce_txpower;
u8 reserved;
__le16 valid;
};
@ -3634,6 +3644,9 @@ enum iwl_bt_coex_profile_traffic_load {
(0x3<<BT_UART_MSG_2_FRAME7RESERVED_POS)
#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62)
#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65)
struct iwl_bt_uart_msg {
u8 header;
u8 frame1;

View file

@ -921,6 +921,7 @@ struct iwl_priv {
__le32 kill_ack_mask;
__le32 kill_cts_mask;
__le16 bt_valid;
bool reduced_txpower;
u16 bt_on_thresh;
u16 bt_duration;
u16 dynamic_frag_thresh;

View file

@ -66,6 +66,7 @@
#include <linux/module.h>
#include "iwl-drv.h"
#include "iwl-debug.h"
#include "iwl-trans.h"
#include "iwl-op-mode.h"
#include "iwl-agn-hw.h"
@ -892,10 +893,9 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
int ret;
drv = kzalloc(sizeof(*drv), GFP_KERNEL);
if (!drv) {
dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_drv");
if (!drv)
return NULL;
}
drv->trans = trans;
drv->dev = trans->dev;
drv->cfg = cfg;
@ -905,7 +905,7 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
ret = iwl_request_firmware(drv, true);
if (ret) {
dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw");
IWL_ERR(trans, "Couldn't request the fw\n");
kfree(drv);
drv = NULL;
}
@ -1012,3 +1012,7 @@ module_param_named(auto_agg, iwlwifi_mod_params.auto_agg,
bool, S_IRUGO);
MODULE_PARM_DESC(auto_agg,
"enable agg w/o check traffic load (default: enable)");
module_param_named(5ghz_disable, iwlwifi_mod_params.disable_5ghz,
bool, S_IRUGO);
MODULE_PARM_DESC(5ghz_disable, "disable 5GHz band (default: 0 [enabled])");

View file

@ -60,8 +60,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#ifndef __iwl_shared_h__
#define __iwl_shared_h__
#ifndef __iwl_modparams_h__
#define __iwl_modparams_h__
#include <linux/types.h>
#include <linux/spinlock.h>
@ -103,6 +103,7 @@ enum iwl_power_level {
* @ant_coupling: antenna coupling in dB, default = 0
* @bt_ch_announce: BT channel inhibition, default = enable
* @auto_agg: enable agg. without check, default = true
* @disable_5ghz: disable 5GHz capability, default = false
*/
struct iwl_mod_params {
int sw_crypto;
@ -119,6 +120,7 @@ struct iwl_mod_params {
int ant_coupling;
bool bt_ch_announce;
bool auto_agg;
bool disable_5ghz;
};
#endif /* #__iwl_shared_h__ */
#endif /* #__iwl_modparams_h__ */

View file

@ -2175,6 +2175,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
/* Initialize the wait queue for commands */
init_waitqueue_head(&trans->wait_command_queue);
spin_lock_init(&trans->reg_lock);
return trans;

View file

@ -2,6 +2,7 @@
* Firmware loading and handling functions.
*/
#include <linux/sched.h>
#include <linux/firmware.h>
#include <linux/firmware.h>
#include <linux/module.h>

View file

@ -10,12 +10,12 @@ config MWIFIEX
mwifiex.
config MWIFIEX_SDIO
tristate "Marvell WiFi-Ex Driver for SD8787/SD8797"
tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797"
depends on MWIFIEX && MMC
select FW_LOADER
---help---
This adds support for wireless adapters based on Marvell
8787/8797 chipsets with SDIO interface.
8786/8787/8797 chipsets with SDIO interface.
If you choose to build it as a module, it will be called
mwifiex_sdio.

View file

@ -993,8 +993,7 @@ struct mwifiex_ie_types_wmm_queue_status {
struct ieee_types_vendor_header {
u8 element_id;
u8 len;
u8 oui[3];
u8 oui_type;
u8 oui[4]; /* 0~2: oui, 3: oui_type */
u8 oui_subtype;
u8 version;
} __packed;

View file

@ -253,6 +253,8 @@ static int mwifiex_sdio_resume(struct device *dev)
return 0;
}
/* Device ID for SD8786 */
#define SDIO_DEVICE_ID_MARVELL_8786 (0x9116)
/* Device ID for SD8787 */
#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
/* Device ID for SD8797 */
@ -260,6 +262,7 @@ static int mwifiex_sdio_resume(struct device *dev)
/* WLAN IDs */
static const struct sdio_device_id mwifiex_ids[] = {
{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786)},
{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797)},
{},
@ -1599,6 +1602,9 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
adapter->dev = &func->dev;
switch (func->device) {
case SDIO_DEVICE_ID_MARVELL_8786:
strcpy(adapter->fw_name, SD8786_DEFAULT_FW_NAME);
break;
case SDIO_DEVICE_ID_MARVELL_8797:
strcpy(adapter->fw_name, SD8797_DEFAULT_FW_NAME);
break;
@ -1807,5 +1813,6 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION);
MODULE_VERSION(SDIO_VERSION);
MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME);
MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME);
MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME);

View file

@ -28,6 +28,7 @@
#include "main.h"
#define SD8786_DEFAULT_FW_NAME "mrvl/sd8786_uapsta.bin"
#define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
#define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin"

View file

@ -102,6 +102,8 @@
#define BBP_SIZE 0x00ff
#define RF_BASE 0x0004
#define RF_SIZE 0x0010
#define RFCSR_BASE 0x0000
#define RFCSR_SIZE 0x0040
/*
* Number of TX queues.

View file

@ -836,6 +836,13 @@ const struct rt2x00debug rt2800_rt2x00debug = {
.word_size = sizeof(u32),
.word_count = RF_SIZE / sizeof(u32),
},
.rfcsr = {
.read = rt2800_rfcsr_read,
.write = rt2800_rfcsr_write,
.word_base = RFCSR_BASE,
.word_size = sizeof(u8),
.word_count = RFCSR_SIZE / sizeof(u8),
},
};
EXPORT_SYMBOL_GPL(rt2800_rt2x00debug);
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */

View file

@ -70,6 +70,7 @@ struct rt2x00debug_intf {
* - eeprom offset/value files
* - bbp offset/value files
* - rf offset/value files
* - rfcsr offset/value files
* - queue folder
* - frame dump file
* - queue stats file
@ -89,6 +90,8 @@ struct rt2x00debug_intf {
struct dentry *bbp_val_entry;
struct dentry *rf_off_entry;
struct dentry *rf_val_entry;
struct dentry *rfcsr_off_entry;
struct dentry *rfcsr_val_entry;
struct dentry *queue_folder;
struct dentry *queue_frame_dump_entry;
struct dentry *queue_stats_entry;
@ -131,6 +134,7 @@ struct rt2x00debug_intf {
unsigned int offset_eeprom;
unsigned int offset_bbp;
unsigned int offset_rf;
unsigned int offset_rfcsr;
};
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
@ -525,6 +529,7 @@ RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);
RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);
RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);
RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);
RT2X00DEBUGFS_OPS(rfcsr, "0x%.2x\n", u8);
static ssize_t rt2x00debug_read_dev_flags(struct file *file,
char __user *buf,
@ -614,7 +619,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
const struct rt2x00debug *debug = intf->debug;
char *data;
data = kzalloc(8 * MAX_LINE_LENGTH, GFP_KERNEL);
data = kzalloc(9 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return NULL;
@ -624,22 +629,22 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev);
data += sprintf(data, "\n");
data += sprintf(data, "register\tbase\twords\twordsize\n");
data += sprintf(data, "csr\t%d\t%d\t%d\n",
debug->csr.word_base,
debug->csr.word_count,
debug->csr.word_size);
data += sprintf(data, "eeprom\t%d\t%d\t%d\n",
debug->eeprom.word_base,
debug->eeprom.word_count,
debug->eeprom.word_size);
data += sprintf(data, "bbp\t%d\t%d\t%d\n",
debug->bbp.word_base,
debug->bbp.word_count,
debug->bbp.word_size);
data += sprintf(data, "rf\t%d\t%d\t%d\n",
debug->rf.word_base,
debug->rf.word_count,
debug->rf.word_size);
#define RT2X00DEBUGFS_SPRINTF_REGISTER(__name) \
{ \
if(debug->__name.read) \
data += sprintf(data, __stringify(__name) \
"\t%d\t%d\t%d\n", \
debug->__name.word_base, \
debug->__name.word_count, \
debug->__name.word_size); \
}
RT2X00DEBUGFS_SPRINTF_REGISTER(csr);
RT2X00DEBUGFS_SPRINTF_REGISTER(eeprom);
RT2X00DEBUGFS_SPRINTF_REGISTER(bbp);
RT2X00DEBUGFS_SPRINTF_REGISTER(rf);
RT2X00DEBUGFS_SPRINTF_REGISTER(rfcsr);
#undef RT2X00DEBUGFS_SPRINTF_REGISTER
blob->size = strlen(blob->data);
return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
@ -694,31 +699,34 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
if (IS_ERR(intf->register_folder) || !intf->register_folder)
goto exit;
#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
({ \
(__intf)->__name##_off_entry = \
debugfs_create_u32(__stringify(__name) "_offset", \
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
&(__intf)->offset_##__name); \
if (IS_ERR((__intf)->__name##_off_entry) \
|| !(__intf)->__name##_off_entry) \
goto exit; \
\
(__intf)->__name##_val_entry = \
debugfs_create_file(__stringify(__name) "_value", \
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
(__intf), &rt2x00debug_fop_##__name);\
if (IS_ERR((__intf)->__name##_val_entry) \
|| !(__intf)->__name##_val_entry) \
goto exit; \
#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
({ \
if(debug->__name.read) { \
(__intf)->__name##_off_entry = \
debugfs_create_u32(__stringify(__name) "_offset", \
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
&(__intf)->offset_##__name); \
if (IS_ERR((__intf)->__name##_off_entry) \
|| !(__intf)->__name##_off_entry) \
goto exit; \
\
(__intf)->__name##_val_entry = \
debugfs_create_file(__stringify(__name) "_value", \
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
(__intf), &rt2x00debug_fop_##__name); \
if (IS_ERR((__intf)->__name##_val_entry) \
|| !(__intf)->__name##_val_entry) \
goto exit; \
} \
})
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, eeprom);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, bbp);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rf);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rfcsr);
#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
@ -770,6 +778,8 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
debugfs_remove(intf->queue_stats_entry);
debugfs_remove(intf->queue_frame_dump_entry);
debugfs_remove(intf->queue_folder);
debugfs_remove(intf->rfcsr_val_entry);
debugfs_remove(intf->rfcsr_off_entry);
debugfs_remove(intf->rf_val_entry);
debugfs_remove(intf->rf_off_entry);
debugfs_remove(intf->bbp_val_entry);

View file

@ -65,6 +65,7 @@ struct rt2x00debug {
RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16);
RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8);
RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32);
RT2X00DEBUGFS_REGISTER_ENTRY(rfcsr, u8);
};
#endif /* RT2X00DEBUG_H */

View file

@ -2154,6 +2154,8 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors
* to synchronize to for 11s default synchronization method (see 11C.12.2.2)
*
* @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode.
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@ -2179,6 +2181,7 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_FORWARDING,
NL80211_MESHCONF_RSSI_THRESHOLD,
NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
NL80211_MESHCONF_HT_OPMODE,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,

View file

@ -821,6 +821,7 @@ struct mesh_config {
bool dot11MeshGateAnnouncementProtocol;
bool dot11MeshForwarding;
s32 rssi_threshold;
u16 ht_opmode;
};
/**
@ -1514,6 +1515,16 @@ struct cfg80211_gtk_rekey_data {
* later passes to cfg80211_probe_status().
*
* @set_noack_map: Set the NoAck Map for the TIDs.
*
* @get_et_sset_count: Ethtool API to get string-set count.
* See @ethtool_ops.get_sset_count
*
* @get_et_stats: Ethtool API to get a set of u64 stats.
* See @ethtool_ops.get_ethtool_stats
*
* @get_et_strings: Ethtool API to get a set of strings to describe stats
* and perhaps other supported types of ethtool data-sets.
* See @ethtool_ops.get_strings
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -1712,6 +1723,13 @@ struct cfg80211_ops {
struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy,
enum nl80211_channel_type *type);
int (*get_et_sset_count)(struct wiphy *wiphy,
struct net_device *dev, int sset);
void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev,
struct ethtool_stats *stats, u64 *data);
void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
u32 sset, u8 *data);
};
/*

View file

@ -2223,6 +2223,14 @@ enum ieee80211_rate_control_changed {
* The @tids parameter is a bitmap and tells the driver which TIDs the
* frames will be on; it will at most have two bits set.
* This callback must be atomic.
*
* @get_et_sset_count: Ethtool API to get string-set count.
*
* @get_et_stats: Ethtool API to get a set of u64 stats.
*
* @get_et_strings: Ethtool API to get a set of strings to describe stats
* and perhaps other supported types of ethtool data-sets.
*
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@ -2353,6 +2361,15 @@ struct ieee80211_ops {
u16 tids, int num_frames,
enum ieee80211_frame_release_type reason,
bool more_data);
int (*get_et_sset_count)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int sset);
void (*get_et_stats)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
void (*get_et_strings)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 sset, u8 *data);
};
/**

View file

@ -450,6 +450,180 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
}
static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "rx_bytes", "wep_weak_iv_count",
"rx_duplicates", "rx_fragments", "rx_dropped",
"tx_packets", "tx_bytes", "tx_fragments",
"tx_filtered", "tx_retry_failed", "tx_retries",
"beacon_loss", "sta_state", "txrate", "rxrate", "signal",
"channel", "noise", "ch_time", "ch_time_busy",
"ch_time_ext_busy", "ch_time_rx", "ch_time_tx"
};
#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats)
static int ieee80211_get_et_sset_count(struct wiphy *wiphy,
struct net_device *dev,
int sset)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int rv = 0;
if (sset == ETH_SS_STATS)
rv += STA_STATS_LEN;
rv += drv_get_et_sset_count(sdata, sset);
if (rv == 0)
return -EOPNOTSUPP;
return rv;
}
static void ieee80211_get_et_stats(struct wiphy *wiphy,
struct net_device *dev,
struct ethtool_stats *stats,
u64 *data)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
struct ieee80211_local *local = sdata->local;
struct station_info sinfo;
struct survey_info survey;
int i, q;
#define STA_STATS_SURVEY_LEN 7
memset(data, 0, sizeof(u64) * STA_STATS_LEN);
#define ADD_STA_STATS(sta) \
do { \
data[i++] += sta->rx_packets; \
data[i++] += sta->rx_bytes; \
data[i++] += sta->wep_weak_iv_count; \
data[i++] += sta->num_duplicates; \
data[i++] += sta->rx_fragments; \
data[i++] += sta->rx_dropped; \
\
data[i++] += sta->tx_packets; \
data[i++] += sta->tx_bytes; \
data[i++] += sta->tx_fragments; \
data[i++] += sta->tx_filtered_count; \
data[i++] += sta->tx_retry_failed; \
data[i++] += sta->tx_retry_count; \
data[i++] += sta->beacon_loss_count; \
} while (0)
/* For Managed stations, find the single station based on BSSID
* and use that. For interface types, iterate through all available
* stations and add stats for any station that is assigned to this
* network device.
*/
rcu_read_lock();
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
goto do_survey;
i = 0;
ADD_STA_STATS(sta);
data[i++] = sta->sta_state;
sinfo.filled = 0;
sta_set_sinfo(sta, &sinfo);
if (sinfo.filled | STATION_INFO_TX_BITRATE)
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.txrate);
i++;
if (sinfo.filled | STATION_INFO_RX_BITRATE)
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.rxrate);
i++;
if (sinfo.filled | STATION_INFO_SIGNAL_AVG)
data[i] = (u8)sinfo.signal_avg;
i++;
} else {
list_for_each_entry_rcu(sta, &local->sta_list, list) {
/* Make sure this station belongs to the proper dev */
if (sta->sdata->dev != dev)
continue;
i = 0;
ADD_STA_STATS(sta);
}
}
do_survey:
i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
/* Get survey stats for current channel */
q = 0;
while (true) {
survey.filled = 0;
if (drv_get_survey(local, q, &survey) != 0) {
survey.filled = 0;
break;
}
if (survey.channel &&
(local->oper_channel->center_freq ==
survey.channel->center_freq))
break;
q++;
}
if (survey.filled)
data[i++] = survey.channel->center_freq;
else
data[i++] = 0;
if (survey.filled & SURVEY_INFO_NOISE_DBM)
data[i++] = (u8)survey.noise;
else
data[i++] = -1LL;
if (survey.filled & SURVEY_INFO_CHANNEL_TIME)
data[i++] = survey.channel_time;
else
data[i++] = -1LL;
if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
data[i++] = survey.channel_time_busy;
else
data[i++] = -1LL;
if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
data[i++] = survey.channel_time_ext_busy;
else
data[i++] = -1LL;
if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX)
data[i++] = survey.channel_time_rx;
else
data[i++] = -1LL;
if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX)
data[i++] = survey.channel_time_tx;
else
data[i++] = -1LL;
rcu_read_unlock();
if (WARN_ON(i != STA_STATS_LEN))
return;
drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
}
static void ieee80211_get_et_strings(struct wiphy *wiphy,
struct net_device *dev,
u32 sset, u8 *data)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int sz_sta_stats = 0;
if (sset == ETH_SS_STATS) {
sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
memcpy(data, *ieee80211_gstrings_sta_stats, sz_sta_stats);
}
drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
}
static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *mac, struct station_info *sinfo)
@ -1364,6 +1538,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
return -ENOTSUPP;
conf->rssi_threshold = nconf->rssi_threshold;
}
if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) {
conf->ht_opmode = nconf->ht_opmode;
sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
}
return 0;
}
@ -2794,4 +2973,7 @@ struct cfg80211_ops mac80211_config_ops = {
#ifdef CONFIG_PM
.set_wakeup = ieee80211_set_wakeup,
#endif
.get_et_sset_count = ieee80211_get_et_sset_count,
.get_et_stats = ieee80211_get_et_stats,
.get_et_strings = ieee80211_get_et_strings,
};

View file

@ -35,6 +35,43 @@ static inline void drv_tx_frags(struct ieee80211_local *local,
local->ops->tx_frags(&local->hw, vif, sta, skbs);
}
static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata,
u32 sset, u8 *data)
{
struct ieee80211_local *local = sdata->local;
if (local->ops->get_et_strings) {
trace_drv_get_et_strings(local, sset);
local->ops->get_et_strings(&local->hw, &sdata->vif, sset, data);
trace_drv_return_void(local);
}
}
static inline void drv_get_et_stats(struct ieee80211_sub_if_data *sdata,
struct ethtool_stats *stats,
u64 *data)
{
struct ieee80211_local *local = sdata->local;
if (local->ops->get_et_stats) {
trace_drv_get_et_stats(local);
local->ops->get_et_stats(&local->hw, &sdata->vif, stats, data);
trace_drv_return_void(local);
}
}
static inline int drv_get_et_sset_count(struct ieee80211_sub_if_data *sdata,
int sset)
{
struct ieee80211_local *local = sdata->local;
int rv = 0;
if (local->ops->get_et_sset_count) {
trace_drv_get_et_sset_count(local, sset);
rv = local->ops->get_et_sset_count(&local->hw, &sdata->vif,
sset);
trace_drv_return_int(local, rv);
}
return rv;
}
static inline int drv_start(struct ieee80211_local *local)
{
int ret;

View file

@ -161,6 +161,21 @@ DEFINE_EVENT(local_only_evt, drv_start,
TP_ARGS(local)
);
DEFINE_EVENT(local_u32_evt, drv_get_et_strings,
TP_PROTO(struct ieee80211_local *local, u32 sset),
TP_ARGS(local, sset)
);
DEFINE_EVENT(local_u32_evt, drv_get_et_sset_count,
TP_PROTO(struct ieee80211_local *local, u32 sset),
TP_ARGS(local, sset)
);
DEFINE_EVENT(local_only_evt, drv_get_et_stats,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
);
DEFINE_EVENT(local_only_evt, drv_suspend,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)

View file

@ -164,7 +164,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
sband->ht_cap.cap);
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
chan, channel_type);
chan, channel_type, 0);
}
if (local->hw.queues >= IEEE80211_NUM_ACS) {

View file

@ -1497,7 +1497,8 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 cap);
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type);
enum nl80211_channel_type channel_type,
u16 prot_mode);
/* internal work items */
void ieee80211_work_init(struct ieee80211_local *local);

View file

@ -76,6 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
u32 basic_rates = 0;
enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT;
/*
* As support for each feature is added, check for matching
@ -102,10 +103,15 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.bss_conf.basic_rates != basic_rates)
goto mismatch;
/* disallow peering with mismatched channel types for now */
if (ie->ht_operation)
sta_channel_type =
ieee80211_ht_oper_to_channel_type(ie->ht_operation);
/* Disallow HT40+/- mismatch */
if (ie->ht_operation &&
(local->_oper_channel_type !=
ieee80211_ht_oper_to_channel_type(ie->ht_operation)))
local->_oper_channel_type > NL80211_CHAN_HT20 &&
sta_channel_type > NL80211_CHAN_HT20 &&
local->_oper_channel_type != sta_channel_type)
goto mismatch;
return true;
@ -396,7 +402,8 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
return -ENOMEM;
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type);
ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type,
sdata->vif.bss_conf.ht_operation_mode);
return 0;
}
@ -588,12 +595,15 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
ieee80211_mesh_root_setup(ifmsh);
ieee80211_queue_work(&local->hw, &sdata->work);
sdata->vif.bss_conf.ht_operation_mode =
ifmsh->mshcfg.ht_opmode;
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
sdata->vif.bss_conf.basic_rates =
ieee80211_mandatory_rates(sdata->local,
sdata->local->hw.conf.channel->band);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_HT |
BSS_CHANGED_BASIC_RATES |
BSS_CHANGED_BEACON_INT);
}

View file

@ -102,12 +102,70 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
set_sta_flag(sta, WLAN_STA_WME);
if (sta_info_insert(sta))
return NULL;
return sta;
}
/** mesh_set_ht_prot_mode - set correct HT protection mode
*
* Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for
* HT mesh STA in a MBSS. Three HT protection modes are supported for now,
* non-HT mixed mode, 20MHz-protection and no-protection mode. non-HT mixed
* mode is selected if any non-HT peers are present in our MBSS.
* 20MHz-protection mode is selected if all peers in our 20/40MHz MBSS support
* HT and atleast one HT20 peer is present. Otherwise no-protection mode is
* selected.
*/
static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
u32 changed = 0;
u16 ht_opmode;
bool non_ht_sta = false, ht20_sta = false;
if (local->_oper_channel_type == NL80211_CHAN_NO_HT)
return 0;
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list) {
if (sdata == sta->sdata &&
sta->plink_state == NL80211_PLINK_ESTAB) {
switch (sta->ch_type) {
case NL80211_CHAN_NO_HT:
mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present",
sdata->vif.addr, sta->sta.addr);
non_ht_sta = true;
goto out;
case NL80211_CHAN_HT20:
mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present",
sdata->vif.addr, sta->sta.addr);
ht20_sta = true;
default:
break;
}
}
}
out:
rcu_read_unlock();
if (non_ht_sta)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
else
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
changed = BSS_CHANGED_HT;
mpl_dbg("mesh_plink %pM: protection mode changed to %d",
sdata->vif.addr, ht_opmode);
}
return changed;
}
/**
* __mesh_plink_deactivate - deactivate mesh peer link
*
@ -281,6 +339,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband;
u32 rates, basic_rates = 0;
struct sta_info *sta;
bool insert = false;
sband = local->hw.wiphy->bands[band];
rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
@ -290,6 +349,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
sta = mesh_plink_alloc(sdata, addr);
if (!sta)
return NULL;
insert = true;
}
spin_lock_bh(&sta->lock);
@ -303,9 +363,21 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
else
memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
if (elems->ht_operation) {
if (!(elems->ht_operation->ht_param &
IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
sta->sta.ht_cap.cap &=
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
sta->ch_type =
ieee80211_ht_oper_to_channel_type(elems->ht_operation);
}
rate_control_rate_init(sta);
spin_unlock_bh(&sta->lock);
if (insert && sta_info_insert(sta))
return NULL;
return sta;
}
@ -487,9 +559,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
enum plink_event event;
enum ieee80211_self_protected_actioncode ftype;
size_t baselen;
bool deactivated, matches_local = true;
bool matches_local = true;
u8 ie_len;
u8 *baseaddr;
u32 changed = 0;
__le16 plid, llid, reason;
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
static const char *mplstates[] = {
@ -775,7 +848,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
mesh_plink_inc_estab_count(sdata);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= BSS_CHANGED_BEACON;
mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
break;
@ -810,7 +884,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
mesh_plink_inc_estab_count(sdata);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= BSS_CHANGED_BEACON;
mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
mesh_plink_frame_tx(sdata,
@ -828,13 +903,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
case CLS_ACPT:
reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
sta->reason = reason;
deactivated = __mesh_plink_deactivate(sta);
__mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_HOLDING;
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
if (deactivated)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= BSS_CHANGED_BEACON;
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
sta->sta.addr, llid, plid, reason);
break;
@ -881,4 +956,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
}
rcu_read_unlock();
if (changed)
ieee80211_bss_info_change_notify(sdata, changed);
}

View file

@ -210,7 +210,7 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
disable_40 = true;
if (sta && (!reconfig ||
(disable_40 != !!(sta->sta.ht_cap.cap &
(disable_40 != !(sta->sta.ht_cap.cap &
IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
if (disable_40)

View file

@ -362,6 +362,7 @@ struct sta_info {
struct timer_list plink_timer;
s64 t_offset;
s64 t_offset_setpoint;
enum nl80211_channel_type ch_type;
#endif
#ifdef CONFIG_MAC80211_DEBUGFS

View file

@ -1663,7 +1663,8 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type)
enum nl80211_channel_type channel_type,
u16 prot_mode)
{
struct ieee80211_ht_operation *ht_oper;
/* Build HT Information */
@ -1689,11 +1690,7 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
channel_type != NL80211_CHAN_HT20)
ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
/*
* Note: According to 802.11n-2009 9.13.3.1, HT Protection field and
* RIFS Mode are reserved in IBSS mode, therefore keep them at 0
*/
ht_oper->operation_mode = 0x0000;
ht_oper->operation_mode = cpu_to_le16(prot_mode);
ht_oper->stbc_param = 0x0000;
/* It seems that Basic MCS set and Supported MCS set

View file

@ -68,6 +68,32 @@ static int cfg80211_set_ringparam(struct net_device *dev,
return -ENOTSUPP;
}
static int cfg80211_get_sset_count(struct net_device *dev, int sset)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
if (rdev->ops->get_et_sset_count)
return rdev->ops->get_et_sset_count(wdev->wiphy, dev, sset);
return -EOPNOTSUPP;
}
static void cfg80211_get_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
if (rdev->ops->get_et_stats)
rdev->ops->get_et_stats(wdev->wiphy, dev, stats, data);
}
static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
if (rdev->ops->get_et_strings)
rdev->ops->get_et_strings(wdev->wiphy, dev, sset, data);
}
const struct ethtool_ops cfg80211_ethtool_ops = {
.get_drvinfo = cfg80211_get_drvinfo,
.get_regs_len = cfg80211_get_regs_len,
@ -75,4 +101,7 @@ const struct ethtool_ops cfg80211_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_ringparam = cfg80211_get_ringparam,
.set_ringparam = cfg80211_set_ringparam,
.get_strings = cfg80211_get_strings,
.get_ethtool_stats = cfg80211_get_stats,
.get_sset_count = cfg80211_get_sset_count,
};

View file

@ -61,6 +61,7 @@ const struct mesh_config default_mesh_config = {
.dot11MeshGateAnnouncementProtocol = false,
.dot11MeshForwarding = true,
.rssi_threshold = MESH_RSSI_THRESHOLD,
.ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED,
};
const struct mesh_setup default_mesh_setup = {

View file

@ -3390,7 +3390,9 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
cur_params.dot11MeshForwarding) ||
nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
cur_params.rssi_threshold))
cur_params.rssi_threshold) ||
nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
cur_params.ht_opmode))
goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
@ -3426,6 +3428,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
[NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
[NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32},
[NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16},
};
static const struct nla_policy
@ -3523,6 +3526,8 @@ do {\
mask, NL80211_MESHCONF_FORWARDING, nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode,
mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16);
if (mask_out)
*mask_out = mask;

View file

@ -378,7 +378,11 @@ static int cmp_bss_core(struct cfg80211_bss *a,
b->len_information_elements);
}
return compare_ether_addr(a->bssid, b->bssid);
/*
* we can't use compare_ether_addr here since we need a < > operator.
* The binary return value of compare_ether_addr isn't enough
*/
return memcmp(a->bssid, b->bssid, sizeof(a->bssid));
}
static int cmp_bss(struct cfg80211_bss *a,