Merge remote-tracking branch 'wireless-next/master' into mac80211-next

This commit is contained in:
Johannes Berg 2012-09-06 17:05:28 +02:00
commit 00b14825ee
146 changed files with 4318 additions and 1385 deletions

View File

@ -48,12 +48,6 @@ min_adv_mss - INTEGER
The advertised MSS depends on the first hop route MTU, but will The advertised MSS depends on the first hop route MTU, but will
never be lower than this setting. never be lower than this setting.
rt_cache_rebuild_count - INTEGER
The per net-namespace route cache emergency rebuild threshold.
Any net-namespace having its route cache rebuilt due to
a hash bucket chain being too long more than this many times
will have its route caching disabled
IP Fragmentation: IP Fragmentation:
ipfrag_high_thresh - INTEGER ipfrag_high_thresh - INTEGER

View File

@ -48,12 +48,12 @@ config BCMA_DRIVER_MIPS
config BCMA_SFLASH config BCMA_SFLASH
bool bool
depends on BCMA_DRIVER_MIPS && BROKEN depends on BCMA_DRIVER_MIPS
default y default y
config BCMA_NFLASH config BCMA_NFLASH
bool bool
depends on BCMA_DRIVER_MIPS && BROKEN depends on BCMA_DRIVER_MIPS
default y default y
config BCMA_DRIVER_GMAC_CMN config BCMA_DRIVER_GMAC_CMN

View File

@ -54,6 +54,7 @@ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
#ifdef CONFIG_BCMA_SFLASH #ifdef CONFIG_BCMA_SFLASH
/* driver_chipcommon_sflash.c */ /* driver_chipcommon_sflash.c */
int bcma_sflash_init(struct bcma_drv_cc *cc); int bcma_sflash_init(struct bcma_drv_cc *cc);
extern struct platform_device bcma_sflash_dev;
#else #else
static inline int bcma_sflash_init(struct bcma_drv_cc *cc) static inline int bcma_sflash_init(struct bcma_drv_cc *cc)
{ {
@ -65,6 +66,7 @@ static inline int bcma_sflash_init(struct bcma_drv_cc *cc)
#ifdef CONFIG_BCMA_NFLASH #ifdef CONFIG_BCMA_NFLASH
/* driver_chipcommon_nflash.c */ /* driver_chipcommon_nflash.c */
int bcma_nflash_init(struct bcma_drv_cc *cc); int bcma_nflash_init(struct bcma_drv_cc *cc);
extern struct platform_device bcma_nflash_dev;
#else #else
static inline int bcma_nflash_init(struct bcma_drv_cc *cc) static inline int bcma_nflash_init(struct bcma_drv_cc *cc)
{ {

View File

@ -5,15 +5,37 @@
* Licensed under the GNU/GPL. See COPYING for details. * Licensed under the GNU/GPL. See COPYING for details.
*/ */
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h> #include <linux/bcma/bcma.h>
#include <linux/bcma/bcma_driver_chipcommon.h>
#include <linux/delay.h>
#include "bcma_private.h" #include "bcma_private.h"
struct platform_device bcma_nflash_dev = {
.name = "bcma_nflash",
.num_resources = 0,
};
/* Initialize NAND flash access */ /* Initialize NAND flash access */
int bcma_nflash_init(struct bcma_drv_cc *cc) 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; return 0;
} }

View File

@ -101,7 +101,7 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val); 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; struct bcma_bus *bus = cc->core->bus;
@ -257,7 +257,7 @@ static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
} }
/* query bus clock frequency for PMU-enabled chipcommon */ /* 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; struct bcma_bus *bus = cc->core->bus;

View File

@ -5,15 +5,132 @@
* Licensed under the GNU/GPL. See COPYING for details. * Licensed under the GNU/GPL. See COPYING for details.
*/ */
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h> #include <linux/bcma/bcma.h>
#include <linux/bcma/bcma_driver_chipcommon.h>
#include <linux/delay.h>
#include "bcma_private.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 */ /* Initialize serial flash access */
int bcma_sflash_init(struct bcma_drv_cc *cc) 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; return 0;
} }

View File

@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
} }
#ifdef CONFIG_BCMA_BLOCKIO #ifdef CONFIG_BCMA_BLOCKIO
void bcma_host_pci_block_read(struct bcma_device *core, void *buffer, static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
size_t count, u16 offset, u8 reg_width) size_t count, u16 offset, u8 reg_width)
{ {
void __iomem *addr = core->bus->mmio + offset; void __iomem *addr = core->bus->mmio + offset;
if (core->bus->mapped_core != core) if (core->bus->mapped_core != core)
@ -100,8 +100,9 @@ void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
} }
} }
void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer, static void bcma_host_pci_block_write(struct bcma_device *core,
size_t count, u16 offset, u8 reg_width) const void *buffer, size_t count,
u16 offset, u8 reg_width)
{ {
void __iomem *addr = core->bus->mmio + offset; void __iomem *addr = core->bus->mmio + offset;
if (core->bus->mapped_core != core) if (core->bus->mapped_core != core)
@ -139,7 +140,7 @@ static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); 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, .read8 = bcma_host_pci_read8,
.read16 = bcma_host_pci_read16, .read16 = bcma_host_pci_read16,
.read32 = bcma_host_pci_read32, .read32 = bcma_host_pci_read32,

View File

@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
writel(value, core->io_wrap + offset); 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, .read8 = bcma_host_soc_read8,
.read16 = bcma_host_soc_read16, .read16 = bcma_host_soc_read16,
.read32 = bcma_host_soc_read32, .read32 = bcma_host_soc_read32,

View File

@ -7,6 +7,7 @@
#include "bcma_private.h" #include "bcma_private.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h> #include <linux/bcma/bcma.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -136,6 +137,22 @@ static int bcma_register_cores(struct bcma_bus *bus)
dev_id++; 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; return 0;
} }

View File

@ -177,7 +177,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV; return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL); data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) { if (!data) {
BT_ERR("Can't allocate memory for data structure"); BT_ERR("Can't allocate memory for data structure");
return -ENOMEM; return -ENOMEM;
@ -189,14 +189,12 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
data->urb = usb_alloc_urb(0, GFP_KERNEL); data->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!data->urb) { if (!data->urb) {
BT_ERR("Can't allocate URB"); BT_ERR("Can't allocate URB");
kfree(data);
return -ENOMEM; return -ENOMEM;
} }
if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
BT_ERR("Mini driver request failed"); BT_ERR("Mini driver request failed");
usb_free_urb(data->urb); usb_free_urb(data->urb);
kfree(data);
return -EIO; return -EIO;
} }
@ -209,7 +207,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
BT_ERR("Can't allocate memory for mini driver"); BT_ERR("Can't allocate memory for mini driver");
release_firmware(firmware); release_firmware(firmware);
usb_free_urb(data->urb); usb_free_urb(data->urb);
kfree(data);
return -ENOMEM; return -ENOMEM;
} }
@ -224,7 +221,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
BT_ERR("Firmware request failed"); BT_ERR("Firmware request failed");
usb_free_urb(data->urb); usb_free_urb(data->urb);
kfree(data->buffer); kfree(data->buffer);
kfree(data);
return -EIO; return -EIO;
} }
@ -236,7 +232,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
release_firmware(firmware); release_firmware(firmware);
usb_free_urb(data->urb); usb_free_urb(data->urb);
kfree(data->buffer); kfree(data->buffer);
kfree(data);
return -ENOMEM; return -ENOMEM;
} }
@ -271,7 +266,6 @@ static void bcm203x_disconnect(struct usb_interface *intf)
usb_free_urb(data->urb); usb_free_urb(data->urb);
kfree(data->fw_data); kfree(data->fw_data);
kfree(data->buffer); kfree(data->buffer);
kfree(data);
} }
static struct usb_driver bcm203x_driver = { static struct usb_driver bcm203x_driver = {

View File

@ -653,7 +653,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
} }
/* Initialize control structure and load firmware */ /* 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) { if (!data) {
BT_ERR("Can't allocate memory for control structure"); BT_ERR("Can't allocate memory for control structure");
goto done; goto done;
@ -674,7 +674,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) { if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
BT_ERR("Firmware request failed"); BT_ERR("Firmware request failed");
goto error; goto done;
} }
BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
@ -690,7 +690,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
hdev = hci_alloc_dev(); hdev = hci_alloc_dev();
if (!hdev) { if (!hdev) {
BT_ERR("Can't allocate HCI device"); BT_ERR("Can't allocate HCI device");
goto error; goto done;
} }
data->hdev = hdev; data->hdev = hdev;
@ -708,7 +708,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
if (hci_register_dev(hdev) < 0) { if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device"); BT_ERR("Can't register HCI device");
hci_free_dev(hdev); hci_free_dev(hdev);
goto error; goto done;
} }
usb_set_intfdata(intf, data); usb_set_intfdata(intf, data);
@ -718,9 +718,6 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
release: release:
release_firmware(firmware); release_firmware(firmware);
error:
kfree(data);
done: done:
return -EIO; return -EIO;
} }
@ -741,7 +738,6 @@ static void bfusb_disconnect(struct usb_interface *intf)
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data);
} }
static struct usb_driver bfusb_driver = { static struct usb_driver bfusb_driver = {

View File

@ -849,7 +849,7 @@ static int bluecard_probe(struct pcmcia_device *link)
bluecard_info_t *info; bluecard_info_t *info;
/* Create new info device */ /* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL); info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
@ -864,10 +864,7 @@ static int bluecard_probe(struct pcmcia_device *link)
static void bluecard_detach(struct pcmcia_device *link) static void bluecard_detach(struct pcmcia_device *link)
{ {
bluecard_info_t *info = link->priv;
bluecard_release(link); bluecard_release(link);
kfree(info);
} }

View File

@ -443,7 +443,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV; return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL); data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
@ -453,10 +453,8 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
init_usb_anchor(&data->rx_anchor); init_usb_anchor(&data->rx_anchor);
hdev = hci_alloc_dev(); hdev = hci_alloc_dev();
if (!hdev) { if (!hdev)
kfree(data);
return -ENOMEM; return -ENOMEM;
}
hdev->bus = HCI_USB; hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data); hci_set_drvdata(hdev, data);
@ -475,7 +473,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
err = hci_register_dev(hdev); err = hci_register_dev(hdev);
if (err < 0) { if (err < 0) {
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data);
return err; return err;
} }
@ -500,7 +497,6 @@ static void bpa10x_disconnect(struct usb_interface *intf)
hci_free_dev(data->hdev); hci_free_dev(data->hdev);
kfree_skb(data->rx_skb[0]); kfree_skb(data->rx_skb[0]);
kfree_skb(data->rx_skb[1]); kfree_skb(data->rx_skb[1]);
kfree(data);
} }
static struct usb_driver bpa10x_driver = { static struct usb_driver bpa10x_driver = {

View File

@ -638,7 +638,7 @@ static int bt3c_probe(struct pcmcia_device *link)
bt3c_info_t *info; bt3c_info_t *info;
/* Create new info device */ /* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL); info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
@ -654,10 +654,7 @@ static int bt3c_probe(struct pcmcia_device *link)
static void bt3c_detach(struct pcmcia_device *link) static void bt3c_detach(struct pcmcia_device *link)
{ {
bt3c_info_t *info = link->priv;
bt3c_release(link); bt3c_release(link);
kfree(info);
} }
static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data) static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)

View File

@ -956,11 +956,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d", BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
id->vendor, id->device, id->class, func->num); id->vendor, id->device, id->class, func->num);
card = kzalloc(sizeof(*card), GFP_KERNEL); card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL);
if (!card) { if (!card)
ret = -ENOMEM; return -ENOMEM;
goto done;
}
card->func = func; card->func = func;
@ -974,8 +972,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
if (btmrvl_sdio_register_dev(card) < 0) { if (btmrvl_sdio_register_dev(card) < 0) {
BT_ERR("Failed to register BT device!"); BT_ERR("Failed to register BT device!");
ret = -ENODEV; return -ENODEV;
goto free_card;
} }
/* Disable the interrupts on the card */ /* Disable the interrupts on the card */
@ -1023,9 +1020,6 @@ disable_host_int:
btmrvl_sdio_disable_host_int(card); btmrvl_sdio_disable_host_int(card);
unreg_dev: unreg_dev:
btmrvl_sdio_unregister_dev(card); btmrvl_sdio_unregister_dev(card);
free_card:
kfree(card);
done:
return ret; return ret;
} }
@ -1047,7 +1041,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
BT_DBG("unregester dev"); BT_DBG("unregester dev");
btmrvl_sdio_unregister_dev(card); btmrvl_sdio_unregister_dev(card);
btmrvl_remove_card(card->priv); btmrvl_remove_card(card->priv);
kfree(card);
} }
} }
} }

View File

@ -304,7 +304,7 @@ static int btsdio_probe(struct sdio_func *func,
tuple = tuple->next; tuple = tuple->next;
} }
data = kzalloc(sizeof(*data), GFP_KERNEL); data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
@ -315,10 +315,8 @@ static int btsdio_probe(struct sdio_func *func,
skb_queue_head_init(&data->txq); skb_queue_head_init(&data->txq);
hdev = hci_alloc_dev(); hdev = hci_alloc_dev();
if (!hdev) { if (!hdev)
kfree(data);
return -ENOMEM; return -ENOMEM;
}
hdev->bus = HCI_SDIO; hdev->bus = HCI_SDIO;
hci_set_drvdata(hdev, data); hci_set_drvdata(hdev, data);
@ -340,7 +338,6 @@ static int btsdio_probe(struct sdio_func *func,
err = hci_register_dev(hdev); err = hci_register_dev(hdev);
if (err < 0) { if (err < 0) {
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data);
return err; return err;
} }
@ -366,7 +363,6 @@ static void btsdio_remove(struct sdio_func *func)
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data);
} }
static struct sdio_driver btsdio_driver = { static struct sdio_driver btsdio_driver = {

View File

@ -567,7 +567,7 @@ static int btuart_probe(struct pcmcia_device *link)
btuart_info_t *info; btuart_info_t *info;
/* Create new info device */ /* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL); info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
@ -583,10 +583,7 @@ static int btuart_probe(struct pcmcia_device *link)
static void btuart_detach(struct pcmcia_device *link) static void btuart_detach(struct pcmcia_device *link)
{ {
btuart_info_t *info = link->priv;
btuart_release(link); btuart_release(link);
kfree(info);
} }
static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data) static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)

View File

@ -952,7 +952,7 @@ static int btusb_probe(struct usb_interface *intf,
return -ENODEV; return -ENODEV;
} }
data = kzalloc(sizeof(*data), GFP_KERNEL); data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
@ -975,10 +975,8 @@ static int btusb_probe(struct usb_interface *intf,
} }
} }
if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
kfree(data);
return -ENODEV; return -ENODEV;
}
data->cmdreq_type = USB_TYPE_CLASS; data->cmdreq_type = USB_TYPE_CLASS;
@ -998,10 +996,8 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->deferred); init_usb_anchor(&data->deferred);
hdev = hci_alloc_dev(); hdev = hci_alloc_dev();
if (!hdev) { if (!hdev)
kfree(data);
return -ENOMEM; return -ENOMEM;
}
hdev->bus = HCI_USB; hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data); hci_set_drvdata(hdev, data);
@ -1069,7 +1065,6 @@ static int btusb_probe(struct usb_interface *intf,
data->isoc, data); data->isoc, data);
if (err < 0) { if (err < 0) {
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data);
return err; return err;
} }
} }
@ -1077,7 +1072,6 @@ static int btusb_probe(struct usb_interface *intf,
err = hci_register_dev(hdev); err = hci_register_dev(hdev);
if (err < 0) { if (err < 0) {
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data);
return err; return err;
} }
@ -1110,7 +1104,6 @@ static void btusb_disconnect(struct usb_interface *intf)
usb_driver_release_interface(&btusb_driver, data->isoc); usb_driver_release_interface(&btusb_driver, data->isoc);
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(data);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM

View File

@ -297,16 +297,14 @@ static int bt_ti_probe(struct platform_device *pdev)
struct hci_dev *hdev; struct hci_dev *hdev;
int err; int err;
hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL); hst = devm_kzalloc(&pdev->dev, sizeof(struct ti_st), GFP_KERNEL);
if (!hst) if (!hst)
return -ENOMEM; return -ENOMEM;
/* Expose "hciX" device to user space */ /* Expose "hciX" device to user space */
hdev = hci_alloc_dev(); hdev = hci_alloc_dev();
if (!hdev) { if (!hdev)
kfree(hst);
return -ENOMEM; return -ENOMEM;
}
BT_DBG("hdev %p", hdev); BT_DBG("hdev %p", hdev);
@ -321,7 +319,6 @@ static int bt_ti_probe(struct platform_device *pdev)
err = hci_register_dev(hdev); err = hci_register_dev(hdev);
if (err < 0) { if (err < 0) {
BT_ERR("Can't register HCI device error %d", err); BT_ERR("Can't register HCI device error %d", err);
kfree(hst);
hci_free_dev(hdev); hci_free_dev(hdev);
return err; return err;
} }
@ -347,7 +344,6 @@ static int bt_ti_remove(struct platform_device *pdev)
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
hci_free_dev(hdev); hci_free_dev(hdev);
kfree(hst);
dev_set_drvdata(&pdev->dev, NULL); dev_set_drvdata(&pdev->dev, NULL);
return 0; return 0;

View File

@ -550,7 +550,7 @@ static int dtl1_probe(struct pcmcia_device *link)
dtl1_info_t *info; dtl1_info_t *info;
/* Create new info device */ /* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL); info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
@ -569,7 +569,6 @@ static void dtl1_detach(struct pcmcia_device *link)
dtl1_close(info); dtl1_close(info);
pcmcia_disable_device(link); pcmcia_disable_device(link);
kfree(info);
} }
static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data) static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)

View File

@ -449,7 +449,8 @@ hdlc_fill_fifo(struct bchannel *bch)
{ {
struct fritzcard *fc = bch->hw; struct fritzcard *fc = bch->hw;
struct hdlc_hw *hdlc; struct hdlc_hw *hdlc;
int count, fs, cnt = 0, idx, fillempty = 0; int count, fs, cnt = 0, idx;
bool fillempty = false;
u8 *p; u8 *p;
u32 *ptr, val, addr; u32 *ptr, val, addr;
@ -462,7 +463,7 @@ hdlc_fill_fifo(struct bchannel *bch)
return; return;
count = fs; count = fs;
p = bch->fill; p = bch->fill;
fillempty = 1; fillempty = true;
} else { } else {
count = bch->tx_skb->len - bch->tx_idx; count = bch->tx_skb->len - bch->tx_idx;
if (count <= 0) if (count <= 0)
@ -477,7 +478,7 @@ hdlc_fill_fifo(struct bchannel *bch)
hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
} }
ptr = (u32 *)p; ptr = (u32 *)p;
if (fillempty) { if (!fillempty) {
pr_debug("%s.B%d: %d/%d/%d", fc->name, bch->nr, count, pr_debug("%s.B%d: %d/%d/%d", fc->name, bch->nr, count,
bch->tx_idx, bch->tx_skb->len); bch->tx_idx, bch->tx_skb->len);
bch->tx_idx += count; bch->tx_idx += count;

View File

@ -9360,8 +9360,7 @@ static int __devinit bnx2x_prev_mark_path(struct bnx2x *bp)
struct bnx2x_prev_path_list *tmp_list; struct bnx2x_prev_path_list *tmp_list;
int rc; int rc;
tmp_list = (struct bnx2x_prev_path_list *) tmp_list = kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL);
kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL);
if (!tmp_list) { if (!tmp_list) {
BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n"); BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n");
return -ENOMEM; return -ENOMEM;

View File

@ -92,7 +92,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define DRV_MODULE_NAME "tg3" #define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3 #define TG3_MAJ_NUM 3
#define TG3_MIN_NUM 123 #define TG3_MIN_NUM 124
#define DRV_MODULE_VERSION \ #define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
#define DRV_MODULE_RELDATE "March 21, 2012" #define DRV_MODULE_RELDATE "March 21, 2012"
@ -672,6 +672,12 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
else else
bit = 1 << tp->pci_fn; bit = 1 << tp->pci_fn;
break; break;
case TG3_APE_LOCK_PHY0:
case TG3_APE_LOCK_PHY1:
case TG3_APE_LOCK_PHY2:
case TG3_APE_LOCK_PHY3:
bit = APE_LOCK_REQ_DRIVER;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -723,6 +729,12 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
else else
bit = 1 << tp->pci_fn; bit = 1 << tp->pci_fn;
break; break;
case TG3_APE_LOCK_PHY0:
case TG3_APE_LOCK_PHY1:
case TG3_APE_LOCK_PHY2:
case TG3_APE_LOCK_PHY3:
bit = APE_LOCK_GRANT_DRIVER;
break;
default: default:
return; return;
} }
@ -1052,6 +1064,8 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
udelay(80); udelay(80);
} }
tg3_ape_lock(tp, tp->phy_ape_lock);
*val = 0x0; *val = 0x0;
frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
@ -1086,6 +1100,8 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
udelay(80); udelay(80);
} }
tg3_ape_unlock(tp, tp->phy_ape_lock);
return ret; return ret;
} }
@ -1105,6 +1121,8 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
udelay(80); udelay(80);
} }
tg3_ape_lock(tp, tp->phy_ape_lock);
frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
MI_COM_PHY_ADDR_MASK); MI_COM_PHY_ADDR_MASK);
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
@ -1135,6 +1153,8 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
udelay(80); udelay(80);
} }
tg3_ape_unlock(tp, tp->phy_ape_lock);
return ret; return ret;
} }
@ -9066,8 +9086,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
tg3_flag(tp, 57765_PLUS)) { tg3_flag(tp, 57765_PLUS)) {
val = tr32(TG3_RDMA_RSRVCTRL_REG); val = tr32(TG3_RDMA_RSRVCTRL_REG);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) {
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK | val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK |
TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK | TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK |
TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK); TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK);
@ -9257,6 +9276,19 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32_f(RDMAC_MODE, rdmac_mode); tw32_f(RDMAC_MODE, rdmac_mode);
udelay(40); udelay(40);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
for (i = 0; i < TG3_NUM_RDMA_CHANNELS; i++) {
if (tr32(TG3_RDMA_LENGTH + (i << 2)) > TG3_MAX_MTU(tp))
break;
}
if (i < TG3_NUM_RDMA_CHANNELS) {
val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
val |= TG3_LSO_RD_DMA_TX_LENGTH_WA;
tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val);
tg3_flag_set(tp, 5719_RDMA_BUG);
}
}
tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
if (!tg3_flag(tp, 5705_PLUS)) if (!tg3_flag(tp, 5705_PLUS))
tw32(MBFREE_MODE, MBFREE_MODE_ENABLE); tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
@ -9616,6 +9648,16 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
TG3_STAT_ADD32(&sp->tx_ucast_packets, MAC_TX_STATS_UCAST); TG3_STAT_ADD32(&sp->tx_ucast_packets, MAC_TX_STATS_UCAST);
TG3_STAT_ADD32(&sp->tx_mcast_packets, MAC_TX_STATS_MCAST); TG3_STAT_ADD32(&sp->tx_mcast_packets, MAC_TX_STATS_MCAST);
TG3_STAT_ADD32(&sp->tx_bcast_packets, MAC_TX_STATS_BCAST); TG3_STAT_ADD32(&sp->tx_bcast_packets, MAC_TX_STATS_BCAST);
if (unlikely(tg3_flag(tp, 5719_RDMA_BUG) &&
(sp->tx_ucast_packets.low + sp->tx_mcast_packets.low +
sp->tx_bcast_packets.low) > TG3_NUM_RDMA_CHANNELS)) {
u32 val;
val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
val &= ~TG3_LSO_RD_DMA_TX_LENGTH_WA;
tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val);
tg3_flag_clear(tp, 5719_RDMA_BUG);
}
TG3_STAT_ADD32(&sp->rx_octets, MAC_RX_STATS_OCTETS); TG3_STAT_ADD32(&sp->rx_octets, MAC_RX_STATS_OCTETS);
TG3_STAT_ADD32(&sp->rx_fragments, MAC_RX_STATS_FRAGMENTS); TG3_STAT_ADD32(&sp->rx_fragments, MAC_RX_STATS_FRAGMENTS);
@ -12482,10 +12524,12 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
{ {
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
if (!tp->hw_stats)
return &tp->net_stats_prev;
spin_lock_bh(&tp->lock); spin_lock_bh(&tp->lock);
if (!tp->hw_stats) {
spin_unlock_bh(&tp->lock);
return &tp->net_stats_prev;
}
tg3_get_nstats(tp, stats); tg3_get_nstats(tp, stats);
spin_unlock_bh(&tp->lock); spin_unlock_bh(&tp->lock);
@ -13648,6 +13692,23 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
tg3_flag_set(tp, PAUSE_AUTONEG); tg3_flag_set(tp, PAUSE_AUTONEG);
tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX; tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
if (tg3_flag(tp, ENABLE_APE)) {
switch (tp->pci_fn) {
case 0:
tp->phy_ape_lock = TG3_APE_LOCK_PHY0;
break;
case 1:
tp->phy_ape_lock = TG3_APE_LOCK_PHY1;
break;
case 2:
tp->phy_ape_lock = TG3_APE_LOCK_PHY2;
break;
case 3:
tp->phy_ape_lock = TG3_APE_LOCK_PHY3;
break;
}
}
if (tg3_flag(tp, USE_PHYLIB)) if (tg3_flag(tp, USE_PHYLIB))
return tg3_phy_init(tp); return tg3_phy_init(tp);

View File

@ -1376,7 +1376,11 @@
#define TG3_LSO_RD_DMA_CRPTEN_CTRL 0x00004910 #define TG3_LSO_RD_DMA_CRPTEN_CTRL 0x00004910
#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K 0x00030000 #define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K 0x00030000
#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K 0x000c0000 #define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K 0x000c0000
/* 0x4914 --> 0x4c00 unused */ #define TG3_LSO_RD_DMA_TX_LENGTH_WA 0x02000000
/* 0x4914 --> 0x4be0 unused */
#define TG3_NUM_RDMA_CHANNELS 4
#define TG3_RDMA_LENGTH 0x00004be0
/* Write DMA control registers */ /* Write DMA control registers */
#define WDMAC_MODE 0x00004c00 #define WDMAC_MODE 0x00004c00
@ -2959,6 +2963,7 @@ enum TG3_FLAGS {
TG3_FLAG_L1PLLPD_EN, TG3_FLAG_L1PLLPD_EN,
TG3_FLAG_APE_HAS_NCSI, TG3_FLAG_APE_HAS_NCSI,
TG3_FLAG_4K_FIFO_LIMIT, TG3_FLAG_4K_FIFO_LIMIT,
TG3_FLAG_5719_RDMA_BUG,
TG3_FLAG_RESET_TASK_PENDING, TG3_FLAG_RESET_TASK_PENDING,
TG3_FLAG_5705_PLUS, TG3_FLAG_5705_PLUS,
TG3_FLAG_IS_5788, TG3_FLAG_IS_5788,
@ -3107,6 +3112,7 @@ struct tg3 {
int old_link; int old_link;
u8 phy_addr; u8 phy_addr;
u8 phy_ape_lock;
/* PHY info */ /* PHY info */
u32 phy_id; u32 phy_id;

View File

@ -4682,6 +4682,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM;
ndev->features = ndev->hw_features | ndev->features = ndev->hw_features |
NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
ndev->vlan_features = ndev->hw_features;
if (test_bit(QL_DMA64, &qdev->flags)) if (test_bit(QL_DMA64, &qdev->flags))
ndev->features |= NETIF_F_HIGHDMA; ndev->features |= NETIF_F_HIGHDMA;

View File

@ -736,9 +736,7 @@ MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
int __init init_module(void) int __init init_module(void)
{ {
dev_seeq = seeq8005_probe(-1); dev_seeq = seeq8005_probe(-1);
if (IS_ERR(dev_seeq)) return PTR_RET(dev_seeq);
return PTR_ERR(dev_seeq);
return 0;
} }
void __exit cleanup_module(void) void __exit cleanup_module(void)

View File

@ -1379,10 +1379,12 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
int vnet_hdr_sz; int vnet_hdr_sz;
int ret; int ret;
if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) {
if (copy_from_user(&ifr, argp, ifreq_len)) if (copy_from_user(&ifr, argp, ifreq_len))
return -EFAULT; return -EFAULT;
} else {
memset(&ifr, 0, sizeof(ifr));
}
if (cmd == TUNGETFEATURES) { if (cmd == TUNGETFEATURES) {
/* Currently this just means: "what IFF flags are valid?". /* Currently this just means: "what IFF flags are valid?".
* This is needed because we never checked for invalid flags on * This is needed because we never checked for invalid flags on

View File

@ -1314,7 +1314,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
int retv; int retv;
int length = 0; /* shut up GCC */ int length = 0; /* shut up GCC */
urb = usb_alloc_urb(0, GFP_NOIO); urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) if (!urb)
return -ENOMEM; return -ENOMEM;

View File

@ -1331,7 +1331,6 @@ struct ath5k_hw {
unsigned int nexttbtt; /* next beacon time in TU */ unsigned int nexttbtt; /* next beacon time in TU */
struct ath5k_txq *cabq; /* content after beacon */ struct ath5k_txq *cabq; /* content after beacon */
int power_level; /* Requested tx power in dBm */
bool assoc; /* associate state */ bool assoc; /* associate state */
bool enable_beacon; /* true if beacons are on */ bool enable_beacon; /* true if beacons are on */
@ -1425,6 +1424,7 @@ struct ath5k_hw {
/* Value in dB units */ /* Value in dB units */
s16 txp_cck_ofdm_pwr_delta; s16 txp_cck_ofdm_pwr_delta;
bool txp_setup; bool txp_setup;
int txp_requested; /* Requested tx power in dBm */
} ah_txpower; } ah_txpower;
struct ath5k_nfcal_hist ah_nfcal_hist; struct ath5k_nfcal_hist ah_nfcal_hist;

View File

@ -723,7 +723,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), padsize, ieee80211_get_hdrlen_from_skb(skb), padsize,
get_hw_packet_type(skb), get_hw_packet_type(skb),
(ah->power_level * 2), (ah->ah_txpower.txp_requested * 2),
hw_rate, hw_rate,
info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
cts_rate, duration); cts_rate, duration);
@ -1778,7 +1778,8 @@ ath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf)
ds->ds_data = bf->skbaddr; ds->ds_data = bf->skbaddr;
ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb), padsize, 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, ieee80211_get_tx_rate(ah->hw, info)->hw_value,
1, AR5K_TXKEYIX_INVALID, 1, AR5K_TXKEYIX_INVALID,
antenna, flags, 0, 0); antenna, flags, 0, 0);

View File

@ -208,8 +208,8 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
} }
if ((changed & IEEE80211_CONF_CHANGE_POWER) && if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
(ah->power_level != conf->power_level)) { (ah->ah_txpower.txp_requested != conf->power_level)) {
ah->power_level = conf->power_level; ah->ah_txpower.txp_requested = conf->power_level;
/* Half dB steps */ /* Half dB steps */
ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));

View File

@ -3516,6 +3516,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
{ {
unsigned int i; unsigned int i;
u16 *rates; u16 *rates;
s16 rate_idx_scaled = 0;
/* max_pwr is power level we got from driver/user in 0.5dB /* max_pwr is power level we got from driver/user in 0.5dB
* units, switch to 0.25dB units so we can compare */ * units, switch to 0.25dB units so we can compare */
@ -3562,20 +3563,32 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
for (i = 8; i <= 15; i++) for (i = 8; i <= 15; i++)
rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; 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 /* Now that we have all rates setup use table offset to
* match the power range set by user with the power indices * match the power range set by user with the power indices
* on PCDAC/PDADC table */ * on PCDAC/PDADC table */
for (i = 0; i < 16; i++) { 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 */ /* Don't get out of bounds */
if (rates[i] > 63) if (rate_idx_scaled > 63)
rates[i] = 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];
} }
@ -3639,10 +3652,17 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
if (!ah->ah_txpower.txp_setup || if (!ah->ah_txpower.txp_setup ||
(channel->hw_value != curr_channel->hw_value) || (channel->hw_value != curr_channel->hw_value) ||
(channel->center_freq != curr_channel->center_freq)) { (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)); 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_tpc = AR5K_TUNE_TPC_TXPOWER;
ah->ah_txpower.txp_requested = requested_txpower;
/* Calculate the powertable */ /* Calculate the powertable */
ret = ath5k_setup_channel_powertable(ah, channel, ret = ath5k_setup_channel_powertable(ah, channel,
ee_mode, type); ee_mode, type);
@ -3789,8 +3809,9 @@ ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
* RF buffer settings on 5211/5212+ so that we * RF buffer settings on 5211/5212+ so that we
* properly set curve indices. * properly set curve indices.
*/ */
ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_cur_pwr ? ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_requested ?
ah->ah_txpower.txp_cur_pwr / 2 : AR5K_TUNE_MAX_TXPOWER); ah->ah_txpower.txp_requested * 2 :
AR5K_TUNE_MAX_TXPOWER);
if (ret) if (ret)
return ret; return ret;

View File

@ -4901,90 +4901,79 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i], i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
chan->channel); chan->channel);
/* /*
* compare test group from regulatory * compare test group from regulatory
* channel list with test mode from pCtlMode * channel list with test mode from pCtlMode
* list * list
*/ */
if ((((cfgCtl & ~CTL_MODE_M) | if ((((cfgCtl & ~CTL_MODE_M) |
(pCtlMode[ctlMode] & CTL_MODE_M)) == (pCtlMode[ctlMode] & CTL_MODE_M)) ==
ctlIndex[i]) || ctlIndex[i]) ||
(((cfgCtl & ~CTL_MODE_M) | (((cfgCtl & ~CTL_MODE_M) |
(pCtlMode[ctlMode] & CTL_MODE_M)) == (pCtlMode[ctlMode] & CTL_MODE_M)) ==
((ctlIndex[i] & CTL_MODE_M) | ((ctlIndex[i] & CTL_MODE_M) |
SD_NO_CTL))) { SD_NO_CTL))) {
twiceMinEdgePower = twiceMinEdgePower =
ar9003_hw_get_max_edge_power(pEepData, ar9003_hw_get_max_edge_power(pEepData,
freq, i, freq, i,
is2ghz); is2ghz);
if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
/* /*
* Find the minimum of all CTL * Find the minimum of all CTL
* edge powers that apply to * edge powers that apply to
* this channel * this channel
*/ */
twiceMaxEdgePower = twiceMaxEdgePower =
min(twiceMaxEdgePower, min(twiceMaxEdgePower,
twiceMinEdgePower); twiceMinEdgePower);
else { else {
/* specific */ /* specific */
twiceMaxEdgePower = twiceMaxEdgePower = twiceMinEdgePower;
twiceMinEdgePower; break;
break;
}
} }
} }
}
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
ath_dbg(common, REGULATORY, ath_dbg(common, REGULATORY,
"SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n", "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
scaledPower, minCtlPower); scaledPower, minCtlPower);
/* Apply ctl mode to correct target power set */ /* Apply ctl mode to correct target power set */
switch (pCtlMode[ctlMode]) { switch (pCtlMode[ctlMode]) {
case CTL_11B: case CTL_11B:
for (i = ALL_TARGET_LEGACY_1L_5L; for (i = ALL_TARGET_LEGACY_1L_5L;
i <= ALL_TARGET_LEGACY_11S; i++) i <= ALL_TARGET_LEGACY_11S; i++)
pPwrArray[i] = pPwrArray[i] = (u8)min((u16)pPwrArray[i],
(u8)min((u16)pPwrArray[i], minCtlPower);
minCtlPower); break;
break; case CTL_11A:
case CTL_11A: case CTL_11G:
case CTL_11G: for (i = ALL_TARGET_LEGACY_6_24;
for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++)
i <= ALL_TARGET_LEGACY_54; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i],
pPwrArray[i] = minCtlPower);
(u8)min((u16)pPwrArray[i], break;
minCtlPower); case CTL_5GHT20:
break; case CTL_2GHT20:
case CTL_5GHT20: for (i = ALL_TARGET_HT20_0_8_16;
case CTL_2GHT20: i <= ALL_TARGET_HT20_23; i++)
for (i = ALL_TARGET_HT20_0_8_16; pPwrArray[i] = (u8)min((u16)pPwrArray[i],
i <= ALL_TARGET_HT20_21; i++) minCtlPower);
pPwrArray[i] = break;
(u8)min((u16)pPwrArray[i], case CTL_5GHT40:
minCtlPower); case CTL_2GHT40:
pPwrArray[ALL_TARGET_HT20_22] = for (i = ALL_TARGET_HT40_0_8_16;
(u8)min((u16)pPwrArray[ALL_TARGET_HT20_22], i <= ALL_TARGET_HT40_23; i++)
minCtlPower); pPwrArray[i] = (u8)min((u16)pPwrArray[i],
pPwrArray[ALL_TARGET_HT20_23] = minCtlPower);
(u8)min((u16)pPwrArray[ALL_TARGET_HT20_23], break;
minCtlPower); default:
break; 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 */ } /* end ctl mode checking */
} }

View File

@ -1333,6 +1333,34 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
return ret; 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, static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
@ -1760,6 +1788,7 @@ struct ieee80211_ops ath9k_htc_ops = {
.sta_add = ath9k_htc_sta_add, .sta_add = ath9k_htc_sta_add,
.sta_remove = ath9k_htc_sta_remove, .sta_remove = ath9k_htc_sta_remove,
.conf_tx = ath9k_htc_conf_tx, .conf_tx = ath9k_htc_conf_tx,
.sta_rc_update = ath9k_htc_sta_rc_update,
.bss_info_changed = ath9k_htc_bss_info_changed, .bss_info_changed = ath9k_htc_bss_info_changed,
.set_key = ath9k_htc_set_key, .set_key = ath9k_htc_set_key,
.get_tsf = ath9k_htc_get_tsf, .get_tsf = ath9k_htc_get_tsf,

File diff suppressed because it is too large Load Diff

View File

@ -160,10 +160,6 @@ struct ath_rate_table {
u32 user_ratekbps; u32 user_ratekbps;
u8 ratecode; u8 ratecode;
u8 dot11rate; u8 dot11rate;
u8 ctrl_rate;
u8 cw40index;
u8 sgi_index;
u8 ht_index;
} info[RATE_TABLE_SIZE]; } info[RATE_TABLE_SIZE];
u32 probe_interval; u32 probe_interval;
u8 initial_ratemax; u8 initial_ratemax;

View File

@ -425,6 +425,7 @@ struct ar9170 {
bool rx_has_plcp; bool rx_has_plcp;
struct sk_buff *rx_failover; struct sk_buff *rx_failover;
int rx_failover_missing; int rx_failover_missing;
u32 ampdu_ref;
/* FIFO for collecting outstanding BlockAckRequest */ /* FIFO for collecting outstanding BlockAckRequest */
struct list_head bar_list[__AR9170_NUM_TXQ]; struct list_head bar_list[__AR9170_NUM_TXQ];

View File

@ -341,6 +341,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (SUPP(CARL9170FW_WLANTX_CAB)) { if (SUPP(CARL9170FW_WLANTX_CAB)) {
if_comb_types |= if_comb_types |=
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_P2P_GO); BIT(NL80211_IFTYPE_P2P_GO);
} }
} }

View File

@ -318,10 +318,10 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
bssid = common->curbssid; bssid = common->curbssid;
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
cam_mode |= AR9170_MAC_CAM_IBSS; cam_mode |= AR9170_MAC_CAM_IBSS;
break; break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
cam_mode |= AR9170_MAC_CAM_AP; cam_mode |= AR9170_MAC_CAM_AP;

View File

@ -616,10 +616,12 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
goto unlock; goto unlock;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
if ((vif->type == NL80211_IFTYPE_STATION) || if ((vif->type == NL80211_IFTYPE_STATION) ||
(vif->type == NL80211_IFTYPE_WDS) || (vif->type == NL80211_IFTYPE_WDS) ||
(vif->type == NL80211_IFTYPE_AP)) (vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_MESH_POINT))
break; break;
err = -EBUSY; err = -EBUSY;

View File

@ -206,6 +206,7 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
carl9170_update_beacon(ar, true); carl9170_update_beacon(ar, true);
break; break;
@ -623,7 +624,8 @@ static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)
#undef TID_CHECK #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; __le16 fc;
@ -636,6 +638,9 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms)
return true; 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 * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts
* certain frame types can be part of an aMPDU. * certain frame types can be part of an aMPDU.
@ -684,12 +689,15 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
if (unlikely(len < sizeof(*mac))) if (unlikely(len < sizeof(*mac)))
goto drop; goto drop;
memset(&status, 0, sizeof(status));
mpdu_len = len - sizeof(*mac); mpdu_len = len - sizeof(*mac);
mac = (void *)(buf + mpdu_len); mac = (void *)(buf + mpdu_len);
mac_status = mac->status; mac_status = mac->status;
switch (mac_status & AR9170_RX_STATUS_MPDU) { switch (mac_status & AR9170_RX_STATUS_MPDU) {
case AR9170_RX_STATUS_MPDU_FIRST: case AR9170_RX_STATUS_MPDU_FIRST:
ar->ampdu_ref++;
/* Aggregated MPDUs start with an PLCP header */ /* Aggregated MPDUs start with an PLCP header */
if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
head = (void *) buf; head = (void *) buf;
@ -720,12 +728,13 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
break; break;
case AR9170_RX_STATUS_MPDU_LAST: case AR9170_RX_STATUS_MPDU_LAST:
status.flag |= RX_FLAG_AMPDU_IS_LAST;
/* /*
* The last frame of an A-MPDU has an extra tail * The last frame of an A-MPDU has an extra tail
* which does contain the phy status of the whole * which does contain the phy status of the whole
* aggregate. * aggregate.
*/ */
if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
mpdu_len -= sizeof(struct ar9170_rx_phystatus); mpdu_len -= sizeof(struct ar9170_rx_phystatus);
phy = (void *)(buf + mpdu_len); phy = (void *)(buf + mpdu_len);
@ -773,11 +782,10 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN)))
goto drop; goto drop;
memset(&status, 0, sizeof(status));
if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status)))
goto drop; goto drop;
if (!carl9170_ampdu_check(ar, buf, mac_status)) if (!carl9170_ampdu_check(ar, buf, mac_status, &status))
goto drop; goto drop;
if (phy) if (phy)

View File

@ -4,6 +4,7 @@ b43-y += tables.o
b43-$(CONFIG_B43_PHY_N) += tables_nphy.o b43-$(CONFIG_B43_PHY_N) += tables_nphy.o
b43-$(CONFIG_B43_PHY_N) += radio_2055.o b43-$(CONFIG_B43_PHY_N) += radio_2055.o
b43-$(CONFIG_B43_PHY_N) += radio_2056.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_common.o
b43-y += phy_g.o b43-y += phy_g.o
b43-y += phy_a.o b43-y += phy_a.o

View File

@ -241,16 +241,18 @@ enum {
#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */ #define B43_SHM_SH_PHYVER 0x0050 /* PHY version */
#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ #define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ #define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */ #define B43_SHM_SH_HOSTF1 0x005E /* Hostflags 1 for ucode options */
#define B43_SHM_SH_HOSTFMI 0x0060 /* Hostflags for ucode options (middle) */ #define B43_SHM_SH_HOSTF2 0x0060 /* Hostflags 2 for ucode options */
#define B43_SHM_SH_HOSTFHI 0x0062 /* Hostflags for ucode options (high) */ #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_RFATT 0x0064 /* Current radio attenuation value */
#define B43_SHM_SH_RADAR 0x0066 /* Radar register */ #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_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_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 0x00A0 /* Current channel (low 8bit only) */
#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */ #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_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 */ #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* TSSI information */ /* TSSI information */
#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */ #define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */
@ -415,6 +417,8 @@ enum {
#define B43_PHYTYPE_HT 0x07 #define B43_PHYTYPE_HT 0x07
#define B43_PHYTYPE_LCN 0x08 #define B43_PHYTYPE_LCN 0x08
#define B43_PHYTYPE_LCNXN 0x09 #define B43_PHYTYPE_LCNXN 0x09
#define B43_PHYTYPE_LCN40 0x0a
#define B43_PHYTYPE_AC 0x0b
/* PHYRegisters */ /* PHYRegisters */
#define B43_PHY_ILT_A_CTRL 0x0072 #define B43_PHY_ILT_A_CTRL 0x0072

View File

@ -533,11 +533,11 @@ u64 b43_hf_read(struct b43_wldev *dev)
{ {
u64 ret; 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 <<= 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 <<= 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; return ret;
} }
@ -550,9 +550,9 @@ void b43_hf_write(struct b43_wldev *dev, u64 value)
lo = (value & 0x00000000FFFFULL); lo = (value & 0x00000000FFFFULL);
mi = (value & 0x0000FFFF0000ULL) >> 16; mi = (value & 0x0000FFFF0000ULL) >> 16;
hi = (value & 0xFFFF00000000ULL) >> 32; 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_HOSTF1, lo);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2, mi);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3, hi);
} }
/* Read the firmware capabilities bitmask (Opensource firmware only) */ /* Read the firmware capabilities bitmask (Opensource firmware only) */
@ -4278,6 +4278,35 @@ out:
return err; 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 */ /* Get PHY and RADIO versioning numbers */
static int b43_phy_versioning(struct b43_wldev *dev) static int b43_phy_versioning(struct b43_wldev *dev)
{ {
@ -4338,13 +4367,13 @@ static int b43_phy_versioning(struct b43_wldev *dev)
unsupported = 1; unsupported = 1;
} }
if (unsupported) { if (unsupported) {
b43err(dev->wl, "FOUND UNSUPPORTED PHY " b43err(dev->wl, "FOUND UNSUPPORTED PHY (Analog %u, Type %d (%s), Revision %u)\n",
"(Analog %u, Type %u, Revision %u)\n", analog_type, phy_type, b43_phy_name(dev, phy_type),
analog_type, phy_type, phy_rev); phy_rev);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n", b43info(dev->wl, "Found PHY: Analog %u, Type %d (%s), Revision %u\n",
analog_type, phy_type, phy_rev); analog_type, phy_type, b43_phy_name(dev, phy_type), phy_rev);
/* Get RADIO versioning */ /* Get RADIO versioning */
if (dev->dev->core_rev >= 24) { if (dev->dev->core_rev >= 24) {

View File

@ -240,6 +240,21 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
(b43_radio_read16(dev, offset) & mask) | set); (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) u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{ {
assert_mac_suspended(dev); assert_mac_suspended(dev);
@ -428,7 +443,7 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
average = (a + b + c + d + 2) / 4; average = (a + b + c + d + 2) / 4;
if (is_ofdm) { if (is_ofdm) {
/* Adjust for CCK-boost */ /* 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) & B43_HF_CCKBOOST)
average = (average >= 13) ? (average - 13) : 0; average = (average >= 13) ? (average - 13) : 0;
} }

View File

@ -364,6 +364,12 @@ void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
*/ */
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); 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 * b43_radio_lock - Lock firmware radio register access
*/ */

View File

@ -32,6 +32,7 @@
#include "tables_nphy.h" #include "tables_nphy.h"
#include "radio_2055.h" #include "radio_2055.h"
#include "radio_2056.h" #include "radio_2056.h"
#include "radio_2057.h"
#include "main.h" #include "main.h"
struct nphy_txgains { struct nphy_txgains {
@ -126,6 +127,46 @@ ok:
b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); 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 */ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
u16 value, u8 core, bool off) u16 value, u8 core, bool off)
@ -458,6 +499,137 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
b43_nphy_stay_in_carrier_search(dev, false); 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 * Radio 0x2056
**************************************************/ **************************************************/
@ -545,7 +717,9 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
enum ieee80211_band band = b43_current_band(dev->wl); enum ieee80211_band band = b43_current_band(dev->wl);
u16 offset; u16 offset;
u8 i; 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_WARN_ON(dev->phy.rev < 3);
@ -630,7 +804,56 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee); b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
} }
} else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) { } 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(50);
@ -643,6 +866,37 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
udelay(300); 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) static void b43_radio_init2056_pre(struct b43_wldev *dev)
{ {
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
@ -665,10 +919,8 @@ static void b43_radio_init2056_post(struct b43_wldev *dev)
b43_radio_mask(dev, B2056_SYN_COM_RESET, ~0x2); b43_radio_mask(dev, B2056_SYN_COM_RESET, ~0x2);
b43_radio_mask(dev, B2056_SYN_PLL_MAST2, ~0xFC); b43_radio_mask(dev, B2056_SYN_PLL_MAST2, ~0xFC);
b43_radio_mask(dev, B2056_SYN_RCCAL_CTRL0, ~0x1); b43_radio_mask(dev, B2056_SYN_RCCAL_CTRL0, ~0x1);
/* if (dev->phy.n->init_por)
if (nphy->init_por) b43_radio_2056_rcal(dev);
Call Radio 2056 Recalibrate
*/
} }
/* /*
@ -680,6 +932,8 @@ static void b43_radio_init2056(struct b43_wldev *dev)
b43_radio_init2056_pre(dev); b43_radio_init2056_pre(dev);
b2056_upload_inittabs(dev, 0, 0); b2056_upload_inittabs(dev, 0, 0);
b43_radio_init2056_post(dev); b43_radio_init2056_post(dev);
dev->phy.n->init_por = false;
} }
/************************************************** /**************************************************
@ -753,8 +1007,6 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
{ {
struct b43_phy_n *nphy = dev->phy.n; struct b43_phy_n *nphy = dev->phy.n;
struct ssb_sprom *sprom = dev->dev->bus_sprom; struct ssb_sprom *sprom = dev->dev->bus_sprom;
int i;
u16 val;
bool workaround = false; bool workaround = false;
if (sprom->revision < 4) if (sprom->revision < 4)
@ -777,15 +1029,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
b43_radio_set(dev, B2055_CAL_MISC, 0x1); b43_radio_set(dev, B2055_CAL_MISC, 0x1);
msleep(1); msleep(1);
b43_radio_set(dev, B2055_CAL_MISC, 0x40); b43_radio_set(dev, B2055_CAL_MISC, 0x40);
for (i = 0; i < 200; i++) { if (!b43_radio_wait_value(dev, B2055_CAL_COUT2, 0x80, 0x80, 10, 2000))
val = b43_radio_read(dev, B2055_CAL_COUT2);
if (val & 0x80) {
i = 0;
break;
}
udelay(10);
}
if (i)
b43err(dev->wl, "radio post init timeout\n"); b43err(dev->wl, "radio post init timeout\n");
b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
b43_switch_channel(dev, dev->phy.channel); b43_switch_channel(dev, dev->phy.channel);
@ -1860,12 +2104,334 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev) 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); b43_nphy_gain_ctl_workarounds_rev3plus(dev);
else else
b43_nphy_gain_ctl_workarounds_rev1_2(dev); 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) static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
{ {
struct b43_phy_n *nphy = dev->phy.n; struct b43_phy_n *nphy = dev->phy.n;
@ -1916,7 +2482,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
rx2tx_delays[6] = 1; rx2tx_delays[6] = 1;
rx2tx_events[7] = 0x1F; 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)); ARRAY_SIZE(rx2tx_events));
} }
@ -1926,8 +2492,13 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700); b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700);
b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D); if (!dev->phy.is_40mhz) {
b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D); 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_nphy_gain_ctl_workarounds(dev);
@ -1963,13 +2534,14 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32); b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32);
if (dev->phy.rev == 4 && 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, b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC,
0x70); 0x70);
b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC, b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC,
0x70); 0x70);
} }
/* Dropped probably-always-true condition */
b43_phy_write(dev, 0x224, 0x03eb); b43_phy_write(dev, 0x224, 0x03eb);
b43_phy_write(dev, 0x225, 0x03eb); b43_phy_write(dev, 0x225, 0x03eb);
b43_phy_write(dev, 0x226, 0x0341); b43_phy_write(dev, 0x226, 0x0341);
@ -1982,6 +2554,9 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_phy_write(dev, 0x22d, 0x042b); b43_phy_write(dev, 0x22d, 0x042b);
b43_phy_write(dev, 0x22e, 0x0381); b43_phy_write(dev, 0x22e, 0x0381);
b43_phy_write(dev, 0x22f, 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) static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
@ -1996,6 +2571,12 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 }; u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 }; 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 && if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
nphy->band5g_pwrgain) { nphy->band5g_pwrgain) {
b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8); b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
@ -2007,8 +2588,10 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A); 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, 0x10), 0x000A);
b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); if (dev->phy.rev < 3) {
b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
}
if (dev->phy.rev < 2) { if (dev->phy.rev < 2) {
b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000); b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
@ -2024,11 +2607,6 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); 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, 0, events1, delays1, 7);
b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7); b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
@ -2055,11 +2633,13 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
b43_phy_mask(dev, B43_NPHY_PIL_DW1, if (dev->phy.rev < 3) {
~B43_NPHY_PIL_DW_64QAM & 0xFFFF); b43_phy_mask(dev, B43_NPHY_PIL_DW1,
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5); ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4); b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00); 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) if (dev->phy.rev == 2)
b43_phy_set(dev, B43_NPHY_FINERX2_CGC, b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
@ -2083,7 +2663,9 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
b43_phy_set(dev, B43_NPHY_IQFLIP, b43_phy_set(dev, B43_NPHY_IQFLIP,
B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); 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); b43_nphy_workarounds_rev3plus(dev);
else else
b43_nphy_workarounds_rev1_2(dev); b43_nphy_workarounds_rev1_2(dev);
@ -2542,7 +3124,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
b43_nphy_ipa_internal_tssi_setup(dev); b43_nphy_ipa_internal_tssi_setup(dev);
if (phy->rev >= 7) 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) else if (phy->rev >= 3)
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false); b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false);
@ -2554,7 +3136,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
b43_nphy_rssi_select(dev, 0, 0); b43_nphy_rssi_select(dev, 0, 0);
if (phy->rev >= 7) 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) else if (phy->rev >= 3)
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true); b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true);
@ -4761,6 +5343,7 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4); nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4);
nphy->spur_avoid = (phy->rev >= 3) ? nphy->spur_avoid = (phy->rev >= 3) ?
B43_SPUR_AVOID_AUTO : B43_SPUR_AVOID_DISABLE; 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->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->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->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
@ -4801,6 +5384,8 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
nphy->ipa2g_on = sprom->fem.ghz2.extpa_gain == 2; nphy->ipa2g_on = sprom->fem.ghz2.extpa_gain == 2;
nphy->ipa5g_on = sprom->fem.ghz5.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) static void b43_nphy_op_free(struct b43_wldev *dev)
@ -4887,7 +5472,9 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
if (blocked) { if (blocked) {
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
~B43_NPHY_RFCTL_CMD_CHIP0PU); ~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_mask(dev, 0x09, ~0x2);
b43_radio_write(dev, 0x204D, 0); b43_radio_write(dev, 0x204D, 0);
@ -4905,7 +5492,10 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
b43_radio_write(dev, 0x3064, 0); b43_radio_write(dev, 0x3064, 0);
} }
} else { } 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_radio_init2056(dev);
b43_switch_channel(dev, dev->phy.channel); b43_switch_channel(dev, dev->phy.channel);
} else { } else {

View File

@ -785,6 +785,7 @@ struct b43_phy_n {
u16 papd_epsilon_offset[2]; u16 papd_epsilon_offset[2];
s32 preamble_override; s32 preamble_override;
u32 bb_mult_save; u32 bb_mult_save;
bool init_por;
bool gain_boost; bool gain_boost;
bool elna_gain_config; bool elna_gain_config;

View File

@ -0,0 +1,141 @@
/*
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++;
}
}
}

View File

@ -0,0 +1,430 @@
#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_ */

View File

@ -2757,6 +2757,49 @@ const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = {
{ 0x00C0, 6, 0xE7, 0xF9, 0xEC, 0xFB } /* field == 0x4000 (fls 15) */ { 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 = { struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
{ 10, 14, 19, 27 }, { 10, 14, 19, 27 },
{ -5, 6, 10, 15 }, { -5, 6, 10, 15 },
@ -3248,3 +3291,35 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
return e; 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;
}

View File

@ -35,6 +35,14 @@ struct nphy_rf_control_override_rev3 {
u8 val_addr1; 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 { struct nphy_gain_ctl_workaround_entry {
s8 lna1_gain[4]; s8 lna1_gain[4];
s8 lna2_gain[4]; s8 lna2_gain[4];
@ -202,5 +210,7 @@ extern const struct nphy_rf_control_override_rev2
tbl_rf_control_override_rev2[]; tbl_rf_control_override_rev2[];
extern const struct nphy_rf_control_override_rev3 extern const struct nphy_rf_control_override_rev3
tbl_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_ */ #endif /* B43_TABLES_NPHY_H_ */

View File

@ -1920,7 +1920,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
return 0; return 0;
ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
(ssb_read32(gpiodev, B43legacy_GPIO_CONTROL) (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
& mask) | set); & ~mask) | set);
return 0; return 0;
} }

View File

@ -86,7 +86,9 @@ MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
MODULE_LICENSE("Dual BSD/GPL"); 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 */ /* recognized BCMA Core IDs */
static struct bcma_device_id brcms_coreid_table[] = { static struct bcma_device_id brcms_coreid_table[] = {

View File

@ -7512,15 +7512,10 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
channel = BRCMS_CHAN_CHANNEL(rxh->RxChan); channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
if (channel > 14) { rx_status->band =
rx_status->band = IEEE80211_BAND_5GHZ; channel > 14 ? IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
rx_status->freq = ieee80211_ofdm_chan_to_freq( rx_status->freq =
WF_CHAN_FACTOR_5_G/2, channel); ieee80211_channel_to_frequency(channel, rx_status->band);
} else {
rx_status->band = IEEE80211_BAND_2GHZ;
rx_status->freq = ieee80211_dsss_chan_to_freq(channel);
}
rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh); rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);

View File

@ -67,11 +67,6 @@
#define WL_CHANSPEC_BAND_2G 0x2000 #define WL_CHANSPEC_BAND_2G 0x2000
#define INVCHANSPEC 255 #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_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) #define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)

View File

@ -4860,7 +4860,7 @@ EXPORT_SYMBOL(il_add_beacon_time);
#ifdef CONFIG_PM #ifdef CONFIG_PM
int static int
il_pci_suspend(struct device *device) il_pci_suspend(struct device *device)
{ {
struct pci_dev *pdev = to_pci_dev(device); struct pci_dev *pdev = to_pci_dev(device);
@ -4877,9 +4877,8 @@ il_pci_suspend(struct device *device)
return 0; return 0;
} }
EXPORT_SYMBOL(il_pci_suspend);
int static int
il_pci_resume(struct device *device) il_pci_resume(struct device *device)
{ {
struct pci_dev *pdev = to_pci_dev(device); struct pci_dev *pdev = to_pci_dev(device);
@ -4906,16 +4905,8 @@ il_pci_resume(struct device *device)
return 0; return 0;
} }
EXPORT_SYMBOL(il_pci_resume);
const struct dev_pm_ops il_pm_ops = { SIMPLE_DEV_PM_OPS(il_pm_ops, il_pci_suspend, il_pci_resume);
.suspend = il_pci_suspend,
.resume = il_pci_resume,
.freeze = il_pci_suspend,
.thaw = il_pci_resume,
.poweroff = il_pci_suspend,
.restore = il_pci_resume,
};
EXPORT_SYMBOL(il_pm_ops); EXPORT_SYMBOL(il_pm_ops);
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */

View File

@ -1845,8 +1845,6 @@ __le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon,
u32 beacon_interval); u32 beacon_interval);
#ifdef CONFIG_PM #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; extern const struct dev_pm_ops il_pm_ops;
#define IL_LEGACY_PM_OPS (&il_pm_ops) #define IL_LEGACY_PM_OPS (&il_pm_ops)

View File

@ -487,16 +487,13 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state)
} }
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir);
void iwl_dbgfs_unregister(struct iwl_priv *priv);
#else #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; return 0;
} }
static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
{
}
#endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUGFS */
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG

View File

@ -2349,24 +2349,19 @@ DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled);
* Create the debugfs files and directories * 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_data, *dir_rf, *dir_debug;
struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
dir_drv = debugfs_create_dir(name, phyd); priv->debugfs_dir = dbgfs_dir;
if (!dir_drv)
return -ENOMEM;
priv->debugfs_dir = dir_drv; dir_data = debugfs_create_dir("data", dbgfs_dir);
dir_data = debugfs_create_dir("data", dir_drv);
if (!dir_data) if (!dir_data)
goto err; goto err;
dir_rf = debugfs_create_dir("rf", dir_drv); dir_rf = debugfs_create_dir("rf", dbgfs_dir);
if (!dir_rf) if (!dir_rf)
goto err; goto err;
dir_debug = debugfs_create_dir("debug", dir_drv); dir_debug = debugfs_create_dir("debug", dbgfs_dir);
if (!dir_debug) if (!dir_debug)
goto err; goto err;
@ -2412,25 +2407,30 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
/* Calibrations disabled/enabled status*/ /* Calibrations disabled/enabled status*/
DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); 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; return 0;
err: err:
IWL_ERR(priv, "Can't create the debugfs directory\n"); IWL_ERR(priv, "failed to create the dvm debugfs entries\n");
iwl_dbgfs_unregister(priv);
return -ENOMEM; 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;
}

View File

@ -195,7 +195,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
ARRAY_SIZE(iwlagn_iface_combinations_dualmode); 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 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_DISABLE_BEACON_HINTS |

View File

@ -862,7 +862,8 @@ void iwl_down(struct iwl_priv *priv)
* No race since we hold the mutex here and a new one * No race since we hold the mutex here and a new one
* can't come in at this time. * 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 = exit_pending =
test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
@ -994,7 +995,11 @@ static void iwl_bg_restart(struct work_struct *data)
iwlagn_prepare_restart(priv); iwlagn_prepare_restart(priv);
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
iwl_cancel_deferred_work(priv); 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 { } else {
WARN_ON(1); WARN_ON(1);
} }
@ -1222,7 +1227,8 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
const struct iwl_cfg *cfg, const struct iwl_cfg *cfg,
const struct iwl_fw *fw) const struct iwl_fw *fw,
struct dentry *dbgfs_dir)
{ {
struct iwl_priv *priv; struct iwl_priv *priv;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
@ -1466,13 +1472,17 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
goto out_destroy_workqueue; goto out_destroy_workqueue;
if (iwl_dbgfs_register(priv, DRV_NAME)) if (iwl_dbgfs_register(priv, dbgfs_dir))
IWL_ERR(priv, goto out_mac80211_unregister;
"failed to create debugfs files. Ignoring error\n");
return op_mode; return op_mode;
out_mac80211_unregister:
iwlagn_mac_unregister(priv);
out_destroy_workqueue: out_destroy_workqueue:
iwl_tt_exit(priv);
iwl_testmode_free(priv);
iwl_cancel_deferred_work(priv);
destroy_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue);
priv->workqueue = NULL; priv->workqueue = NULL;
iwl_uninit_drv(priv); iwl_uninit_drv(priv);
@ -1493,8 +1503,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
iwl_dbgfs_unregister(priv);
iwl_testmode_free(priv); iwl_testmode_free(priv);
iwlagn_mac_unregister(priv); iwlagn_mac_unregister(priv);

View File

@ -150,7 +150,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
if (!(flags & CMD_ASYNC)) { if (!(flags & CMD_ASYNC)) {
cmd.flags |= CMD_WANT_SKB; cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD;
might_sleep(); might_sleep();
} }

View File

@ -433,7 +433,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
* only. Check this here. * only. Check this here.
*/ */
if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON && 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)) "Tx while agg.state = %d", tid_data->agg.state))
goto drop_unlock_sta; goto drop_unlock_sta;

View File

@ -101,6 +101,10 @@ MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifdef CONFIG_IWLWIFI_DEBUGFS
static struct dentry *iwl_dbgfs_root;
#endif
/** /**
* struct iwl_drv - drv common data * struct iwl_drv - drv common data
* @list: list of drv structures using this opmode * @list: list of drv structures using this opmode
@ -126,6 +130,12 @@ struct iwl_drv {
char firmware_name[25]; /* name of firmware file to load */ char firmware_name[25]; /* name of firmware file to load */
struct completion request_firmware_complete; 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 #define DVM_OP_MODE 0
@ -194,7 +204,8 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
return 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_INDEX 100
#define UCODE_EXPERIMENTAL_TAG "exp" #define UCODE_EXPERIMENTAL_TAG "exp"
@ -231,7 +242,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name,
drv->trans->dev, drv->trans->dev,
GFP_KERNEL, drv, iwl_ucode_callback); GFP_KERNEL, drv, iwl_req_fw_callback);
} }
struct fw_img_parsing { struct fw_img_parsing {
@ -759,13 +770,57 @@ static int validate_sec_sizes(struct iwl_drv *drv,
return 0; 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 * If loaded successfully, copies the firmware into buffers
* for the card to fetch (via DMA). * 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_drv *drv = context;
struct iwl_fw *fw = &drv->fw; struct iwl_fw *fw = &drv->fw;
@ -908,8 +963,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
list_add_tail(&drv->list, &op->drv); list_add_tail(&drv->list, &op->drv);
if (op->ops) { if (op->ops) {
const struct iwl_op_mode_ops *ops = op->ops; drv->op_mode = _iwl_op_mode_start(drv, op);
drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
if (!drv->op_mode) { if (!drv->op_mode) {
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
@ -969,14 +1023,43 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
init_completion(&drv->request_firmware_complete); init_completion(&drv->request_firmware_complete);
INIT_LIST_HEAD(&drv->list); 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); ret = iwl_request_firmware(drv, true);
if (ret) { if (ret) {
IWL_ERR(trans, "Couldn't request the fw\n"); IWL_ERR(trans, "Couldn't request the fw\n");
kfree(drv); goto err_fw;
drv = NULL;
} }
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; return drv;
} }
@ -984,9 +1067,7 @@ void iwl_drv_stop(struct iwl_drv *drv)
{ {
wait_for_completion(&drv->request_firmware_complete); wait_for_completion(&drv->request_firmware_complete);
/* op_mode can be NULL if its start failed */ _iwl_op_mode_stop(drv);
if (drv->op_mode)
iwl_op_mode_stop(drv->op_mode);
iwl_dealloc_ucode(drv); iwl_dealloc_ucode(drv);
@ -1000,6 +1081,10 @@ void iwl_drv_stop(struct iwl_drv *drv)
list_del(&drv->list); list_del(&drv->list);
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
#ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive(drv->dbgfs_drv);
#endif
kfree(drv); kfree(drv);
} }
@ -1022,15 +1107,18 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
{ {
int i; int i;
struct iwl_drv *drv; struct iwl_drv *drv;
struct iwlwifi_opmode_table *op;
mutex_lock(&iwlwifi_opmode_table_mtx); mutex_lock(&iwlwifi_opmode_table_mtx);
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { 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; continue;
iwlwifi_opmode_table[i].ops = ops; op->ops = ops;
list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) /* TODO: need to handle exceptional case */
drv->op_mode = ops->start(drv->trans, drv->cfg, list_for_each_entry(drv, &op->drv, list)
&drv->fw); drv->op_mode = _iwl_op_mode_start(drv, op);
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
return 0; return 0;
} }
@ -1051,12 +1139,9 @@ void iwl_opmode_deregister(const char *name)
iwlwifi_opmode_table[i].ops = NULL; iwlwifi_opmode_table[i].ops = NULL;
/* call the stop routine for all devices */ /* call the stop routine for all devices */
list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) { list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
if (drv->op_mode) { _iwl_op_mode_stop(drv);
iwl_op_mode_stop(drv->op_mode);
drv->op_mode = NULL;
}
}
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
return; return;
} }
@ -1076,6 +1161,14 @@ static int __init iwl_drv_init(void)
pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
pr_info(DRV_COPYRIGHT "\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(); return iwl_pci_register_driver();
} }
module_init(iwl_drv_init); module_init(iwl_drv_init);
@ -1083,6 +1176,10 @@ module_init(iwl_drv_init);
static void __exit iwl_drv_exit(void) static void __exit iwl_drv_exit(void)
{ {
iwl_pci_unregister_driver(); iwl_pci_unregister_driver();
#ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive(iwl_dbgfs_root);
#endif
} }
module_exit(iwl_drv_exit); module_exit(iwl_drv_exit);

View File

@ -90,9 +90,9 @@
* 4) The bus specific component configures the bus * 4) The bus specific component configures the bus
* 5) The bus specific component calls to the drv bus agnostic part * 5) The bus specific component calls to the drv bus agnostic part
* (iwl_drv_start) * (iwl_drv_start)
* 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback * 6) iwl_drv_start fetches the fw ASYNC, iwl_req_fw_callback
* 7) iwl_ucode_callback parses the fw file * 7) iwl_req_fw_callback parses the fw file
* 8) iwl_ucode_callback starts the wifi implementation to matches the fw * 8) iwl_req_fw_callback starts the wifi implementation to matches the fw
*/ */
struct iwl_drv; struct iwl_drv;

View File

@ -134,7 +134,8 @@ struct iwl_cfg;
struct iwl_op_mode_ops { struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans, struct iwl_op_mode *(*start)(struct iwl_trans *trans,
const struct iwl_cfg *cfg, 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); void (*stop)(struct iwl_op_mode *op_mode);
int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd); struct iwl_device_cmd *cmd);

View File

@ -184,14 +184,20 @@ struct iwl_rx_packet {
* @CMD_SYNC: The caller will be stalled until the fw responds to the command * @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_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 * @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. * @CMD_ON_DEMAND: This command is sent by the test mode pipe.
*/ */
enum CMD_MODE { enum CMD_MODE {
CMD_SYNC = 0, CMD_SYNC = 0,
CMD_ASYNC = BIT(0), CMD_ASYNC = BIT(0),
CMD_WANT_SKB = BIT(1), 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 #define DEF_CMD_PAYLOAD_SIZE 320
@ -460,6 +466,8 @@ struct iwl_trans {
size_t dev_cmd_headroom; size_t dev_cmd_headroom;
char dev_cmd_pool_name[50]; char dev_cmd_pool_name[50];
struct dentry *dbgfs_dir;
/* pointer to trans specific struct */ /* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */ /*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *)); char trans_specific[0] __aligned(sizeof(void *));

View File

@ -282,8 +282,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!trans_pcie->drv) if (!trans_pcie->drv)
goto out_free_trans; 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; return 0;
out_free_drv:
iwl_drv_stop(trans_pcie->drv);
out_free_trans: out_free_trans:
iwl_trans_pcie_free(iwl_trans); iwl_trans_pcie_free(iwl_trans);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);

View File

@ -184,6 +184,7 @@ struct iwl_queue {
struct iwl_pcie_tx_queue_entry { struct iwl_pcie_tx_queue_entry {
struct iwl_device_cmd *cmd; struct iwl_device_cmd *cmd;
struct iwl_device_cmd *copy_cmd;
struct sk_buff *skb; struct sk_buff *skb;
struct iwl_cmd_meta meta; struct iwl_cmd_meta meta;
}; };

View File

@ -421,13 +421,23 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
index = SEQ_TO_INDEX(sequence); index = SEQ_TO_INDEX(sequence);
cmd_index = get_cmd_index(&txq->q, index); cmd_index = get_cmd_index(&txq->q, index);
if (reclaim) if (reclaim) {
cmd = txq->entries[cmd_index].cmd; struct iwl_pcie_tx_queue_entry *ent;
else ent = &txq->entries[cmd_index];
cmd = ent->copy_cmd;
WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD);
} else {
cmd = NULL; cmd = NULL;
}
err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); 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, * After here, we should always check rxcb._page_stolen,
* if it is true then one of the handlers took the page. * if it is true then one of the handlers took the page.

View File

@ -492,10 +492,11 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
iwl_tx_queue_unmap(trans, txq_id); iwl_tx_queue_unmap(trans, txq_id);
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
if (txq_id == trans_pcie->cmd_queue) 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].cmd);
kfree(txq->entries[i].copy_cmd);
}
/* De-alloc circular buffer of TFDs */ /* De-alloc circular buffer of TFDs */
if (txq->q.n_bd) { if (txq->q.n_bd) {
@ -896,6 +897,7 @@ static int iwl_set_hw_ready(struct iwl_trans *trans)
static int iwl_prepare_card_hw(struct iwl_trans *trans) static int iwl_prepare_card_hw(struct iwl_trans *trans)
{ {
int ret; int ret;
int t = 0;
IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
@ -908,17 +910,15 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE); CSR_HW_IF_CONFIG_REG_PREPARE);
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, do {
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, ret = iwl_set_hw_ready(trans);
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); if (ret >= 0)
return 0;
if (ret < 0) usleep_range(200, 1000);
return ret; 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; return ret;
} }
@ -1769,7 +1769,7 @@ void iwl_dump_csr(struct iwl_trans *trans)
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, trans, \ if (!debugfs_create_file(#name, mode, parent, trans, \
&iwl_dbgfs_##name##_ops)) \ &iwl_dbgfs_##name##_ops)) \
return -ENOMEM; \ goto err; \
} while (0) } while (0)
/* file operation */ /* file operation */
@ -2033,6 +2033,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR); DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
return 0; return 0;
err:
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
return -ENOMEM;
} }
#else #else
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,

View File

@ -521,7 +521,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
u16 copy_size, cmd_size; u16 copy_size, cmd_size;
bool had_nocopy = false; bool had_nocopy = false;
int i; int i;
u8 *cmd_dest; u32 cmd_pos;
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING #ifdef CONFIG_IWLWIFI_DEVICE_TRACING
const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {}; const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
int trace_lens[IWL_MAX_CMD_TFDS + 1] = {}; int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
@ -584,15 +584,31 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
INDEX_TO_SEQ(q->write_ptr)); INDEX_TO_SEQ(q->write_ptr));
/* and copy the data that needs to be copied */ /* and copy the data that needs to be copied */
cmd_pos = offsetof(struct iwl_device_cmd, payload);
cmd_dest = out_cmd->payload;
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
if (!cmd->len[i]) if (!cmd->len[i])
continue; continue;
if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
break; break;
memcpy(cmd_dest, cmd->data[i], cmd->len[i]); memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);
cmd_dest += 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, IWL_DEBUG_HC(trans,

View File

@ -726,3 +726,29 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
return count; 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;
}

View File

@ -69,6 +69,7 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
int cmd_action, int cmd_action,
struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl); 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. * This function checks whether AMPDU is allowed or not for a particular TID.
@ -157,4 +158,18 @@ mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
return false; 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_ */ #endif /* !_MWIFIEX_11N_H_ */

View File

@ -62,9 +62,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
}; };
struct tx_packet_hdr *tx_header; struct tx_packet_hdr *tx_header;
skb_put(skb_aggr, sizeof(*tx_header)); tx_header = (void *)skb_put(skb_aggr, sizeof(*tx_header));
tx_header = (struct tx_packet_hdr *) skb_aggr->data;
/* Copy DA and SA */ /* Copy DA and SA */
dt_offset = 2 * ETH_ALEN; dt_offset = 2 * ETH_ALEN;
@ -82,12 +80,10 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
/* Add payload */ /* Add payload */
skb_put(skb_aggr, skb_src->len); memcpy(skb_put(skb_aggr, skb_src->len), skb_src->data, skb_src->len);
memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
skb_src->len); /* Add padding for new MSDU to start from 4 byte boundary */
*pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len + *pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4;
LLC_SNAP_LEN)) & 3)) : 0;
skb_put(skb_aggr, *pad);
return skb_aggr->len + *pad; return skb_aggr->len + *pad;
} }

View File

@ -54,8 +54,13 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
tbl->rx_reorder_ptr[i] = NULL; tbl->rx_reorder_ptr[i] = NULL;
} }
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
if (rx_tmp_ptr) if (rx_tmp_ptr) {
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); spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@ -97,7 +102,11 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
rx_tmp_ptr = tbl->rx_reorder_ptr[i]; rx_tmp_ptr = tbl->rx_reorder_ptr[i];
tbl->rx_reorder_ptr[i] = NULL; tbl->rx_reorder_ptr[i] = NULL;
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 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); spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@ -148,7 +157,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
* This function returns the pointer to an entry in Rx reordering * This function returns the pointer to an entry in Rx reordering
* table which matches the given TA/TID pair. * 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) mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
{ {
struct mwifiex_rx_reorder_tbl *tbl; struct mwifiex_rx_reorder_tbl *tbl;
@ -167,6 +176,31 @@ mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
return NULL; 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 * This function finds the last sequence number used in the packets
* buffered in Rx reordering table. * buffered in Rx reordering table.
@ -226,6 +260,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
struct mwifiex_rx_reorder_tbl *tbl, *new_node; struct mwifiex_rx_reorder_tbl *tbl, *new_node;
u16 last_seq = 0; u16 last_seq = 0;
unsigned long flags; unsigned long flags;
struct mwifiex_sta_node *node;
/* /*
* If we get a TID, ta pair which is already present dispatch all the * If we get a TID, ta pair which is already present dispatch all the
@ -248,13 +283,19 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
new_node->tid = tid; new_node->tid = tid;
memcpy(new_node->ta, ta, ETH_ALEN); memcpy(new_node->ta, ta, ETH_ALEN);
new_node->start_win = seq_num; 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, 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); 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]; last_seq = priv->rx_seq[tid];
}
if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
last_seq >= new_node->start_win) last_seq >= new_node->start_win)
@ -396,8 +437,13 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
if (!tbl) { if (!tbl) {
if (pkt_type != PKT_TYPE_BAR) if (pkt_type != PKT_TYPE_BAR) {
mwifiex_process_rx_packet(priv->adapter, payload); 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; return 0;
} }
start_win = tbl->start_win; start_win = tbl->start_win;

View File

@ -38,6 +38,8 @@
#define ADDBA_RSP_STATUS_ACCEPT 0 #define ADDBA_RSP_STATUS_ACCEPT 0
#define MWIFIEX_DEF_11N_RX_SEQ_NUM 0xffff #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) static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
{ {
@ -68,5 +70,8 @@ struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
mwifiex_private mwifiex_private
*priv, int tid, *priv, int tid,
u8 *ta); 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_ */ #endif /* _MWIFIEX_11N_RXREORDER_H_ */

View File

@ -33,8 +33,10 @@ mwifiex-y += uap_cmd.o
mwifiex-y += ie.o mwifiex-y += ie.o
mwifiex-y += sta_cmdresp.o mwifiex-y += sta_cmdresp.o
mwifiex-y += sta_event.o mwifiex-y += sta_event.o
mwifiex-y += uap_event.o
mwifiex-y += sta_tx.o mwifiex-y += sta_tx.o
mwifiex-y += sta_rx.o mwifiex-y += sta_rx.o
mwifiex-y += uap_txrx.o
mwifiex-y += cfg80211.o mwifiex-y += cfg80211.o
mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MWIFIEX) += mwifiex.o obj-$(CONFIG_MWIFIEX) += mwifiex.o

View File

@ -99,7 +99,7 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const u8 *peer_mac = pairwise ? mac_addr : bc_mac; 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"); wiphy_err(wiphy, "deleting the crypto keys\n");
return -EFAULT; return -EFAULT;
} }
@ -171,7 +171,8 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) { if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
priv->wep_key_curr_index = key_index; 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"); wiphy_err(wiphy, "set default Tx key index\n");
return -EFAULT; return -EFAULT;
} }
@ -207,7 +208,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
return 0; 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)) { key_index, peer_mac, 0)) {
wiphy_err(wiphy, "crypto keys added\n"); wiphy_err(wiphy, "crypto keys added\n");
return -EFAULT; return -EFAULT;
@ -748,6 +749,7 @@ static const u32 mwifiex_cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP, WLAN_CIPHER_SUITE_CCMP,
WLAN_CIPHER_SUITE_AES_CMAC,
}; };
/* /*
@ -906,6 +908,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
if (mwifiex_del_mgmt_ies(priv)) if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); 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, if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL)) { HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to stop the BSS\n"); wiphy_err(wiphy, "Failed to stop the BSS\n");
@ -1159,7 +1163,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
priv->wep_key_curr_index = 0; priv->wep_key_curr_index = 0;
priv->sec_info.encryption_mode = 0; priv->sec_info.encryption_mode = 0;
priv->sec_info.is_authtype_auto = 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) { if (mode == NL80211_IFTYPE_ADHOC) {
/* "privacy" is set only for ad-hoc mode */ /* "privacy" is set only for ad-hoc mode */
@ -1206,8 +1210,9 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
"info: setting wep encryption" "info: setting wep encryption"
" with key len %d\n", sme->key_len); " with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx; priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, sme->key, sme->key_len, ret = mwifiex_set_encode(priv, NULL, sme->key,
sme->key_idx, NULL, 0); sme->key_len, sme->key_idx,
NULL, 0);
} }
} }
done: done:

View File

@ -447,7 +447,10 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 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_cause = 0;
adapter->event_skb = NULL; adapter->event_skb = NULL;

View File

@ -60,6 +60,9 @@
#define MWIFIEX_SDIO_BLOCK_SIZE 256 #define MWIFIEX_SDIO_BLOCK_SIZE 256
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) #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 { enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_STA = 0,

View File

@ -65,10 +65,12 @@ enum KEY_TYPE_ID {
KEY_TYPE_ID_TKIP, KEY_TYPE_ID_TKIP,
KEY_TYPE_ID_AES, KEY_TYPE_ID_AES,
KEY_TYPE_ID_WAPI, KEY_TYPE_ID_WAPI,
KEY_TYPE_ID_AES_CMAC,
}; };
#define KEY_MCAST BIT(0) #define KEY_MCAST BIT(0)
#define KEY_UNICAST BIT(1) #define KEY_UNICAST BIT(1)
#define KEY_ENABLED BIT(2) #define KEY_ENABLED BIT(2)
#define KEY_IGTK BIT(10)
#define WAPI_KEY_LEN 50 #define WAPI_KEY_LEN 50
@ -424,10 +426,10 @@ struct txpd {
struct rxpd { struct rxpd {
u8 bss_type; u8 bss_type;
u8 bss_num; u8 bss_num;
u16 rx_pkt_length; __le16 rx_pkt_length;
u16 rx_pkt_offset; __le16 rx_pkt_offset;
u16 rx_pkt_type; __le16 rx_pkt_type;
u16 seq_num; __le16 seq_num;
u8 priority; u8 priority;
u8 rx_rate; u8 rx_rate;
s8 snr; s8 snr;
@ -439,6 +441,31 @@ struct rxpd {
u8 reserved; u8 reserved;
} __packed; } __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 { enum mwifiex_chan_scan_mode_bitmasks {
MWIFIEX_PASSIVE_SCAN = BIT(0), MWIFIEX_PASSIVE_SCAN = BIT(0),
MWIFIEX_DISABLE_CHAN_FILT = BIT(1), MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
@ -558,6 +585,13 @@ struct mwifiex_ie_type_key_param_set {
u8 key[50]; u8 key[50];
} __packed; } __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 { struct host_cmd_ds_802_11_key_material {
__le16 action; __le16 action;
struct mwifiex_ie_type_key_param_set key_param_set; struct mwifiex_ie_type_key_param_set key_param_set;

View File

@ -64,60 +64,72 @@ static void scan_delay_timer_fn(unsigned long data)
struct cmd_ctrl_node *cmd_node, *tmp_node; struct cmd_ctrl_node *cmd_node, *tmp_node;
unsigned long flags; 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);
cmd_node->wait_q_enabled = false;
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;
}
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 * No Tx traffic for 200msec. Get scan command from
* command * 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); spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_for_each_entry_safe(cmd_node, tmp_node, cmd_node = list_first_entry(&adapter->scan_pending_q,
&adapter->scan_pending_q, struct cmd_ctrl_node, list);
list) { list_del(&cmd_node->list);
list_del(&cmd_node->list);
cmd_node->wait_q_enabled = false;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
}
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags); flags);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
adapter->scan_processing = false; true);
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, goto done;
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++;
} }
queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
} else { } else {
/* adapter->empty_tx_q_cnt = 0;
* 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);
} }
/* 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;
} }
/* /*
@ -196,6 +208,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
priv->curr_bcn_size = 0; priv->curr_bcn_size = 0;
priv->wps_ie = NULL; priv->wps_ie = NULL;
priv->wps_ie_len = 0; priv->wps_ie_len = 0;
priv->ap_11n_enabled = 0;
priv->scan_block = false; priv->scan_block = false;
@ -345,6 +358,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0; adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
adapter->empty_tx_q_cnt = 0;
} }
/* /*
@ -410,6 +424,7 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
list_del(&priv->tx_ba_stream_tbl_ptr); list_del(&priv->tx_ba_stream_tbl_ptr);
list_del(&priv->rx_reorder_tbl_ptr); list_del(&priv->rx_reorder_tbl_ptr);
list_del(&priv->sta_list);
} }
} }
} }
@ -472,6 +487,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
spin_lock_init(&priv->rx_pkt_lock); spin_lock_init(&priv->rx_pkt_lock);
spin_lock_init(&priv->wmm.ra_list_spinlock); spin_lock_init(&priv->wmm.ra_list_spinlock);
spin_lock_init(&priv->curr_bcn_buf_lock); spin_lock_init(&priv->curr_bcn_buf_lock);
spin_lock_init(&priv->sta_list_spinlock);
} }
} }
@ -504,6 +520,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
} }
INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
INIT_LIST_HEAD(&priv->rx_reorder_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->tx_ba_stream_tbl_lock);
spin_lock_init(&priv->rx_reorder_tbl_lock); spin_lock_init(&priv->rx_reorder_tbl_lock);

View File

@ -213,7 +213,7 @@ struct mwifiex_debug_info {
}; };
#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 #define MWIFIEX_KEY_INDEX_UNICAST 0x40000000
#define WAPI_RXPN_LEN 16 #define PN_LEN 16
struct mwifiex_ds_encrypt_key { struct mwifiex_ds_encrypt_key {
u32 key_disable; u32 key_disable;
@ -222,7 +222,8 @@ struct mwifiex_ds_encrypt_key {
u8 key_material[WLAN_MAX_KEY_LEN]; u8 key_material[WLAN_MAX_KEY_LEN];
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
u32 is_wapi_key; u32 is_wapi_key;
u8 wapi_rxpn[WAPI_RXPN_LEN]; u8 pn[PN_LEN]; /* packet number */
u8 is_igtk_key;
}; };
struct mwifiex_power_cfg { struct mwifiex_power_cfg {

View File

@ -520,6 +520,9 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
mwifiex_wmm_add_buf_txqueue(priv, skb); mwifiex_wmm_add_buf_txqueue(priv, skb);
atomic_inc(&priv->adapter->tx_pending); 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) { if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
mwifiex_set_trans_start(dev); mwifiex_set_trans_start(dev);
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);

View File

@ -88,6 +88,7 @@ enum {
#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) #define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
#define MWIFIEX_MAX_SCAN_DELAY_CNT 50 #define MWIFIEX_MAX_SCAN_DELAY_CNT 50
#define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10
#define MWIFIEX_SCAN_DELAY_MSEC 20 #define MWIFIEX_SCAN_DELAY_MSEC 20
#define RSN_GTK_OUI_OFFSET 2 #define RSN_GTK_OUI_OFFSET 2
@ -199,6 +200,9 @@ struct mwifiex_ra_list_tbl {
u8 ra[ETH_ALEN]; u8 ra[ETH_ALEN];
u32 total_pkts_size; u32 total_pkts_size;
u32 is_11n_enabled; u32 is_11n_enabled;
u16 max_amsdu;
u16 pkt_count;
u8 ba_packet_thr;
}; };
struct mwifiex_tid_tbl { struct mwifiex_tid_tbl {
@ -431,6 +435,9 @@ struct mwifiex_private {
u8 wmm_enabled; u8 wmm_enabled;
u8 wmm_qosinfo; u8 wmm_qosinfo;
struct mwifiex_wmm_desc wmm; 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; struct list_head tx_ba_stream_tbl_ptr;
/* spin lock for tx_ba_stream_tbl_ptr queue */ /* spin lock for tx_ba_stream_tbl_ptr queue */
spinlock_t tx_ba_stream_tbl_lock; spinlock_t tx_ba_stream_tbl_lock;
@ -486,6 +493,7 @@ struct mwifiex_private {
u16 assocresp_idx; u16 assocresp_idx;
u16 rsn_idx; u16 rsn_idx;
struct timer_list scan_delay_timer; struct timer_list scan_delay_timer;
u8 ap_11n_enabled;
}; };
enum mwifiex_ba_status { enum mwifiex_ba_status {
@ -550,6 +558,19 @@ struct mwifiex_bss_priv {
u64 fw_tsf; 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 { struct mwifiex_if_ops {
int (*init_if) (struct mwifiex_adapter *); int (*init_if) (struct mwifiex_adapter *);
void (*cleanup_if) (struct mwifiex_adapter *); void (*cleanup_if) (struct mwifiex_adapter *);
@ -690,6 +711,9 @@ struct mwifiex_adapter {
u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
u16 max_mgmt_ie_index; u16 max_mgmt_ie_index;
u8 scan_delay_cnt; 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); int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@ -780,7 +804,15 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
struct host_cmd_ds_command *resp); struct host_cmd_ds_command *resp);
int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
struct sk_buff *skb); 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_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); 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_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
@ -949,9 +981,9 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
const struct mwifiex_user_scan_cfg *user_scan_in); const struct mwifiex_user_scan_cfg *user_scan_in);
int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
int key_len, u8 key_index, const u8 *mac_addr, const u8 *key, int key_len, u8 key_index,
int disable); const u8 *mac_addr, int disable);
int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);

View File

@ -989,6 +989,8 @@ mwifiex_config_scan(struct mwifiex_private *priv,
*max_chan_per_scan = 2; *max_chan_per_scan = 2;
else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD) else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
*max_chan_per_scan = 3; *max_chan_per_scan = 3;
else
*max_chan_per_scan = 4;
} }
} }
@ -1433,9 +1435,9 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
if (ret) if (ret)
dev_err(priv->adapter->dev, "cannot find ssid " dev_err(priv->adapter->dev, "cannot find ssid "
"%s\n", bss_desc->ssid.ssid); "%s\n", bss_desc->ssid.ssid);
break; break;
default: default:
ret = 0; ret = 0;
} }
} }

View File

@ -610,7 +610,7 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
memcpy(&key_material->key_param_set.key[2], memcpy(&key_material->key_param_set.key[2],
enc_key->key_material, enc_key->key_len); enc_key->key_material, enc_key->key_len);
memcpy(&key_material->key_param_set.key[2 + 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 = key_material->key_param_set.length =
cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN); cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
@ -621,23 +621,38 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
return ret; return ret;
} }
if (enc_key->key_len == WLAN_KEY_LEN_CCMP) { if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n"); if (enc_key->is_igtk_key) {
key_material->key_param_set.key_type_id = dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n");
cpu_to_le16(KEY_TYPE_ID_AES); key_material->key_param_set.key_type_id =
if (cmd_oid == KEY_INFO_ENABLED) cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
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); cpu_to_le16(KEY_ENABLED);
else else
key_material->key_param_set.key_info = key_material->key_param_set.key_info =
cpu_to_le16(!KEY_ENABLED); cpu_to_le16(!KEY_ENABLED);
if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) 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 =
cpu_to_le16(KEY_ENABLED);
else
key_material->key_param_set.key_info =
cpu_to_le16(!KEY_ENABLED);
if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
/* AES pairwise key: unicast */ /* AES pairwise key: unicast */
key_material->key_param_set.key_info |= key_material->key_param_set.key_info |=
cpu_to_le16(KEY_UNICAST); cpu_to_le16(KEY_UNICAST);
else /* AES group key: multicast */ else /* AES group key: multicast */
key_material->key_param_set.key_info |= key_material->key_param_set.key_info |=
cpu_to_le16(KEY_MCAST); cpu_to_le16(KEY_MCAST);
}
} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
key_material->key_param_set.key_type_id = key_material->key_param_set.key_type_id =
@ -668,6 +683,24 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN) key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ sizeof(struct mwifiex_ie_types_header); + 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 cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
+ key_param_len); + key_param_len);

View File

@ -184,10 +184,9 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
int mwifiex_process_sta_event(struct mwifiex_private *priv) int mwifiex_process_sta_event(struct mwifiex_private *priv)
{ {
struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_adapter *adapter = priv->adapter;
int len, ret = 0; int ret = 0;
u32 eventcause = adapter->event_cause; u32 eventcause = adapter->event_cause;
struct station_info sinfo; u16 ctrl;
struct mwifiex_assoc_event *event;
switch (eventcause) { switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
@ -279,10 +278,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_MIC_ERR_UNICAST: case EVENT_MIC_ERR_UNICAST:
dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); 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; break;
case EVENT_MIC_ERR_MULTICAST: case EVENT_MIC_ERR_MULTICAST:
dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); 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; break;
case EVENT_MIB_CHANGED: case EVENT_MIB_CHANGED:
case EVENT_INIT_DONE: case EVENT_INIT_DONE:
@ -384,11 +389,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
adapter->event_body); adapter->event_body);
break; break;
case EVENT_AMSDU_AGGR_CTRL: case EVENT_AMSDU_AGGR_CTRL:
dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
*(u16 *) adapter->event_body); dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
adapter->tx_buf_size = adapter->tx_buf_size =
min(adapter->curr_tx_buf_size, min_t(u16, adapter->curr_tx_buf_size, ctrl);
le16_to_cpu(*(__le16 *) adapter->event_body));
dev_dbg(adapter->dev, "event: tx_buf_size %d\n", dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
adapter->tx_buf_size); adapter->tx_buf_size);
break; break;
@ -405,51 +410,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
break; 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: default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n", dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause); eventcause);

View File

@ -942,20 +942,26 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
* This function allocates the IOCTL request buffer, fills it * This function allocates the IOCTL request buffer, fills it
* with requisite parameters and calls the IOCTL handler. * with requisite parameters and calls the IOCTL handler.
*/ */
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
int key_len, u8 key_index, const u8 *key, int key_len, u8 key_index,
const u8 *mac_addr, int disable) const u8 *mac_addr, int disable)
{ {
struct mwifiex_ds_encrypt_key encrypt_key; struct mwifiex_ds_encrypt_key encrypt_key;
memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
encrypt_key.key_len = key_len; encrypt_key.key_len = key_len;
if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
encrypt_key.is_igtk_key = true;
if (!disable) { if (!disable) {
encrypt_key.key_index = key_index; encrypt_key.key_index = key_index;
if (key_len) if (key_len)
memcpy(encrypt_key.key_material, key, key_len); memcpy(encrypt_key.key_material, key, key_len);
if (mac_addr) if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); 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 { } else {
encrypt_key.key_disable = true; encrypt_key.key_disable = true;
if (mac_addr) if (mac_addr)

View File

@ -54,8 +54,8 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
local_rx_pd = (struct rxpd *) (skb->data); local_rx_pd = (struct rxpd *) (skb->data);
rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + rx_pkt_hdr = (void *)local_rx_pd +
local_rx_pd->rx_pkt_offset); le16_to_cpu(local_rx_pd->rx_pkt_offset);
if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
@ -125,7 +125,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
struct rx_packet_hdr *rx_pkt_hdr; struct rx_packet_hdr *rx_pkt_hdr;
u8 ta[ETH_ALEN]; u8 ta[ETH_ALEN];
u16 rx_pkt_type; u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num;
struct mwifiex_private *priv = struct mwifiex_private *priv =
mwifiex_get_priv_by_id(adapter, rx_info->bss_num, mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
rx_info->bss_type); rx_info->bss_type);
@ -134,16 +134,17 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
return -1; return -1;
local_rx_pd = (struct rxpd *) (skb->data); 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 + rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
local_rx_pd->rx_pkt_offset);
if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) > if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
(u16) skb->len) { dev_err(adapter->dev,
dev_err(adapter->dev, "wrong rx packet: len=%d," "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
" rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, skb->len, rx_pkt_offset, rx_pkt_length);
local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length);
priv->stats.rx_dropped++; priv->stats.rx_dropped++;
if (adapter->if_ops.data_complete) if (adapter->if_ops.data_complete)
@ -154,14 +155,14 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
return ret; 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_head list;
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
__skb_queue_head_init(&list); __skb_queue_head_init(&list);
skb_pull(skb, local_rx_pd->rx_pkt_offset); skb_pull(skb, rx_pkt_offset);
skb_trim(skb, local_rx_pd->rx_pkt_length); skb_trim(skb, rx_pkt_length);
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev->iftype, 0, false); priv->wdev->iftype, 0, false);
@ -189,17 +190,14 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
} else { } else {
if (rx_pkt_type != PKT_TYPE_BAR) if (rx_pkt_type != PKT_TYPE_BAR)
priv->rx_seq[local_rx_pd->priority] = priv->rx_seq[local_rx_pd->priority] = seq_num;
local_rx_pd->seq_num;
memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
ETH_ALEN); ETH_ALEN);
} }
/* Reorder and send to OS */ /* Reorder and send to OS */
ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num, ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority,
local_rx_pd->priority, ta, ta, (u8) rx_pkt_type, skb);
(u8) local_rx_pd->rx_pkt_type,
skb);
if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
if (adapter->if_ops.data_complete) if (adapter->if_ops.data_complete)

View File

@ -51,6 +51,9 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
rx_info->bss_num = priv->bss_num; rx_info->bss_num = priv->bss_num;
rx_info->bss_type = priv->bss_type; 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); return mwifiex_process_sta_rx_packet(adapter, skb);
} }
EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
@ -157,6 +160,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
priv->stats.tx_errors++; 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) if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
goto done; goto done;

View File

@ -167,6 +167,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
if (ht_ie) { if (ht_ie) {
memcpy(&bss_cfg->ht_cap, ht_ie + 2, memcpy(&bss_cfg->ht_cap, ht_ie + 2,
sizeof(struct ieee80211_ht_cap)); sizeof(struct ieee80211_ht_cap));
priv->ap_11n_enabled = 1;
} else { } else {
memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap)); memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP); bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);

View File

@ -0,0 +1,290 @@
/*
* 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;
}

View File

@ -0,0 +1,255 @@
/*
* 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;
}

View File

@ -127,6 +127,29 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
return ra_list; 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 * This function allocates and adds a RA list for all TIDs
* with the given RA. * with the given RA.
@ -137,6 +160,12 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
int i; int i;
struct mwifiex_ra_list_tbl *ra_list; struct mwifiex_ra_list_tbl *ra_list;
struct mwifiex_adapter *adapter = priv->adapter; 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) { for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra); ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
@ -145,14 +174,24 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
if (!ra_list) if (!ra_list)
break; 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); ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
else } else {
ra_list->is_11n_enabled = false; 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", dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
ra_list, ra_list->is_11n_enabled); 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, list_add_tail(&ra_list->list,
&priv->wmm.tid_tbl_ptr[i].ra_list); &priv->wmm.tid_tbl_ptr[i].ra_list);
@ -647,6 +686,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
skb_queue_tail(&ra_list->skb_head, skb); skb_queue_tail(&ra_list->skb_head, skb);
ra_list->total_pkts_size += skb->len; ra_list->total_pkts_size += skb->len;
ra_list->pkt_count++;
atomic_inc(&priv->wmm.tx_pkts_queued); atomic_inc(&priv->wmm.tx_pkts_queued);
@ -986,10 +1026,17 @@ mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv,
{ {
int count = 0, total_size = 0; int count = 0, total_size = 0;
struct sk_buff *skb, *tmp; 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) { skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
total_size += skb->len; total_size += skb->len;
if (total_size >= max_buf_size) if (total_size >= max_amsdu_size)
break; break;
if (++count >= MIN_NUM_AMSDU) if (++count >= MIN_NUM_AMSDU)
return true; return true;
@ -1050,6 +1097,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
skb_queue_tail(&ptr->skb_head, skb); skb_queue_tail(&ptr->skb_head, skb);
ptr->total_pkts_size += skb->len; ptr->total_pkts_size += skb->len;
ptr->pkt_count++;
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags); ra_list_flags);
@ -1231,7 +1279,8 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
/* ra_list_spinlock has been freed in /* ra_list_spinlock has been freed in
mwifiex_send_single_packet() */ mwifiex_send_single_packet() */
} else { } 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)) { if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
mwifiex_create_ba_tbl(priv, ptr->ra, tid, mwifiex_create_ba_tbl(priv, ptr->ra, tid,
BA_SETUP_INPROGRESS); BA_SETUP_INPROGRESS);

View File

@ -76,6 +76,7 @@ struct p54_channel_entry {
u16 freq; u16 freq;
u16 data; u16 data;
int index; int index;
int max_power;
enum ieee80211_band band; enum ieee80211_band band;
}; };
@ -173,6 +174,7 @@ static int p54_generate_band(struct ieee80211_hw *dev,
for (i = 0, j = 0; (j < list->band_channel_num[band]) && for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
(i < list->entries); i++) { (i < list->entries); i++) {
struct p54_channel_entry *chan = &list->channels[i]; struct p54_channel_entry *chan = &list->channels[i];
struct ieee80211_channel *dest = &tmp->channels[j];
if (chan->band != band) if (chan->band != band)
continue; continue;
@ -190,14 +192,15 @@ static int p54_generate_band(struct ieee80211_hw *dev,
continue; continue;
} }
tmp->channels[j].band = chan->band; dest->band = chan->band;
tmp->channels[j].center_freq = chan->freq; dest->center_freq = chan->freq;
dest->max_power = chan->max_power;
priv->survey[*chan_num].channel = &tmp->channels[j]; priv->survey[*chan_num].channel = &tmp->channels[j];
priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_TX; SURVEY_INFO_CHANNEL_TIME_TX;
tmp->channels[j].hw_value = (*chan_num); dest->hw_value = (*chan_num);
j++; j++;
(*chan_num)++; (*chan_num)++;
} }
@ -229,10 +232,11 @@ err_out:
return ret; return ret;
} }
static void p54_update_channel_param(struct p54_channel_list *list, static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
u16 freq, u16 data) u16 freq, u16 data)
{ {
int band, i; int i;
struct p54_channel_entry *entry = NULL;
/* /*
* usually all lists in the eeprom are mostly sorted. * usually all lists in the eeprom are mostly sorted.
@ -241,30 +245,78 @@ static void p54_update_channel_param(struct p54_channel_list *list,
*/ */
for (i = list->entries; i >= 0; i--) { for (i = list->entries; i >= 0; i--) {
if (freq == list->channels[i].freq) { if (freq == list->channels[i].freq) {
list->channels[i].data |= data; entry = &list->channels[i];
break; break;
} }
} }
if ((i < 0) && (list->entries < list->max_entries)) { if ((i < 0) && (list->entries < list->max_entries)) {
/* entry does not exist yet. Initialize a new one. */ /* 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 * filter out frequencies which don't belong into
* any supported band. * any supported band.
*/ */
if (band < 0) if (band >= 0) {
return ; i = list->entries++;
list->band_channel_num[band]++;
i = list->entries++; entry = &list->channels[i];
list->band_channel_num[band]++; entry->freq = freq;
entry->band = band;
entry->index = ieee80211_frequency_to_channel(freq);
entry->max_power = 0;
entry->data = 0;
}
}
list->channels[i].freq = freq; if (entry)
list->channels[i].data = data; entry->data |= data;
list->channels[i].band = band;
list->channels[i].index = ieee80211_frequency_to_channel(freq); return entry;
/* TODO: parse output_limit and fill max_power */ }
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;
} }
} }
@ -315,12 +367,19 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
} }
if (i < priv->output_limit->entries) { if (i < priv->output_limit->entries) {
freq = le16_to_cpup((__le16 *) (i * struct p54_channel_entry *tmp;
priv->output_limit->entry_size +
priv->output_limit->offset +
priv->output_limit->data));
p54_update_channel_param(list, freq, CHAN_HAS_LIMIT); 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) { if (i < priv->curve_data->entries) {
@ -834,11 +893,12 @@ good_eeprom:
goto err; goto err;
} }
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
err = p54_generate_channel_lists(dev); err = p54_generate_channel_lists(dev);
if (err) if (err)
goto err; goto err;
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
p54_init_xbow_synth(priv); p54_init_xbow_synth(priv);
if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))

View File

@ -57,6 +57,18 @@ struct pda_channel_output_limit {
u8 rate_set_size; u8 rate_set_size;
} __packed; } __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 { struct pda_pa_curve_data_sample_rev0 {
u8 rf_power; u8 rf_power;
u8 pa_detector; u8 pa_detector;

View File

@ -488,6 +488,58 @@ static int p54p_open(struct ieee80211_hw *dev)
return 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, static int __devinit p54p_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
@ -496,6 +548,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
unsigned long mem_addr, mem_len; unsigned long mem_addr, mem_len;
int err; int err;
pci_dev_get(pdev);
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) { if (err) {
dev_err(&pdev->dev, "Cannot enable new PCI device\n"); dev_err(&pdev->dev, "Cannot enable new PCI device\n");
@ -537,6 +590,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
priv = dev->priv; priv = dev->priv;
priv->pdev = pdev; priv->pdev = pdev;
init_completion(&priv->fw_loaded);
SET_IEEE80211_DEV(dev, &pdev->dev); SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
@ -561,32 +615,12 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev); tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
err = request_firmware(&priv->firmware, "isl3886pci", err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
&priv->pdev->dev); &priv->pdev->dev, GFP_KERNEL,
if (err) { priv, p54p_firmware_step2);
dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n"); if (!err)
err = request_firmware(&priv->firmware, "isl3886", return 0;
&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_free_common:
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control), pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma); priv->ring_control, priv->ring_control_dma);
@ -601,6 +635,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
pci_release_regions(pdev); pci_release_regions(pdev);
err_disable_dev: err_disable_dev:
pci_disable_device(pdev); pci_disable_device(pdev);
pci_dev_put(pdev);
return err; return err;
} }
@ -612,8 +647,9 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev) if (!dev)
return; return;
p54_unregister_common(dev);
priv = dev->priv; priv = dev->priv;
wait_for_completion(&priv->fw_loaded);
p54_unregister_common(dev);
release_firmware(priv->firmware); release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control), pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma); priv->ring_control, priv->ring_control_dma);

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