config BCMA_SFLASH
bool
- depends on BCMA_DRIVER_MIPS && BROKEN
+ depends on BCMA_DRIVER_MIPS
default y
config BCMA_NFLASH
bool
- depends on BCMA_DRIVER_MIPS && BROKEN
+ depends on BCMA_DRIVER_MIPS
default y
config BCMA_DRIVER_GMAC_CMN
#ifdef CONFIG_BCMA_SFLASH
/* driver_chipcommon_sflash.c */
int bcma_sflash_init(struct bcma_drv_cc *cc);
+extern struct platform_device bcma_sflash_dev;
#else
static inline int bcma_sflash_init(struct bcma_drv_cc *cc)
{
#ifdef CONFIG_BCMA_NFLASH
/* driver_chipcommon_nflash.c */
int bcma_nflash_init(struct bcma_drv_cc *cc);
+extern struct platform_device bcma_nflash_dev;
#else
static inline int bcma_nflash_init(struct bcma_drv_cc *cc)
{
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
-#include <linux/bcma/bcma_driver_chipcommon.h>
-#include <linux/delay.h>
#include "bcma_private.h"
+struct platform_device bcma_nflash_dev = {
+ .name = "bcma_nflash",
+ .num_resources = 0,
+};
+
/* Initialize NAND flash access */
int bcma_nflash_init(struct bcma_drv_cc *cc)
{
- bcma_err(cc->core->bus, "NAND flash support is broken\n");
+ struct bcma_bus *bus = cc->core->bus;
+
+ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
+ cc->core->id.rev != 0x38) {
+ bcma_err(bus, "NAND flash on unsupported board!\n");
+ return -ENOTSUPP;
+ }
+
+ if (!(cc->capabilities & BCMA_CC_CAP_NFLASH)) {
+ bcma_err(bus, "NAND flash not present according to ChipCommon\n");
+ return -ENODEV;
+ }
+
+ cc->nflash.present = true;
+
+ /* Prepare platform device, but don't register it yet. It's too early,
+ * malloc (required by device_private_init) is not available yet. */
+ bcma_nflash_dev.dev.platform_data = &cc->nflash;
+
return 0;
}
bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
}
-void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
}
/* query bus clock frequency for PMU-enabled chipcommon */
-u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
-#include <linux/bcma/bcma_driver_chipcommon.h>
-#include <linux/delay.h>
#include "bcma_private.h"
+static struct resource bcma_sflash_resource = {
+ .name = "bcma_sflash",
+ .start = BCMA_SFLASH,
+ .end = 0,
+ .flags = IORESOURCE_MEM | IORESOURCE_READONLY,
+};
+
+struct platform_device bcma_sflash_dev = {
+ .name = "bcma_sflash",
+ .resource = &bcma_sflash_resource,
+ .num_resources = 1,
+};
+
+struct bcma_sflash_tbl_e {
+ char *name;
+ u32 id;
+ u32 blocksize;
+ u16 numblocks;
+};
+
+static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+ { "", 0x14, 0x10000, 32, },
+ { 0 },
+};
+
+static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+ { 0 },
+};
+
+static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+ { 0 },
+};
+
+static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
+{
+ int i;
+ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
+ BCMA_CC_FLASHCTL_START | opcode);
+ for (i = 0; i < 1000; i++) {
+ if (!(bcma_cc_read32(cc, BCMA_CC_FLASHCTL) &
+ BCMA_CC_FLASHCTL_BUSY))
+ return;
+ cpu_relax();
+ }
+ bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
+}
+
/* Initialize serial flash access */
int bcma_sflash_init(struct bcma_drv_cc *cc)
{
- bcma_err(cc->core->bus, "Serial flash support is broken\n");
+ struct bcma_bus *bus = cc->core->bus;
+ struct bcma_sflash *sflash = &cc->sflash;
+ struct bcma_sflash_tbl_e *e;
+ u32 id, id2;
+
+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+ case BCMA_CC_FLASHT_STSER:
+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP);
+
+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0);
+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
+ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
+
+ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1);
+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
+ id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
+
+ switch (id) {
+ case 0xbf:
+ for (e = bcma_sflash_sst_tbl; e->name; e++) {
+ if (e->id == id2)
+ break;
+ }
+ break;
+ default:
+ for (e = bcma_sflash_st_tbl; e->name; e++) {
+ if (e->id == id)
+ break;
+ }
+ break;
+ }
+ if (!e->name) {
+ bcma_err(bus, "Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2);
+ return -ENOTSUPP;
+ }
+
+ break;
+ case BCMA_CC_FLASHT_ATSER:
+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
+ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
+
+ for (e = bcma_sflash_at_tbl; e->name; e++) {
+ if (e->id == id)
+ break;
+ }
+ if (!e->name) {
+ bcma_err(bus, "Unsupported Atmel serial flash (id: 0x%X)\n", id);
+ return -ENOTSUPP;
+ }
+
+ break;
+ default:
+ bcma_err(bus, "Unsupported flash type\n");
+ return -ENOTSUPP;
+ }
+
+ sflash->window = BCMA_SFLASH;
+ sflash->blocksize = e->blocksize;
+ sflash->numblocks = e->numblocks;
+ sflash->size = sflash->blocksize * sflash->numblocks;
+ sflash->present = true;
+
+ bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
+ e->name, sflash->size / 1024, sflash->blocksize,
+ sflash->numblocks);
+
+ /* Prepare platform device, but don't register it yet. It's too early,
+ * malloc (required by device_private_init) is not available yet. */
+ bcma_sflash_dev.resource[0].end = bcma_sflash_dev.resource[0].start +
+ sflash->size;
+ bcma_sflash_dev.dev.platform_data = sflash;
+
return 0;
}
}
#ifdef CONFIG_BCMA_BLOCKIO
-void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
- size_t count, u16 offset, u8 reg_width)
+static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
+ size_t count, u16 offset, u8 reg_width)
{
void __iomem *addr = core->bus->mmio + offset;
if (core->bus->mapped_core != core)
}
}
-void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
- size_t count, u16 offset, u8 reg_width)
+static void bcma_host_pci_block_write(struct bcma_device *core,
+ const void *buffer, size_t count,
+ u16 offset, u8 reg_width)
{
void __iomem *addr = core->bus->mmio + offset;
if (core->bus->mapped_core != core)
iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
}
-const struct bcma_host_ops bcma_host_pci_ops = {
+static const struct bcma_host_ops bcma_host_pci_ops = {
.read8 = bcma_host_pci_read8,
.read16 = bcma_host_pci_read16,
.read32 = bcma_host_pci_read32,
writel(value, core->io_wrap + offset);
}
-const struct bcma_host_ops bcma_host_soc_ops = {
+static const struct bcma_host_ops bcma_host_soc_ops = {
.read8 = bcma_host_soc_read8,
.read16 = bcma_host_soc_read16,
.read32 = bcma_host_soc_read32,
#include "bcma_private.h"
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
#include <linux/slab.h>
dev_id++;
}
+#ifdef CONFIG_BCMA_SFLASH
+ if (bus->drv_cc.sflash.present) {
+ err = platform_device_register(&bcma_sflash_dev);
+ if (err)
+ bcma_err(bus, "Error registering serial flash\n");
+ }
+#endif
+
+#ifdef CONFIG_BCMA_NFLASH
+ if (bus->drv_cc.nflash.present) {
+ err = platform_device_register(&bcma_nflash_dev);
+ if (err)
+ bcma_err(bus, "Error registering NAND flash\n");
+ }
+#endif
+
return 0;
}
void bcma_bus_unregister(struct bcma_bus *bus)
{
+ struct bcma_device *cores[3];
+
+ 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);
+
bcma_unregister_cores(bus);
+
+ kfree(cores[2]);
+ kfree(cores[1]);
+ kfree(cores[0]);
}
int __init bcma_bus_early_register(struct bcma_bus *bus,
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
BT_ERR("Can't allocate memory for data structure");
return -ENOMEM;
data->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!data->urb) {
BT_ERR("Can't allocate URB");
- kfree(data);
return -ENOMEM;
}
if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
BT_ERR("Mini driver request failed");
usb_free_urb(data->urb);
- kfree(data);
return -EIO;
}
BT_ERR("Can't allocate memory for mini driver");
release_firmware(firmware);
usb_free_urb(data->urb);
- kfree(data);
return -ENOMEM;
}
BT_ERR("Firmware request failed");
usb_free_urb(data->urb);
kfree(data->buffer);
- kfree(data);
return -EIO;
}
release_firmware(firmware);
usb_free_urb(data->urb);
kfree(data->buffer);
- kfree(data);
return -ENOMEM;
}
usb_free_urb(data->urb);
kfree(data->fw_data);
kfree(data->buffer);
- kfree(data);
}
static struct usb_driver bcm203x_driver = {
}
/* Initialize control structure and load firmware */
- data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
+ data = devm_kzalloc(&intf->dev, sizeof(struct bfusb_data), GFP_KERNEL);
if (!data) {
BT_ERR("Can't allocate memory for control structure");
goto done;
if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
BT_ERR("Firmware request failed");
- goto error;
+ goto done;
}
BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
hdev = hci_alloc_dev();
if (!hdev) {
BT_ERR("Can't allocate HCI device");
- goto error;
+ goto done;
}
data->hdev = hdev;
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
hci_free_dev(hdev);
- goto error;
+ goto done;
}
usb_set_intfdata(intf, data);
release:
release_firmware(firmware);
-error:
- kfree(data);
-
done:
return -EIO;
}
hci_unregister_dev(hdev);
hci_free_dev(hdev);
- kfree(data);
}
static struct usb_driver bfusb_driver = {
bluecard_info_t *info;
/* Create new info device */
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
static void bluecard_detach(struct pcmcia_device *link)
{
- bluecard_info_t *info = link->priv;
-
bluecard_release(link);
- kfree(info);
}
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
init_usb_anchor(&data->rx_anchor);
hdev = hci_alloc_dev();
- if (!hdev) {
- kfree(data);
+ if (!hdev)
return -ENOMEM;
- }
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
- kfree(data);
return err;
}
hci_free_dev(data->hdev);
kfree_skb(data->rx_skb[0]);
kfree_skb(data->rx_skb[1]);
- kfree(data);
}
static struct usb_driver bpa10x_driver = {
bt3c_info_t *info;
/* Create new info device */
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
static void bt3c_detach(struct pcmcia_device *link)
{
- bt3c_info_t *info = link->priv;
-
bt3c_release(link);
- kfree(info);
}
static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
id->vendor, id->device, id->class, func->num);
- card = kzalloc(sizeof(*card), GFP_KERNEL);
- if (!card) {
- ret = -ENOMEM;
- goto done;
- }
+ card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
card->func = func;
if (btmrvl_sdio_register_dev(card) < 0) {
BT_ERR("Failed to register BT device!");
- ret = -ENODEV;
- goto free_card;
+ return -ENODEV;
}
/* Disable the interrupts on the card */
btmrvl_sdio_disable_host_int(card);
unreg_dev:
btmrvl_sdio_unregister_dev(card);
-free_card:
- kfree(card);
-done:
return ret;
}
BT_DBG("unregester dev");
btmrvl_sdio_unregister_dev(card);
btmrvl_remove_card(card->priv);
- kfree(card);
}
}
}
tuple = tuple->next;
}
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
skb_queue_head_init(&data->txq);
hdev = hci_alloc_dev();
- if (!hdev) {
- kfree(data);
+ if (!hdev)
return -ENOMEM;
- }
hdev->bus = HCI_SDIO;
hci_set_drvdata(hdev, data);
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
- kfree(data);
return err;
}
hci_unregister_dev(hdev);
hci_free_dev(hdev);
- kfree(data);
}
static struct sdio_driver btsdio_driver = {
btuart_info_t *info;
/* Create new info device */
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
static void btuart_detach(struct pcmcia_device *link)
{
- btuart_info_t *info = link->priv;
-
btuart_release(link);
- kfree(info);
}
static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)
return -ENODEV;
}
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
}
}
- if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
- kfree(data);
+ if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
return -ENODEV;
- }
data->cmdreq_type = USB_TYPE_CLASS;
init_usb_anchor(&data->deferred);
hdev = hci_alloc_dev();
- if (!hdev) {
- kfree(data);
+ if (!hdev)
return -ENOMEM;
- }
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
data->isoc, data);
if (err < 0) {
hci_free_dev(hdev);
- kfree(data);
return err;
}
}
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
- kfree(data);
return err;
}
usb_driver_release_interface(&btusb_driver, data->isoc);
hci_free_dev(hdev);
- kfree(data);
}
#ifdef CONFIG_PM
struct hci_dev *hdev;
int err;
- hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL);
+ hst = devm_kzalloc(&pdev->dev, sizeof(struct ti_st), GFP_KERNEL);
if (!hst)
return -ENOMEM;
/* Expose "hciX" device to user space */
hdev = hci_alloc_dev();
- if (!hdev) {
- kfree(hst);
+ if (!hdev)
return -ENOMEM;
- }
BT_DBG("hdev %p", hdev);
err = hci_register_dev(hdev);
if (err < 0) {
BT_ERR("Can't register HCI device error %d", err);
- kfree(hst);
hci_free_dev(hdev);
return err;
}
hci_unregister_dev(hdev);
hci_free_dev(hdev);
- kfree(hst);
dev_set_drvdata(&pdev->dev, NULL);
return 0;
dtl1_info_t *info;
/* Create new info device */
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
dtl1_close(info);
pcmcia_disable_device(link);
- kfree(info);
}
static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
}
/* Put adm8211_tx_hdr on skb and transmit */
-static void adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
+static void adm8211_tx(struct ieee80211_hw *dev,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct adm8211_tx_hdr *txhdr;
size_t payload_len, hdrlen;
/* Include Wireless Extension definition and check version - Jean II */
#include <linux/wireless.h>
#define WIRELESS_SPY /* enable iwspy support */
-#include <net/iw_handler.h> /* New driver API */
#define CISCO_EXT /* enable Cisco extensions */
#ifdef CISCO_EXT
Cmd cmd;
Resp rsp;
APListRid APList_rid;
- static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
if (awrq->sa_family != ARPHRD_ETHER)
return -EINVAL;
- else if (!memcmp(any, awrq->sa_data, ETH_ALEN) ||
- !memcmp(off, awrq->sa_data, ETH_ALEN)) {
+ else if (is_broadcast_ether_addr(awrq->sa_data) ||
+ is_zero_ether_addr(awrq->sa_data)) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LOSE_SYNC;
if (down_interruptible(&local->sem))
ieee80211_wake_queues(priv->hw);
}
-static void at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void at76_mac80211_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct at76_priv *priv = hw->priv;
struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
unsigned int nexttbtt; /* next beacon time in TU */
struct ath5k_txq *cabq; /* content after beacon */
- int power_level; /* Requested tx power in dBm */
bool assoc; /* associate state */
bool enable_beacon; /* true if beacons are on */
/* Value in dB units */
s16 txp_cck_ofdm_pwr_delta;
bool txp_setup;
+ int txp_requested; /* Requested tx power in dBm */
} ah_txpower;
struct ath5k_nfcal_hist ah_nfcal_hist;
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), padsize,
get_hw_packet_type(skb),
- (ah->power_level * 2),
+ (ah->ah_txpower.txp_requested * 2),
hw_rate,
info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
cts_rate, duration);
ds->ds_data = bf->skbaddr;
ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb), padsize,
- AR5K_PKT_TYPE_BEACON, (ah->power_level * 2),
+ AR5K_PKT_TYPE_BEACON,
+ (ah->ah_txpower.txp_requested * 2),
ieee80211_get_tx_rate(ah->hw, info)->hw_value,
1, AR5K_TXKEYIX_INVALID,
antenna, flags, 0, 0);
\********************/
static void
-ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+ath5k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct ath5k_hw *ah = hw->priv;
u16 qnum = skb_get_queue_mapping(skb);
}
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
- (ah->power_level != conf->power_level)) {
- ah->power_level = conf->power_level;
+ (ah->ah_txpower.txp_requested != conf->power_level)) {
+ ah->ah_txpower.txp_requested = conf->power_level;
/* Half dB steps */
ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
{
unsigned int i;
u16 *rates;
+ s16 rate_idx_scaled = 0;
/* max_pwr is power level we got from driver/user in 0.5dB
* units, switch to 0.25dB units so we can compare */
for (i = 8; i <= 15; i++)
rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
+ /* Save min/max and current tx power for this channel
+ * in 0.25dB units.
+ *
+ * Note: We use rates[0] for current tx power because
+ * it covers most of the rates, in most cases. It's our
+ * tx power limit and what the user expects to see. */
+ ah->ah_txpower.txp_min_pwr = 2 * rates[7];
+ ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
+
+ /* Set max txpower for correct OFDM operation on all rates
+ * -that is the txpower for 54Mbit-, it's used for the PAPD
+ * gain probe and it's in 0.5dB units */
+ ah->ah_txpower.txp_ofdm = rates[7];
+
/* Now that we have all rates setup use table offset to
* match the power range set by user with the power indices
* on PCDAC/PDADC table */
for (i = 0; i < 16; i++) {
- rates[i] += ah->ah_txpower.txp_offset;
+ rate_idx_scaled = rates[i] + ah->ah_txpower.txp_offset;
/* Don't get out of bounds */
- if (rates[i] > 63)
- rates[i] = 63;
+ if (rate_idx_scaled > 63)
+ rate_idx_scaled = 63;
+ if (rate_idx_scaled < 0)
+ rate_idx_scaled = 0;
+ rates[i] = rate_idx_scaled;
}
-
- /* Min/max in 0.25dB units */
- ah->ah_txpower.txp_min_pwr = 2 * rates[7];
- ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
- ah->ah_txpower.txp_ofdm = rates[7];
}
if (!ah->ah_txpower.txp_setup ||
(channel->hw_value != curr_channel->hw_value) ||
(channel->center_freq != curr_channel->center_freq)) {
- /* Reset TX power values */
+ /* Reset TX power values but preserve requested
+ * tx power from above */
+ int requested_txpower = ah->ah_txpower.txp_requested;
+
memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+
+ /* Restore TPC setting and requested tx power */
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+ ah->ah_txpower.txp_requested = requested_txpower;
+
/* Calculate the powertable */
ret = ath5k_setup_channel_powertable(ah, channel,
ee_mode, type);
* RF buffer settings on 5211/5212+ so that we
* properly set curve indices.
*/
- ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_cur_pwr ?
- ah->ah_txpower.txp_cur_pwr / 2 : AR5K_TUNE_MAX_TXPOWER);
+ ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_requested ?
+ ah->ah_txpower.txp_requested * 2 :
+ AR5K_TUNE_MAX_TXPOWER);
if (ret)
return ret;
i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
chan->channel);
- /*
- * compare test group from regulatory
- * channel list with test mode from pCtlMode
- * list
- */
- if ((((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- ctlIndex[i]) ||
- (((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- ((ctlIndex[i] & CTL_MODE_M) |
- SD_NO_CTL))) {
- twiceMinEdgePower =
- ar9003_hw_get_max_edge_power(pEepData,
- freq, i,
- is2ghz);
-
- if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
- /*
- * Find the minimum of all CTL
- * edge powers that apply to
- * this channel
- */
- twiceMaxEdgePower =
- min(twiceMaxEdgePower,
- twiceMinEdgePower);
- else {
- /* specific */
- twiceMaxEdgePower =
- twiceMinEdgePower;
- break;
- }
+ /*
+ * compare test group from regulatory
+ * channel list with test mode from pCtlMode
+ * list
+ */
+ if ((((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ctlIndex[i]) ||
+ (((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ((ctlIndex[i] & CTL_MODE_M) |
+ SD_NO_CTL))) {
+ twiceMinEdgePower =
+ ar9003_hw_get_max_edge_power(pEepData,
+ freq, i,
+ is2ghz);
+
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
+ /*
+ * Find the minimum of all CTL
+ * edge powers that apply to
+ * this channel
+ */
+ twiceMaxEdgePower =
+ min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ else {
+ /* specific */
+ twiceMaxEdgePower = twiceMinEdgePower;
+ break;
}
}
+ }
- minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+ minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
- ath_dbg(common, REGULATORY,
- "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
- ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
- scaledPower, minCtlPower);
-
- /* Apply ctl mode to correct target power set */
- switch (pCtlMode[ctlMode]) {
- case CTL_11B:
- for (i = ALL_TARGET_LEGACY_1L_5L;
- i <= ALL_TARGET_LEGACY_11S; i++)
- pPwrArray[i] =
- (u8)min((u16)pPwrArray[i],
- minCtlPower);
- break;
- case CTL_11A:
- case CTL_11G:
- for (i = ALL_TARGET_LEGACY_6_24;
- i <= ALL_TARGET_LEGACY_54; i++)
- pPwrArray[i] =
- (u8)min((u16)pPwrArray[i],
- minCtlPower);
- break;
- case CTL_5GHT20:
- case CTL_2GHT20:
- for (i = ALL_TARGET_HT20_0_8_16;
- i <= ALL_TARGET_HT20_21; i++)
- pPwrArray[i] =
- (u8)min((u16)pPwrArray[i],
- minCtlPower);
- pPwrArray[ALL_TARGET_HT20_22] =
- (u8)min((u16)pPwrArray[ALL_TARGET_HT20_22],
- minCtlPower);
- pPwrArray[ALL_TARGET_HT20_23] =
- (u8)min((u16)pPwrArray[ALL_TARGET_HT20_23],
- minCtlPower);
- break;
- case CTL_5GHT40:
- case CTL_2GHT40:
- for (i = ALL_TARGET_HT40_0_8_16;
- i <= ALL_TARGET_HT40_23; i++)
- pPwrArray[i] =
- (u8)min((u16)pPwrArray[i],
- minCtlPower);
- break;
- default:
- break;
- }
+ ath_dbg(common, REGULATORY,
+ "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
+ ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+ scaledPower, minCtlPower);
+
+ /* Apply ctl mode to correct target power set */
+ switch (pCtlMode[ctlMode]) {
+ case CTL_11B:
+ for (i = ALL_TARGET_LEGACY_1L_5L;
+ i <= ALL_TARGET_LEGACY_11S; i++)
+ pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+ minCtlPower);
+ break;
+ case CTL_11A:
+ case CTL_11G:
+ for (i = ALL_TARGET_LEGACY_6_24;
+ i <= ALL_TARGET_LEGACY_54; i++)
+ pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+ minCtlPower);
+ break;
+ case CTL_5GHT20:
+ case CTL_2GHT20:
+ for (i = ALL_TARGET_HT20_0_8_16;
+ i <= ALL_TARGET_HT20_23; i++)
+ pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+ minCtlPower);
+ break;
+ case CTL_5GHT40:
+ case CTL_2GHT40:
+ for (i = ALL_TARGET_HT40_0_8_16;
+ i <= ALL_TARGET_HT40_23; i++)
+ pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+ minCtlPower);
+ break;
+ default:
+ break;
+ }
} /* end ctl mode checking */
}
ar9003_mci_2g5g_switch(ah, false);
break;
- case MCI_STATE_SET_BT_CAL_START:
- mci->bt_state = MCI_BT_CAL_START;
- break;
- case MCI_STATE_SET_BT_CAL:
- mci->bt_state = MCI_BT_CAL;
- break;
case MCI_STATE_RESET_REQ_WAKE:
ar9003_mci_reset_req_wakeup(ah);
mci->update_2g5g = true;
enum mci_state_type {
MCI_STATE_ENABLE,
MCI_STATE_SET_BT_AWAKE,
- MCI_STATE_SET_BT_CAL_START,
- MCI_STATE_SET_BT_CAL,
MCI_STATE_LAST_SCHD_MSG_OFFSET,
MCI_STATE_REMOTE_SLEEP,
MCI_STATE_RESET_REQ_WAKE,
struct ath_txq *txq;
struct ath_node *an;
u8 paprd;
+ struct ieee80211_sta *sta;
};
#define ATH_TX_ERROR 0x01
static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
{
int transfer, err;
- const void *data = hif_dev->firmware->data;
- size_t len = hif_dev->firmware->size;
+ const void *data = hif_dev->fw_data;
+ size_t len = hif_dev->fw_size;
u32 addr = AR9271_FIRMWARE;
u8 *buf = kzalloc(4096, GFP_KERNEL);
u32 firm_offset;
return -EIO;
dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n",
- hif_dev->fw_name, (unsigned long) hif_dev->firmware->size);
+ hif_dev->fw_name, (unsigned long) hif_dev->fw_size);
return 0;
}
hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
&hif_dev->udev->dev);
- if (hif_dev->htc_handle == NULL) {
- goto err_fw;
- }
+ if (hif_dev->htc_handle == NULL)
+ goto err_dev_alloc;
- hif_dev->firmware = fw;
+ hif_dev->fw_data = fw->data;
+ hif_dev->fw_size = fw->size;
/* Proceed with initialization */
goto err_htc_hw_init;
}
+ release_firmware(fw);
+ hif_dev->flags |= HIF_USB_READY;
complete(&hif_dev->fw_done);
return;
ath9k_hif_usb_dev_deinit(hif_dev);
err_dev_init:
ath9k_htc_hw_free(hif_dev->htc_handle);
+err_dev_alloc:
release_firmware(fw);
- hif_dev->firmware = NULL;
err_fw:
ath9k_hif_usb_firmware_fail(hif_dev);
}
wait_for_completion(&hif_dev->fw_done);
- if (hif_dev->firmware) {
+ if (hif_dev->flags & HIF_USB_READY) {
ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
ath9k_htc_hw_free(hif_dev->htc_handle);
ath9k_hif_usb_dev_deinit(hif_dev);
- release_firmware(hif_dev->firmware);
}
usb_set_intfdata(interface, NULL);
struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
struct htc_target *htc_handle = hif_dev->htc_handle;
int ret;
+ const struct firmware *fw;
ret = ath9k_hif_usb_alloc_urbs(hif_dev);
if (ret)
return ret;
- if (hif_dev->firmware) {
+ if (hif_dev->flags & HIF_USB_READY) {
+ /* request cached firmware during suspend/resume cycle */
+ ret = request_firmware(&fw, hif_dev->fw_name,
+ &hif_dev->udev->dev);
+ if (ret)
+ goto fail_resume;
+
+ hif_dev->fw_data = fw->data;
+ hif_dev->fw_size = fw->size;
ret = ath9k_hif_usb_download_fw(hif_dev);
+ release_firmware(fw);
if (ret)
goto fail_resume;
} else {
};
#define HIF_USB_START BIT(0)
+#define HIF_USB_READY BIT(1)
struct hif_device_usb {
struct usb_device *udev;
struct usb_interface *interface;
const struct usb_device_id *usb_device_id;
- const struct firmware *firmware;
+ const void *fw_data;
+ size_t fw_size;
struct completion fw_done;
struct htc_target *htc_handle;
struct hif_usb_tx tx;
int ath9k_tx_init(struct ath9k_htc_priv *priv);
int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, u8 slot, bool is_cab);
void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
goto next;
}
- ret = ath9k_htc_tx_start(priv, skb, tx_slot, true);
+ ret = ath9k_htc_tx_start(priv, NULL, skb, tx_slot, true);
if (ret != 0) {
ath9k_htc_tx_clear_slot(priv, tx_slot);
dev_kfree_skb_any(skb);
/* mac80211 Callbacks */
/**********************/
-static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void ath9k_htc_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
struct ath9k_htc_priv *priv = hw->priv;
goto fail_tx;
}
- ret = ath9k_htc_tx_start(priv, skb, slot, false);
+ ret = ath9k_htc_tx_start(priv, control->sta, skb, slot, false);
if (ret != 0) {
ath_dbg(common, XMIT, "Tx failed\n");
goto clear_slot;
return ret;
}
+static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u32 changed)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_rate trate;
+
+ mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
+
+ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+ memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
+ ath9k_htc_setup_rate(priv, sta, &trate);
+ if (!ath9k_htc_send_rate_cmd(priv, &trate))
+ ath_dbg(common, CONFIG,
+ "Supported rates for sta: %pM updated, rate caps: 0x%X\n",
+ sta->addr, be32_to_cpu(trate.capflags));
+ else
+ ath_dbg(common, CONFIG,
+ "Unable to update supported rates for sta: %pM\n",
+ sta->addr);
+ }
+
+ ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
+}
+
static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
.sta_add = ath9k_htc_sta_add,
.sta_remove = ath9k_htc_sta_remove,
.conf_tx = ath9k_htc_conf_tx,
+ .sta_rc_update = ath9k_htc_sta_rc_update,
.bss_info_changed = ath9k_htc_bss_info_changed,
.set_key = ath9k_htc_set_key,
.get_tsf = ath9k_htc_get_tsf,
}
int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+ struct ieee80211_sta *sta,
struct sk_buff *skb,
u8 slot, bool is_cab)
{
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = tx_info->control.sta;
struct ieee80211_vif *vif = tx_info->control.vif;
struct ath9k_htc_sta *ista;
struct ath9k_htc_vif *avp = NULL;
return r;
}
-static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void ath9k_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
memset(&txctl, 0, sizeof(struct ath_tx_control));
txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
+ txctl.sta = control->sta;
ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb);
switch (opcode) {
case MCI_GPM_BT_CAL_REQ:
if (mci_hw->bt_state == MCI_BT_AWAKE) {
- ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START);
+ mci_hw->bt_state = MCI_BT_CAL_START;
ath9k_queue_reset(sc, RESET_TYPE_MCI);
}
ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
8, /* MCS start */
{
[0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000,
- 5400, 0, 12, 0, 0, 0, 0 }, /* 6 Mb */
+ 5400, 0, 12 }, /* 6 Mb */
[1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000,
- 7800, 1, 18, 0, 1, 1, 1 }, /* 9 Mb */
+ 7800, 1, 18 }, /* 9 Mb */
[2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
- 10000, 2, 24, 2, 2, 2, 2 }, /* 12 Mb */
+ 10000, 2, 24 }, /* 12 Mb */
[3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
- 13900, 3, 36, 2, 3, 3, 3 }, /* 18 Mb */
+ 13900, 3, 36 }, /* 18 Mb */
[4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
- 17300, 4, 48, 4, 4, 4, 4 }, /* 24 Mb */
+ 17300, 4, 48 }, /* 24 Mb */
[5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
- 23000, 5, 72, 4, 5, 5, 5 }, /* 36 Mb */
+ 23000, 5, 72 }, /* 36 Mb */
[6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
- 27400, 6, 96, 4, 6, 6, 6 }, /* 48 Mb */
+ 27400, 6, 96 }, /* 48 Mb */
[7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
- 29300, 7, 108, 4, 7, 7, 7 }, /* 54 Mb */
+ 29300, 7, 108 }, /* 54 Mb */
[8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500,
- 6400, 0, 0, 0, 38, 8, 38 }, /* 6.5 Mb */
+ 6400, 0, 0 }, /* 6.5 Mb */
[9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
- 12700, 1, 1, 2, 39, 9, 39 }, /* 13 Mb */
+ 12700, 1, 1 }, /* 13 Mb */
[10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
- 18800, 2, 2, 2, 40, 10, 40 }, /* 19.5 Mb */
+ 18800, 2, 2 }, /* 19.5 Mb */
[11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
- 25000, 3, 3, 4, 41, 11, 41 }, /* 26 Mb */
+ 25000, 3, 3 }, /* 26 Mb */
[12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
- 36700, 4, 4, 4, 42, 12, 42 }, /* 39 Mb */
+ 36700, 4, 4 }, /* 39 Mb */
[13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
- 48100, 5, 5, 4, 43, 13, 43 }, /* 52 Mb */
+ 48100, 5, 5 }, /* 52 Mb */
[14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
- 53500, 6, 6, 4, 44, 14, 44 }, /* 58.5 Mb */
+ 53500, 6, 6 }, /* 58.5 Mb */
[15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
- 59000, 7, 7, 4, 45, 16, 46 }, /* 65 Mb */
+ 59000, 7, 7 }, /* 65 Mb */
[16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
- 65400, 7, 7, 4, 45, 16, 46 }, /* 75 Mb */
+ 65400, 7, 7 }, /* 75 Mb */
[17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
- 12700, 8, 8, 0, 47, 17, 47 }, /* 13 Mb */
+ 12700, 8, 8 }, /* 13 Mb */
[18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
- 24800, 9, 9, 2, 48, 18, 48 }, /* 26 Mb */
+ 24800, 9, 9 }, /* 26 Mb */
[19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
- 36600, 10, 10, 2, 49, 19, 49 }, /* 39 Mb */
+ 36600, 10, 10 }, /* 39 Mb */
[20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
- 48100, 11, 11, 4, 50, 20, 50 }, /* 52 Mb */
+ 48100, 11, 11 }, /* 52 Mb */
[21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
- 69500, 12, 12, 4, 51, 21, 51 }, /* 78 Mb */
+ 69500, 12, 12 }, /* 78 Mb */
[22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
- 89500, 13, 13, 4, 52, 22, 52 }, /* 104 Mb */
+ 89500, 13, 13 }, /* 104 Mb */
[23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
- 98900, 14, 14, 4, 53, 23, 53 }, /* 117 Mb */
+ 98900, 14, 14 }, /* 117 Mb */
[24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
- 108300, 15, 15, 4, 54, 25, 55 }, /* 130 Mb */
+ 108300, 15, 15 }, /* 130 Mb */
[25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
- 120000, 15, 15, 4, 54, 25, 55 }, /* 144.4 Mb */
+ 120000, 15, 15 }, /* 144.4 Mb */
[26] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
- 17400, 16, 16, 0, 56, 26, 56 }, /* 19.5 Mb */
+ 17400, 16, 16 }, /* 19.5 Mb */
[27] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
- 35100, 17, 17, 2, 57, 27, 57 }, /* 39 Mb */
+ 35100, 17, 17 }, /* 39 Mb */
[28] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
- 52600, 18, 18, 2, 58, 28, 58 }, /* 58.5 Mb */
+ 52600, 18, 18 }, /* 58.5 Mb */
[29] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
- 70400, 19, 19, 4, 59, 29, 59 }, /* 78 Mb */
+ 70400, 19, 19 }, /* 78 Mb */
[30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
- 104900, 20, 20, 4, 60, 31, 61 }, /* 117 Mb */
+ 104900, 20, 20 }, /* 117 Mb */
[31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
- 115800, 20, 20, 4, 60, 31, 61 }, /* 130 Mb*/
+ 115800, 20, 20 }, /* 130 Mb*/
[32] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
- 137200, 21, 21, 4, 62, 33, 63 }, /* 156 Mb */
+ 137200, 21, 21 }, /* 156 Mb */
[33] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
- 151100, 21, 21, 4, 62, 33, 63 }, /* 173.3 Mb */
+ 151100, 21, 21 }, /* 173.3 Mb */
[34] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
- 152800, 22, 22, 4, 64, 35, 65 }, /* 175.5 Mb */
+ 152800, 22, 22 }, /* 175.5 Mb */
[35] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
- 168400, 22, 22, 4, 64, 35, 65 }, /* 195 Mb*/
+ 168400, 22, 22 }, /* 195 Mb*/
[36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
- 168400, 23, 23, 4, 66, 37, 67 }, /* 195 Mb */
+ 168400, 23, 23 }, /* 195 Mb */
[37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
- 185000, 23, 23, 4, 66, 37, 67 }, /* 216.7 Mb */
+ 185000, 23, 23 }, /* 216.7 Mb */
[38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
- 13200, 0, 0, 0, 38, 38, 38 }, /* 13.5 Mb*/
+ 13200, 0, 0 }, /* 13.5 Mb*/
[39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
- 25900, 1, 1, 2, 39, 39, 39 }, /* 27.0 Mb*/
+ 25900, 1, 1 }, /* 27.0 Mb*/
[40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
- 38600, 2, 2, 2, 40, 40, 40 }, /* 40.5 Mb*/
+ 38600, 2, 2 }, /* 40.5 Mb*/
[41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
- 49800, 3, 3, 4, 41, 41, 41 }, /* 54 Mb */
+ 49800, 3, 3 }, /* 54 Mb */
[42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
- 72200, 4, 4, 4, 42, 42, 42 }, /* 81 Mb */
+ 72200, 4, 4 }, /* 81 Mb */
[43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000,
- 92900, 5, 5, 4, 43, 43, 43 }, /* 108 Mb */
+ 92900, 5, 5 }, /* 108 Mb */
[44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
- 102700, 6, 6, 4, 44, 44, 44 }, /* 121.5 Mb*/
+ 102700, 6, 6 }, /* 121.5 Mb*/
[45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
- 112000, 7, 7, 4, 45, 46, 46 }, /* 135 Mb */
+ 112000, 7, 7 }, /* 135 Mb */
[46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
- 122000, 7, 7, 4, 45, 46, 46 }, /* 150 Mb */
+ 122000, 7, 7 }, /* 150 Mb */
[47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
- 25800, 8, 8, 0, 47, 47, 47 }, /* 27 Mb */
+ 25800, 8, 8 }, /* 27 Mb */
[48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
- 49800, 9, 9, 2, 48, 48, 48 }, /* 54 Mb */
+ 49800, 9, 9 }, /* 54 Mb */
[49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
- 71900, 10, 10, 2, 49, 49, 49 }, /* 81 Mb */
+ 71900, 10, 10 }, /* 81 Mb */
[50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
- 92500, 11, 11, 4, 50, 50, 50 }, /* 108 Mb */
+ 92500, 11, 11 }, /* 108 Mb */
[51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
- 130300, 12, 12, 4, 51, 51, 51 }, /* 162 Mb */
+ 130300, 12, 12 }, /* 162 Mb */
[52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
- 162800, 13, 13, 4, 52, 52, 52 }, /* 216 Mb */
+ 162800, 13, 13 }, /* 216 Mb */
[53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
- 178200, 14, 14, 4, 53, 53, 53 }, /* 243 Mb */
+ 178200, 14, 14 }, /* 243 Mb */
[54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
- 192100, 15, 15, 4, 54, 55, 55 }, /* 270 Mb */
+ 192100, 15, 15 }, /* 270 Mb */
[55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
- 207000, 15, 15, 4, 54, 55, 55 }, /* 300 Mb */
+ 207000, 15, 15 }, /* 300 Mb */
[56] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
- 36100, 16, 16, 0, 56, 56, 56 }, /* 40.5 Mb */
+ 36100, 16, 16 }, /* 40.5 Mb */
[57] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
- 72900, 17, 17, 2, 57, 57, 57 }, /* 81 Mb */
+ 72900, 17, 17 }, /* 81 Mb */
[58] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
- 108300, 18, 18, 2, 58, 58, 58 }, /* 121.5 Mb */
+ 108300, 18, 18 }, /* 121.5 Mb */
[59] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
- 142000, 19, 19, 4, 59, 59, 59 }, /* 162 Mb */
+ 142000, 19, 19 }, /* 162 Mb */
[60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
- 205100, 20, 20, 4, 60, 61, 61 }, /* 243 Mb */
+ 205100, 20, 20 }, /* 243 Mb */
[61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
- 224700, 20, 20, 4, 60, 61, 61 }, /* 270 Mb */
+ 224700, 20, 20 }, /* 270 Mb */
[62] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
- 263100, 21, 21, 4, 62, 63, 63 }, /* 324 Mb */
+ 263100, 21, 21 }, /* 324 Mb */
[63] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
- 288000, 21, 21, 4, 62, 63, 63 }, /* 360 Mb */
+ 288000, 21, 21 }, /* 360 Mb */
[64] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
- 290700, 22, 22, 4, 64, 65, 65 }, /* 364.5 Mb */
+ 290700, 22, 22 }, /* 364.5 Mb */
[65] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
- 317200, 22, 22, 4, 64, 65, 65 }, /* 405 Mb */
+ 317200, 22, 22 }, /* 405 Mb */
[66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
- 317200, 23, 23, 4, 66, 67, 67 }, /* 405 Mb */
+ 317200, 23, 23 }, /* 405 Mb */
[67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
- 346400, 23, 23, 4, 66, 67, 67 }, /* 450 Mb */
+ 346400, 23, 23 }, /* 450 Mb */
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
12, /* MCS start */
{
[0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000,
- 900, 0, 2, 0, 0, 0, 0 }, /* 1 Mb */
+ 900, 0, 2 }, /* 1 Mb */
[1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000,
- 1900, 1, 4, 1, 1, 1, 1 }, /* 2 Mb */
+ 1900, 1, 4 }, /* 2 Mb */
[2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500,
- 4900, 2, 11, 2, 2, 2, 2 }, /* 5.5 Mb */
+ 4900, 2, 11 }, /* 5.5 Mb */
[3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000,
- 8100, 3, 22, 3, 3, 3, 3 }, /* 11 Mb */
+ 8100, 3, 22 }, /* 11 Mb */
[4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000,
- 5400, 4, 12, 4, 4, 4, 4 }, /* 6 Mb */
+ 5400, 4, 12 }, /* 6 Mb */
[5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000,
- 7800, 5, 18, 4, 5, 5, 5 }, /* 9 Mb */
+ 7800, 5, 18 }, /* 9 Mb */
[6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
- 10100, 6, 24, 6, 6, 6, 6 }, /* 12 Mb */
+ 10100, 6, 24 }, /* 12 Mb */
[7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
- 14100, 7, 36, 6, 7, 7, 7 }, /* 18 Mb */
+ 14100, 7, 36 }, /* 18 Mb */
[8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
- 17700, 8, 48, 8, 8, 8, 8 }, /* 24 Mb */
+ 17700, 8, 48 }, /* 24 Mb */
[9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
- 23700, 9, 72, 8, 9, 9, 9 }, /* 36 Mb */
+ 23700, 9, 72 }, /* 36 Mb */
[10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
- 27400, 10, 96, 8, 10, 10, 10 }, /* 48 Mb */
+ 27400, 10, 96 }, /* 48 Mb */
[11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
- 30900, 11, 108, 8, 11, 11, 11 }, /* 54 Mb */
+ 30900, 11, 108 }, /* 54 Mb */
[12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500,
- 6400, 0, 0, 4, 42, 12, 42 }, /* 6.5 Mb */
+ 6400, 0, 0 }, /* 6.5 Mb */
[13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
- 12700, 1, 1, 6, 43, 13, 43 }, /* 13 Mb */
+ 12700, 1, 1 }, /* 13 Mb */
[14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
- 18800, 2, 2, 6, 44, 14, 44 }, /* 19.5 Mb*/
+ 18800, 2, 2 }, /* 19.5 Mb*/
[15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
- 25000, 3, 3, 8, 45, 15, 45 }, /* 26 Mb */
+ 25000, 3, 3 }, /* 26 Mb */
[16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
- 36700, 4, 4, 8, 46, 16, 46 }, /* 39 Mb */
+ 36700, 4, 4 }, /* 39 Mb */
[17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
- 48100, 5, 5, 8, 47, 17, 47 }, /* 52 Mb */
+ 48100, 5, 5 }, /* 52 Mb */
[18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
- 53500, 6, 6, 8, 48, 18, 48 }, /* 58.5 Mb */
+ 53500, 6, 6 }, /* 58.5 Mb */
[19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
- 59000, 7, 7, 8, 49, 20, 50 }, /* 65 Mb */
+ 59000, 7, 7 }, /* 65 Mb */
[20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
- 65400, 7, 7, 8, 49, 20, 50 }, /* 65 Mb*/
+ 65400, 7, 7 }, /* 65 Mb*/
[21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
- 12700, 8, 8, 4, 51, 21, 51 }, /* 13 Mb */
+ 12700, 8, 8 }, /* 13 Mb */
[22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
- 24800, 9, 9, 6, 52, 22, 52 }, /* 26 Mb */
+ 24800, 9, 9 }, /* 26 Mb */
[23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
- 36600, 10, 10, 6, 53, 23, 53 }, /* 39 Mb */
+ 36600, 10, 10 }, /* 39 Mb */
[24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
- 48100, 11, 11, 8, 54, 24, 54 }, /* 52 Mb */
+ 48100, 11, 11 }, /* 52 Mb */
[25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
- 69500, 12, 12, 8, 55, 25, 55 }, /* 78 Mb */
+ 69500, 12, 12 }, /* 78 Mb */
[26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
- 89500, 13, 13, 8, 56, 26, 56 }, /* 104 Mb */
+ 89500, 13, 13 }, /* 104 Mb */
[27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
- 98900, 14, 14, 8, 57, 27, 57 }, /* 117 Mb */
+ 98900, 14, 14 }, /* 117 Mb */
[28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
- 108300, 15, 15, 8, 58, 29, 59 }, /* 130 Mb */
+ 108300, 15, 15 }, /* 130 Mb */
[29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
- 120000, 15, 15, 8, 58, 29, 59 }, /* 144.4 Mb */
+ 120000, 15, 15 }, /* 144.4 Mb */
[30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
- 17400, 16, 16, 4, 60, 30, 60 }, /* 19.5 Mb */
+ 17400, 16, 16 }, /* 19.5 Mb */
[31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
- 35100, 17, 17, 6, 61, 31, 61 }, /* 39 Mb */
+ 35100, 17, 17 }, /* 39 Mb */
[32] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
- 52600, 18, 18, 6, 62, 32, 62 }, /* 58.5 Mb */
+ 52600, 18, 18 }, /* 58.5 Mb */
[33] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
- 70400, 19, 19, 8, 63, 33, 63 }, /* 78 Mb */
+ 70400, 19, 19 }, /* 78 Mb */
[34] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
- 104900, 20, 20, 8, 64, 35, 65 }, /* 117 Mb */
+ 104900, 20, 20 }, /* 117 Mb */
[35] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
- 115800, 20, 20, 8, 64, 35, 65 }, /* 130 Mb */
+ 115800, 20, 20 }, /* 130 Mb */
[36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
- 137200, 21, 21, 8, 66, 37, 67 }, /* 156 Mb */
+ 137200, 21, 21 }, /* 156 Mb */
[37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
- 151100, 21, 21, 8, 66, 37, 67 }, /* 173.3 Mb */
+ 151100, 21, 21 }, /* 173.3 Mb */
[38] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
- 152800, 22, 22, 8, 68, 39, 69 }, /* 175.5 Mb */
+ 152800, 22, 22 }, /* 175.5 Mb */
[39] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
- 168400, 22, 22, 8, 68, 39, 69 }, /* 195 Mb */
+ 168400, 22, 22 }, /* 195 Mb */
[40] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
- 168400, 23, 23, 8, 70, 41, 71 }, /* 195 Mb */
+ 168400, 23, 23 }, /* 195 Mb */
[41] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
- 185000, 23, 23, 8, 70, 41, 71 }, /* 216.7 Mb */
+ 185000, 23, 23 }, /* 216.7 Mb */
[42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
- 13200, 0, 0, 8, 42, 42, 42 }, /* 13.5 Mb */
+ 13200, 0, 0 }, /* 13.5 Mb */
[43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
- 25900, 1, 1, 8, 43, 43, 43 }, /* 27.0 Mb */
+ 25900, 1, 1 }, /* 27.0 Mb */
[44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
- 38600, 2, 2, 8, 44, 44, 44 }, /* 40.5 Mb */
+ 38600, 2, 2 }, /* 40.5 Mb */
[45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
- 49800, 3, 3, 8, 45, 45, 45 }, /* 54 Mb */
+ 49800, 3, 3 }, /* 54 Mb */
[46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
- 72200, 4, 4, 8, 46, 46, 46 }, /* 81 Mb */
+ 72200, 4, 4 }, /* 81 Mb */
[47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000,
- 92900, 5, 5, 8, 47, 47, 47 }, /* 108 Mb */
+ 92900, 5, 5 }, /* 108 Mb */
[48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
- 102700, 6, 6, 8, 48, 48, 48 }, /* 121.5 Mb */
+ 102700, 6, 6 }, /* 121.5 Mb */
[49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
- 112000, 7, 7, 8, 49, 50, 50 }, /* 135 Mb */
+ 112000, 7, 7 }, /* 135 Mb */
[50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
- 122000, 7, 7, 8, 49, 50, 50 }, /* 150 Mb */
+ 122000, 7, 7 }, /* 150 Mb */
[51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
- 25800, 8, 8, 8, 51, 51, 51 }, /* 27 Mb */
+ 25800, 8, 8 }, /* 27 Mb */
[52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
- 49800, 9, 9, 8, 52, 52, 52 }, /* 54 Mb */
+ 49800, 9, 9 }, /* 54 Mb */
[53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
- 71900, 10, 10, 8, 53, 53, 53 }, /* 81 Mb */
+ 71900, 10, 10 }, /* 81 Mb */
[54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
- 92500, 11, 11, 8, 54, 54, 54 }, /* 108 Mb */
+ 92500, 11, 11 }, /* 108 Mb */
[55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
- 130300, 12, 12, 8, 55, 55, 55 }, /* 162 Mb */
+ 130300, 12, 12 }, /* 162 Mb */
[56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
- 162800, 13, 13, 8, 56, 56, 56 }, /* 216 Mb */
+ 162800, 13, 13 }, /* 216 Mb */
[57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
- 178200, 14, 14, 8, 57, 57, 57 }, /* 243 Mb */
+ 178200, 14, 14 }, /* 243 Mb */
[58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
- 192100, 15, 15, 8, 58, 59, 59 }, /* 270 Mb */
+ 192100, 15, 15 }, /* 270 Mb */
[59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
- 207000, 15, 15, 8, 58, 59, 59 }, /* 300 Mb */
+ 207000, 15, 15 }, /* 300 Mb */
[60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
- 36100, 16, 16, 8, 60, 60, 60 }, /* 40.5 Mb */
+ 36100, 16, 16 }, /* 40.5 Mb */
[61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
- 72900, 17, 17, 8, 61, 61, 61 }, /* 81 Mb */
+ 72900, 17, 17 }, /* 81 Mb */
[62] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
- 108300, 18, 18, 8, 62, 62, 62 }, /* 121.5 Mb */
+ 108300, 18, 18 }, /* 121.5 Mb */
[63] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
- 142000, 19, 19, 8, 63, 63, 63 }, /* 162 Mb */
+ 142000, 19, 19 }, /* 162 Mb */
[64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
- 205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */
+ 205100, 20, 20 }, /* 243 Mb */
[65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
- 224700, 20, 20, 8, 64, 65, 65 }, /* 270 Mb */
+ 224700, 20, 20 }, /* 270 Mb */
[66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
- 263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */
+ 263100, 21, 21 }, /* 324 Mb */
[67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
- 288000, 21, 21, 8, 66, 67, 67 }, /* 360 Mb */
+ 288000, 21, 21 }, /* 360 Mb */
[68] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
- 290700, 22, 22, 8, 68, 69, 69 }, /* 364.5 Mb */
+ 290700, 22, 22 }, /* 364.5 Mb */
[69] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
- 317200, 22, 22, 8, 68, 69, 69 }, /* 405 Mb */
+ 317200, 22, 22 }, /* 405 Mb */
[70] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
- 317200, 23, 23, 8, 70, 71, 71 }, /* 405 Mb */
+ 317200, 23, 23 }, /* 405 Mb */
[71] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
- 346400, 23, 23, 8, 70, 71, 71 }, /* 450 Mb */
+ 346400, 23, 23 }, /* 450 Mb */
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
0,
{
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 0, 12, 0},
+ 5400, 0, 12},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 1, 18, 0},
+ 7800, 1, 18},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10000, 2, 24, 2},
+ 10000, 2, 24},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 13900, 3, 36, 2},
+ 13900, 3, 36},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17300, 4, 48, 4},
+ 17300, 4, 48},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23000, 5, 72, 4},
+ 23000, 5, 72},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 6, 96, 4},
+ 27400, 6, 96},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 29300, 7, 108, 4},
+ 29300, 7, 108},
},
50, /* probe interval */
0, /* Phy rates allowed initially */
0,
{
{ RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0, 2, 0},
+ 900, 0, 2},
{ RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1900, 1, 4, 1},
+ 1900, 1, 4},
{ RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4900, 2, 11, 2},
+ 4900, 2, 11},
{ RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 8100, 3, 22, 3},
+ 8100, 3, 22},
{ RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 4, 12, 4},
+ 5400, 4, 12},
{ RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 5, 18, 4},
+ 7800, 5, 18},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10000, 6, 24, 6},
+ 10000, 6, 24},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 13900, 7, 36, 6},
+ 13900, 7, 36},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17300, 8, 48, 8},
+ 17300, 8, 48},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23000, 9, 72, 8},
+ 23000, 9, 72},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 10, 96, 8},
+ 27400, 10, 96},
{ RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 29300, 11, 108, 8},
+ 29300, 11, 108},
},
50, /* probe interval */
0, /* Phy rates allowed initially */
};
-static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
+static int ath_rc_get_rateindex(struct ath_rate_priv *ath_rc_priv,
struct ieee80211_tx_rate *rate)
{
- int rix = 0, i = 0;
- static const int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
+ const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
+ int rix, i, idx = 0;
if (!(rate->flags & IEEE80211_TX_RC_MCS))
return rate->idx;
- while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
- rix++; i++;
+ for (i = 0; i < ath_rc_priv->max_valid_rate; i++) {
+ idx = ath_rc_priv->valid_rate_index[i];
+
+ if (WLAN_RC_PHY_HT(rate_table->info[idx].phy) &&
+ rate_table->info[idx].ratecode == rate->idx)
+ break;
}
- rix += rate->idx + rate_table->mcs_start;
+ rix = idx;
- if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
- (rate->flags & IEEE80211_TX_RC_SHORT_GI))
- rix = rate_table->info[rix].ht_index;
- else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
- rix = rate_table->info[rix].sgi_index;
- else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- rix = rate_table->info[rix].cw40index;
+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ rix++;
return rix;
}
-static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv)
+static void ath_rc_sort_validrates(struct ath_rate_priv *ath_rc_priv)
{
+ const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
u8 i, j, idx, idx_next;
for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) {
}
}
-static void ath_rc_init_valid_rate_idx(struct ath_rate_priv *ath_rc_priv)
-{
- u8 i;
-
- for (i = 0; i < ath_rc_priv->rate_table_size; i++)
- ath_rc_priv->valid_rate_index[i] = 0;
-}
-
-static inline void ath_rc_set_valid_rate_idx(struct ath_rate_priv *ath_rc_priv,
- u8 index, int valid_tx_rate)
-{
- BUG_ON(index > ath_rc_priv->rate_table_size);
- ath_rc_priv->valid_rate_index[index] = !!valid_tx_rate;
-}
-
static inline
int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
struct ath_rate_priv *ath_rc_priv,
}
static inline int
-ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv,
+ath_rc_get_lower_rix(struct ath_rate_priv *ath_rc_priv,
u8 cur_valid_txrate, u8 *next_idx)
{
int8_t i;
return 0;
}
-static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u32 capflag)
+static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv)
{
+ const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
u8 i, hi = 0;
for (i = 0; i < rate_table->rate_cnt; i++) {
u32 phy = rate_table->info[i].phy;
u8 valid_rate_count = 0;
- if (!ath_rc_valid_phyrate(phy, capflag, 0))
+ if (!ath_rc_valid_phyrate(phy, ath_rc_priv->ht_cap, 0))
continue;
valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_rate_idx(ath_rc_priv, i, 1);
+ ath_rc_priv->valid_rate_index[i] = true;
hi = i;
}
}
return hi;
}
-static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- struct ath_rateset *rateset,
- u32 capflag)
+static inline bool ath_rc_check_legacy(u8 rate, u8 dot11rate, u16 rate_flags,
+ u32 phy, u32 capflag)
{
- u8 i, j, hi = 0;
+ if (rate != dot11rate || WLAN_RC_PHY_HT(phy))
+ return false;
- /* Use intersection of working rates and valid rates */
- for (i = 0; i < rateset->rs_nrates; i++) {
- for (j = 0; j < rate_table->rate_cnt; j++) {
- u32 phy = rate_table->info[j].phy;
- u16 rate_flags = rate_table->info[j].rate_flags;
- u8 rate = rateset->rs_rates[i];
- u8 dot11rate = rate_table->info[j].dot11rate;
-
- /* We allow a rate only if its valid and the
- * capflag matches one of the validity
- * (VALID/VALID_20/VALID_40) flags */
-
- if ((rate == dot11rate) &&
- (rate_flags & WLAN_RC_CAP_MODE(capflag)) ==
- WLAN_RC_CAP_MODE(capflag) &&
- (rate_flags & WLAN_RC_CAP_STREAM(capflag)) &&
- !WLAN_RC_PHY_HT(phy)) {
- u8 valid_rate_count = 0;
-
- if (!ath_rc_valid_phyrate(phy, capflag, 0))
- continue;
-
- valid_rate_count =
- ath_rc_priv->valid_phy_ratecnt[phy];
-
- ath_rc_priv->valid_phy_rateidx[phy]
- [valid_rate_count] = j;
- ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
- hi = max(hi, j);
- }
- }
- }
+ if ((rate_flags & WLAN_RC_CAP_MODE(capflag)) != WLAN_RC_CAP_MODE(capflag))
+ return false;
- return hi;
+ if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag)))
+ return false;
+
+ return true;
}
-static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- struct ath_rateset *rateset, u32 capflag)
+static inline bool ath_rc_check_ht(u8 rate, u8 dot11rate, u16 rate_flags,
+ u32 phy, u32 capflag)
{
- u8 i, j, hi = 0;
+ if (rate != dot11rate || !WLAN_RC_PHY_HT(phy))
+ return false;
+
+ if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag))
+ return false;
+
+ if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag)))
+ return false;
+
+ return true;
+}
+
+static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, bool legacy)
+{
+ const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
+ struct ath_rateset *rateset;
+ u32 phy, capflag = ath_rc_priv->ht_cap;
+ u16 rate_flags;
+ u8 i, j, hi = 0, rate, dot11rate, valid_rate_count;
+
+ if (legacy)
+ rateset = &ath_rc_priv->neg_rates;
+ else
+ rateset = &ath_rc_priv->neg_ht_rates;
- /* Use intersection of working rates and valid rates */
for (i = 0; i < rateset->rs_nrates; i++) {
for (j = 0; j < rate_table->rate_cnt; j++) {
- u32 phy = rate_table->info[j].phy;
- u16 rate_flags = rate_table->info[j].rate_flags;
- u8 rate = rateset->rs_rates[i];
- u8 dot11rate = rate_table->info[j].dot11rate;
-
- if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) ||
- !(rate_flags & WLAN_RC_CAP_STREAM(capflag)) ||
- !WLAN_RC_PHY_HT_VALID(rate_flags, capflag))
+ phy = rate_table->info[j].phy;
+ rate_flags = rate_table->info[j].rate_flags;
+ rate = rateset->rs_rates[i];
+ dot11rate = rate_table->info[j].dot11rate;
+
+ if (legacy &&
+ !ath_rc_check_legacy(rate, dot11rate,
+ rate_flags, phy, capflag))
+ continue;
+
+ if (!legacy &&
+ !ath_rc_check_ht(rate, dot11rate,
+ rate_flags, phy, capflag))
continue;
if (!ath_rc_valid_phyrate(phy, capflag, 0))
continue;
- ath_rc_priv->valid_phy_rateidx[phy]
- [ath_rc_priv->valid_phy_ratecnt[phy]] = j;
+ valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
+ ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = j;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
+ ath_rc_priv->valid_rate_index[j] = true;
hi = max(hi, j);
}
}
return hi;
}
-/* Finds the highest rate index we can use */
-static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- int *is_probing,
- bool legacy)
+static u8 ath_rc_get_highest_rix(struct ath_rate_priv *ath_rc_priv,
+ int *is_probing)
{
+ const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
u32 best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
int8_t index = 0;
u8 per_thres;
rate = ath_rc_priv->valid_rate_index[index];
- if (legacy && !(rate_table->info[rate].rate_flags & RC_LEGACY))
- continue;
if (rate > ath_rc_priv->rate_max_phy)
continue;
rate->count = tries;
rate->idx = rate_table->info[rix].ratecode;
- if (txrc->short_preamble)
- rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
if (txrc->rts || rtsctsenable)
rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
const struct ath_rate_table *rate_table,
struct ieee80211_tx_info *tx_info)
{
- struct ieee80211_tx_rate *rates = tx_info->control.rates;
- int i = 0, rix = 0, cix, enable_g_protection = 0;
+ struct ieee80211_bss_conf *bss_conf;
- /* get the cix for the lowest valid rix */
- for (i = 3; i >= 0; i--) {
- if (rates[i].count && (rates[i].idx >= 0)) {
- rix = ath_rc_get_rateindex(rate_table, &rates[i]);
- break;
- }
- }
- cix = rate_table->info[rix].ctrl_rate;
+ if (!tx_info->control.vif)
+ return;
+ /*
+ * For legacy frames, mac80211 takes care of CTS protection.
+ */
+ if (!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS))
+ return;
- /* All protection frames are transmited at 2Mb/s for 802.11g,
- * otherwise we transmit them at 1Mb/s */
- if (sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ &&
- !conf_is_ht(&sc->hw->conf))
- enable_g_protection = 1;
+ bss_conf = &tx_info->control.vif->bss_conf;
+
+ if (!bss_conf->basic_rates)
+ return;
/*
- * If 802.11g protection is enabled, determine whether to use RTS/CTS or
- * just CTS. Note that this is only done for OFDM/HT unicast frames.
+ * For now, use the lowest allowed basic rate for HT frames.
*/
- if ((tx_info->control.vif &&
- tx_info->control.vif->bss_conf.use_cts_prot) &&
- (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
- WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
- rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
- cix = rate_table->info[enable_g_protection].ctrl_rate;
- }
-
- tx_info->control.rts_cts_rate_idx = cix;
+ tx_info->control.rts_cts_rate_idx = __ffs(bss_conf->basic_rates);
}
static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
try_per_rate = 4;
rate_table = ath_rc_priv->rate_table;
- rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
- &is_probe, false);
+ rix = ath_rc_get_highest_rix(ath_rc_priv, &is_probe);
- /*
- * If we're in HT mode and both us and our peer supports LDPC.
- * We don't need to check our own device's capabilities as our own
- * ht capabilities would have already been intersected with our peer's.
- */
if (conf_is_ht(&sc->hw->conf) &&
(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
tx_info->flags |= IEEE80211_TX_CTL_LDPC;
tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT);
if (is_probe) {
- /* set one try for probe rates. For the
- * probes don't enable rts */
+ /*
+ * Set one try for probe rates. For the
+ * probes don't enable RTS.
+ */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
1, rix, 0);
-
- /* Get the next tried/allowed rate. No RTS for the next series
- * after the probe rate
+ /*
+ * Get the next tried/allowed rate.
+ * No RTS for the next series after the probe rate.
*/
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+ ath_rc_get_lower_rix(ath_rc_priv, rix, &rix);
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, rix, 0);
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
- /* Set the chosen rate. No RTS for first series entry. */
+ /*
+ * Set the chosen rate. No RTS for first series entry.
+ */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, rix, 0);
}
- /* Fill in the other rates for multirate retry */
- for ( ; i < 3; i++) {
+ for ( ; i < 4; i++) {
+ /*
+ * Use twice the number of tries for the last MRR segment.
+ */
+ if (i + 1 == 4)
+ try_per_rate = 8;
+
+ ath_rc_get_lower_rix(ath_rc_priv, rix, &rix);
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
- /* All other rates in the series have RTS enabled */
+ /*
+ * All other rates in the series have RTS enabled.
+ */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
try_per_rate, rix, 1);
}
- /* Use twice the number of tries for the last MRR segment. */
- try_per_rate = 8;
-
- /*
- * If the last rate in the rate series is MCS and has
- * more than 80% of per thresh, then use a legacy rate
- * as last retry to ensure that the frame is tried in both
- * MCS and legacy rate.
- */
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
- if (WLAN_RC_PHY_HT(rate_table->info[rix].phy) &&
- (ath_rc_priv->per[rix] > 45))
- rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
- &is_probe, true);
-
- /* All other rates in the series have RTS enabled */
- ath_rc_rate_set_series(rate_table, &rates[i], txrc,
- try_per_rate, rix, 1);
/*
* NB:Change rate series to enable aggregation when operating
* at lower MCS rates. When first rate in series is MCS2
rates[0].count = ATH_TXMAXTRY;
}
- /* Setup RTS/CTS */
ath_rc_rate_set_rtscts(sc, rate_table, tx_info);
}
stats->per = per;
}
-/* Update PER, RSSI and whatever else that the code thinks it is doing.
- If you can make sense of all this, you really need to go out more. */
-
static void ath_rc_update_ht(struct ath_softc *sc,
struct ath_rate_priv *ath_rc_priv,
struct ieee80211_tx_info *tx_info,
if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
- ath_rc_get_lower_rix(rate_table, ath_rc_priv,
- (u8)tx_rate, &ath_rc_priv->rate_max_phy);
+ ath_rc_get_lower_rix(ath_rc_priv, (u8)tx_rate,
+ &ath_rc_priv->rate_max_phy);
/* Don't probe for a little while. */
ath_rc_priv->probe_time = now_msec;
}
+static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
+{
+ struct ath_rc_stats *stats;
+
+ stats = &rc->rcstats[final_rate];
+ stats->success++;
+}
static void ath_rc_tx_status(struct ath_softc *sc,
struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_info *tx_info,
- int final_ts_idx, int xretries, int long_retry)
+ struct sk_buff *skb)
{
- const struct ath_rate_table *rate_table;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->status.rates;
+ struct ieee80211_tx_rate *rate;
+ int final_ts_idx = 0, xretries = 0, long_retry = 0;
u8 flags;
u32 i = 0, rix;
- rate_table = ath_rc_priv->rate_table;
+ for (i = 0; i < sc->hw->max_rates; i++) {
+ rate = &tx_info->status.rates[i];
+ if (rate->idx < 0 || !rate->count)
+ break;
+
+ final_ts_idx = i;
+ long_retry = rate->count - 1;
+ }
+
+ if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
+ xretries = 1;
/*
* If the first rate is not the final index, there
* are intermediate rate failures to be processed.
*/
if (final_ts_idx != 0) {
- /* Process intermediate rates that failed.*/
for (i = 0; i < final_ts_idx ; i++) {
if (rates[i].count != 0 && (rates[i].idx >= 0)) {
flags = rates[i].flags;
!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
return;
- rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+ rix = ath_rc_get_rateindex(ath_rc_priv, &rates[i]);
ath_rc_update_ht(sc, ath_rc_priv, tx_info,
- rix, xretries ? 1 : 2,
- rates[i].count);
+ rix, xretries ? 1 : 2,
+ rates[i].count);
}
}
- } else {
- /*
- * Handle the special case of MIMO PS burst, where the second
- * aggregate is sent out with only one rate and one try.
- * Treating it as an excessive retry penalizes the rate
- * inordinately.
- */
- if (rates[0].count == 1 && xretries == 1)
- xretries = 2;
}
- flags = rates[i].flags;
+ flags = rates[final_ts_idx].flags;
/* If HT40 and we have switched mode from 40 to 20 => don't update */
if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
return;
- rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+ rix = ath_rc_get_rateindex(ath_rc_priv, &rates[final_ts_idx]);
ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
+ ath_debug_stat_rc(ath_rc_priv, rix);
}
static const
enum ieee80211_band band,
bool is_ht)
{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
switch(band) {
case IEEE80211_BAND_2GHZ:
if (is_ht)
return &ar5416_11na_ratetable;
return &ar5416_11a_ratetable;
default:
- ath_dbg(common, CONFIG, "Invalid band\n");
return NULL;
}
}
static void ath_rc_init(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta,
- const struct ath_rate_table *rate_table)
+ struct ath_rate_priv *ath_rc_priv)
{
+ const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_rateset *ht_mcs = &ath_rc_priv->neg_ht_rates;
u8 i, j, k, hi = 0, hthi = 0;
- /* Initial rate table size. Will change depending
- * on the working rate set */
ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
- /* Initialize thresholds according to the global rate table */
for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
ath_rc_priv->per[i] = 0;
+ ath_rc_priv->valid_rate_index[i] = 0;
}
- /* Determine the valid rates */
- ath_rc_init_valid_rate_idx(ath_rc_priv);
-
for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < RATE_TABLE_SIZE; j++)
ath_rc_priv->valid_phy_rateidx[i][j] = 0;
}
if (!rateset->rs_nrates) {
- /* No working rate, just initialize valid rates */
- hi = ath_rc_init_validrates(ath_rc_priv, rate_table,
- ath_rc_priv->ht_cap);
+ hi = ath_rc_init_validrates(ath_rc_priv);
} else {
- /* Use intersection of working rates and valid rates */
- hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table,
- rateset, ath_rc_priv->ht_cap);
- if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) {
- hthi = ath_rc_setvalid_htrates(ath_rc_priv,
- rate_table,
- ht_mcs,
- ath_rc_priv->ht_cap);
- }
+ hi = ath_rc_setvalid_rates(ath_rc_priv, true);
+
+ if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG)
+ hthi = ath_rc_setvalid_rates(ath_rc_priv, false);
+
hi = max(hi, hthi);
}
ath_rc_priv->rate_table_size = hi + 1;
ath_rc_priv->rate_max_phy = 0;
- BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
+ WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
ath_rc_priv->valid_phy_rateidx[i][j];
}
- if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1)
- || !ath_rc_priv->valid_phy_ratecnt[i])
+ if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) ||
+ !ath_rc_priv->valid_phy_ratecnt[i])
continue;
ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
}
- BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
- BUG_ON(k > RATE_TABLE_SIZE);
+ WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
+ WARN_ON(k > RATE_TABLE_SIZE);
ath_rc_priv->max_valid_rate = k;
- ath_rc_sort_validrates(rate_table, ath_rc_priv);
+ ath_rc_sort_validrates(ath_rc_priv);
ath_rc_priv->rate_max_phy = (k > 4) ?
- ath_rc_priv->valid_rate_index[k-4] :
- ath_rc_priv->valid_rate_index[k-1];
- ath_rc_priv->rate_table = rate_table;
+ ath_rc_priv->valid_rate_index[k-4] :
+ ath_rc_priv->valid_rate_index[k-1];
ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n",
ath_rc_priv->ht_cap);
}
-static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
- bool is_cw40, bool is_sgi)
+static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta)
{
u8 caps = 0;
caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
else if (sta->ht_cap.mcs.rx_mask[1])
caps |= WLAN_RC_DS_FLAG;
- if (is_cw40)
+ if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
caps |= WLAN_RC_40_FLAG;
- if (is_sgi)
+ if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40 ||
+ sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
caps |= WLAN_RC_SGI_FLAG;
}
/* mac80211 Rate Control callbacks */
/***********************************/
-static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
-{
- struct ath_rc_stats *stats;
-
- stats = &rc->rcstats[final_rate];
- stats->success++;
-}
-
-
static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr;
- int final_ts_idx = 0, tx_status = 0;
- int long_retry = 0;
- __le16 fc;
- int i;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
- for (i = 0; i < sc->hw->max_rates; i++) {
- struct ieee80211_tx_rate *rate = &tx_info->status.rates[i];
- if (rate->idx < 0 || !rate->count)
- break;
-
- final_ts_idx = i;
- long_retry = rate->count - 1;
- }
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ __le16 fc = hdr->frame_control;
if (!priv_sta || !ieee80211_is_data(fc))
return;
if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
return;
- if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
- tx_status = 1;
-
- ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
- long_retry);
+ ath_rc_tx_status(sc, ath_rc_priv, skb);
/* Check if aggregation has to be enabled for this tid */
if (conf_is_ht(&sc->hw->conf) &&
ieee80211_start_tx_ba_session(sta, tid, 0);
}
}
-
- ath_debug_stat_rc(ath_rc_priv,
- ath_rc_get_rateindex(ath_rc_priv->rate_table,
- &tx_info->status.rates[final_ts_idx]));
}
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
struct ath_softc *sc = priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_rate_priv *ath_rc_priv = priv_sta;
- const struct ath_rate_table *rate_table;
- bool is_cw40, is_sgi = false;
int i, j = 0;
for (i = 0; i < sband->n_bitrates; i++) {
ath_rc_priv->neg_ht_rates.rs_nrates = j;
}
- is_cw40 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
- if (is_cw40)
- is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
- else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
- is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
-
- /* Choose rate table first */
-
- rate_table = ath_choose_rate_table(sc, sband->band,
- sta->ht_cap.ht_supported);
+ ath_rc_priv->rate_table = ath_choose_rate_table(sc, sband->band,
+ sta->ht_cap.ht_supported);
+ if (!ath_rc_priv->rate_table) {
+ ath_err(common, "No rate table chosen\n");
+ return;
+ }
- ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi);
- ath_rc_init(sc, priv_sta, sband, sta, rate_table);
+ ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta);
+ ath_rc_init(sc, priv_sta);
}
static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
{
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
- const struct ath_rate_table *rate_table = NULL;
- bool oper_cw40 = false, oper_sgi;
- bool local_cw40 = !!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG);
- bool local_sgi = !!(ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG);
-
- /* FIXME: Handle AP mode later when we support CWM */
if (changed & IEEE80211_RC_BW_CHANGED) {
- if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
- return;
+ ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta);
+ ath_rc_init(sc, priv_sta);
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
- oper_cw40 = true;
-
- if (oper_cw40)
- oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
- true : false;
- else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
- oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
- true : false;
- else
- oper_sgi = false;
-
- if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) {
- rate_table = ath_choose_rate_table(sc, sband->band,
- sta->ht_cap.ht_supported);
- ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta,
- oper_cw40, oper_sgi);
- ath_rc_init(sc, priv_sta, sband, sta, rate_table);
-
- ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG,
- "Operating HT Bandwidth changed to: %d\n",
- sc->hw->conf.channel_type);
- }
+ ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG,
+ "Operating HT Bandwidth changed to: %d\n",
+ sc->hw->conf.channel_type);
}
}
struct ath_rate_priv *rc = file->private_data;
char *buf;
unsigned int len = 0, max;
- int i = 0;
+ int rix;
ssize_t retval;
if (rc->rate_table == NULL)
"HT", "MCS", "Rate",
"Success", "Retries", "XRetries", "PER");
- for (i = 0; i < rc->rate_table_size; i++) {
+ for (rix = 0; rix < rc->max_valid_rate; rix++) {
+ u8 i = rc->valid_rate_index[rix];
u32 ratekbps = rc->rate_table->info[i].ratekbps;
struct ath_rc_stats *stats = &rc->rcstats[i];
char mcs[5];
u32 user_ratekbps;
u8 ratecode;
u8 dot11rate;
- u8 ctrl_rate;
- u8 cw40index;
- u8 sgi_index;
- u8 ht_index;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
u8 initial_ratemax;
if (!an->sleeping) {
ath_tx_queue_tid(txq, tid);
- if (ts->ts_status & ATH9K_TXERR_FILT)
+ if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
tid->ac->clear_ps_filter = true;
}
}
TX_STAT_INC(txq->axq_qnum, queued);
}
-static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
+static void setup_frame_info(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
int framelen)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = tx_info->control.sta;
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
const struct ieee80211_rate *rate;
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = info->control.sta;
+ struct ieee80211_sta *sta = txctl->sta;
struct ieee80211_vif *vif = info->control.vif;
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
!ieee80211_is_data(hdr->frame_control))
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
- setup_frame_info(hw, skb, frmlen);
+ setup_frame_info(hw, sta, skb, frmlen);
/*
* At this point, the vif, hw_key and sta pointers in the tx control
bool rx_has_plcp;
struct sk_buff *rx_failover;
int rx_failover_missing;
+ u32 ampdu_ref;
/* FIFO for collecting outstanding BlockAckRequest */
struct list_head bar_list[__AR9170_NUM_TXQ];
void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
/* TX */
-void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+void carl9170_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
void carl9170_tx_janitor(struct work_struct *work);
void carl9170_tx_process_status(struct ar9170 *ar,
const struct carl9170_rsp *cmd);
if (SUPP(CARL9170FW_WLANTX_CAB)) {
if_comb_types |=
BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_P2P_GO);
}
}
bssid = common->curbssid;
switch (vif->type) {
- case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
cam_mode |= AR9170_MAC_CAM_IBSS;
break;
+ case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
cam_mode |= AR9170_MAC_CAM_AP;
goto unlock;
+ case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
if ((vif->type == NL80211_IFTYPE_STATION) ||
(vif->type == NL80211_IFTYPE_WDS) ||
- (vif->type == NL80211_IFTYPE_AP))
+ (vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_MESH_POINT))
break;
err = -EBUSY;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
carl9170_update_beacon(ar, true);
break;
#undef TID_CHECK
}
-static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms)
+static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms,
+ struct ieee80211_rx_status *rx_status)
{
__le16 fc;
return true;
}
+ rx_status->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN;
+ rx_status->ampdu_reference = ar->ampdu_ref;
+
/*
* "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts
* certain frame types can be part of an aMPDU.
if (unlikely(len < sizeof(*mac)))
goto drop;
+ memset(&status, 0, sizeof(status));
+
mpdu_len = len - sizeof(*mac);
mac = (void *)(buf + mpdu_len);
mac_status = mac->status;
switch (mac_status & AR9170_RX_STATUS_MPDU) {
case AR9170_RX_STATUS_MPDU_FIRST:
+ ar->ampdu_ref++;
/* Aggregated MPDUs start with an PLCP header */
if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
head = (void *) buf;
break;
case AR9170_RX_STATUS_MPDU_LAST:
+ status.flag |= RX_FLAG_AMPDU_IS_LAST;
+
/*
* The last frame of an A-MPDU has an extra tail
* which does contain the phy status of the whole
* aggregate.
*/
-
if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
mpdu_len -= sizeof(struct ar9170_rx_phystatus);
phy = (void *)(buf + mpdu_len);
if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN)))
goto drop;
- memset(&status, 0, sizeof(status));
if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status)))
goto drop;
- if (!carl9170_ampdu_check(ar, buf, mac_status))
+ if (!carl9170_ampdu_check(ar, buf, mac_status, &status))
goto drop;
if (phy)
return false;
}
-static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
+static int carl9170_tx_prepare(struct ar9170 *ar,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
struct _carl9170_tx_superframe *txc;
struct carl9170_vif_info *cvif;
struct ieee80211_tx_info *info;
struct ieee80211_tx_rate *txrate;
- struct ieee80211_sta *sta;
struct carl9170_tx_info *arinfo;
unsigned int hw_queue;
int i;
else
cvif = NULL;
- sta = info->control.sta;
-
txc = (void *)skb_push(skb, sizeof(*txc));
memset(txc, 0, sizeof(*txc));
return false;
}
-void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+void carl9170_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct ar9170 *ar = hw->priv;
struct ieee80211_tx_info *info;
- struct ieee80211_sta *sta;
+ struct ieee80211_sta *sta = control->sta;
bool run;
if (unlikely(!IS_STARTED(ar)))
goto err_free;
info = IEEE80211_SKB_CB(skb);
- sta = info->control.sta;
- if (unlikely(carl9170_tx_prepare(ar, skb)))
+ if (unlikely(carl9170_tx_prepare(ar, sta, skb)))
goto err_free;
carl9170_tx_accounting(ar, skb);
b43-$(CONFIG_B43_PHY_N) += tables_nphy.o
b43-$(CONFIG_B43_PHY_N) += radio_2055.o
b43-$(CONFIG_B43_PHY_N) += radio_2056.o
+b43-$(CONFIG_B43_PHY_N) += radio_2057.o
b43-y += phy_common.o
b43-y += phy_g.o
b43-y += phy_a.o
#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */
#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
-#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
-#define B43_SHM_SH_HOSTFMI 0x0060 /* Hostflags for ucode options (middle) */
-#define B43_SHM_SH_HOSTFHI 0x0062 /* Hostflags for ucode options (high) */
+#define B43_SHM_SH_HOSTF1 0x005E /* Hostflags 1 for ucode options */
+#define B43_SHM_SH_HOSTF2 0x0060 /* Hostflags 2 for ucode options */
+#define B43_SHM_SH_HOSTF3 0x0062 /* Hostflags 3 for ucode options */
#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */
#define B43_SHM_SH_RADAR 0x0066 /* Radar register */
#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
+#define B43_SHM_SH_HOSTF4 0x0078 /* Hostflags 4 for ucode options */
#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_HOSTF5 0x00D4 /* Hostflags 5 for ucode options */
#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* TSSI information */
#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */
#define B43_PHYTYPE_HT 0x07
#define B43_PHYTYPE_LCN 0x08
#define B43_PHYTYPE_LCNXN 0x09
+#define B43_PHYTYPE_LCN40 0x0a
+#define B43_PHYTYPE_AC 0x0b
/* PHYRegisters */
#define B43_PHY_ILT_A_CTRL 0x0072
{
u64 ret;
- ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
+ ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3);
ret <<= 16;
- ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
+ ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2);
ret <<= 16;
- ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
+ ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1);
return ret;
}
lo = (value & 0x00000000FFFFULL);
mi = (value & 0x0000FFFF0000ULL) >> 16;
hi = (value & 0xFFFF00000000ULL) >> 32;
- b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
- b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
- b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1, lo);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2, mi);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3, hi);
}
/* Read the firmware capabilities bitmask (Opensource firmware only) */
}
static void b43_op_tx(struct ieee80211_hw *hw,
- struct sk_buff *skb)
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
return err;
}
+static char *b43_phy_name(struct b43_wldev *dev, u8 phy_type)
+{
+ switch (phy_type) {
+ case B43_PHYTYPE_A:
+ return "A";
+ case B43_PHYTYPE_B:
+ return "B";
+ case B43_PHYTYPE_G:
+ return "G";
+ case B43_PHYTYPE_N:
+ return "N";
+ case B43_PHYTYPE_LP:
+ return "LP";
+ case B43_PHYTYPE_SSLPN:
+ return "SSLPN";
+ case B43_PHYTYPE_HT:
+ return "HT";
+ case B43_PHYTYPE_LCN:
+ return "LCN";
+ case B43_PHYTYPE_LCNXN:
+ return "LCNXN";
+ case B43_PHYTYPE_LCN40:
+ return "LCN40";
+ case B43_PHYTYPE_AC:
+ return "AC";
+ }
+ return "UNKNOWN";
+}
+
/* Get PHY and RADIO versioning numbers */
static int b43_phy_versioning(struct b43_wldev *dev)
{
unsupported = 1;
}
if (unsupported) {
- b43err(dev->wl, "FOUND UNSUPPORTED PHY "
- "(Analog %u, Type %u, Revision %u)\n",
- analog_type, phy_type, phy_rev);
+ b43err(dev->wl, "FOUND UNSUPPORTED PHY (Analog %u, Type %d (%s), Revision %u)\n",
+ analog_type, phy_type, b43_phy_name(dev, phy_type),
+ phy_rev);
return -EOPNOTSUPP;
}
- b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
- analog_type, phy_type, phy_rev);
+ b43info(dev->wl, "Found PHY: Analog %u, Type %d (%s), Revision %u\n",
+ analog_type, phy_type, b43_phy_name(dev, phy_type), phy_rev);
/* Get RADIO versioning */
if (dev->dev->core_rev >= 24) {
(b43_radio_read16(dev, offset) & mask) | set);
}
+bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
+ u16 value, int delay, int timeout)
+{
+ u16 val;
+ int i;
+
+ for (i = 0; i < timeout; i += delay) {
+ val = b43_radio_read(dev, offset);
+ if ((val & mask) == value)
+ return true;
+ udelay(delay);
+ }
+ return false;
+}
+
u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
assert_mac_suspended(dev);
average = (a + b + c + d + 2) / 4;
if (is_ofdm) {
/* Adjust for CCK-boost */
- if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO)
+ if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1)
& B43_HF_CCKBOOST)
average = (average >= 13) ? (average - 13) : 0;
}
*/
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+/**
+ * b43_radio_wait_value - Waits for a given value in masked register read
+ */
+bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
+ u16 value, int delay, int timeout);
+
/**
* b43_radio_lock - Lock firmware radio register access
*/
#include "tables_nphy.h"
#include "radio_2055.h"
#include "radio_2056.h"
+#include "radio_2057.h"
#include "main.h"
struct nphy_txgains {
b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */
+static void b43_nphy_rf_control_override_rev7(struct b43_wldev *dev, u16 field,
+ u16 value, u8 core, bool off,
+ u8 override)
+{
+ const struct nphy_rf_control_override_rev7 *e;
+ u16 en_addrs[3][2] = {
+ { 0x0E7, 0x0EC }, { 0x342, 0x343 }, { 0x346, 0x347 }
+ };
+ u16 en_addr;
+ u16 en_mask = field;
+ u16 val_addr;
+ u8 i;
+
+ /* Remember: we can get NULL! */
+ e = b43_nphy_get_rf_ctl_over_rev7(dev, field, override);
+
+ for (i = 0; i < 2; i++) {
+ if (override >= ARRAY_SIZE(en_addrs)) {
+ b43err(dev->wl, "Invalid override value %d\n", override);
+ return;
+ }
+ en_addr = en_addrs[override][i];
+
+ val_addr = (i == 0) ? e->val_addr_core0 : e->val_addr_core1;
+
+ if (off) {
+ b43_phy_mask(dev, en_addr, ~en_mask);
+ if (e) /* Do it safer, better than wl */
+ b43_phy_mask(dev, val_addr, ~e->val_mask);
+ } else {
+ if (!core || (core & (1 << i))) {
+ b43_phy_set(dev, en_addr, en_mask);
+ if (e)
+ b43_phy_maskset(dev, val_addr, ~e->val_mask, (value << e->val_shift));
+ }
+ }
+ }
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
u16 value, u8 core, bool off)
b43_nphy_stay_in_carrier_search(dev, false);
}
+/**************************************************
+ * Radio 0x2057
+ **************************************************/
+
+/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rcal */
+static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+
+ if (phy->radio_rev == 5) {
+ b43_phy_mask(dev, 0x342, ~0x2);
+ udelay(10);
+ b43_radio_set(dev, R2057_IQTEST_SEL_PU, 0x1);
+ b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1);
+ }
+
+ b43_radio_set(dev, R2057_RCAL_CONFIG, 0x1);
+ udelay(10);
+ b43_radio_set(dev, R2057_RCAL_CONFIG, 0x3);
+ if (!b43_radio_wait_value(dev, R2057_RCCAL_N1_1, 1, 1, 100, 1000000)) {
+ b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
+ return 0;
+ }
+ b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2);
+ tmp = b43_radio_read(dev, R2057_RCAL_STATUS) & 0x3E;
+ b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1);
+
+ if (phy->radio_rev == 5) {
+ b43_radio_mask(dev, R2057_IPA2G_CASCONV_CORE0, ~0x1);
+ b43_radio_mask(dev, 0x1ca, ~0x2);
+ }
+ if (phy->radio_rev <= 4 || phy->radio_rev == 6) {
+ b43_radio_maskset(dev, R2057_TEMPSENSE_CONFIG, ~0x3C, tmp);
+ b43_radio_maskset(dev, R2057_BANDGAP_RCAL_TRIM, ~0xF0,
+ tmp << 2);
+ }
+
+ return tmp & 0x3e;
+}
+
+/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal */
+static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ bool special = (phy->radio_rev == 3 || phy->radio_rev == 4 ||
+ phy->radio_rev == 6);
+ u16 tmp;
+
+ if (special) {
+ b43_radio_write(dev, R2057_RCCAL_MASTER, 0x61);
+ b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0);
+ } else {
+ b43_radio_write(dev, 0x1AE, 0x61);
+ b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE1);
+ }
+ b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
+ b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
+ if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
+ 5000000))
+ b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
+ b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
+ if (special) {
+ b43_radio_write(dev, R2057_RCCAL_MASTER, 0x69);
+ b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
+ } else {
+ b43_radio_write(dev, 0x1AE, 0x69);
+ b43_radio_write(dev, R2057_RCCAL_TRC0, 0xD5);
+ }
+ b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
+ b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
+ if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
+ 5000000))
+ b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
+ b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
+ if (special) {
+ b43_radio_write(dev, R2057_RCCAL_MASTER, 0x73);
+ b43_radio_write(dev, R2057_RCCAL_X1, 0x28);
+ b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
+ } else {
+ b43_radio_write(dev, 0x1AE, 0x73);
+ b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
+ b43_radio_write(dev, R2057_RCCAL_TRC0, 0x99);
+ }
+ b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
+ if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
+ 5000000)) {
+ b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
+ return 0;
+ }
+ tmp = b43_radio_read(dev, R2057_RCCAL_DONE_OSCCAP);
+ b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
+ return tmp;
+}
+
+static void b43_radio_2057_init_pre(struct b43_wldev *dev)
+{
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, ~B43_NPHY_RFCTL_CMD_CHIP0PU);
+ /* Maybe wl meant to reset and set (order?) RFCTL_CMD_OEPORFORCE? */
+ b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_OEPORFORCE);
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD, ~B43_NPHY_RFCTL_CMD_OEPORFORCE);
+ b43_phy_set(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_CHIP0PU);
+}
+
+static void b43_radio_2057_init_post(struct b43_wldev *dev)
+{
+ b43_radio_set(dev, R2057_XTALPUOVR_PINCTRL, 0x1);
+
+ b43_radio_set(dev, R2057_RFPLL_MISC_CAL_RESETN, 0x78);
+ b43_radio_set(dev, R2057_XTAL_CONFIG2, 0x80);
+ mdelay(2);
+ b43_radio_mask(dev, R2057_RFPLL_MISC_CAL_RESETN, ~0x78);
+ b43_radio_mask(dev, R2057_XTAL_CONFIG2, ~0x80);
+
+ if (dev->phy.n->init_por) {
+ b43_radio_2057_rcal(dev);
+ b43_radio_2057_rccal(dev);
+ }
+ b43_radio_mask(dev, R2057_RFPLL_MASTER, ~0x8);
+
+ dev->phy.n->init_por = false;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */
+static void b43_radio_2057_init(struct b43_wldev *dev)
+{
+ b43_radio_2057_init_pre(dev);
+ r2057_upload_inittabs(dev);
+ b43_radio_2057_init_post(dev);
+}
+
/**************************************************
* Radio 0x2056
**************************************************/
enum ieee80211_band band = b43_current_band(dev->wl);
u16 offset;
u8 i;
- u16 bias, cbias, pag_boost, pgag_boost, mixg_boost, padg_boost;
+ u16 bias, cbias;
+ u16 pag_boost, padg_boost, pgag_boost, mixg_boost;
+ u16 paa_boost, pada_boost, pgaa_boost, mixa_boost;
B43_WARN_ON(dev->phy.rev < 3);
b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
}
} else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) {
- /* TODO */
+ u16 freq = dev->phy.channel_freq;
+ if (freq < 5100) {
+ paa_boost = 0xA;
+ pada_boost = 0x77;
+ pgaa_boost = 0xF;
+ mixa_boost = 0xF;
+ } else if (freq < 5340) {
+ paa_boost = 0x8;
+ pada_boost = 0x77;
+ pgaa_boost = 0xFB;
+ mixa_boost = 0xF;
+ } else if (freq < 5650) {
+ paa_boost = 0x0;
+ pada_boost = 0x77;
+ pgaa_boost = 0xB;
+ mixa_boost = 0xF;
+ } else {
+ paa_boost = 0x0;
+ pada_boost = 0x77;
+ if (freq != 5825)
+ pgaa_boost = -(freq - 18) / 36 + 168;
+ else
+ pgaa_boost = 6;
+ mixa_boost = 0xF;
+ }
+
+ for (i = 0; i < 2; i++) {
+ offset = i ? B2056_TX1 : B2056_TX0;
+
+ b43_radio_write(dev,
+ offset | B2056_TX_INTPAA_BOOST_TUNE, paa_boost);
+ b43_radio_write(dev,
+ offset | B2056_TX_PADA_BOOST_TUNE, pada_boost);
+ b43_radio_write(dev,
+ offset | B2056_TX_PGAA_BOOST_TUNE, pgaa_boost);
+ b43_radio_write(dev,
+ offset | B2056_TX_MIXA_BOOST_TUNE, mixa_boost);
+ b43_radio_write(dev,
+ offset | B2056_TX_TXSPARE1, 0x30);
+ b43_radio_write(dev,
+ offset | B2056_TX_PA_SPARE2, 0xee);
+ b43_radio_write(dev,
+ offset | B2056_TX_PADA_CASCBIAS, 0x03);
+ b43_radio_write(dev,
+ offset | B2056_TX_INTPAA_IAUX_STAT, 0x50);
+ b43_radio_write(dev,
+ offset | B2056_TX_INTPAA_IMAIN_STAT, 0x50);
+ b43_radio_write(dev,
+ offset | B2056_TX_INTPAA_CASCBIAS, 0x30);
+ }
}
udelay(50);
udelay(300);
}
+static u8 b43_radio_2056_rcal(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 mast2, tmp;
+
+ if (phy->rev != 3)
+ return 0;
+
+ mast2 = b43_radio_read(dev, B2056_SYN_PLL_MAST2);
+ b43_radio_write(dev, B2056_SYN_PLL_MAST2, mast2 | 0x7);
+
+ udelay(10);
+ b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x01);
+ udelay(10);
+ b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x09);
+
+ if (!b43_radio_wait_value(dev, B2056_SYN_RCAL_CODE_OUT, 0x80, 0x80, 100,
+ 1000000)) {
+ b43err(dev->wl, "Radio recalibration timeout\n");
+ return 0;
+ }
+
+ b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x01);
+ tmp = b43_radio_read(dev, B2056_SYN_RCAL_CODE_OUT);
+ b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x00);
+
+ b43_radio_write(dev, B2056_SYN_PLL_MAST2, mast2);
+
+ return tmp & 0x1f;
+}
+
static void b43_radio_init2056_pre(struct b43_wldev *dev)
{
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
b43_radio_mask(dev, B2056_SYN_COM_RESET, ~0x2);
b43_radio_mask(dev, B2056_SYN_PLL_MAST2, ~0xFC);
b43_radio_mask(dev, B2056_SYN_RCCAL_CTRL0, ~0x1);
- /*
- if (nphy->init_por)
- Call Radio 2056 Recalibrate
- */
+ if (dev->phy.n->init_por)
+ b43_radio_2056_rcal(dev);
}
/*
b43_radio_init2056_pre(dev);
b2056_upload_inittabs(dev, 0, 0);
b43_radio_init2056_post(dev);
+
+ dev->phy.n->init_por = false;
}
/**************************************************
{
struct b43_phy_n *nphy = dev->phy.n;
struct ssb_sprom *sprom = dev->dev->bus_sprom;
- int i;
- u16 val;
bool workaround = false;
if (sprom->revision < 4)
b43_radio_set(dev, B2055_CAL_MISC, 0x1);
msleep(1);
b43_radio_set(dev, B2055_CAL_MISC, 0x40);
- for (i = 0; i < 200; i++) {
- val = b43_radio_read(dev, B2055_CAL_COUT2);
- if (val & 0x80) {
- i = 0;
- break;
- }
- udelay(10);
- }
- if (i)
+ if (!b43_radio_wait_value(dev, B2055_CAL_COUT2, 0x80, 0x80, 10, 2000))
b43err(dev->wl, "radio post init timeout\n");
b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
b43_switch_channel(dev, dev->phy.channel);
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev)
{
- if (dev->phy.rev >= 3)
+ if (dev->phy.rev >= 7)
+ ; /* TODO */
+ else if (dev->phy.rev >= 3)
b43_nphy_gain_ctl_workarounds_rev3plus(dev);
else
b43_nphy_gain_ctl_workarounds_rev1_2(dev);
}
+/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */
+static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset)
+{
+ if (!offset)
+ offset = (dev->phy.is_40mhz) ? 0x159 : 0x154;
+ return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7;
+}
+
+static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
+{
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+ struct b43_phy *phy = &dev->phy;
+
+ u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
+ 0x1F };
+ u8 rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
+
+ u16 ntab7_15e_16e[] = { 0x10f, 0x10f };
+ u8 ntab7_138_146[] = { 0x11, 0x11 };
+ u8 ntab7_133[] = { 0x77, 0x11, 0x11 };
+
+ u16 lpf_20, lpf_40, lpf_11b;
+ u16 bcap_val, bcap_val_11b, bcap_val_11n_20, bcap_val_11n_40;
+ u16 scap_val, scap_val_11b, scap_val_11n_20, scap_val_11n_40;
+ bool rccal_ovrd = false;
+
+ u16 rx2tx_lut_20_11b, rx2tx_lut_20_11n, rx2tx_lut_40_11n;
+ u16 bias, conv, filt;
+
+ u32 tmp32;
+ u8 core;
+
+ if (phy->rev == 7) {
+ b43_phy_set(dev, B43_NPHY_FINERX2_CGC, 0x10);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0xFF80, 0x0020);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0x80FF, 0x2700);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN1, 0xFF80, 0x002E);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN1, 0x80FF, 0x3300);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN2, 0xFF80, 0x0037);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN2, 0x80FF, 0x3A00);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN3, 0xFF80, 0x003C);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN3, 0x80FF, 0x3E00);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN4, 0xFF80, 0x003E);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN4, 0x80FF, 0x3F00);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN5, 0xFF80, 0x0040);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN5, 0x80FF, 0x4000);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN6, 0xFF80, 0x0040);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN6, 0x80FF, 0x4000);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0xFF80, 0x0040);
+ b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0x80FF, 0x4000);
+ }
+ if (phy->rev <= 8) {
+ b43_phy_write(dev, 0x23F, 0x1B0);
+ b43_phy_write(dev, 0x240, 0x1B0);
+ }
+ if (phy->rev >= 8)
+ b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0x72);
+
+ b43_ntab_write(dev, B43_NTAB16(8, 0x00), 2);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x10), 2);
+ tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0));
+ tmp32 &= 0xffffff;
+ b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x15e), 2, ntab7_15e_16e);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x16e), 2, ntab7_15e_16e);
+
+ if (b43_nphy_ipa(dev))
+ b43_nphy_set_rf_sequence(dev, 0, rx2tx_events_ipa,
+ rx2tx_delays_ipa, ARRAY_SIZE(rx2tx_events_ipa));
+
+ b43_phy_maskset(dev, 0x299, 0x3FFF, 0x4000);
+ b43_phy_maskset(dev, 0x29D, 0x3FFF, 0x4000);
+
+ lpf_20 = b43_nphy_read_lpf_ctl(dev, 0x154);
+ lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159);
+ lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152);
+ if (b43_nphy_ipa(dev)) {
+ if ((phy->radio_rev == 5 && phy->is_40mhz) ||
+ phy->radio_rev == 7 || phy->radio_rev == 8) {
+ bcap_val = b43_radio_read(dev, 0x16b);
+ scap_val = b43_radio_read(dev, 0x16a);
+ scap_val_11b = scap_val;
+ bcap_val_11b = bcap_val;
+ if (phy->radio_rev == 5 && phy->is_40mhz) {
+ scap_val_11n_20 = scap_val;
+ bcap_val_11n_20 = bcap_val;
+ scap_val_11n_40 = bcap_val_11n_40 = 0xc;
+ rccal_ovrd = true;
+ } else { /* Rev 7/8 */
+ lpf_20 = 4;
+ lpf_11b = 1;
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ scap_val_11n_20 = 0xc;
+ bcap_val_11n_20 = 0xc;
+ scap_val_11n_40 = 0xa;
+ bcap_val_11n_40 = 0xa;
+ } else {
+ scap_val_11n_20 = 0x14;
+ bcap_val_11n_20 = 0x14;
+ scap_val_11n_40 = 0xf;
+ bcap_val_11n_40 = 0xf;
+ }
+ rccal_ovrd = true;
+ }
+ }
+ } else {
+ if (phy->radio_rev == 5) {
+ lpf_20 = 1;
+ lpf_40 = 3;
+ bcap_val = b43_radio_read(dev, 0x16b);
+ scap_val = b43_radio_read(dev, 0x16a);
+ scap_val_11b = scap_val;
+ bcap_val_11b = bcap_val;
+ scap_val_11n_20 = 0x11;
+ scap_val_11n_40 = 0x11;
+ bcap_val_11n_20 = 0x13;
+ bcap_val_11n_40 = 0x13;
+ rccal_ovrd = true;
+ }
+ }
+ if (rccal_ovrd) {
+ rx2tx_lut_20_11b = (bcap_val_11b << 8) |
+ (scap_val_11b << 3) |
+ lpf_11b;
+ rx2tx_lut_20_11n = (bcap_val_11n_20 << 8) |
+ (scap_val_11n_20 << 3) |
+ lpf_20;
+ rx2tx_lut_40_11n = (bcap_val_11n_40 << 8) |
+ (scap_val_11n_40 << 3) |
+ lpf_40;
+ for (core = 0; core < 2; core++) {
+ b43_ntab_write(dev, B43_NTAB16(7, 0x152 + core * 16),
+ rx2tx_lut_20_11b);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x153 + core * 16),
+ rx2tx_lut_20_11n);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x154 + core * 16),
+ rx2tx_lut_20_11n);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x155 + core * 16),
+ rx2tx_lut_40_11n);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x156 + core * 16),
+ rx2tx_lut_40_11n);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x157 + core * 16),
+ rx2tx_lut_40_11n);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x158 + core * 16),
+ rx2tx_lut_40_11n);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x159 + core * 16),
+ rx2tx_lut_40_11n);
+ }
+ b43_nphy_rf_control_override_rev7(dev, 16, 1, 3, false, 2);
+ }
+ b43_phy_write(dev, 0x32F, 0x3);
+ if (phy->radio_rev == 4 || phy->radio_rev == 6)
+ b43_nphy_rf_control_override_rev7(dev, 4, 1, 3, false, 0);
+
+ if (phy->radio_rev == 3 || phy->radio_rev == 4 || phy->radio_rev == 6) {
+ if (sprom->revision &&
+ sprom->boardflags2_hi & B43_BFH2_IPALVLSHIFT_3P3) {
+ b43_radio_write(dev, 0x5, 0x05);
+ b43_radio_write(dev, 0x6, 0x30);
+ b43_radio_write(dev, 0x7, 0x00);
+ b43_radio_set(dev, 0x4f, 0x1);
+ b43_radio_set(dev, 0xd4, 0x1);
+ bias = 0x1f;
+ conv = 0x6f;
+ filt = 0xaa;
+ } else {
+ bias = 0x2b;
+ conv = 0x7f;
+ filt = 0xee;
+ }
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ for (core = 0; core < 2; core++) {
+ if (core == 0) {
+ b43_radio_write(dev, 0x5F, bias);
+ b43_radio_write(dev, 0x64, conv);
+ b43_radio_write(dev, 0x66, filt);
+ } else {
+ b43_radio_write(dev, 0xE8, bias);
+ b43_radio_write(dev, 0xE9, conv);
+ b43_radio_write(dev, 0xEB, filt);
+ }
+ }
+ }
+ }
+
+ if (b43_nphy_ipa(dev)) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ if (phy->radio_rev == 3 || phy->radio_rev == 4 ||
+ phy->radio_rev == 6) {
+ for (core = 0; core < 2; core++) {
+ if (core == 0)
+ b43_radio_write(dev, 0x51,
+ 0x7f);
+ else
+ b43_radio_write(dev, 0xd6,
+ 0x7f);
+ }
+ }
+ if (phy->radio_rev == 3) {
+ for (core = 0; core < 2; core++) {
+ if (core == 0) {
+ b43_radio_write(dev, 0x64,
+ 0x13);
+ b43_radio_write(dev, 0x5F,
+ 0x1F);
+ b43_radio_write(dev, 0x66,
+ 0xEE);
+ b43_radio_write(dev, 0x59,
+ 0x8A);
+ b43_radio_write(dev, 0x80,
+ 0x3E);
+ } else {
+ b43_radio_write(dev, 0x69,
+ 0x13);
+ b43_radio_write(dev, 0xE8,
+ 0x1F);
+ b43_radio_write(dev, 0xEB,
+ 0xEE);
+ b43_radio_write(dev, 0xDE,
+ 0x8A);
+ b43_radio_write(dev, 0x105,
+ 0x3E);
+ }
+ }
+ } else if (phy->radio_rev == 7 || phy->radio_rev == 8) {
+ if (!phy->is_40mhz) {
+ b43_radio_write(dev, 0x5F, 0x14);
+ b43_radio_write(dev, 0xE8, 0x12);
+ } else {
+ b43_radio_write(dev, 0x5F, 0x16);
+ b43_radio_write(dev, 0xE8, 0x16);
+ }
+ }
+ } else {
+ u16 freq = phy->channel_freq;
+ if ((freq >= 5180 && freq <= 5230) ||
+ (freq >= 5745 && freq <= 5805)) {
+ b43_radio_write(dev, 0x7D, 0xFF);
+ b43_radio_write(dev, 0xFE, 0xFF);
+ }
+ }
+ } else {
+ if (phy->radio_rev != 5) {
+ for (core = 0; core < 2; core++) {
+ if (core == 0) {
+ b43_radio_write(dev, 0x5c, 0x61);
+ b43_radio_write(dev, 0x51, 0x70);
+ } else {
+ b43_radio_write(dev, 0xe1, 0x61);
+ b43_radio_write(dev, 0xd6, 0x70);
+ }
+ }
+ }
+ }
+
+ if (phy->radio_rev == 4) {
+ b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20);
+ for (core = 0; core < 2; core++) {
+ if (core == 0) {
+ b43_radio_write(dev, 0x1a1, 0x00);
+ b43_radio_write(dev, 0x1a2, 0x3f);
+ b43_radio_write(dev, 0x1a6, 0x3f);
+ } else {
+ b43_radio_write(dev, 0x1a7, 0x00);
+ b43_radio_write(dev, 0x1ab, 0x3f);
+ b43_radio_write(dev, 0x1ac, 0x3f);
+ }
+ }
+ } else {
+ b43_phy_set(dev, B43_NPHY_AFECTL_C1, 0x4);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x4);
+ b43_phy_set(dev, B43_NPHY_AFECTL_C2, 0x4);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4);
+
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x1);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x1);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x1);
+ b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x1);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20);
+
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x4);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x4);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x4);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x4);
+ }
+
+ b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, 0x2);
+
+ b43_ntab_write(dev, B43_NTAB32(16, 0x100), 20);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x138), 2, ntab7_138_146);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x141), 0x77);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x133), 3, ntab7_133);
+ b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x146), 2, ntab7_138_146);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x123), 0x77);
+ b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 0x77);
+
+ if (!phy->is_40mhz) {
+ b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x18D);
+ b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D);
+ } else {
+ b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x14D);
+ b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x14D);
+ }
+
+ b43_nphy_gain_ctl_workarounds(dev);
+
+ /* TODO
+ b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4,
+ aux_adc_vmid_rev7_core0);
+ b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4,
+ aux_adc_vmid_rev7_core1);
+ b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0C), 4,
+ aux_adc_gain_rev7);
+ b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1C), 4,
+ aux_adc_gain_rev7);
+ */
+}
+
static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
rx2tx_delays[6] = 1;
rx2tx_events[7] = 0x1F;
}
- b43_nphy_set_rf_sequence(dev, 1, rx2tx_events, rx2tx_delays,
+ b43_nphy_set_rf_sequence(dev, 0, rx2tx_events, rx2tx_delays,
ARRAY_SIZE(rx2tx_events));
}
b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700);
- b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
- b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
+ if (!dev->phy.is_40mhz) {
+ b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
+ b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
+ } else {
+ b43_ntab_write(dev, B43_NTAB32(16, 3), 0x14D);
+ b43_ntab_write(dev, B43_NTAB32(16, 127), 0x14D);
+ }
b43_nphy_gain_ctl_workarounds(dev);
b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32);
if (dev->phy.rev == 4 &&
- b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC,
0x70);
b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC,
0x70);
}
+ /* Dropped probably-always-true condition */
b43_phy_write(dev, 0x224, 0x03eb);
b43_phy_write(dev, 0x225, 0x03eb);
b43_phy_write(dev, 0x226, 0x0341);
b43_phy_write(dev, 0x22d, 0x042b);
b43_phy_write(dev, 0x22e, 0x0381);
b43_phy_write(dev, 0x22f, 0x0381);
+
+ if (dev->phy.rev >= 6 && sprom->boardflags2_lo & B43_BFL2_SINGLEANT_CCK)
+ ; /* TODO: 0x0080000000000000 HF */
}
static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
+ if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD ||
+ dev->dev->board_type == 0x8B) {
+ delays1[0] = 0x1;
+ delays1[5] = 0x14;
+ }
+
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
nphy->band5g_pwrgain) {
b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A);
b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A);
- b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
- b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+ if (dev->phy.rev < 3) {
+ b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+ }
if (dev->phy.rev < 2) {
b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
- if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD &&
- dev->dev->board_type == 0x8B) {
- delays1[0] = 0x1;
- delays1[5] = 0x14;
- }
b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
- b43_phy_mask(dev, B43_NPHY_PIL_DW1,
- ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
- b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
- b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
- b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+ if (dev->phy.rev < 3) {
+ b43_phy_mask(dev, B43_NPHY_PIL_DW1,
+ ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+ }
if (dev->phy.rev == 2)
b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
b43_phy_set(dev, B43_NPHY_IQFLIP,
B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
- if (dev->phy.rev >= 3)
+ if (dev->phy.rev >= 7)
+ b43_nphy_workarounds_rev7plus(dev);
+ else if (dev->phy.rev >= 3)
b43_nphy_workarounds_rev3plus(dev);
else
b43_nphy_workarounds_rev1_2(dev);
b43_nphy_ipa_internal_tssi_setup(dev);
if (phy->rev >= 7)
- ; /* TODO: Override Rev7 with 0x2000, 0, 3, 0, 0 as arguments */
+ b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, false, 0);
else if (phy->rev >= 3)
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false);
b43_nphy_rssi_select(dev, 0, 0);
if (phy->rev >= 7)
- ; /* TODO: Override Rev7 with 0x2000, 0, 3, 1, 0 as arguments */
+ b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, true, 0);
else if (phy->rev >= 3)
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true);
nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4);
nphy->spur_avoid = (phy->rev >= 3) ?
B43_SPUR_AVOID_AUTO : B43_SPUR_AVOID_DISABLE;
+ nphy->init_por = true;
nphy->gain_boost = true; /* this way we follow wl, assume it is true */
nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
nphy->ipa2g_on = sprom->fem.ghz2.extpa_gain == 2;
nphy->ipa5g_on = sprom->fem.ghz5.extpa_gain == 2;
}
+
+ nphy->init_por = true;
}
static void b43_nphy_op_free(struct b43_wldev *dev)
if (blocked) {
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
~B43_NPHY_RFCTL_CMD_CHIP0PU);
- if (dev->phy.rev >= 3) {
+ if (dev->phy.rev >= 7) {
+ /* TODO */
+ } else if (dev->phy.rev >= 3) {
b43_radio_mask(dev, 0x09, ~0x2);
b43_radio_write(dev, 0x204D, 0);
b43_radio_write(dev, 0x3064, 0);
}
} else {
- if (dev->phy.rev >= 3) {
+ if (dev->phy.rev >= 7) {
+ b43_radio_2057_init(dev);
+ b43_switch_channel(dev, dev->phy.channel);
+ } else if (dev->phy.rev >= 3) {
b43_radio_init2056(dev);
b43_switch_channel(dev, dev->phy.channel);
} else {
u16 papd_epsilon_offset[2];
s32 preamble_override;
u32 bb_mult_save;
+ bool init_por;
bool gain_boost;
bool elna_gain_config;
--- /dev/null
+/*
+
+ Broadcom B43 wireless driver
+ IEEE 802.11n 2057 radio device data tables
+
+ Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "radio_2057.h"
+#include "phy_common.h"
+
+static u16 r2057_rev4_init[42][2] = {
+ { 0x0E, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 },
+ { 0x35, 0x26 }, { 0x3C, 0xff }, { 0x3D, 0xff }, { 0x3E, 0xff },
+ { 0x3F, 0xff }, { 0x62, 0x33 }, { 0x8A, 0xf0 }, { 0x8B, 0x10 },
+ { 0x8C, 0xf0 }, { 0x91, 0x3f }, { 0x92, 0x36 }, { 0xA4, 0x8c },
+ { 0xA8, 0x55 }, { 0xAF, 0x01 }, { 0x10F, 0xf0 }, { 0x110, 0x10 },
+ { 0x111, 0xf0 }, { 0x116, 0x3f }, { 0x117, 0x36 }, { 0x129, 0x8c },
+ { 0x12D, 0x55 }, { 0x134, 0x01 }, { 0x15E, 0x00 }, { 0x15F, 0x00 },
+ { 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 },
+ { 0x169, 0x02 }, { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 },
+ { 0x1A4, 0x00 }, { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 },
+ { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
+};
+
+static u16 r2057_rev5_init[44][2] = {
+ { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
+ { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
+ { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
+ { 0x64, 0x0f }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
+ { 0xA1, 0x20 }, { 0xD6, 0x70 }, { 0xDE, 0x88 }, { 0xE1, 0x20 },
+ { 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0x106, 0x01 }, { 0x116, 0x3f },
+ { 0x117, 0x36 }, { 0x126, 0x20 }, { 0x15E, 0x00 }, { 0x15F, 0x00 },
+ { 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 },
+ { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 },
+ { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 },
+ { 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 }, { 0x1C2, 0x80 },
+};
+
+static u16 r2057_rev5a_init[45][2] = {
+ { 0x00, 0x15 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
+ { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
+ { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
+ { 0x64, 0x0f }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
+ { 0xC9, 0x01 }, { 0xD6, 0x70 }, { 0xDE, 0x88 }, { 0xE1, 0x20 },
+ { 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0x106, 0x01 }, { 0x116, 0x3f },
+ { 0x117, 0x36 }, { 0x126, 0x20 }, { 0x14E, 0x01 }, { 0x15E, 0x00 },
+ { 0x15F, 0x00 }, { 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 },
+ { 0x163, 0x00 }, { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 },
+ { 0x1A4, 0x00 }, { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 },
+ { 0x1AB, 0x00 }, { 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 },
+ { 0x1C2, 0x80 },
+};
+
+static u16 r2057_rev7_init[54][2] = {
+ { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
+ { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
+ { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x13 },
+ { 0x66, 0xee }, { 0x6E, 0x58 }, { 0x75, 0x13 }, { 0x7B, 0x13 },
+ { 0x7C, 0x14 }, { 0x7D, 0xee }, { 0x81, 0x01 }, { 0x91, 0x3f },
+ { 0x92, 0x36 }, { 0xA1, 0x20 }, { 0xD6, 0x70 }, { 0xDE, 0x88 },
+ { 0xE1, 0x20 }, { 0xE8, 0x0f }, { 0xE9, 0x13 }, { 0xEB, 0xee },
+ { 0xF3, 0x58 }, { 0xFA, 0x13 }, { 0x100, 0x13 }, { 0x101, 0x14 },
+ { 0x102, 0xee }, { 0x106, 0x01 }, { 0x116, 0x3f }, { 0x117, 0x36 },
+ { 0x126, 0x20 }, { 0x15E, 0x00 }, { 0x15F, 0x00 }, { 0x160, 0x00 },
+ { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 }, { 0x16A, 0x00 },
+ { 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 }, { 0x1A5, 0x00 },
+ { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
+ { 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
+};
+
+static u16 r2057_rev8_init[54][2] = {
+ { 0x00, 0x08 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
+ { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
+ { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x0f },
+ { 0x6E, 0x58 }, { 0x75, 0x13 }, { 0x7B, 0x13 }, { 0x7C, 0x0f },
+ { 0x7D, 0xee }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
+ { 0xA1, 0x20 }, { 0xC9, 0x01 }, { 0xD6, 0x70 }, { 0xDE, 0x88 },
+ { 0xE1, 0x20 }, { 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0xF3, 0x58 },
+ { 0xFA, 0x13 }, { 0x100, 0x13 }, { 0x101, 0x0f }, { 0x102, 0xee },
+ { 0x106, 0x01 }, { 0x116, 0x3f }, { 0x117, 0x36 }, { 0x126, 0x20 },
+ { 0x14E, 0x01 }, { 0x15E, 0x00 }, { 0x15F, 0x00 }, { 0x160, 0x00 },
+ { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 }, { 0x16A, 0x00 },
+ { 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 }, { 0x1A5, 0x00 },
+ { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
+ { 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
+};
+
+void r2057_upload_inittabs(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 *table = NULL;
+ u16 size, i;
+
+ if (phy->rev == 7) {
+ table = r2057_rev4_init[0];
+ size = ARRAY_SIZE(r2057_rev4_init);
+ } else if (phy->rev == 8 || phy->rev == 9) {
+ if (phy->radio_rev == 5) {
+ if (phy->radio_rev == 8) {
+ table = r2057_rev5_init[0];
+ size = ARRAY_SIZE(r2057_rev5_init);
+ } else {
+ table = r2057_rev5a_init[0];
+ size = ARRAY_SIZE(r2057_rev5a_init);
+ }
+ } else if (phy->radio_rev == 7) {
+ table = r2057_rev7_init[0];
+ size = ARRAY_SIZE(r2057_rev7_init);
+ } else if (phy->radio_rev == 9) {
+ table = r2057_rev8_init[0];
+ size = ARRAY_SIZE(r2057_rev8_init);
+ }
+ }
+
+ if (table) {
+ for (i = 0; i < 10; i++) {
+ pr_info("radio_write 0x%X ", *table);
+ table++;
+ pr_info("0x%X\n", *table);
+ table++;
+ }
+ }
+}
--- /dev/null
+#ifndef B43_RADIO_2057_H_
+#define B43_RADIO_2057_H_
+
+#include <linux/types.h>
+
+#include "tables_nphy.h"
+
+#define R2057_DACBUF_VINCM_CORE0 0x000
+#define R2057_IDCODE 0x001
+#define R2057_RCCAL_MASTER 0x002
+#define R2057_RCCAL_CAP_SIZE 0x003
+#define R2057_RCAL_CONFIG 0x004
+#define R2057_GPAIO_CONFIG 0x005
+#define R2057_GPAIO_SEL1 0x006
+#define R2057_GPAIO_SEL0 0x007
+#define R2057_CLPO_CONFIG 0x008
+#define R2057_BANDGAP_CONFIG 0x009
+#define R2057_BANDGAP_RCAL_TRIM 0x00a
+#define R2057_AFEREG_CONFIG 0x00b
+#define R2057_TEMPSENSE_CONFIG 0x00c
+#define R2057_XTAL_CONFIG1 0x00d
+#define R2057_XTAL_ICORE_SIZE 0x00e
+#define R2057_XTAL_BUF_SIZE 0x00f
+#define R2057_XTAL_PULLCAP_SIZE 0x010
+#define R2057_RFPLL_MASTER 0x011
+#define R2057_VCOMONITOR_VTH_L 0x012
+#define R2057_VCOMONITOR_VTH_H 0x013
+#define R2057_VCOCAL_BIASRESET_RFPLLREG_VOUT 0x014
+#define R2057_VCO_VARCSIZE_IDAC 0x015
+#define R2057_VCOCAL_COUNTVAL0 0x016
+#define R2057_VCOCAL_COUNTVAL1 0x017
+#define R2057_VCOCAL_INTCLK_COUNT 0x018
+#define R2057_VCOCAL_MASTER 0x019
+#define R2057_VCOCAL_NUMCAPCHANGE 0x01a
+#define R2057_VCOCAL_WINSIZE 0x01b
+#define R2057_VCOCAL_DELAY_AFTER_REFRESH 0x01c
+#define R2057_VCOCAL_DELAY_AFTER_CLOSELOOP 0x01d
+#define R2057_VCOCAL_DELAY_AFTER_OPENLOOP 0x01e
+#define R2057_VCOCAL_DELAY_BEFORE_OPENLOOP 0x01f
+#define R2057_VCO_FORCECAPEN_FORCECAP1 0x020
+#define R2057_VCO_FORCECAP0 0x021
+#define R2057_RFPLL_REFMASTER_SPAREXTALSIZE 0x022
+#define R2057_RFPLL_PFD_RESET_PW 0x023
+#define R2057_RFPLL_LOOPFILTER_R2 0x024
+#define R2057_RFPLL_LOOPFILTER_R1 0x025
+#define R2057_RFPLL_LOOPFILTER_C3 0x026
+#define R2057_RFPLL_LOOPFILTER_C2 0x027
+#define R2057_RFPLL_LOOPFILTER_C1 0x028
+#define R2057_CP_KPD_IDAC 0x029
+#define R2057_RFPLL_IDACS 0x02a
+#define R2057_RFPLL_MISC_EN 0x02b
+#define R2057_RFPLL_MMD0 0x02c
+#define R2057_RFPLL_MMD1 0x02d
+#define R2057_RFPLL_MISC_CAL_RESETN 0x02e
+#define R2057_JTAGXTAL_SIZE_CPBIAS_FILTRES 0x02f
+#define R2057_VCO_ALCREF_BBPLLXTAL_SIZE 0x030
+#define R2057_VCOCAL_READCAP0 0x031
+#define R2057_VCOCAL_READCAP1 0x032
+#define R2057_VCOCAL_STATUS 0x033
+#define R2057_LOGEN_PUS 0x034
+#define R2057_LOGEN_PTAT_RESETS 0x035
+#define R2057_VCOBUF_IDACS 0x036
+#define R2057_VCOBUF_TUNE 0x037
+#define R2057_CMOSBUF_TX2GQ_IDACS 0x038
+#define R2057_CMOSBUF_TX2GI_IDACS 0x039
+#define R2057_CMOSBUF_TX5GQ_IDACS 0x03a
+#define R2057_CMOSBUF_TX5GI_IDACS 0x03b
+#define R2057_CMOSBUF_RX2GQ_IDACS 0x03c
+#define R2057_CMOSBUF_RX2GI_IDACS 0x03d
+#define R2057_CMOSBUF_RX5GQ_IDACS 0x03e
+#define R2057_CMOSBUF_RX5GI_IDACS 0x03f
+#define R2057_LOGEN_MX2G_IDACS 0x040
+#define R2057_LOGEN_MX2G_TUNE 0x041
+#define R2057_LOGEN_MX5G_IDACS 0x042
+#define R2057_LOGEN_MX5G_TUNE 0x043
+#define R2057_LOGEN_MX5G_RCCR 0x044
+#define R2057_LOGEN_INDBUF2G_IDAC 0x045
+#define R2057_LOGEN_INDBUF2G_IBOOST 0x046
+#define R2057_LOGEN_INDBUF2G_TUNE 0x047
+#define R2057_LOGEN_INDBUF5G_IDAC 0x048
+#define R2057_LOGEN_INDBUF5G_IBOOST 0x049
+#define R2057_LOGEN_INDBUF5G_TUNE 0x04a
+#define R2057_CMOSBUF_TX_RCCR 0x04b
+#define R2057_CMOSBUF_RX_RCCR 0x04c
+#define R2057_LOGEN_SEL_PKDET 0x04d
+#define R2057_CMOSBUF_SHAREIQ_PTAT 0x04e
+#define R2057_RXTXBIAS_CONFIG_CORE0 0x04f
+#define R2057_TXGM_TXRF_PUS_CORE0 0x050
+#define R2057_TXGM_IDAC_BLEED_CORE0 0x051
+#define R2057_TXGM_GAIN_CORE0 0x056
+#define R2057_TXGM2G_PKDET_PUS_CORE0 0x057
+#define R2057_PAD2G_PTATS_CORE0 0x058
+#define R2057_PAD2G_IDACS_CORE0 0x059
+#define R2057_PAD2G_BOOST_PU_CORE0 0x05a
+#define R2057_PAD2G_CASCV_GAIN_CORE0 0x05b
+#define R2057_TXMIX2G_TUNE_BOOST_PU_CORE0 0x05c
+#define R2057_TXMIX2G_LODC_CORE0 0x05d
+#define R2057_PAD2G_TUNE_PUS_CORE0 0x05e
+#define R2057_IPA2G_GAIN_CORE0 0x05f
+#define R2057_TSSI2G_SPARE1_CORE0 0x060
+#define R2057_TSSI2G_SPARE2_CORE0 0x061
+#define R2057_IPA2G_TUNEV_CASCV_PTAT_CORE0 0x062
+#define R2057_IPA2G_IMAIN_CORE0 0x063
+#define R2057_IPA2G_CASCONV_CORE0 0x064
+#define R2057_IPA2G_CASCOFFV_CORE0 0x065
+#define R2057_IPA2G_BIAS_FILTER_CORE0 0x066
+#define R2057_TX5G_PKDET_CORE0 0x069
+#define R2057_PGA_PTAT_TXGM5G_PU_CORE0 0x06a
+#define R2057_PAD5G_PTATS1_CORE0 0x06b
+#define R2057_PAD5G_CLASS_PTATS2_CORE0 0x06c
+#define R2057_PGA_BOOSTPTAT_IMAIN_CORE0 0x06d
+#define R2057_PAD5G_CASCV_IMAIN_CORE0 0x06e
+#define R2057_TXMIX5G_IBOOST_PAD_IAUX_CORE0 0x06f
+#define R2057_PGA_BOOST_TUNE_CORE0 0x070
+#define R2057_PGA_GAIN_CORE0 0x071
+#define R2057_PAD5G_CASCOFFV_GAIN_PUS_CORE0 0x072
+#define R2057_TXMIX5G_BOOST_TUNE_CORE0 0x073
+#define R2057_PAD5G_TUNE_MISC_PUS_CORE0 0x074
+#define R2057_IPA5G_IAUX_CORE0 0x075
+#define R2057_IPA5G_GAIN_CORE0 0x076
+#define R2057_TSSI5G_SPARE1_CORE0 0x077
+#define R2057_TSSI5G_SPARE2_CORE0 0x078
+#define R2057_IPA5G_CASCOFFV_PU_CORE0 0x079
+#define R2057_IPA5G_PTAT_CORE0 0x07a
+#define R2057_IPA5G_IMAIN_CORE0 0x07b
+#define R2057_IPA5G_CASCONV_CORE0 0x07c
+#define R2057_IPA5G_BIAS_FILTER_CORE0 0x07d
+#define R2057_PAD_BIAS_FILTER_BWS_CORE0 0x080
+#define R2057_TR2G_CONFIG1_CORE0_NU 0x081
+#define R2057_TR2G_CONFIG2_CORE0_NU 0x082
+#define R2057_LNA5G_RFEN_CORE0 0x083
+#define R2057_TR5G_CONFIG2_CORE0_NU 0x084
+#define R2057_RXRFBIAS_IBOOST_PU_CORE0 0x085
+#define R2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE0 0x086
+#define R2057_RXGM_CMFBITAIL_AUXPTAT_CORE0 0x087
+#define R2057_RXMIX_ICORE_RXGM_IAUX_CORE0 0x088
+#define R2057_RXMIX_CMFBITAIL_PU_CORE0 0x089
+#define R2057_LNA2_IMAIN_PTAT_PU_CORE0 0x08a
+#define R2057_LNA2_IAUX_PTAT_CORE0 0x08b
+#define R2057_LNA1_IMAIN_PTAT_PU_CORE0 0x08c
+#define R2057_LNA15G_INPUT_MATCH_TUNE_CORE0 0x08d
+#define R2057_RXRFBIAS_BANDSEL_CORE0 0x08e
+#define R2057_TIA_CONFIG_CORE0 0x08f
+#define R2057_TIA_IQGAIN_CORE0 0x090
+#define R2057_TIA_IBIAS2_CORE0 0x091
+#define R2057_TIA_IBIAS1_CORE0 0x092
+#define R2057_TIA_SPARE_Q_CORE0 0x093
+#define R2057_TIA_SPARE_I_CORE0 0x094
+#define R2057_RXMIX2G_PUS_CORE0 0x095
+#define R2057_RXMIX2G_VCMREFS_CORE0 0x096
+#define R2057_RXMIX2G_LODC_QI_CORE0 0x097
+#define R2057_W12G_BW_LNA2G_PUS_CORE0 0x098
+#define R2057_LNA2G_GAIN_CORE0 0x099
+#define R2057_LNA2G_TUNE_CORE0 0x09a
+#define R2057_RXMIX5G_PUS_CORE0 0x09b
+#define R2057_RXMIX5G_VCMREFS_CORE0 0x09c
+#define R2057_RXMIX5G_LODC_QI_CORE0 0x09d
+#define R2057_W15G_BW_LNA5G_PUS_CORE0 0x09e
+#define R2057_LNA5G_GAIN_CORE0 0x09f
+#define R2057_LNA5G_TUNE_CORE0 0x0a0
+#define R2057_LPFSEL_TXRX_RXBB_PUS_CORE0 0x0a1
+#define R2057_RXBB_BIAS_MASTER_CORE0 0x0a2
+#define R2057_RXBB_VGABUF_IDACS_CORE0 0x0a3
+#define R2057_LPF_VCMREF_TXBUF_VCMREF_CORE0 0x0a4
+#define R2057_TXBUF_VINCM_CORE0 0x0a5
+#define R2057_TXBUF_IDACS_CORE0 0x0a6
+#define R2057_LPF_RESP_RXBUF_BW_CORE0 0x0a7
+#define R2057_RXBB_CC_CORE0 0x0a8
+#define R2057_RXBB_SPARE3_CORE0 0x0a9
+#define R2057_RXBB_RCCAL_HPC_CORE0 0x0aa
+#define R2057_LPF_IDACS_CORE0 0x0ab
+#define R2057_LPFBYP_DCLOOP_BYP_IDAC_CORE0 0x0ac
+#define R2057_TXBUF_GAIN_CORE0 0x0ad
+#define R2057_AFELOOPBACK_AACI_RESP_CORE0 0x0ae
+#define R2057_RXBUF_DEGEN_CORE0 0x0af
+#define R2057_RXBB_SPARE2_CORE0 0x0b0
+#define R2057_RXBB_SPARE1_CORE0 0x0b1
+#define R2057_RSSI_MASTER_CORE0 0x0b2
+#define R2057_W2_MASTER_CORE0 0x0b3
+#define R2057_NB_MASTER_CORE0 0x0b4
+#define R2057_W2_IDACS0_Q_CORE0 0x0b5
+#define R2057_W2_IDACS1_Q_CORE0 0x0b6
+#define R2057_W2_IDACS0_I_CORE0 0x0b7
+#define R2057_W2_IDACS1_I_CORE0 0x0b8
+#define R2057_RSSI_GPAIOSEL_W1_IDACS_CORE0 0x0b9
+#define R2057_NB_IDACS_Q_CORE0 0x0ba
+#define R2057_NB_IDACS_I_CORE0 0x0bb
+#define R2057_BACKUP4_CORE0 0x0c1
+#define R2057_BACKUP3_CORE0 0x0c2
+#define R2057_BACKUP2_CORE0 0x0c3
+#define R2057_BACKUP1_CORE0 0x0c4
+#define R2057_SPARE16_CORE0 0x0c5
+#define R2057_SPARE15_CORE0 0x0c6
+#define R2057_SPARE14_CORE0 0x0c7
+#define R2057_SPARE13_CORE0 0x0c8
+#define R2057_SPARE12_CORE0 0x0c9
+#define R2057_SPARE11_CORE0 0x0ca
+#define R2057_TX2G_BIAS_RESETS_CORE0 0x0cb
+#define R2057_TX5G_BIAS_RESETS_CORE0 0x0cc
+#define R2057_IQTEST_SEL_PU 0x0cd
+#define R2057_XTAL_CONFIG2 0x0ce
+#define R2057_BUFS_MISC_LPFBW_CORE0 0x0cf
+#define R2057_TXLPF_RCCAL_CORE0 0x0d0
+#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0 0x0d1
+#define R2057_LPF_GAIN_CORE0 0x0d2
+#define R2057_DACBUF_IDACS_BW_CORE0 0x0d3
+#define R2057_RXTXBIAS_CONFIG_CORE1 0x0d4
+#define R2057_TXGM_TXRF_PUS_CORE1 0x0d5
+#define R2057_TXGM_IDAC_BLEED_CORE1 0x0d6
+#define R2057_TXGM_GAIN_CORE1 0x0db
+#define R2057_TXGM2G_PKDET_PUS_CORE1 0x0dc
+#define R2057_PAD2G_PTATS_CORE1 0x0dd
+#define R2057_PAD2G_IDACS_CORE1 0x0de
+#define R2057_PAD2G_BOOST_PU_CORE1 0x0df
+#define R2057_PAD2G_CASCV_GAIN_CORE1 0x0e0
+#define R2057_TXMIX2G_TUNE_BOOST_PU_CORE1 0x0e1
+#define R2057_TXMIX2G_LODC_CORE1 0x0e2
+#define R2057_PAD2G_TUNE_PUS_CORE1 0x0e3
+#define R2057_IPA2G_GAIN_CORE1 0x0e4
+#define R2057_TSSI2G_SPARE1_CORE1 0x0e5
+#define R2057_TSSI2G_SPARE2_CORE1 0x0e6
+#define R2057_IPA2G_TUNEV_CASCV_PTAT_CORE1 0x0e7
+#define R2057_IPA2G_IMAIN_CORE1 0x0e8
+#define R2057_IPA2G_CASCONV_CORE1 0x0e9
+#define R2057_IPA2G_CASCOFFV_CORE1 0x0ea
+#define R2057_IPA2G_BIAS_FILTER_CORE1 0x0eb
+#define R2057_TX5G_PKDET_CORE1 0x0ee
+#define R2057_PGA_PTAT_TXGM5G_PU_CORE1 0x0ef
+#define R2057_PAD5G_PTATS1_CORE1 0x0f0
+#define R2057_PAD5G_CLASS_PTATS2_CORE1 0x0f1
+#define R2057_PGA_BOOSTPTAT_IMAIN_CORE1 0x0f2
+#define R2057_PAD5G_CASCV_IMAIN_CORE1 0x0f3
+#define R2057_TXMIX5G_IBOOST_PAD_IAUX_CORE1 0x0f4
+#define R2057_PGA_BOOST_TUNE_CORE1 0x0f5
+#define R2057_PGA_GAIN_CORE1 0x0f6
+#define R2057_PAD5G_CASCOFFV_GAIN_PUS_CORE1 0x0f7
+#define R2057_TXMIX5G_BOOST_TUNE_CORE1 0x0f8
+#define R2057_PAD5G_TUNE_MISC_PUS_CORE1 0x0f9
+#define R2057_IPA5G_IAUX_CORE1 0x0fa
+#define R2057_IPA5G_GAIN_CORE1 0x0fb
+#define R2057_TSSI5G_SPARE1_CORE1 0x0fc
+#define R2057_TSSI5G_SPARE2_CORE1 0x0fd
+#define R2057_IPA5G_CASCOFFV_PU_CORE1 0x0fe
+#define R2057_IPA5G_PTAT_CORE1 0x0ff
+#define R2057_IPA5G_IMAIN_CORE1 0x100
+#define R2057_IPA5G_CASCONV_CORE1 0x101
+#define R2057_IPA5G_BIAS_FILTER_CORE1 0x102
+#define R2057_PAD_BIAS_FILTER_BWS_CORE1 0x105
+#define R2057_TR2G_CONFIG1_CORE1_NU 0x106
+#define R2057_TR2G_CONFIG2_CORE1_NU 0x107
+#define R2057_LNA5G_RFEN_CORE1 0x108
+#define R2057_TR5G_CONFIG2_CORE1_NU 0x109
+#define R2057_RXRFBIAS_IBOOST_PU_CORE1 0x10a
+#define R2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE1 0x10b
+#define R2057_RXGM_CMFBITAIL_AUXPTAT_CORE1 0x10c
+#define R2057_RXMIX_ICORE_RXGM_IAUX_CORE1 0x10d
+#define R2057_RXMIX_CMFBITAIL_PU_CORE1 0x10e
+#define R2057_LNA2_IMAIN_PTAT_PU_CORE1 0x10f
+#define R2057_LNA2_IAUX_PTAT_CORE1 0x110
+#define R2057_LNA1_IMAIN_PTAT_PU_CORE1 0x111
+#define R2057_LNA15G_INPUT_MATCH_TUNE_CORE1 0x112
+#define R2057_RXRFBIAS_BANDSEL_CORE1 0x113
+#define R2057_TIA_CONFIG_CORE1 0x114
+#define R2057_TIA_IQGAIN_CORE1 0x115
+#define R2057_TIA_IBIAS2_CORE1 0x116
+#define R2057_TIA_IBIAS1_CORE1 0x117
+#define R2057_TIA_SPARE_Q_CORE1 0x118
+#define R2057_TIA_SPARE_I_CORE1 0x119
+#define R2057_RXMIX2G_PUS_CORE1 0x11a
+#define R2057_RXMIX2G_VCMREFS_CORE1 0x11b
+#define R2057_RXMIX2G_LODC_QI_CORE1 0x11c
+#define R2057_W12G_BW_LNA2G_PUS_CORE1 0x11d
+#define R2057_LNA2G_GAIN_CORE1 0x11e
+#define R2057_LNA2G_TUNE_CORE1 0x11f
+#define R2057_RXMIX5G_PUS_CORE1 0x120
+#define R2057_RXMIX5G_VCMREFS_CORE1 0x121
+#define R2057_RXMIX5G_LODC_QI_CORE1 0x122
+#define R2057_W15G_BW_LNA5G_PUS_CORE1 0x123
+#define R2057_LNA5G_GAIN_CORE1 0x124
+#define R2057_LNA5G_TUNE_CORE1 0x125
+#define R2057_LPFSEL_TXRX_RXBB_PUS_CORE1 0x126
+#define R2057_RXBB_BIAS_MASTER_CORE1 0x127
+#define R2057_RXBB_VGABUF_IDACS_CORE1 0x128
+#define R2057_LPF_VCMREF_TXBUF_VCMREF_CORE1 0x129
+#define R2057_TXBUF_VINCM_CORE1 0x12a
+#define R2057_TXBUF_IDACS_CORE1 0x12b
+#define R2057_LPF_RESP_RXBUF_BW_CORE1 0x12c
+#define R2057_RXBB_CC_CORE1 0x12d
+#define R2057_RXBB_SPARE3_CORE1 0x12e
+#define R2057_RXBB_RCCAL_HPC_CORE1 0x12f
+#define R2057_LPF_IDACS_CORE1 0x130
+#define R2057_LPFBYP_DCLOOP_BYP_IDAC_CORE1 0x131
+#define R2057_TXBUF_GAIN_CORE1 0x132
+#define R2057_AFELOOPBACK_AACI_RESP_CORE1 0x133
+#define R2057_RXBUF_DEGEN_CORE1 0x134
+#define R2057_RXBB_SPARE2_CORE1 0x135
+#define R2057_RXBB_SPARE1_CORE1 0x136
+#define R2057_RSSI_MASTER_CORE1 0x137
+#define R2057_W2_MASTER_CORE1 0x138
+#define R2057_NB_MASTER_CORE1 0x139
+#define R2057_W2_IDACS0_Q_CORE1 0x13a
+#define R2057_W2_IDACS1_Q_CORE1 0x13b
+#define R2057_W2_IDACS0_I_CORE1 0x13c
+#define R2057_W2_IDACS1_I_CORE1 0x13d
+#define R2057_RSSI_GPAIOSEL_W1_IDACS_CORE1 0x13e
+#define R2057_NB_IDACS_Q_CORE1 0x13f
+#define R2057_NB_IDACS_I_CORE1 0x140
+#define R2057_BACKUP4_CORE1 0x146
+#define R2057_BACKUP3_CORE1 0x147
+#define R2057_BACKUP2_CORE1 0x148
+#define R2057_BACKUP1_CORE1 0x149
+#define R2057_SPARE16_CORE1 0x14a
+#define R2057_SPARE15_CORE1 0x14b
+#define R2057_SPARE14_CORE1 0x14c
+#define R2057_SPARE13_CORE1 0x14d
+#define R2057_SPARE12_CORE1 0x14e
+#define R2057_SPARE11_CORE1 0x14f
+#define R2057_TX2G_BIAS_RESETS_CORE1 0x150
+#define R2057_TX5G_BIAS_RESETS_CORE1 0x151
+#define R2057_SPARE8_CORE1 0x152
+#define R2057_SPARE7_CORE1 0x153
+#define R2057_BUFS_MISC_LPFBW_CORE1 0x154
+#define R2057_TXLPF_RCCAL_CORE1 0x155
+#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1 0x156
+#define R2057_LPF_GAIN_CORE1 0x157
+#define R2057_DACBUF_IDACS_BW_CORE1 0x158
+#define R2057_DACBUF_VINCM_CORE1 0x159
+#define R2057_RCCAL_START_R1_Q1_P1 0x15a
+#define R2057_RCCAL_X1 0x15b
+#define R2057_RCCAL_TRC0 0x15c
+#define R2057_RCCAL_TRC1 0x15d
+#define R2057_RCCAL_DONE_OSCCAP 0x15e
+#define R2057_RCCAL_N0_0 0x15f
+#define R2057_RCCAL_N0_1 0x160
+#define R2057_RCCAL_N1_0 0x161
+#define R2057_RCCAL_N1_1 0x162
+#define R2057_RCAL_STATUS 0x163
+#define R2057_XTALPUOVR_PINCTRL 0x164
+#define R2057_OVR_REG0 0x165
+#define R2057_OVR_REG1 0x166
+#define R2057_OVR_REG2 0x167
+#define R2057_OVR_REG3 0x168
+#define R2057_OVR_REG4 0x169
+#define R2057_RCCAL_SCAP_VAL 0x16a
+#define R2057_RCCAL_BCAP_VAL 0x16b
+#define R2057_RCCAL_HPC_VAL 0x16c
+#define R2057_RCCAL_OVERRIDES 0x16d
+#define R2057_TX0_IQCAL_GAIN_BW 0x170
+#define R2057_TX0_LOFT_FINE_I 0x171
+#define R2057_TX0_LOFT_FINE_Q 0x172
+#define R2057_TX0_LOFT_COARSE_I 0x173
+#define R2057_TX0_LOFT_COARSE_Q 0x174
+#define R2057_TX0_TX_SSI_MASTER 0x175
+#define R2057_TX0_IQCAL_VCM_HG 0x176
+#define R2057_TX0_IQCAL_IDAC 0x177
+#define R2057_TX0_TSSI_VCM 0x178
+#define R2057_TX0_TX_SSI_MUX 0x179
+#define R2057_TX0_TSSIA 0x17a
+#define R2057_TX0_TSSIG 0x17b
+#define R2057_TX0_TSSI_MISC1 0x17c
+#define R2057_TX0_TXRXCOUPLE_2G_ATTEN 0x17d
+#define R2057_TX0_TXRXCOUPLE_2G_PWRUP 0x17e
+#define R2057_TX0_TXRXCOUPLE_5G_ATTEN 0x17f
+#define R2057_TX0_TXRXCOUPLE_5G_PWRUP 0x180
+#define R2057_TX1_IQCAL_GAIN_BW 0x190
+#define R2057_TX1_LOFT_FINE_I 0x191
+#define R2057_TX1_LOFT_FINE_Q 0x192
+#define R2057_TX1_LOFT_COARSE_I 0x193
+#define R2057_TX1_LOFT_COARSE_Q 0x194
+#define R2057_TX1_TX_SSI_MASTER 0x195
+#define R2057_TX1_IQCAL_VCM_HG 0x196
+#define R2057_TX1_IQCAL_IDAC 0x197
+#define R2057_TX1_TSSI_VCM 0x198
+#define R2057_TX1_TX_SSI_MUX 0x199
+#define R2057_TX1_TSSIA 0x19a
+#define R2057_TX1_TSSIG 0x19b
+#define R2057_TX1_TSSI_MISC1 0x19c
+#define R2057_TX1_TXRXCOUPLE_2G_ATTEN 0x19d
+#define R2057_TX1_TXRXCOUPLE_2G_PWRUP 0x19e
+#define R2057_TX1_TXRXCOUPLE_5G_ATTEN 0x19f
+#define R2057_TX1_TXRXCOUPLE_5G_PWRUP 0x1a0
+#define R2057_AFE_VCM_CAL_MASTER_CORE0 0x1a1
+#define R2057_AFE_SET_VCM_I_CORE0 0x1a2
+#define R2057_AFE_SET_VCM_Q_CORE0 0x1a3
+#define R2057_AFE_STATUS_VCM_IQADC_CORE0 0x1a4
+#define R2057_AFE_STATUS_VCM_I_CORE0 0x1a5
+#define R2057_AFE_STATUS_VCM_Q_CORE0 0x1a6
+#define R2057_AFE_VCM_CAL_MASTER_CORE1 0x1a7
+#define R2057_AFE_SET_VCM_I_CORE1 0x1a8
+#define R2057_AFE_SET_VCM_Q_CORE1 0x1a9
+#define R2057_AFE_STATUS_VCM_IQADC_CORE1 0x1aa
+#define R2057_AFE_STATUS_VCM_I_CORE1 0x1ab
+#define R2057_AFE_STATUS_VCM_Q_CORE1 0x1ac
+
+#define R2057v7_DACBUF_VINCM_CORE0 0x1ad
+#define R2057v7_RCCAL_MASTER 0x1ae
+#define R2057v7_TR2G_CONFIG3_CORE0_NU 0x1af
+#define R2057v7_TR2G_CONFIG3_CORE1_NU 0x1b0
+#define R2057v7_LOGEN_PUS1 0x1b1
+#define R2057v7_OVR_REG5 0x1b2
+#define R2057v7_OVR_REG6 0x1b3
+#define R2057v7_OVR_REG7 0x1b4
+#define R2057v7_OVR_REG8 0x1b5
+#define R2057v7_OVR_REG9 0x1b6
+#define R2057v7_OVR_REG10 0x1b7
+#define R2057v7_OVR_REG11 0x1b8
+#define R2057v7_OVR_REG12 0x1b9
+#define R2057v7_OVR_REG13 0x1ba
+#define R2057v7_OVR_REG14 0x1bb
+#define R2057v7_OVR_REG15 0x1bc
+#define R2057v7_OVR_REG16 0x1bd
+#define R2057v7_OVR_REG1 0x1be
+#define R2057v7_OVR_REG18 0x1bf
+#define R2057v7_OVR_REG19 0x1c0
+#define R2057v7_OVR_REG20 0x1c1
+#define R2057v7_OVR_REG21 0x1c2
+#define R2057v7_OVR_REG2 0x1c3
+#define R2057v7_OVR_REG23 0x1c4
+#define R2057v7_OVR_REG24 0x1c5
+#define R2057v7_OVR_REG25 0x1c6
+#define R2057v7_OVR_REG26 0x1c7
+#define R2057v7_OVR_REG27 0x1c8
+#define R2057v7_OVR_REG28 0x1c9
+#define R2057v7_IQTEST_SEL_PU2 0x1ca
+
+#define R2057_VCM_MASK 0x7
+
+void r2057_upload_inittabs(struct b43_wldev *dev);
+
+#endif /* B43_RADIO_2057_H_ */
{ 0x00C0, 6, 0xE7, 0xF9, 0xEC, 0xFB } /* field == 0x4000 (fls 15) */
};
+/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
+static const struct nphy_rf_control_override_rev7
+ tbl_rf_control_override_rev7_over0[] = {
+ { 0x0004, 0x07A, 0x07D, 0x0002, 1 },
+ { 0x0008, 0x07A, 0x07D, 0x0004, 2 },
+ { 0x0010, 0x07A, 0x07D, 0x0010, 4 },
+ { 0x0020, 0x07A, 0x07D, 0x0020, 5 },
+ { 0x0040, 0x07A, 0x07D, 0x0040, 6 },
+ { 0x0080, 0x0F8, 0x0FA, 0x0080, 7 },
+ { 0x0400, 0x0F8, 0x0FA, 0x0070, 4 },
+ { 0x0800, 0x07B, 0x07E, 0xFFFF, 0 },
+ { 0x1000, 0x07C, 0x07F, 0xFFFF, 0 },
+ { 0x6000, 0x348, 0x349, 0xFFFF, 0 },
+ { 0x2000, 0x348, 0x349, 0x000F, 0 },
+};
+
+/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
+static const struct nphy_rf_control_override_rev7
+ tbl_rf_control_override_rev7_over1[] = {
+ { 0x0002, 0x340, 0x341, 0x0002, 1 },
+ { 0x0008, 0x340, 0x341, 0x0008, 3 },
+ { 0x0020, 0x340, 0x341, 0x0020, 5 },
+ { 0x0010, 0x340, 0x341, 0x0010, 4 },
+ { 0x0004, 0x340, 0x341, 0x0004, 2 },
+ { 0x0080, 0x340, 0x341, 0x0700, 8 },
+ { 0x0800, 0x340, 0x341, 0x4000, 14 },
+ { 0x0400, 0x340, 0x341, 0x2000, 13 },
+ { 0x0200, 0x340, 0x341, 0x0800, 12 },
+ { 0x0100, 0x340, 0x341, 0x0100, 11 },
+ { 0x0040, 0x340, 0x341, 0x0040, 6 },
+ { 0x0001, 0x340, 0x341, 0x0001, 0 },
+};
+
+/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
+static const struct nphy_rf_control_override_rev7
+ tbl_rf_control_override_rev7_over2[] = {
+ { 0x0008, 0x344, 0x345, 0x0008, 3 },
+ { 0x0002, 0x344, 0x345, 0x0002, 1 },
+ { 0x0001, 0x344, 0x345, 0x0001, 0 },
+ { 0x0004, 0x344, 0x345, 0x0004, 2 },
+ { 0x0010, 0x344, 0x345, 0x0010, 4 },
+};
+
struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
{ 10, 14, 19, 27 },
{ -5, 6, 10, 15 },
return e;
}
+
+const struct nphy_rf_control_override_rev7 *b43_nphy_get_rf_ctl_over_rev7(
+ struct b43_wldev *dev, u16 field, u8 override)
+{
+ const struct nphy_rf_control_override_rev7 *e;
+ u8 size, i;
+
+ switch (override) {
+ case 0:
+ e = tbl_rf_control_override_rev7_over0;
+ size = ARRAY_SIZE(tbl_rf_control_override_rev7_over0);
+ break;
+ case 1:
+ e = tbl_rf_control_override_rev7_over1;
+ size = ARRAY_SIZE(tbl_rf_control_override_rev7_over1);
+ break;
+ case 2:
+ e = tbl_rf_control_override_rev7_over2;
+ size = ARRAY_SIZE(tbl_rf_control_override_rev7_over2);
+ break;
+ default:
+ b43err(dev->wl, "Invalid override value %d\n", override);
+ return NULL;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (e[i].field == field)
+ return &e[i];
+ }
+
+ return NULL;
+}
u8 val_addr1;
};
+struct nphy_rf_control_override_rev7 {
+ u16 field;
+ u16 val_addr_core0;
+ u16 val_addr_core1;
+ u16 val_mask;
+ u8 val_shift;
+};
+
struct nphy_gain_ctl_workaround_entry {
s8 lna1_gain[4];
s8 lna2_gain[4];
tbl_rf_control_override_rev2[];
extern const struct nphy_rf_control_override_rev3
tbl_rf_control_override_rev3[];
+const struct nphy_rf_control_override_rev7 *b43_nphy_get_rf_ctl_over_rev7(
+ struct b43_wldev *dev, u16 field, u8 override);
#endif /* B43_TABLES_NPHY_H_ */
return 0;
ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
(ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
- & mask) | set);
+ & ~mask) | set);
return 0;
}
}
static void b43legacy_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
#define DMA_ALIGN_MASK 0x03
+#define SDIO_DEVICE_ID_BROADCOM_43241 0x4324
#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330
#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
+ {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len);
+extern int brcmf_netlink_dcmd(struct net_device *ndev, struct brcmf_dcmd *dcmd);
/* Return pointer to interface name */
extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
return err;
}
+int brcmf_netlink_dcmd(struct net_device *ndev, struct brcmf_dcmd *dcmd)
+{
+ brcmf_dbg(TRACE, "enter: cmd %x buf %p len %d\n",
+ dcmd->cmd, dcmd->buf, dcmd->len);
+
+ return brcmf_exec_dcmd(ndev, dcmd->cmd, dcmd->buf, dcmd->len);
+}
+
static int brcmf_netdev_stop(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
static bool brcmf_sdbrcm_chipmatch(u16 chipid)
{
+ if (chipid == BCM43241_CHIP_ID)
+ return true;
if (chipid == BCM4329_CHIP_ID)
return true;
if (chipid == BCM4330_CHIP_ID)
/* Address of cores for new chips should be added here */
switch (ci->chip) {
+ case BCM43241_CHIP_ID:
+ ci->c_inf[0].wrapbase = 0x18100000;
+ ci->c_inf[0].cib = 0x2a084411;
+ ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+ ci->c_inf[1].base = 0x18002000;
+ ci->c_inf[1].wrapbase = 0x18102000;
+ ci->c_inf[1].cib = 0x0e004211;
+ ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+ ci->c_inf[2].base = 0x18004000;
+ ci->c_inf[2].wrapbase = 0x18104000;
+ ci->c_inf[2].cib = 0x14080401;
+ ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+ ci->c_inf[3].base = 0x18003000;
+ ci->c_inf[3].wrapbase = 0x18103000;
+ ci->c_inf[3].cib = 0x07004211;
+ ci->ramsize = 0x90000;
+ break;
case BCM4329_CHIP_ID:
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
#define BRCMF_USB_CBCTL_READ 1
#define BRCMF_USB_MAX_PKT_SIZE 1600
+#define BRCMF_USB_43143_FW_NAME "brcm/brcmfmac43143.bin"
#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin"
+#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin"
enum usbdev_suspend_state {
USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow
if (test_and_set_bit(0, &devinfo->ctl_op))
return -EIO;
+ devinfo->ctl_completed = false;
err = brcmf_usb_send_ctl(devinfo, buf, len);
if (err) {
brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
return err;
}
- devinfo->ctl_completed = false;
timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
&pending);
clear_bit(0, &devinfo->ctl_op);
static bool brcmf_usb_chip_support(int chipid, int chiprev)
{
switch(chipid) {
+ case 43143:
+ return true;
case 43235:
case 43236:
case 43238:
return (chiprev == 3);
+ case 43242:
+ return true;
default:
break;
}
if (devinfo->image)
return 0;
- fwname = BRCMF_USB_43236_FW_NAME;
+ switch (devinfo->bus_pub.devid) {
+ case 43143:
+ fwname = BRCMF_USB_43143_FW_NAME;
+ break;
+ case 43235:
+ case 43236:
+ case 43238:
+ fwname = BRCMF_USB_43236_FW_NAME;
+ break;
+ case 43242:
+ fwname = BRCMF_USB_43242_FW_NAME;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
err = request_firmware(&fw, fwname, devinfo->dev);
if (!fw) {
}
#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c
+#define BRCMF_USB_DEVICE_ID_43143 0xbd1e
#define BRCMF_USB_DEVICE_ID_43236 0xbd17
+#define BRCMF_USB_DEVICE_ID_43242 0xbd1f
#define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc
static struct usb_device_id brcmf_usb_devid_table[] = {
+ { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43143) },
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) },
+ { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43242) },
/* special entry for device with firmware loaded and running */
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
{ }
};
MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
+MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
+MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME);
/* TODO: suspend and resume entries */
static struct usb_driver brcmf_usbdrvr = {
#include <linux/ieee80211.h>
#include <linux/uaccess.h>
#include <net/cfg80211.h>
+#include <net/netlink.h>
#include <brcmu_utils.h>
#include <defs.h>
}
+#ifdef CONFIG_NL80211_TESTMODE
+static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_priv->wdev->netdev;
+ struct brcmf_dcmd *dcmd = data;
+ struct sk_buff *reply;
+ int ret;
+
+ ret = brcmf_netlink_dcmd(ndev, dcmd);
+ if (ret == 0) {
+ reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
+ nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
+ ret = cfg80211_testmode_reply(reply);
+ }
+ return ret;
+}
+#endif
+
static struct cfg80211_ops wl_cfg80211_ops = {
.change_virtual_intf = brcmf_cfg80211_change_iface,
.scan = brcmf_cfg80211_scan,
.resume = brcmf_cfg80211_resume,
.set_pmksa = brcmf_cfg80211_set_pmksa,
.del_pmksa = brcmf_cfg80211_del_pmksa,
- .flush_pmksa = brcmf_cfg80211_flush_pmksa
+ .flush_pmksa = brcmf_cfg80211_flush_pmksa,
+#ifdef CONFIG_NL80211_TESTMODE
+ .testmode_cmd = brcmf_cfg80211_testmode
+#endif
};
static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");
-
+/* This needs to be adjusted when brcms_firmwares changes */
+MODULE_FIRMWARE("brcm/bcm43xx-0.fw");
+MODULE_FIRMWARE("brcm/bcm43xx_hdr-0.fw");
/* recognized BCMA Core IDs */
static struct bcma_device_id brcms_coreid_table[] = {
}
}
-static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void brcms_ops_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct brcms_info *wl = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
goto done;
}
brcms_c_sendpkt_mac80211(wl->wlc, skb, hw);
- tx_info->rate_driver_data[0] = tx_info->control.sta;
+ tx_info->rate_driver_data[0] = control->sta;
done:
spin_unlock_bh(&wl->lock);
}
channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
- if (channel > 14) {
- rx_status->band = IEEE80211_BAND_5GHZ;
- rx_status->freq = ieee80211_ofdm_chan_to_freq(
- WF_CHAN_FACTOR_5_G/2, channel);
-
- } else {
- rx_status->band = IEEE80211_BAND_2GHZ;
- rx_status->freq = ieee80211_dsss_chan_to_freq(channel);
- }
+ rx_status->band =
+ channel > 14 ? IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+ rx_status->freq =
+ ieee80211_channel_to_frequency(channel, rx_status->band);
rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);
#define BCM43235_CHIP_ID 43235
#define BCM43236_CHIP_ID 43236
#define BCM43238_CHIP_ID 43238
+#define BCM43241_CHIP_ID 0x4324
#define BCM4329_CHIP_ID 0x4329
#define BCM4330_CHIP_ID 0x4330
#define BCM4331_CHIP_ID 0x4331
#define WL_CHANSPEC_BAND_2G 0x2000
#define INVCHANSPEC 255
-/* used to calculate the chan_freq = chan_factor * 500Mhz + 5 * chan_number */
-#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */
-#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
-#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
-
#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/etherdevice.h>
#include "hostap_wlan.h"
#include "hostap.h"
#include "hostap_ap.h"
prism2_host_roaming(local);
if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
- memcmp(local->preferred_ap, "\x00\x00\x00\x00\x00\x00",
- ETH_ALEN) != 0) {
+ !is_zero_ether_addr(local->preferred_ap)) {
/*
* Firmware seems to be getting into odd state in host_roaming
* mode 2 when hostscan is used without join command, so try
#include <linux/ethtool.h>
#include <linux/if_arp.h>
#include <linux/module.h>
+#include <linux/etherdevice.h>
#include <net/lib80211.h>
#include "hostap_wlan.h"
return -EINVAL;
addr = ext->addr.sa_data;
- if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
- addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+ if (is_broadcast_ether_addr(addr)) {
sta_ptr = NULL;
crypt = &local->crypt_info.crypt[i];
} else {
i--;
addr = ext->addr.sa_data;
- if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
- addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+ if (is_broadcast_ether_addr(addr)) {
sta_ptr = NULL;
crypt = &local->crypt_info.crypt[i];
} else {
param->u.crypt.key_len)
return -EINVAL;
- if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
- param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
- param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (is_broadcast_ether_addr(param->sta_addr)) {
if (param->u.crypt.idx >= WEP_KEYS)
return -EINVAL;
sta_ptr = NULL;
if (max_key_len < 0)
return -EINVAL;
- if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
- param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
- param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (is_broadcast_ether_addr(param->sta_addr)) {
sta_ptr = NULL;
if (param->u.crypt.idx >= WEP_KEYS)
param->u.crypt.idx = local->crypt_info.tx_keyidx;
__le16 val = cpu_to_le16(reason);
if (local->iw_mode != IW_MODE_INFRA ||
- memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 ||
+ is_zero_ether_addr(local->bssid) ||
memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0)
return 0;
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
- static const unsigned char any[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- static const unsigned char off[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
// sanity checks
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
return -EINVAL;
goto done;
}
- if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
- !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+ if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
+ is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
/* we disable mandatory BSSID association */
IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
priv->config &= ~CFG_STATIC_BSSID;
{
struct ipw_priv *priv = libipw_priv(dev);
- static const unsigned char any[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- static const unsigned char off[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
return -EINVAL;
mutex_lock(&priv->mutex);
- if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
- !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+ if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
+ is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
/* we disable mandatory BSSID association */
IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
priv->config &= ~CFG_STATIC_BSSID;
* start C_TX command process
*/
static int
-il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
+il3945_tx_skb(struct il_priv *il,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr_len = ieee80211_hdrlen(fc);
/* Find idx into station table for destination station */
- sta_id = il_sta_id_or_broadcast(il, info->control.sta);
+ sta_id = il_sta_id_or_broadcast(il, sta);
if (sta_id == IL_INVALID_STATION) {
D_DROP("Dropping - INVALID STATION: %pM\n", hdr->addr1);
goto drop;
}
static void
-il3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+il3945_mac_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct il_priv *il = hw->priv;
D_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
- if (il3945_tx_skb(il, skb))
+ if (il3945_tx_skb(il, control->sta, skb))
dev_kfree_skb_any(skb);
D_MAC80211("leave\n");
}
static void
-il4965_tx_cmd_build_rate(struct il_priv *il, struct il_tx_cmd *tx_cmd,
- struct ieee80211_tx_info *info, __le16 fc)
+il4965_tx_cmd_build_rate(struct il_priv *il,
+ struct il_tx_cmd *tx_cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ __le16 fc)
{
const u8 rts_retry_limit = 60;
u32 rate_flags;
rate_idx = info->control.rates[0].idx;
if ((info->control.rates[0].flags & IEEE80211_TX_RC_MCS) || rate_idx < 0
|| rate_idx > RATE_COUNT_LEGACY)
- rate_idx =
- rate_lowest_index(&il->bands[info->band],
- info->control.sta);
+ rate_idx = rate_lowest_index(&il->bands[info->band], sta);
/* For 5 GHZ band, remap mac80211 rate indices into driver indices */
if (info->band == IEEE80211_BAND_5GHZ)
rate_idx += IL_FIRST_OFDM_RATE;
* start C_TX command process
*/
int
-il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
+il4965_tx_skb(struct il_priv *il,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = info->control.sta;
struct il_station_priv *sta_priv = NULL;
struct il_tx_queue *txq;
struct il_queue *q;
sta_id = il->hw_params.bcast_id;
else {
/* Find idx into station table for destination station */
- sta_id = il_sta_id_or_broadcast(il, info->control.sta);
+ sta_id = il_sta_id_or_broadcast(il, sta);
if (sta_id == IL_INVALID_STATION) {
D_DROP("Dropping - INVALID STATION: %pM\n", hdr->addr1);
/* TODO need this for burst mode later on */
il4965_tx_cmd_build_basic(il, skb, tx_cmd, info, hdr, sta_id);
- il4965_tx_cmd_build_rate(il, tx_cmd, info, fc);
+ il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc);
il_update_stats(il, true, fc, len);
/*
}
void
-il4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+il4965_mac_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct il_priv *il = hw->priv;
D_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
- if (il4965_tx_skb(il, skb))
+ if (il4965_tx_skb(il, control->sta, skb))
dev_kfree_skb_any(skb);
D_MACDUMP("leave\n");
int il4965_hw_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq);
void il4965_hwrate_to_tx_control(struct il_priv *il, u32 rate_n_flags,
struct ieee80211_tx_info *info);
-int il4965_tx_skb(struct il_priv *il, struct sk_buff *skb);
+int il4965_tx_skb(struct il_priv *il,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb);
int il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 * ssn);
int il4965_tx_agg_stop(struct il_priv *il, struct ieee80211_vif *vif,
int il4965_eeprom_check_version(struct il_priv *il);
/* mac80211 handlers (for 4965) */
-void il4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+void il4965_mac_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
int il4965_mac_start(struct ieee80211_hw *hw);
void il4965_mac_stop(struct ieee80211_hw *hw);
void il4965_configure_filter(struct ieee80211_hw *hw,
#ifdef CONFIG_PM
-int
+static int
il_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
return 0;
}
-EXPORT_SYMBOL(il_pci_suspend);
-int
+static int
il_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
return 0;
}
-EXPORT_SYMBOL(il_pci_resume);
-const struct dev_pm_ops il_pm_ops = {
- .suspend = il_pci_suspend,
- .resume = il_pci_resume,
- .freeze = il_pci_suspend,
- .thaw = il_pci_resume,
- .poweroff = il_pci_suspend,
- .restore = il_pci_resume,
-};
+SIMPLE_DEV_PM_OPS(il_pm_ops, il_pci_suspend, il_pci_resume);
EXPORT_SYMBOL(il_pm_ops);
#endif /* CONFIG_PM */
u32 beacon_interval);
#ifdef CONFIG_PM
-int il_pci_suspend(struct device *device);
-int il_pci_resume(struct device *device);
extern const struct dev_pm_ops il_pm_ops;
#define IL_LEGACY_PM_OPS (&il_pm_ops)
/* tx */
-int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
+int iwlagn_tx_skb(struct iwl_priv *priv,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb);
int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
-void iwl_dbgfs_unregister(struct iwl_priv *priv);
+int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir);
#else
-static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
+static inline int iwl_dbgfs_register(struct iwl_priv *priv,
+ struct dentry *dbgfs_dir)
{
return 0;
}
-static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
-{
-}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
#ifdef CONFIG_IWLWIFI_DEBUG
#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1)
#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2)
#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK 0xf0
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK 0x70
#define RX_RES_PHY_FLAGS_ANTENNA_POS 4
+#define RX_RES_PHY_FLAGS_AGG_MSK cpu_to_le16(1 << 7)
#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
* Create the debugfs files and directories
*
*/
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
+int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir)
{
- struct dentry *phyd = priv->hw->wiphy->debugfsdir;
- struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
+ struct dentry *dir_data, *dir_rf, *dir_debug;
- dir_drv = debugfs_create_dir(name, phyd);
- if (!dir_drv)
- return -ENOMEM;
-
- priv->debugfs_dir = dir_drv;
+ priv->debugfs_dir = dbgfs_dir;
- dir_data = debugfs_create_dir("data", dir_drv);
+ dir_data = debugfs_create_dir("data", dbgfs_dir);
if (!dir_data)
goto err;
- dir_rf = debugfs_create_dir("rf", dir_drv);
+ dir_rf = debugfs_create_dir("rf", dbgfs_dir);
if (!dir_rf)
goto err;
- dir_debug = debugfs_create_dir("debug", dir_drv);
+ dir_debug = debugfs_create_dir("debug", dbgfs_dir);
if (!dir_debug)
goto err;
/* Calibrations disabled/enabled status*/
DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR);
- if (iwl_trans_dbgfs_register(priv->trans, dir_debug))
- goto err;
+ /*
+ * Create a symlink with mac80211. This is not very robust, as it does
+ * not remove the symlink created. The implicit assumption is that
+ * when the opmode exits, mac80211 will also exit, and will remove
+ * this symlink as part of its cleanup.
+ */
+ if (priv->mac80211_registered) {
+ char buf[100];
+ struct dentry *mac80211_dir, *dev_dir, *root_dir;
+
+ dev_dir = dbgfs_dir->d_parent;
+ root_dir = dev_dir->d_parent;
+ mac80211_dir = priv->hw->wiphy->debugfsdir;
+
+ snprintf(buf, 100, "../../%s/%s", root_dir->d_name.name,
+ dev_dir->d_name.name);
+
+ if (!debugfs_create_symlink("iwlwifi", mac80211_dir, buf))
+ goto err;
+ }
+
return 0;
err:
- IWL_ERR(priv, "Can't create the debugfs directory\n");
- iwl_dbgfs_unregister(priv);
+ IWL_ERR(priv, "failed to create the dvm debugfs entries\n");
return -ENOMEM;
}
-
-/**
- * Remove the debugfs files and directories
- *
- */
-void iwl_dbgfs_unregister(struct iwl_priv *priv)
-{
- if (!priv->debugfs_dir)
- return;
-
- debugfs_remove_recursive(priv->debugfs_dir);
- priv->debugfs_dir = NULL;
-}
u8 agg_tids_count;
struct iwl_rx_phy_res last_phy_res;
+ u32 ampdu_ref;
bool last_phy_res_valid;
/*
ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
}
- hw->wiphy->max_remain_on_channel_duration = 1000;
+ hw->wiphy->max_remain_on_channel_duration = 500;
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS |
}
#endif
-static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void iwlagn_mac_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
- if (iwlagn_tx_skb(priv, skb))
+ if (iwlagn_tx_skb(priv, control->sta, skb))
dev_kfree_skb_any(skb);
}
* No race since we hold the mutex here and a new one
* can't come in at this time.
*/
- ieee80211_remain_on_channel_expired(priv->hw);
+ if (priv->ucode_loaded && priv->cur_ucode != IWL_UCODE_INIT)
+ ieee80211_remain_on_channel_expired(priv->hw);
exit_pending =
test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
iwlagn_prepare_restart(priv);
mutex_unlock(&priv->mutex);
iwl_cancel_deferred_work(priv);
- ieee80211_restart_hw(priv->hw);
+ if (priv->mac80211_registered)
+ ieee80211_restart_hw(priv->hw);
+ else
+ IWL_ERR(priv,
+ "Cannot request restart before registrating with mac80211");
} else {
WARN_ON(1);
}
static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
- const struct iwl_fw *fw)
+ const struct iwl_fw *fw,
+ struct dentry *dbgfs_dir)
{
struct iwl_priv *priv;
struct ieee80211_hw *hw;
if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
goto out_destroy_workqueue;
- if (iwl_dbgfs_register(priv, DRV_NAME))
- IWL_ERR(priv,
- "failed to create debugfs files. Ignoring error\n");
+ if (iwl_dbgfs_register(priv, dbgfs_dir))
+ goto out_mac80211_unregister;
return op_mode;
+out_mac80211_unregister:
+ iwlagn_mac_unregister(priv);
out_destroy_workqueue:
+ iwl_tt_exit(priv);
+ iwl_testmode_free(priv);
+ iwl_cancel_deferred_work(priv);
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
iwl_uninit_drv(priv);
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
- iwl_dbgfs_unregister(priv);
-
iwl_testmode_free(priv);
iwlagn_mac_unregister(priv);
struct iwl_rx_packet *pkt = rxb_addr(rxb);
priv->last_phy_res_valid = true;
+ priv->ampdu_ref++;
memcpy(&priv->last_phy_res, pkt->data,
sizeof(struct iwl_rx_phy_res));
return 0;
if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
rx_status.flag |= RX_FLAG_SHORTPRE;
+ if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) {
+ /*
+ * We know which subframes of an A-MPDU belong
+ * together since we get a single PHY response
+ * from the firmware for all of them
+ */
+ rx_status.flag |= RX_FLAG_AMPDU_DETAILS;
+ rx_status.ampdu_reference = priv->ampdu_ref;
+ }
+
/* Set up the HT phy flags */
if (rate_n_flags & RATE_MCS_HT_MSK)
rx_status.flag |= RX_FLAG_HT;
sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
if (!(flags & CMD_ASYNC)) {
- cmd.flags |= CMD_WANT_SKB;
+ cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD;
might_sleep();
}
static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
struct iwl_tx_cmd *tx_cmd,
struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
__le16 fc)
{
u32 rate_flags;
if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
rate_idx = rate_lowest_index(
- &priv->eeprom_data->bands[info->band],
- info->control.sta);
+ &priv->eeprom_data->bands[info->band], sta);
/* For 5 GHZ band, remap mac80211 rate indices into driver indices */
if (info->band == IEEE80211_BAND_5GHZ)
rate_idx += IWL_FIRST_OFDM_RATE;
/*
* start REPLY_TX command process
*/
-int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
+int iwlagn_tx_skb(struct iwl_priv *priv,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
sta_id = ctx->bcast_sta_id;
else {
/* Find index into station table for destination station */
- sta_id = iwl_sta_id_or_broadcast(ctx, info->control.sta);
+ sta_id = iwl_sta_id_or_broadcast(ctx, sta);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
- if (info->control.sta)
- sta_priv = (void *)info->control.sta->drv_priv;
+ if (sta)
+ sta_priv = (void *)sta->drv_priv;
if (sta_priv && sta_priv->asleep &&
(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
/* TODO need this for burst mode later on */
iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
- iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
+ iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, sta, fc);
memset(&info->status, 0, sizeof(info->status));
* only. Check this here.
*/
if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON &&
- tid_data->agg.state != IWL_AGG_OFF,
+ tid_data->agg.state != IWL_AGG_OFF,
"Tx while agg.state = %d", tid_data->agg.state))
goto drop_unlock_sta;
#include <linux/tracepoint.h>
#include <linux/device.h>
+#include "iwl-trans.h"
#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
#define TRACE_SYSTEM iwlwifi
TRACE_EVENT(iwlwifi_dev_hcmd,
- TP_PROTO(const struct device *dev, u32 flags,
- const void *hcmd0, size_t len0,
- const void *hcmd1, size_t len1,
- const void *hcmd2, size_t len2),
- TP_ARGS(dev, flags, hcmd0, len0, hcmd1, len1, hcmd2, len2),
+ TP_PROTO(const struct device *dev,
+ struct iwl_host_cmd *cmd, u16 total_size,
+ const void *hdr, size_t hdr_len),
+ TP_ARGS(dev, cmd, total_size, hdr, hdr_len),
TP_STRUCT__entry(
DEV_ENTRY
- __dynamic_array(u8, hcmd0, len0)
- __dynamic_array(u8, hcmd1, len1)
- __dynamic_array(u8, hcmd2, len2)
+ __dynamic_array(u8, hcmd, total_size)
__field(u32, flags)
),
TP_fast_assign(
+ int i, offset = hdr_len;
+
DEV_ASSIGN;
- memcpy(__get_dynamic_array(hcmd0), hcmd0, len0);
- memcpy(__get_dynamic_array(hcmd1), hcmd1, len1);
- memcpy(__get_dynamic_array(hcmd2), hcmd2, len2);
- __entry->flags = flags;
+ __entry->flags = cmd->flags;
+ memcpy(__get_dynamic_array(hcmd), hdr, hdr_len);
+
+ for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+ if (!cmd->len[i])
+ continue;
+ if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
+ continue;
+ memcpy((u8 *)__get_dynamic_array(hcmd) + offset,
+ cmd->data[i], cmd->len[i]);
+ offset += cmd->len[i];
+ }
),
TP_printk("[%s] hcmd %#.2x (%ssync)",
- __get_str(dev), ((u8 *)__get_dynamic_array(hcmd0))[0],
+ __get_str(dev), ((u8 *)__get_dynamic_array(hcmd))[0],
__entry->flags & CMD_ASYNC ? "a" : "")
);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+static struct dentry *iwl_dbgfs_root;
+#endif
+
/**
* struct iwl_drv - drv common data
* @list: list of drv structures using this opmode
char firmware_name[25]; /* name of firmware file to load */
struct completion request_firmware_complete;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ struct dentry *dbgfs_drv;
+ struct dentry *dbgfs_trans;
+ struct dentry *dbgfs_op_mode;
+#endif
};
#define DVM_OP_MODE 0
return 0;
}
-static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
+static void iwl_req_fw_callback(const struct firmware *ucode_raw,
+ void *context);
#define UCODE_EXPERIMENTAL_INDEX 100
#define UCODE_EXPERIMENTAL_TAG "exp"
return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name,
drv->trans->dev,
- GFP_KERNEL, drv, iwl_ucode_callback);
+ GFP_KERNEL, drv, iwl_req_fw_callback);
}
struct fw_img_parsing {
return 0;
}
+static struct iwl_op_mode *
+_iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
+{
+ const struct iwl_op_mode_ops *ops = op->ops;
+ struct dentry *dbgfs_dir = NULL;
+ struct iwl_op_mode *op_mode = NULL;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ drv->dbgfs_op_mode = debugfs_create_dir(op->name,
+ drv->dbgfs_drv);
+ if (!drv->dbgfs_op_mode) {
+ IWL_ERR(drv,
+ "failed to create opmode debugfs directory\n");
+ return op_mode;
+ }
+ dbgfs_dir = drv->dbgfs_op_mode;
+#endif
+
+ op_mode = ops->start(drv->trans, drv->cfg, &drv->fw, dbgfs_dir);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (!op_mode) {
+ debugfs_remove_recursive(drv->dbgfs_op_mode);
+ drv->dbgfs_op_mode = NULL;
+ }
+#endif
+
+ return op_mode;
+}
+
+static void _iwl_op_mode_stop(struct iwl_drv *drv)
+{
+ /* op_mode can be NULL if its start failed */
+ if (drv->op_mode) {
+ iwl_op_mode_stop(drv->op_mode);
+ drv->op_mode = NULL;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ debugfs_remove_recursive(drv->dbgfs_op_mode);
+ drv->dbgfs_op_mode = NULL;
+#endif
+ }
+}
+
/**
- * iwl_ucode_callback - callback when firmware was loaded
+ * iwl_req_fw_callback - callback when firmware was loaded
*
* If loaded successfully, copies the firmware into buffers
* for the card to fetch (via DMA).
*/
-static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
+static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
{
struct iwl_drv *drv = context;
struct iwl_fw *fw = &drv->fw;
list_add_tail(&drv->list, &op->drv);
if (op->ops) {
- const struct iwl_op_mode_ops *ops = op->ops;
- drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
+ drv->op_mode = _iwl_op_mode_start(drv, op);
if (!drv->op_mode) {
mutex_unlock(&iwlwifi_opmode_table_mtx);
init_completion(&drv->request_firmware_complete);
INIT_LIST_HEAD(&drv->list);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ /* Create the device debugfs entries. */
+ drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev),
+ iwl_dbgfs_root);
+
+ if (!drv->dbgfs_drv) {
+ IWL_ERR(drv, "failed to create debugfs directory\n");
+ goto err_free_drv;
+ }
+
+ /* Create transport layer debugfs dir */
+ drv->trans->dbgfs_dir = debugfs_create_dir("trans", drv->dbgfs_drv);
+
+ if (!drv->trans->dbgfs_dir) {
+ IWL_ERR(drv, "failed to create transport debugfs directory\n");
+ goto err_free_dbgfs;
+ }
+#endif
+
ret = iwl_request_firmware(drv, true);
if (ret) {
IWL_ERR(trans, "Couldn't request the fw\n");
- kfree(drv);
- drv = NULL;
+ goto err_fw;
}
+ return drv;
+
+err_fw:
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+err_free_dbgfs:
+ debugfs_remove_recursive(drv->dbgfs_drv);
+err_free_drv:
+#endif
+ kfree(drv);
+ drv = NULL;
+
return drv;
}
{
wait_for_completion(&drv->request_firmware_complete);
- /* op_mode can be NULL if its start failed */
- if (drv->op_mode)
- iwl_op_mode_stop(drv->op_mode);
+ _iwl_op_mode_stop(drv);
iwl_dealloc_ucode(drv);
list_del(&drv->list);
mutex_unlock(&iwlwifi_opmode_table_mtx);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ debugfs_remove_recursive(drv->dbgfs_drv);
+#endif
+
kfree(drv);
}
{
int i;
struct iwl_drv *drv;
+ struct iwlwifi_opmode_table *op;
mutex_lock(&iwlwifi_opmode_table_mtx);
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
- if (strcmp(iwlwifi_opmode_table[i].name, name))
+ op = &iwlwifi_opmode_table[i];
+ if (strcmp(op->name, name))
continue;
- iwlwifi_opmode_table[i].ops = ops;
- list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
- drv->op_mode = ops->start(drv->trans, drv->cfg,
- &drv->fw);
+ op->ops = ops;
+ /* TODO: need to handle exceptional case */
+ list_for_each_entry(drv, &op->drv, list)
+ drv->op_mode = _iwl_op_mode_start(drv, op);
+
mutex_unlock(&iwlwifi_opmode_table_mtx);
return 0;
}
iwlwifi_opmode_table[i].ops = NULL;
/* call the stop routine for all devices */
- list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) {
- if (drv->op_mode) {
- iwl_op_mode_stop(drv->op_mode);
- drv->op_mode = NULL;
- }
- }
+ list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
+ _iwl_op_mode_stop(drv);
+
mutex_unlock(&iwlwifi_opmode_table_mtx);
return;
}
pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
pr_info(DRV_COPYRIGHT "\n");
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ /* Create the root of iwlwifi debugfs subsystem. */
+ iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL);
+
+ if (!iwl_dbgfs_root)
+ return -EFAULT;
+#endif
+
return iwl_pci_register_driver();
}
module_init(iwl_drv_init);
static void __exit iwl_drv_exit(void)
{
iwl_pci_unregister_driver();
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ debugfs_remove_recursive(iwl_dbgfs_root);
+#endif
}
module_exit(iwl_drv_exit);
* 4) The bus specific component configures the bus
* 5) The bus specific component calls to the drv bus agnostic part
* (iwl_drv_start)
- * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback
- * 7) iwl_ucode_callback parses the fw file
- * 8) iwl_ucode_callback starts the wifi implementation to matches the fw
+ * 6) iwl_drv_start fetches the fw ASYNC, iwl_req_fw_callback
+ * 7) iwl_req_fw_callback parses the fw file
+ * 8) iwl_req_fw_callback starts the wifi implementation to matches the fw
*/
struct iwl_drv;
int n_hw_addrs;
u8 hw_addr[ETH_ALEN];
- u16 radio_config;
-
u8 calib_version;
__le16 calib_voltage;
struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
- const struct iwl_fw *fw);
+ const struct iwl_fw *fw,
+ struct dentry *dbgfs_dir);
void (*stop)(struct iwl_op_mode *op_mode);
int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
* @CMD_SYNC: The caller will be stalled until the fw responds to the command
* @CMD_ASYNC: Return right away and don't want for the response
* @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
- * response.
+ * response. The caller needs to call iwl_free_resp when done.
+ * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the
+ * response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be
+ * copied. The pointer passed to the response handler is in the transport
+ * ownership and don't need to be freed by the op_mode. This also means
+ * that the pointer is invalidated after the op_mode's handler returns.
* @CMD_ON_DEMAND: This command is sent by the test mode pipe.
*/
enum CMD_MODE {
CMD_SYNC = 0,
CMD_ASYNC = BIT(0),
CMD_WANT_SKB = BIT(1),
- CMD_ON_DEMAND = BIT(2),
+ CMD_WANT_HCMD = BIT(2),
+ CMD_ON_DEMAND = BIT(3),
};
#define DEF_CMD_PAYLOAD_SIZE 320
size_t dev_cmd_headroom;
char dev_cmd_pool_name[50];
+ struct dentry *dbgfs_dir;
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *));
if (!trans_pcie->drv)
goto out_free_trans;
+ /* register transport layer debugfs here */
+ if (iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir))
+ goto out_free_drv;
+
return 0;
+out_free_drv:
+ iwl_drv_stop(trans_pcie->drv);
out_free_trans:
iwl_trans_pcie_free(iwl_trans);
pci_set_drvdata(pdev, NULL);
struct iwl_pcie_tx_queue_entry {
struct iwl_device_cmd *cmd;
+ struct iwl_device_cmd *copy_cmd;
struct sk_buff *skb;
struct iwl_cmd_meta meta;
};
index = SEQ_TO_INDEX(sequence);
cmd_index = get_cmd_index(&txq->q, index);
- if (reclaim)
- cmd = txq->entries[cmd_index].cmd;
- else
+ if (reclaim) {
+ struct iwl_pcie_tx_queue_entry *ent;
+ ent = &txq->entries[cmd_index];
+ cmd = ent->copy_cmd;
+ WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD);
+ } else {
cmd = NULL;
+ }
err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
+ if (reclaim) {
+ /* The original command isn't needed any more */
+ kfree(txq->entries[cmd_index].copy_cmd);
+ txq->entries[cmd_index].copy_cmd = NULL;
+ }
+
/*
* After here, we should always check rxcb._page_stolen,
* if it is true then one of the handlers took the page.
iwl_tx_queue_unmap(trans, txq_id);
/* De-alloc array of command/tx buffers */
-
if (txq_id == trans_pcie->cmd_queue)
- for (i = 0; i < txq->q.n_window; i++)
+ for (i = 0; i < txq->q.n_window; i++) {
kfree(txq->entries[i].cmd);
+ kfree(txq->entries[i].copy_cmd);
+ }
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd) {
static int iwl_prepare_card_hw(struct iwl_trans *trans)
{
int ret;
+ int t = 0;
IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE);
- ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
- ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+ do {
+ ret = iwl_set_hw_ready(trans);
+ if (ret >= 0)
+ return 0;
- if (ret < 0)
- return ret;
+ usleep_range(200, 1000);
+ t += 200;
+ } while (t < 150000);
- /* HW should be ready by now, check again. */
- ret = iwl_set_hw_ready(trans);
- if (ret >= 0)
- return 0;
return ret;
}
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, trans, \
&iwl_dbgfs_##name##_ops)) \
- return -ENOMEM; \
+ goto err; \
} while (0)
/* file operation */
DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
return 0;
+
+err:
+ IWL_ERR(trans, "failed to create the trans debugfs entry\n");
+ return -ENOMEM;
}
#else
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
u16 copy_size, cmd_size;
bool had_nocopy = false;
int i;
- u8 *cmd_dest;
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
- const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
- int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
- int trace_idx;
-#endif
+ u32 cmd_pos;
copy_size = sizeof(out_cmd->hdr);
cmd_size = sizeof(out_cmd->hdr);
INDEX_TO_SEQ(q->write_ptr));
/* and copy the data that needs to be copied */
-
- cmd_dest = out_cmd->payload;
+ cmd_pos = offsetof(struct iwl_device_cmd, payload);
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
if (!cmd->len[i])
continue;
if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
break;
- memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
- cmd_dest += cmd->len[i];
+ memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);
+ cmd_pos += cmd->len[i];
+ }
+
+ WARN_ON_ONCE(txq->entries[idx].copy_cmd);
+
+ /*
+ * since out_cmd will be the source address of the FH, it will write
+ * the retry count there. So when the user needs to receivce the HCMD
+ * that corresponds to the response in the response handler, it needs
+ * to set CMD_WANT_HCMD.
+ */
+ if (cmd->flags & CMD_WANT_HCMD) {
+ txq->entries[idx].copy_cmd =
+ kmemdup(out_cmd, cmd_pos, GFP_ATOMIC);
+ if (unlikely(!txq->entries[idx].copy_cmd)) {
+ idx = -ENOMEM;
+ goto out;
+ }
}
IWL_DEBUG_HC(trans,
dma_unmap_len_set(out_meta, len, copy_size);
iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, copy_size, 1);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
- trace_bufs[0] = &out_cmd->hdr;
- trace_lens[0] = copy_size;
- trace_idx = 1;
-#endif
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
if (!cmd->len[i])
iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
cmd->len[i], 0);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
- trace_bufs[trace_idx] = cmd->data[i];
- trace_lens[trace_idx] = cmd->len[i];
- trace_idx++;
-#endif
}
out_meta->flags = cmd->flags;
txq->need_update = 1;
- /* check that tracing gets all possible blocks */
- BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
- trace_iwlwifi_dev_hcmd(trans->dev, cmd->flags,
- trace_bufs[0], trace_lens[0],
- trace_bufs[1], trace_lens[1],
- trace_bufs[2], trace_lens[2]);
-#endif
+ trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size,
+ &out_cmd->hdr, copy_size);
/* start timer if queue currently empty */
if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
lbtf_deb_leave(LBTF_DEB_MAIN);
}
-static void lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void lbtf_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct lbtf_private *priv = hw->priv;
return ack;
}
-static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
bool ack;
struct ieee80211_tx_info *txi;
#endif
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) },
+ { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
};
static const struct ieee80211_iface_combination hwsim_if_comb = {
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT);
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM |
return count;
}
+
+/*
+ * This function retrieves the entry for specific tx BA stream table by RA and
+ * deletes it.
+ */
+void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
+{
+ struct mwifiex_tx_ba_stream_tbl *tbl, *tmp;
+ unsigned long flags;
+
+ if (!ra)
+ return;
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) {
+ if (!memcmp(tbl->ra, ra, ETH_ALEN)) {
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
+ flags);
+ mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl);
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+ return;
+}
int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
int cmd_action,
struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl);
+void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra);
/*
* This function checks whether AMPDU is allowed or not for a particular TID.
return false;
}
+
+/*
+ * This function checks whether associated station is 11n enabled
+ */
+static inline int mwifiex_is_sta_11n_enabled(struct mwifiex_private *priv,
+ struct mwifiex_sta_node *node)
+{
+
+ if (!node || (priv->bss_role != MWIFIEX_BSS_ROLE_UAP) ||
+ !priv->ap_11n_enabled)
+ return 0;
+
+ return node->is_11n_enabled;
+}
#endif /* !_MWIFIEX_11N_H_ */
};
struct tx_packet_hdr *tx_header;
- skb_put(skb_aggr, sizeof(*tx_header));
-
- tx_header = (struct tx_packet_hdr *) skb_aggr->data;
+ tx_header = (void *)skb_put(skb_aggr, sizeof(*tx_header));
/* Copy DA and SA */
dt_offset = 2 * ETH_ALEN;
tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
/* Add payload */
- skb_put(skb_aggr, skb_src->len);
- memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
- skb_src->len);
- *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
- LLC_SNAP_LEN)) & 3)) : 0;
- skb_put(skb_aggr, *pad);
+ memcpy(skb_put(skb_aggr, skb_src->len), skb_src->data, skb_src->len);
+
+ /* Add padding for new MSDU to start from 4 byte boundary */
+ *pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4;
return skb_aggr->len + *pad;
}
tbl->rx_reorder_ptr[i] = NULL;
}
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
- if (rx_tmp_ptr)
- mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+ if (rx_tmp_ptr) {
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
+ else
+ mwifiex_process_rx_packet(priv->adapter,
+ rx_tmp_ptr);
+ }
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
rx_tmp_ptr = tbl->rx_reorder_ptr[i];
tbl->rx_reorder_ptr[i] = NULL;
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
- mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
+ else
+ mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
* This function returns the pointer to an entry in Rx reordering
* table which matches the given TA/TID pair.
*/
-static struct mwifiex_rx_reorder_tbl *
+struct mwifiex_rx_reorder_tbl *
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
{
struct mwifiex_rx_reorder_tbl *tbl;
return NULL;
}
+/* This function retrieves the pointer to an entry in Rx reordering
+ * table which matches the given TA and deletes it.
+ */
+void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
+{
+ struct mwifiex_rx_reorder_tbl *tbl, *tmp;
+ unsigned long flags;
+
+ if (!ta)
+ return;
+
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
+ if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+ flags);
+ mwifiex_del_rx_reorder_entry(priv, tbl);
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+ return;
+}
+
/*
* This function finds the last sequence number used in the packets
* buffered in Rx reordering table.
struct mwifiex_rx_reorder_tbl *tbl, *new_node;
u16 last_seq = 0;
unsigned long flags;
+ struct mwifiex_sta_node *node;
/*
* If we get a TID, ta pair which is already present dispatch all the
new_node->tid = tid;
memcpy(new_node->ta, ta, ETH_ALEN);
new_node->start_win = seq_num;
- if (mwifiex_queuing_ra_based(priv))
- /* TODO for adhoc */
+
+ if (mwifiex_queuing_ra_based(priv)) {
dev_dbg(priv->adapter->dev,
- "info: ADHOC:last_seq=%d start_win=%d\n",
+ "info: AP/ADHOC:last_seq=%d start_win=%d\n",
last_seq, new_node->start_win);
- else
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
+ node = mwifiex_get_sta_entry(priv, ta);
+ if (node)
+ last_seq = node->rx_seq[tid];
+ }
+ } else {
last_seq = priv->rx_seq[tid];
+ }
if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
last_seq >= new_node->start_win)
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
if (!tbl) {
- if (pkt_type != PKT_TYPE_BAR)
- mwifiex_process_rx_packet(priv->adapter, payload);
+ if (pkt_type != PKT_TYPE_BAR) {
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ mwifiex_handle_uap_rx_forward(priv, payload);
+ else
+ mwifiex_process_rx_packet(priv->adapter,
+ payload);
+ }
return 0;
}
start_win = tbl->start_win;
#define ADDBA_RSP_STATUS_ACCEPT 0
#define MWIFIEX_DEF_11N_RX_SEQ_NUM 0xffff
+#define BA_SETUP_MAX_PACKET_THRESHOLD 16
+#define BA_SETUP_PACKET_OFFSET 16
static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
{
mwifiex_private
*priv, int tid,
u8 *ta);
+struct mwifiex_rx_reorder_tbl *
+mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta);
+void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta);
#endif /* _MWIFIEX_11N_RXREORDER_H_ */
mwifiex-y += ie.o
mwifiex-y += sta_cmdresp.o
mwifiex-y += sta_event.o
+mwifiex-y += uap_event.o
mwifiex-y += sta_tx.o
mwifiex-y += sta_rx.o
+mwifiex-y += uap_txrx.o
mwifiex-y += cfg80211.o
mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MWIFIEX) += mwifiex.o
const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
- if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) {
+ if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {
wiphy_err(wiphy, "deleting the crypto keys\n");
return -EFAULT;
}
if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
priv->wep_key_curr_index = key_index;
- } else if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
+ } else if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index,
+ NULL, 0)) {
wiphy_err(wiphy, "set default Tx key index\n");
return -EFAULT;
}
return 0;
}
- if (mwifiex_set_encode(priv, params->key, params->key_len,
+ if (mwifiex_set_encode(priv, params, params->key, params->key_len,
key_index, peer_mac, 0)) {
wiphy_err(wiphy, "crypto keys added\n");
return -EFAULT;
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
};
/*
if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+ priv->ap_11n_enabled = 0;
+
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
bss_cfg->channel =
(u8)ieee80211_frequency_to_channel(params->channel->center_freq);
- bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
/* Set appropriate bands */
if (params->channel->band == IEEE80211_BAND_2GHZ) {
+ bss_cfg->band_cfg = BAND_CONFIG_BG;
+
if (params->channel_type == NL80211_CHAN_NO_HT)
config_bands = BAND_B | BAND_G;
else
config_bands = BAND_B | BAND_G | BAND_GN;
} else {
+ bss_cfg->band_cfg = BAND_CONFIG_A;
+
if (params->channel_type == NL80211_CHAN_NO_HT)
config_bands = BAND_A;
else
~priv->adapter->fw_bands))
priv->adapter->config_bands = config_bands;
+ mwifiex_set_uap_rates(bss_cfg, params);
mwifiex_send_domain_info_cmd_fw(wiphy);
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
priv->wep_key_curr_index = 0;
priv->sec_info.encryption_mode = 0;
priv->sec_info.is_authtype_auto = 0;
- ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1);
+ ret = mwifiex_set_encode(priv, NULL, NULL, 0, 0, NULL, 1);
if (mode == NL80211_IFTYPE_ADHOC) {
/* "privacy" is set only for ad-hoc mode */
"info: setting wep encryption"
" with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
- ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
- sme->key_idx, NULL, 0);
+ ret = mwifiex_set_encode(priv, NULL, sme->key,
+ sme->key_len, sme->key_idx,
+ NULL, 0);
}
}
done:
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
}
- ret = mwifiex_process_sta_event(priv);
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ ret = mwifiex_process_uap_event(priv);
+ else
+ ret = mwifiex_process_sta_event(priv);
adapter->event_cause = 0;
adapter->event_skb = NULL;
#define MWIFIEX_SDIO_BLOCK_SIZE 256
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
+#define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1)
+
+#define MWIFIEX_BRIDGED_PKTS_THRESHOLD 1024
enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0,
KEY_TYPE_ID_TKIP,
KEY_TYPE_ID_AES,
KEY_TYPE_ID_WAPI,
+ KEY_TYPE_ID_AES_CMAC,
};
#define KEY_MCAST BIT(0)
#define KEY_UNICAST BIT(1)
#define KEY_ENABLED BIT(2)
+#define KEY_IGTK BIT(10)
#define WAPI_KEY_LEN 50
#define MGMT_MASK_BEACON 0x100
#define TLV_TYPE_UAP_SSID 0x0000
+#define TLV_TYPE_UAP_RATES 0x0001
#define PROPRIETARY_TLV_BASE_ID 0x0100
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
struct rxpd {
u8 bss_type;
u8 bss_num;
- u16 rx_pkt_length;
- u16 rx_pkt_offset;
- u16 rx_pkt_type;
- u16 seq_num;
+ __le16 rx_pkt_length;
+ __le16 rx_pkt_offset;
+ __le16 rx_pkt_type;
+ __le16 seq_num;
u8 priority;
u8 rx_rate;
s8 snr;
u8 reserved;
} __packed;
+struct uap_txpd {
+ u8 bss_type;
+ u8 bss_num;
+ __le16 tx_pkt_length;
+ __le16 tx_pkt_offset;
+ __le16 tx_pkt_type;
+ __le32 tx_control;
+ u8 priority;
+ u8 flags;
+ u8 pkt_delay_2ms;
+ u8 reserved1;
+ __le32 reserved2;
+};
+
+struct uap_rxpd {
+ u8 bss_type;
+ u8 bss_num;
+ __le16 rx_pkt_length;
+ __le16 rx_pkt_offset;
+ __le16 rx_pkt_type;
+ __le16 seq_num;
+ u8 priority;
+ u8 reserved1;
+};
+
enum mwifiex_chan_scan_mode_bitmasks {
MWIFIEX_PASSIVE_SCAN = BIT(0),
MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
u8 key[50];
} __packed;
+#define IGTK_PN_LEN 8
+
+struct mwifiex_cmac_param {
+ u8 ipn[IGTK_PN_LEN];
+ u8 key[WLAN_KEY_LEN_AES_CMAC];
+} __packed;
+
struct host_cmd_ds_802_11_key_material {
__le16 action;
struct mwifiex_ie_type_key_param_set key_param_set;
u8 ssid[0];
} __packed;
+struct host_cmd_tlv_rates {
+ struct host_cmd_tlv tlv;
+ u8 rates[0];
+} __packed;
+
struct host_cmd_tlv_bcast_ssid {
struct host_cmd_tlv tlv;
u8 bcast_ctl;
struct cmd_ctrl_node *cmd_node, *tmp_node;
unsigned long flags;
- if (!mwifiex_wmm_lists_empty(adapter)) {
- if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+ if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+ /*
+ * Abort scan operation by cancelling all pending scan
+ * commands
+ */
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->scan_pending_q, list) {
+ list_del(&cmd_node->list);
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ }
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ adapter->scan_delay_cnt = 0;
+ adapter->empty_tx_q_cnt = 0;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+ if (priv->user_scan_cfg) {
+ dev_dbg(priv->adapter->dev,
+ "info: %s: scan aborted\n", __func__);
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ kfree(priv->user_scan_cfg);
+ priv->user_scan_cfg = NULL;
+ }
+
+ if (priv->scan_pending_on_block) {
+ priv->scan_pending_on_block = false;
+ up(&priv->async_sem);
+ }
+ goto done;
+ }
+
+ if (!atomic_read(&priv->adapter->is_tx_received)) {
+ adapter->empty_tx_q_cnt++;
+ if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
/*
- * Abort scan operation by cancelling all pending scan
- * command
+ * No Tx traffic for 200msec. Get scan command from
+ * scan pending queue and put to cmd pending queue to
+ * resume scan operation
*/
+ adapter->scan_delay_cnt = 0;
+ adapter->empty_tx_q_cnt = 0;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
- list_for_each_entry_safe(cmd_node, tmp_node,
- &adapter->scan_pending_q,
- list) {
- list_del(&cmd_node->list);
- cmd_node->wait_q_enabled = false;
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
- }
+ cmd_node = list_first_entry(&adapter->scan_pending_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->scan_processing = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock,
- flags);
-
- if (priv->user_scan_cfg) {
- dev_dbg(priv->adapter->dev,
- "info: %s: scan aborted\n", __func__);
- cfg80211_scan_done(priv->scan_request, 1);
- priv->scan_request = NULL;
- kfree(priv->user_scan_cfg);
- priv->user_scan_cfg = NULL;
- }
- } else {
- /*
- * Tx data queue is still not empty, delay scan
- * operation further by 20msec.
- */
- mod_timer(&priv->scan_delay_timer, jiffies +
- msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
- adapter->scan_delay_cnt++;
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+ true);
+ goto done;
}
- queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
} else {
- /*
- * Tx data queue is empty. Get scan command from scan_pending_q
- * and put to cmd_pending_q to resume scan operation
- */
- adapter->scan_delay_cnt = 0;
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
- cmd_node = list_first_entry(&adapter->scan_pending_q,
- struct cmd_ctrl_node, list);
- list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
-
- mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+ adapter->empty_tx_q_cnt = 0;
}
+
+ /* Delay scan operation further by 20msec */
+ mod_timer(&priv->scan_delay_timer, jiffies +
+ msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+ adapter->scan_delay_cnt++;
+
+done:
+ if (atomic_read(&priv->adapter->is_tx_received))
+ atomic_set(&priv->adapter->is_tx_received, false);
+
+ return;
}
/*
priv->curr_bcn_size = 0;
priv->wps_ie = NULL;
priv->wps_ie_len = 0;
+ priv->ap_11n_enabled = 0;
priv->scan_block = false;
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
+ adapter->empty_tx_q_cnt = 0;
}
/*
list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
list_del(&priv->tx_ba_stream_tbl_ptr);
list_del(&priv->rx_reorder_tbl_ptr);
+ list_del(&priv->sta_list);
}
}
}
spin_lock_init(&priv->rx_pkt_lock);
spin_lock_init(&priv->wmm.ra_list_spinlock);
spin_lock_init(&priv->curr_bcn_buf_lock);
+ spin_lock_init(&priv->sta_list_spinlock);
}
}
}
INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
+ INIT_LIST_HEAD(&priv->sta_list);
spin_lock_init(&priv->tx_ba_stream_tbl_lock);
spin_lock_init(&priv->rx_reorder_tbl_lock);
#define KEY_MGMT_ON_HOST 0x03
#define MWIFIEX_AUTH_MODE_AUTO 0xFF
-#define BAND_CONFIG_MANUAL 0x00
+#define BAND_CONFIG_BG 0x00
+#define BAND_CONFIG_A 0x01
+#define MWIFIEX_SUPPORTED_RATES 14
+#define MWIFIEX_SUPPORTED_RATES_EXT 32
+
struct mwifiex_uap_bss_param {
u8 channel;
u8 band_cfg;
struct wpa_param wpa_cfg;
struct wep_key wep_cfg[NUM_WEP_KEYS];
struct ieee80211_ht_cap ht_cap;
+ u8 rates[MWIFIEX_SUPPORTED_RATES];
};
enum {
};
#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000
-#define WAPI_RXPN_LEN 16
+#define PN_LEN 16
struct mwifiex_ds_encrypt_key {
u32 key_disable;
u8 key_material[WLAN_MAX_KEY_LEN];
u8 mac_addr[ETH_ALEN];
u32 is_wapi_key;
- u8 wapi_rxpn[WAPI_RXPN_LEN];
+ u8 pn[PN_LEN]; /* packet number */
+ u8 is_igtk_key;
};
struct mwifiex_power_cfg {
mwifiex_wmm_add_buf_txqueue(priv, skb);
atomic_inc(&priv->adapter->tx_pending);
+ if (priv->adapter->scan_delay_cnt)
+ atomic_set(&priv->adapter->is_tx_received, true);
+
if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
mwifiex_set_trans_start(dev);
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
#define MWIFIEX_MAX_SCAN_DELAY_CNT 50
+#define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10
#define MWIFIEX_SCAN_DELAY_MSEC 20
#define RSN_GTK_OUI_OFFSET 2
#define MAX_BITMAP_RATES_SIZE 10
#define MAX_CHANNEL_BAND_BG 14
+#define MAX_CHANNEL_BAND_A 165
#define MAX_FREQUENCY_BAND_BG 2484
u8 ra[ETH_ALEN];
u32 total_pkts_size;
u32 is_11n_enabled;
+ u16 max_amsdu;
+ u16 pkt_count;
+ u8 ba_packet_thr;
};
struct mwifiex_tid_tbl {
u8 len;
} __packed;
-#define MWIFIEX_SUPPORTED_RATES 14
-
-#define MWIFIEX_SUPPORTED_RATES_EXT 32
-
struct ieee_types_vendor_specific {
struct ieee_types_vendor_header vend_hdr;
u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)];
u8 wmm_enabled;
u8 wmm_qosinfo;
struct mwifiex_wmm_desc wmm;
+ struct list_head sta_list;
+ /* spin lock for associated station list */
+ spinlock_t sta_list_spinlock;
struct list_head tx_ba_stream_tbl_ptr;
/* spin lock for tx_ba_stream_tbl_ptr queue */
spinlock_t tx_ba_stream_tbl_lock;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
u8 subsc_evt_rssi_state;
+ struct mwifiex_ds_misc_subsc_evt async_subsc_evt_storage;
struct mwifiex_ie mgmt_ie[MAX_MGMT_IE_INDEX];
u16 beacon_idx;
u16 proberesp_idx;
u16 assocresp_idx;
u16 rsn_idx;
struct timer_list scan_delay_timer;
+ u8 ap_11n_enabled;
};
enum mwifiex_ba_status {
u64 fw_tsf;
};
+/* This is AP specific structure which stores information
+ * about associated STA
+ */
+struct mwifiex_sta_node {
+ struct list_head list;
+ u8 mac_addr[ETH_ALEN];
+ u8 is_wmm_enabled;
+ u8 is_11n_enabled;
+ u8 ampdu_sta[MAX_NUM_TID];
+ u16 rx_seq[MAX_NUM_TID];
+ u16 max_amsdu;
+};
+
struct mwifiex_if_ops {
int (*init_if) (struct mwifiex_adapter *);
void (*cleanup_if) (struct mwifiex_adapter *);
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
u16 max_mgmt_ie_index;
u8 scan_delay_cnt;
+ u8 empty_tx_q_cnt;
+ atomic_t is_tx_received;
+ atomic_t pending_bridged_pkts;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
struct host_cmd_ds_command *resp);
int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
struct sk_buff *skb);
+int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb);
+int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
+ struct sk_buff *skb);
int mwifiex_process_sta_event(struct mwifiex_private *);
+int mwifiex_process_uap_event(struct mwifiex_private *);
+struct mwifiex_sta_node *
+mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac);
+void mwifiex_delete_all_station_list(struct mwifiex_private *priv);
void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
void mwifiex_set_ht_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params);
/*
* This function checks if the queuing is RA based or not.
const struct mwifiex_user_scan_cfg *user_scan_in);
int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
-int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
- int key_len, u8 key_index, const u8 *mac_addr,
- int disable);
+int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
+ const u8 *key, int key_len, u8 key_index,
+ const u8 *mac_addr, int disable);
int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
struct mwifiex_ie_types_num_probes *num_probes_tlv;
struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
struct mwifiex_ie_types_rates_param_set *rates_tlv;
- const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
u8 *tlv_pos;
u32 num_probes;
u32 ssid_len;
* or BSSID filter applied to the scan results in the firmware.
*/
if ((i && ssid_filter) ||
- memcmp(scan_cfg_out->specific_bssid, &zero_mac,
- sizeof(zero_mac)))
+ !is_zero_ether_addr(scan_cfg_out->specific_bssid))
*filtered_scan = true;
} else {
scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
*max_chan_per_scan = 2;
else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
*max_chan_per_scan = 3;
+ else
+ *max_chan_per_scan = 4;
}
}
if (ret)
dev_err(priv->adapter->dev, "cannot find ssid "
"%s\n", bss_desc->ssid.ssid);
- break;
+ break;
default:
- ret = 0;
+ ret = 0;
}
}
struct host_cmd_tlv_mac_addr *tlv_mac;
u16 key_param_len = 0, cmd_size;
int ret = 0;
- const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
key_material->action = cpu_to_le16(cmd_action);
/* set 0 when re-key */
key_material->key_param_set.key[1] = 0;
- if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
+ if (!is_broadcast_ether_addr(enc_key->mac_addr)) {
/* WAPI pairwise key: unicast */
key_material->key_param_set.key_info |=
cpu_to_le16(KEY_UNICAST);
memcpy(&key_material->key_param_set.key[2],
enc_key->key_material, enc_key->key_len);
memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
- enc_key->wapi_rxpn, WAPI_RXPN_LEN);
+ enc_key->pn, PN_LEN);
key_material->key_param_set.length =
cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
return ret;
}
if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
- dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
- key_material->key_param_set.key_type_id =
+ if (enc_key->is_igtk_key) {
+ dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n");
+ key_material->key_param_set.key_type_id =
+ cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ key_material->key_param_set.key_info =
+ cpu_to_le16(KEY_ENABLED);
+ else
+ key_material->key_param_set.key_info =
+ cpu_to_le16(!KEY_ENABLED);
+
+ key_material->key_param_set.key_info |=
+ cpu_to_le16(KEY_IGTK);
+ } else {
+ dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
+ key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES);
- if (cmd_oid == KEY_INFO_ENABLED)
- key_material->key_param_set.key_info =
+ if (cmd_oid == KEY_INFO_ENABLED)
+ key_material->key_param_set.key_info =
cpu_to_le16(KEY_ENABLED);
- else
- key_material->key_param_set.key_info =
+ else
+ key_material->key_param_set.key_info =
cpu_to_le16(!KEY_ENABLED);
- if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+ if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
/* AES pairwise key: unicast */
- key_material->key_param_set.key_info |=
+ key_material->key_param_set.key_info |=
cpu_to_le16(KEY_UNICAST);
- else /* AES group key: multicast */
- key_material->key_param_set.key_info |=
+ else /* AES group key: multicast */
+ key_material->key_param_set.key_info |=
cpu_to_le16(KEY_MCAST);
+ }
} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
key_material->key_param_set.key_type_id =
key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ sizeof(struct mwifiex_ie_types_header);
+ if (le16_to_cpu(key_material->key_param_set.key_type_id) ==
+ KEY_TYPE_ID_AES_CMAC) {
+ struct mwifiex_cmac_param *param =
+ (void *)key_material->key_param_set.key;
+
+ memcpy(param->ipn, enc_key->pn, IGTK_PN_LEN);
+ memcpy(param->key, enc_key->key_material,
+ WLAN_KEY_LEN_AES_CMAC);
+
+ key_param_len = sizeof(struct mwifiex_cmac_param);
+ key_material->key_param_set.key_len =
+ cpu_to_le16(key_param_len);
+ key_param_len += KEYPARAMSET_FIXED_LEN;
+ key_material->key_param_set.length =
+ cpu_to_le16(key_param_len);
+ key_param_len += sizeof(struct mwifiex_ie_types_header);
+ }
+
cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
+ key_param_len);
{
struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
&resp->params.rssi_info_rsp;
- struct mwifiex_ds_misc_subsc_evt subsc_evt;
+ struct mwifiex_ds_misc_subsc_evt *subsc_evt =
+ &priv->async_subsc_evt_storage;
priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
if (priv->subsc_evt_rssi_state == EVENT_HANDLED)
return 0;
+ memset(subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt));
+
/* Resubscribe low and high rssi events with new thresholds */
- memset(&subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt));
- subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH;
- subsc_evt.action = HostCmd_ACT_BITWISE_SET;
+ subsc_evt->events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH;
+ subsc_evt->action = HostCmd_ACT_BITWISE_SET;
if (priv->subsc_evt_rssi_state == RSSI_LOW_RECVD) {
- subsc_evt.bcn_l_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg -
+ subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg -
priv->cqm_rssi_hyst);
- subsc_evt.bcn_h_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
+ subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
} else if (priv->subsc_evt_rssi_state == RSSI_HIGH_RECVD) {
- subsc_evt.bcn_l_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
- subsc_evt.bcn_h_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg +
+ subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
+ subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg +
priv->cqm_rssi_hyst);
}
- subsc_evt.bcn_l_rssi_cfg.evt_freq = 1;
- subsc_evt.bcn_h_rssi_cfg.evt_freq = 1;
+ subsc_evt->bcn_l_rssi_cfg.evt_freq = 1;
+ subsc_evt->bcn_h_rssi_cfg.evt_freq = 1;
priv->subsc_evt_rssi_state = EVENT_HANDLED;
mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
- 0, 0, &subsc_evt);
+ 0, 0, subsc_evt);
return 0;
}
{
struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
&(resp->params.ibss_coalescing);
- u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
return 0;
"info: new BSSID %pM\n", ibss_coal_resp->bssid);
/* If rsp has NULL BSSID, Just return..... No Action */
- if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
+ if (is_zero_ether_addr(ibss_coal_resp->bssid)) {
dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
return 0;
}
int mwifiex_process_sta_event(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
- int len, ret = 0;
+ int ret = 0;
u32 eventcause = adapter->event_cause;
- struct station_info sinfo;
- struct mwifiex_assoc_event *event;
+ u16 ctrl;
switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
case EVENT_MIC_ERR_UNICAST:
dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
+ cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+ NL80211_KEYTYPE_PAIRWISE,
+ -1, NULL, GFP_KERNEL);
break;
case EVENT_MIC_ERR_MULTICAST:
dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
+ cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+ NL80211_KEYTYPE_GROUP,
+ -1, NULL, GFP_KERNEL);
break;
case EVENT_MIB_CHANGED:
case EVENT_INIT_DONE:
adapter->event_body);
break;
case EVENT_AMSDU_AGGR_CTRL:
- dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n",
- *(u16 *) adapter->event_body);
+ ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
+ dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+
adapter->tx_buf_size =
- min(adapter->curr_tx_buf_size,
- le16_to_cpu(*(__le16 *) adapter->event_body));
+ min_t(u16, adapter->curr_tx_buf_size, ctrl);
dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
adapter->tx_buf_size);
break;
dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
break;
- case EVENT_UAP_STA_ASSOC:
- memset(&sinfo, 0, sizeof(sinfo));
- event = (struct mwifiex_assoc_event *)
- (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
- if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
- len = -1;
-
- if (ieee80211_is_assoc_req(event->frame_control))
- len = 0;
- else if (ieee80211_is_reassoc_req(event->frame_control))
- /* There will be ETH_ALEN bytes of
- * current_ap_addr before the re-assoc ies.
- */
- len = ETH_ALEN;
-
- if (len != -1) {
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
- sinfo.assoc_req_ies = &event->data[len];
- len = (u8 *)sinfo.assoc_req_ies -
- (u8 *)&event->frame_control;
- sinfo.assoc_req_ies_len =
- le16_to_cpu(event->len) - (u16)len;
- }
- }
- cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
- GFP_KERNEL);
- break;
- case EVENT_UAP_STA_DEAUTH:
- cfg80211_del_sta(priv->netdev, adapter->event_body +
- MWIFIEX_UAP_EVENT_EXTRA_HEADER, GFP_KERNEL);
- break;
- case EVENT_UAP_BSS_IDLE:
- priv->media_connected = false;
- break;
- case EVENT_UAP_BSS_ACTIVE:
- priv->media_connected = true;
- break;
- case EVENT_UAP_BSS_START:
- dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
- memcpy(priv->netdev->dev_addr, adapter->event_body+2, ETH_ALEN);
- break;
- case EVENT_UAP_MIC_COUNTERMEASURES:
- /* For future development */
- dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
- break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
* This function allocates the IOCTL request buffer, fills it
* with requisite parameters and calls the IOCTL handler.
*/
-int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
- int key_len, u8 key_index,
- const u8 *mac_addr, int disable)
+int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
+ const u8 *key, int key_len, u8 key_index,
+ const u8 *mac_addr, int disable)
{
struct mwifiex_ds_encrypt_key encrypt_key;
memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
encrypt_key.key_len = key_len;
+
+ if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ encrypt_key.is_igtk_key = true;
+
if (!disable) {
encrypt_key.key_index = key_index;
if (key_len)
memcpy(encrypt_key.key_material, key, key_len);
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
+ if (kp && kp->seq && kp->seq_len)
+ memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
} else {
encrypt_key.key_disable = true;
if (mac_addr)
local_rx_pd = (struct rxpd *) (skb->data);
- rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
- local_rx_pd->rx_pkt_offset);
+ rx_pkt_hdr = (void *)local_rx_pd +
+ le16_to_cpu(local_rx_pd->rx_pkt_offset);
if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
struct rx_packet_hdr *rx_pkt_hdr;
u8 ta[ETH_ALEN];
- u16 rx_pkt_type;
+ u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num;
struct mwifiex_private *priv =
mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
rx_info->bss_type);
return -1;
local_rx_pd = (struct rxpd *) (skb->data);
- rx_pkt_type = local_rx_pd->rx_pkt_type;
+ rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type);
+ rx_pkt_offset = le16_to_cpu(local_rx_pd->rx_pkt_offset);
+ rx_pkt_length = le16_to_cpu(local_rx_pd->rx_pkt_length);
+ seq_num = le16_to_cpu(local_rx_pd->seq_num);
- rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
- local_rx_pd->rx_pkt_offset);
+ rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
- if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) >
- (u16) skb->len) {
- dev_err(adapter->dev, "wrong rx packet: len=%d,"
- " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len,
- local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length);
+ if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
+ dev_err(adapter->dev,
+ "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
+ skb->len, rx_pkt_offset, rx_pkt_length);
priv->stats.rx_dropped++;
if (adapter->if_ops.data_complete)
return ret;
}
- if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+ if (rx_pkt_type == PKT_TYPE_AMSDU) {
struct sk_buff_head list;
struct sk_buff *rx_skb;
__skb_queue_head_init(&list);
- skb_pull(skb, local_rx_pd->rx_pkt_offset);
- skb_trim(skb, local_rx_pd->rx_pkt_length);
+ skb_pull(skb, rx_pkt_offset);
+ skb_trim(skb, rx_pkt_length);
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev->iftype, 0, false);
memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
} else {
if (rx_pkt_type != PKT_TYPE_BAR)
- priv->rx_seq[local_rx_pd->priority] =
- local_rx_pd->seq_num;
+ priv->rx_seq[local_rx_pd->priority] = seq_num;
memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
ETH_ALEN);
}
/* Reorder and send to OS */
- ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num,
- local_rx_pd->priority, ta,
- (u8) local_rx_pd->rx_pkt_type,
- skb);
+ ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority,
+ ta, (u8) rx_pkt_type, skb);
if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
if (adapter->if_ops.data_complete)
rx_info->bss_num = priv->bss_num;
rx_info->bss_type = priv->bss_type;
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ return mwifiex_process_uap_rx_packet(adapter, skb);
+
return mwifiex_process_sta_rx_packet(adapter, skb);
}
EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
priv->stats.tx_errors++;
}
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
+ atomic_dec_return(&adapter->pending_bridged_pkts);
if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
goto done;
if (ht_ie) {
memcpy(&bss_cfg->ht_cap, ht_ie + 2,
sizeof(struct ieee80211_ht_cap));
+ priv->ap_11n_enabled = 1;
} else {
memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
return;
}
+/* This function finds supported rates IE from beacon parameter and sets
+ * these rates into bss_config structure.
+ */
+void
+mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params)
+{
+ struct ieee_types_header *rate_ie;
+ int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ const u8 *var_pos = params->beacon.head + var_offset;
+ int len = params->beacon.head_len - var_offset;
+
+ rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
+ if (rate_ie)
+ memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
+
+ return;
+}
+
/* This function initializes some of mwifiex_uap_bss_param variables.
* This helps FW in ignoring invalid values. These values may or may not
* be get updated to valid ones at later stage.
struct host_cmd_tlv_retry_limit *retry_limit;
struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
struct host_cmd_tlv_auth_type *auth_type;
+ struct host_cmd_tlv_rates *tlv_rates;
struct mwifiex_ie_types_htcap *htcap;
struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
+ int i;
u16 cmd_size = *param_size;
if (bss_cfg->ssid.ssid_len) {
cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
}
- if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
+ if (bss_cfg->rates[0]) {
+ tlv_rates = (struct host_cmd_tlv_rates *)tlv;
+ tlv_rates->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RATES);
+
+ for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_cfg->rates[i];
+ i++)
+ tlv_rates->rates[i] = bss_cfg->rates[i];
+
+ tlv_rates->tlv.len = cpu_to_le16(i);
+ cmd_size += sizeof(struct host_cmd_tlv_rates) + i;
+ tlv += sizeof(struct host_cmd_tlv_rates) + i;
+ }
+ if (bss_cfg->channel &&
+ ((bss_cfg->band_cfg == BAND_CONFIG_BG &&
+ bss_cfg->channel <= MAX_CHANNEL_BAND_BG) ||
+ (bss_cfg->band_cfg == BAND_CONFIG_A &&
+ bss_cfg->channel <= MAX_CHANNEL_BAND_A))) {
chan_band = (struct host_cmd_tlv_channel_band *)tlv;
chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
chan_band->tlv.len =
--- /dev/null
+/*
+ * Marvell Wireless LAN device driver: AP event handling
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "main.h"
+#include "11n.h"
+
+/*
+ * This function will return the pointer to station entry in station list
+ * table which matches specified mac address.
+ * This function should be called after acquiring RA list spinlock.
+ * NULL is returned if station entry is not found in associated STA list.
+ */
+struct mwifiex_sta_node *
+mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_sta_node *node;
+
+ if (!mac)
+ return NULL;
+
+ list_for_each_entry(node, &priv->sta_list, list) {
+ if (!memcmp(node->mac_addr, mac, ETH_ALEN))
+ return node;
+ }
+
+ return NULL;
+}
+
+/*
+ * This function will add a sta_node entry to associated station list
+ * table with the given mac address.
+ * If entry exist already, existing entry is returned.
+ * If received mac address is NULL, NULL is returned.
+ */
+static struct mwifiex_sta_node *
+mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_sta_node *node;
+ unsigned long flags;
+
+ if (!mac)
+ return NULL;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ node = mwifiex_get_sta_entry(priv, mac);
+ if (node)
+ goto done;
+
+ node = kzalloc(sizeof(struct mwifiex_sta_node), GFP_ATOMIC);
+ if (!node)
+ goto done;
+
+ memcpy(node->mac_addr, mac, ETH_ALEN);
+ list_add_tail(&node->list, &priv->sta_list);
+
+done:
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ return node;
+}
+
+/*
+ * This function will search for HT IE in association request IEs
+ * and set station HT parameters accordingly.
+ */
+static void
+mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
+ int ies_len, struct mwifiex_sta_node *node)
+{
+ const struct ieee80211_ht_cap *ht_cap;
+
+ if (!ies)
+ return;
+
+ ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
+ if (ht_cap) {
+ node->is_11n_enabled = 1;
+ node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
+ IEEE80211_HT_CAP_MAX_AMSDU ?
+ MWIFIEX_TX_DATA_BUF_SIZE_8K :
+ MWIFIEX_TX_DATA_BUF_SIZE_4K;
+ } else {
+ node->is_11n_enabled = 0;
+ }
+
+ return;
+}
+
+/*
+ * This function will delete a station entry from station list
+ */
+static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+ struct mwifiex_sta_node *node, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+
+ node = mwifiex_get_sta_entry(priv, mac);
+ if (node) {
+ list_for_each_entry_safe(node, tmp, &priv->sta_list,
+ list) {
+ list_del(&node->list);
+ kfree(node);
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ return;
+}
+
+/*
+ * This function will delete all stations from associated station list.
+ */
+static void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
+{
+ struct mwifiex_sta_node *node, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+
+ list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
+ list_del(&node->list);
+ kfree(node);
+ }
+
+ INIT_LIST_HEAD(&priv->sta_list);
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ return;
+}
+
+/*
+ * This function handles AP interface specific events generated by firmware.
+ *
+ * Event specific routines are called by this function based
+ * upon the generated event cause.
+ *
+ *
+ * Events supported for AP -
+ * - EVENT_UAP_STA_ASSOC
+ * - EVENT_UAP_STA_DEAUTH
+ * - EVENT_UAP_BSS_ACTIVE
+ * - EVENT_UAP_BSS_START
+ * - EVENT_UAP_BSS_IDLE
+ * - EVENT_UAP_MIC_COUNTERMEASURES:
+ */
+int mwifiex_process_uap_event(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int len, i;
+ u32 eventcause = adapter->event_cause;
+ struct station_info sinfo;
+ struct mwifiex_assoc_event *event;
+ struct mwifiex_sta_node *node;
+ u8 *deauth_mac;
+ struct host_cmd_ds_11n_batimeout *ba_timeout;
+ u16 ctrl;
+
+ switch (eventcause) {
+ case EVENT_UAP_STA_ASSOC:
+ memset(&sinfo, 0, sizeof(sinfo));
+ event = (struct mwifiex_assoc_event *)
+ (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
+ if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
+ len = -1;
+
+ if (ieee80211_is_assoc_req(event->frame_control))
+ len = 0;
+ else if (ieee80211_is_reassoc_req(event->frame_control))
+ /* There will be ETH_ALEN bytes of
+ * current_ap_addr before the re-assoc ies.
+ */
+ len = ETH_ALEN;
+
+ if (len != -1) {
+ sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ sinfo.assoc_req_ies = &event->data[len];
+ len = (u8 *)sinfo.assoc_req_ies -
+ (u8 *)&event->frame_control;
+ sinfo.assoc_req_ies_len =
+ le16_to_cpu(event->len) - (u16)len;
+ }
+ }
+ cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
+ GFP_KERNEL);
+
+ node = mwifiex_add_sta_entry(priv, event->sta_addr);
+ if (!node) {
+ dev_warn(adapter->dev,
+ "could not create station entry!\n");
+ return -1;
+ }
+
+ if (!priv->ap_11n_enabled)
+ break;
+
+ mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies,
+ sinfo.assoc_req_ies_len, node);
+
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ if (node->is_11n_enabled)
+ node->ampdu_sta[i] =
+ priv->aggr_prio_tbl[i].ampdu_user;
+ else
+ node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
+ }
+ memset(node->rx_seq, 0xff, sizeof(node->rx_seq));
+ break;
+ case EVENT_UAP_STA_DEAUTH:
+ deauth_mac = adapter->event_body +
+ MWIFIEX_UAP_EVENT_EXTRA_HEADER;
+ cfg80211_del_sta(priv->netdev, deauth_mac, GFP_KERNEL);
+
+ if (priv->ap_11n_enabled) {
+ mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac);
+ mwifiex_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
+ }
+ mwifiex_del_sta_entry(priv, deauth_mac);
+ break;
+ case EVENT_UAP_BSS_IDLE:
+ priv->media_connected = false;
+ mwifiex_clean_txrx(priv);
+ mwifiex_del_all_sta_list(priv);
+ break;
+ case EVENT_UAP_BSS_ACTIVE:
+ priv->media_connected = true;
+ break;
+ case EVENT_UAP_BSS_START:
+ dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
+ ETH_ALEN);
+ break;
+ case EVENT_UAP_MIC_COUNTERMEASURES:
+ /* For future development */
+ dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
+ dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+
+ if (priv->media_connected) {
+ adapter->tx_buf_size =
+ min_t(u16, adapter->curr_tx_buf_size, ctrl);
+ dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
+ adapter->tx_buf_size);
+ }
+ break;
+ case EVENT_ADDBA:
+ dev_dbg(adapter->dev, "event: ADDBA Request\n");
+ if (priv->media_connected)
+ mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0,
+ adapter->event_body);
+ break;
+ case EVENT_DELBA:
+ dev_dbg(adapter->dev, "event: DELBA Request\n");
+ if (priv->media_connected)
+ mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
+ break;
+ case EVENT_BA_STREAM_TIEMOUT:
+ dev_dbg(adapter->dev, "event: BA Stream timeout\n");
+ if (priv->media_connected) {
+ ba_timeout = (void *)adapter->event_body;
+ mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
+ }
+ break;
+ default:
+ dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
+ eventcause);
+ break;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Marvell Wireless LAN device driver: AP TX and RX data handling
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n_aggr.h"
+#include "11n_rxreorder.h"
+
+static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct uap_rxpd *uap_rx_pd;
+ struct rx_packet_hdr *rx_pkt_hdr;
+ struct sk_buff *new_skb;
+ struct mwifiex_txinfo *tx_info;
+ int hdr_chop;
+ struct timeval tv;
+ u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+ uap_rx_pd = (struct uap_rxpd *)(skb->data);
+ rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+
+ if ((atomic_read(&adapter->pending_bridged_pkts) >=
+ MWIFIEX_BRIDGED_PKTS_THRESHOLD)) {
+ dev_err(priv->adapter->dev,
+ "Tx: Bridge packet limit reached. Drop packet!\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)))
+ /* Chop off the rxpd + the excess memory from
+ * 802.2/llc/snap header that was removed.
+ */
+ hdr_chop = (u8 *)eth_hdr - (u8 *)uap_rx_pd;
+ else
+ /* Chop off the rxpd */
+ hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd;
+
+ /* Chop off the leading header bytes so the it points
+ * to the start of either the reconstructed EthII frame
+ * or the 802.2/llc/snap frame.
+ */
+ skb_pull(skb, hdr_chop);
+
+ if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
+ dev_dbg(priv->adapter->dev,
+ "data: Tx: insufficient skb headroom %d\n",
+ skb_headroom(skb));
+ /* Insufficient skb headroom - allocate a new skb */
+ new_skb =
+ skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
+ if (unlikely(!new_skb)) {
+ dev_err(priv->adapter->dev,
+ "Tx: cannot allocate new_skb\n");
+ kfree_skb(skb);
+ priv->stats.tx_dropped++;
+ return;
+ }
+
+ kfree_skb(skb);
+ skb = new_skb;
+ dev_dbg(priv->adapter->dev, "info: new skb headroom %d\n",
+ skb_headroom(skb));
+ }
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ tx_info->bss_num = priv->bss_num;
+ tx_info->bss_type = priv->bss_type;
+ tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
+
+ do_gettimeofday(&tv);
+ skb->tstamp = timeval_to_ktime(tv);
+ mwifiex_wmm_add_buf_txqueue(priv, skb);
+ atomic_inc(&adapter->tx_pending);
+ atomic_inc(&adapter->pending_bridged_pkts);
+
+ if ((atomic_read(&adapter->tx_pending) >= MAX_TX_PENDING)) {
+ mwifiex_set_trans_start(priv->netdev);
+ mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+ }
+ return;
+}
+
+/*
+ * This function contains logic for AP packet forwarding.
+ *
+ * If a packet is multicast/broadcast, it is sent to kernel/upper layer
+ * as well as queued back to AP TX queue so that it can be sent to other
+ * associated stations.
+ * If a packet is unicast and RA is present in associated station list,
+ * it is again requeued into AP TX queue.
+ * If a packet is unicast and RA is not in associated station list,
+ * packet is forwarded to kernel to handle routing logic.
+ */
+int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct uap_rxpd *uap_rx_pd;
+ struct rx_packet_hdr *rx_pkt_hdr;
+ u8 ra[ETH_ALEN];
+ struct sk_buff *skb_uap;
+
+ uap_rx_pd = (struct uap_rxpd *)(skb->data);
+ rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+
+ /* don't do packet forwarding in disconnected state */
+ if (!priv->media_connected) {
+ dev_err(adapter->dev, "drop packet in disconnected state.\n");
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ memcpy(ra, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN);
+
+ if (is_multicast_ether_addr(ra)) {
+ skb_uap = skb_copy(skb, GFP_ATOMIC);
+ mwifiex_uap_queue_bridged_pkt(priv, skb_uap);
+ } else {
+ if (mwifiex_get_sta_entry(priv, ra)) {
+ /* Requeue Intra-BSS packet */
+ mwifiex_uap_queue_bridged_pkt(priv, skb);
+ return 0;
+ }
+ }
+
+ /* Forward unicat/Inter-BSS packets to kernel. */
+ return mwifiex_process_rx_packet(adapter, skb);
+}
+
+/*
+ * This function processes the packet received on AP interface.
+ *
+ * The function looks into the RxPD and performs sanity tests on the
+ * received buffer to ensure its a valid packet before processing it
+ * further. If the packet is determined to be aggregated, it is
+ * de-aggregated accordingly. Then skb is passed to AP packet forwarding logic.
+ *
+ * The completion callback is called after processing is complete.
+ */
+int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ int ret;
+ struct uap_rxpd *uap_rx_pd;
+ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+ struct rx_packet_hdr *rx_pkt_hdr;
+ u16 rx_pkt_type;
+ u8 ta[ETH_ALEN], pkt_type;
+ struct mwifiex_sta_node *node;
+
+ struct mwifiex_private *priv =
+ mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
+ rx_info->bss_type);
+
+ if (!priv)
+ return -1;
+
+ uap_rx_pd = (struct uap_rxpd *)(skb->data);
+ rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
+ rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+
+ if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
+ le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) {
+ dev_err(adapter->dev,
+ "wrong rx packet: len=%d, offset=%d, length=%d\n",
+ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
+ le16_to_cpu(uap_rx_pd->rx_pkt_length));
+ priv->stats.rx_dropped++;
+
+ if (adapter->if_ops.data_complete)
+ adapter->if_ops.data_complete(adapter, skb);
+ else
+ dev_kfree_skb_any(skb);
+
+ return 0;
+ }
+
+ if (le16_to_cpu(uap_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
+ struct sk_buff_head list;
+ struct sk_buff *rx_skb;
+
+ __skb_queue_head_init(&list);
+ skb_pull(skb, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
+ skb_trim(skb, le16_to_cpu(uap_rx_pd->rx_pkt_length));
+
+ ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
+ priv->wdev->iftype, 0, false);
+
+ while (!skb_queue_empty(&list)) {
+ rx_skb = __skb_dequeue(&list);
+ ret = mwifiex_recv_packet(adapter, rx_skb);
+ if (ret)
+ dev_err(adapter->dev,
+ "AP:Rx A-MSDU failed");
+ }
+
+ return 0;
+ }
+
+ memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
+
+ if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
+ node = mwifiex_get_sta_entry(priv, ta);
+ if (node)
+ node->rx_seq[uap_rx_pd->priority] =
+ le16_to_cpu(uap_rx_pd->seq_num);
+ }
+
+ if (!priv->ap_11n_enabled ||
+ (!mwifiex_11n_get_rx_reorder_tbl(priv, uap_rx_pd->priority, ta) &&
+ (le16_to_cpu(uap_rx_pd->rx_pkt_type) != PKT_TYPE_AMSDU))) {
+ ret = mwifiex_handle_uap_rx_forward(priv, skb);
+ return ret;
+ }
+
+ /* Reorder and send to kernel */
+ pkt_type = (u8)le16_to_cpu(uap_rx_pd->rx_pkt_type);
+ ret = mwifiex_11n_rx_reorder_pkt(priv, le16_to_cpu(uap_rx_pd->seq_num),
+ uap_rx_pd->priority, ta, pkt_type,
+ skb);
+
+ if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
+ if (adapter->if_ops.data_complete)
+ adapter->if_ops.data_complete(adapter, skb);
+ else
+ dev_kfree_skb_any(skb);
+ }
+
+ if (ret)
+ priv->stats.rx_dropped++;
+
+ return ret;
+}
return ra_list;
}
+/* This function returns random no between 16 and 32 to be used as threshold
+ * for no of packets after which BA setup is initiated.
+ */
+static u8 mwifiex_get_random_ba_threshold(void)
+{
+ u32 sec, usec;
+ struct timeval ba_tstamp;
+ u8 ba_threshold;
+
+ /* setup ba_packet_threshold here random number between
+ * [BA_SETUP_PACKET_OFFSET,
+ * BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1]
+ */
+
+ do_gettimeofday(&ba_tstamp);
+ sec = (ba_tstamp.tv_sec & 0xFFFF) + (ba_tstamp.tv_sec >> 16);
+ usec = (ba_tstamp.tv_usec & 0xFFFF) + (ba_tstamp.tv_usec >> 16);
+ ba_threshold = (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD)
+ + BA_SETUP_PACKET_OFFSET;
+
+ return ba_threshold;
+}
+
/*
* This function allocates and adds a RA list for all TIDs
* with the given RA.
int i;
struct mwifiex_ra_list_tbl *ra_list;
struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_sta_node *node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ node = mwifiex_get_sta_entry(priv, ra);
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
if (!ra_list)
break;
- if (!mwifiex_queuing_ra_based(priv))
+ ra_list->is_11n_enabled = 0;
+ if (!mwifiex_queuing_ra_based(priv)) {
ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
- else
- ra_list->is_11n_enabled = false;
+ } else {
+ ra_list->is_11n_enabled =
+ mwifiex_is_sta_11n_enabled(priv, node);
+ if (ra_list->is_11n_enabled)
+ ra_list->max_amsdu = node->max_amsdu;
+ }
dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
ra_list, ra_list->is_11n_enabled);
+ if (ra_list->is_11n_enabled) {
+ ra_list->pkt_count = 0;
+ ra_list->ba_packet_thr =
+ mwifiex_get_random_ba_threshold();
+ }
list_add_tail(&ra_list->list,
&priv->wmm.tid_tbl_ptr[i].ra_list);
skb_queue_tail(&ra_list->skb_head, skb);
ra_list->total_pkts_size += skb->len;
+ ra_list->pkt_count++;
atomic_inc(&priv->wmm.tx_pkts_queued);
{
int count = 0, total_size = 0;
struct sk_buff *skb, *tmp;
+ int max_amsdu_size;
+
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP && priv->ap_11n_enabled &&
+ ptr->is_11n_enabled)
+ max_amsdu_size = min_t(int, ptr->max_amsdu, max_buf_size);
+ else
+ max_amsdu_size = max_buf_size;
skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
total_size += skb->len;
- if (total_size >= max_buf_size)
+ if (total_size >= max_amsdu_size)
break;
if (++count >= MIN_NUM_AMSDU)
return true;
skb_queue_tail(&ptr->skb_head, skb);
ptr->total_pkts_size += skb->len;
+ ptr->pkt_count++;
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
/* ra_list_spinlock has been freed in
mwifiex_send_single_packet() */
} else {
- if (mwifiex_is_ampdu_allowed(priv, tid)) {
+ if (mwifiex_is_ampdu_allowed(priv, tid) &&
+ ptr->pkt_count > ptr->ba_packet_thr) {
if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
mwifiex_create_ba_tbl(priv, ptr->ra, tid,
BA_SETUP_INPROGRESS);
}
static void
-mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
+mwl8k_txq_xmit(struct ieee80211_hw *hw,
+ int index,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
{
struct mwl8k_priv *priv = hw->priv;
struct ieee80211_tx_info *tx_info;
struct mwl8k_vif *mwl8k_vif;
- struct ieee80211_sta *sta;
struct ieee80211_hdr *wh;
struct mwl8k_tx_queue *txq;
struct mwl8k_tx_desc *tx;
wh = &((struct mwl8k_dma_data *)skb->data)->wh;
tx_info = IEEE80211_SKB_CB(skb);
- sta = tx_info->control.sta;
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
tx->rate_info = 0;
- if (!priv->ap_fw && tx_info->control.sta != NULL)
- tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id;
+ if (!priv->ap_fw && sta != NULL)
+ tx->peer_id = MWL8K_STA(sta)->peer_id;
else
tx->peer_id = 0;
/*
* Core driver operations.
*/
-static void mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void mwl8k_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct mwl8k_priv *priv = hw->priv;
int index = skb_get_queue_mapping(skb);
return;
}
- mwl8k_txq_xmit(hw, index, skb);
+ mwl8k_txq_xmit(hw, index, control->sta, skb);
}
static int mwl8k_start(struct ieee80211_hw *hw)
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
+#include <linux/etherdevice.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
#include <net/cfg80211-wext.h>
struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
- static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
/* Enable automatic roaming - no sanity checks are needed */
- if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
- memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+ if (is_zero_ether_addr(ap_addr->sa_data) ||
+ is_broadcast_ether_addr(ap_addr->sa_data)) {
priv->bssid_fixed = 0;
memset(priv->desired_bssid, 0, ETH_ALEN);
u16 freq;
u16 data;
int index;
+ int max_power;
enum ieee80211_band band;
};
for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
(i < list->entries); i++) {
struct p54_channel_entry *chan = &list->channels[i];
+ struct ieee80211_channel *dest = &tmp->channels[j];
if (chan->band != band)
continue;
continue;
}
- tmp->channels[j].band = chan->band;
- tmp->channels[j].center_freq = chan->freq;
+ dest->band = chan->band;
+ dest->center_freq = chan->freq;
+ dest->max_power = chan->max_power;
priv->survey[*chan_num].channel = &tmp->channels[j];
priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_TX;
- tmp->channels[j].hw_value = (*chan_num);
+ dest->hw_value = (*chan_num);
j++;
(*chan_num)++;
}
return ret;
}
-static void p54_update_channel_param(struct p54_channel_list *list,
- u16 freq, u16 data)
+static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
+ u16 freq, u16 data)
{
- int band, i;
+ int i;
+ struct p54_channel_entry *entry = NULL;
/*
* usually all lists in the eeprom are mostly sorted.
*/
for (i = list->entries; i >= 0; i--) {
if (freq == list->channels[i].freq) {
- list->channels[i].data |= data;
+ entry = &list->channels[i];
break;
}
}
if ((i < 0) && (list->entries < list->max_entries)) {
/* entry does not exist yet. Initialize a new one. */
- band = p54_get_band_from_freq(freq);
+ int band = p54_get_band_from_freq(freq);
/*
* filter out frequencies which don't belong into
* any supported band.
*/
- if (band < 0)
- return ;
+ if (band >= 0) {
+ i = list->entries++;
+ list->band_channel_num[band]++;
+
+ entry = &list->channels[i];
+ entry->freq = freq;
+ entry->band = band;
+ entry->index = ieee80211_frequency_to_channel(freq);
+ entry->max_power = 0;
+ entry->data = 0;
+ }
+ }
- i = list->entries++;
- list->band_channel_num[band]++;
+ if (entry)
+ entry->data |= data;
- list->channels[i].freq = freq;
- list->channels[i].data = data;
- list->channels[i].band = band;
- list->channels[i].index = ieee80211_frequency_to_channel(freq);
- /* TODO: parse output_limit and fill max_power */
+ return entry;
+}
+
+static int p54_get_maxpower(struct p54_common *priv, void *data)
+{
+ switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
+ case PDR_SYNTH_FRONTEND_LONGBOW: {
+ struct pda_channel_output_limit_longbow *pda = data;
+ int j;
+ u16 rawpower = 0;
+ pda = data;
+ for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
+ struct pda_channel_output_limit_point_longbow *point =
+ &pda->point[j];
+ rawpower = max_t(u16,
+ rawpower, le16_to_cpu(point->val_qpsk));
+ rawpower = max_t(u16,
+ rawpower, le16_to_cpu(point->val_bpsk));
+ rawpower = max_t(u16,
+ rawpower, le16_to_cpu(point->val_16qam));
+ rawpower = max_t(u16,
+ rawpower, le16_to_cpu(point->val_64qam));
+ }
+ /* longbow seems to use 1/16 dBm units */
+ return rawpower / 16;
+ }
+
+ case PDR_SYNTH_FRONTEND_DUETTE3:
+ case PDR_SYNTH_FRONTEND_DUETTE2:
+ case PDR_SYNTH_FRONTEND_FRISBEE:
+ case PDR_SYNTH_FRONTEND_XBOW: {
+ struct pda_channel_output_limit *pda = data;
+ u8 rawpower = 0;
+ rawpower = max(rawpower, pda->val_qpsk);
+ rawpower = max(rawpower, pda->val_bpsk);
+ rawpower = max(rawpower, pda->val_16qam);
+ rawpower = max(rawpower, pda->val_64qam);
+ /* raw values are in 1/4 dBm units */
+ return rawpower / 4;
+ }
+
+ default:
+ return 20;
}
}
}
if (i < priv->output_limit->entries) {
- freq = le16_to_cpup((__le16 *) (i *
- priv->output_limit->entry_size +
- priv->output_limit->offset +
- priv->output_limit->data));
-
- p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+ struct p54_channel_entry *tmp;
+
+ void *data = (void *) ((unsigned long) i *
+ priv->output_limit->entry_size +
+ priv->output_limit->offset +
+ priv->output_limit->data);
+
+ freq = le16_to_cpup((__le16 *) data);
+ tmp = p54_update_channel_param(list, freq,
+ CHAN_HAS_LIMIT);
+ if (tmp) {
+ tmp->max_power = p54_get_maxpower(priv, data);
+ }
}
if (i < priv->curve_data->entries) {
goto err;
}
+ priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+
err = p54_generate_channel_lists(dev);
if (err)
goto err;
- priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
p54_init_xbow_synth(priv);
if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
u8 rate_set_size;
} __packed;
+struct pda_channel_output_limit_point_longbow {
+ __le16 val_bpsk;
+ __le16 val_qpsk;
+ __le16 val_16qam;
+ __le16 val_64qam;
+} __packed;
+
+struct pda_channel_output_limit_longbow {
+ __le16 freq;
+ struct pda_channel_output_limit_point_longbow point[3];
+} __packed;
+
struct pda_pa_curve_data_sample_rev0 {
u8 rf_power;
u8 pa_detector;
void p54_unregister_leds(struct p54_common *priv);
/* xmit functions */
-void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb);
+void p54_tx_80211(struct ieee80211_hw *dev,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
void p54_tx(struct p54_common *priv, struct sk_buff *skb);
* to cancel the old beacon template by hand, instead the firmware
* will release the previous one through the feedback mechanism.
*/
- p54_tx_80211(priv->hw, beacon);
+ p54_tx_80211(priv->hw, NULL, beacon);
priv->tsf_high32 = 0;
priv->tsf_low32 = 0;
return 0;
}
+static void p54p_firmware_step2(const struct firmware *fw,
+ void *context)
+{
+ struct p54p_priv *priv = context;
+ struct ieee80211_hw *dev = priv->common.hw;
+ struct pci_dev *pdev = priv->pdev;
+ int err;
+
+ if (!fw) {
+ dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
+ err = -ENOENT;
+ goto out;
+ }
+
+ priv->firmware = fw;
+
+ err = p54p_open(dev);
+ if (err)
+ goto out;
+ err = p54_read_eeprom(dev);
+ p54p_stop(dev);
+ if (err)
+ goto out;
+
+ err = p54_register_common(dev, &pdev->dev);
+ if (err)
+ goto out;
+
+out:
+
+ complete(&priv->fw_loaded);
+
+ if (err) {
+ struct device *parent = pdev->dev.parent;
+
+ if (parent)
+ device_lock(parent);
+
+ /*
+ * This will indirectly result in a call to p54p_remove.
+ * Hence, we don't need to bother with freeing any
+ * allocated ressources at all.
+ */
+ device_release_driver(&pdev->dev);
+
+ if (parent)
+ device_unlock(parent);
+ }
+
+ pci_dev_put(pdev);
+}
+
static int __devinit p54p_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
unsigned long mem_addr, mem_len;
int err;
+ pci_dev_get(pdev);
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Cannot enable new PCI device\n");
priv = dev->priv;
priv->pdev = pdev;
+ init_completion(&priv->fw_loaded);
SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);
spin_lock_init(&priv->lock);
tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
- err = request_firmware(&priv->firmware, "isl3886pci",
- &priv->pdev->dev);
- if (err) {
- dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
- err = request_firmware(&priv->firmware, "isl3886",
- &priv->pdev->dev);
- if (err)
- goto err_free_common;
- }
-
- err = p54p_open(dev);
- if (err)
- goto err_free_common;
- err = p54_read_eeprom(dev);
- p54p_stop(dev);
- if (err)
- goto err_free_common;
-
- err = p54_register_common(dev, &pdev->dev);
- if (err)
- goto err_free_common;
-
- return 0;
+ err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
+ &priv->pdev->dev, GFP_KERNEL,
+ priv, p54p_firmware_step2);
+ if (!err)
+ return 0;
- err_free_common:
- release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
pci_release_regions(pdev);
err_disable_dev:
pci_disable_device(pdev);
+ pci_dev_put(pdev);
return err;
}
if (!dev)
return;
- p54_unregister_common(dev);
priv = dev->priv;
+ wait_for_completion(&priv->fw_loaded);
+ p54_unregister_common(dev);
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
struct sk_buff *tx_buf_data[32];
struct sk_buff *tx_buf_mgmt[4];
struct completion boot_comp;
+ struct completion fw_loaded;
};
#endif /* P54USB_H */
EXPORT_SYMBOL_GPL(p54_rx);
static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
- struct ieee80211_tx_info *info, u8 *queue,
- u32 *extra_len, u16 *flags, u16 *aid,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ u8 *queue, u32 *extra_len, u16 *flags, u16 *aid,
bool *burst_possible)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
}
}
- if (info->control.sta)
- *aid = info->control.sta->aid;
+ if (sta)
+ *aid = sta->aid;
break;
}
}
}
}
-void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
+void p54_tx_80211(struct ieee80211_hw *dev,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct p54_common *priv = dev->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 nrates = 0, nremaining = 8;
bool burst_allowed = false;
- p54_tx_80211_header(priv, skb, info, &queue, &extra_len,
+ p54_tx_80211_header(priv, skb, info, control->sta, &queue, &extra_len,
&hdr_flags, &aid, &burst_allowed);
if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
/*
* mac80211 handlers.
*/
-void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+void rt2x00mac_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
int rt2x00mac_start(struct ieee80211_hw *hw);
void rt2x00mac_stop(struct ieee80211_hw *hw);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
*/
skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
while (skb) {
- rt2x00mac_tx(rt2x00dev->hw, skb);
+ rt2x00mac_tx(rt2x00dev->hw, NULL, skb);
skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
}
}
return retval;
}
-void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+void rt2x00mac_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txentry_desc *txdesc,
+ struct ieee80211_sta *sta,
const struct rt2x00_rate *hwrate)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct rt2x00_sta *sta_priv = NULL;
- if (tx_info->control.sta) {
+ if (sta) {
txdesc->u.ht.mpdu_density =
- tx_info->control.sta->ht_cap.ampdu_density;
+ sta->ht_cap.ampdu_density;
- sta_priv = sta_to_rt2x00_sta(tx_info->control.sta);
+ sta_priv = sta_to_rt2x00_sta(sta);
txdesc->u.ht.wcid = sta_priv->wcid;
}
* MIMO PS should be set to 1 for STA's using dynamic SM PS
* when using more then one tx stream (>MCS7).
*/
- if (tx_info->control.sta && txdesc->u.ht.mcs > 7 &&
- ((tx_info->control.sta->ht_cap.cap &
+ if (sta && txdesc->u.ht.mcs > 7 &&
+ ((sta->ht_cap.cap &
IEEE80211_HT_CAP_SM_PS) >>
IEEE80211_HT_CAP_SM_PS_SHIFT) ==
WLAN_HT_CAP_SM_PS_DYNAMIC)
static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txentry_desc *txdesc)
+ struct txentry_desc *txdesc,
+ struct ieee80211_sta *sta)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags))
rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc,
- hwrate);
+ sta, hwrate);
else
rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc,
hwrate);
* after that we are free to use the skb->cb array
* for our information.
*/
- rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc);
+ rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc, NULL);
/*
* All information is retrieved from the skb->cb array,
* after that we are free to use the skb->cb array
* for our information.
*/
- rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc);
+ rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc, NULL);
/*
* Fill in skb descriptor
return IRQ_HANDLED;
}
-static void rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
+static void rtl8180_tx(struct ieee80211_hw *dev,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
/* TODO: use actual beacon queue */
skb_set_queue_mapping(skb, 0);
- rtl8180_tx(dev, skb);
+ rtl8180_tx(dev, NULL, skb);
resched:
/*
}
}
-static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
+static void rtl8187_tx(struct ieee80211_hw *dev,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct rtl8187_priv *priv = dev->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
/* TODO: use actual beacon queue */
skb_set_queue_mapping(skb, 0);
- rtl8187_tx(dev, skb);
+ rtl8187_tx(dev, NULL, skb);
resched:
/*
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
info->control.rates[0].idx = 0;
- info->control.sta = sta;
info->band = hw->conf.channel->band;
- rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+ rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc);
}
err_free:
return 0;
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
-static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void rtl_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
goto err_free;
- if (!rtlpriv->intf_ops->waitq_insert(hw, skb))
- rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+ if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb))
+ rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc);
return;
_rtl_update_earlymode_info(hw, skb,
&tcb_desc, tid);
- rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+ rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc);
}
}
}
info = IEEE80211_SKB_CB(pskb);
pdesc = &ring->desc[0];
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- info, pskb, BEACON_QUEUE, &tcb_desc);
+ info, NULL, pskb, BEACON_QUEUE, &tcb_desc);
__skb_queue_tail(&ring->queue, pskb);
}
static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = info->control.sta;
struct rtl_sta_info *sta_entry = NULL;
u8 tid = rtl_get_tid(skb);
return true;
}
-static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct rtl_tcb_desc *ptcb_desc)
+static int rtl_pci_tx(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ struct rtl_tcb_desc *ptcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_sta_info *sta_entry = NULL;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = info->control.sta;
struct rtl8192_tx_ring *ring;
struct rtl_tx_desc *pdesc;
u8 idx;
rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
- info, skb, hw_queue, ptcb_desc);
+ info, sta, skb, hw_queue, ptcb_desc);
__skb_queue_tail(&ring->queue, skb);
dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
dm_digtable->cur_igvalue = 0x20;
dm_digtable->pre_igvalue = 0x0;
- dm_digtable->cursta_connectctate = DIG_STA_DISCONNECT;
+ dm_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
dm_digtable->presta_connectstate = DIG_STA_DISCONNECT;
dm_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT;
dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
long rssi_val_min = 0;
if ((dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) &&
- (dm_digtable->cursta_connectctate == DIG_STA_CONNECT)) {
+ (dm_digtable->cursta_connectstate == DIG_STA_CONNECT)) {
if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb != 0)
rssi_val_min =
(rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb >
rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
else
rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb;
- } else if (dm_digtable->cursta_connectctate == DIG_STA_CONNECT ||
- dm_digtable->cursta_connectctate == DIG_STA_BEFORE_CONNECT) {
+ } else if (dm_digtable->cursta_connectstate == DIG_STA_CONNECT ||
+ dm_digtable->cursta_connectstate == DIG_STA_BEFORE_CONNECT) {
rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb;
} else if (dm_digtable->curmultista_connectstate ==
DIG_MULTISTA_CONNECT) {
multi_sta = true;
if (!multi_sta ||
- dm_digtable->cursta_connectctate != DIG_STA_DISCONNECT) {
+ dm_digtable->cursta_connectstate != DIG_STA_DISCONNECT) {
initialized = false;
dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
return;
struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
- "presta_connectstate = %x, cursta_connectctate = %x\n",
+ "presta_connectstate = %x, cursta_connectstate = %x\n",
dm_digtable->presta_connectstate,
- dm_digtable->cursta_connectctate);
+ dm_digtable->cursta_connectstate);
- if (dm_digtable->presta_connectstate == dm_digtable->cursta_connectctate
- || dm_digtable->cursta_connectctate == DIG_STA_BEFORE_CONNECT
- || dm_digtable->cursta_connectctate == DIG_STA_CONNECT) {
+ if (dm_digtable->presta_connectstate == dm_digtable->cursta_connectstate
+ || dm_digtable->cursta_connectstate == DIG_STA_BEFORE_CONNECT
+ || dm_digtable->cursta_connectstate == DIG_STA_CONNECT) {
- if (dm_digtable->cursta_connectctate != DIG_STA_DISCONNECT) {
+ if (dm_digtable->cursta_connectstate != DIG_STA_DISCONNECT) {
dm_digtable->rssi_val_min =
rtl92c_dm_initial_gain_min_pwdb(hw);
rtl92c_dm_ctrl_initgain_by_rssi(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
- if (dm_digtable->cursta_connectctate == DIG_STA_CONNECT) {
+ if (dm_digtable->cursta_connectstate == DIG_STA_CONNECT) {
dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw);
if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
return;
if (mac->link_state >= MAC80211_LINKED)
- dm_digtable->cursta_connectctate = DIG_STA_CONNECT;
+ dm_digtable->cursta_connectstate = DIG_STA_CONNECT;
else
- dm_digtable->cursta_connectctate = DIG_STA_DISCONNECT;
+ dm_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
rtl92c_dm_initial_gain_sta(hw);
rtl92c_dm_initial_gain_multi_sta(hw);
rtl92c_dm_cck_packet_detection_thresh(hw);
- dm_digtable->presta_connectstate = dm_digtable->cursta_connectctate;
+ dm_digtable->presta_connectstate = dm_digtable->cursta_connectstate;
}
"PreState = %d, CurState = %d\n",
p_ra->pre_ratr_state, p_ra->ratr_state);
- /* Only the PCI card uses sta in the update rate table
- * callback routine */
- if (rtlhal->interface == INTF_PCI) {
- rcu_read_lock();
- sta = ieee80211_find_sta(mac->vif, mac->bssid);
- }
+ rcu_read_lock();
+ sta = ieee80211_find_sta(mac->vif, mac->bssid);
rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
p_ra->ratr_state);
p_ra->pre_ratr_state = p_ra->ratr_state;
- if (rtlhal->interface == INTF_PCI)
- rcu_read_unlock();
+ rcu_read_unlock();
}
}
}
ring = &rtlpci->tx_ring[BEACON_QUEUE];
pskb = __skb_dequeue(&ring->queue);
- if (pskb)
- kfree_skb(pskb);
+ kfree_skb(pskb);
spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
}
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
"ratr_bitmap :%x\n", ratr_bitmap);
- *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) |
- (ratr_index << 28));
+ *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+ (ratr_index << 28);
rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
"Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x\n",
.maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
};
-DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = {
+static DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = {
{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)},
{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)},
{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)},
void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info, struct sk_buff *skb,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *tcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
bool defaultadapter = true;
- struct ieee80211_sta *sta;
u8 *pdesc = pdesc_tx;
u16 seq_number;
__le16 fc = hdr->frame_control;
void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr,
u8 *pdesc, struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
SET_TX_DESC_TX_DESC_CHECKSUM(txdesc, 0);
for (index = 0; index < 16; index++)
checksum = checksum ^ (*(ptr + index));
- SET_TX_DESC_TX_DESC_CHECKSUM(txdesc, cpu_to_le16(checksum));
+ SET_TX_DESC_TX_DESC_CHECKSUM(txdesc, checksum);
}
void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info, struct sk_buff *skb,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
u8 queue_index,
struct rtl_tcb_desc *tcb_desc)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
bool defaultadapter = true;
- struct ieee80211_sta *sta = info->control.sta = info->control.sta;
u8 *qc = ieee80211_get_qos_ctl(hdr);
u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
u16 seq_number;
struct sk_buff_head *);
void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info, struct sk_buff *skb,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
u8 queue_index,
struct rtl_tcb_desc *tcb_desc);
void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc,
de_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
de_digtable->cur_igvalue = 0x20;
de_digtable->pre_igvalue = 0x0;
- de_digtable->cursta_connectctate = DIG_STA_DISCONNECT;
+ de_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
de_digtable->presta_connectstate = DIG_STA_DISCONNECT;
de_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT;
de_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
struct dig_t *de_digtable = &rtlpriv->dm_digtable;
unsigned long flag = 0;
- if (de_digtable->cursta_connectctate == DIG_STA_CONNECT) {
+ if (de_digtable->cursta_connectstate == DIG_STA_CONNECT) {
if (de_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) {
if (de_digtable->min_undecorated_pwdb_for_dm <= 25)
de_digtable->cur_cck_pd_state =
de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state;
}
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CurSTAConnectState=%s\n",
- de_digtable->cursta_connectctate == DIG_STA_CONNECT ?
+ de_digtable->cursta_connectstate == DIG_STA_CONNECT ?
"DIG_STA_CONNECT " : "DIG_STA_DISCONNECT");
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CCKPDStage=%s\n",
de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI ?
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "progress\n");
/* Decide the current status and if modify initial gain or not */
if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
- de_digtable->cursta_connectctate = DIG_STA_CONNECT;
+ de_digtable->cursta_connectstate = DIG_STA_CONNECT;
else
- de_digtable->cursta_connectctate = DIG_STA_DISCONNECT;
+ de_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
/* adjust initial gain according to false alarm counter */
if (falsealm_cnt->cnt_all < DM_DIG_FA_TH0)
ring = &rtlpci->tx_ring[BEACON_QUEUE];
pskb = __skb_dequeue(&ring->queue);
- if (pskb)
- kfree_skb(pskb);
+ kfree_skb(pskb);
spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
pdesc = &ring->desc[idx];
/* discard output from call below */
void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info, struct sk_buff *skb,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
- struct ieee80211_sta *sta = info->control.sta;
u8 *pdesc = pdesc_tx;
u16 seq_number;
__le16 fc = hdr->frame_control;
void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr,
u8 *pdesc, struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
bool rtl92de_rx_query_desc(struct ieee80211_hw *hw,
void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
- struct ieee80211_tx_info *info, struct sk_buff *skb,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- struct ieee80211_sta *sta = info->control.sta;
u8 *pdesc = pdesc_tx;
u16 seq_number;
__le16 fc = hdr->frame_control;
SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len);
/* DOWRD 8 */
- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
}
/* 92SE need not to set TX packet size when firmware download */
SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
wmb();
SET_TX_DESC_OWN(pdesc, 1);
SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq);
SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
wmb();
SET_TX_DESC_OWN(pdesc, 1);
void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
u8 *pdesc, struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg,
if (status < 0 && count++ < 4)
pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n",
- value, status, le32_to_cpu(*(u32 *)pdata));
+ value, status, *(u32 *)pdata);
return status;
}
_rtl_submit_tx_urb(hw, _urb);
}
-static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
- u16 hw_queue)
+static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ u16 hw_queue)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
seq_number += 1;
seq_number <<= 4;
}
- rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb,
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, sta, skb,
hw_queue, &tcb_desc);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
if (qc)
rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
}
-static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+static int rtl_usb_tx(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
struct rtl_tcb_desc *dummy)
{
struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
if (unlikely(is_hal_stop(rtlhal)))
goto err_free;
hw_queue = rtlusb->usb_mq_to_hwq(fc, skb_get_queue_mapping(skb));
- _rtl_usb_tx_preprocess(hw, skb, hw_queue);
+ _rtl_usb_tx_preprocess(hw, sta, skb, hw_queue);
_rtl_usb_transmit(hw, skb, hw_queue);
return NETDEV_TX_OK;
}
static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
struct sk_buff *skb)
{
return false;
EEPROM_BOOT_EFUSE,
};
-enum rtl_status {
+enum ttl_status {
RTL_STATUS_INTERFACE_START = 0,
};
HARDWARE_TYPE_RTL8192CU,
HARDWARE_TYPE_RTL8192DE,
HARDWARE_TYPE_RTL8192DU,
- HARDWARE_TYPE_RTL8723E,
+ HARDWARE_TYPE_RTL8723AE,
HARDWARE_TYPE_RTL8723U,
/* keep it last */
RSERVED_ENCRYPTION = 3,
AESCCMP_ENCRYPTION = 4,
WEP104_ENCRYPTION = 5,
+ AESCMAC_ENCRYPTION = 6, /*IEEE802.11w */
};
enum rtl_hal_state {
u32 adda_backup[16];
u32 iqk_mac_backup[IQK_MAC_REG_NUM];
u32 iqk_bb_backup[10];
+ bool iqk_initialized;
/* Dual mac */
bool need_iqk;
#define RTL_AGG_OPERATIONAL 3
#define RTL_AGG_OFF 0
#define RTL_AGG_ON 1
+#define RTL_RX_AGG_START 1
+#define RTL_RX_AGG_STOP 0
#define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2
#define RTL_AGG_EMPTYING_HW_QUEUE_DELBA 3
u64 bitmap;
u32 rate_n_flags;
u8 agg_state;
+ u8 rx_agg_state;
};
struct rtl_tid_data {
struct rtl_ht_agg agg;
};
+struct rssi_sta {
+ long undecorated_smoothed_pwdb;
+};
+
struct rtl_sta_info {
+ struct list_head list;
u8 ratr_index;
u8 wireless_mode;
u8 mimo_ps;
struct rtl_tid_data tids[MAX_TID_COUNT];
+
+ /* just used for ap adhoc or mesh*/
+ struct rssi_sta rssi_stat;
} __packed;
struct rtl_priv;
struct rtl_hal {
struct ieee80211_hw *hw;
+ bool up_first_time;
+ bool first_init;
+ bool being_init_adapter;
+ bool bbrf_ready;
+
enum intf_type interface;
u16 hw_type; /*92c or 92d or 92s and so on */
u8 ic_class;
u16 fw_subversion;
bool h2c_setinprogress;
u8 last_hmeboxnum;
+ bool fw_ready;
/*Reserve page start offset except beacon in TxQ. */
u8 fw_rsvdpage_startoffset;
u8 h2c_txcmd_seq;
bool load_imrandiqk_setting_for2g;
bool disable_amsdu_8k;
+ bool master_of_dmsp;
+ bool slave_of_dmsp;
};
struct rtl_security {
bool disable_tx_int;
char ofdm_index[2];
char cck_index;
+
+ /* DMSP */
+ bool supp_phymode_switch;
};
#define EFUSE_MAX_LOGICAL_SIZE 256
};
struct rt_link_detect {
+ /* count for roaming */
+ u32 bcn_rx_inperiod;
+ u32 roam_times;
+
u32 num_tx_in4period[4];
u32 num_rx_in4period[4];
u32 num_rx_inperiod;
bool busytraffic;
+ bool tx_busy_traffic;
+ bool rx_busy_traffic;
bool higher_busytraffic;
bool higher_busyrxtraffic;
void (*fill_tx_desc) (struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc,
u32 regaddr, u32 bitmask);
void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath,
u32 regaddr, u32 bitmask, u32 data);
+ void (*allow_all_destaddr)(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg);
void (*linked_set_reg) (struct ieee80211_hw *hw);
+ void (*check_switch_to_dmdp) (struct ieee80211_hw *hw);
+ void (*dualmac_easy_concurrent) (struct ieee80211_hw *hw);
+ void (*dualmac_switch_to_dmdp) (struct ieee80211_hw *hw);
bool (*phy_rf6052_config) (struct ieee80211_hw *hw);
void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw,
u8 *powerlevel);
void (*read_efuse_byte)(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf);
int (*adapter_start) (struct ieee80211_hw *hw);
void (*adapter_stop) (struct ieee80211_hw *hw);
+ bool (*check_buddy_priv)(struct ieee80211_hw *hw,
+ struct rtl_priv **buddy_priv);
- int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb,
- struct rtl_tcb_desc *ptcb_desc);
+ int (*adapter_tx) (struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ struct rtl_tcb_desc *ptcb_desc);
void (*flush)(struct ieee80211_hw *hw, bool drop);
int (*reset_trx_ring) (struct ieee80211_hw *hw);
- bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb);
+ bool (*waitq_insert) (struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb);
/*pci */
void (*disable_aspm) (struct ieee80211_hw *hw);
spinlock_t h2c_lock;
spinlock_t rf_ps_lock;
spinlock_t rf_lock;
+ spinlock_t lps_lock;
spinlock_t waitq_lock;
+ spinlock_t entry_list_lock;
spinlock_t usb_lock;
/*Dual mac*/
spinlock_t cck_and_rw_pagea_lock;
+
+ /*Easy concurrent*/
+ spinlock_t check_sendpkt_lock;
};
struct rtl_works {
/*timer */
struct timer_list watchdog_timer;
+ struct timer_list dualmac_easyconcurrent_retrytimer;
/*task */
struct tasklet_struct irq_tasklet;
char proc_name[20];
};
+#define MIMO_PS_STATIC 0
+#define MIMO_PS_DYNAMIC 1
+#define MIMO_PS_NOLIMIT 3
+
+struct rtl_dualmac_easy_concurrent_ctl {
+ enum band_type currentbandtype_backfordmdp;
+ bool close_bbandrf_for_dmsp;
+ bool change_to_dmdp;
+ bool change_to_dmsp;
+ bool switch_in_process;
+};
+
+struct rtl_dmsp_ctl {
+ bool activescan_for_slaveofdmsp;
+ bool scan_for_anothermac_fordmsp;
+ bool scan_for_itself_fordmsp;
+ bool writedig_for_anothermacofdmsp;
+ u32 curdigvalue_for_anothermacofdmsp;
+ bool changecckpdstate_for_anothermacofdmsp;
+ u8 curcckpdstate_for_anothermacofdmsp;
+ bool changetxhighpowerlvl_for_anothermacofdmsp;
+ u8 curtxhighlvl_for_anothermacofdmsp;
+ long rssivalmin_for_anothermacofdmsp;
+};
+
struct ps_t {
u8 pre_ccastate;
u8 cur_ccasate;
u8 dig_twoport_algorithm;
u8 dig_dbgmode;
u8 dig_slgorithm_switch;
- u8 cursta_connectctate;
+ u8 cursta_connectstate;
u8 presta_connectstate;
u8 curmultista_connectstate;
char backoff_val;
char backoffval_range_min;
};
+struct rtl_global_var {
+ /* from this list we can get
+ * other adapter's rtl_priv */
+ struct list_head glb_priv_list;
+ spinlock_t glb_list_lock;
+};
+
struct rtl_priv {
struct completion firmware_loading_complete;
+ struct list_head list;
+ struct rtl_priv *buddy_priv;
+ struct rtl_global_var *glb_var;
+ struct rtl_dualmac_easy_concurrent_ctl easy_concurrent_ctl;
+ struct rtl_dmsp_ctl dmsp_ctl;
struct rtl_locks locks;
struct rtl_works works;
struct rtl_mac mac80211;
struct rtl_rate_priv *rate_priv;
+ /* sta entry list for ap adhoc or mesh */
+ struct list_head entry_list;
+
struct rtl_debug dbg;
int max_fw_size;
EF1BYTE(*((u8 *)(_ptr)))
/* Read le16 data from memory and convert to host ordering */
#define READEF2BYTE(_ptr) \
- EF2BYTE(*((u16 *)(_ptr)))
+ EF2BYTE(*(_ptr))
#define READEF4BYTE(_ptr) \
- EF4BYTE(*((u32 *)(_ptr)))
+ EF4BYTE(*(_ptr))
/* Write data to memory */
#define WRITEEF1BYTE(_ptr, _val) \
#define WRITEEF2BYTE(_ptr, _val) \
(*((u16 *)(_ptr))) = EF2BYTE(_val)
#define WRITEEF4BYTE(_ptr, _val) \
- (*((u16 *)(_ptr))) = EF2BYTE(_val)
+ (*((u32 *)(_ptr))) = EF2BYTE(_val)
/* Create a bit mask
* Examples:
* 4-byte pointer in little-endian system.
*/
#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \
- (EF4BYTE(*((u32 *)(__pstart))))
+ (EF4BYTE(*((__le32 *)(__pstart))))
#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \
- (EF2BYTE(*((u16 *)(__pstart))))
+ (EF2BYTE(*((__le16 *)(__pstart))))
#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \
(EF1BYTE(*((u8 *)(__pstart))))
* Set subfield of little-endian 4-byte value to specified value.
*/
#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \
- *((u32 *)(__pstart)) = EF4BYTE \
+ *((u32 *)(__pstart)) = \
( \
LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \
);
#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
- *((u16 *)(__pstart)) = EF2BYTE \
+ *((u16 *)(__pstart)) = \
( \
LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \
return ieee80211_find_sta(vif, bssid);
}
+static inline struct ieee80211_sta *rtl_find_sta(struct ieee80211_hw *hw,
+ u8 *mac_addr)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ return ieee80211_find_sta(mac->vif, mac_addr);
+}
+
#endif
return ret;
}
-static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void wl1251_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct wl1251 *wl = hw->priv;
unsigned long flags;
#include "../wlcore/acx.h"
#include "../wlcore/tx.h"
#include "../wlcore/rx.h"
-#include "../wlcore/io.h"
#include "../wlcore/boot.h"
#include "reg.h"
return ret;
}
-static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void wl1271_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct wl1271 *wl = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
mapping = skb_get_queue_mapping(skb);
q = wl1271_tx_get_queue(mapping);
- hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
+ hlid = wl12xx_tx_get_hlid(wl, wlvif, skb, control->sta);
spin_lock_irqsave(&wl->wl_lock, flags);
}
EXPORT_SYMBOL(wl12xx_is_dummy_packet);
-u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct sk_buff *skb)
+static u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct sk_buff *skb, struct ieee80211_sta *sta)
{
- struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
-
- if (control->control.sta) {
+ if (sta) {
struct wl1271_station *wl_sta;
- wl_sta = (struct wl1271_station *)
- control->control.sta->drv_priv;
+ wl_sta = (struct wl1271_station *)sta->drv_priv;
return wl_sta->hlid;
} else {
struct ieee80211_hdr *hdr;
}
u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct sk_buff *skb)
+ struct sk_buff *skb, struct ieee80211_sta *sta)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
return wl->system_hlid;
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
- return wl12xx_tx_get_hlid_ap(wl, wlvif, skb);
+ return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta);
if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
/* caller must hold wl->mutex */
static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct sk_buff *skb, u32 buf_offset)
+ struct sk_buff *skb, u32 buf_offset, u8 hlid)
{
struct ieee80211_tx_info *info;
u32 extra = 0;
int ret = 0;
u32 total_len;
- u8 hlid;
bool is_dummy;
bool is_gem = false;
return -EINVAL;
}
+ if (hlid == WL12XX_INVALID_LINK_ID) {
+ wl1271_error("invalid hlid. dropping skb 0x%p", skb);
+ return -EINVAL;
+ }
+
info = IEEE80211_SKB_CB(skb);
- /* TODO: handle dummy packets on multi-vifs */
is_dummy = wl12xx_is_dummy_packet(wl, skb);
if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
is_gem = (cipher == WL1271_CIPHER_SUITE_GEM);
}
- hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
- if (hlid == WL12XX_INVALID_LINK_ID) {
- wl1271_error("invalid hlid. dropping skb 0x%p", skb);
- return -EINVAL;
- }
ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid,
is_gem);
}
static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
+ struct wl12xx_vif *wlvif,
+ u8 *hlid)
{
struct sk_buff *skb = NULL;
int i, h, start_hlid;
if (!skb)
wlvif->last_tx_hlid = 0;
+ *hlid = wlvif->last_tx_hlid;
return skb;
}
-static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
+static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid)
{
unsigned long flags;
struct wl12xx_vif *wlvif = wl->last_wlvif;
/* continue from last wlvif (round robin) */
if (wlvif) {
wl12xx_for_each_wlvif_continue(wl, wlvif) {
- skb = wl12xx_vif_skb_dequeue(wl, wlvif);
+ skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid);
if (skb) {
wl->last_wlvif = wlvif;
break;
}
/* dequeue from the system HLID before the restarting wlvif list */
- if (!skb)
+ if (!skb) {
skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
+ *hlid = wl->system_hlid;
+ }
/* do a new pass over the wlvif list */
if (!skb) {
wl12xx_for_each_wlvif(wl, wlvif) {
- skb = wl12xx_vif_skb_dequeue(wl, wlvif);
+ skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid);
if (skb) {
wl->last_wlvif = wlvif;
break;
int q;
skb = wl->dummy_packet;
+ *hlid = wl->system_hlid;
q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
}
static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct sk_buff *skb)
+ struct sk_buff *skb, u8 hlid)
{
unsigned long flags;
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
if (wl12xx_is_dummy_packet(wl, skb)) {
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
} else {
- u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
/* make sure we dequeue the same packet next time */
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
int ret = 0;
int bus_ret = 0;
+ u8 hlid;
if (unlikely(wl->state == WL1271_STATE_OFF))
return 0;
- while ((skb = wl1271_skb_dequeue(wl))) {
+ while ((skb = wl1271_skb_dequeue(wl, &hlid))) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
bool has_data = false;
wlvif = NULL;
if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif)
wlvif = wl12xx_vif_to_data(info->control.vif);
+ else
+ hlid = wl->system_hlid;
has_data = wlvif && wl1271_tx_is_data_present(skb);
- ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset);
+ ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset,
+ hlid);
if (ret == -EAGAIN) {
/*
* Aggregation buffer is full.
* Flush buffer and try again.
*/
- wl1271_skb_queue_head(wl, wlvif, skb);
+ wl1271_skb_queue_head(wl, wlvif, skb, hlid);
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
last_len);
* Firmware buffer is full.
* Queue back last skb, and stop aggregating.
*/
- wl1271_skb_queue_head(wl, wlvif, skb);
+ wl1271_skb_queue_head(wl, wlvif, skb, hlid);
/* No work left, avoid scheduling redundant tx work */
set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
goto out_ack;
* fw still expects dummy packet,
* so re-enqueue it
*/
- wl1271_skb_queue_head(wl, wlvif, skb);
+ wl1271_skb_queue_head(wl, wlvif, skb, hlid);
else
ieee80211_free_txskb(wl->hw, skb);
goto out_ack;
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
enum ieee80211_band rate_band);
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
-u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct sk_buff *skb);
u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct sk_buff *skb);
+ struct sk_buff *skb, struct ieee80211_sta *sta);
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
union iwreq_data *wrqu, char *extra)
{
struct wl3501_card *this = netdev_priv(dev);
- static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
int rc = -EINVAL;
/* FIXME: we support other ARPHRDs...*/
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
goto out;
- if (!memcmp(bcast, wrqu->ap_addr.sa_data, ETH_ALEN)) {
+ if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data)) {
/* FIXME: rescan? */
} else
memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
* control block of the skbuff will be initialized. If necessary the incoming
* mac80211 queues will be stopped.
*/
-static void zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void zd_op_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct zd_mac *mac = zd_hw_mac(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
skb = ieee80211_get_buffered_bc(mac->hw, mac->vif);
if (!skb)
break;
- zd_op_tx(mac->hw, skb);
+ zd_op_tx(mac->hw, NULL, skb);
}
/*
{
struct ssb_bus *bus = mcore->dev->bus;
- mcore->flash_buswidth = 2;
- if (bus->chipco.dev) {
- mcore->flash_window = 0x1c000000;
- mcore->flash_window_size = 0x02000000;
+ /* When there is no chipcommon on the bus there is 4MB flash */
+ if (!bus->chipco.dev) {
+ mcore->flash_buswidth = 2;
+ mcore->flash_window = SSB_FLASH1;
+ mcore->flash_window_size = SSB_FLASH1_SZ;
+ return;
+ }
+
+ /* There is ChipCommon, so use it to read info about flash */
+ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
+ case SSB_CHIPCO_FLASHT_STSER:
+ case SSB_CHIPCO_FLASHT_ATSER:
+ pr_err("Serial flash not supported\n");
+ break;
+ case SSB_CHIPCO_FLASHT_PARA:
+ pr_debug("Found parallel flash\n");
+ mcore->flash_window = SSB_FLASH2;
+ mcore->flash_window_size = SSB_FLASH2_SZ;
if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
& SSB_CHIPCO_CFG_DS16) == 0)
mcore->flash_buswidth = 1;
- } else {
- mcore->flash_window = 0x1fc00000;
- mcore->flash_window_size = 0x00400000;
+ else
+ mcore->flash_buswidth = 2;
+ break;
}
}
*total_flags = new_flags;
}
-static void wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
+static void wbsoft_tx(struct ieee80211_hw *dev,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct wbsoft_priv *priv = dev->priv;
#define BCMA_CC_CHIPST_4706_SFLASH_TYPE BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */
#define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */
#define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */
+#define BCMA_CC_CHIPST_5357_NAND_BOOT BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
#define BCMA_CC_JCMD_START 0x80000000
#define BCMA_CC_JCMD_BUSY 0x80000000
#define BCMA_CC_SROM_CONTROL_SIZE_16K 0x00000004
#define BCMA_CC_SROM_CONTROL_SIZE_SHIFT 1
#define BCMA_CC_SROM_CONTROL_PRESENT 0x00000001
+/* Block 0x140 - 0x190 registers are chipset specific */
+#define BCMA_CC_4706_FLASHSCFG 0x18C /* Flash struct configuration */
+#define BCMA_CC_4706_FLASHSCFG_MASK 0x000000ff
+#define BCMA_CC_4706_FLASHSCFG_SF1 0x00000001 /* 2nd serial flash present */
+#define BCMA_CC_4706_FLASHSCFG_PF1 0x00000002 /* 2nd parallel flash present */
+#define BCMA_CC_4706_FLASHSCFG_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */
+#define BCMA_CC_4706_FLASHSCFG_NF1 0x00000008 /* 2nd NAND flash present */
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_MASK 0x000000f0
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */
+#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */
+/* NAND flash registers for BCM4706 (corerev = 31) */
+#define BCMA_CC_NFLASH_CTL 0x01A0
+#define BCMA_CC_NFLASH_CTL_ERR 0x08000000
+#define BCMA_CC_NFLASH_CONF 0x01A4
+#define BCMA_CC_NFLASH_COL_ADDR 0x01A8
+#define BCMA_CC_NFLASH_ROW_ADDR 0x01AC
+#define BCMA_CC_NFLASH_DATA 0x01B0
+#define BCMA_CC_NFLASH_WAITCNT0 0x01B4
/* 0x1E0 is defined as shared BCMA_CLKCTLST */
#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
#define BCMA_CC_UART0_DATA 0x0300
#define BCMA_CC_PLLCTL_ADDR 0x0660
#define BCMA_CC_PLLCTL_DATA 0x0664
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
+/* NAND flash MLC controller registers (corerev >= 38) */
+#define BCMA_CC_NAND_REVISION 0x0C00
+#define BCMA_CC_NAND_CMD_START 0x0C04
+#define BCMA_CC_NAND_CMD_ADDR_X 0x0C08
+#define BCMA_CC_NAND_CMD_ADDR 0x0C0C
+#define BCMA_CC_NAND_CMD_END_ADDR 0x0C10
+#define BCMA_CC_NAND_CS_NAND_SELECT 0x0C14
+#define BCMA_CC_NAND_CS_NAND_XOR 0x0C18
+#define BCMA_CC_NAND_SPARE_RD0 0x0C20
+#define BCMA_CC_NAND_SPARE_RD4 0x0C24
+#define BCMA_CC_NAND_SPARE_RD8 0x0C28
+#define BCMA_CC_NAND_SPARE_RD12 0x0C2C
+#define BCMA_CC_NAND_SPARE_WR0 0x0C30
+#define BCMA_CC_NAND_SPARE_WR4 0x0C34
+#define BCMA_CC_NAND_SPARE_WR8 0x0C38
+#define BCMA_CC_NAND_SPARE_WR12 0x0C3C
+#define BCMA_CC_NAND_ACC_CONTROL 0x0C40
+#define BCMA_CC_NAND_CONFIG 0x0C48
+#define BCMA_CC_NAND_TIMING_1 0x0C50
+#define BCMA_CC_NAND_TIMING_2 0x0C54
+#define BCMA_CC_NAND_SEMAPHORE 0x0C58
+#define BCMA_CC_NAND_DEVID 0x0C60
+#define BCMA_CC_NAND_DEVID_X 0x0C64
+#define BCMA_CC_NAND_BLOCK_LOCK_STATUS 0x0C68
+#define BCMA_CC_NAND_INTFC_STATUS 0x0C6C
+#define BCMA_CC_NAND_ECC_CORR_ADDR_X 0x0C70
+#define BCMA_CC_NAND_ECC_CORR_ADDR 0x0C74
+#define BCMA_CC_NAND_ECC_UNC_ADDR_X 0x0C78
+#define BCMA_CC_NAND_ECC_UNC_ADDR 0x0C7C
+#define BCMA_CC_NAND_READ_ERROR_COUNT 0x0C80
+#define BCMA_CC_NAND_CORR_STAT_THRESHOLD 0x0C84
+#define BCMA_CC_NAND_READ_ADDR_X 0x0C90
+#define BCMA_CC_NAND_READ_ADDR 0x0C94
+#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR_X 0x0C98
+#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR 0x0C9C
+#define BCMA_CC_NAND_COPY_BACK_ADDR_X 0x0CA0
+#define BCMA_CC_NAND_COPY_BACK_ADDR 0x0CA4
+#define BCMA_CC_NAND_BLOCK_ERASE_ADDR_X 0x0CA8
+#define BCMA_CC_NAND_BLOCK_ERASE_ADDR 0x0CAC
+#define BCMA_CC_NAND_INV_READ_ADDR_X 0x0CB0
+#define BCMA_CC_NAND_INV_READ_ADDR 0x0CB4
+#define BCMA_CC_NAND_BLK_WR_PROTECT 0x0CC0
+#define BCMA_CC_NAND_ACC_CONTROL_CS1 0x0CD0
+#define BCMA_CC_NAND_CONFIG_CS1 0x0CD4
+#define BCMA_CC_NAND_TIMING_1_CS1 0x0CD8
+#define BCMA_CC_NAND_TIMING_2_CS1 0x0CDC
+#define BCMA_CC_NAND_SPARE_RD16 0x0D30
+#define BCMA_CC_NAND_SPARE_RD20 0x0D34
+#define BCMA_CC_NAND_SPARE_RD24 0x0D38
+#define BCMA_CC_NAND_SPARE_RD28 0x0D3C
+#define BCMA_CC_NAND_CACHE_ADDR 0x0D40
+#define BCMA_CC_NAND_CACHE_DATA 0x0D44
+#define BCMA_CC_NAND_CTRL_CONFIG 0x0D48
+#define BCMA_CC_NAND_CTRL_STATUS 0x0D4C
/* Divider allocation in 4716/47162/5356 */
#define BCMA_CC_PMU5_MAINPLL_CPU 1
/* 4313 Chip specific ChipControl register bits */
#define BCMA_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
+/* BCM5357 ChipControl register bits */
+#define BCMA_CHIPCTL_5357_EXTPA BIT(14)
+#define BCMA_CHIPCTL_5357_ANT_MUX_2O3 BIT(15)
+#define BCMA_CHIPCTL_5357_NFLASH BIT(16)
+#define BCMA_CHIPCTL_5357_I2S_PINS_ENABLE BIT(18)
+#define BCMA_CHIPCTL_5357_I2CSPI_PINS_ENABLE BIT(19)
+
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
u32 window_size;
};
+#ifdef CONFIG_BCMA_SFLASH
+struct bcma_sflash {
+ bool present;
+ u32 window;
+ u32 blocksize;
+ u16 numblocks;
+ u32 size;
+};
+#endif
+
+#ifdef CONFIG_BCMA_NFLASH
+struct mtd_info;
+
+struct bcma_nflash {
+ bool present;
+
+ struct mtd_info *mtd;
+};
+#endif
+
struct bcma_serial_port {
void *regs;
unsigned long clockspeed;
struct bcma_chipcommon_pmu pmu;
#ifdef CONFIG_BCMA_DRIVER_MIPS
struct bcma_pflash pflash;
+#ifdef CONFIG_BCMA_SFLASH
+ struct bcma_sflash sflash;
+#endif
+#ifdef CONFIG_BCMA_NFLASH
+ struct bcma_nflash nflash;
+#endif
int nr_serial_ports;
struct bcma_serial_port serial_ports[4];
#define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
#define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
#define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */
+#define BCMA_CLKCTLST_EXTRESREQ_SHIFT 8
#define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */
#define BCMA_CLKCTLST_HAVEHT 0x00020000 /* HT available */
#define BCMA_CLKCTLST_BP_ON_ALP 0x00040000 /* RO: running on ALP clock */
#define BCMA_CLKCTLST_BP_ON_HT 0x00080000 /* RO: running on HT clock */
#define BCMA_CLKCTLST_EXTRESST 0x07000000 /* Mask of external resource status */
+#define BCMA_CLKCTLST_EXTRESST_SHIFT 24
/* Is there any BCM4328 on BCMA bus? */
#define BCMA_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */
#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */
* (2 ZettaBytes), high 32 bits
*/
+#define BCMA_SFLASH 0x1c000000
+
#endif /* LINUX_BCMA_REGS_H_ */
* %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
* %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
*
+ * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
+ * its %NL80211_ATTR_WDEV identifier. It must have been created with
+ * %NL80211_CMD_NEW_INTERFACE previously. After it has been started, the
+ * P2P Device can be used for P2P operations, e.g. remain-on-channel and
+ * public action frame TX.
+ * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by
+ * its %NL80211_ATTR_WDEV identifier.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
NL80211_CMD_CH_SWITCH_NOTIFY,
+ NL80211_CMD_START_P2P_DEVICE,
+ NL80211_CMD_STOP_P2P_DEVICE,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
* @NL80211_IFTYPE_MESH_POINT: mesh point
* @NL80211_IFTYPE_P2P_CLIENT: P2P client
* @NL80211_IFTYPE_P2P_GO: P2P group owner
+ * @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev
+ * and therefore can't be created in the normal ways, use the
+ * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
+ * commands to create and destroy one
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
NL80211_IFTYPE_MESH_POINT,
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
+ NL80211_IFTYPE_P2P_DEVICE,
/* keep last */
NUM_NL80211_IFTYPES,
* @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
* to work properly to suppport receiving regulatory hints from
* cellular base stations.
+ * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active
+ * P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel
+ * in the interface combinations, even when it's only used for scan
+ * and remain-on-channel. This could be due to, for example, the
+ * remain-on-channel implementation requiring a channel context.
*/
enum nl80211_feature_flags {
- NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
- NL80211_FEATURE_HT_IBSS = 1 << 1,
- NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
- NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
+ NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
+ NL80211_FEATURE_HT_IBSS = 1 << 1,
+ NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
+ NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
+ NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4,
};
/**
}
#endif /* RFKILL || RFKILL_MODULE */
+
+#ifdef CONFIG_RFKILL_LEDS
+/**
+ * rfkill_get_led_trigger_name - Get the LED trigger name for the button's LED.
+ * This function might return a NULL pointer if registering of the
+ * LED trigger failed. Use this as "default_trigger" for the LED.
+ */
+const char *rfkill_get_led_trigger_name(struct rfkill *rfkill);
+
+/**
+ * rfkill_set_led_trigger_name -- set the LED trigger name
+ * @rfkill: rfkill struct
+ * @name: LED trigger name
+ *
+ * This function sets the LED trigger name of the radio LED
+ * trigger that rfkill creates. It is optional, but if called
+ * must be called before rfkill_register() to be effective.
+ */
+void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name);
+#else
+static inline const char *rfkill_get_led_trigger_name(struct rfkill *rfkill)
+{
+ return NULL;
+}
+
+static inline void
+rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name)
+{
+}
+#endif
+
#endif /* __KERNEL__ */
#endif /* RFKILL_H */
#define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
#define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
-#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
+#define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
+#define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
+#define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
/* Status register bits for ST flashes */
#define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
#include <linux/poll.h>
#include <net/sock.h>
+#include <linux/seq_file.h>
#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH 31
struct bt_sock_list {
struct hlist_head head;
rwlock_t lock;
+#ifdef CONFIG_PROC_FS
+ struct file_operations fops;
+ int (* custom_seq_show)(struct seq_file *, void *);
+#endif
};
int bt_sock_register(int proto, const struct net_proto_family *ops);
extern int bt_sysfs_init(void);
extern void bt_sysfs_cleanup(void);
+extern int bt_procfs_init(struct module* module, struct net *net, const char *name,
+ struct bt_sock_list* sk_list,
+ int (* seq_show)(struct seq_file *, void *));
+extern void bt_procfs_cleanup(struct net *net, const char *name);
+
extern struct dentry *bt_debugfs;
int l2cap_init(void);
/* First BR/EDR Controller shall have ID = 0 */
#define HCI_BREDR_ID 0
+/* AMP controller status */
+#define AMP_CTRL_POWERED_DOWN 0x00
+#define AMP_CTRL_BLUETOOTH_ONLY 0x01
+#define AMP_CTRL_NO_CAPACITY 0x02
+#define AMP_CTRL_LOW_CAPACITY 0x03
+#define AMP_CTRL_MEDIUM_CAPACITY 0x04
+#define AMP_CTRL_HIGH_CAPACITY 0x05
+#define AMP_CTRL_FULL_CAPACITY 0x06
+
/* HCI device quirks */
enum {
HCI_QUIRK_RESET_ON_CLOSE,
} __packed;
/* Low energy meta events */
+#define LE_CONN_ROLE_MASTER 0x00
+
#define HCI_EV_LE_CONN_COMPLETE 0x01
struct hci_ev_le_conn_complete {
__u8 status;
u8 randomizer[16];
};
-struct adv_entry {
- struct list_head list;
- bdaddr_t bdaddr;
- u8 bdaddr_type;
-};
-
struct le_scan_params {
u8 type;
u16 interval;
/* ----- HCI interface to upper protocols ----- */
extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
-extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
+extern void l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
extern int l2cap_disconn_ind(struct hci_conn *hcon);
-extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
+extern void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
u16 flags);
extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
-extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
-extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
+extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status);
+extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
/* ----- Inquiry cache ----- */
static inline void hci_conn_hold(struct hci_conn *conn)
{
- BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt),
- atomic_read(&conn->refcnt) + 1);
+ BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
atomic_inc(&conn->refcnt);
cancel_delayed_work(&conn->disc_work);
static inline void hci_conn_put(struct hci_conn *conn)
{
- BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt),
- atomic_read(&conn->refcnt) - 1);
+ BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo;
int mgmt_interleaved_discovery(struct hci_dev *hdev);
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
-
+bool mgmt_valid_hdev(struct hci_dev *hdev);
int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
/* HCI info for socket */
L2CAP_EV_RECV_FRAME,
};
-static inline void l2cap_chan_hold(struct l2cap_chan *c)
-{
- BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
-
- atomic_inc(&c->refcnt);
-}
-
-static inline void l2cap_chan_put(struct l2cap_chan *c)
-{
- BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
-
- if (atomic_dec_and_test(&c->refcnt))
- kfree(c);
-}
+void l2cap_chan_hold(struct l2cap_chan *c);
+void l2cap_chan_put(struct l2cap_chan *c);
static inline void l2cap_chan_lock(struct l2cap_chan *chan)
{
struct l2cap_chan *l2cap_chan_create(void);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
-void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
bdaddr_t *dst, u8 dst_type);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
#define SMP_CONFIRM_FAILED 0x04
#define SMP_PAIRING_NOTSUPP 0x05
#define SMP_ENC_KEY_SIZE 0x06
-#define SMP_CMD_NOTSUPP 0x07
-#define SMP_UNSPECIFIED 0x08
+#define SMP_CMD_NOTSUPP 0x07
+#define SMP_UNSPECIFIED 0x08
#define SMP_REPEATED_ATTEMPTS 0x09
#define SMP_MIN_ENC_KEY_SIZE 7
struct l2cap_conn *conn;
u8 preq[7]; /* SMP Pairing Request */
u8 prsp[7]; /* SMP Pairing Response */
- u8 prnd[16]; /* SMP Pairing Random (local) */
- u8 rrnd[16]; /* SMP Pairing Random (remote) */
+ u8 prnd[16]; /* SMP Pairing Random (local) */
+ u8 rrnd[16]; /* SMP Pairing Random (remote) */
u8 pcnf[16]; /* SMP Pairing Confirm */
u8 tk[16]; /* SMP Temporary Key */
u8 enc_key_size;
* rates" IE, i.e. CCK rates first, then OFDM.
* @n_bitrates: Number of bitrates in @bitrates
* @ht_cap: HT capabilities in this band
+ * @vht_cap: VHT capabilities in this band
*/
struct ieee80211_supported_band {
struct ieee80211_channel *channels;
* @add_virtual_intf: create a new virtual interface with the given name,
* must set the struct wireless_dev's iftype. Beware: You must create
* the new netdev in the wiphy's network namespace! Returns the struct
- * wireless_dev, or an ERR_PTR.
+ * wireless_dev, or an ERR_PTR. For P2P device wdevs, the driver must
+ * also set the address member in the wdev.
*
* @del_virtual_intf: remove the virtual interface
*
* @get_channel: Get the current operating channel for the virtual interface.
* For monitor interfaces, it should return %NULL unless there's a single
* current monitoring channel.
+ *
+ * @start_p2p_device: Start the given P2P device.
+ * @stop_p2p_device: Stop the given P2P device.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
(*get_channel)(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_channel_type *type);
+
+ int (*start_p2p_device)(struct wiphy *wiphy,
+ struct wireless_dev *wdev);
+ void (*stop_p2p_device)(struct wiphy *wiphy,
+ struct wireless_dev *wdev);
};
/*
* @cleanup_work: work struct used for cleanup that can't be done directly
* @beacon_interval: beacon interval used on this device for transmitting
* beacons, 0 when not valid
+ * @address: The address for this device, valid only if @netdev is %NULL
+ * @p2p_started: true if this is a P2P Device that has been started
*/
struct wireless_dev {
struct wiphy *wiphy;
struct work_struct cleanup_work;
- bool use_4addr;
+ bool use_4addr, p2p_started;
+
+ u8 address[ETH_ALEN] __aligned(sizeof(u16));
/* currently used for IBSS and SME - might be rearranged later */
u8 ssid[IEEE80211_MAX_SSID_LEN];
#endif
};
+static inline u8 *wdev_address(struct wireless_dev *wdev)
+{
+ if (wdev->netdev)
+ return wdev->netdev->dev_addr;
+ return wdev->address;
+}
+
/**
* wdev_priv - return wiphy priv from wireless_dev
*
*/
u32 cfg80211_calculate_bitrate(struct rate_info *rate);
+/**
+ * cfg80211_unregister_wdev - remove the given wdev
+ * @wdev: struct wireless_dev to remove
+ *
+ * Call this function only for wdevs that have no netdev assigned,
+ * e.g. P2P Devices. It removes the device from the list so that
+ * it can no longer be used. It is necessary to call this function
+ * even when cfg80211 requests the removal of the interface by
+ * calling the del_virtual_intf() callback. The function must also
+ * be called when the driver wishes to unregister the wdev, e.g.
+ * when the device is unbound from the driver.
+ *
+ * Requires the RTNL to be held.
+ */
+void cfg80211_unregister_wdev(struct wireless_dev *wdev);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
* Contains a bitmap of known fields/flags, the flags, and
* the MCS index.
*
+ * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitless
+ *
+ * Contains the AMPDU information for the subframe.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
IEEE80211_RADIOTAP_MCS = 19,
+ IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
/* valid in every it_present bitmap, even vendor namespaces */
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
+/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
+#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
+#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
+#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
+#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
+#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
+#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
/* helpers */
static inline int ieee80211_get_radiotap_len(unsigned char *data)
* @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
* @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
* @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
+ * @BSS_CHANGED_PS: PS changed for this BSS (STA mode)
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
BSS_CHANGED_IDLE = 1<<14,
BSS_CHANGED_SSID = 1<<15,
BSS_CHANGED_AP_PROBE_RESP = 1<<16,
+ BSS_CHANGED_PS = 1<<17,
/* when adding here, make sure to change ieee80211_reconfig */
};
* @idle: This interface is idle. There's also a global idle flag in the
* hardware config which may be more appropriate depending on what
* your driver/device needs to do.
+ * @ps: power-save mode (STA only). This flag is NOT affected by
+ * offchannel/dynamic_ps operations.
* @ssid: The SSID of the current vif. Only valid in AP-mode.
* @ssid_len: Length of SSID given in @ssid.
* @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
bool arp_filter_enabled;
bool qos;
bool idle;
+ bool ps;
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
bool hidden_ssid;
* (2) driver internal use (if applicable)
* (3) TX status information - driver tells mac80211 what happened
*
- * The TX control's sta pointer is only valid during the ->tx call,
- * it may be NULL.
- *
* @flags: transmit info flags, defined above
* @band: the band to transmit on (use for checking for races)
* @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
struct ieee80211_tx_rate rates[
IEEE80211_TX_MAX_RATES];
s8 rts_cts_rate_idx;
+ /* 3 bytes free */
};
/* only needed before rate control */
unsigned long jiffies;
/* NB: vif can be NULL for injected frames */
struct ieee80211_vif *vif;
struct ieee80211_key_conf *hw_key;
- struct ieee80211_sta *sta;
+ /* 8 bytes free */
} control;
struct {
struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
* @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if
* the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT
* to hw.radiotap_mcs_details to advertise that fact
+ * @RX_FLAG_AMPDU_DETAILS: A-MPDU details are known, in particular the reference
+ * number (@ampdu_reference) must be populated and be a distinct number for
+ * each A-MPDU
+ * @RX_FLAG_AMPDU_REPORT_ZEROLEN: driver reports 0-length subframes
+ * @RX_FLAG_AMPDU_IS_ZEROLEN: This is a zero-length subframe, for
+ * monitoring purposes only
+ * @RX_FLAG_AMPDU_LAST_KNOWN: last subframe is known, should be set on all
+ * subframes of a single A-MPDU
+ * @RX_FLAG_AMPDU_IS_LAST: this subframe is the last subframe of the A-MPDU
+ * @RX_FLAG_AMPDU_DELIM_CRC_ERROR: A delimiter CRC error has been detected
+ * on this subframe
+ * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
+ * is stored in the @ampdu_delimiter_crc field)
*/
enum mac80211_rx_flags {
- RX_FLAG_MMIC_ERROR = 1<<0,
- RX_FLAG_DECRYPTED = 1<<1,
- RX_FLAG_MMIC_STRIPPED = 1<<3,
- RX_FLAG_IV_STRIPPED = 1<<4,
- RX_FLAG_FAILED_FCS_CRC = 1<<5,
- RX_FLAG_FAILED_PLCP_CRC = 1<<6,
- RX_FLAG_MACTIME_MPDU = 1<<7,
- RX_FLAG_SHORTPRE = 1<<8,
- RX_FLAG_HT = 1<<9,
- RX_FLAG_40MHZ = 1<<10,
- RX_FLAG_SHORT_GI = 1<<11,
- RX_FLAG_NO_SIGNAL_VAL = 1<<12,
- RX_FLAG_HT_GF = 1<<13,
+ RX_FLAG_MMIC_ERROR = BIT(0),
+ RX_FLAG_DECRYPTED = BIT(1),
+ RX_FLAG_MMIC_STRIPPED = BIT(3),
+ RX_FLAG_IV_STRIPPED = BIT(4),
+ RX_FLAG_FAILED_FCS_CRC = BIT(5),
+ RX_FLAG_FAILED_PLCP_CRC = BIT(6),
+ RX_FLAG_MACTIME_MPDU = BIT(7),
+ RX_FLAG_SHORTPRE = BIT(8),
+ RX_FLAG_HT = BIT(9),
+ RX_FLAG_40MHZ = BIT(10),
+ RX_FLAG_SHORT_GI = BIT(11),
+ RX_FLAG_NO_SIGNAL_VAL = BIT(12),
+ RX_FLAG_HT_GF = BIT(13),
+ RX_FLAG_AMPDU_DETAILS = BIT(14),
+ RX_FLAG_AMPDU_REPORT_ZEROLEN = BIT(15),
+ RX_FLAG_AMPDU_IS_ZEROLEN = BIT(16),
+ RX_FLAG_AMPDU_LAST_KNOWN = BIT(17),
+ RX_FLAG_AMPDU_IS_LAST = BIT(18),
+ RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19),
+ RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(20),
};
/**
* HT rates are use (RX_FLAG_HT)
* @flag: %RX_FLAG_*
* @rx_flags: internal RX flags for mac80211
+ * @ampdu_reference: A-MPDU reference number, must be a different value for
+ * each A-MPDU but the same for each subframe within one A-MPDU
+ * @ampdu_delimiter_crc: A-MPDU delimiter CRC
*/
struct ieee80211_rx_status {
u64 mactime;
u32 device_timestamp;
- u16 flag;
+ u32 ampdu_reference;
+ u32 flag;
u16 freq;
u8 rate_idx;
u8 rx_flags;
u8 band;
u8 antenna;
s8 signal;
+ u8 ampdu_delimiter_crc;
};
/**
STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE,
};
+/**
+ * struct ieee80211_tx_control - TX control data
+ *
+ * @sta: station table entry, this sta pointer may be NULL and
+ * it is not allowed to copy the pointer, due to RCU.
+ */
+struct ieee80211_tx_control {
+ struct ieee80211_sta *sta;
+};
+
/**
* enum ieee80211_hw_flags - hardware flags
*
* queue mapping in order to use different queues (not just one per AC)
* for different virtual interfaces. See the doc section on HW queue
* control for more details.
+ *
+ * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any
+ * P2P Interface. This will be honoured even if more than one interface
+ * is supported.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
IEEE80211_HW_AP_LINK_PS = 1<<22,
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23,
IEEE80211_HW_SCAN_WHILE_IDLE = 1<<24,
+ IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25,
};
/**
* @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit
* to this station changed.
* @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed.
+ * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer
+ * changed (in IBSS mode) due to discovering more information about
+ * the peer.
*/
enum ieee80211_rate_control_changed {
IEEE80211_RC_BW_CHANGED = BIT(0),
IEEE80211_RC_SMPS_CHANGED = BIT(1),
+ IEEE80211_RC_SUPP_RATES_CHANGED = BIT(2),
};
/**
* The callback is optional and can (should!) sleep.
*/
struct ieee80211_ops {
- void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
+ void (*tx)(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw);
#ifdef CONFIG_PM
static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
- BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+ BT_DBG("ident %d code 0x%2.2x", hdr->ident, hdr->code);
skb_pull(skb, le16_to_cpu(hdr->len));
return 0;
/* Handle A2MP signalling */
static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
{
- struct a2mp_cmd *hdr = (void *) skb->data;
+ struct a2mp_cmd *hdr;
struct amp_mgr *mgr = chan->data;
int err = 0;
amp_mgr_get(mgr);
while (skb->len >= sizeof(*hdr)) {
- struct a2mp_cmd *hdr = (void *) skb->data;
- u16 len = le16_to_cpu(hdr->len);
+ u16 len;
- BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+ hdr = (void *) skb->data;
+ len = le16_to_cpu(hdr->len);
+
+ BT_DBG("code 0x%2.2x id %d len %u", hdr->code, hdr->ident, len);
skb_pull(skb, sizeof(*hdr));
if (err) {
struct a2mp_cmd_rej rej;
+
rej.reason = __constant_cpu_to_le16(0);
+ hdr = (void *) skb->data;
BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
static void a2mp_chan_close_cb(struct l2cap_chan *chan)
{
- l2cap_chan_destroy(chan);
+ l2cap_chan_put(chan);
}
static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
#include <asm/ioctls.h>
#include <net/bluetooth/bluetooth.h>
+#include <linux/proc_fs.h>
#define VERSION "2.16"
}
EXPORT_SYMBOL(bt_sock_wait_state);
+#ifdef CONFIG_PROC_FS
+struct bt_seq_state {
+ struct bt_sock_list *l;
+};
+
+static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(seq->private->l->lock)
+{
+ struct bt_seq_state *s = seq->private;
+ struct bt_sock_list *l = s->l;
+
+ read_lock(&l->lock);
+ return seq_hlist_start_head(&l->head, *pos);
+}
+
+static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct bt_seq_state *s = seq->private;
+ struct bt_sock_list *l = s->l;
+
+ return seq_hlist_next(v, &l->head, pos);
+}
+
+static void bt_seq_stop(struct seq_file *seq, void *v)
+ __releases(seq->private->l->lock)
+{
+ struct bt_seq_state *s = seq->private;
+ struct bt_sock_list *l = s->l;
+
+ read_unlock(&l->lock);
+}
+
+static int bt_seq_show(struct seq_file *seq, void *v)
+{
+ struct sock *sk;
+ struct bt_sock *bt;
+ struct bt_seq_state *s = seq->private;
+ struct bt_sock_list *l = s->l;
+ bdaddr_t src_baswapped, dst_baswapped;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent");
+
+ if (l->custom_seq_show) {
+ seq_putc(seq, ' ');
+ l->custom_seq_show(seq, v);
+ }
+
+ seq_putc(seq, '\n');
+ } else {
+ sk = sk_entry(v);
+ bt = bt_sk(sk);
+ baswap(&src_baswapped, &bt->src);
+ baswap(&dst_baswapped, &bt->dst);
+
+ seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu",
+ sk,
+ atomic_read(&sk->sk_refcnt),
+ sk_rmem_alloc_get(sk),
+ sk_wmem_alloc_get(sk),
+ sock_i_uid(sk),
+ sock_i_ino(sk),
+ &src_baswapped,
+ &dst_baswapped,
+ bt->parent? sock_i_ino(bt->parent): 0LU);
+
+ if (l->custom_seq_show) {
+ seq_putc(seq, ' ');
+ l->custom_seq_show(seq, v);
+ }
+
+ seq_putc(seq, '\n');
+ }
+ return 0;
+}
+
+static struct seq_operations bt_seq_ops = {
+ .start = bt_seq_start,
+ .next = bt_seq_next,
+ .stop = bt_seq_stop,
+ .show = bt_seq_show,
+};
+
+static int bt_seq_open(struct inode *inode, struct file *file)
+{
+ struct bt_sock_list *sk_list;
+ struct bt_seq_state *s;
+
+ sk_list = PDE(inode)->data;
+ s = __seq_open_private(file, &bt_seq_ops,
+ sizeof(struct bt_seq_state));
+ if (s == NULL)
+ return -ENOMEM;
+
+ s->l = sk_list;
+ return 0;
+}
+
+int bt_procfs_init(struct module* module, struct net *net, const char *name,
+ struct bt_sock_list* sk_list,
+ int (* seq_show)(struct seq_file *, void *))
+{
+ struct proc_dir_entry * pde;
+
+ sk_list->custom_seq_show = seq_show;
+
+ sk_list->fops.owner = module;
+ sk_list->fops.open = bt_seq_open;
+ sk_list->fops.read = seq_read;
+ sk_list->fops.llseek = seq_lseek;
+ sk_list->fops.release = seq_release_private;
+
+ pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
+ if (pde == NULL)
+ return -ENOMEM;
+
+ pde->data = sk_list;
+
+ return 0;
+}
+
+void bt_procfs_cleanup(struct net *net, const char *name)
+{
+ proc_net_remove(net, name);
+}
+#else
+int bt_procfs_init(struct module* module, struct net *net, const char *name,
+ struct bt_sock_list* sk_list,
+ int (* seq_show)(struct seq_file *, void *))
+{
+ return 0;
+}
+
+void bt_procfs_cleanup(struct net *net, const char *name)
+{
+}
+#endif
+EXPORT_SYMBOL(bt_procfs_init);
+EXPORT_SYMBOL(bt_procfs_cleanup);
+
static struct net_proto_family bt_sock_family_ops = {
.owner = THIS_MODULE,
.family = PF_BLUETOOTH,
#include "bnep.h"
+static struct bt_sock_list bnep_sk_list = {
+ .lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
+};
+
static int bnep_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
if (!sk)
return 0;
+ bt_sock_unlink(&bnep_sk_list, sk);
+
sock_orphan(sk);
sock_put(sk);
return 0;
sk->sk_protocol = protocol;
sk->sk_state = BT_OPEN;
+ bt_sock_link(&bnep_sk_list, sk);
return 0;
}
return err;
err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
- if (err < 0)
+ if (err < 0) {
+ BT_ERR("Can't register BNEP socket");
goto error;
+ }
+
+ err = bt_procfs_init(THIS_MODULE, &init_net, "bnep", &bnep_sk_list, NULL);
+ if (err < 0) {
+ BT_ERR("Failed to create BNEP proc file");
+ bt_sock_unregister(BTPROTO_BNEP);
+ goto error;
+ }
+
+ BT_INFO("BNEP socket layer initialized");
return 0;
error:
- BT_ERR("Can't register BNEP socket");
proto_unregister(&bnep_proto);
return err;
}
void __exit bnep_sock_cleanup(void)
{
+ bt_procfs_cleanup(&init_net, "bnep");
if (bt_sock_unregister(BTPROTO_BNEP) < 0)
BT_ERR("Can't unregister BNEP socket");
#include "cmtp.h"
+static struct bt_sock_list cmtp_sk_list = {
+ .lock = __RW_LOCK_UNLOCKED(cmtp_sk_list.lock)
+};
+
static int cmtp_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
if (!sk)
return 0;
+ bt_sock_unlink(&cmtp_sk_list, sk);
+
sock_orphan(sk);
sock_put(sk);
sk->sk_protocol = protocol;
sk->sk_state = BT_OPEN;
+ bt_sock_link(&cmtp_sk_list, sk);
+
return 0;
}
return err;
err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
- if (err < 0)
+ if (err < 0) {
+ BT_ERR("Can't register CMTP socket");
goto error;
+ }
+
+ err = bt_procfs_init(THIS_MODULE, &init_net, "cmtp", &cmtp_sk_list, NULL);
+ if (err < 0) {
+ BT_ERR("Failed to create CMTP proc file");
+ bt_sock_unregister(BTPROTO_HIDP);
+ goto error;
+ }
+
+ BT_INFO("CMTP socket layer initialized");
return 0;
error:
- BT_ERR("Can't register CMTP socket");
proto_unregister(&cmtp_proto);
return err;
}
void cmtp_cleanup_sockets(void)
{
+ bt_procfs_cleanup(&init_net, "cmtp");
if (bt_sock_unregister(BTPROTO_CMTP) < 0)
BT_ERR("Can't unregister CMTP socket");
hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
- if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
+ if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
+ mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
mgmt_powered(hdev, 1);
hci_dev_unlock(hdev);
* and no tasks are scheduled. */
hdev->close(hdev);
- if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
+ if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
+ mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
mgmt_powered(hdev, 0);
hci_dev_unlock(hdev);
if (hdev->features[3] & LMP_RSSI_INQ)
events[4] |= 0x02; /* Inquiry Result with RSSI */
- if (hdev->features[5] & LMP_SNIFF_SUBR)
+ if (lmp_sniffsubr_capable(hdev))
events[5] |= 0x20; /* Sniff Subrating */
if (hdev->features[5] & LMP_PAUSE_ENC)
if (hdev->features[6] & LMP_EXT_INQ)
events[5] |= 0x40; /* Extended Inquiry Result */
- if (hdev->features[6] & LMP_NO_FLUSH)
+ if (lmp_no_flush_capable(hdev))
events[7] |= 0x01; /* Enhanced Flush Complete */
if (hdev->features[7] & LMP_LSTO)
events[6] |= 0x80; /* Link Supervision Timeout Changed */
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
+ if (lmp_ssp_capable(hdev)) {
events[6] |= 0x01; /* IO Capability Request */
events[6] |= 0x02; /* IO Capability Response */
events[6] |= 0x04; /* User Confirmation Request */
* Features Notification */
}
- if (hdev->features[4] & LMP_LE)
+ if (lmp_le_capable(hdev))
events[7] |= 0x20; /* LE Meta-Event */
hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
struct hci_cp_write_def_link_policy cp;
u16 link_policy = 0;
- if (hdev->features[0] & LMP_RSWITCH)
+ if (lmp_rswitch_capable(hdev))
link_policy |= HCI_LP_RSWITCH;
if (hdev->features[0] & LMP_HOLD)
link_policy |= HCI_LP_HOLD;
- if (hdev->features[0] & LMP_SNIFF)
+ if (lmp_sniff_capable(hdev))
link_policy |= HCI_LP_SNIFF;
if (hdev->features[1] & LMP_PARK)
link_policy |= HCI_LP_PARK;
hdev->esco_type |= (ESCO_HV3);
}
- if (hdev->features[3] & LMP_ESCO)
+ if (lmp_esco_capable(hdev))
hdev->esco_type |= (ESCO_EV3);
if (hdev->features[4] & LMP_EV4)
break;
}
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
+ if (test_bit(HCI_INIT, &hdev->flags) && lmp_le_capable(hdev))
hci_set_le_support(hdev);
done:
static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
{
- struct hci_cp_le_create_conn *cp;
struct hci_conn *conn;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
- if (!cp)
- return;
+ if (status) {
+ hci_dev_lock(hdev);
- hci_dev_lock(hdev);
+ conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+ if (!conn) {
+ hci_dev_unlock(hdev);
+ return;
+ }
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
+ BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&conn->dst),
+ conn);
- BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
- conn);
+ conn->state = BT_CLOSED;
+ mgmt_connect_failed(hdev, &conn->dst, conn->type,
+ conn->dst_type, status);
+ hci_proto_connect_cfm(conn, status);
+ hci_conn_del(conn);
- if (status) {
- if (conn && conn->state == BT_CONNECT) {
- conn->state = BT_CLOSED;
- mgmt_connect_failed(hdev, &cp->peer_addr, conn->type,
- conn->dst_type, status);
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
- }
- } else {
- if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
- if (conn) {
- conn->dst_type = cp->peer_addr_type;
- conn->out = true;
- } else {
- BT_ERR("No memory for new connection");
- }
- }
+ hci_dev_unlock(hdev);
}
-
- hci_dev_unlock(hdev);
}
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
BT_DBG("%s", hdev->name);
- hci_dev_lock(hdev);
-
if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
-
- hci_dev_unlock(hdev);
}
static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
hci_dev_lock(hdev);
- if (ev->status) {
- conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
- if (!conn)
+ conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+ if (!conn) {
+ conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
+ if (!conn) {
+ BT_ERR("No memory for new connection");
goto unlock;
+ }
+ conn->dst_type = ev->bdaddr_type;
+
+ if (ev->role == LE_CONN_ROLE_MASTER) {
+ conn->out = true;
+ conn->link_mode |= HCI_LM_MASTER;
+ }
+ }
+
+ if (ev->status) {
mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, ev->status);
hci_proto_connect_cfm(conn, ev->status);
goto unlock;
}
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
- if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
- if (!conn) {
- BT_ERR("No memory for new connection");
- hci_dev_unlock(hdev);
- return;
- }
-
- conn->dst_type = ev->bdaddr_type;
- }
-
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
conn->dst_type, 0, NULL, 0, NULL);
return err;
err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);
- if (err < 0)
+ if (err < 0) {
+ BT_ERR("HCI socket registration failed");
goto error;
+ }
+
+ err = bt_procfs_init(THIS_MODULE, &init_net, "hci", &hci_sk_list, NULL);
+ if (err < 0) {
+ BT_ERR("Failed to create HCI proc file");
+ bt_sock_unregister(BTPROTO_HCI);
+ goto error;
+ }
BT_INFO("HCI socket layer initialized");
return 0;
error:
- BT_ERR("HCI socket registration failed");
proto_unregister(&hci_sk_proto);
return err;
}
void hci_sock_cleanup(void)
{
+ bt_procfs_cleanup(&init_net, "hci");
if (bt_sock_unregister(BTPROTO_HCI) < 0)
BT_ERR("HCI socket unregistration failed");
#include "hidp.h"
+static struct bt_sock_list hidp_sk_list = {
+ .lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
+};
+
static int hidp_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
if (!sk)
return 0;
+ bt_sock_unlink(&hidp_sk_list, sk);
+
sock_orphan(sk);
sock_put(sk);
sk->sk_protocol = protocol;
sk->sk_state = BT_OPEN;
+ bt_sock_link(&hidp_sk_list, sk);
+
return 0;
}
return err;
err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
- if (err < 0)
+ if (err < 0) {
+ BT_ERR("Can't register HIDP socket");
goto error;
+ }
+
+ err = bt_procfs_init(THIS_MODULE, &init_net, "hidp", &hidp_sk_list, NULL);
+ if (err < 0) {
+ BT_ERR("Failed to create HIDP proc file");
+ bt_sock_unregister(BTPROTO_HIDP);
+ goto error;
+ }
+
+ BT_INFO("HIDP socket layer initialized");
return 0;
void __exit hidp_cleanup_sockets(void)
{
+ bt_procfs_cleanup(&init_net, "hidp");
if (bt_sock_unregister(BTPROTO_HIDP) < 0)
BT_ERR("Can't unregister HIDP socket");
return chan;
}
-void l2cap_chan_destroy(struct l2cap_chan *chan)
+static void l2cap_chan_destroy(struct l2cap_chan *chan)
{
+ BT_DBG("chan %p", chan);
+
write_lock(&chan_list_lock);
list_del(&chan->global_l);
write_unlock(&chan_list_lock);
- l2cap_chan_put(chan);
+ kfree(chan);
+}
+
+void l2cap_chan_hold(struct l2cap_chan *c)
+{
+ BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
+
+ atomic_inc(&c->refcnt);
+}
+
+void l2cap_chan_put(struct l2cap_chan *c)
+{
+ BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
+
+ if (atomic_dec_and_test(&c->refcnt))
+ l2cap_chan_destroy(c);
}
void l2cap_chan_set_defaults(struct l2cap_chan *chan)
return exact ? lm1 : lm2;
}
-int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
+void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
{
struct l2cap_conn *conn;
} else
l2cap_conn_del(hcon, bt_to_errno(status));
- return 0;
}
int l2cap_disconn_ind(struct hci_conn *hcon)
return conn->disc_reason;
}
-int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
+void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
l2cap_conn_del(hcon, bt_to_errno(reason));
- return 0;
}
static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
state_to_string(chan->state));
+ if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+ l2cap_chan_unlock(chan);
+ continue;
+ }
+
if (chan->scid == L2CAP_CID_LE_DATA) {
if (!status && encrypt) {
chan->sec_level = hcon->sec_level;
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
+static struct bt_sock_list l2cap_sk_list = {
+ .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
+};
+
static const struct proto_ops l2cap_sock_ops;
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
/* Kill poor orphan */
- l2cap_chan_destroy(l2cap_pi(sk)->chan);
+ l2cap_chan_put(l2cap_pi(sk)->chan);
sock_set_flag(sk, SOCK_DEAD);
sock_put(sk);
}
if (!sk)
return 0;
+ bt_sock_unlink(&l2cap_sk_list, sk);
+
err = l2cap_sock_shutdown(sock, 2);
sock_orphan(sk);
return -ENOMEM;
l2cap_sock_init(sk, NULL);
+ bt_sock_link(&l2cap_sk_list, sk);
return 0;
}
return err;
err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
- if (err < 0)
+ if (err < 0) {
+ BT_ERR("L2CAP socket registration failed");
goto error;
+ }
+
+ err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list, NULL);
+ if (err < 0) {
+ BT_ERR("Failed to create L2CAP proc file");
+ bt_sock_unregister(BTPROTO_L2CAP);
+ goto error;
+ }
BT_INFO("L2CAP socket layer initialized");
return 0;
error:
- BT_ERR("L2CAP socket registration failed");
proto_unregister(&l2cap_proto);
return err;
}
void l2cap_cleanup_sockets(void)
{
+ bt_procfs_cleanup(&init_net, "l2cap");
if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
BT_ERR("L2CAP socket unregistration failed");
MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
};
+bool mgmt_valid_hdev(struct hci_dev *hdev)
+{
+ return hdev->dev_type == HCI_BREDR;
+}
+
static u8 mgmt_status(u8 hci_status)
{
if (hci_status < ARRAY_SIZE(mgmt_status_table))
u16 data_len)
{
struct mgmt_rp_read_index_list *rp;
- struct list_head *p;
struct hci_dev *d;
size_t rp_len;
u16 count;
read_lock(&hci_dev_list_lock);
count = 0;
- list_for_each(p, &hci_dev_list) {
+ list_for_each_entry(d, &hci_dev_list, list) {
+ if (!mgmt_valid_hdev(d))
+ continue;
+
count++;
}
if (test_bit(HCI_SETUP, &d->dev_flags))
continue;
+ if (!mgmt_valid_hdev(d))
+ continue;
+
rp->index[i++] = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
settings |= MGMT_SETTING_DISCOVERABLE;
settings |= MGMT_SETTING_PAIRABLE;
- if (hdev->features[6] & LMP_SIMPLE_PAIR)
+ if (lmp_ssp_capable(hdev))
settings |= MGMT_SETTING_SSP;
- if (!(hdev->features[4] & LMP_NO_BREDR)) {
+ if (lmp_bredr_capable(hdev)) {
settings |= MGMT_SETTING_BREDR;
settings |= MGMT_SETTING_LINK_SECURITY;
}
if (enable_hs)
settings |= MGMT_SETTING_HS;
- if (hdev->features[4] & LMP_LE)
+ if (lmp_le_capable(hdev))
settings |= MGMT_SETTING_LE;
return settings;
if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_PAIRABLE;
- if (!(hdev->features[4] & LMP_NO_BREDR))
+ if (lmp_bredr_capable(hdev))
settings |= MGMT_SETTING_BREDR;
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
hci_dev_lock(hdev);
- if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+ if (!lmp_ssp_capable(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
MGMT_STATUS_NOT_SUPPORTED);
goto failed;
hci_dev_lock(hdev);
- if (!(hdev->features[4] & LMP_LE)) {
+ if (!lmp_le_capable(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
MGMT_STATUS_NOT_SUPPORTED);
goto unlock;
goto unlock;
}
- if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+ if (!lmp_ssp_capable(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
MGMT_STATUS_NOT_SUPPORTED);
goto unlock;
int mgmt_index_added(struct hci_dev *hdev)
{
+ if (!mgmt_valid_hdev(hdev))
+ return -ENOTSUPP;
+
return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
}
{
u8 status = MGMT_STATUS_INVALID_INDEX;
+ if (!mgmt_valid_hdev(hdev))
+ return -ENOTSUPP;
+
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
return err;
err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
- if (err < 0)
+ if (err < 0) {
+ BT_ERR("RFCOMM socket layer registration failed");
+ goto error;
+ }
+
+ err = bt_procfs_init(THIS_MODULE, &init_net, "rfcomm", &rfcomm_sk_list, NULL);
+ if (err < 0) {
+ BT_ERR("Failed to create RFCOMM proc file");
+ bt_sock_unregister(BTPROTO_RFCOMM);
goto error;
+ }
if (bt_debugfs) {
rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
return 0;
error:
- BT_ERR("RFCOMM socket layer registration failed");
proto_unregister(&rfcomm_proto);
return err;
}
void __exit rfcomm_cleanup_sockets(void)
{
+ bt_procfs_cleanup(&init_net, "rfcomm");
+
debugfs_remove(rfcomm_sock_debugfs);
if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
return lm;
}
-int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
{
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (!status) {
sco_conn_ready(conn);
} else
sco_conn_del(hcon, bt_to_errno(status));
-
- return 0;
}
-int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
+void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
sco_conn_del(hcon, bt_to_errno(reason));
- return 0;
}
int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
goto error;
}
+ err = bt_procfs_init(THIS_MODULE, &init_net, "sco", &sco_sk_list, NULL);
+ if (err < 0) {
+ BT_ERR("Failed to create SCO proc file");
+ bt_sock_unregister(BTPROTO_SCO);
+ goto error;
+ }
+
if (bt_debugfs) {
sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
NULL, &sco_debugfs_fops);
void __exit sco_exit(void)
{
+ bt_procfs_cleanup(&init_net, "sco");
+
debugfs_remove(sco_debugfs);
if (bt_sock_unregister(BTPROTO_SCO) < 0)
static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
- u8 scratch[2 * AES_BLOCK_SIZE];
- u8 *cbc, *pad;
+ u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end;
size_t i, e, left, total_len;
- cbc = scratch;
- pad = scratch + AES_BLOCK_SIZE;
-
memset(cbc, 0, AES_BLOCK_SIZE);
total_len = 0;
return 0;
}
+static int ieee80211_start_p2p_device(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ return ieee80211_do_open(wdev, true);
+}
+
+static void ieee80211_stop_p2p_device(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev));
+}
+
static int ieee80211_set_noack_map(struct wiphy *wiphy,
struct net_device *dev,
u16 noack_map)
if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
struct ieee80211_supported_band *sband;
sband = sta->local->hw.wiphy->bands[
- sta->local->hw.conf.channel->band];
+ sta->local->oper_channel->band];
rate->legacy = sband->bitrates[idx].bitrate;
} else
rate->mcs = idx;
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
const u8 *resp, size_t resp_len)
{
- struct sk_buff *new, *old;
+ struct probe_resp *new, *old;
if (!resp || !resp_len)
return 1;
old = rtnl_dereference(sdata->u.ap.probe_resp);
- new = dev_alloc_skb(resp_len);
+ new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);
if (!new)
return -ENOMEM;
- memcpy(skb_put(new, resp_len), resp, resp_len);
+ new->len = resp_len;
+ memcpy(new->data, resp, resp_len);
rcu_assign_pointer(sdata->u.ap.probe_resp, new);
- if (old) {
- /* TODO: use call_rcu() */
- synchronize_rcu();
- dev_kfree_skb(old);
- }
+ if (old)
+ kfree_rcu(old, rcu_head);
return 0;
}
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
- memset(msg->da, 0xff, ETH_ALEN);
+ eth_broadcast_addr(msg->da);
memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
msg->len = htons(6);
msg->dsap = 0;
mutex_unlock(&local->sta_mtx);
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))
+ params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
ieee80211_recalc_ps(local, -1);
-
+ ieee80211_recalc_ps_vif(sdata);
+ }
return 0;
}
}
if (!sdata->vif.bss_conf.use_short_slot &&
- sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) {
+ sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) {
sdata->vif.bss_conf.use_short_slot = true;
changed |= BSS_CHANGED_ERP_SLOT;
}
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_DEVICE:
break;
case NL80211_IFTYPE_P2P_GO:
if (sdata->local->ops->hw_scan)
enum nl80211_tx_power_setting type, int mbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_channel *chan = local->hw.conf.channel;
+ struct ieee80211_channel *chan = local->oper_channel;
u32 changes = 0;
switch (type) {
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
ieee80211_recalc_ps(local, -1);
+ ieee80211_recalc_ps_vif(sdata);
return 0;
}
if (!sdata->u.mgd.associated)
need_offchan = true;
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ need_offchan = true;
+ break;
default:
return -EOPNOTSUPP;
}
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_tdls_data *tf;
tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
tf->u.setup_req.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
- ieee80211_add_srates_ie(sdata, skb, false);
- ieee80211_add_ext_srates_ie(sdata, skb, false);
+ ieee80211_add_srates_ie(sdata, skb, false,
+ local->oper_channel->band);
+ ieee80211_add_ext_srates_ie(sdata, skb, false,
+ local->oper_channel->band);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_RESPONSE:
tf->u.setup_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
- ieee80211_add_srates_ie(sdata, skb, false);
- ieee80211_add_ext_srates_ie(sdata, skb, false);
+ ieee80211_add_srates_ie(sdata, skb, false,
+ local->oper_channel->band);
+ ieee80211_add_ext_srates_ie(sdata, skb, false,
+ local->oper_channel->band);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_CONFIRM:
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
mgmt = (void *)skb_put(skb, 24);
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
- ieee80211_add_srates_ie(sdata, skb, false);
- ieee80211_add_ext_srates_ie(sdata, skb, false);
+ ieee80211_add_srates_ie(sdata, skb, false,
+ local->oper_channel->band);
+ ieee80211_add_ext_srates_ie(sdata, skb, false,
+ local->oper_channel->band);
ieee80211_tdls_add_ext_capab(skb);
break;
default:
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
.change_virtual_intf = ieee80211_change_iface,
+ .start_p2p_device = ieee80211_start_p2p_device,
+ .stop_p2p_device = ieee80211_stop_p2p_device,
.add_key = ieee80211_add_key,
.del_key = ieee80211_del_key,
.get_key = ieee80211_get_key,
local->user_power_level);
DEBUGFS_READONLY_FILE(power, "%d",
local->hw.conf.power_level);
-DEBUGFS_READONLY_FILE(frequency, "%d",
- local->hw.conf.channel->center_freq);
DEBUGFS_READONLY_FILE(total_ps_buffered, "%d",
local->total_ps_buffered);
DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
.llseek = noop_llseek,
};
-static ssize_t channel_type_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- const char *buf;
-
- switch (local->hw.conf.channel_type) {
- case NL80211_CHAN_NO_HT:
- buf = "no ht\n";
- break;
- case NL80211_CHAN_HT20:
- buf = "ht20\n";
- break;
- case NL80211_CHAN_HT40MINUS:
- buf = "ht40-\n";
- break;
- case NL80211_CHAN_HT40PLUS:
- buf = "ht40+\n";
- break;
- default:
- buf = "???";
- break;
- }
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
-}
-
static ssize_t hwflags_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
}
DEBUGFS_READONLY_FILE_OPS(hwflags);
-DEBUGFS_READONLY_FILE_OPS(channel_type);
DEBUGFS_READONLY_FILE_OPS(queues);
/* statistics stuff */
local->debugfs.keys = debugfs_create_dir("keys", phyd);
- DEBUGFS_ADD(frequency);
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(queues);
DEBUGFS_ADD_MODE(reset, 0200);
- DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power);
{
WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER),
"%s: Failed check-sdata-in-driver check, flags: 0x%x\n",
- sdata->dev->name, sdata->flags);
+ sdata->dev ? sdata->dev->name : sdata->name, sdata->flags);
}
static inline struct ieee80211_sub_if_data *
return sdata;
}
-static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
+static inline void drv_tx(struct ieee80211_local *local,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
- local->ops->tx(&local->hw, skb);
+ local->ops->tx(&local->hw, control, skb);
}
static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata,
sdata = get_bss_sdata(sdata);
check_sdata_in_driver(sdata);
+ WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC);
+
trace_drv_sta_rc_update(local, sdata, sta, changed);
if (local->ops->sta_rc_update)
local->ops->sta_rc_update(&local->hw, &sdata->vif,
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP);
- memset(mgmt->da, 0xff, ETH_ALEN);
+ eth_broadcast_addr(mgmt->da);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int);
mod_timer(&ifibss->timer,
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
- bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
+ bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan,
mgmt, skb->len, 0, GFP_KERNEL);
cfg80211_put_bss(bss);
netif_carrier_on(sdata->dev);
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- int band = local->hw.conf.channel->band;
+ int band = local->oper_channel->band;
/*
* XXX: Consider removing the least recently used entry and
}
}
- if (sta && rates_updated)
+ if (sta && rates_updated) {
+ drv_sta_rc_update(local, sdata, &sta->sta,
+ IEEE80211_RC_SUPP_RATES_CHANGED);
rate_control_rate_init(sta);
+ }
rcu_read_unlock();
}
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- int band = local->hw.conf.channel->band;
+ int band = local->oper_channel->band;
/*
* XXX: Consider removing the least recently used entry and
return;
}
sdata_info(sdata, "IBSS not allowed on %d MHz\n",
- local->hw.conf.channel->center_freq);
+ local->oper_channel->center_freq);
/* No IBSS found - decrease scan interval and continue
* scanning. */
struct sta_info *sta;
struct ieee80211_key *key;
- struct ieee80211_channel *channel;
-
unsigned int flags;
};
struct rcu_head rcu_head;
};
+struct probe_resp {
+ struct rcu_head rcu_head;
+ int len;
+ u8 data[0];
+};
+
struct ieee80211_if_ap {
struct beacon_data __rcu *beacon;
- struct sk_buff __rcu *probe_resp;
+ struct probe_resp __rcu *probe_resp;
struct list_head vlans;
IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9),
IEEE80211_STA_DISABLE_40MHZ = BIT(10),
+ IEEE80211_STA_DISABLE_VHT = BIT(11),
};
struct ieee80211_mgd_auth_data {
struct idr ack_status_frames;
spinlock_t ack_status_lock;
+ struct ieee80211_sub_if_data __rcu *p2p_sdata;
+
/* dummy netdev for use w/ NAPI */
struct net_device napi_dev;
u8 *prep;
u8 *perr;
struct ieee80211_rann_ie *rann;
- u8 *ch_switch_elem;
+ struct ieee80211_channel_sw_ie *ch_switch_ie;
u8 *country_elem;
u8 *pwr_constr_elem;
u8 *quiet_elem; /* first quite element */
u8 preq_len;
u8 prep_len;
u8 perr_len;
- u8 ch_switch_elem_len;
u8 country_elem_len;
u8 pwr_constr_elem_len;
u8 quiet_elem_len;
void ieee80211_send_pspoll(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
+void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_idle(struct ieee80211_local *local);
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset);
+int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);
+void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_hdr *hdr);
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr, bool ack);
-void ieee80211_beacon_connection_loss_work(struct work_struct *work);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason);
u8 channel);
struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
u8 *dst, u32 ratemask,
+ struct ieee80211_channel *chan,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
bool directed);
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
- u32 ratemask, bool directed, bool no_cck);
+ u32 ratemask, bool directed, bool no_cck,
+ struct ieee80211_channel *channel);
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len,
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u32 cap);
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, bool need_basic);
+ struct sk_buff *skb, bool need_basic,
+ enum ieee80211_band band);
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, bool need_basic);
+ struct sk_buff *skb, bool need_basic,
+ enum ieee80211_band band);
/* channel management */
enum ieee80211_chan_mode {
sdata->vif.bss_conf.idle = true;
continue;
}
+
+ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
+ continue;
+
/* count everything else */
sdata->vif.bss_conf.idle = false;
count++;
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
continue;
if (sdata->old_idle == sdata->vif.bss_conf.idle)
continue;
{
return type1 == NL80211_IFTYPE_MONITOR ||
type2 == NL80211_IFTYPE_MONITOR ||
+ type1 == NL80211_IFTYPE_P2P_DEVICE ||
+ type2 == NL80211_IFTYPE_P2P_DEVICE ||
(type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_WDS) ||
(type1 == NL80211_IFTYPE_WDS &&
(type2 == NL80211_IFTYPE_WDS ||
int n_queues = sdata->local->hw.queues;
int i;
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- if (WARN_ON_ONCE(sdata->vif.hw_queue[i] ==
- IEEE80211_INVAL_HW_QUEUE))
- return -EINVAL;
- if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >=
- n_queues))
- return -EINVAL;
+ if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) {
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ if (WARN_ON_ONCE(sdata->vif.hw_queue[i] ==
+ IEEE80211_INVAL_HW_QUEUE))
+ return -EINVAL;
+ if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >=
+ n_queues))
+ return -EINVAL;
+ }
}
if ((sdata->vif.type != NL80211_IFTYPE_AP) ||
* an error on interface type changes that have been pre-checked, so most
* checks should be in ieee80211_check_concurrent_iface.
*/
-static int ieee80211_do_open(struct net_device *dev, bool coming_up)
+int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
u32 changed = 0;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_P2P_DEVICE:
/* no special treatment */
break;
case NL80211_IFTYPE_UNSPECIFIED:
* Copy the hopefully now-present MAC address to
* this interface, if it has the special null one.
*/
- if (is_zero_ether_addr(dev->dev_addr)) {
+ if (dev && is_zero_ether_addr(dev->dev_addr)) {
memcpy(dev->dev_addr,
local->hw.wiphy->perm_addr,
ETH_ALEN);
local->fif_probe_req++;
}
- changed |= ieee80211_reset_erp_info(sdata);
+ if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE)
+ changed |= ieee80211_reset_erp_info(sdata);
ieee80211_bss_info_change_notify(sdata, changed);
- if (sdata->vif.type == NL80211_IFTYPE_STATION ||
- sdata->vif.type == NL80211_IFTYPE_ADHOC ||
- sdata->vif.type == NL80211_IFTYPE_AP)
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
netif_carrier_off(dev);
- else
+ break;
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ break;
+ default:
netif_carrier_on(dev);
+ }
/*
* set default queue parameters so drivers don't
}
rate_control_rate_init(sta);
+ netif_carrier_on(dev);
+ } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
+ rcu_assign_pointer(local->p2p_sdata, sdata);
}
/*
ieee80211_recalc_ps(local, -1);
- netif_tx_start_all_queues(dev);
+ if (dev)
+ netif_tx_start_all_queues(dev);
return 0;
err_del_interface:
if (err)
return err;
- return ieee80211_do_open(dev, true);
+ return ieee80211_do_open(&sdata->wdev, true);
}
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
/*
* Stop TX on this interface first.
*/
- netif_tx_stop_all_queues(sdata->dev);
+ if (sdata->dev)
+ netif_tx_stop_all_queues(sdata->dev);
ieee80211_roc_purge(sdata);
local->fif_probe_req--;
}
- netif_addr_lock_bh(sdata->dev);
- spin_lock_bh(&local->filter_lock);
- __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
- sdata->dev->addr_len);
- spin_unlock_bh(&local->filter_lock);
- netif_addr_unlock_bh(sdata->dev);
+ if (sdata->dev) {
+ netif_addr_lock_bh(sdata->dev);
+ spin_lock_bh(&local->filter_lock);
+ __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
+ sdata->dev->addr_len);
+ spin_unlock_bh(&local->filter_lock);
+ netif_addr_unlock_bh(sdata->dev);
- ieee80211_configure_filter(local);
+ ieee80211_configure_filter(local);
+ }
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
struct ieee80211_sub_if_data *vlan, *tmpsdata;
struct beacon_data *old_beacon =
rtnl_dereference(sdata->u.ap.beacon);
- struct sk_buff *old_probe_resp =
+ struct probe_resp *old_probe_resp =
rtnl_dereference(sdata->u.ap.probe_resp);
/* sdata_running will return false, so this will disable */
RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
synchronize_rcu();
kfree(old_beacon);
- kfree_skb(old_probe_resp);
+ kfree(old_probe_resp);
/* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
ieee80211_adjust_monitor_flags(sdata, -1);
ieee80211_configure_filter(local);
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ /* relies on synchronize_rcu() below */
+ rcu_assign_pointer(local->p2p_sdata, NULL);
+ /* fall through */
default:
flush_work(&sdata->work);
/*
synchronize_rcu();
skb_queue_purge(&sdata->skb_queue);
- /*
- * Disable beaconing here for mesh only, AP and IBSS
- * are already taken care of.
- */
- if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
- ieee80211_bss_info_change_notify(sdata,
- BSS_CHANGED_BEACON_ENABLED);
-
/*
* Free all remaining keys, there shouldn't be any,
* except maybe group keys in AP more or WDS?
* Called when the netdev is removed or, by the code below, before
* the interface type changes.
*/
-static void ieee80211_teardown_sdata(struct net_device *dev)
+static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
int flushed;
int i;
WARN_ON(flushed);
}
+static void ieee80211_uninit(struct net_device *dev)
+{
+ ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
+}
+
static u16 ieee80211_netdev_select_queue(struct net_device *dev,
struct sk_buff *skb)
{
static const struct net_device_ops ieee80211_dataif_ops = {
.ndo_open = ieee80211_open,
.ndo_stop = ieee80211_stop,
- .ndo_uninit = ieee80211_teardown_sdata,
+ .ndo_uninit = ieee80211_uninit,
.ndo_start_xmit = ieee80211_subif_start_xmit,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu,
static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_open = ieee80211_open,
.ndo_stop = ieee80211_stop,
- .ndo_uninit = ieee80211_teardown_sdata,
+ .ndo_uninit = ieee80211_uninit,
.ndo_start_xmit = ieee80211_monitor_start_xmit,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu,
/* and set some type-dependent values */
sdata->vif.type = type;
sdata->vif.p2p = false;
- sdata->dev->netdev_ops = &ieee80211_dataif_ops;
sdata->wdev.iftype = type;
sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
sdata->noack_map = 0;
- /* only monitor differs */
- sdata->dev->type = ARPHRD_ETHER;
+ /* only monitor/p2p-device differ */
+ if (sdata->dev) {
+ sdata->dev->netdev_ops = &ieee80211_dataif_ops;
+ sdata->dev->type = ARPHRD_ETHER;
+ }
skb_queue_head_init(&sdata->skb_queue);
INIT_WORK(&sdata->work, ieee80211_iface_work);
break;
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_P2P_DEVICE:
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
ieee80211_debugfs_add_netdev(sdata);
}
-static void ieee80211_clean_sdata(struct ieee80211_sub_if_data *sdata)
-{
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_MESH_POINT:
- mesh_path_flush_by_iface(sdata);
- break;
-
- default:
- break;
- }
-}
-
static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
enum nl80211_iftype type)
{
ieee80211_do_stop(sdata, false);
- ieee80211_teardown_sdata(sdata->dev);
+ ieee80211_teardown_sdata(sdata);
ret = drv_change_interface(local, sdata, internal_type, p2p);
if (ret)
ieee80211_setup_sdata(sdata, type);
- err = ieee80211_do_open(sdata->dev, false);
+ err = ieee80211_do_open(&sdata->wdev, false);
WARN(err, "type change: do_open returned %d", err);
return ret;
return ret;
} else {
/* Purge and reset type-dependent state. */
- ieee80211_teardown_sdata(sdata->dev);
+ ieee80211_teardown_sdata(sdata);
ieee80211_setup_sdata(sdata, type);
}
/* reset some values that shouldn't be kept across type changes */
sdata->vif.bss_conf.basic_rates =
ieee80211_mandatory_rates(sdata->local,
- sdata->local->hw.conf.channel->band);
+ sdata->local->oper_channel->band);
sdata->drop_unencrypted = 0;
if (type == NL80211_IFTYPE_STATION)
sdata->u.mgd.use_4addr = false;
}
static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
- struct net_device *dev,
- enum nl80211_iftype type)
+ u8 *perm_addr, enum nl80211_iftype type)
{
struct ieee80211_sub_if_data *sdata;
u64 mask, start, addr, val, inc;
int i;
/* default ... something at least */
- memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ memcpy(perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
if (is_zero_ether_addr(local->hw.wiphy->addr_mask) &&
local->hw.wiphy->n_addresses <= 1)
return;
-
mutex_lock(&local->iflist_mtx);
switch (type) {
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP)
continue;
- memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN);
+ memcpy(perm_addr, sdata->vif.addr, ETH_ALEN);
break;
}
/* keep default if no AP interface present */
break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ if (local->hw.flags & IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF) {
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE)
+ continue;
+ if (!ieee80211_sdata_running(sdata))
+ continue;
+ memcpy(perm_addr, sdata->vif.addr, ETH_ALEN);
+ goto out_unlock;
+ }
+ }
+ /* otherwise fall through */
default:
/* assign a new address if possible -- try n_addresses first */
for (i = 0; i < local->hw.wiphy->n_addresses; i++) {
}
if (!used) {
- memcpy(dev->perm_addr,
+ memcpy(perm_addr,
local->hw.wiphy->addresses[i].addr,
ETH_ALEN);
break;
}
if (!used) {
- memcpy(dev->perm_addr, tmp_addr, ETH_ALEN);
+ memcpy(perm_addr, tmp_addr, ETH_ALEN);
break;
}
addr = (start & ~mask) | (val & mask);
break;
}
+ out_unlock:
mutex_unlock(&local->iflist_mtx);
}
struct wireless_dev **new_wdev, enum nl80211_iftype type,
struct vif_params *params)
{
- struct net_device *ndev;
+ struct net_device *ndev = NULL;
struct ieee80211_sub_if_data *sdata = NULL;
int ret, i;
int txqs = 1;
ASSERT_RTNL();
- if (local->hw.queues >= IEEE80211_NUM_ACS)
- txqs = IEEE80211_NUM_ACS;
-
- ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size,
- name, ieee80211_if_setup, txqs, 1);
- if (!ndev)
- return -ENOMEM;
- dev_net_set(ndev, wiphy_net(local->hw.wiphy));
-
- ndev->needed_headroom = local->tx_headroom +
- 4*6 /* four MAC addresses */
- + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
- + 6 /* mesh */
- + 8 /* rfc1042/bridge tunnel */
- - ETH_HLEN /* ethernet hard_header_len */
- + IEEE80211_ENCRYPT_HEADROOM;
- ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
-
- ret = dev_alloc_name(ndev, ndev->name);
- if (ret < 0)
- goto fail;
-
- ieee80211_assign_perm_addr(local, ndev, type);
- memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
- SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
-
- /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
- sdata = netdev_priv(ndev);
- ndev->ieee80211_ptr = &sdata->wdev;
- memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
- memcpy(sdata->name, ndev->name, IFNAMSIZ);
+ if (type == NL80211_IFTYPE_P2P_DEVICE) {
+ struct wireless_dev *wdev;
+
+ sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size,
+ GFP_KERNEL);
+ if (!sdata)
+ return -ENOMEM;
+ wdev = &sdata->wdev;
+
+ sdata->dev = NULL;
+ strlcpy(sdata->name, name, IFNAMSIZ);
+ ieee80211_assign_perm_addr(local, wdev->address, type);
+ memcpy(sdata->vif.addr, wdev->address, ETH_ALEN);
+ } else {
+ if (local->hw.queues >= IEEE80211_NUM_ACS)
+ txqs = IEEE80211_NUM_ACS;
+
+ ndev = alloc_netdev_mqs(sizeof(*sdata) +
+ local->hw.vif_data_size,
+ name, ieee80211_if_setup, txqs, 1);
+ if (!ndev)
+ return -ENOMEM;
+ dev_net_set(ndev, wiphy_net(local->hw.wiphy));
+
+ ndev->needed_headroom = local->tx_headroom +
+ 4*6 /* four MAC addresses */
+ + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
+ + 6 /* mesh */
+ + 8 /* rfc1042/bridge tunnel */
+ - ETH_HLEN /* ethernet hard_header_len */
+ + IEEE80211_ENCRYPT_HEADROOM;
+ ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
+
+ ret = dev_alloc_name(ndev, ndev->name);
+ if (ret < 0) {
+ free_netdev(ndev);
+ return ret;
+ }
+
+ ieee80211_assign_perm_addr(local, ndev->perm_addr, type);
+ memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
+
+ /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */
+ sdata = netdev_priv(ndev);
+ ndev->ieee80211_ptr = &sdata->wdev;
+ memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
+ memcpy(sdata->name, ndev->name, IFNAMSIZ);
+
+ sdata->dev = ndev;
+ }
/* initialise type-independent data */
sdata->wdev.wiphy = local->hw.wiphy;
sdata->local = local;
- sdata->dev = ndev;
#ifdef CONFIG_INET
sdata->arp_filter_state = true;
#endif
/* setup type-dependent data */
ieee80211_setup_sdata(sdata, type);
- if (params) {
- ndev->ieee80211_ptr->use_4addr = params->use_4addr;
- if (type == NL80211_IFTYPE_STATION)
- sdata->u.mgd.use_4addr = params->use_4addr;
- }
+ if (ndev) {
+ if (params) {
+ ndev->ieee80211_ptr->use_4addr = params->use_4addr;
+ if (type == NL80211_IFTYPE_STATION)
+ sdata->u.mgd.use_4addr = params->use_4addr;
+ }
- ndev->features |= local->hw.netdev_features;
+ ndev->features |= local->hw.netdev_features;
- ret = register_netdevice(ndev);
- if (ret)
- goto fail;
+ ret = register_netdevice(ndev);
+ if (ret) {
+ free_netdev(ndev);
+ return ret;
+ }
+ }
mutex_lock(&local->iflist_mtx);
list_add_tail_rcu(&sdata->list, &local->interfaces);
*new_wdev = &sdata->wdev;
return 0;
-
- fail:
- free_netdev(ndev);
- return ret;
}
void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);
- /* clean up type-dependent data */
- ieee80211_clean_sdata(sdata);
-
synchronize_rcu();
- unregister_netdevice(sdata->dev);
+
+ if (sdata->dev) {
+ unregister_netdevice(sdata->dev);
+ } else {
+ cfg80211_unregister_wdev(&sdata->wdev);
+ kfree(sdata);
+ }
+}
+
+void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
+{
+ if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state)))
+ return;
+ ieee80211_do_stop(sdata, true);
+ ieee80211_teardown_sdata(sdata);
}
/*
{
struct ieee80211_sub_if_data *sdata, *tmp;
LIST_HEAD(unreg_list);
+ LIST_HEAD(wdev_list);
ASSERT_RTNL();
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
list_del(&sdata->list);
- ieee80211_clean_sdata(sdata);
-
- unregister_netdevice_queue(sdata->dev, &unreg_list);
+ if (sdata->dev)
+ unregister_netdevice_queue(sdata->dev, &unreg_list);
+ else
+ list_add(&sdata->list, &wdev_list);
}
mutex_unlock(&local->iflist_mtx);
unregister_netdevice_many(&unreg_list);
list_del(&unreg_list);
+
+ list_for_each_entry_safe(sdata, tmp, &wdev_list, list) {
+ list_del(&sdata->list);
+ cfg80211_unregister_wdev(&sdata->wdev);
+ kfree(sdata);
+ }
}
static int netdev_notify(struct notifier_block *nb,
sdata->vif.bss_conf.bssid = NULL;
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
sdata->vif.bss_conf.bssid = zero;
+ } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
+ sdata->vif.bss_conf.bssid = sdata->vif.addr;
+ WARN_ONCE(changed & ~(BSS_CHANGED_IDLE),
+ "P2P Device BSS changed %#x", changed);
} else {
WARN_ON(1);
return;
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4),
},
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
};
static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
int priv_size, i;
struct wiphy *wiphy;
+ if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
+ !ops->add_interface || !ops->remove_interface ||
+ !ops->configure_filter))
+ return NULL;
+
if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
return NULL;
local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
- BUG_ON(!ops->tx);
- BUG_ON(!ops->start);
- BUG_ON(!ops->stop);
- BUG_ON(!ops->config);
- BUG_ON(!ops->add_interface);
- BUG_ON(!ops->remove_interface);
- BUG_ON(!ops->configure_filter);
local->ops = ops;
/* set up some defaults */
/* Disallow HT40+/- mismatch */
if (ie->ht_operation &&
- (local->_oper_channel_type == NL80211_CHAN_HT40MINUS ||
- local->_oper_channel_type == NL80211_CHAN_HT40PLUS) &&
+ (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS ||
+ sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) &&
(sta_channel_type == NL80211_CHAN_HT40MINUS ||
sta_channel_type == NL80211_CHAN_HT40PLUS) &&
- local->_oper_channel_type != sta_channel_type)
+ sdata->vif.bss_conf.channel_type != sta_channel_type)
goto mismatch;
return true;
* mesh_accept_plinks_update - update accepting_plink in local mesh beacons
*
* @sdata: mesh interface in which mesh beacons are going to be updated
+ *
+ * Returns: beacon changed flag if the beacon content changed.
*/
-void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
+u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
{
bool free_plinks;
+ u32 changed = 0;
/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
* the mesh interface might be able to establish plinks with peers that
*/
free_plinks = mesh_plink_availables(sdata);
- if (free_plinks != sdata->u.mesh.accepting_plinks)
- ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
+ if (free_plinks != sdata->u.mesh.accepting_plinks) {
+ sdata->u.mesh.accepting_plinks = free_plinks;
+ changed = BSS_CHANGED_BEACON;
+ }
+
+ return changed;
}
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
neighbors = (neighbors > 15) ? 15 : neighbors;
*pos++ = neighbors << 1;
/* Mesh capability */
- ifmsh->accepting_plinks = mesh_plink_availables(sdata);
*pos = MESHCONF_CAPAB_FORWARDING;
*pos |= ifmsh->accepting_plinks ?
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan = local->oper_channel;
u8 *pos;
if (skb_tailroom(skb) < 3)
return -ENOMEM;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[chan->band];
if (sband->band == IEEE80211_BAND_2GHZ) {
pos = skb_put(skb, 2 + 1);
*pos++ = WLAN_EID_DS_PARAMS;
*pos++ = 1;
- *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
+ *pos++ = ieee80211_frequency_to_channel(chan->center_freq);
}
return 0;
sband = local->hw.wiphy->bands[local->oper_channel->band];
if (!sband->ht_cap.ht_supported ||
- local->_oper_channel_type == NL80211_CHAN_NO_HT)
+ sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
return 0;
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_channel *channel = local->oper_channel;
- enum nl80211_channel_type channel_type = local->_oper_channel_type;
+ enum nl80211_channel_type channel_type =
+ sdata->vif.bss_conf.channel_type;
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[channel->band];
struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh)
{
- bool free_plinks;
+ u32 changed;
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
mesh_path_expire(sdata);
- free_plinks = mesh_plink_availables(sdata);
- if (free_plinks != sdata->u.mesh.accepting_plinks)
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ changed = mesh_accept_plinks_update(sdata);
+ ieee80211_bss_info_change_notify(sdata, changed);
mod_timer(&ifmsh->housekeeping_timer,
round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
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);
+ sdata->local->oper_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);
+
+ netif_carrier_on(sdata->dev);
}
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ netif_carrier_off(sdata->dev);
+
+ /* stop the beacon */
ifmsh->mesh_id_len = 0;
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
- sta_info_flush(local, NULL);
+
+ /* flush STAs and mpaths on this iface */
+ sta_info_flush(sdata->local, sdata);
+ mesh_path_flush_by_iface(sdata);
del_timer_sync(&sdata->u.mesh.housekeeping_timer);
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
/* Maximum number of paths per interface */
#define MESH_MAX_MPATHS 1024
+/* Number of frames buffered per destination for unresolved destinations */
+#define MESH_FRAME_QUEUE_LEN 10
+
/* Public interfaces */
/* Various */
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
u8 *hw_addr,
struct ieee802_11_elems *ie);
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
-void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
+u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
void mesh_plink_broken(struct sta_info *sta);
void mesh_plink_deactivate(struct sta_info *sta);
int mesh_plink_open(struct sta_info *sta);
#define MAX_METRIC 0xffffffff
#define ARITH_SHIFT 8
-/* Number of frames buffered per destination for unresolved destinations */
-#define MESH_FRAME_QUEUE_LEN 10
#define MAX_PREQ_QUEUE_LEN 64
/* Destination only */
{
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
- struct sk_buff_head tmpq;
unsigned long flags;
rcu_assign_pointer(mpath->next_hop, sta);
- __skb_queue_head_init(&tmpq);
-
spin_lock_irqsave(&mpath->frame_queue.lock, flags);
-
- while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
+ skb_queue_walk(&mpath->frame_queue, skb) {
hdr = (struct ieee80211_hdr *) skb->data;
memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN);
- __skb_queue_tail(&tmpq, skb);
}
- skb_queue_splice(&tmpq, &mpath->frame_queue);
spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
}
struct mesh_path *from_mpath,
bool copy)
{
- struct sk_buff *skb, *cp_skb = NULL;
- struct sk_buff_head gateq, failq;
+ struct sk_buff *skb, *fskb, *tmp;
+ struct sk_buff_head failq;
unsigned long flags;
- int num_skbs;
BUG_ON(gate_mpath == from_mpath);
BUG_ON(!gate_mpath->next_hop);
- __skb_queue_head_init(&gateq);
__skb_queue_head_init(&failq);
spin_lock_irqsave(&from_mpath->frame_queue.lock, flags);
skb_queue_splice_init(&from_mpath->frame_queue, &failq);
spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
- num_skbs = skb_queue_len(&failq);
-
- while (num_skbs--) {
- skb = __skb_dequeue(&failq);
- if (copy) {
- cp_skb = skb_copy(skb, GFP_ATOMIC);
- if (cp_skb)
- __skb_queue_tail(&failq, cp_skb);
+ skb_queue_walk_safe(&failq, fskb, tmp) {
+ if (skb_queue_len(&gate_mpath->frame_queue) >=
+ MESH_FRAME_QUEUE_LEN) {
+ mpath_dbg(gate_mpath->sdata, "mpath queue full!\n");
+ break;
}
+ skb = skb_copy(fskb, GFP_ATOMIC);
+ if (WARN_ON(!skb))
+ break;
+
prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
- __skb_queue_tail(&gateq, skb);
+ skb_queue_tail(&gate_mpath->frame_queue, skb);
+
+ if (copy)
+ continue;
+
+ __skb_unlink(fskb, &failq);
+ kfree_skb(fskb);
}
- spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags);
- skb_queue_splice(&gateq, &gate_mpath->frame_queue);
mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n",
gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue));
- spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags);
if (!copy)
return;
read_lock_bh(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
- memset(new_mpath->rann_snd_addr, 0xff, ETH_ALEN);
+ eth_broadcast_addr(new_mpath->rann_snd_addr);
new_mpath->is_root = false;
new_mpath->sdata = sdata;
new_mpath->flags = 0;
u8 *da, __le16 llid, __le16 plid, __le16 reason);
static inline
-void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
+u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
- mesh_accept_plinks_update(sdata);
+ return mesh_accept_plinks_update(sdata);
}
static inline
-void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
+u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
- mesh_accept_plinks_update(sdata);
+ return mesh_accept_plinks_update(sdata);
}
/**
u16 ht_opmode;
bool non_ht_sta = false, ht20_sta = false;
- if (local->_oper_channel_type == NL80211_CHAN_NO_HT)
+ if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
return 0;
rcu_read_lock();
if (non_ht_sta)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
- else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20)
+ else if (ht20_sta &&
+ sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20)
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
else
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
* @sta: mesh peer link to deactivate
*
* All mesh paths with this peer as next hop will be flushed
+ * Returns beacon changed flag if the beacon content changed.
*
* Locking: the caller must hold sta->lock
*/
-static bool __mesh_plink_deactivate(struct sta_info *sta)
+static u32 __mesh_plink_deactivate(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
- bool deactivated = false;
+ u32 changed = 0;
- if (sta->plink_state == NL80211_PLINK_ESTAB) {
- mesh_plink_dec_estab_count(sdata);
- deactivated = true;
- }
+ if (sta->plink_state == NL80211_PLINK_ESTAB)
+ changed = mesh_plink_dec_estab_count(sdata);
sta->plink_state = NL80211_PLINK_BLOCKED;
mesh_path_flush_by_nexthop(sta);
- return deactivated;
+ return changed;
}
/**
void mesh_plink_deactivate(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
- bool deactivated;
+ u32 changed;
spin_lock_bh(&sta->lock);
- deactivated = __mesh_plink_deactivate(sta);
+ changed = __mesh_plink_deactivate(sta);
sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
sta->sta.addr, sta->llid, sta->plid,
sta->reason);
spin_unlock_bh(&sta->lock);
- if (deactivated)
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ ieee80211_bss_info_change_notify(sdata, changed);
}
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
u8 *da, __le16 llid, __le16 plid, __le16 reason) {
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
struct ieee80211_mgmt *mgmt;
bool include_plid = false;
u16 peering_proto = 0;
u8 *pos, ie_len = 4;
int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
sizeof(mgmt->u.action.u.self_prot);
+ int err = -ENOMEM;
skb = dev_alloc_skb(local->tx_headroom +
hdr_len +
sdata->u.mesh.ie_len);
if (!skb)
return -1;
+ info = IEEE80211_SKB_CB(skb);
skb_reserve(skb, local->tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
memset(mgmt, 0, hdr_len);
pos = skb_put(skb, 2);
memcpy(pos + 2, &plid, 2);
}
- if (ieee80211_add_srates_ie(sdata, skb, true) ||
- ieee80211_add_ext_srates_ie(sdata, skb, true) ||
+ if (ieee80211_add_srates_ie(sdata, skb, true,
+ local->oper_channel->band) ||
+ ieee80211_add_ext_srates_ie(sdata, skb, true,
+ local->oper_channel->band) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata))
- return -1;
+ goto free;
} else { /* WLAN_SP_MESH_PEERING_CLOSE */
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
if (mesh_add_meshid_ie(skb, sdata))
- return -1;
+ goto free;
}
/* Add Mesh Peering Management element */
ie_len += 2; /* reason code */
break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto free;
}
if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
- return -ENOMEM;
+ goto free;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PEER_MGMT;
if (action != WLAN_SP_MESH_PEERING_CLOSE) {
if (mesh_add_ht_cap_ie(skb, sdata) ||
mesh_add_ht_oper_ie(skb, sdata))
- return -1;
+ goto free;
}
if (mesh_add_vendor_ies(skb, sdata))
- return -1;
+ goto free;
ieee80211_tx_skb(sdata, skb);
return 0;
+free:
+ kfree_skb(skb);
+ return err;
}
/**
spin_lock_bh(&sta->lock);
sta->last_rx = jiffies;
+ if (sta->plink_state == NL80211_PLINK_ESTAB) {
+ spin_unlock_bh(&sta->lock);
+ return sta;
+ }
+
sta->sta.supp_rates[band] = rates;
if (elems->ht_cap_elem &&
- sdata->local->_oper_channel_type != NL80211_CHAN_NO_HT)
+ sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT)
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem,
&sta->sta.ht_cap);
void mesh_plink_block(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
- bool deactivated;
+ u32 changed;
spin_lock_bh(&sta->lock);
- deactivated = __mesh_plink_deactivate(sta);
+ changed = __mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_BLOCKED;
spin_unlock_bh(&sta->lock);
- if (deactivated)
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ ieee80211_bss_info_change_notify(sdata, changed);
}
del_timer(&sta->plink_timer);
sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
- mesh_plink_inc_estab_count(sdata);
+ changed |= mesh_plink_inc_estab_count(sdata);
changed |= mesh_set_ht_prot_mode(sdata);
- changed |= BSS_CHANGED_BEACON;
mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
break;
del_timer(&sta->plink_timer);
sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
- mesh_plink_inc_estab_count(sdata);
+ changed |= mesh_plink_inc_estab_count(sdata);
changed |= mesh_set_ht_prot_mode(sdata);
- changed |= BSS_CHANGED_BEACON;
mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
mesh_plink_frame_tx(sdata,
case CLS_ACPT:
reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
sta->reason = reason;
- __mesh_plink_deactivate(sta);
+ changed |= __mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_HOLDING;
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
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;
if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
return;
+ if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+ return;
+
mod_timer(&sdata->u.mgd.bcn_mon_timer,
round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout));
}
u16 ht_opmode;
bool disable_40 = false;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[local->oper_channel->band];
switch (sdata->vif.bss_conf.channel_type) {
case NL80211_CHAN_HT40PLUS:
- if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
disable_40 = true;
break;
case NL80211_CHAN_HT40MINUS:
- if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
disable_40 = true;
break;
default:
ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
}
+static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb,
+ struct ieee80211_supported_band *sband)
+{
+ u8 *pos;
+ u32 cap;
+ struct ieee80211_sta_vht_cap vht_cap;
+
+ BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
+
+ memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
+
+ /* determine capability flags */
+ cap = vht_cap.cap;
+
+ /* reserve and fill IE */
+ pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2);
+ ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
+}
+
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
4 + /* power capability */
2 + 2 * sband->n_channels + /* supported channels */
2 + sizeof(struct ieee80211_ht_cap) + /* HT */
+ 2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */
assoc_data->ie_len + /* extra IEs */
9, /* WMM */
GFP_KERNEL);
ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
sband, local->oper_channel, ifmgd->ap_smps);
+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ ieee80211_add_vht_ie(sdata, skb, sband);
+
/* if present, add any custom non-vendor IEs that go after HT */
if (assoc_data->ie_len && assoc_data->ie) {
noffset = ieee80211_ie_split_vendor(assoc_data->ie,
IEEE80211_SKB_CB(skb)->flags |=
IEEE80211_TX_INTFL_DONT_ENCRYPT;
- drv_mgd_prepare_tx(local, sdata);
-
ieee80211_tx_skb(sdata, skb);
}
}
/* XXX: shouldn't really modify cfg80211-owned data! */
ifmgd->associated->channel = sdata->local->oper_channel;
+ /* XXX: wait for a beacon first? */
ieee80211_wake_queues_by_reason(&sdata->local->hw,
IEEE80211_QUEUE_STOP_REASON_CSA);
out:
sdata->local->csa_channel = new_ch;
+ ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+
+ if (sw_elem->mode)
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+
if (sdata->local->ops->channel_switch) {
/* use driver's channel switch callback */
- struct ieee80211_channel_switch ch_switch;
- memset(&ch_switch, 0, sizeof(ch_switch));
- ch_switch.timestamp = timestamp;
- if (sw_elem->mode) {
- ch_switch.block_tx = true;
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
- IEEE80211_QUEUE_STOP_REASON_CSA);
- }
- ch_switch.channel = new_ch;
- ch_switch.count = sw_elem->count;
- ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+ struct ieee80211_channel_switch ch_switch = {
+ .timestamp = timestamp,
+ .block_tx = sw_elem->mode,
+ .channel = new_ch,
+ .count = sw_elem->count,
+ };
+
drv_channel_switch(sdata->local, &ch_switch);
return;
}
/* channel switch handled in software */
- if (sw_elem->count <= 1) {
+ if (sw_elem->count <= 1)
ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
- } else {
- if (sw_elem->mode)
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
- IEEE80211_QUEUE_STOP_REASON_CSA);
- ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+ else
mod_timer(&ifmgd->chswitch_timer,
- jiffies +
- msecs_to_jiffies(sw_elem->count *
- cbss->beacon_interval));
- }
+ TU_TO_EXP_TIME(sw_elem->count *
+ cbss->beacon_interval));
}
static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
ieee80211_change_ps(local);
}
+void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata)
+{
+ bool ps_allowed = ieee80211_powersave_allowed(sdata);
+
+ if (sdata->vif.bss_conf.ps != ps_allowed) {
+ sdata->vif.bss_conf.ps = ps_allowed;
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS);
+ }
+}
+
void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
{
struct ieee80211_local *local =
}
use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
- if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
+ if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ)
use_short_slot = true;
if (use_protection != bss_conf->use_cts_prot) {
ieee80211_recalc_smps(local);
mutex_unlock(&local->iflist_mtx);
+ ieee80211_recalc_ps_vif(sdata);
+
netif_tx_start_all_queues(sdata->dev);
netif_carrier_on(sdata->dev);
}
}
local->ps_sdata = NULL;
+ /* disable per-vif ps */
+ ieee80211_recalc_ps_vif(sdata);
+
/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
if (tx)
drv_flush(local, false);
ssid_len = ssid[1];
ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
- 0, (u32) -1, true, false);
+ 0, (u32) -1, true, false,
+ ifmgd->associated->channel);
}
ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
ssid_len = ssid[1];
skb = ieee80211_build_probe_req(sdata, cbss->bssid,
- (u32) -1, ssid + 2, ssid_len,
+ (u32) -1,
+ sdata->local->oper_channel,
+ ssid + 2, ssid_len,
NULL, 0, true);
return skb;
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- u8 bssid[ETH_ALEN];
u8 frame_buf[DEAUTH_DISASSOC_LEN];
mutex_lock(&ifmgd->mtx);
return;
}
- memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
-
- sdata_info(sdata, "Connection to AP %pM lost\n", bssid);
+ sdata_info(sdata, "Connection to AP %pM lost\n",
+ ifmgd->associated->bssid);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
mutex_unlock(&local->mtx);
}
-void ieee80211_beacon_connection_loss_work(struct work_struct *work)
+static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data,
mutex_unlock(&local->iflist_mtx);
}
- if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
- (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
- ETH_ALEN) == 0)) {
- struct ieee80211_channel_sw_ie *sw_elem =
- (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
- ieee80211_sta_process_chanswitch(sdata, sw_elem,
+ if (elems->ch_switch_ie &&
+ memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)
+ ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie,
bss, rx_status->mactime);
- }
}
if (baselen > len)
return;
- if (rx_status->freq != local->hw.conf.channel->center_freq)
+ if (rx_status->freq != local->oper_channel->center_freq)
return;
if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[local->oper_channel->band];
changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
bssid, true);
* will not answer to direct packet in unassociated state.
*/
ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
- NULL, 0, (u32) -1, true, false);
+ NULL, 0, (u32) -1, true, false,
+ auth_data->bss->channel);
}
auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
return 0;
}
-static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_bss *cbss, bool assoc)
+static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_bss *cbss)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_bss *bss = (void *)cbss->priv;
- struct sta_info *sta = NULL;
- bool have_sta = false;
- int err;
int ht_cfreq;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
const u8 *ht_oper_ie;
const struct ieee80211_ht_operation *ht_oper = NULL;
struct ieee80211_supported_band *sband;
- if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
- return -EINVAL;
-
- if (assoc) {
- rcu_read_lock();
- have_sta = sta_info_get(sdata, cbss->bssid);
- rcu_read_unlock();
- }
-
- if (!have_sta) {
- sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
- if (!sta)
- return -ENOMEM;
- }
-
- mutex_lock(&local->mtx);
- ieee80211_recalc_idle(sdata->local);
- mutex_unlock(&local->mtx);
-
- /* switch to the right channel */
sband = local->hw.wiphy->bands[cbss->channel->band];
ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ;
local->oper_channel = cbss->channel;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
- if (sta) {
+ return 0;
+}
+
+static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_bss *cbss, bool assoc)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_bss *bss = (void *)cbss->priv;
+ struct sta_info *new_sta = NULL;
+ bool have_sta = false;
+ int err;
+
+ if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
+ return -EINVAL;
+
+ if (assoc) {
+ rcu_read_lock();
+ have_sta = sta_info_get(sdata, cbss->bssid);
+ rcu_read_unlock();
+ }
+
+ if (!have_sta) {
+ new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
+ if (!new_sta)
+ return -ENOMEM;
+ }
+
+ mutex_lock(&local->mtx);
+ ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&local->mtx);
+
+ if (new_sta) {
u32 rates = 0, basic_rates = 0;
bool have_higher_than_11mbit;
int min_rate = INT_MAX, min_rate_index = -1;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[cbss->channel->band];
+
+ err = ieee80211_prep_channel(sdata, cbss);
+ if (err) {
+ sta_info_free(local, new_sta);
+ return err;
+ }
ieee80211_get_rates(sband, bss->supp_rates,
bss->supp_rates_len,
basic_rates = BIT(min_rate_index);
}
- sta->sta.supp_rates[cbss->channel->band] = rates;
+ new_sta->sta.supp_rates[cbss->channel->band] = rates;
sdata->vif.bss_conf.basic_rates = basic_rates;
/* cf. IEEE 802.11 9.2.12 */
BSS_CHANGED_BEACON_INT);
if (assoc)
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+ sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH);
- err = sta_info_insert(sta);
- sta = NULL;
+ err = sta_info_insert(new_sta);
+ new_sta = NULL;
if (err) {
sdata_info(sdata,
"failed to insert STA entry for the AP (error %d)\n",
}
/* prepare assoc data */
-
- ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
- ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
+
+ /*
+ * keep only the 40 MHz disable bit set as it might have
+ * been set during authentication already, all other bits
+ * should be reset for a new connection
+ */
+ ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ;
ifmgd->beacon_crc_valid = false;
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+ ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
netdev_info(sdata->dev,
- "disabling HT due to WEP/TKIP use\n");
+ "disabling HT/VHT due to WEP/TKIP use\n");
}
}
- if (req->flags & ASSOC_REQ_DISABLE_HT)
+ if (req->flags & ASSOC_REQ_DISABLE_HT) {
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+ ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+ }
/* Also disable HT if we don't support it or the AP doesn't use WMM */
sband = local->hw.wiphy->bands[req->bss->channel->band];
if (!sband->ht_cap.ht_supported ||
local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
- netdev_info(sdata->dev,
- "disabling HT as WMM/QoS is not supported\n");
+ if (!bss->wmm_used)
+ netdev_info(sdata->dev,
+ "disabling HT as WMM/QoS is not supported by the AP\n");
+ }
+
+ /* disable VHT if we don't support it or the AP doesn't use WMM */
+ if (!sband->vht_cap.vht_supported ||
+ local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
+ ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+ if (!bss->wmm_used)
+ netdev_info(sdata->dev,
+ "disabling VHT as WMM/QoS is not supported by the AP\n");
}
memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
req->bssid, req->reason_code);
if (ifmgd->associated &&
- ether_addr_equal(ifmgd->associated->bssid, req->bssid))
+ ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, true, frame_buf);
- else
+ } else {
+ drv_mgd_prepare_tx(sdata->local, sdata);
ieee80211_send_deauth_disassoc(sdata, req->bssid,
IEEE80211_STYPE_DEAUTH,
req->reason_code, true,
frame_buf);
+ }
+
mutex_unlock(&ifmgd->mtx);
__cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN);
if (!ieee80211_sdata_running(sdata))
continue;
+ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
+ continue;
+
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
+ continue;
+
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
if (!ref)
return;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[local->oper_channel->band];
ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+ if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
+ RX_FLAG_FAILED_PLCP_CRC |
+ RX_FLAG_AMPDU_IS_ZEROLEN))
return 1;
if (unlikely(skb->len < 16 + present_fcs_len))
return 1;
if (status->flag & RX_FLAG_HT) /* HT info */
len += 3;
+ if (status->flag & RX_FLAG_AMPDU_DETAILS) {
+ /* padding */
+ while (len & 3)
+ len++;
+ len += 8;
+ }
+
return len;
}
-/**
+/*
* ieee80211_add_rx_radiotap_header - add radiotap header
*
* add a radiotap header containing all the fields which the hardware provided.
pos++;
*pos++ = status->rate_idx;
}
+
+ if (status->flag & RX_FLAG_AMPDU_DETAILS) {
+ u16 flags = 0;
+
+ /* ensure 4 byte alignment */
+ while ((pos - (u8 *)rthdr) & 3)
+ pos++;
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS);
+ put_unaligned_le32(status->ampdu_reference, pos);
+ pos += 4;
+ if (status->flag & RX_FLAG_AMPDU_REPORT_ZEROLEN)
+ flags |= IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN;
+ if (status->flag & RX_FLAG_AMPDU_IS_ZEROLEN)
+ flags |= IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN;
+ if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN)
+ flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN;
+ if (status->flag & RX_FLAG_AMPDU_IS_LAST)
+ flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
+ if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR)
+ flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
+ if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
+ flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
+ put_unaligned_le16(flags, pos);
+ pos += 2;
+ if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
+ *pos++ = status->ampdu_delimiter_crc;
+ else
+ *pos++ = 0;
+ *pos++ = 0;
+ }
}
/*
goto queue;
case WLAN_CATEGORY_SPECTRUM_MGMT:
- if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
+ if (status->band != IEEE80211_BAND_5GHZ)
break;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
if (!bssid) {
if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
return 0;
- } else if (!ieee80211_bssid_match(bssid,
- sdata->vif.addr)) {
+ } else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
/*
* Accept public action frames even when the
* BSSID doesn't match, this is used for P2P
if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
return 0;
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ if (!ieee80211_is_public_action(hdr, skb->len) &&
+ !ieee80211_is_probe_req(hdr->frame_control) &&
+ !ieee80211_is_probe_resp(hdr->frame_control) &&
+ !ieee80211_is_beacon(hdr->frame_control))
+ return 0;
+ if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
+ break;
default:
/* should never get here */
- WARN_ON(1);
+ WARN_ON_ONCE(1);
break;
}
local->scan_req->ssids[i].ssid_len,
local->scan_req->ie, local->scan_req->ie_len,
local->scan_req->rates[band], false,
- local->scan_req->no_cck);
+ local->scan_req->no_cck,
+ local->hw.conf.channel);
/*
* After sending probe requests, wait for probe responses
if (local->ops->hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning);
} else if ((req->n_channels == 1) &&
- (req->channels[0]->center_freq ==
- local->hw.conf.channel->center_freq)) {
-
- /* If we are scanning only on the current channel, then
- * we do not need to stop normal activities
+ (req->channels[0] == local->oper_channel)) {
+ /*
+ * If we are scanning only on the operating channel
+ * then we do not need to stop normal activities
*/
unsigned long next_delay;
u64 cookie = (unsigned long)skb;
acked = info->flags & IEEE80211_TX_STAT_ACK;
- /*
- * TODO: When we have non-netdev frame TX,
- * we cannot use skb->dev->ieee80211_ptr
- */
-
if (ieee80211_is_nullfunc(hdr->frame_control) ||
- ieee80211_is_qos_nullfunc(hdr->frame_control))
+ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
cfg80211_probe_status(skb->dev, hdr->addr1,
cookie, acked, GFP_ATOMIC);
- else
+ } else if (skb->dev) {
cfg80211_mgmt_tx_status(
skb->dev->ieee80211_ptr, cookie, skb->data,
skb->len, acked, GFP_ATOMIC);
+ } else {
+ struct ieee80211_sub_if_data *p2p_sdata;
+
+ rcu_read_lock();
+
+ p2p_sdata = rcu_dereference(local->p2p_sdata);
+ if (p2p_sdata) {
+ cfg80211_mgmt_tx_status(
+ &p2p_sdata->wdev, cookie, skb->data,
+ skb->len, acked, GFP_ATOMIC);
+ }
+ rcu_read_unlock();
+ }
}
if (unlikely(info->ack_frame_id)) {
__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
__entry->p2p = sdata->vif.p2p; \
- __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+ __assign_str(vif_name, sdata->dev ? sdata->dev->name : sdata->name)
#define VIF_PR_FMT " vif:%s(%d%s)"
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
__entry->max_sleep_period = local->hw.conf.max_sleep_period;
__entry->listen_interval = local->hw.conf.listen_interval;
- __entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
- __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
- __entry->center_freq = local->hw.conf.channel->center_freq;
+ __entry->long_frame_max_tx_count =
+ local->hw.conf.long_frame_max_tx_count;
+ __entry->short_frame_max_tx_count =
+ local->hw.conf.short_frame_max_tx_count;
+ __entry->center_freq = local->hw.conf.channel ?
+ local->hw.conf.channel->center_freq : 0;
__entry->channel_type = local->hw.conf.channel_type;
__entry->smps = local->hw.conf.smps_mode;
),
if (WARN_ON_ONCE(info->control.rates[0].idx < 0))
return 0;
- sband = local->hw.wiphy->bands[tx->channel->band];
+ sband = local->hw.wiphy->bands[info->band];
txrate = &sband->bitrates[info->control.rates[0].idx];
erp = txrate->flags & IEEE80211_RATE_ERP_G;
memset(&txrc, 0, sizeof(txrc));
- sband = tx->local->hw.wiphy->bands[tx->channel->band];
+ sband = tx->local->hw.wiphy->bands[info->band];
len = min_t(u32, tx->skb->len + FCS_LEN,
tx->local->hw.wiphy->frag_threshold);
txrc.bss_conf = &tx->sdata->vif.bss_conf;
txrc.skb = tx->skb;
txrc.reported_rate.idx = -1;
- txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band];
+ txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band];
if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
memcpy(txrc.rate_idx_mcs_mask,
- tx->sdata->rc_rateidx_mcs_mask[tx->channel->band],
+ tx->sdata->rc_rateidx_mcs_mask[info->band],
sizeof(txrc.rate_idx_mcs_mask));
txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
"scanning and associated. Target station: "
"%pM on %d GHz band\n",
tx->sdata->name, hdr->addr1,
- tx->channel->band ? 5 : 2))
+ info->band ? 5 : 2))
return TX_DROP;
/*
tx->skb = skb;
tx->local = local;
tx->sdata = sdata;
- tx->channel = local->hw.conf.channel;
__skb_queue_head_init(&tx->skbs);
/*
struct sk_buff_head *skbs,
bool txpending)
{
+ struct ieee80211_tx_control control;
struct sk_buff *skb, *tmp;
unsigned long flags;
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
info->control.vif = vif;
- info->control.sta = sta;
+ control.sta = sta;
__skb_unlink(skb, skbs);
- drv_tx(local, skb);
+ drv_tx(local, &control, skb);
}
return true;
goto out;
}
- tx.channel = local->hw.conf.channel;
- info->band = tx.channel->band;
+ info->band = local->hw.conf.channel->band;
/* set up hw_queue value early */
if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info;
- int ret = NETDEV_TX_BUSY, head_need;
+ int head_need;
u16 ethertype, hdrlen, meshhdrlen = 0;
__le16 fc;
struct ieee80211_hdr hdr;
u32 info_flags = 0;
u16 info_id = 0;
- if (unlikely(skb->len < ETH_HLEN)) {
- ret = NETDEV_TX_OK;
+ if (unlikely(skb->len < ETH_HLEN))
goto fail;
- }
/* convert Ethernet header to proper 802.11 header (based on
* operation mode) */
if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
/* Do not send frames with mesh_ttl == 0 */
sdata->u.mesh.mshstats.dropped_frames_ttl++;
- ret = NETDEV_TX_OK;
goto fail;
}
rcu_read_lock();
if (tdls_direct) {
/* link during setup - throw out frames to peer */
- if (!tdls_auth) {
- ret = NETDEV_TX_OK;
+ if (!tdls_auth)
goto fail;
- }
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
hdrlen = 24;
break;
default:
- ret = NETDEV_TX_OK;
goto fail;
}
I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
- ret = NETDEV_TX_OK;
goto fail;
}
skb = skb_clone(skb, GFP_ATOMIC);
kfree_skb(tmp_skb);
- if (!skb) {
- ret = NETDEV_TX_OK;
+ if (!skb)
goto fail;
- }
}
hdr.frame_control = fc;
return NETDEV_TX_OK;
fail:
- if (ret == NETDEV_TX_OK)
- dev_kfree_skb(skb);
-
- return ret;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
}
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
struct beacon_data *beacon;
- struct ieee80211_supported_band *sband;
- enum ieee80211_band band = local->hw.conf.channel->band;
+ enum ieee80211_band band = local->oper_channel->band;
struct ieee80211_tx_rate_control txrc;
- sband = local->hw.wiphy->bands[band];
-
rcu_read_lock();
sdata = vif_to_sdata(vif);
memset(mgmt, 0, hdr_len);
mgmt->frame_control =
cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
- memset(mgmt->da, 0xff, ETH_ALEN);
+ eth_broadcast_addr(mgmt->da);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
mgmt->u.beacon.beacon_int =
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;
- if (ieee80211_add_srates_ie(sdata, skb, true) ||
+ if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(skb, sdata) ||
- ieee80211_add_ext_srates_ie(sdata, skb, true) ||
+ ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_ht_cap_ie(skb, sdata) ||
mesh_add_ht_oper_ie(skb, sdata) ||
memset(&txrc, 0, sizeof(txrc));
txrc.hw = hw;
- txrc.sband = sband;
+ txrc.sband = local->hw.wiphy->bands[band];
txrc.bss_conf = &sdata->vif.bss_conf;
txrc.skb = skb;
txrc.reported_rate.idx = -1;
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
- if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
+ if (txrc.rate_idx_mask == (1 << txrc.sband->n_bitrates) - 1)
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
struct ieee80211_vif *vif)
{
struct ieee80211_if_ap *ap = NULL;
- struct sk_buff *presp = NULL, *skb = NULL;
+ struct sk_buff *skb = NULL;
+ struct probe_resp *presp = NULL;
struct ieee80211_hdr *hdr;
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
if (!presp)
goto out;
- skb = skb_copy(presp, GFP_ATOMIC);
+ skb = dev_alloc_skb(presp->len);
if (!skb)
goto out;
+ memcpy(skb_put(skb, presp->len), presp->data, presp->len);
+
hdr = (struct ieee80211_hdr *) skb->data;
memset(hdr->addr1, 0, sizeof(hdr->addr1));
memset(hdr, 0, sizeof(*hdr));
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_REQ);
- memset(hdr->addr1, 0xff, ETH_ALEN);
+ eth_broadcast_addr(hdr->addr1);
memcpy(hdr->addr2, vif->addr, ETH_ALEN);
- memset(hdr->addr3, 0xff, ETH_ALEN);
+ eth_broadcast_addr(hdr->addr3);
pos = skb_put(skb, ie_ssid_len);
*pos++ = WLAN_EID_SSID;
info = IEEE80211_SKB_CB(skb);
tx.flags |= IEEE80211_TX_PS_BUFFERED;
- tx.channel = local->hw.conf.channel;
- info->band = tx.channel->band;
+ info->band = local->oper_channel->band;
if (invoke_tx_handlers(&tx))
skb = NULL;
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
int ac;
+ if (!sdata->dev)
+ continue;
+
if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
continue;
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
int ac;
+ if (!sdata->dev)
+ continue;
+
for (ac = 0; ac < n_acs; ac++) {
if (sdata->vif.hw_queue[ac] == queue ||
sdata->vif.cab_queue == queue)
elem_parse_failed = true;
break;
case WLAN_EID_CHANNEL_SWITCH:
- elems->ch_switch_elem = pos;
- elems->ch_switch_elem_len = elen;
+ if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
+ elem_parse_failed = true;
+ break;
+ }
+ elems->ch_switch_ie = (void *)pos;
break;
case WLAN_EID_QUIET:
if (!elems->quiet_elem) {
memset(&qparam, 0, sizeof(qparam));
- use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
+ use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
/*
drv_conf_tx(local, sdata, ac, &qparam);
}
- if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+ sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) {
sdata->vif.bss_conf.qos = enable_qos;
if (bss_notify)
ieee80211_bss_info_change_notify(sdata,
if ((supp_rates[i] & 0x7f) * 5 > 110)
have_higher_than_11mbit = 1;
- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+ if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
have_higher_than_11mbit)
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
else
struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
u8 *dst, u32 ratemask,
+ struct ieee80211_channel *chan,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
bool directed)
struct ieee80211_mgmt *mgmt;
size_t buf_len;
u8 *buf;
- u8 chan;
+ u8 chan_no;
/* FIXME: come up with a proper value */
buf = kmalloc(200 + ie_len, GFP_KERNEL);
* badly-behaved APs don't respond when this parameter is included.
*/
if (directed)
- chan = 0;
+ chan_no = 0;
else
- chan = ieee80211_frequency_to_channel(
- local->hw.conf.channel->center_freq);
+ chan_no = ieee80211_frequency_to_channel(chan->center_freq);
- buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
- local->hw.conf.channel->band,
- ratemask, chan);
+ buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band,
+ ratemask, chan_no);
skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
ssid, ssid_len,
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
- u32 ratemask, bool directed, bool no_cck)
+ u32 ratemask, bool directed, bool no_cck,
+ struct ieee80211_channel *channel)
{
struct sk_buff *skb;
- skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
+ skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel,
+ ssid, ssid_len,
ie, ie_len, directed);
if (skb) {
if (no_cck)
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
changed |= BSS_CHANGED_ASSOC |
- BSS_CHANGED_ARP_FILTER;
+ BSS_CHANGED_ARP_FILTER |
+ BSS_CHANGED_PS;
mutex_lock(&sdata->u.mgd.mtx);
ieee80211_bss_info_change_notify(sdata, changed);
mutex_unlock(&sdata->u.mgd.mtx);
case NL80211_IFTYPE_MONITOR:
/* ignore virtual */
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ changed = BSS_CHANGED_IDLE;
+ break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
+ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
+ continue;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
goto set;
}
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, bool need_basic)
+ struct sk_buff *skb, bool need_basic,
+ enum ieee80211_band band)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
u8 i, rates, *pos;
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[band];
rates = sband->n_bitrates;
if (rates > 8)
rates = 8;
}
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, bool need_basic)
+ struct sk_buff *skb, bool need_basic,
+ enum ieee80211_band band)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
u8 i, exrates, *pos;
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[band];
exrates = sband->n_bitrates;
if (exrates > 8)
exrates -= 8;
rfkill_led_trigger_event(rfkill);
}
+const char *rfkill_get_led_trigger_name(struct rfkill *rfkill)
+{
+ return rfkill->led_trigger.name;
+}
+EXPORT_SYMBOL(rfkill_get_led_trigger_name);
+
+void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name)
+{
+ BUG_ON(!rfkill);
+
+ rfkill->ledtrigname = name;
+}
+EXPORT_SYMBOL(rfkill_set_led_trigger_name);
+
static int rfkill_led_trigger_register(struct rfkill *rfkill)
{
rfkill->led_trigger.name = rfkill->ledtrigname
ASSERT_WDEV_LOCK(wdev);
- if (!netif_running(wdev->netdev))
+ if (wdev->netdev && !netif_running(wdev->netdev))
return;
switch (wdev->iftype) {
case NL80211_IFTYPE_WDS:
/* these interface types don't really have a channel */
return;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ if (wdev->wiphy->features &
+ NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL)
+ *chanmode = CHAN_MODE_EXCLUSIVE;
+ return;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
WARN_ON(1);
rtnl_lock();
mutex_lock(&rdev->devlist_mtx);
- list_for_each_entry(wdev, &rdev->wdev_list, list)
- if (wdev->netdev)
+ list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ if (wdev->netdev) {
dev_close(wdev->netdev);
+ continue;
+ }
+ /* otherwise, check iftype */
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_P2P_DEVICE:
+ if (!wdev->p2p_started)
+ break;
+ rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
+ wdev->p2p_started = false;
+ rdev->opencount--;
+ break;
+ default:
+ break;
+ }
+ }
mutex_unlock(&rdev->devlist_mtx);
rtnl_unlock();
if (WARN_ON(wiphy->software_iftypes & types))
return -EINVAL;
+ /* Only a single P2P_DEVICE can be allowed */
+ if (WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
+ c->limits[j].max > 1))
+ return -EINVAL;
+
cnt += c->limits[j].max;
/*
* Don't advertise an unsupported type
dev_put(wdev->netdev);
}
+void cfg80211_unregister_wdev(struct wireless_dev *wdev)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+ ASSERT_RTNL();
+
+ if (WARN_ON(wdev->netdev))
+ return;
+
+ mutex_lock(&rdev->devlist_mtx);
+ list_del_rcu(&wdev->list);
+ rdev->devlist_generation++;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_P2P_DEVICE:
+ if (!wdev->p2p_started)
+ break;
+ rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
+ wdev->p2p_started = false;
+ rdev->opencount--;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+ mutex_unlock(&rdev->devlist_mtx);
+}
+EXPORT_SYMBOL(cfg80211_unregister_wdev);
+
static struct device_type wiphy_type = {
.name = "wlan",
};
const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
{
- struct net_device *dev = wdev->netdev;
const struct ieee80211_mgmt *mgmt;
u16 stype;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_AP_VLAN:
- if (!ether_addr_equal(mgmt->bssid, dev->dev_addr))
+ if (!ether_addr_equal(mgmt->bssid, wdev_address(wdev)))
err = -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
* cfg80211 doesn't track the stations
*/
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ /*
+ * fall through, P2P device only supports
+ * public action frames
+ */
default:
err = -EOPNOTSUPP;
break;
return err;
}
- if (!ether_addr_equal(mgmt->sa, dev->dev_addr))
+ if (!ether_addr_equal(mgmt->sa, wdev_address(wdev)))
return -EINVAL;
/* Transmit the Action frame as requested by user space */
if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
goto nla_put_failure;
}
+ CMD(start_p2p_device, START_P2P_DEVICE);
#ifdef CONFIG_NL80211_TESTMODE
CMD(testmode_cmd, TESTMODE);
if (dev &&
(nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
- nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr)))
+ nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
nla_put_u32(msg, NL80211_ATTR_GENERATION,
rdev->devlist_generation ^
(cfg80211_rdev_list_generation << 2)))
return PTR_ERR(wdev);
}
- if (type == NL80211_IFTYPE_MESH_POINT &&
- info->attrs[NL80211_ATTR_MESH_ID]) {
+ switch (type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ if (!info->attrs[NL80211_ATTR_MESH_ID])
+ break;
wdev_lock(wdev);
BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
IEEE80211_MAX_MESH_ID_LEN);
memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
wdev->mesh_id_up_len);
wdev_unlock(wdev);
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ /*
+ * P2P Device doesn't have a netdev, so doesn't go
+ * through the netdev notifier and must be added here
+ */
+ mutex_init(&wdev->mtx);
+ INIT_LIST_HEAD(&wdev->event_list);
+ spin_lock_init(&wdev->event_lock);
+ INIT_LIST_HEAD(&wdev->mgmt_registrations);
+ spin_lock_init(&wdev->mgmt_registrations_lock);
+
+ mutex_lock(&rdev->devlist_mtx);
+ wdev->identifier = ++rdev->wdev_id;
+ list_add_rcu(&wdev->list, &rdev->wdev_list);
+ rdev->devlist_generation++;
+ mutex_unlock(&rdev->devlist_mtx);
+ break;
+ default:
+ break;
}
if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
break;
default:
return -EOPNOTSUPP;
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
break;
default:
return -EOPNOTSUPP;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
break;
default:
return -EOPNOTSUPP;
return 0;
}
+static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ int err;
+
+ if (!rdev->ops->start_p2p_device)
+ return -EOPNOTSUPP;
+
+ if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
+ return -EOPNOTSUPP;
+
+ if (wdev->p2p_started)
+ return 0;
+
+ mutex_lock(&rdev->devlist_mtx);
+ err = cfg80211_can_add_interface(rdev, wdev->iftype);
+ mutex_unlock(&rdev->devlist_mtx);
+ if (err)
+ return err;
+
+ err = rdev->ops->start_p2p_device(&rdev->wiphy, wdev);
+ if (err)
+ return err;
+
+ wdev->p2p_started = true;
+ mutex_lock(&rdev->devlist_mtx);
+ rdev->opencount++;
+ mutex_unlock(&rdev->devlist_mtx);
+
+ return 0;
+}
+
+static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+
+ if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->stop_p2p_device)
+ return -EOPNOTSUPP;
+
+ if (!wdev->p2p_started)
+ return 0;
+
+ rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
+ wdev->p2p_started = false;
+
+ mutex_lock(&rdev->devlist_mtx);
+ rdev->opencount--;
+ mutex_unlock(&rdev->devlist_mtx);
+
+ if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
+ rdev->scan_req->aborted = true;
+ ___cfg80211_scan_done(rdev, true);
+ }
+
+ return 0;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
NL80211_FLAG_CHECK_NETDEV_UP)
#define NL80211_FLAG_NEED_WDEV 0x10
-/* If a netdev is associated, it must be UP */
+/* If a netdev is associated, it must be UP, P2P must be started */
#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
NL80211_FLAG_CHECK_NETDEV_UP)
}
dev_hold(dev);
+ } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
+ if (!wdev->p2p_started) {
+ mutex_unlock(&cfg80211_mutex);
+ if (rtnl)
+ rtnl_unlock();
+ return -ENETDOWN;
+ }
}
cfg80211_lock_rdev(rdev);
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
-
+ {
+ .cmd = NL80211_CMD_START_P2P_DEVICE,
+ .doit = nl80211_start_p2p_device,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_STOP_P2P_DEVICE,
+ .doit = nl80211_stop_p2p_device,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
[IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
[IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
+ [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
/*
* add more here as they are defined in radiotap.h
*/
if (reg_request->initiator !=
NL80211_REGDOM_SET_BY_USER)
continue;
- list_del(®_request->list);
- list_add_tail(®_request->list, &tmp_reg_req_list);
+ list_move_tail(®_request->list, &tmp_reg_req_list);
}
}
spin_unlock(®_requests_lock);
"into the queue\n",
reg_request->alpha2[0],
reg_request->alpha2[1]);
- list_del(®_request->list);
- list_add_tail(®_request->list, ®_requests_list);
+ list_move_tail(®_request->list, ®_requests_list);
}
spin_unlock(®_requests_lock);
return NULL;
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
- (signal < 0 || signal > 100)))
+ (signal < 0 || signal > 100)))
return NULL;
if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
{
- u8 *end, *pos;
-
- pos = bss->information_elements;
- if (pos == NULL)
+ if (bss->information_elements == NULL)
return NULL;
- end = pos + bss->len_information_elements;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
+ return cfg80211_find_ie(ie, bss->information_elements,
+ bss->len_information_elements);
}
EXPORT_SYMBOL(ieee80211_bss_get_ie);
if (otype == NL80211_IFTYPE_AP_VLAN)
return -EOPNOTSUPP;
+ /* cannot change into P2P device type */
+ if (ntype == NL80211_IFTYPE_P2P_DEVICE)
+ return -EOPNOTSUPP;
+
if (!rdev->ops->change_virtual_intf ||
!(rdev->wiphy.interface_modes & (1 << ntype)))
return -EOPNOTSUPP;
case NUM_NL80211_IFTYPES:
/* not happening */
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ WARN_ON(1);
+ break;
}
}
list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
if (wdev_iter == wdev)
continue;
- if (!netif_running(wdev_iter->netdev))
- continue;
+ if (wdev_iter->netdev) {
+ if (!netif_running(wdev_iter->netdev))
+ continue;
+ } else if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ if (!wdev_iter->p2p_started)
+ continue;
+ } else {
+ WARN_ON(1);
+ }
if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
continue;
if (descr->header_type == IW_HEADER_TYPE_POINT) {
/* Check if number of token fits within bounds */
if (wrqu->data.length > descr->max_tokens) {
- netdev_err(dev, "(WE) : Wireless Event too big (%d)\n",
- wrqu->data.length);
+ netdev_err(dev, "(WE) : Wireless Event (cmd=0x%04X) too big (%d)\n",
+ cmd, wrqu->data.length);
return;
}
if (wrqu->data.length < descr->min_tokens) {
- netdev_err(dev, "(WE) : Wireless Event too small (%d)\n",
- wrqu->data.length);
+ netdev_err(dev, "(WE) : Wireless Event (cmd=0x%04X) too small (%d)\n",
+ cmd, wrqu->data.length);
return;
}
/* Calculate extra_len - extra is NULL for restricted events */